]> rtime.felk.cvut.cz Git - jailhouse.git/commitdiff
arm: Rework interrupt affinity management on cell creation
authorJan Kiszka <jan.kiszka@siemens.com>
Mon, 27 Jun 2016 06:41:14 +0000 (08:41 +0200)
committerJan Kiszka <jan.kiszka@siemens.com>
Mon, 27 Jun 2016 09:51:18 +0000 (11:51 +0200)
So far, we only ensured that the affinities of interrupts given to new
cells match with the corresponding CPU set. However, we also need to
check that Linux properly adjusted the affinity of all its remaining
interrupts properly.

This introduces a new irqchip callback adjust_irq_target which performs
the check and the potential adjustment to the first CPU of a cell on a
per-interrupt basis. A single loop in irqchip_cell_init triggers them.
gic_target_spis and gic_route_spis become obsolete.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
hypervisor/arch/arm/gic-common.c
hypervisor/arch/arm/gic-v2.c
hypervisor/arch/arm/gic-v3.c
hypervisor/arch/arm/include/asm/gic_common.h
hypervisor/arch/arm/include/asm/irqchip.h
hypervisor/arch/arm/irqchip.c

index 5d0eed86d5a2fc61cd81fb7bb053fabf1ac36698..60aa6fe560c5a04043cd31a8877be836d609767a 100644 (file)
@@ -31,7 +31,7 @@ extern unsigned int gicd_size;
 static DEFINE_SPINLOCK(dist_lock);
 
 /* The GIC interface numbering does not necessarily match the logical map */
-static u8 target_cpu_map[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+u8 target_cpu_map[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
 
 /* Check that the targeted interface belongs to the cell */
 bool gic_targets_in_cell(struct cell *cell, u8 targets)
@@ -344,40 +344,3 @@ void gic_handle_irq(struct per_cpu *cpu_data)
                irqchip_eoi_irq(irq_id, handled);
        }
 }
