I've analysed the axi_pcie.vhd module in the original Xilinx IP core, and I have found, that:
- The msi_vector_num is delayed together with the intx_msi_request.
- The delayed msi_vector_num is read when the rising edge of the delayed intx_msi_request is detected. Therefore, the msi_vector_num value is important only in that cycle, in which the intx_msi_request is set to 1.
- After the the delayed msi_vector_num is read, the state machine changes its state to INTR_HS. In that state it ignores further changes of intx_msi_request and msi_vector_num. The machine leaves that state only, when sig_blk_interrupt_rdy is asserted. However, it is important, that intx_msi_request goes low before INTR_HS state is left (it is OK to set it high only for one cycle).
- As delayed signals msi_vector_num and intx_msi_request are used, it is safe to set the new value of mis_vector_num and to assert intx_msi_reuqest in the same cycle in which the intx_msi_grant was set to '1'.
However, the above scheme of interrupt handling rises one more question.
How masking of interrupts is handled?
In case of legacy interrupts, it is easy. When my device requires service, it keeps the IRQ line asserted.
If the interrupt is masked, the host CPU will not be interrupted. Of course the device may be serviced in another way (e.g., via polling). So it may h appen that even though interrupt was masked, the irq line may get deasserte d.
When the interrupt gets unmasked, the interrupt will be generated only if t he irq line is still asserted.
Now, in the MSI handling scheme implemented in the AXI MM 2 PCIe, it is unc lear how the masking is handled.
The user IP core should assert intx_msi_request for one clock cycle, and wa it until intx_msi_grant is asserted (also for one cycle).
What happens if the interrupt is masked? Will the intx_msi_grant be never a sserted? So the core will wait forever and other MSI interrupts can't be po sted - obviously bad solution.
If the core asserts intx_msi_granted, even if the interrupt is masked, then of course next MSI interrupts may be posted, but what will be the state of the current interrupt?
Will it be remembered as active, and the appropriate ISR will be executed b y the host CPU, when the interrupt is unmasked?
However, what if the device is serviced by polling, and it does not require servicing any more?
One of main advantages of MSI(X) interrupts is that I don't need to check t he status of the device at the beginig of my ISR to ensure that my device r equires servicing. With that behavior I still have to do it!
OK. So what if the masked interrupt is confirmed (by intx_msi_granted) but silently dropped. In that case it is even worse, because my IP core assumes that the interrupt was successfully posted and ISR will be executed, which will never happen. So if that solution is implemented, my IP core should r esend the interrupt periodically until it is finally serviced. So we get an other crazy situation, where the peripheral must poll the PCIe host.
I hope that I've mistaken in the above analysis. If not, it seems that hand ling of MSI interrupts is somehow broken...
I'll be glad if someone explains how it is really handled.
Thank you in advance, Best regards, Wojtek