Merge branch 'akpm' (patches from Andrew)
[linux-2.6-microblaze.git] / arch / powerpc / sysdev / xive / common.c
index 595310e..a830432 100644 (file)
@@ -63,8 +63,19 @@ static const struct xive_ops *xive_ops;
 static struct irq_domain *xive_irq_domain;
 
 #ifdef CONFIG_SMP
-/* The IPIs all use the same logical irq number */
-static u32 xive_ipi_irq;
+/* The IPIs use the same logical irq number when on the same chip */
+static struct xive_ipi_desc {
+       unsigned int irq;
+       char name[16];
+} *xive_ipis;
+
+/*
+ * Use early_cpu_to_node() for hot-plugged CPUs
+ */
+static unsigned int xive_ipi_cpu_to_irq(unsigned int cpu)
+{
+       return xive_ipis[early_cpu_to_node(cpu)].irq;
+}
 #endif
 
 /* Xive state for each CPU */
@@ -253,17 +264,20 @@ notrace void xmon_xive_do_dump(int cpu)
        xmon_printf("\n");
 }
 
+static struct irq_data *xive_get_irq_data(u32 hw_irq)
+{
+       unsigned int irq = irq_find_mapping(xive_irq_domain, hw_irq);
+
+       return irq ? irq_get_irq_data(irq) : NULL;
+}
+
 int xmon_xive_get_irq_config(u32 hw_irq, struct irq_data *d)
 {
-       struct irq_chip *chip = irq_data_get_irq_chip(d);
        int rc;
        u32 target;
        u8 prio;
        u32 lirq;
 
-       if (!is_xive_irq(chip))
-               return -EINVAL;
-
        rc = xive_ops->get_irq_config(hw_irq, &target, &prio, &lirq);
        if (rc) {
                xmon_printf("IRQ 0x%08x : no config rc=%d\n", hw_irq, rc);
@@ -273,6 +287,9 @@ int xmon_xive_get_irq_config(u32 hw_irq, struct irq_data *d)
        xmon_printf("IRQ 0x%08x : target=0x%x prio=%02x lirq=0x%x ",
                    hw_irq, target, prio, lirq);
 
+       if (!d)
+               d = xive_get_irq_data(hw_irq);
+
        if (d) {
                struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
                u64 val = xive_esb_read(xd, XIVE_ESB_GET);
@@ -289,6 +306,20 @@ int xmon_xive_get_irq_config(u32 hw_irq, struct irq_data *d)
        return 0;
 }
 
+void xmon_xive_get_irq_all(void)
+{
+       unsigned int i;
+       struct irq_desc *desc;
+
+       for_each_irq_desc(i, desc) {
+               struct irq_data *d = irq_desc_get_irq_data(desc);
+               unsigned int hwirq = (unsigned int)irqd_to_hwirq(d);
+
+               if (d->domain == xive_irq_domain)
+                       xmon_xive_get_irq_config(hwirq, d);
+       }
+}
+
 #endif /* CONFIG_XMON */
 
 static unsigned int xive_get_irq(void)
@@ -959,16 +990,12 @@ EXPORT_SYMBOL_GPL(is_xive_irq);
 void xive_cleanup_irq_data(struct xive_irq_data *xd)
 {
        if (xd->eoi_mmio) {
-               unmap_kernel_range((unsigned long)xd->eoi_mmio,
-                                  1u << xd->esb_shift);
                iounmap(xd->eoi_mmio);
                if (xd->eoi_mmio == xd->trig_mmio)
                        xd->trig_mmio = NULL;
                xd->eoi_mmio = NULL;
        }
        if (xd->trig_mmio) {
-               unmap_kernel_range((unsigned long)xd->trig_mmio,
-                                  1u << xd->esb_shift);
                iounmap(xd->trig_mmio);
                xd->trig_mmio = NULL;
        }
@@ -1067,28 +1094,94 @@ static struct irq_chip xive_ipi_chip = {
        .irq_unmask = xive_ipi_do_nothing,
 };
 
-static void __init xive_request_ipi(void)
+/*
+ * IPIs are marked per-cpu. We use separate HW interrupts under the
+ * hood but associated with the same "linux" interrupt
+ */
+struct xive_ipi_alloc_info {
+       irq_hw_number_t hwirq;
+};
+
+static int xive_ipi_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
+                                    unsigned int nr_irqs, void *arg)
 {
-       unsigned int virq;
+       struct xive_ipi_alloc_info *info = arg;
+       int i;
 
-       /*
-        * Initialization failed, move on, we might manage to
-        * reach the point where we display our errors before
-        * the system falls appart
-        */
-       if (!xive_irq_domain)
-               return;
+       for (i = 0; i < nr_irqs; i++) {
+               irq_domain_set_info(domain, virq + i, info->hwirq + i, &xive_ipi_chip,
+                                   domain->host_data, handle_percpu_irq,
+                                   NULL, NULL);
+       }
+       return 0;
+}
 
-       /* Initialize it */
-       virq = irq_create_mapping(xive_irq_domain, XIVE_IPI_HW_IRQ);
-       xive_ipi_irq = virq;
+static const struct irq_domain_ops xive_ipi_irq_domain_ops = {
+       .alloc  = xive_ipi_irq_domain_alloc,
+};
 
-       WARN_ON(request_irq(virq, xive_muxed_ipi_action,
-                           IRQF_PERCPU | IRQF_NO_THREAD, "IPI", NULL));
+static int __init xive_request_ipi(void)
+{
+       struct fwnode_handle *fwnode;
+       struct irq_domain *ipi_domain;
+       unsigned int node;
+       int ret = -ENOMEM;
+
+       fwnode = irq_domain_alloc_named_fwnode("XIVE-IPI");
+       if (!fwnode)
+               goto out;
+
+       ipi_domain = irq_domain_create_linear(fwnode, nr_node_ids,
+                                             &xive_ipi_irq_domain_ops, NULL);
+       if (!ipi_domain)
+               goto out_free_fwnode;
+
+       xive_ipis = kcalloc(nr_node_ids, sizeof(*xive_ipis), GFP_KERNEL | __GFP_NOFAIL);
+       if (!xive_ipis)
+               goto out_free_domain;
+
+       for_each_node(node) {
+               struct xive_ipi_desc *xid = &xive_ipis[node];
+               struct xive_ipi_alloc_info info = { node };
+
+               /* Skip nodes without CPUs */
+               if (cpumask_empty(cpumask_of_node(node)))
+                       continue;
+
+               /*
+                * Map one IPI interrupt per node for all cpus of that node.
+                * Since the HW interrupt number doesn't have any meaning,
+                * simply use the node number.
+                */
+               xid->irq = irq_domain_alloc_irqs(ipi_domain, 1, node, &info);
+               if (xid->irq < 0) {
+                       ret = xid->irq;
+                       goto out_free_xive_ipis;
+               }
+
+               snprintf(xid->name, sizeof(xid->name), "IPI-%d", node);
+
+               ret = request_irq(xid->irq, xive_muxed_ipi_action,
+                                 IRQF_PERCPU | IRQF_NO_THREAD, xid->name, NULL);
+
+               WARN(ret < 0, "Failed to request IPI %d: %d\n", xid->irq, ret);
+       }
+
+       return ret;
+
+out_free_xive_ipis:
+       kfree(xive_ipis);
+out_free_domain:
+       irq_domain_remove(ipi_domain);
+out_free_fwnode:
+       irq_domain_free_fwnode(fwnode);
+out:
+       return ret;
 }
 
 static int xive_setup_cpu_ipi(unsigned int cpu)
 {
+       unsigned int xive_ipi_irq = xive_ipi_cpu_to_irq(cpu);
        struct xive_cpu *xc;
        int rc;
 
@@ -1131,6 +1224,8 @@ static int xive_setup_cpu_ipi(unsigned int cpu)
 
 static void xive_cleanup_cpu_ipi(unsigned int cpu, struct xive_cpu *xc)
 {
+       unsigned int xive_ipi_irq = xive_ipi_cpu_to_irq(cpu);
+
        /* Disable the IPI and free the IRQ data */
 
        /* Already cleaned up ? */
@@ -1178,19 +1273,6 @@ static int xive_irq_domain_map(struct irq_domain *h, unsigned int virq,
         */
        irq_clear_status_flags(virq, IRQ_LEVEL);
 
-#ifdef CONFIG_SMP
-       /* IPIs are special and come up with HW number 0 */
-       if (hw == XIVE_IPI_HW_IRQ) {
-               /*
-                * IPIs are marked per-cpu. We use separate HW interrupts under
-                * the hood but associated with the same "linux" interrupt
-                */
-               irq_set_chip_and_handler(virq, &xive_ipi_chip,
-                                        handle_percpu_irq);
-               return 0;
-       }
-#endif
-
        rc = xive_irq_alloc_data(virq, hw);
        if (rc)
                return rc;
@@ -1202,15 +1284,7 @@ static int xive_irq_domain_map(struct irq_domain *h, unsigned int virq,
 
 static void xive_irq_domain_unmap(struct irq_domain *d, unsigned int virq)
 {
-       struct irq_data *data = irq_get_irq_data(virq);
-       unsigned int hw_irq;
-
-       /* XXX Assign BAD number */
-       if (!data)
-               return;
-       hw_irq = (unsigned int)irqd_to_hwirq(data);
-       if (hw_irq != XIVE_IPI_HW_IRQ)
-               xive_irq_free_data(virq);
+       xive_irq_free_data(virq);
 }
 
 static int xive_irq_domain_xlate(struct irq_domain *h, struct device_node *ct,
@@ -1335,17 +1409,14 @@ static int xive_prepare_cpu(unsigned int cpu)
 
        xc = per_cpu(xive_cpu, cpu);
        if (!xc) {
-               struct device_node *np;
-
                xc = kzalloc_node(sizeof(struct xive_cpu),
                                  GFP_KERNEL, cpu_to_node(cpu));
                if (!xc)
                        return -ENOMEM;
-               np = of_get_cpu_node(cpu, NULL);
-               if (np)
-                       xc->chip_id = of_get_ibm_chip_id(np);
-               of_node_put(np);
                xc->hw_ipi = XIVE_BAD_IRQ;
+               xc->chip_id = XIVE_INVALID_CHIP_ID;
+               if (xive_ops->prepare_cpu)
+                       xive_ops->prepare_cpu(cpu, xc);
 
                per_cpu(xive_cpu, cpu) = xc;
        }
@@ -1408,13 +1479,12 @@ static void xive_flush_cpu_queue(unsigned int cpu, struct xive_cpu *xc)
                struct irq_desc *desc = irq_to_desc(irq);
                struct irq_data *d = irq_desc_get_irq_data(desc);
                struct xive_irq_data *xd;
-               unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
 
                /*
                 * Ignore anything that isn't a XIVE irq and ignore
                 * IPIs, so can just be dropped.
                 */
-               if (d->domain != xive_irq_domain || hw_irq == XIVE_IPI_HW_IRQ)
+               if (d->domain != xive_irq_domain)
                        continue;
 
                /*
@@ -1592,16 +1662,15 @@ static void xive_debug_show_cpu(struct seq_file *m, int cpu)
        seq_puts(m, "\n");
 }
 
-static void xive_debug_show_irq(struct seq_file *m, u32 hw_irq, struct irq_data *d)
+static void xive_debug_show_irq(struct seq_file *m, struct irq_data *d)
 {
-       struct irq_chip *chip = irq_data_get_irq_chip(d);
+       unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
        int rc;
        u32 target;
        u8 prio;
        u32 lirq;
-
-       if (!is_xive_irq(chip))
-               return;
+       struct xive_irq_data *xd;
+       u64 val;
 
        rc = xive_ops->get_irq_config(hw_irq, &target, &prio, &lirq);
        if (rc) {
@@ -1612,17 +1681,14 @@ static void xive_debug_show_irq(struct seq_file *m, u32 hw_irq, struct irq_data
        seq_printf(m, "IRQ 0x%08x : target=0x%x prio=%02x lirq=0x%x ",
                   hw_irq, target, prio, lirq);
 
-       if (d) {
-               struct xive_irq_data *xd = irq_data_get_irq_handler_data(d);
-               u64 val = xive_esb_read(xd, XIVE_ESB_GET);
-
-               seq_printf(m, "flags=%c%c%c PQ=%c%c",
-                          xd->flags & XIVE_IRQ_FLAG_STORE_EOI ? 'S' : ' ',
-                          xd->flags & XIVE_IRQ_FLAG_LSI ? 'L' : ' ',
-                          xd->flags & XIVE_IRQ_FLAG_H_INT_ESB ? 'H' : ' ',
-                          val & XIVE_ESB_VAL_P ? 'P' : '-',
-                          val & XIVE_ESB_VAL_Q ? 'Q' : '-');
-       }
+       xd = irq_data_get_irq_handler_data(d);
+       val = xive_esb_read(xd, XIVE_ESB_GET);
+       seq_printf(m, "flags=%c%c%c PQ=%c%c",
+                  xd->flags & XIVE_IRQ_FLAG_STORE_EOI ? 'S' : ' ',
+                  xd->flags & XIVE_IRQ_FLAG_LSI ? 'L' : ' ',
+                  xd->flags & XIVE_IRQ_FLAG_H_INT_ESB ? 'H' : ' ',
+                  val & XIVE_ESB_VAL_P ? 'P' : '-',
+                  val & XIVE_ESB_VAL_Q ? 'Q' : '-');
        seq_puts(m, "\n");
 }
 
@@ -1640,16 +1706,9 @@ static int xive_core_debug_show(struct seq_file *m, void *private)
 
        for_each_irq_desc(i, desc) {
                struct irq_data *d = irq_desc_get_irq_data(desc);
-               unsigned int hw_irq;
-
-               if (!d)
-                       continue;
-
-               hw_irq = (unsigned int)irqd_to_hwirq(d);
 
-               /* IPIs are special (HW number 0) */
-               if (hw_irq != XIVE_IPI_HW_IRQ)
-                       xive_debug_show_irq(m, hw_irq, d);
+               if (d->domain == xive_irq_domain)
+                       xive_debug_show_irq(m, d);
        }
        return 0;
 }