PCIE设备MSI 中断配置流程

来源:互联网 发布:未来软件怎么样 编辑:程序博客网 时间:2024/05/19 01:08

PCI 主控制器如何配置设备
设备端的定义

设备在自己的配置空间定义了自己的Capabilities list. 如果该设备支持MSI中断,在此capabilities list其中必定有一个节点的Capabilities ID=0x5D(0x5D 表明是MSI中断节点,其位置由设备自定义).
capabilities list.JPG



主控制器
1> 主控制器的工作是扫描到该设备后顺藤摸瓜,沿着Capabilities List找到MSI中断节点.
msi config structure.JPG
2> 主控制器给设备上的Address Register和data register俩寄存器赋值(以MPC8548E为例,该值是中断控制器的MSI中断寄存器定义决定);

设备
MSI中断, 本质上是一个内存写事务,该事务的payload部分都由MSI Capabilities 寄存器的值组成。 format.JPG
下载 (51.18 KB)
2010-7-23 09:12

 

本帖最后由 bingquan 于 2010-8-17 12:16 编辑

The key points here are:
1> Device prepare the capabilities list and the MSI node
2> Controller assign a value to the address register, which is inside the MSI capability node, andthe value assigned is the kernel virtual address of the MSI interrupt description register inside the interrupt controller.
3> As well, the value assigned to the data register is defined by the MSI registers inside the interrupt controller.

 

 

Capabilites list 指针位于config space的 0x34 偏移量处,它是所有capabilities 节点的根节点。

capabilities PTR.png

 

本帖最后由 bingquan 于 2010-8-17 21:02 编辑

和传统中断在系统初始化扫描PCI bus tree时就已自动为设备分配好中断号不同,MSI中断是在设备驱动程序初始化时调用pci_enable_msi() kernel API 时才分配中断号的。所以如果使用传统中断,在设备驱动程序中直接调用request_irq(pDev->irq, handler,...) 注册设备中断处理函数即可。而使用MSI中断的话,需先调用pci_enable_msi() 初始化设备MSI 结构,分配MSI中断号,并替换INTx中断号,再调用request_irq(pDev->irq, handler,...) 注册设备中断处理函数。除了卸载中断处理函数需要相应地调用pci_diable_msi()外,其他的处理完全相同。下面的Linux 内核代码详细描述了这一过程

int pci_enable_msi(struct pci_dev* dev)
{
    int status;

    status = pci_msi_check_device(dev, 1, PCI_CAP_ID_MSI);
    if (status)
        return status;

    WARN_ON(!!dev->msi_enabled);

   
    if (dev->msix_enabled) {
        dev_info(&dev->dev, "can't enable MSI "
             "(MSI-X already enabled)\n");
        return -EINVAL;
    }
    status = msi_capability_init(dev);//此函数会配置设备MSI结构并分配替换MSI中断号
}

static int msi_capability_init(struct pci_dev *dev)
{
    struct msi_desc *entry;
    int pos, ret;
    u16 control;
    ......
    msi_set_enable(dev, 0);
   
    pci_intx_for_msi(dev, 0);// disable INTx interrupts   
    msi_set_enable(dev, 1);
    dev->msi_enabled = 1;

    dev->irq = entry->irq;   
    return 0;
}
0 0
原创粉丝点击