PCIE-MIS/MSIX中断
+ -

PCIE-MSI中断LINUX驱动-imt_driv.c

2025-07-16 0 0

#include <linux/io.h>
#include <linux/types.h>
#include <linux/init.h>  
#include <linux/module.h>
#include <linux/kthread.h>  
#include <linux/sched.h>  
#include <linux/kernel.h>
#include <linux/err.h>  
#include <linux/delay.h>
#include <linux/poll.h>

#include "imt_drv.h"

/***************************************************************
全局变量定义
****************************************************************/
imt_test_pci_dev_s g_imt_pci_dev;

static void imt_tasklet_handler (unsigned long data)
{
    printk("Enter imt tasklet\n");

    enable_irq(pci_irq_vector(g_imt_pci_dev.pci_dev, 0));
}

DECLARE_TASKLET(imt_test_handler, imt_tasklet_handler, 0);


static irqreturn_t imt_irq_handle(int irq, void* dev_id)
{
    printk("imt_irq_handle %d\n", irq);
    disable_irq(irq);

    tasklet_schedule(&imt_test_handler);
    return IRQ_HANDLED;
}

static int imt_test_open(struct inode *inode, struct file *filp)
{
    filp->private_data = &g_imt_pci_dev;

    return 0;
}

static int imt_test_release(struct inode *inode, struct file *filp)
{
    return 0;
}


static struct file_operations imt_test_fops = {
    .open            =    imt_test_open,
    .release        =    imt_test_release,
    .owner            =    THIS_MODULE,
};

unsigned int imt_test_irq_num = 0;
/**
 * @brief 初始化设备
 * 
 * @param pci_dev 
 * @param pci_id 
 * @return int 
 */
static int imt_test_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
{
    int ret;
    int i;
    int msi_num;
    int irq_num;

    imt_test_pci_dev_s *privdata;

    printk("imt enter probe\n");

    memset(&g_imt_pci_dev, 0, sizeof(imt_test_pci_dev_s)); 
    privdata = &g_imt_pci_dev;

    if(pci_enable_device(pci_dev)) {
        printk(KERN_ERR "%s:cannot enable device\n", pci_name(pci_dev));
        return -ENODEV;
    }

    /* 对PCI区进行标记,标记该区域已经分配出去*/
    ret = pci_request_regions(pci_dev, IMT_TEST_DEV_NAME);
    if(ret) {
        printk("pci_request_regions failed ret:%d\n", ret);
        return ret;
    }

    pci_set_master(pci_dev);
    pci_set_drvdata(pci_dev, privdata);


    g_imt_pci_dev.pci_dev = pci_dev;

    ret = alloc_chrdev_region(&g_imt_pci_dev.dev_num, 0, 1, IMT_TEST_DEV_NAME); 
    cdev_init(&privdata->cdev, &imt_test_fops);
    cdev_add(&privdata->cdev, privdata->dev_num, 1);

    privdata->cdev_class = class_create(THIS_MODULE, IMT_TEST_DEV_NAME);
    device_create(privdata->cdev_class, NULL, privdata->dev_num, pci_dev, IMT_TEST_DEV_NAME);


    msi_num = pci_alloc_irq_vectors(pci_dev, 1, 32, PCI_IRQ_MSI);
    printk("pci_alloc_irq_vectors return %d\n", msi_num);

    if (msi_num == 32) {
        irq_num = pci_irq_vector(pci_dev, 0);
        for (i = 0; i < 32; i++) {
            if ((ret = devm_request_irq(&pci_dev->dev, irq_num + i, imt_irq_handle, 0,"imt_msi", pci_dev)) < 0){
                printk("Cannot request irq %d, ret=%d\n", irq_num, ret);
                return -1;
            } else {
                printk("request irq %d, ret=%d success\n", irq_num, ret);
            }
        }
    } else {
        printk("Error: pci_alloc_irq_vectors alloc 32 irqs failed. msi_num:%d\n", msi_num);
        return -1;
    }

    printk("imt_test_probe end successful\n");

    return 0;

}


static void imt_test_remove(struct pci_dev *pci_dev) 
{
    unsigned int i;

    printk("imt_test_remove enter\n");

    device_destroy(g_imt_pci_dev.cdev_class, g_imt_pci_dev.dev_num);
    class_destroy(g_imt_pci_dev.cdev_class);
    unregister_chrdev_region(g_imt_pci_dev.dev_num, 1);

    for (i = 0; i < 32; i++) {
        devm_free_irq(&pci_dev->dev, pci_irq_vector(pci_dev, i), pci_dev);
    }

    iounmap((void*)g_imt_pci_dev.ioaddr);
    pci_release_regions(pci_dev);

    pci_set_drvdata(pci_dev, NULL);
    pci_disable_device(pci_dev);

    printk("imt_test_remove end\n");
}


static struct pci_device_id imt_test_tbl[] = {
    {IMT_TEST_VENDOR_ID, IMT_TEST_DEVICE_ID_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
    { 0,}
};

MODULE_DEVICE_TABLE(pci, imt_test_tbl);
static struct pci_driver imt_test_driver = {
    .name       =  IMT_MODULE_NAME,          ///< 驱动的名字,一般是一个宏定义
    .id_table   =   imt_test_tbl,            ///< 包含了相关物理PCI设备的基本信息,vendorID,deviceID
    .probe      =   imt_test_probe,          ///< 用于发现PCI设备
    .remove     =   imt_test_remove,
};

static int __init  imt_test_init_module(void)
{
    return pci_register_driver(&imt_test_driver); 
}

static void __exit imt_test_cleanup_module(void)
{
    pci_unregister_driver(&imt_test_driver);
}

module_init(imt_test_init_module);
module_exit(imt_test_cleanup_module);
MODULE_LICENSE("GPL");

0 篇笔记 写笔记

PCIE MSI-X
MSI-XCA 结构MSI-X和MSI最大的不同是messagedata、message address和status字段没有存放在设备的配置空间中,而是使用MSI-XTable structure和MSI-X PBA structure来存放这些字段。MSI-X Table structur......
PCIe 中断机制介绍(MSI
前面的文章中介绍过,MSI本质上是一种Memory Write,和PCIe总线中的Message概念半毛钱关系都没有。并且,MSI的Data Payload也是固定的,始终为1DW。由于MSI也是从PCI总线继承而来的,因此MSI相关的寄存器也存在于配置空间中的PCI兼容部分(前256个字节)。如......
PCIe 中断机制介绍(MSI-X)
PCI总线自3.0版本开始支持MSI-X机制,对MSI做出了一些升级和改进,以克服MSI机制的三个主要的缺陷:随着系统的发展,对于特定的大型应用,32个中断向量不够用了(参考前一篇文章);只有一个目标地址使得多核CPU情况下的,静态中断分配变得困难。如果能够使每个向量对应不同的唯一的地址,便会灵......
PCIE-MSI中断LINUX驱动-imt_driv.h
#ifndef __IMT_TEST__H__ #define __IMT_TEST__H__#include #include #include "linux/pci.h"#incl......
PCIE-MSI中断LINUX驱动-imt_driv.c
#include #include #include #include #include
all: make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules#make -C $(KDIR) M=$(PWD) modulesclean: make -C /lib/modules/$(shell una......
#include #include #include ///<支持的ioctrl 命令#define GDMA_TEST_IOC_SUBMIT _IOW('p', ......
#include #include #include #include #include "gdma_app.h"#include <......
关注公众号
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!