Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 054ea4ce authored by Thomas Petazzoni's avatar Thomas Petazzoni Committed by Marc Zyngier
Browse files

irqchip/armada-370-xp: Document the overall driver logic



Since the overall logic of the driver to handle the global and per-CPU
masking of the interrupts is far from trivial, this commit adds a long
comment detailing how the hardware operates and what strategy the
driver implements on top of that.

Acked-by: default avatarGregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: default avatarThomas Petazzoni <thomas.petazzoni@free-electrons.com>
Signed-off-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
parent 9a234c9c
Loading
Loading
Loading
Loading
+80 −0
Original line number Diff line number Diff line
@@ -34,6 +34,86 @@
#include <asm/smp_plat.h>
#include <asm/mach/irq.h>

/*
 * Overall diagram of the Armada XP interrupt controller:
 *
 *    To CPU 0                 To CPU 1
 *
 *       /\                       /\
 *       ||                       ||
 * +---------------+     +---------------+
 * |               |	 |               |
 * |    per-CPU    |	 |    per-CPU    |
 * |  mask/unmask  |	 |  mask/unmask  |
 * |     CPU0      |	 |     CPU1      |
 * |               |	 |               |
 * +---------------+	 +---------------+
 *        /\                       /\
 *        ||                       ||
 *        \\_______________________//
 *                     ||
 *            +-------------------+
 *            |                   |
 *            | Global interrupt  |
 *            |    mask/unmask    |
 *            |                   |
 *            +-------------------+
 *                     /\
 *                     ||
 *               interrupt from
 *                   device
 *
 * The "global interrupt mask/unmask" is modified using the
 * ARMADA_370_XP_INT_SET_ENABLE_OFFS and
 * ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS registers, which are relative
 * to "main_int_base".
 *
 * The "per-CPU mask/unmask" is modified using the
 * ARMADA_370_XP_INT_SET_MASK_OFFS and
 * ARMADA_370_XP_INT_CLEAR_MASK_OFFS registers, which are relative to
 * "per_cpu_int_base". This base address points to a special address,
 * which automatically accesses the registers of the current CPU.
 *
 * The per-CPU mask/unmask can also be adjusted using the global
 * per-interrupt ARMADA_370_XP_INT_SOURCE_CTL register, which we use
 * to configure interrupt affinity.
 *
 * Due to this model, all interrupts need to be mask/unmasked at two
 * different levels: at the global level and at the per-CPU level.
 *
 * This driver takes the following approach to deal with this:
 *
 *  - For global interrupts:
 *
 *    At ->map() time, a global interrupt is unmasked at the per-CPU
 *    mask/unmask level. It is therefore unmasked at this level for
 *    the current CPU, running the ->map() code. This allows to have
 *    the interrupt unmasked at this level in non-SMP
 *    configurations. In SMP configurations, the ->set_affinity()
 *    callback is called, which using the
 *    ARMADA_370_XP_INT_SOURCE_CTL() readjusts the per-CPU mask/unmask
 *    for the interrupt.
 *
 *    The ->mask() and ->unmask() operations only mask/unmask the
 *    interrupt at the "global" level.
 *
 *    So, a global interrupt is enabled at the per-CPU level as soon
 *    as it is mapped. At run time, the masking/unmasking takes place
 *    at the global level.
 *
 *  - For per-CPU interrupts
 *
 *    At ->map() time, a per-CPU interrupt is unmasked at the global
 *    mask/unmask level.
 *
 *    The ->mask() and ->unmask() operations mask/unmask the interrupt
 *    at the per-CPU level.
 *
 *    So, a per-CPU interrupt is enabled at the global level as soon
 *    as it is mapped. At run time, the masking/unmasking takes place
 *    at the per-CPU level.
 */

/* Registers relative to main_int_base */
#define ARMADA_370_XP_INT_CONTROL		(0x00)
#define ARMADA_370_XP_SW_TRIG_INT_OFFS		(0x04)