KVM: selftests: aarch64: Add GICv3 register accessor library functions
authorRicardo Koller <ricarkol@google.com>
Tue, 9 Nov 2021 02:38:52 +0000 (18:38 -0800)
committerMarc Zyngier <maz@kernel.org>
Tue, 28 Dec 2021 19:23:13 +0000 (19:23 +0000)
Add library functions for accessing GICv3 registers: DIR, PMR, CTLR,
ISACTIVER, ISPENDR.

Signed-off-by: Ricardo Koller <ricarkol@google.com>
Acked-by: Andrew Jones <drjones@redhat.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20211109023906.1091208-4-ricarkol@google.com
tools/testing/selftests/kvm/include/aarch64/gic.h
tools/testing/selftests/kvm/include/aarch64/gic_v3.h
tools/testing/selftests/kvm/lib/aarch64/gic.c
tools/testing/selftests/kvm/lib/aarch64/gic_private.h
tools/testing/selftests/kvm/lib/aarch64/gic_v3.c

index 85dd1e5..c932cf3 100644 (file)
@@ -17,5 +17,21 @@ void gic_irq_enable(unsigned int intid);
 void gic_irq_disable(unsigned int intid);
 unsigned int gic_get_and_ack_irq(void);
 void gic_set_eoi(unsigned int intid);
+void gic_set_dir(unsigned int intid);
+
+/*
+ * Sets the EOI mode. When split is false, EOI just drops the priority. When
+ * split is true, EOI drops the priority and deactivates the interrupt.
+ */
+void gic_set_eoi_split(bool split);
+void gic_set_priority_mask(uint64_t mask);
+void gic_set_priority(uint32_t intid, uint32_t prio);
+void gic_irq_set_active(unsigned int intid);
+void gic_irq_clear_active(unsigned int intid);
+bool gic_irq_get_active(unsigned int intid);
+void gic_irq_set_pending(unsigned int intid);
+void gic_irq_clear_pending(unsigned int intid);
+bool gic_irq_get_pending(unsigned int intid);
+void gic_irq_set_config(unsigned int intid, bool is_edge);
 
 #endif /* SELFTEST_KVM_GIC_H */
index b51536d..ba0886e 100644 (file)
 #define GICD_IGROUPR                   0x0080
 #define GICD_ISENABLER                 0x0100
 #define GICD_ICENABLER                 0x0180
+#define GICD_ISPENDR                   0x0200
+#define GICD_ICPENDR                   0x0280
 #define GICD_ICACTIVER                 0x0380
+#define GICD_ISACTIVER                 0x0300
 #define GICD_IPRIORITYR                        0x0400
+#define GICD_ICFGR                     0x0C00
 
 /*
  * The assumption is that the guest runs in a non-secure mode.
 #define GICR_IGROUPR0                  GICD_IGROUPR
 #define GICR_ISENABLER0                        GICD_ISENABLER
 #define GICR_ICENABLER0                        GICD_ICENABLER
+#define GICR_ISPENDR0                  GICD_ISPENDR
+#define GICR_ISACTIVER0                        GICD_ISACTIVER
 #define GICR_ICACTIVER0                        GICD_ICACTIVER
+#define GICR_ICENABLER                 GICD_ICENABLER
+#define GICR_ICACTIVER                 GICD_ICACTIVER
 #define GICR_IPRIORITYR0               GICD_IPRIORITYR
 
 /* CPU interface registers */
 #define SYS_ICC_PMR_EL1                        sys_reg(3, 0, 4, 6, 0)
 #define SYS_ICC_IAR1_EL1               sys_reg(3, 0, 12, 12, 0)
 #define SYS_ICC_EOIR1_EL1              sys_reg(3, 0, 12, 12, 1)
+#define SYS_ICC_DIR_EL1                        sys_reg(3, 0, 12, 11, 1)
+#define SYS_ICC_CTLR_EL1               sys_reg(3, 0, 12, 12, 4)
 #define SYS_ICC_SRE_EL1                        sys_reg(3, 0, 12, 12, 5)
 #define SYS_ICC_GRPEN1_EL1             sys_reg(3, 0, 12, 12, 7)
 
+#define SYS_ICV_AP1R0_EL1              sys_reg(3, 0, 12, 9, 0)
+
 #define ICC_PMR_DEF_PRIO               0xf0
 
 #define ICC_SRE_EL1_SRE                        (1U << 0)
