Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Relationship between CPSID instruction and Generic Interrupt Controller on ARM

I am currently trying to understand the relationship between the different ways to mask/disable interrupts on the ARM architecture using either the GIC or the cps instructions.

So far I gathered the following:

  • cps can be used to enable/disable the interrupts for a processor. Using cpsid i disables all interrupts for the processor which issued the instruction (by setting the cpsr register), and using cpsie i enables interrupts. This does not change any state of the Interrupt Distributor or the CPU Interfaces.
  • Specific interrupts can be masked by writing 1 to the corresponding bit in one of the GICD_ICENABLERn registers in the Interrupt Distributor.
  • Specific interrupts can also be disabled by setting no targets in the Interrupt distributor.

Is this understanding correct so far?

Now I am currently unclear how these methods relate to one another. I assume the following:

If interrupts are disabled using the cpsr register, and then any kind of interrupt signaled (no matter if level or edge triggered), then the cpu interface will be notified of the interrupt (assuming it is set as a target), which changes the state of the interrupt to pending. Then as soon as a cpsie i instruction is issued, the processor will switch to interrupt handling.

However, if an interrupt is globally disabled by setting no targets, and an edge triggered interrupt is signaled, the CPU Interface will not change its state. Therefore, if the targets are later changed, the interrupt will not be signaled to any CPU Interface (as the trigger is not active anymore). This would mean, that edge triggered interrupts are lost in this case. For level triggered interrupts, these would only be signaled to the CPU Interfaces, if the interrupt line is still asserted. Is this correct? Or does the Distributor "remember" the state and if the interrupt has been signaled, so that in both cases the interrupt will later be distributed?

Now if the interrupt is masked, again it will not be distributed to any CPU Interface. In that case, however, I would expect the interrupt to be distributed later upon unmasking.

like image 548
LiKao Avatar asked Jan 13 '15 15:01

LiKao


2 Answers

Is this understanding correct so far?

Mainly it is correct. The GIC is a separate block and is intended for multi-CPU designs. The cpsiX instructions are in the ARM core. The GIC is further separated into a global distributor (also known as distribution) and also the per-CPU registers. So in a four core systems, you will have four sets of GIC per-CPU, but only one distributor. The per-core registers are typically mapped to the same address for each core. Of course each core will have a core (and the cpsiX will apply to it).

You can also mask interrupts with per-CPU registers such as GICC_PMR, etc. and possibly with the peripheral register directly (Ie, the Ethernet controller has an interrupt enable which signals the GIC dist -> GIC per-CPU -> ARM core). The last one won't apply if it is an external interrupt. Often many of the GIC SPI are actually wired on-chip/SOC, so you can disable the source.

This would mean, that edge triggered interrupts are lost in this case. For level triggered interrupts, these would only be signaled to the CPU Interfaces, if the interrupt line is still asserted. Is this correct?

This seems generally correct. However, I would look a the specifics of our GIC implementation. Typically, this is gic pl390 or gic pl400. Depending on the GIC version and registers available, the handling of masking, pending, and cancelling can be quite involved. For instance, if a CPU maybe signaled but before it handles the interrupt, another CPU has already read and serviced the interrupt. If you route interrupts to only one CPU, then this doesn't happen. Then there is interrupt priorities and per-empted interrupts. See chapter 3.2.1 Priority drop and interrupt deactivation of the ARM Generic Interrupt Controller - Architecture Specification.

For the edge triggered interrupts, you need to look before re-enabling interrupts (at the distributor level) if the hardware needs to be serviced. The distributor will hold the pending state and if either the cpsie or the per-CPU registers enable is used.

like image 149
artless noise Avatar answered Oct 13 '22 16:10

artless noise


To expand on the "separate block" aspect mentioned in the other answer, an ARM CPU core has a single active-low nIRQ line (and a corresponding nFIQ line). The CPSR bits only control how that core responds to that signal internally - whatever's asserted it is just sat on the other end waiting for some kind of response and has no knowledge of what the core's doing.

Similarly, from the other perspective, whilst the GIC CPU interface is designed with a low-priority interrupt output and a high-priority interrupt output to correspond with an ARM core's nIRQ and nFIQ, there's no reason it couldn't be hooked up to something else (the spec even explicity says this). Thus the GIC architecture has little notion of what the receiver of those signals does with them - cps is entirely irrelevant if there's some custom DSP on the other end, rather than an ARM-architecture core.

like image 42
Notlikethat Avatar answered Oct 13 '22 15:10

Notlikethat