Our irqchip is inherently GIC-centric, so there is no reason to split up
the frontend interface from the common GIC part. Move them together, and
also fold gic_set_irq_pending into its only caller.

Signed-off-by: Jan Kiszka <[email protected]>
---
 hypervisor/arch/arm-common/Kbuild            |   2 +-
 hypervisor/arch/arm-common/gic-common.c      | 251 ---------------------------
 hypervisor/arch/arm-common/include/asm/gic.h |   3 -
 hypervisor/arch/arm-common/irqchip.c         | 228 +++++++++++++++++++++++-
 4 files changed, 227 insertions(+), 257 deletions(-)
 delete mode 100644 hypervisor/arch/arm-common/gic-common.c

diff --git a/hypervisor/arch/arm-common/Kbuild 
b/hypervisor/arch/arm-common/Kbuild
index 0aa613d..2901ccf 100644
--- a/hypervisor/arch/arm-common/Kbuild
+++ b/hypervisor/arch/arm-common/Kbuild
@@ -13,7 +13,7 @@
 include $(CONFIG_MK)
 
 OBJS-y += dbg-write.o lib.o psci.o control.o paging.o mmu_cell.o
-OBJS-y += irqchip.o gic-common.o pci.o ivshmem.o uart-pl011.o uart-8250.o
+OBJS-y += irqchip.o pci.o ivshmem.o uart-pl011.o uart-8250.o
 OBJS-$(CONFIG_ARM_GIC_V2) += gic-v2.o
 
 COMMON_OBJECTS = $(addprefix ../arm-common/,$(OBJS-y))
diff --git a/hypervisor/arch/arm-common/gic-common.c 
b/hypervisor/arch/arm-common/gic-common.c
deleted file mode 100644
index 37a12b6..0000000
--- a/hypervisor/arch/arm-common/gic-common.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Jailhouse, a Linux-based partitioning hypervisor
- *
- * Copyright (c) ARM Limited, 2014
- *
- * Authors:
- *  Jean-Philippe Brucker <[email protected]>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- */
-
-#include <jailhouse/cell.h>
-#include <jailhouse/control.h>
-#include <jailhouse/mmio.h>
-#include <jailhouse/printk.h>
-#include <asm/control.h>
-#include <asm/gic.h>
-#include <asm/irqchip.h>
-#include <asm/percpu.h>
-#include <asm/spinlock.h>
-#include <asm/traps.h>
-
-#define REG_RANGE(base, n, size)               \
-               (base) ... ((base) + (n - 1) * (size))
-
-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 };
-
-/*
- * Most of the GIC distributor writes only reconfigure the IRQs corresponding 
to
- * the bits of the written value, by using separate `set' and `clear' 
registers.
- * Such registers can be handled by setting the `is_poke' boolean, which allows
- * to simply restrict the mmio->value with the cell configuration mask.
- * Others, such as the priority registers, will need to be read and written 
back
- * with a restricted value, by using the distributor lock.
- */
-static enum mmio_result
-restrict_bitmask_access(struct mmio_access *mmio, unsigned int reg_index,
-                       unsigned int bits_per_irq, bool is_poke)
-{
-       struct cell *cell = this_cell();
-       unsigned int irq;
-       unsigned long access_mask = 0;
-       /*
-        * In order to avoid division, the number of bits per irq is limited
-        * to powers of 2 for the moment.
-        */
-       unsigned long irqs_per_reg = 32 >> ffsl(bits_per_irq);
-       unsigned long irq_bits = (1 << bits_per_irq) - 1;
-       /* First, extract the first interrupt affected by this access */
-       unsigned int first_irq = reg_index * irqs_per_reg;
-
-       for (irq = 0; irq < irqs_per_reg; irq++)
-               if (irqchip_irq_in_cell(cell, first_irq + irq))
-                       access_mask |= irq_bits << (irq * bits_per_irq);
-
-       if (!mmio->is_write) {
-               /* Restrict the read value */
-               mmio_perform_access(gicd_base, mmio);
-               mmio->value &= access_mask;
-               return MMIO_HANDLED;
-       }
-
-       if (!is_poke) {
-               /*
-                * Modify the existing value of this register by first reading
-                * it into mmio->value
-                * Relies on a spinlock since we need two mmio accesses.
-                */
-               unsigned long access_val = mmio->value;
-
-               spin_lock(&dist_lock);
-
-               mmio->is_write = false;
-               mmio_perform_access(gicd_base, mmio);
-               mmio->is_write = true;
-
-               mmio->value &= ~access_mask;
-               mmio->value |= access_val & access_mask;
-               mmio_perform_access(gicd_base, mmio);
-
-               spin_unlock(&dist_lock);
-       } else {
-               mmio->value &= access_mask;
-               mmio_perform_access(gicd_base, mmio);
-       }
-       return MMIO_HANDLED;
-}
-
-static enum mmio_result handle_sgir_access(struct mmio_access *mmio)
-{
-       struct sgi sgi;
-       unsigned long val = mmio->value;
-
-       if (!mmio->is_write)
-               return MMIO_HANDLED;
-
-       sgi.targets = (val >> 16) & 0xff;
-       sgi.routing_mode = (val >> 24) & 0x3;
-       sgi.aff1 = 0;
-       sgi.aff2 = 0;
-       sgi.aff3 = 0;
-       sgi.id = val & 0xf;
-
-       gic_handle_sgir_write(&sgi, false);
-       return MMIO_HANDLED;
-}
-
-void gic_handle_sgir_write(struct sgi *sgi, bool virt_input)
-{
-       struct per_cpu *cpu_data = this_cpu_data();
-       unsigned long targets = sgi->targets;
-       unsigned int cpu;
-
-       if (sgi->routing_mode == 2) {
-               /* Route to the caller itself */
-               irqchip_set_pending(cpu_data, sgi->id);
-               sgi->targets = (1 << cpu_data->cpu_id);
-       } else {
-               sgi->targets = 0;
-
-               for_each_cpu(cpu, cpu_data->cell->cpu_set) {
-                       if (sgi->routing_mode == 1) {
-                               /* Route to all (cell) CPUs but the caller. */
-                               if (cpu == cpu_data->cpu_id)
-                                       continue;
-                       } else if (virt_input) {
-                               if (!test_bit(arm_cpu_phys2virt(cpu),
-                                             &targets))
-                                       continue;
-                       } else {
-                               /*
-                                * When using a cpu map to target the different
-                                * CPUs (GICv2), they are independent from the
-                                * physical CPU IDs, so there is no need to
-                                * translate them to the hypervisor's virtual
-                                * IDs.
-                                */
-                               if (!(targets & gicv2_target_cpu_map[cpu]))
-                                       continue;
-                       }
-
-                       irqchip_set_pending(per_cpu(cpu), sgi->id);
-                       sgi->targets |= (1 << cpu);
-               }
-       }
-
-       /* Let the other CPUS inject their SGIs */
-       sgi->id = SGI_INJECT;
-       irqchip_send_sgi(sgi);
-}
-
-enum mmio_result gic_handle_dist_access(void *arg, struct mmio_access *mmio)
-{
-       unsigned long reg = mmio->address;
-       enum mmio_result ret;
-
-       switch (reg) {
-       case REG_RANGE(GICD_IROUTER, 1024, 8):
-               ret = gic_handle_irq_route(mmio, (reg - GICD_IROUTER) / 8);
-               break;
-
-       case REG_RANGE(GICD_ITARGETSR, 1024, 1):
-               ret = irqchip.handle_irq_target(mmio, reg - GICD_ITARGETSR);
-               break;
-
-       case REG_RANGE(GICD_ICENABLER, 32, 4):
-       case REG_RANGE(GICD_ISENABLER, 32, 4):
-       case REG_RANGE(GICD_ICPENDR, 32, 4):
-       case REG_RANGE(GICD_ISPENDR, 32, 4):
-       case REG_RANGE(GICD_ICACTIVER, 32, 4):
-       case REG_RANGE(GICD_ISACTIVER, 32, 4):
-               ret = restrict_bitmask_access(mmio, (reg & 0x7f) / 4, 1, true);
-               break;
-
-       case REG_RANGE(GICD_IGROUPR, 32, 4):
-               ret = restrict_bitmask_access(mmio, (reg & 0x7f) / 4, 1, false);
-               break;
-
-       case REG_RANGE(GICD_ICFGR, 64, 4):
-               ret = restrict_bitmask_access(mmio, (reg & 0xff) / 4, 2, false);
-               break;
-
-       case REG_RANGE(GICD_IPRIORITYR, 255, 4):
-               ret = restrict_bitmask_access(mmio, (reg & 0x3ff) / 4, 8,
-                                             false);
-               break;
-
-       case GICD_SGIR:
-               ret = handle_sgir_access(mmio);
-               break;
-
-       case GICD_CTLR:
-       case GICD_TYPER:
-       case GICD_IIDR:
-       case REG_RANGE(GICD_PIDR0, 4, 4):
-       case REG_RANGE(GICD_PIDR4, 4, 4):
-       case REG_RANGE(GICD_CIDR0, 4, 4):
-               /* Allow read access, ignore write */
-               if (!mmio->is_write)
-                       mmio_perform_access(gicd_base, mmio);
-               /* fall through */
-       default:
-               /* Ignore access. */
-               ret = MMIO_HANDLED;
-       }
-
-       return ret;
-}
-
-void irqchip_handle_irq(struct per_cpu *cpu_data)
-{
-       unsigned int count_event = 1;
-       bool handled = false;
-       u32 irq_id;
-
-       while (1) {
-               /* Read IAR1: set 'active' state */
-               irq_id = gic_read_iar();
-
-               if (irq_id == 0x3ff) /* Spurious IRQ */
-                       break;
-
-               /* Handle IRQ */
-               if (is_sgi(irq_id)) {
-                       arch_handle_sgi(cpu_data, irq_id, count_event);
-                       handled = true;
-               } else {
-                       handled = arch_handle_phys_irq(cpu_data, irq_id,
-                                                      count_event);
-               }
-               count_event = 0;
-
-               /*
-                * Write EOIR1: drop priority, but stay active if handled is
-                * false.
-                * This allows to not be re-interrupted by a level-triggered
-                * interrupt that needs handling in the guest (e.g. timer)
-                */
-               irqchip_eoi_irq(irq_id, handled);
-       }
-}
-
-void gic_set_irq_pending(u16 irq_id)
-{
-       mmio_write32(gicd_base + GICD_ISPENDR + (irq_id / 32) * 4,
-                    1 << (irq_id % 32));
-}
diff --git a/hypervisor/arch/arm-common/include/asm/gic.h 
b/hypervisor/arch/arm-common/include/asm/gic.h
index d74ec9b..35f48dc 100644
--- a/hypervisor/arch/arm-common/include/asm/gic.h
+++ b/hypervisor/arch/arm-common/include/asm/gic.h
@@ -54,11 +54,8 @@ extern u8 gicv2_target_cpu_map[8];
 extern void *gicd_base;
 extern spinlock_t dist_lock;
 
-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_set_irq_pending(u16 irq_id);
-
 #endif /* !__ASSEMBLY__ */
 #endif /* !_JAILHOUSE_ASM_GIC_COMMON_H */
diff --git a/hypervisor/arch/arm-common/irqchip.c 
b/hypervisor/arch/arm-common/irqchip.c
index 794259d..d523797 100644
--- a/hypervisor/arch/arm-common/irqchip.c
+++ b/hypervisor/arch/arm-common/irqchip.c
@@ -21,7 +21,6 @@
 #include <asm/control.h>
 #include <asm/gic.h>
 #include <asm/irqchip.h>
-#include <asm/setup.h>
 #include <asm/sysregs.h>
 
 /* AMBA's biosfood */
@@ -32,6 +31,14 @@
             (counter) < (config)->num_irqchips;                        \
             (chip)++, (counter)++)
 
+#define REG_RANGE(base, n, size)       \
+               (base) ... ((base) + (n - 1) * (size))
+
+/* 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 };
+
+DEFINE_SPINLOCK(dist_lock);
+
 void *gicd_base;
 
 /*
@@ -40,6 +47,222 @@ void *gicd_base;
  */
 static bool irqchip_is_init;
 
+/*
+ * Most of the GIC distributor writes only reconfigure the IRQs corresponding 
to
+ * the bits of the written value, by using separate `set' and `clear' 
registers.
+ * Such registers can be handled by setting the `is_poke' boolean, which allows
+ * to simply restrict the mmio->value with the cell configuration mask.
+ * Others, such as the priority registers, will need to be read and written 
back
+ * with a restricted value, by using the distributor lock.
+ */
+static enum mmio_result
+restrict_bitmask_access(struct mmio_access *mmio, unsigned int reg_index,
+                       unsigned int bits_per_irq, bool is_poke)
+{
+       struct cell *cell = this_cell();
+       unsigned int irq;
+       unsigned long access_mask = 0;
+       /*
+        * In order to avoid division, the number of bits per irq is limited
+        * to powers of 2 for the moment.
+        */
+       unsigned long irqs_per_reg = 32 >> ffsl(bits_per_irq);
+       unsigned long irq_bits = (1 << bits_per_irq) - 1;
+       /* First, extract the first interrupt affected by this access */
+       unsigned int first_irq = reg_index * irqs_per_reg;
+
+       for (irq = 0; irq < irqs_per_reg; irq++)
+               if (irqchip_irq_in_cell(cell, first_irq + irq))
+                       access_mask |= irq_bits << (irq * bits_per_irq);
+
+       if (!mmio->is_write) {
+               /* Restrict the read value */
+               mmio_perform_access(gicd_base, mmio);
+               mmio->value &= access_mask;
+               return MMIO_HANDLED;
+       }
+
+       if (!is_poke) {
+               /*
+                * Modify the existing value of this register by first reading
+                * it into mmio->value
+                * Relies on a spinlock since we need two mmio accesses.
+                */
+               unsigned long access_val = mmio->value;
+
+               spin_lock(&dist_lock);
+
+               mmio->is_write = false;
+               mmio_perform_access(gicd_base, mmio);
+               mmio->is_write = true;
+
+               mmio->value &= ~access_mask;
+               mmio->value |= access_val & access_mask;
+               mmio_perform_access(gicd_base, mmio);
+
+               spin_unlock(&dist_lock);
+       } else {
+               mmio->value &= access_mask;
+               mmio_perform_access(gicd_base, mmio);
+       }
+       return MMIO_HANDLED;
+}
+
+static enum mmio_result handle_sgir_access(struct mmio_access *mmio)
+{
+       struct sgi sgi;
+       unsigned long val = mmio->value;
+
+       if (!mmio->is_write)
+               return MMIO_HANDLED;
+
+       sgi.targets = (val >> 16) & 0xff;
+       sgi.routing_mode = (val >> 24) & 0x3;
+       sgi.aff1 = 0;
+       sgi.aff2 = 0;
+       sgi.aff3 = 0;
+       sgi.id = val & 0xf;
+
+       gic_handle_sgir_write(&sgi, false);
+       return MMIO_HANDLED;
+}
+
+void gic_handle_sgir_write(struct sgi *sgi, bool virt_input)
+{
+       struct per_cpu *cpu_data = this_cpu_data();
+       unsigned long targets = sgi->targets;
+       unsigned int cpu;
+
+       if (sgi->routing_mode == 2) {
+               /* Route to the caller itself */
+               irqchip_set_pending(cpu_data, sgi->id);
+               sgi->targets = (1 << cpu_data->cpu_id);
+       } else {
+               sgi->targets = 0;
+
+               for_each_cpu(cpu, cpu_data->cell->cpu_set) {
+                       if (sgi->routing_mode == 1) {
+                               /* Route to all (cell) CPUs but the caller. */
+                               if (cpu == cpu_data->cpu_id)
+                                       continue;
+                       } else if (virt_input) {
+                               if (!test_bit(arm_cpu_phys2virt(cpu),
+                                             &targets))
+                                       continue;
+                       } else {
+                               /*
+                                * When using a cpu map to target the different
+                                * CPUs (GICv2), they are independent from the
+                                * physical CPU IDs, so there is no need to
+                                * translate them to the hypervisor's virtual
+                                * IDs.
+                                */
+                               if (!(targets & gicv2_target_cpu_map[cpu]))
+                                       continue;
+                       }
+
+                       irqchip_set_pending(per_cpu(cpu), sgi->id);
+                       sgi->targets |= (1 << cpu);
+               }
+       }
+
+       /* Let the other CPUS inject their SGIs */
+       sgi->id = SGI_INJECT;
+       irqchip_send_sgi(sgi);
+}
+
+static enum mmio_result gic_handle_dist_access(void *arg,
+                                              struct mmio_access *mmio)
+{
+       unsigned long reg = mmio->address;
+       enum mmio_result ret;
+
+       switch (reg) {
+       case REG_RANGE(GICD_IROUTER, 1024, 8):
+               ret = gic_handle_irq_route(mmio, (reg - GICD_IROUTER) / 8);
+               break;
+
+       case REG_RANGE(GICD_ITARGETSR, 1024, 1):
+               ret = irqchip.handle_irq_target(mmio, reg - GICD_ITARGETSR);
+               break;
+
+       case REG_RANGE(GICD_ICENABLER, 32, 4):
+       case REG_RANGE(GICD_ISENABLER, 32, 4):
+       case REG_RANGE(GICD_ICPENDR, 32, 4):
+       case REG_RANGE(GICD_ISPENDR, 32, 4):
+       case REG_RANGE(GICD_ICACTIVER, 32, 4):
+       case REG_RANGE(GICD_ISACTIVER, 32, 4):
+               ret = restrict_bitmask_access(mmio, (reg & 0x7f) / 4, 1, true);
+               break;
+
+       case REG_RANGE(GICD_IGROUPR, 32, 4):
+               ret = restrict_bitmask_access(mmio, (reg & 0x7f) / 4, 1, false);
+               break;
+
+       case REG_RANGE(GICD_ICFGR, 64, 4):
+               ret = restrict_bitmask_access(mmio, (reg & 0xff) / 4, 2, false);
+               break;
+
+       case REG_RANGE(GICD_IPRIORITYR, 255, 4):
+               ret = restrict_bitmask_access(mmio, (reg & 0x3ff) / 4, 8,
+                                             false);
+               break;
+
+       case GICD_SGIR:
+               ret = handle_sgir_access(mmio);
+               break;
+
+       case GICD_CTLR:
+       case GICD_TYPER:
+       case GICD_IIDR:
+       case REG_RANGE(GICD_PIDR0, 4, 4):
+       case REG_RANGE(GICD_PIDR4, 4, 4):
+       case REG_RANGE(GICD_CIDR0, 4, 4):
+               /* Allow read access, ignore write */
+               if (!mmio->is_write)
+                       mmio_perform_access(gicd_base, mmio);
+               /* fall through */
+       default:
+               /* Ignore access. */
+               ret = MMIO_HANDLED;
+       }
+
+       return ret;
+}
+
+void irqchip_handle_irq(struct per_cpu *cpu_data)
+{
+       unsigned int count_event = 1;
+       bool handled = false;
+       u32 irq_id;
+
+       while (1) {
+               /* Read IAR1: set 'active' state */
+               irq_id = gic_read_iar();
+
+               if (irq_id == 0x3ff) /* Spurious IRQ */
+                       break;
+
+               /* Handle IRQ */
+               if (is_sgi(irq_id)) {
+                       arch_handle_sgi(cpu_data, irq_id, count_event);
+                       handled = true;
+               } else {
+                       handled = arch_handle_phys_irq(cpu_data, irq_id,
+                                                      count_event);
+               }
+               count_event = 0;
+
+               /*
+                * Write EOIR1: drop priority, but stay active if handled is
+                * false.
+                * This allows to not be re-interrupted by a level-triggered
+                * interrupt that needs handling in the guest (e.g. timer)
+                */
+               irqchip_eoi_irq(irq_id, handled);
+       }
+}
+
 bool irqchip_irq_in_cell(struct cell *cell, unsigned int irq_id)
 {
        if (irq_id >= sizeof(cell->arch.irq_bitmap) * 8)
@@ -60,7 +283,8 @@ void irqchip_set_pending(struct per_cpu *cpu_data, u16 
irq_id)
 
        if (!cpu_data) {
                /* Injection via GICD */
-               gic_set_irq_pending(irq_id);
+               mmio_write32(gicd_base + GICD_ISPENDR + (irq_id / 32) * 4,
+                            1 << (irq_id % 32));
                return;
        }
 
-- 
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