-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Kernel: Add MSIx interrupt mechanism for PCI devices #18580
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly style comments, exciting changes!
I will look into this today or tomorrow. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Besides my comment on that explicit
keyword, this looks wonderful!
I was not sure about the whole PCIIRQHandler
thing, but it does seem correct to me, so let's try this out and if we happen to have something better we can always fix this :)
f9a53f6
to
f65d4a6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just two more things
c049cc3
to
f9a1cb3
Compare
Pin-based PCI device are allocated an IRQ, and it could be shared with multiple devices. An interrupt handler with an IRQ for a PCI device will get registered only during the driver initialization. For MSI(x) interrupts, the driver has to allocate IRQs and this field can be used to skip IRQs that have already been reserved by pin-based interrupts so that we don't have to share IRQs, which generally will reduce the performance.
Set pin-based interrupt handler as reserved during PCI bus init. This is required so that MSI(x) based interrupts can avoid sharing the IRQ which has been marked as reserved.
MSI(x) interrupts need to reserve IRQs so that it can be programmed by the device. Add an API to reserve contiguous ranges of interrupt handlers so that it can used by PCI devices that use MSI(x) mechanism. This API needs to be implemented by aarch64 architecture.
MSI(x) mechanism requires the device to write to its Capability structure. Add write{8,16,32} similar to read{8,16,32}.
Add a struct named MSIxInfo that stores all the relevant MSIx information as a part of PCI DeviceIdentifier struct. Populate the MSIx struct during the PCI device init. As the DeviceIdentifier struct need to populate MSIx info, don't mark DeviceIdentifier as const in the PCI::Device class.
Instead of iterating through the capabilities, use the is_msix_capable() API from the PCIIdentifier class that belongs to the device.
Implement enabling and disabling MSIx interrupts for a PCI device. Removes two TODO()s from PCI::Device.cpp :^)
MSIx table entry is used to program interrupt vectors and it is architecture specific. Add helper functions declaration in Arch/PCIMSI.h. The definition of the function is placed in the respective arch specific code.
Add reserve_irqs, allocate_irq, enable_interrupt and disable_interrupt API to a PCI device. reserve_irqs() can be used by a device driver that would like to reserve irqs for MSI(x) interrupts. The API returns the type of IRQ that was reserved by the PCI device. If the PCI device does not support MSI(x), then it is a noop. allocate_irq() API can be used to allocate an IRQ at an index. For MSIx the driver needs to map the vector table into the memory and add the corresponding IRQ at the given index. This API will return the actual IRQ that was used so that the driver can use it create interrupt handler for that IRQ. {enable, disable}_interrupt API is used to enable or disable a particular IRQ at the given index. It is a noop for pin-based interrupts. This could be used by IRQHandler to enable or disable an interrupt.
@Panky-codes result of running
|
PCIIRQHandler is a generic IRQ handler that the device driver can inherit to use either Pin or MSI(x) based interrupt mechanism. The PCIIRQHandler can do what the existing IRQHandler can do for pin based interrupts but also deal with MSI based interrupts. We can hopefully convert all the PCI based devices to use this handler so that MSI(x) can be used.
Add an explicit QueueType enum which could be used to create a poll or an interrupt queue. This is better than passing an Optional<irq>. This refactoring is in preparation for adding MSIx support to NVMe.
This is in preparation for adding MSI(x) support to the NVMe device. NVMeInterruptQueue needs access to the PCI device to deal with MSI(x) interrupts. It is ok to pass the NVMeController as a reference to the NVMeQueue as NVMeController is the one that owns the NVMeQueue. This is very similar to how AHCIController passes its reference to its interrupt handler.
Add MSIx support to NVMe. Prefer MSIx over pin-based interrupts as they are more efficient and all modern hardware support them.
Now we support MSIx for NVMe. Retain the information about using nvme_poll until MSIx is tested on a Bare metal system.
Thanks for the report @gmta . I missed one place to check for null ptr in PCIIRQHandler. Updated the code to return |
Thanks @Panky-codes, that fixed it! |
This adds support to MSI(x) based interrupt mechanism, an alternative to pin-based interrupts.
The first 10 commits add the necessary infrastructure to use MSIx interrupt mechanism. The next three commits add MSIx support to the NVMe device. This PR only adds MSIx support. TODOs have been added for the old MSI-based interrupts which could be extended later.
Test:
Trace from QEMU for the NVMe device: