These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / irqchip / irq-gic-common.c
index ad96ebb..f174ce0 100644 (file)
 
 #include "irq-gic-common.h"
 
+void gic_enable_quirks(u32 iidr, const struct gic_quirk *quirks,
+               void *data)
+{
+       for (; quirks->desc; quirks++) {
+               if (quirks->iidr != (quirks->mask & iidr))
+                       continue;
+               quirks->init(data);
+               pr_info("GIC: enabling workaround for %s\n", quirks->desc);
+       }
+}
+
 int gic_configure_irq(unsigned int irq, unsigned int type,
                       void __iomem *base, void (*sync_access)(void))
 {
-       u32 enablemask = 1 << (irq % 32);
-       u32 enableoff = (irq / 32) * 4;
        u32 confmask = 0x2 << ((irq % 16) * 2);
        u32 confoff = (irq / 16) * 4;
-       bool enabled = false;
        u32 val, oldval;
        int ret = 0;
 
@@ -42,17 +50,6 @@ int gic_configure_irq(unsigned int irq, unsigned int type,
        else if (type & IRQ_TYPE_EDGE_BOTH)
                val |= confmask;
 
-       /*
-        * As recommended by the spec, disable the interrupt before changing
-        * the configuration
-        */
-       if (readl_relaxed(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) {
-               writel_relaxed(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff);
-               if (sync_access)
-                       sync_access();
-               enabled = true;
-       }
-
        /*
         * Write back the new configuration, and possibly re-enable
         * the interrupt. If we tried to write a new configuration and failed,
@@ -62,9 +59,6 @@ int gic_configure_irq(unsigned int irq, unsigned int type,
        if (readl_relaxed(base + GIC_DIST_CONFIG + confoff) != val && val != oldval)
                ret = -EINVAL;
 
-       if (enabled)
-               writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
-
        if (sync_access)
                sync_access();
 
@@ -90,12 +84,15 @@ void __init gic_dist_config(void __iomem *base, int gic_irqs,
                writel_relaxed(GICD_INT_DEF_PRI_X4, base + GIC_DIST_PRI + i);
 
        /*
-        * Disable all interrupts.  Leave the PPI and SGIs alone
-        * as they are enabled by redistributor registers.
+        * Deactivate and disable all SPIs. Leave the PPI and SGIs
+        * alone as they are in the redistributor registers on GICv3.
         */
-       for (i = 32; i < gic_irqs; i += 32)
+       for (i = 32; i < gic_irqs; i += 32) {
                writel_relaxed(GICD_INT_EN_CLR_X32,
-                                       base + GIC_DIST_ENABLE_CLEAR + i / 8);
+                              base + GIC_DIST_ACTIVE_CLEAR + i / 8);
+               writel_relaxed(GICD_INT_EN_CLR_X32,
+                              base + GIC_DIST_ENABLE_CLEAR + i / 8);
+       }
 
        if (sync_access)
                sync_access();
@@ -108,7 +105,9 @@ void gic_cpu_config(void __iomem *base, void (*sync_access)(void))
        /*
         * Deal with the banked PPI and SGI interrupts - disable all
         * PPI interrupts, ensure all SGI interrupts are enabled.
+        * Make sure everything is deactivated.
         */
+       writel_relaxed(GICD_INT_EN_CLR_X32, base + GIC_DIST_ACTIVE_CLEAR);
        writel_relaxed(GICD_INT_EN_CLR_PPI, base + GIC_DIST_ENABLE_CLEAR);
        writel_relaxed(GICD_INT_EN_SET_SGI, base + GIC_DIST_ENABLE_SET);