How to generate LPI with ITS?

Hello, I am currently conducting LPI(generic MSI) testing using a dummy device in the kernel.
The environment supports kernel version 6.12.y and GIC-600 / ITS.

I'd like to share the tests I have performed with Trace32 so far, and I have a question I'd like to ask.
I created a dummy device driver in the kernel and registered the device using the device tree.
Then, by referring to the document "Learn the architecture – Generic Interrupt Controller v3 and v4, LPIs", I successfully generated an ITS LPI.

After the kernel boots, the relevant register values are as follows:
On the left are the ITS CBASER, CWRITER, and CREADR registers,
and on the right is a dump of the ITS command queue.
The initial values of the command queue pointers are as follows:
CWRITER: 0x5C0
CREADR: 0x5C0

The DeviceID of the registered dummy device is 1.
Following the implementation guide, I issued the INV(1, 0) and INT(1, 0) commands to verify the interrupt.


Sequence:

B::Data.Set ANSD:0x1A05605C0 %LE %Quad 0x10000000C // INV(1, 0)
B::Data.Set ANSD:0x17640088 %LE %Quad 0x5E0 // Update CWRITER
B::Data.Set ANSD:0x1A05605E0 %LE %Quad 0x100000003 // INT(1, 0)
B::Data.Set ANSD:0x17640088 %LE %Quad 0x600 // Update CWRITER


then, check Ack of interrupt by reading ICC_IAR1_EL1 (Disable All system counters)

  (pINTID: 8192)

And, run "B:: Go"

I have finally succeeded in triggering the LPI interrupt handler!


However, this was verified using the ITS command,

and what I would really like to do is confirm the interrupt by writing a value to the GITS_TRANSLATER register during actual device operation.

I have a few questions regarding this:

  1. When using the ITS INT command, does it not update the LPI pending table in the GICR? I was not able to observe any updates..

  2. If I were to replace the INT(1, 0) command with writing data directly to GITS_TRANSLATER, what value should be written to this register?
    I tried writing a value to GITS_TRANSLATER in PCIe BDF format, but it was unsuccessful.
    I tried I wrote the value of (1 << 11.)

Thank you.

  • what I would really like to do is confirm the interrupt by writing a value to the GITS_TRANSLATER register during actual device operation.

    That's a little trickier than it sounds.  The summary is that the GIC spec does not expect software to ever directly write GITS_TRANSLATER - but rather that only devices will do so.

    To recap, MSIs arrive at GITS_TRANSLATER in the form of a write.  The MSI contains two pieces of information, the DeviceID (sender) and the EventID (which of the sender's events is being signalled).  The EventID is just the payload of the write. However, the DeviceID is (typically) a side-band signal, as intended not the be spoof-able/controllable.  That is, DeviceID will always reflect who did the write.  That introduces two problems.

    First, the processor might simply be unable to reach GITS_TRANSLATER with writes.  The register is intended to be written by devices, not the processor - so the memory system of your SoC might not have a path from the processor(s) to GITS_TRANSLATER.  Second, even if you can write the register, you'd need to know what the DeviceID of the processor is - that'll be SoC specific.

    This is one of the reasons the INT command exists - it's the alternative to writing GIT_TRANSLATER.

    The alternative is you find an MSI or DMA capable device, for which you know the DeviceID, and work with that.

    When using the ITS INT command, does it not update the LPI pending table in the GICR? I was not able to observe any updates.

    Yes and no.  Assuming the DeviceID+EventID in the INT (or MSI) translates to a valid LPI INTID, it will be update that INTID's Pending State.  LPI pending state is stored in the LPI Pending Table, however there's a good chance you won't be able to observe the update in memory.  The GIC is permitted to cache the table and typically would only update memory if it has to spill from its caches (which it would try to avoid) or if you're turning the RD off.