Before debugging the MSI interrupt of the PCI-E, you need to ensure that the traditional interrupt is called, and then DEBUG this. Msi interruption is essentially a memory read/write event. Set the MSI address to an address in the memory (which can be 64-bit). When an MSI interruption occurs, the interrupt source will write the MSI data to the address of the MSI address. That is to say, if there are four MSI disconnections, data, data + 1, data + 2, and data + 3 will be written in the memory in sequence to differentiate the interrupt source device.
Device Definition
The device defines its capabilities list in its own configuration space. if the device supports MSI interruption, the capabilities ID of one node in the capabilities list must be 0x5d (0x5d indicates that the node is an MSI interrupt node and its location is customized by the device)
Master Controller
1> the main controller scans the device and finds the MSI interrupt node along the capabilities list.
2> the master controller assigns values to the address register and data register registers on the device (taking the mpc8548e as an example, which is determined by the definition of the MSI interrupt register of the interrupt controller );
Device
An MSI interrupt is essentially a memory write transaction. The payload part of the transaction is composed of the value of the MSI capabilities register.
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.
The capabilites list pointer is located at the 0x34 offset of config space. It is the root node of all capabilities nodes.
Unlike the traditional interrupt, which is automatically assigned with an interrupt number when the system initializes and scans the PCI bus tree, the MSI interrupt calls pci_enable_msi () during device driver initialization () the interrupt number is allocated only when the kernel API is used. Therefore, if you use the traditional interrupt function, you can directly call request_irq (pdev-> IRQ, handler,...) in the device driver to register the device interrupt handler function. If an MSI interrupt is used, call pci_enable_msi () first ()
Initialize the device MSI structure, assign the MSI interrupt number, replace the intx interrupt number, and then call request_irq (pdev-> IRQ, handler,...) to register the device interrupt handler. In addition to detaching the interrupt handler function, call pci_diable_msi (). Other operations are identical. The following Linux kernel code describes the process in detail:
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); // This function configures the device MSI structure and assigns replacement for the MSI interrupt number} static int msi_capability_init (struct pci_dev * Dev) {struct msi_desc * entry; int POs, RET; 2010control ;...... 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 ;}