-
-void gic_target_spis(struct cell *config_cell, struct cell *dest_cell)
-{
-       unsigned int i, first_cpu, cpu_itf;
-       unsigned int shift = 0;
-       void *itargetsr = gicd_base + GICD_ITARGETSR;
-       u32 targets;
-       u32 mask = 0;
-       u32 bits = 0;
-
-       /* Always route to the first logical CPU on reset */
-       for_each_cpu(first_cpu, dest_cell->cpu_set)
-               break;
-
-       cpu_itf = target_cpu_map[first_cpu];
-
-       /* ITARGETSR0-7 contain the PPIs and SGIs, and are read-only. */
-       itargetsr += 4 * 8;
-
-       for (i = 0; i < 64; i++, shift = (shift + 8) % 32) {
-               if (irqchip_irq_in_cell(config_cell, 32 + i)) {
-                       mask |= (0xff << shift);
-                       bits |= (cpu_itf << shift);
-               }
-
-               /* ITARGETRs have 4 IRQ per register */
-               if ((i + 1) % 4 == 0) {
-                       targets = mmio_read32(itargetsr);
-                       targets &= ~mask;
-                       targets |= bits;
-                       mmio_write32(itargetsr, targets);
-                       itargetsr += 4;
-                       mask = 0;
-                       bits = 0;
-               }
-       }
-}
index 9d1d311ef49e2aa7169680da8e4015a316efafac..a4ca99c113b6b56bd330573f8f9b83f2c52b914b 100644 (file)
@@ -181,15 +181,6 @@ static int gic_cell_init(struct cell *cell)
 {
        int err;
 
-       /*
-        * target_cpu_map has not been populated by all available CPUs when the
-        * setup code initialises the root cell. It is assumed that the kernel
-        * already has configured all its SPIs anyway, and that it will redirect
-        * them when unplugging a CPU.
-        */
-       if (cell != &root_cell)
-               gic_target_spis(cell, cell);
-
        /*
         * Let the guest access the virtual CPU interface instead of the
         * physical one.
@@ -218,6 +209,21 @@ static void gic_cell_exit(struct cell *cell)
                       PAGING_NON_COHERENT);
 }
 
+static void gic_adjust_irq_target(struct cell *cell, u16 irq_id)
+{
+       void *itargetsr = gicd_base + GICD_ITARGETSR + (irq_id & ~0x3);
+       u32 targets = mmio_read32(itargetsr);
+       unsigned int shift = irq_id % 4;
+
+       if (gic_targets_in_cell(cell, (u8)(targets >> shift)))
+               return;
+
+       targets &= ~(0xff << shift);
+       targets |= target_cpu_map[first_cpu(cell->cpu_set)] << shift;
+
+       mmio_write32(itargetsr, targets);
+}
+
 static int gic_send_sgi(struct sgi *sgi)
 {
        u32 val;
@@ -304,6 +310,7 @@ struct irqchip_ops irqchip = {
        .cpu_reset = gic_cpu_reset,
        .cell_init = gic_cell_init,
        .cell_exit = gic_cell_exit,
+       .adjust_irq_target = gic_adjust_irq_target,
 
        .send_sgi = gic_send_sgi,
        .handle_irq = gic_handle_irq,
index 8d076f9759225612c2f89586f05c3817d894d587..25e560dea92547c1cf0aee883fe932a844b1e6f5 100644 (file)
@@ -202,19 +202,13 @@ static int gic_cpu_init(struct per_cpu *cpu_data)
        return 0;
 }
 
-static void gic_route_spis(struct cell *config_cell, struct cell *dest_cell)
+static void gic_adjust_irq_target(struct cell *cell, u16 irq_id)
 {
-       int i;
-       void *irouter = gicd_base + GICD_IROUTER;
-       unsigned int first_cpu;
-
-       /* Use the core functions to retrieve the first physical id */
-       for_each_cpu(first_cpu, dest_cell->cpu_set)
-               break;
+       void *irouter = gicd_base + GICD_IROUTER + irq_id;
+       u32 route = mmio_read32(irouter);
 
-       for (i = 0; i < 64; i++, irouter += 8)
-               if (irqchip_irq_in_cell(config_cell, 32 + i))
-                       mmio_write64(irouter, first_cpu);
+       if (!cell_owns_cpu(cell, route))
+               mmio_write32(irouter, first_cpu(cell->cpu_set));
 }
 
 static enum mmio_result gic_handle_redist_access(void *arg,
@@ -273,8 +267,6 @@ static enum mmio_result gic_handle_redist_access(void *arg,
 
 static int gic_cell_init(struct cell *cell)
 {
-       gic_route_spis(cell, cell);
-
        mmio_region_register(cell, (unsigned long)gicd_base, gicd_size,
                             gic_handle_dist_access, NULL);
        mmio_region_register(cell, (unsigned long)gicr_base, gicr_size,
@@ -448,6 +440,7 @@ struct irqchip_ops irqchip = {
        .cpu_init = gic_cpu_init,
        .cpu_reset = gic_cpu_reset,
        .cell_init = gic_cell_init,
+       .adjust_irq_target = gic_adjust_irq_target,
        .send_sgi = gic_send_sgi,
        .handle_irq = gic_handle_irq,
        .inject_irq = gic_inject_irq,
index 162595363a879e7926a037ee351f4ccfdcc4e0fd..df43b973d89e575e26433913b8e025560e3adfcc 100644 (file)
@@ -17,6 +17,7 @@
 #include <jailhouse/types.h>
 
 #define GICD_CTLR                      0x0000
+# define GICD_CTLR_ARE_NS              (1 << 4)
 #define GICD_TYPER                     0x0004
 #define GICD_IIDR                      0x0008
 #define GICD_IGROUPR                   0x0080
@@ -48,13 +49,14 @@ struct arm_mmio_access;
 struct per_cpu;
 struct sgi;
 
+extern u8 target_cpu_map[];
+
 int gic_probe_cpu_id(unsigned int cpu);
 enum mmio_result gic_handle_dist_access(void *arg, struct mmio_access *mmio);
 enum mmio_result gic_handle_irq_route(struct mmio_access *mmio,
                                      unsigned int irq);
 void gic_handle_sgir_write(struct sgi *sgi, bool virt_input);
 void gic_handle_irq(struct per_cpu *cpu_data);
-void gic_target_spis(struct cell *config_cell, struct cell *dest_cell);
 bool gic_targets_in_cell(struct cell *cell, u8 targets);
 
 #endif /* !__ASSEMBLY__ */
index eb78a582cb2cf396525222016d1bd53566392ca9..eb4c25eb0ce8bdead699f0106b265c84a74903fe 100644 (file)
@@ -45,6 +45,7 @@ struct irqchip_ops {
        int     (*cell_init)(struct cell *cell);
        void    (*cell_exit)(struct cell *cell);
        int     (*cpu_reset)(struct per_cpu *cpu_data, bool is_shutdown);
+       void    (*adjust_irq_target)(struct cell *cell, u16 irq_id);
 
        int     (*send_sgi)(struct sgi *sgi);
        void    (*handle_irq)(struct per_cpu *cpu_data);
index ef017913e96bfd066e080ead0fc5b12ced8e8a4b..a6fce0104af48adc287a360d570e26545a683cf3 100644 (file)
@@ -176,7 +176,7 @@ int irqchip_cell_init(struct cell *cell)
        if (err)
                return err;
 
-       if (cell != &root_cell)
+       if (cell != &root_cell) {
                for_each_irqchip(chip, cell->config, n) {
                        if (chip->address != (unsigned long)gicd_base)
                                continue;
@@ -185,6 +185,14 @@ int irqchip_cell_init(struct cell *cell)
                                        ~chip->pin_bitmap[pos];
                }
 
+               for (n = 32; n < sizeof(cell->arch.irq_bitmap) * 8; n++) {
+                       if (irqchip_irq_in_cell(cell, n))
+                               irqchip.adjust_irq_target(cell, n);
+                       if (irqchip_irq_in_cell(&root_cell, n))
+                               irqchip.adjust_irq_target(&root_cell, n);
+               }
+       }
+
        return 0;
 }