在調試PCI-E的MSI中斷前,,需要先保證將傳統(tǒng)中斷調通,,然后再調試這個。MSI中斷究其本質,,就是一個存儲器讀寫事件,。將MSI Address設置為內存中的某個地址(可以為64位),產(chǎn)生MSI中斷時,,中斷源會在MSI Address所在的地址寫入MSI Data,。也就是說,如果有四條MSI中斷線,,就會依次寫入Data,、Data+1、Data+2、Data+3在內存中,,依次來區(qū)分中斷源設備,。 設備端的定義 設備在自己的配置空間定義了自己的Capabilities list. 如果該設備支持MSI中斷,在此capabilities list其中必定有一個節(jié)點的Capabilities ID=0x5D(0x5D 表明是MSI中斷節(jié)點,,其位置由設備自定義) 主控制器 1> 主控制器的工作是掃描到該設備后順藤摸瓜,沿著Capabilities List找到MSI中斷節(jié)點. 2> 主控制器給設備上的Address Register和data register倆寄存器賦值(以MPC8548E為例,,該值是中斷控制器的MSI中斷寄存器定義決定); 設備 MSI中斷, 本質上是一個內存寫事務,該事務的payload部分都由MSI Capabilities 寄存器的值組成,。 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 節(jié)點的根節(jié)點,。 和傳統(tǒng)中斷在系統(tǒng)初始化掃描PCI bus tree時就已自動為設備分配好中斷號不同,,MSI中斷是在設備驅動程序初始化時調用pci_enable_msi() kernel API 時才分配中斷號的。所以如果使用傳統(tǒng)中斷,,在設備驅動程序中直接調用request_irq(pDev->irq, handler,...) 注冊設備中斷處理函數(shù)即可,。而使用MSI中斷的話,需先調用pci_enable_msi() 初始化設備MSI 結構,,分配MSI中斷號,,并替換INTx中斷號,再調用request_irq(pDev->irq, handler,...) 注冊設備中斷處理函數(shù),。除了卸載中斷處理函數(shù)需要相應地調用pci_diable_msi()外,,其他的處理完全相同。下面的Linux 內核代碼詳細描述了這一過程: int pci_enable_msi(struct pci_dev* dev) status = pci_msi_check_device(dev, 1, PCI_CAP_ID_MSI); WARN_ON(!!dev->msi_enabled); dev_info(&dev->dev, 'can't enable MSI ' '(MSI-X already enabled)\n'); status = msi_capability_init(dev);//此函數(shù)會配置設備MSI結構并分配替換MSI中斷號 static int msi_capability_init(struct pci_dev *dev) pci_intx_for_msi(dev, 0);// disable INTx interrupts
|