aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms
diff options
context:
space:
mode:
authorGavin Shan <shangw@linux.vnet.ibm.com>2013-04-25 15:20:59 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-04-26 02:09:59 -0400
commit137436c9a6ee385c883db09e41af763888ee7642 (patch)
tree251fb4b23142e8dc05a5824359ba73e383b0434d /arch/powerpc/platforms
parenta486bdb0e9da8d876d6ff4efc3138d35e141c0b5 (diff)
powerpc/powernv: Patch MSI EOI handler on P8
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>
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r--arch/powerpc/platforms/powernv/opal-wrappers.S1
-rw-r--r--arch/powerpc/platforms/powernv/pci-ioda.c38
-rw-r--r--arch/powerpc/platforms/powernv/pci-p5ioc2.c4
-rw-r--r--arch/powerpc/platforms/powernv/pci.c2
-rw-r--r--arch/powerpc/platforms/powernv/pci.h8
5 files changed, 46 insertions, 7 deletions
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index 3bb07e5e43cd..6fabe92eafb6 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -107,3 +107,4 @@ OPAL_CALL(opal_pci_mask_pe_error, OPAL_PCI_MASK_PE_ERROR);
107OPAL_CALL(opal_set_slot_led_status, OPAL_SET_SLOT_LED_STATUS); 107OPAL_CALL(opal_set_slot_led_status, OPAL_SET_SLOT_LED_STATUS);
108OPAL_CALL(opal_get_epow_status, OPAL_GET_EPOW_STATUS); 108OPAL_CALL(opal_get_epow_status, OPAL_GET_EPOW_STATUS);
109OPAL_CALL(opal_set_system_attention_led, OPAL_SET_SYSTEM_ATTENTION_LED); 109OPAL_CALL(opal_set_system_attention_led, OPAL_SET_SYSTEM_ATTENTION_LED);
110OPAL_CALL(opal_pci_msi_eoi, OPAL_PCI_MSI_EOI);
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 3d4e9588a695..3f88c51cb95b 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -31,6 +31,7 @@
31#include <asm/opal.h> 31#include <asm/opal.h>
32#include <asm/iommu.h> 32#include <asm/iommu.h>
33#include <asm/tce.h> 33#include <asm/tce.h>
34#include <asm/xics.h>
34 35
35#include "powernv.h" 36#include "powernv.h"
36#include "pci.h" 37#include "pci.h"
@@ -589,11 +590,27 @@ static void pnv_ioda_setup_dma(struct pnv_phb *phb)
589} 590}
590 591
591#ifdef CONFIG_PCI_MSI 592#ifdef CONFIG_PCI_MSI
593static void pnv_ioda2_msi_eoi(struct irq_data *d)
594{
595 unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
596 struct irq_chip *chip = irq_data_get_irq_chip(d);
597 struct pnv_phb *phb = container_of(chip, struct pnv_phb,
598 ioda.irq_chip);
599 int64_t rc;
600
601 rc = opal_pci_msi_eoi(phb->opal_id, hw_irq);
602 WARN_ON_ONCE(rc);
603
604 icp_native_eoi(d);
605}
606
592static int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev, 607static int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev,
593 unsigned int hwirq, unsigned int is_64, 608 unsigned int hwirq, unsigned int virq,
594 struct msi_msg *msg) 609 unsigned int is_64, struct msi_msg *msg)
595{ 610{
596 struct pnv_ioda_pe *pe = pnv_ioda_get_pe(dev); 611 struct pnv_ioda_pe *pe = pnv_ioda_get_pe(dev);
612 struct irq_data *idata;
613 struct irq_chip *ichip;
597 unsigned int xive_num = hwirq - phb->msi_base; 614 unsigned int xive_num = hwirq - phb->msi_base;
598 uint64_t addr64; 615 uint64_t addr64;
599 uint32_t addr32, data; 616 uint32_t addr32, data;
@@ -638,6 +655,23 @@ static int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev,
638 } 655 }
639 msg->data = data; 656 msg->data = data;
640 657
658 /*
659 * Change the IRQ chip for the MSI interrupts on PHB3.
660 * The corresponding IRQ chip should be populated for
661 * the first time.
662 */
663 if (phb->type == PNV_PHB_IODA2) {
664 if (!phb->ioda.irq_chip_init) {
665 idata = irq_get_irq_data(virq);
666 ichip = irq_data_get_irq_chip(idata);
667 phb->ioda.irq_chip_init = 1;
668 phb->ioda.irq_chip = *ichip;
669 phb->ioda.irq_chip.irq_eoi = pnv_ioda2_msi_eoi;
670 }
671
672 irq_set_chip(virq, &phb->ioda.irq_chip);
673 }
674
641 pr_devel("%s: %s-bit MSI on hwirq %x (xive #%d)," 675 pr_devel("%s: %s-bit MSI on hwirq %x (xive #%d),"
642 " address=%x_%08x data=%x PE# %d\n", 676 " address=%x_%08x data=%x PE# %d\n",
643 pci_name(dev), is_64 ? "64" : "32", hwirq, xive_num, 677 pci_name(dev), is_64 ? "64" : "32", hwirq, xive_num,
diff --git a/arch/powerpc/platforms/powernv/pci-p5ioc2.c b/arch/powerpc/platforms/powernv/pci-p5ioc2.c
index d5c066ea7d1f..92b37a0186c9 100644
--- a/arch/powerpc/platforms/powernv/pci-p5ioc2.c
+++ b/arch/powerpc/platforms/powernv/pci-p5ioc2.c
@@ -42,8 +42,8 @@
42 42
43#ifdef CONFIG_PCI_MSI 43#ifdef CONFIG_PCI_MSI
44static int pnv_pci_p5ioc2_msi_setup(struct pnv_phb *phb, struct pci_dev *dev, 44static int pnv_pci_p5ioc2_msi_setup(struct pnv_phb *phb, struct pci_dev *dev,
45 unsigned int hwirq, unsigned int is_64, 45 unsigned int hwirq, unsigned int virq,
46 struct msi_msg *msg) 46 unsigned int is_64, struct msi_msg *msg)
47{ 47{
48 if (WARN_ON(!is_64)) 48 if (WARN_ON(!is_64))
49 return -ENXIO; 49 return -ENXIO;
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index a11b5a60c91e..861e185483fe 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -84,7 +84,7 @@ static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
84 return -ENOMEM; 84 return -ENOMEM;
85 } 85 }
86 rc = phb->msi_setup(phb, pdev, phb->msi_base + hwirq, 86 rc = phb->msi_setup(phb, pdev, phb->msi_base + hwirq,
87 entry->msi_attrib.is_64, &msg); 87 virq, entry->msi_attrib.is_64, &msg);
88 if (rc) { 88 if (rc) {
89 pr_warn("%s: Failed to setup MSI\n", pci_name(pdev)); 89 pr_warn("%s: Failed to setup MSI\n", pci_name(pdev));
90 irq_dispose_mapping(virq); 90 irq_dispose_mapping(virq);
diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h
index f6314d65c4d9..3c552b3dd0c6 100644
--- a/arch/powerpc/platforms/powernv/pci.h
+++ b/arch/powerpc/platforms/powernv/pci.h
@@ -79,8 +79,8 @@ struct pnv_phb {
79 struct msi_bitmap msi_bmp; 79 struct msi_bitmap msi_bmp;
80#endif 80#endif
81 int (*msi_setup)(struct pnv_phb *phb, struct pci_dev *dev, 81 int (*msi_setup)(struct pnv_phb *phb, struct pci_dev *dev,
82 unsigned int hwirq, unsigned int is_64, 82 unsigned int hwirq, unsigned int virq,
83 struct msi_msg *msg); 83 unsigned int is_64, struct msi_msg *msg);
84 void (*dma_dev_setup)(struct pnv_phb *phb, struct pci_dev *pdev); 84 void (*dma_dev_setup)(struct pnv_phb *phb, struct pci_dev *pdev);
85 void (*fixup_phb)(struct pci_controller *hose); 85 void (*fixup_phb)(struct pci_controller *hose);
86 u32 (*bdfn_to_pe)(struct pnv_phb *phb, struct pci_bus *bus, u32 devfn); 86 u32 (*bdfn_to_pe)(struct pnv_phb *phb, struct pci_bus *bus, u32 devfn);
@@ -108,6 +108,10 @@ struct pnv_phb {
108 unsigned int *io_segmap; 108 unsigned int *io_segmap;
109 struct pnv_ioda_pe *pe_array; 109 struct pnv_ioda_pe *pe_array;
110 110
111 /* IRQ chip */
112 int irq_chip_init;
113 struct irq_chip irq_chip;
114
111 /* Sorted list of used PE's based 115 /* Sorted list of used PE's based
112 * on the sequence of creation 116 * on the sequence of creation
113 */ 117 */