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.
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!