index fff4fc2..5566863 100644 (file)
@@ -93,3 +93,69 @@ void gic_set_eoi(unsigned int intid)
        GUEST_ASSERT(gic_common_ops);
        gic_common_ops->gic_write_eoir(intid);
 }
+
+void gic_set_dir(unsigned int intid)
+{
+       GUEST_ASSERT(gic_common_ops);
+       gic_common_ops->gic_write_dir(intid);
+}
+
+void gic_set_eoi_split(bool split)
+{
+       GUEST_ASSERT(gic_common_ops);
+       gic_common_ops->gic_set_eoi_split(split);
+}
+
+void gic_set_priority_mask(uint64_t pmr)
+{
+       GUEST_ASSERT(gic_common_ops);
+       gic_common_ops->gic_set_priority_mask(pmr);
+}
+
+void gic_set_priority(unsigned int intid, unsigned int prio)
+{
+       GUEST_ASSERT(gic_common_ops);
+       gic_common_ops->gic_set_priority(intid, prio);
+}
+
+void gic_irq_set_active(unsigned int intid)
+{
+       GUEST_ASSERT(gic_common_ops);
+       gic_common_ops->gic_irq_set_active(intid);
+}
+
+void gic_irq_clear_active(unsigned int intid)
+{
+       GUEST_ASSERT(gic_common_ops);
+       gic_common_ops->gic_irq_clear_active(intid);
+}
+
+bool gic_irq_get_active(unsigned int intid)
+{
+       GUEST_ASSERT(gic_common_ops);
+       return gic_common_ops->gic_irq_get_active(intid);
+}
+
+void gic_irq_set_pending(unsigned int intid)
+{
+       GUEST_ASSERT(gic_common_ops);
+       gic_common_ops->gic_irq_set_pending(intid);
+}
+
+void gic_irq_clear_pending(unsigned int intid)
+{
+       GUEST_ASSERT(gic_common_ops);
+       gic_common_ops->gic_irq_clear_pending(intid);
+}
+
+bool gic_irq_get_pending(unsigned int intid)
+{
+       GUEST_ASSERT(gic_common_ops);
+       return gic_common_ops->gic_irq_get_pending(intid);
+}
+
+void gic_irq_set_config(unsigned int intid, bool is_edge)
+{
+       GUEST_ASSERT(gic_common_ops);
+       gic_common_ops->gic_irq_set_config(intid, is_edge);
+}
index d81d739..75d0731 100644 (file)
@@ -14,6 +14,17 @@ struct gic_common_ops {
        void (*gic_irq_disable)(unsigned int intid);
        uint64_t (*gic_read_iar)(void);
        void (*gic_write_eoir)(uint32_t irq);
+       void (*gic_write_dir)(uint32_t irq);
+       void (*gic_set_eoi_split)(bool split);
+       void (*gic_set_priority_mask)(uint64_t mask);
+       void (*gic_set_priority)(uint32_t intid, uint32_t prio);
+       void (*gic_irq_set_active)(uint32_t intid);
+       void (*gic_irq_clear_active)(uint32_t intid);
+       bool (*gic_irq_get_active)(uint32_t intid);
+       void (*gic_irq_set_pending)(uint32_t intid);
+       void (*gic_irq_clear_pending)(uint32_t intid);
+       bool (*gic_irq_get_pending)(uint32_t intid);
+       void (*gic_irq_set_config)(uint32_t intid, bool is_edge);
 };
 
 extern const struct gic_common_ops gicv3_ops;
index 00e944f..00f613c 100644 (file)
@@ -90,6 +90,29 @@ static void gicv3_write_eoir(uint32_t irq)
        isb();
 }
 
