Traditional PCI devices use a shared interrupt line to signal the CPU when they need attention. This can lead to performance issues as all the devices that are connected to the interrupt line need to invoke their interrupt handler. Message Signalled Interrupts (MSI) was developed to address these problems by providing a more efficient and scalable way of handling interrupts.

MSI were introduced as a part of PCI 2.2, and it works by allowing the device to send an interrupt message directly to the CPU through the PCI bus. When the CPU receives the message, it knows exactly which device generated the interrupt and can handle it accordingly. This reduces interrupt latency and helps to avoid conflicts between devices that share the same interrupt line.

The following image shows how E1000NetworkAdapter and NVMe device are sharing the same interrupt line (10) when using the traditional pin-based interrupts:

IOAPIC \label{classdiag}
E1000NetworkAdapter and NVMe sharing the same interrupt line

MSI can solve this problem by not sharing the same interrupt line. I decided add support for MSI and MSIx interrupt mechanism as SerenityOS was lacking those features.

In pin-based interrupt mechanism, the driver reads the interrupt line field in the PCI header and uses that to program the interrupt handler. For MSI based interrupts, the driver has to program the device with an IRQ number that it wants the device to trigger when an interrupt occurs. As serenity always used pin-based interrupts, new APIs were introduced to make MSI(x) work.

The PRs can be found here:

Pull Request: MSIx

Pull Request: MSI. Check out MSIx PR before seeing this PR as I added MSIx support first.

MSI \label{classdiag}
NVMe using MSIx without sharing the interrupt line

Additional resources:

Please check out the osdev article and the intel software manual chapter 11 for more information. Even though they were good documentation, I missed some information when I was implementing this feature. I also used Linux source code and Haiku OS source code to reverse engineer how this feature is implemented.

Happy Hacking!