powerpc/powernv: Patch MSI EOI handler on P8
authorGavin Shan <shangw@linux.vnet.ibm.com>
Thu, 25 Apr 2013 19:20:59 +0000 (19:20 +0000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Fri, 26 Apr 2013 06:09:59 +0000 (16:09 +1000)
The EOI handler of MSI/MSI-X interrupts for P8 (PHB3) need additional
steps to handle the P/Q bits in IVE before EOIing the corresponding
interrupt. The patch changes the EOI handler to cover that. we have
individual IRQ chip in each PHB instance. During the MSI IRQ setup
time, the IRQ chip is copied over from the original one for that IRQ,
and the EOI handler is patched with the one that will handle the P/Q
bits (As Ben suggested).

Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/include/asm/opal.h
arch/powerpc/include/asm/xics.h
arch/powerpc/platforms/powernv/opal-wrappers.S
arch/powerpc/platforms/powernv/pci-ioda.c
arch/powerpc/platforms/powernv/pci-p5ioc2.c
arch/powerpc/platforms/powernv/pci.c
arch/powerpc/platforms/powernv/pci.h
arch/powerpc/sysdev/xics/icp-native.c

index a4b28f165b6c90ef48480b858d23bd0ecd8ffb52..b6c8b58b1d764c5d1d8255fbc62df86b6b88c83e 100644 (file)
@@ -117,6 +117,7 @@ extern int opal_enter_rtas(struct rtas_args *args,
 #define OPAL_SET_SLOT_LED_STATUS               55
 #define OPAL_GET_EPOW_STATUS                   56
 #define OPAL_SET_SYSTEM_ATTENTION_LED          57
+#define OPAL_PCI_MSI_EOI                       63
 
 #ifndef __ASSEMBLY__
 
@@ -506,6 +507,7 @@ int64_t opal_pci_get_xive_reissue(uint64_t phb_id, uint32_t xive_number,
                                  uint8_t *p_bit, uint8_t *q_bit);
 int64_t opal_pci_set_xive_reissue(uint64_t phb_id, uint32_t xive_number,
                                  uint8_t p_bit, uint8_t q_bit);
+int64_t opal_pci_msi_eoi(uint64_t phb_id, uint32_t hw_irq);
 int64_t opal_pci_set_xive_pe(uint64_t phb_id, uint32_t pe_number,
                             uint32_t xive_num);
 int64_t opal_get_xive_source(uint64_t phb_id, uint32_t xive_num,
index 4ae9a09c3b892700241a0e43d74b2ff0806959fe..282d43a0c85566927755dc71d6a2ce9b5bd40d4a 100644 (file)
@@ -150,6 +150,7 @@ extern void xics_register_ics(struct ics *ics);
 extern void xics_teardown_cpu(void);
 extern void xics_kexec_teardown_cpu(int secondary);
 extern void xics_migrate_irqs_away(void);
+extern void icp_native_eoi(struct irq_data *d);
 #ifdef CONFIG_SMP
 extern int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask,
                               unsigned int strict_check);
index 3bb07e5e43cdc24f64ce70716a1530431f067cd5..6fabe92eafb6a122d0286c9a3dd70e1e4eeb793e 100644 (file)
@@ -107,3 +107,4 @@ OPAL_CALL(opal_pci_mask_pe_error,           OPAL_PCI_MASK_PE_ERROR);
 OPAL_CALL(opal_set_slot_led_status,            OPAL_SET_SLOT_LED_STATUS);
 OPAL_CALL(opal_get_epow_status,                        OPAL_GET_EPOW_STATUS);
 OPAL_CALL(opal_set_system_attention_led,       OPAL_SET_SYSTEM_ATTENTION_LED);
+OPAL_CALL(opal_pci_msi_eoi,                    OPAL_PCI_MSI_EOI);
index 3d4e9588a6955e1bbd49acf1664dbdc847b86c12..3f88c51cb95b5c518e6b03da66647b03232309ee 100644 (file)
@@ -31,6 +31,7 @@
 #include <asm/opal.h>
 #include <asm/iommu.h>
 #include <asm/tce.h>
+#include <asm/xics.h>
 
 #include "powernv.h"
 #include "pci.h"
@@ -589,11 +590,27 @@ static void pnv_ioda_setup_dma(struct pnv_phb *phb)
 }
 
 #ifdef CONFIG_PCI_MSI
+static void pnv_ioda2_msi_eoi(struct irq_data *d)
+{
+       unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
+       struct irq_chip *chip = irq_data_get_irq_chip(d);
+       struct pnv_phb *phb = container_of(chip, struct pnv_phb,
+                                          ioda.irq_chip);
+       int64_t rc;
+
+       rc = opal_pci_msi_eoi(phb->opal_id, hw_irq);
+       WARN_ON_ONCE(rc);
+
+       icp_native_eoi(d);
+}
+
 static int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev,
-                                 unsigned int hwirq, unsigned int is_64,
-                                 struct msi_msg *msg)
+                                 unsigned int hwirq, unsigned int virq,
+                                 unsigned int is_64, struct msi_msg *msg)
 {
        struct pnv_ioda_pe *pe = pnv_ioda_get_pe(dev);
+       struct irq_data *idata;
+       struct irq_chip *ichip;
        unsigned int xive_num = hwirq - phb->msi_base;
        uint64_t addr64;
        uint32_t addr32, data;
@@ -638,6 +655,23 @@ static int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev,
        }
        msg->data = data;
 
