Interrupt subsystem rework
Relatively urgent since this is needed for the UART support on Sue Creek.
The Sue Creek SOF port needs a driver for the DesignWare interrupt controller. While working on that it became apparent, that the current SOF interrupt subsystem isn't flexible enough for cascading interrupt controllers. Below I will describe identified issues and propose a solution. Before that a bit of background: from what I have been able to understand from the sources, the Xtensa architecture uses a 2-level interrupt handling system:
- The lowest level, the so called "DSP interrupts." These are about 25 interrupt vectors, directly recognised by the DSP.
- The second level interrupts. They are described in platform specific "platform/interrupt.h" headers. For the lack of a better term we will call them "level interrupts."
The following issues have been identified:
1. The SOF core design consists of two subsystems - the XTOS and the SOF proper. XTOS implements support for the level 0 DSP interrupts, whereas support for level interrupts is implemented in SOF. This creates 2 different interrupt processing APIs. Ideally I think a single API should be introduced for handling of all interrupts, but it seems, that it is important to keep XTOS as is. So, we probably have to live with the existing XTOS low level interrupt handling.
2. In the SOF interrupt handling framework each interrupt is represented by
struct irq_desc. On many platforms that struct contains an array of 32 list nodes, to be used by up to 32 child interrupts. In most (actually, until now in all) cases interrupts have no children, so, that memory is just wasted.
3. Currently level interrupts are represented by interrupt numbers, which are bitfields with 4 or 5 fields, as created by SOF_IRQ() and SOF_ID_IRQ() macros. One of the fields in those bitfields is the actual hardware interrupt number of this interrupt at its level in the interrupt hierarchy, another field is the interrupt number of the parent DSP interrupt. Obviously, such a bitmask cannot represent further cascading levels, since the parent interrupt won't fit in the 8 bits of the bitfield, dedicated for it. In the bitmask the child IRQ number is located in the upper part of the bitmask and the parent in the lower part. Whereas DSP interrupts are represented just by their IRQ number, which corresponds to the lower bits of the bitmask.
4. Many code paths in the SOF interrupt handling framework make hard assumptions about which type of interrupt they are dealing with to overcome the above confusion about the location of the interrupt number in the 32-bit bitfield.
I propose to rework that in the following way:
- Use different types for IRQ descriptors for interrupt controllers and "ordinary" devices.
- Eliminate IRQ bitfields, make interrupt numbers opaque tokens.
- Unify handling of DSP and level interrupts.
- Add API for registering interrupt controllers. E.g.: IRQ controller drivers could register their controllers per
struct irq_controller *ctrl = rzalloc(); ctrl->parent = parent; ctrl->parent_irq = parent_irq; ctrl->n_irqs = n_irqs; ctrl->ops = ops; int interrupt_controller_register(struct irq_controller *ctrl);
device drivers register their interrupt handlers per
int interrupt_request(struct irq_controller *ctrl, unsigned int hw_irq, void (*handler)(void *arg), void *arg, uint32_t flags);
To address interrupts we can either always use a (controller, hw_irq) pair or we can map those pairs to virtual interrupt numbers. In the latter case the above function would return such a virtual IRQ number. We could also use pointers to irq descriptor objects as virtual IRQ numbers and have
struct irq_desc *interrupt_request(struct irq_controller *ctrl, unsigned int hw_irq, void (*handler)(void *arg), void *arg, uint32_t flags);