[RFC PATCH 5/9] irqchip: GICv3: Convert to EOImode == 1

Marc Zyngier marc.zyngier at arm.com
Wed Jun 25 02:28:46 PDT 2014


So far, GICv3 has been used in with EOImode == 0. The effect of this
mode is to perform the priority drop and the deactivation of the
interrupt at the same time.

While this works perfectly for Linux (we only have a single priority),
it causes issues when an interrupt is forwarded to a guest, and when
we want the guest to perform the EOI itself.

For this case, the GIC architecture provides EOImode == 1, where:
- A write to ICC_EOIR1_EL1 drops the priority of the interrupt and leaves
it active. Other interrupts at the same priority level can now be taken,
but the active interrupt cannot be taken again
- A write to ICC_DIR_EL1 marks the interrupt as inactive, meaning it can
now be taken again.

This patch converts the driver to this new mode, without any other feature.

Signed-off-by: Marc Zyngier <marc.zyngier at arm.com>
---
 drivers/irqchip/irq-gic-v3-its.c   | 1 +
 drivers/irqchip/irq-gic-v3.c       | 6 ++++--
 include/linux/irqchip/arm-gic-v3.h | 7 +++++++
 3 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 822f55e..922f228 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -616,6 +616,7 @@ static void its_unmask_irq(struct irq_data *d)
 static void its_eoi_irq(struct irq_data *d)
 {
 	gic_write_eoir(d->hwirq);
+	gic_write_dir(d->hwirq);
 }
 
 static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 3ae53c1..26a08ce 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -238,6 +238,7 @@ static void gic_unmask_irq(struct irq_data *d)
 static void gic_eoi_irq(struct irq_data *d)
 {
 	gic_write_eoir(gic_irq(d));
+	gic_write_dir(gic_irq(d));
 }
 
 static int gic_set_type(struct irq_data *d, unsigned int type)
@@ -297,6 +298,7 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
 		}
 		if (irqnr < 16) {
 			gic_write_eoir(irqnr);
+			gic_write_dir(irqnr);
 #ifdef CONFIG_SMP
 			handle_IPI(irqnr, regs);
 #else
@@ -400,8 +402,8 @@ static void gic_cpu_sys_reg_init(void)
 	/* Set priority mask register */
 	gic_write_pmr(DEFAULT_PMR_VALUE);
 
-	/* EOI deactivates interrupt too (mode 0) */
-	gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir);
+	/* EOI drops priority only (mode 1) */
+	gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop);
 
 	/* ... and let's hit the road... */
 	gic_write_grpen1(1);
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 023b49d..a0bff2f 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -229,6 +229,7 @@
 
 #define ICC_EOIR1_EL1			S3_0_C12_C12_1
 #define ICC_IAR1_EL1			S3_0_C12_C12_0
+#define ICC_DIR_EL1			S3_0_C12_C11_1
 #define ICC_SGI1R_EL1			S3_0_C12_C11_5
 #define ICC_PMR_EL1			S3_0_C4_C6_0
 #define ICC_CTLR_EL1			S3_0_C12_C12_4
@@ -303,6 +304,12 @@ static inline void gic_write_eoir(u64 irq)
 	isb();
 }
 
+static inline void gic_write_dir(u64 irq)
+{
+	asm volatile("msr " __stringify(ICC_DIR_EL1) ", %0" : : "r" (irq));
+	isb();
+}
+
 int its_cpu_init(void);
 struct irq_chip *its_init(struct device_node *node, struct rdist *rdist,
 			  struct irq_domain *domain);
-- 
1.8.3.4




More information about the linux-arm-kernel mailing list