+       /*
+        * Change the IRQ chip for the MSI interrupts on PHB3.
+        * The corresponding IRQ chip should be populated for
+        * the first time.
+        */
+       if (phb->type == PNV_PHB_IODA2) {
+               if (!phb->ioda.irq_chip_init) {
+                       idata = irq_get_irq_data(virq);
+                       ichip = irq_data_get_irq_chip(idata);
+                       phb->ioda.irq_chip_init = 1;
+                       phb->ioda.irq_chip = *ichip;
+                       phb->ioda.irq_chip.irq_eoi = pnv_ioda2_msi_eoi;
+               }
+
+               irq_set_chip(virq, &phb->ioda.irq_chip);
+       }
+
        pr_devel("%s: %s-bit MSI on hwirq %x (xive #%d),"
                 " address=%x_%08x data=%x PE# %d\n",
                 pci_name(dev), is_64 ? "64" : "32", hwirq, xive_num,
index d5c066ea7d1f705de8d257e1682c423523c628a2..92b37a0186c93c277443a92e082b3736ceeee1bc 100644 (file)
@@ -42,8 +42,8 @@
 
 #ifdef CONFIG_PCI_MSI
 static int pnv_pci_p5ioc2_msi_setup(struct pnv_phb *phb, struct pci_dev *dev,
-                                   unsigned int hwirq, unsigned int is_64,
-                                   struct msi_msg *msg)
+                                   unsigned int hwirq, unsigned int virq,
+                                   unsigned int is_64, struct msi_msg *msg)
 {
        if (WARN_ON(!is_64))
                return -ENXIO;
index a11b5a60c91eb6b9a2851bd2ec4e39bb1a690459..861e185483fe979cd173933d153eca990a355d6b 100644 (file)
@@ -84,7 +84,7 @@ static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
                        return -ENOMEM;
                }
                rc = phb->msi_setup(phb, pdev, phb->msi_base + hwirq,
-                                   entry->msi_attrib.is_64, &msg);
+                                   virq, entry->msi_attrib.is_64, &msg);
                if (rc) {
                        pr_warn("%s: Failed to setup MSI\n", pci_name(pdev));
                        irq_dispose_mapping(virq);
index f6314d65c4d98ec23ee132e0dc0713f5cf8e75f9..3c552b3dd0c6cd7f6442c6855cda1ef370e1eedb 100644 (file)
@@ -79,8 +79,8 @@ struct pnv_phb {
        struct msi_bitmap       msi_bmp;
 #endif
        int (*msi_setup)(struct pnv_phb *phb, struct pci_dev *dev,
-                        unsigned int hwirq, unsigned int is_64,
-                        struct msi_msg *msg);
+                        unsigned int hwirq, unsigned int virq,
+                        unsigned int is_64, struct msi_msg *msg);
        void (*dma_dev_setup)(struct pnv_phb *phb, struct pci_dev *pdev);
        void (*fixup_phb)(struct pci_controller *hose);
        u32 (*bdfn_to_pe)(struct pnv_phb *phb, struct pci_bus *bus, u32 devfn);
@@ -108,6 +108,10 @@ struct pnv_phb {
                        unsigned int            *io_segmap;
                        struct pnv_ioda_pe      *pe_array;
 
+                       /* IRQ chip */
+                       int                     irq_chip_init;
+                       struct irq_chip         irq_chip;
+
                        /* Sorted list of used PE's based
                         * on the sequence of creation
                         */
index 48861d3fcd070cbc56f4e4189e4396f7196938c4..89db29d17c25fcea905814879b9f75b16cda58ed 100644 (file)
@@ -81,7 +81,7 @@ static void icp_native_set_cpu_priority(unsigned char cppr)
        iosync();
 }
 
-static void icp_native_eoi(struct irq_data *d)
+void icp_native_eoi(struct irq_data *d)
 {
        unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);