+static void gicv3_write_dir(uint32_t irq)
+{
+       write_sysreg_s(irq, SYS_ICC_DIR_EL1);
+       isb();
+}
+
+static void gicv3_set_priority_mask(uint64_t mask)
+{
+       write_sysreg_s(mask, SYS_ICC_PMR_EL1);
+}
+
+static void gicv3_set_eoi_split(bool split)
+{
+       uint32_t val;
+
+       /* All other fields are read-only, so no need to read CTLR first. In
+        * fact, the kernel does the same.
+        */
+       val = split ? (1U << 1) : 0;
+       write_sysreg_s(val, SYS_ICC_CTLR_EL1);
+       isb();
+}
+
 uint32_t gicv3_reg_readl(uint32_t cpu_or_dist, uint64_t offset)
 {
        void *base = cpu_or_dist & DIST_BIT ? gicv3_data.dist_base
@@ -174,26 +197,70 @@ static uint32_t gicv3_read_reg(uint32_t intid, uint64_t offset,
        return val;
 }
 
-static void gicv3_irq_enable(unsigned int intid)
+static void gicv3_set_priority(uint32_t intid, uint32_t prio)
+{
+       gicv3_write_reg(intid, GICD_IPRIORITYR, 32, 8, prio);
+}
+
+/* Sets the intid to be level-sensitive or edge-triggered. */
+static void gicv3_irq_set_config(uint32_t intid, bool is_edge)
+{
+       uint32_t val;
+
+       /* N/A for private interrupts. */
+       GUEST_ASSERT(get_intid_range(intid) == SPI_RANGE);
+       val = is_edge ? 2 : 0;
+       gicv3_write_reg(intid, GICD_ICFGR, 32, 2, val);
+}
+
+static void gicv3_irq_enable(uint32_t intid)
 {
        bool is_spi = get_intid_range(intid) == SPI_RANGE;
-       unsigned int val = 1;
        uint32_t cpu = guest_get_vcpuid();
 
-       gicv3_write_reg(intid, GICD_ISENABLER, 32, 1, val);
+       gicv3_write_reg(intid, GICD_ISENABLER, 32, 1, 1);
        gicv3_wait_for_rwp(is_spi ? DIST_BIT : cpu);
 }
 
-static void gicv3_irq_disable(unsigned int intid)
+static void gicv3_irq_disable(uint32_t intid)
 {
        bool is_spi = get_intid_range(intid) == SPI_RANGE;
-       uint32_t val = 1;
        uint32_t cpu = guest_get_vcpuid();
 
-       gicv3_write_reg(intid, GICD_ICENABLER, 32, 1, val);
+       gicv3_write_reg(intid, GICD_ICENABLER, 32, 1, 1);
        gicv3_wait_for_rwp(is_spi ? DIST_BIT : cpu);
 }
 
+static void gicv3_irq_set_active(uint32_t intid)
+{
+       gicv3_write_reg(intid, GICD_ISACTIVER, 32, 1, 1);
+}
+
+static void gicv3_irq_clear_active(uint32_t intid)
+{
+       gicv3_write_reg(intid, GICD_ICACTIVER, 32, 1, 1);
+}
+
+static bool gicv3_irq_get_active(uint32_t intid)
+{
+       return gicv3_read_reg(intid, GICD_ISACTIVER, 32, 1);
+}
+
+static void gicv3_irq_set_pending(uint32_t intid)
+{
+       gicv3_write_reg(intid, GICD_ISPENDR, 32, 1, 1);
+}
+
+static void gicv3_irq_clear_pending(uint32_t intid)
+{
+       gicv3_write_reg(intid, GICD_ICPENDR, 32, 1, 1);
+}
+
+static bool gicv3_irq_get_pending(uint32_t intid)
+{
+       return gicv3_read_reg(intid, GICD_ISPENDR, 32, 1);
+}
+
 static void gicv3_enable_redist(void *redist_base)
 {
        uint32_t val = readl(redist_base + GICR_WAKER);
@@ -315,4 +382,15 @@ const struct gic_common_ops gicv3_ops = {
        .gic_irq_disable = gicv3_irq_disable,
        .gic_read_iar = gicv3_read_iar,
        .gic_write_eoir = gicv3_write_eoir,
+       .gic_write_dir = gicv3_write_dir,
+       .gic_set_priority_mask = gicv3_set_priority_mask,
+       .gic_set_eoi_split = gicv3_set_eoi_split,
+       .gic_set_priority = gicv3_set_priority,
+       .gic_irq_set_active = gicv3_irq_set_active,
+       .gic_irq_clear_active = gicv3_irq_clear_active,
+       .gic_irq_get_active = gicv3_irq_get_active,
+       .gic_irq_set_pending = gicv3_irq_set_pending,
+       .gic_irq_clear_pending = gicv3_irq_clear_pending,
+       .gic_irq_get_pending = gicv3_irq_get_pending,
+       .gic_irq_set_config = gicv3_irq_set_config,
 };