]> xenbits.xensource.com Git - xen.git/commitdiff
xen: arm: log warning for interrupt configuration mismatch
authorIan Campbell <ian.campbell@citrix.com>
Thu, 19 Feb 2015 15:24:02 +0000 (15:24 +0000)
committerIan Campbell <ian.campbell@citrix.com>
Wed, 25 Feb 2015 13:45:00 +0000 (13:45 +0000)
The ICFGR register is not necessarily writeable, in particular it is
IMPLEMENTATION DEFINED for a PPI if the configuration register is
writeable. Log a warning if the hardware has ignored our write and
update the actual type in the irq descriptor so subsequent code can do
the right thing.

This most likely implies a buggy firmware description (e.g.
device-tree).

The issue is observed for example on the APM Mustang board where the
device tree (as shipped by Linux) describes all 3 timer interrupts as
rising edge but the PPI is hard-coded to level triggered (as makes
sense for an arch timer interrupt).

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Reviewed-by: Julien Grall <julien.grall@linaro.org>
Cc: Pranavkumar Sawargaonkar <psawargaonkar@apm.com>
xen/arch/arm/gic-v2.c
xen/arch/arm/gic-v3.c

index ee400b6926c13dda6532942256a46975ef347145..c05b64a380e161723b5486a5f786702e2aeb1435 100644 (file)
@@ -211,7 +211,7 @@ static void gicv2_set_irq_properties(struct irq_desc *desc,
                                    const cpumask_t *cpu_mask,
                                    unsigned int priority)
 {
-    uint32_t cfg, edgebit;
+    uint32_t cfg, actual, edgebit;
     unsigned int mask = gicv2_cpu_mask(cpu_mask);
     unsigned int irq = desc->irq;
     unsigned int type = desc->arch.type;
@@ -229,6 +229,20 @@ static void gicv2_set_irq_properties(struct irq_desc *desc,
         cfg |= edgebit;
     writel_gicd(cfg, GICD_ICFGR + (irq / 16) * 4);
 
+    actual = readl_gicd(GICD_ICFGR + (irq / 16) * 4);
+    if ( ( cfg & edgebit ) ^ ( actual & edgebit ) )
+    {
+        printk(XENLOG_WARNING "GICv2: WARNING: "
+               "CPU%d: Failed to configure IRQ%u as %s-triggered. "
+               "H/w forces to %s-triggered.\n",
+               smp_processor_id(), desc->irq,
+               cfg & edgebit ? "Edge" : "Level",
+               actual & edgebit ? "Edge" : "Level");
+        desc->arch.type = actual & edgebit ?
+            DT_IRQ_TYPE_EDGE_RISING :
+            DT_IRQ_TYPE_LEVEL_LOW;
+    }
+
     /* Set target CPU mask (RAZ/WI on uniprocessor) */
     writeb_gicd(mask, GICD_ITARGETSR + irq);
     /* Set priority */
index 41042ab140b9642a4671b720d2642f5d96bcd865..1558e1749d0b5d7fca8badbeb1dd9bf87cbcd34b 100644 (file)
@@ -466,7 +466,7 @@ static void gicv3_set_irq_properties(struct irq_desc *desc,
                                      const cpumask_t *cpu_mask,
                                      unsigned int priority)
 {
-    uint32_t cfg, edgebit;
+    uint32_t cfg, actual, edgebit;
     uint64_t affinity;
     void __iomem *base;
     unsigned int cpu = gicv3_get_cpu_from_mask(cpu_mask);
@@ -493,6 +493,20 @@ static void gicv3_set_irq_properties(struct irq_desc *desc,
 
     writel_relaxed(cfg, base);
 
+    actual = readl_relaxed(base);
+    if ( ( cfg & edgebit ) ^ ( actual & edgebit ) )
+    {
+        printk(XENLOG_WARNING "GICv3: WARNING: "
+               "CPU%d: Failed to configure IRQ%u as %s-triggered. "
+               "H/w forces to %s-triggered.\n",
+               smp_processor_id(), desc->irq,
+               cfg & edgebit ? "Edge" : "Level",
+               actual & edgebit ? "Edge" : "Level");
+        desc->arch.type = actual & edgebit ?
+            DT_IRQ_TYPE_EDGE_RISING :
+            DT_IRQ_TYPE_LEVEL_LOW;
+    }
+
     affinity = gicv3_mpidr_to_affinity(cpu);
     /* Make sure we don't broadcast the interrupt */
     affinity &= ~GICD_IROUTER_SPI_MODE_ANY;