]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blobdiff - arch/powerpc/sysdev/mpic.c
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
[mirror_ubuntu-focal-kernel.git] / arch / powerpc / sysdev / mpic.c
index c83a512fa175c74b83b24eadb5ed9791b03351f1..9ac71ebd2c408b47869f5f152ff577e84c958064 100644 (file)
@@ -873,7 +873,7 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type)
        DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n",
            mpic, d->irq, src, flow_type);
 
-       if (src >= mpic->irq_count)
+       if (src >= mpic->num_sources)
                return -EINVAL;
 
        if (flow_type == IRQ_TYPE_NONE)
@@ -909,7 +909,7 @@ void mpic_set_vector(unsigned int virq, unsigned int vector)
        DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n",
            mpic, virq, src, vector);
 
-       if (src >= mpic->irq_count)
+       if (src >= mpic->num_sources)
                return;
 
        vecpri = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI));
@@ -926,7 +926,7 @@ void mpic_set_destination(unsigned int virq, unsigned int cpuid)
        DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n",
            mpic, virq, src, cpuid);
 
-       if (src >= mpic->irq_count)
+       if (src >= mpic->num_sources)
                return;
 
        mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid);
@@ -1006,7 +1006,7 @@ static int mpic_host_map(struct irq_domain *h, unsigned int virq,
                return 0;
        }
 
-       if (hw >= mpic->irq_count)
+       if (hw >= mpic->num_sources)
                return -EINVAL;
 
        mpic_msi_reserve_hwirq(mpic, hw);
@@ -1149,6 +1149,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        u32 greg_feature;
        const char *vers;
        const u32 *psrc;
+       u32 last_irq;
 
        /* Default MPIC search parameters */
        static const struct of_device_id __initconst mpic_device_id[] = {
@@ -1182,6 +1183,16 @@ struct mpic * __init mpic_alloc(struct device_node *node,
                }
        }
 
+       /* Read extra device-tree properties into the flags variable */
+       if (of_get_property(node, "big-endian", NULL))
+               flags |= MPIC_BIG_ENDIAN;
+       if (of_get_property(node, "pic-no-reset", NULL))
+               flags |= MPIC_NO_RESET;
+       if (of_get_property(node, "single-cpu-affinity", NULL))
+               flags |= MPIC_SINGLE_DEST_CPU;
+       if (of_device_is_compatible(node, "fsl,mpic"))
+               flags |= MPIC_FSL;
+
        mpic = kzalloc(sizeof(struct mpic), GFP_KERNEL);
        if (mpic == NULL)
                goto err_of_node_put;
@@ -1189,15 +1200,16 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        mpic->name = name;
        mpic->node = node;
        mpic->paddr = phys_addr;
+       mpic->flags = flags;
 
        mpic->hc_irq = mpic_irq_chip;
        mpic->hc_irq.name = name;
-       if (!(flags & MPIC_SECONDARY))
+       if (!(mpic->flags & MPIC_SECONDARY))
                mpic->hc_irq.irq_set_affinity = mpic_set_affinity;
 #ifdef CONFIG_MPIC_U3_HT_IRQS
        mpic->hc_ht_irq = mpic_irq_ht_chip;
        mpic->hc_ht_irq.name = name;
-       if (!(flags & MPIC_SECONDARY))
+       if (!(mpic->flags & MPIC_SECONDARY))
                mpic->hc_ht_irq.irq_set_affinity = mpic_set_affinity;
 #endif /* CONFIG_MPIC_U3_HT_IRQS */
 
@@ -1209,12 +1221,9 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        mpic->hc_tm = mpic_tm_chip;
        mpic->hc_tm.name = name;
 
-       mpic->flags = flags;
-       mpic->isu_size = isu_size;
-       mpic->irq_count = irq_count;
        mpic->num_sources = 0; /* so far */
 
-       if (flags & MPIC_LARGE_VECTORS)
+       if (mpic->flags & MPIC_LARGE_VECTORS)
                intvec_top = 2047;
        else
                intvec_top = 255;
@@ -1233,12 +1242,6 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        mpic->ipi_vecs[3]   = intvec_top - 1;
        mpic->spurious_vec  = intvec_top;
 
-       /* Check for "big-endian" in device-tree */
-       if (of_get_property(mpic->node, "big-endian", NULL) != NULL)
-               mpic->flags |= MPIC_BIG_ENDIAN;
-       if (of_device_is_compatible(mpic->node, "fsl,mpic"))
-               mpic->flags |= MPIC_FSL;
-
        /* Look for protected sources */
        psrc = of_get_property(mpic->node, "protected-sources", &psize);
        if (psrc) {
@@ -1254,11 +1257,11 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        }
 
 #ifdef CONFIG_MPIC_WEIRD
-       mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)];
+       mpic->hw_set = mpic_infos[MPIC_GET_REGSET(mpic->flags)];
 #endif
 
        /* default register type */
