gunl

导航

 

http://embexperts.com/redirect.php?tid=43&goto=lastpost

 

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

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

下载 (23.8 KB)
2010-7-23 08:55


主控制器
1> 主控制器的工作是扫描到该设备后顺藤摸瓜,沿着Capabilities List找到MSI中断节点.
PCIE设备MSI <wbr>中断配置流程(转) msi config structure.JPG
下载 (40.86 KB)
2010-7-23 08:55

2> 主控制器给设备上的Address Register和data register俩寄存器赋值(以MPC8548E为例,该值是中断控制器的MSI中断寄存器定义决定);

设备
MSI中断, 本质上是一个内存写事务,该事务的payload部分都由MSI Capabilities 寄存器的值组成。 PCIE设备MSI <wbr>中断配置流程(转) 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, and the 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 节点的根节点。

PCIE设备MSI <wbr>中断配置流程(转) 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;
}
posted on 2011-06-09 22:20  gunl  阅读(4513)  评论(0编辑  收藏  举报