Hello,
I face a challenging task: I need to dynamically change the priority of a potentially pending interrupt and make sure the priority change takes effect. "Takes effect" means if the new priority makes the interrupt deliverable, it is delivered. What makes it challenging is the following note in the GICv3 Spec describing the GICR_IPRIORITYRn registers:"Implementations must ensure that an interrupt that is pending at the time of the write uses either the old value or the new value and must ensure that the interrupt is neither lost nor handled more than once. The effect of the change must be visible in finite time."It's basically saying that if the interrupt is already pending, your write to GICR_IPRIORITYRn may not actually affect its priority (because the GIC would "use the old value"), presumably until the interrupt signal is deasserted.How can I make sure the priority change takes effect on the pending interrupt? My focus right now is on level-triggered PPIs, namely the generic timer and PMU interrupts. My current idea is that I "flicker" the interrupt: deassert it, then assert it again. The new assertion should then use the new priority. My code is going to look like this:- Write the new priority to GICR_IPRIORITYn (mapped with Device nGnRnE attributes)- Barrier- Set CNTP_CTL_EL0.IMASK- Clear CNTP_CTL_EL0.IMASK
My questions are:1. Will the GIC see this flicker? The two back-to-back CPU register writes are pretty fast. Do I need to care about GIC level-sensitive interrupt line sampling rate?
2. What kind of barrier do I need? Obviously at least an ISB, do I need a DSB as well?
3. Is even the DSB enough? "The effect of the change must be visible in finite time." Does it mean the priority write is not guaranteed to have taken effect even after the DSB?
4. Am I wasting my time because GIC is simply not designed to support dynamic interrupt priority change?P.S. My code is not written for a particular CPU/GIC model, it needs to work on any future Arm platform. This code is part of a VM context switch, so it must be as fast as possible and avoid any polling, or other kinds of long delays.
Thank you.
Cyril Novikov said:4. Am I wasting my time because GIC is simply not designed to support dynamic interrupt priority change?
You're not wasting your time. The assumption in the spec is that changing priority happens, but not frequently.
To change an INTID's config, and guarantee the old config is no longer visible, you'd need to:
Clearing the individual enable forces the GIC to recall the interrupt if it's pending on a CPU interface somewhere. The RWP bit won't read as 0 until that recall has completed. You can then change the config (target/group/...) knowing the interrupt isn't signal-able.
Without following the sequence above the changes to the config will still take effect - eventually (aka finite time). Setting up a race condition. Now in some cases you might not care about the race, in which case you could skip the disable-reconfig-enable sequence. But if you care, then you should follow the sequence.
Cyril Novikov said: "Takes effect" means if the new priority makes the interrupt deliverable, it is delivered.
That's interesting... do you mean the old/original priority meant it wasn't deliverable?
For example:
In this case the interrupt cannot be signalled due to the PMR (A must be higher priority than the PMR - numerically lower). If you then change the priority of INTID A to 0x00, then you are guaranteed that when (the finite time guarantee in the spec) it gets signalled, then it's with the new priority. As for as long as the old priority applies, it wouldn't be beating the PMR.
Thank you for your answer, Martin. Your suggestion looks solid compared to what I was thinking. The need to poll is not ideal, but I'll measure how long it takes, maybe it's acceptable.Yes, at the VM context switch we would load the new CNT* registers, new PMR, and new PPI priorities according to the incoming VM state. So the timer PPI may remain pending because both the old and the new contexts had it pending, but becomes deliverable because of its new priority. And we don't have control over what the values are. This is for a realtime environment where you not only don't want to interrupt the VM unless the virtual PMR allows it, but also don't want to interrupt the physical CPU, so you set the physical PMR to the guest PMR value. And the physical PPI priorities need to follow the guest ones as well. It's kind of ugly. Can't wait for board manufacturers to start using GICv4.1 where you don't need all this.
Wait, in fact you still need all that because PPIs are not deliverable directly to guest. Oh well.
Update, the entire sequence for all 3 PPIs takes around 1us on my GICv3 (GIC-500). Which is much better than I expected and quite acceptable!