-       if (flags & MPIC_BIG_ENDIAN)
+       if (mpic->flags & MPIC_BIG_ENDIAN)
                mpic->reg_type = mpic_access_mmio_be;
        else
                mpic->reg_type = mpic_access_mmio_le;
@@ -1268,10 +1271,10 @@ struct mpic * __init mpic_alloc(struct device_node *node,
         * only if the kernel includes DCR support.
         */
 #ifdef CONFIG_PPC_DCR
-       if (flags & MPIC_USES_DCR)
+       if (mpic->flags & MPIC_USES_DCR)
                mpic->reg_type = mpic_access_dcr;
 #else
-       BUG_ON(flags & MPIC_USES_DCR);
+       BUG_ON(mpic->flags & MPIC_USES_DCR);
 #endif
 
        /* Map the global registers */
@@ -1283,10 +1286,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        /* When using a device-node, reset requests are only honored if the MPIC
         * is allowed to reset.
         */
-       if (of_get_property(mpic->node, "pic-no-reset", NULL))
-               mpic->flags |= MPIC_NO_RESET;
-
-       if ((flags & MPIC_WANTS_RESET) && !(mpic->flags & MPIC_NO_RESET)) {
+       if (!(mpic->flags & MPIC_NO_RESET)) {
                printk(KERN_DEBUG "mpic: Resetting\n");
                mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),
                           mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
@@ -1297,30 +1297,16 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        }
 
        /* CoreInt */
-       if (flags & MPIC_ENABLE_COREINT)
+       if (mpic->flags & MPIC_ENABLE_COREINT)
                mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),
                           mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
                           | MPIC_GREG_GCONF_COREINT);
 
-       if (flags & MPIC_ENABLE_MCK)
+       if (mpic->flags & MPIC_ENABLE_MCK)
                mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0),
                           mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0))
                           | MPIC_GREG_GCONF_MCK);
 
-       /*
-        * Read feature register.  For non-ISU MPICs, num sources as well. On
-        * ISU MPICs, sources are counted as ISUs are added
-        */
-       greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0));
-       if (isu_size == 0) {
-               if (flags & MPIC_BROKEN_FRR_NIRQS)
-                       mpic->num_sources = mpic->irq_count;
-               else
-                       mpic->num_sources =
-                               ((greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK)
-                                >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1;
-       }
-
        /*
         * The MPIC driver will crash if there are more cores than we
         * can initialize, so we may as well catch that problem here.
@@ -1336,17 +1322,41 @@ struct mpic * __init mpic_alloc(struct device_node *node,
                         0x1000);
        }
 
+       /*
+        * Read feature register.  For non-ISU MPICs, num sources as well. On
+        * ISU MPICs, sources are counted as ISUs are added
+        */
+       greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0));
+
+       /*
+        * By default, the last source number comes from the MPIC, but the
+        * device-tree and board support code can override it on buggy hw.
+        * If we get passed an isu_size (multi-isu MPIC) then we use that
+        * as a default instead of the value read from the HW.
+        */
+       last_irq = (greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK)
+                               >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT;    
+       if (isu_size)
+               last_irq = isu_size  * MPIC_MAX_ISU - 1;
+       of_property_read_u32(mpic->node, "last-interrupt-source", &last_irq);
+       if (irq_count)
+               last_irq = irq_count - 1;
+
        /* Initialize main ISU if none provided */
-       if (mpic->isu_size == 0) {
-               mpic->isu_size = mpic->num_sources;
+       if (!isu_size) {
+               isu_size = last_irq + 1;
+               mpic->num_sources = isu_size;
                mpic_map(mpic, mpic->paddr, &mpic->isus[0],
-                        MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size);
+                               MPIC_INFO(IRQ_BASE),
+                               MPIC_INFO(IRQ_STRIDE) * isu_size);
        }
+
+       mpic->isu_size = isu_size;
        mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1);
        mpic->isu_mask = (1 << mpic->isu_shift) - 1;
 
        mpic->irqhost = irq_domain_add_linear(mpic->node,
-                                      isu_size ? isu_size : mpic->num_sources,
+                                      last_irq + 1,
                                       &mpic_host_ops, mpic);
 
        /*
@@ -1380,7 +1390,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        mpic->next = mpics;
        mpics = mpic;
 
-       if (!(flags & MPIC_SECONDARY)) {
+       if (!(mpic->flags & MPIC_SECONDARY)) {
                mpic_primary = mpic;
                irq_set_default_host(mpic->irqhost);
        }
@@ -1447,10 +1457,6 @@ void __init mpic_init(struct mpic *mpic)
                               (mpic->ipi_vecs[0] + i));
        }
 
-       /* Initialize interrupt sources */
-       if (mpic->irq_count == 0)
-               mpic->irq_count = mpic->num_sources;
-
        /* Do the HT PIC fixups on U3 broken mpic */
        DBG("MPIC flags: %x\n", mpic->flags);
        if ((mpic->flags & MPIC_U3_HT_IRQS) && !(mpic->flags & MPIC_SECONDARY)) {