Capability ID 0x5 (MSI)

Updated: May 06, 2022

The MSI capability module enables the use of Message Signalled Interrupts. Use the APIs listed below to configure the MSI capability before enabling them. Specifically, you should check the number of device-supported interrupts and then select the number that you intend to support in the driver. The number of driver supported interrupts must be less than or equal to the number of device-supported interrupts.

You must enable the MSI capability (see pci_device_cfg_cap_enable()) before you call pci_device_read_irq(). When the capability is enabled, bit 2 (Bus Master) of the Command Register is also set. This bit isn't automatically cleared when the capability is disabled.

The MSI and MSI-X capabilities are mutually exclusive. If you want to switch to using MSI on a device that has MSI-X enabled, you must first disable the MSI-X capability (see pci_device_cfg_cap_disable()). Failure to do this will result in an error of PCI_ERR_MSIX_ENABLED.

The MSI capability supports the following APIs, as defined in <pci/cap_msi.h>.

The following APIs allow software to obtain the number of device-supported interrupt sources and to specify the number to actually use :

uint_t cap_msi_get_nirq(pci_cap_t cap)
uint_t cap_msi_get_nirq_isr(pci_cap_t cap)
Returns the number of interrupts supported by the device, or 0 on any error. You can call the *_isr-suffixed version from an ISR.
pci_err_t cap_msi_set_nirq(pci_devhdl_t hdl, pci_cap_t cap, uint_t nirq)
Lets you set the number of interrupts to use. The value must be a power of 2 (up to a maximum of 32) and must be less than or equal to the number of device-supported interrupts.

The following APIs retrieve the interrupt pending/mask values, respectively, if Per Vector Masking (PVM) is supported. The *_isr versions are safe to call from an ISR. If PVM isn't supported, these functions return PCI_ERR_ENOTSUP:

If Per Vector Masking (PVM) is supported, the following APIs let you set or clear the interrupt mask, using a mask value or interrupt entry. The *_isr versions are safe to call from an ISR. If PVM isn't supported, these functions return PCI_ERR_ENOTSUP:

The cap_msi_mask_irq_entry() and cap_msi_unmask_irq_entry() APIs let driver software mask and unmask each of the supported device interrupt sources. These APIs operate only for devices that support the optional Per Vector Masking facility of MSI. They otherwise return PCI_ERR_ENOTSUP.

There's no direct relationship between a device's interrupt entry or the assigned MSI vector and the assigned IRQs returned from pci_device_read_irq(). InterruptMask() and InterruptUnmask() mask and unmask an IRQ, but cap_msi_mask_irq_entry() and cap_msi_unmask_irq_entry() (if supported) mask and unmask the interrupt sources associated with the MSI interrupt entry. You can obtain the number of interrupt sources from cap_msi_get_nirq().

When you call pci_device_read_irq() to retrieve the list of allocated IRQs, the list itself is ordered to correspond with each of the n entries (starting from 0).

For example, suppose that a device supports 32 MSI interrupts, as identified by cap_msi_get_nirq(). Then suppose that only 8 interrupts were allocated, as identified by pci_device_read_irq(). This could be because of system limitations or configuration, or because the driver asked to use only this many in a call to cap_msi_set_nirq(). In this case, the 8 IRQs (0 through 7) returned correspond to MSI entries 0 through 7. If the number of requested and allocated IRQs is the same as the number of supported IRQs, this 1:1 relationship is exactly as you'd expect.

The cap_msi_set_nirq() returns PCI_ERR_EINVAL if you request more interrupts than are supported. Note that this function merely requests that nirq interrupts be used; it isn't until you call pci_device_cfg_cap_enable() that an attempt to allocate the number of requested IRQs is made. Depending on the reqType and the availability of IRQs, pci_device_cfg_cap_enable() either succeeds or fails.

When you're enabling the MSI capability with pci_device_cfg_cap_enable(), the reqType argument has the following meanings for the specific capability APIs. Any capability module APIs not listed here aren't affected by the reqType.

cap_msi_set_nirq()
  • pci_reqType_e_MANDATORY — the requested number of IRQs must be allocated to the device, or the capability won't be enabled, and pci_device_cfg_cap_enable() fails with PCI_ERR_CAP_NIRQ.
  • pci_reqType_e_ADVISORY — an attempt to satisfy the requested number of IRQs will be made, but a lower number may be assigned. The pci_device_cfg_cap_enable() call doesn't fail.
  • pci_reqType_e_UNSPECIFIED — behaves the same as pci_reqType_e_ADVISORY.

Errors that may be returned by pci_device_cfg_cap_enable() from the MSI capability module include:

A note about the ISR safe functions

In certain circumstances, a device being managed by driver software may become temporarily unavailable. This may be due to a bus segment reconfiguration or reset or a hot plug removal. Normally these events are conveyed to the driver prior to their occurrence, but it's possible that previously initiated transactions may result in a interrupt that results in the execution of the ISR functions. In this circumstance, the _isr-suffixed calls return PCI_ERR_DEV_NOT_AVAIL, indicating the temporary unavailability of the device. The ISR must detect this specific error (in addition to any others) and handle it accordingly. Access to the device's registers isn't possible in this condition.