As we run the GICv3 only in affinity mode, access to ITARGETSR can be
ignored, and the existing handle_irq_target can become GICv2-only.

Signed-off-by: Jan Kiszka <[email protected]>
---
 hypervisor/arch/arm-common/gic-common.c          | 74 +-----------------------
 hypervisor/arch/arm-common/gic-v2.c              | 74 +++++++++++++++++++++++-
 hypervisor/arch/arm-common/include/asm/gic.h     |  3 +
 hypervisor/arch/arm-common/include/asm/irqchip.h |  3 +
 hypervisor/arch/arm-common/irqchip.c             |  2 -
 hypervisor/arch/arm/gic-v3.c                     |  8 +++
 6 files changed, 89 insertions(+), 75 deletions(-)

diff --git a/hypervisor/arch/arm-common/gic-common.c 
b/hypervisor/arch/arm-common/gic-common.c
index 67dac8b..0fef774 100644
--- a/hypervisor/arch/arm-common/gic-common.c
+++ b/hypervisor/arch/arm-common/gic-common.c
@@ -24,7 +24,7 @@
 #define REG_RANGE(base, n, size)               \
                (base) ... ((base) + (n - 1) * (size))
 
-static DEFINE_SPINLOCK(dist_lock);
+DEFINE_SPINLOCK(dist_lock);
 
 /* The GICv2 interface numbering does not necessarily match the logical map */
 u8 gicv2_target_cpu_map[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
@@ -103,76 +103,6 @@ restrict_bitmask_access(struct mmio_access *mmio, unsigned 
int reg_index,
        return MMIO_HANDLED;
 }
 
-/*
- * GICv2 uses 8bit values for each IRQ in the ITARGETRs registers
- */
-static enum mmio_result handle_irq_target(struct mmio_access *mmio,
-                                         unsigned int irq)
-{
-       /*
-        * ITARGETSR contain one byte per IRQ, so the first one affected by this
-        * access corresponds to the reg index
-        */
-       unsigned int irq_base = irq & ~0x3;
-       struct cell *cell = this_cell();
-       unsigned int offset;
-       u32 access_mask = 0;
-       unsigned int n;
-       u8 targets;
-
-       /*
-        * Let the guest freely access its SGIs and PPIs, which may be used to
-        * fill its CPU interface map.
-        */
-       if (!is_spi(irq)) {
-               mmio_perform_access(gicd_base, mmio);
-               return MMIO_HANDLED;
-       }
-
-       /*
-        * The registers are byte-accessible, but we always do word accesses.
-        */
-       offset = irq % 4;
-       mmio->address &= ~0x3;
-       mmio->value <<= 8 * offset;
-       mmio->size = 4;
-
-       for (n = 0; n < 4; n++) {
-               if (irqchip_irq_in_cell(cell, irq_base + n))
-                       access_mask |= 0xff << (8 * n);
-               else
-                       continue;
-
-               if (!mmio->is_write)
-                       continue;
-
-               targets = (mmio->value >> (8 * n)) & 0xff;
-
-               if (!gic_targets_in_cell(cell, targets)) {
-                       printk("Attempt to route IRQ%d outside of cell\n",
-                              irq_base + n);
-                       return MMIO_ERROR;
-               }
-       }
-
-       if (mmio->is_write) {
-               spin_lock(&dist_lock);
-               u32 itargetsr =
-                       mmio_read32(gicd_base + GICD_ITARGETSR + irq_base);
-               mmio->value &= access_mask;
-               /* Combine with external SPIs */
-               mmio->value |= (itargetsr & ~access_mask);
-               /* And do the access */
-               mmio_perform_access(gicd_base, mmio);
-               spin_unlock(&dist_lock);
-       } else {
-               mmio_perform_access(gicd_base, mmio);
-               mmio->value &= access_mask;
-       }
-
-       return MMIO_HANDLED;
-}
-
 static enum mmio_result handle_sgir_access(struct mmio_access *mmio)
 {
        struct sgi sgi;
@@ -269,7 +199,7 @@ enum mmio_result gic_handle_dist_access(void *arg, struct 
mmio_access *mmio)
                break;
 
        case REG_RANGE(GICD_ITARGETSR, 1024, 1):
-               ret = handle_irq_target(mmio, reg - GICD_ITARGETSR);
+               ret = irqchip.handle_irq_target(mmio, reg - GICD_ITARGETSR);
                break;
 
        case REG_RANGE(GICD_ICENABLER, 32, 4):
diff --git a/hypervisor/arch/arm-common/gic-v2.c 
b/hypervisor/arch/arm-common/gic-v2.c
index c3d8581..51c5c7e 100644
--- a/hypervisor/arch/arm-common/gic-v2.c
+++ b/hypervisor/arch/arm-common/gic-v2.c
@@ -11,7 +11,7 @@
  */
 
 #include <jailhouse/control.h>
-#include <jailhouse/mmio.h>
+#include <jailhouse/printk.h>
 #include <asm/gic.h>
 #include <asm/irqchip.h>
 #include <asm/setup.h>
@@ -291,6 +291,76 @@ enum mmio_result gic_handle_irq_route(struct mmio_access 
*mmio,
        return MMIO_HANDLED;
 }
 
+/*
+ * GICv2 uses 8bit values for each IRQ in the ITARGETSR registers
+ */
+static enum mmio_result gic_handle_irq_target(struct mmio_access *mmio,
+                                             unsigned int irq)
+{
+       /*
+        * ITARGETSR contain one byte per IRQ, so the first one affected by this
+        * access corresponds to the reg index
+        */
+       unsigned int irq_base = irq & ~0x3;
+       struct cell *cell = this_cell();
+       unsigned int offset;
+       u32 access_mask = 0;
+       unsigned int n;
+       u8 targets;
+
+       /*
+        * Let the guest freely access its SGIs and PPIs, which may be used to
+        * fill its CPU interface map.
+        */
+       if (!is_spi(irq)) {
+               mmio_perform_access(gicd_base, mmio);
+               return MMIO_HANDLED;
+       }
+
+       /*
+        * The registers are byte-accessible, but we always do word accesses.
+        */
+       offset = irq % 4;
+       mmio->address &= ~0x3;
+       mmio->value <<= 8 * offset;
+       mmio->size = 4;
+
+       for (n = 0; n < 4; n++) {
+               if (irqchip_irq_in_cell(cell, irq_base + n))
+                       access_mask |= 0xff << (8 * n);
+               else
+                       continue;
+
+               if (!mmio->is_write)
+                       continue;
+
+               targets = (mmio->value >> (8 * n)) & 0xff;
+
+               if (!gic_targets_in_cell(cell, targets)) {
+                       printk("Attempt to route IRQ%d outside of cell\n",
+                              irq_base + n);
+                       return MMIO_ERROR;
+               }
+       }
+
+       if (mmio->is_write) {
+               spin_lock(&dist_lock);
+               u32 itargetsr =
+                       mmio_read32(gicd_base + GICD_ITARGETSR + irq_base);
+               mmio->value &= access_mask;
+               /* Combine with external SPIs */
+               mmio->value |= (itargetsr & ~access_mask);
+               /* And do the access */
+               mmio_perform_access(gicd_base, mmio);
+               spin_unlock(&dist_lock);
+       } else {
+               mmio_perform_access(gicd_base, mmio);
+               mmio->value &= access_mask;
+       }
+
+       return MMIO_HANDLED;
+}
+
 unsigned int irqchip_mmio_count_regions(struct cell *cell)
 {
        return 1;
@@ -309,4 +379,6 @@ struct irqchip_ops irqchip = {
        .enable_maint_irq = gic_enable_maint_irq,
        .has_pending_irqs = gic_has_pending_irqs,
        .eoi_irq = gic_eoi_irq,
+
+       .handle_irq_target = gic_handle_irq_target,
 };
diff --git a/hypervisor/arch/arm-common/include/asm/gic.h 
b/hypervisor/arch/arm-common/include/asm/gic.h
index 44c50f9..a1ee60e 100644
--- a/hypervisor/arch/arm-common/include/asm/gic.h
+++ b/hypervisor/arch/arm-common/include/asm/gic.h
@@ -47,9 +47,12 @@
 #define is_spi(irqn)                   ((irqn) > 31 && (irqn) < 1020)
 
 #ifndef __ASSEMBLY__
+extern struct irqchip_ops irqchip;
+
 extern u8 gicv2_target_cpu_map[8];
 
 extern void *gicd_base;
+extern spinlock_t dist_lock;
 
 int gic_probe_cpu_id(unsigned int cpu);
 enum mmio_result gic_handle_dist_access(void *arg, struct mmio_access *mmio);
diff --git a/hypervisor/arch/arm-common/include/asm/irqchip.h 
b/hypervisor/arch/arm-common/include/asm/irqchip.h
index d9d1f61..40984e0 100644
--- a/hypervisor/arch/arm-common/include/asm/irqchip.h
+++ b/hypervisor/arch/arm-common/include/asm/irqchip.h
@@ -52,6 +52,9 @@ struct irqchip_ops {
        int     (*inject_irq)(struct per_cpu *cpu_data, u16 irq_id);
        void    (*enable_maint_irq)(bool enable);
        bool    (*has_pending_irqs)(void);
+
+       enum mmio_result (*handle_irq_target)(struct mmio_access *mmio,
+                                             unsigned int irq);
 };
 
 unsigned int irqchip_mmio_count_regions(struct cell *cell);
diff --git a/hypervisor/arch/arm-common/irqchip.c 
b/hypervisor/arch/arm-common/irqchip.c
index 28e453e..794259d 100644
--- a/hypervisor/arch/arm-common/irqchip.c
+++ b/hypervisor/arch/arm-common/irqchip.c
@@ -32,8 +32,6 @@
             (counter) < (config)->num_irqchips;                        \
             (chip)++, (counter)++)
 
-extern struct irqchip_ops irqchip;
-
 void *gicd_base;
 
 /*
diff --git a/hypervisor/arch/arm/gic-v3.c b/hypervisor/arch/arm/gic-v3.c
index 3b10d0d..9b17df9 100644
--- a/hypervisor/arch/arm/gic-v3.c
+++ b/hypervisor/arch/arm/gic-v3.c
@@ -432,6 +432,13 @@ static bool gicv3_has_pending_irqs(void)
        return false;
 }
 
+static enum mmio_result gicv3_handle_irq_target(struct mmio_access *mmio,
+                                               unsigned int irq)
+{
+       /* ignore writes, we are in affinity routing mode */
+       return MMIO_HANDLED;
+}
+
 unsigned int irqchip_mmio_count_regions(struct cell *cell)
 {
        return 2;
@@ -448,4 +455,5 @@ struct irqchip_ops irqchip = {
        .enable_maint_irq = gicv3_enable_maint_irq,
        .has_pending_irqs = gicv3_has_pending_irqs,
        .eoi_irq = gic_eoi_irq,
+       .handle_irq_target = gicv3_handle_irq_target,
 };
-- 
2.1.4

-- 
You received this message because you are subscribed to the Google Groups 
"Jailhouse" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to