aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorGavin Shan <shangw@linux.vnet.ibm.com>2012-02-27 15:04:01 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-03-08 19:11:11 -0500
commit1823fbf119e434dd3fb8eb7482613994c09d8527 (patch)
tree650f1b2e6aad8a4764dd3f23762c5eaf7d28badf /arch/powerpc
parent8d633291b4fc0539ecad31f972447104be6953ec (diff)
powerpc/eeh: pseries platform EEH configure bridge
In order to enable particular PCI device, which has been included in the parent PE. The involved PCI bridges should be enabled explicitly if there has. On pSeries platform, there're dedicated RTAS calls to fulfil the purpose. The patch implements the function of configuring PCI bridges through the dedicated RTAS calls. Besides, the function has been abstracted by struct eeh_ops::configure_bridge so that the EEH core components could support multiple platforms in future. Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/include/asm/ppc-pci.h1
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c44
-rw-r--r--arch/powerpc/platforms/pseries/eeh_driver.c2
-rw-r--r--arch/powerpc/platforms/pseries/eeh_pseries.c29
4 files changed, 30 insertions, 46 deletions
diff --git a/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h
index bd1a84f65292..b4b18d82b79b 100644
--- a/arch/powerpc/include/asm/ppc-pci.h
+++ b/arch/powerpc/include/asm/ppc-pci.h
@@ -57,7 +57,6 @@ void eeh_slot_error_detail (struct pci_dn *pdn, int severity);
57int eeh_pci_enable(struct pci_dn *pdn, int function); 57int eeh_pci_enable(struct pci_dn *pdn, int function);
58int eeh_reset_pe(struct pci_dn *); 58int eeh_reset_pe(struct pci_dn *);
59void eeh_restore_bars(struct pci_dn *); 59void eeh_restore_bars(struct pci_dn *);
60void eeh_configure_bridge(struct pci_dn *);
61int rtas_write_config(struct pci_dn *, int where, int size, u32 val); 60int rtas_write_config(struct pci_dn *, int where, int size, u32 val);
62int rtas_read_config(struct pci_dn *, int where, int size, u32 *val); 61int rtas_read_config(struct pci_dn *, int where, int size, u32 *val);
63void eeh_mark_slot(struct device_node *dn, int mode_flag); 62void eeh_mark_slot(struct device_node *dn, int mode_flag);
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 39fcecb1c16b..bd4ed83863f8 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -86,10 +86,6 @@
86/* Time to wait for a PCI slot to report status, in milliseconds */ 86/* Time to wait for a PCI slot to report status, in milliseconds */
87#define PCI_BUS_RESET_WAIT_MSEC (60*1000) 87#define PCI_BUS_RESET_WAIT_MSEC (60*1000)
88 88
89/* RTAS tokens */
90static int ibm_configure_bridge;
91static int ibm_configure_pe;
92
93/* Platform dependent EEH operations */ 89/* Platform dependent EEH operations */
94struct eeh_ops *eeh_ops = NULL; 90struct eeh_ops *eeh_ops = NULL;
95 91
@@ -229,7 +225,7 @@ void eeh_slot_error_detail(struct pci_dn *pdn, int severity)
229 pci_regs_buf[0] = 0; 225 pci_regs_buf[0] = 0;
230 226
231 eeh_pci_enable(pdn, EEH_OPT_THAW_MMIO); 227 eeh_pci_enable(pdn, EEH_OPT_THAW_MMIO);
232 eeh_configure_bridge(pdn); 228 eeh_ops->configure_bridge(pdn->node);
233 eeh_restore_bars(pdn); 229 eeh_restore_bars(pdn);
234 loglen = eeh_gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN); 230 loglen = eeh_gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN);
235 231
@@ -810,41 +806,6 @@ static void eeh_save_bars(struct pci_dn *pdn)
810} 806}
811 807
812/** 808/**
813 * eeh_configure_bridge - Configure PCI bridges for the indicated PE
814 * @pdn: PCI device node
815 *
816 * PCI bridges might be included in PE. In order to make the PE work
817 * again. The included PCI bridges should be recovered after the PE
818 * encounters frozen state.
819 */
820void eeh_configure_bridge(struct pci_dn *pdn)
821{
822 int config_addr;
823 int rc;
824 int token;
825
826 /* Use PE configuration address, if present */
827 config_addr = pdn->eeh_config_addr;
828 if (pdn->eeh_pe_config_addr)
829 config_addr = pdn->eeh_pe_config_addr;
830
831 /* Use new configure-pe function, if supported */
832 if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE)
833 token = ibm_configure_pe;
834 else
835 token = ibm_configure_bridge;
836
837 rc = rtas_call(token, 3, 1, NULL,
838 config_addr,
839 BUID_HI(pdn->phb->buid),
840 BUID_LO(pdn->phb->buid));
841 if (rc) {
842 printk(KERN_WARNING "EEH: Unable to configure device bridge (%d) for %s\n",
843 rc, pdn->node->full_name);
844 }
845}
846
847/**
848 * eeh_early_enable - Early enable EEH on the indicated device 809 * eeh_early_enable - Early enable EEH on the indicated device
849 * @dn: device node 810 * @dn: device node
850 * @data: BUID 811 * @data: BUID
@@ -1027,9 +988,6 @@ void __init eeh_init(void)
1027 if (np == NULL) 988 if (np == NULL)
1028 return; 989 return;
1029 990
1030 ibm_configure_bridge = rtas_token("ibm,configure-bridge");
1031 ibm_configure_pe = rtas_token("ibm,configure-pe");
1032
1033 /* Enable EEH for all adapters. Note that eeh requires buid's */ 991 /* Enable EEH for all adapters. Note that eeh requires buid's */
1034 for (phb = of_find_node_by_name(NULL, "pci"); phb; 992 for (phb = of_find_node_by_name(NULL, "pci"); phb;
1035 phb = of_find_node_by_name(phb, "pci")) { 993 phb = of_find_node_by_name(phb, "pci")) {
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index 68403573a1f4..61450e1b3f7d 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -295,7 +295,7 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)
295 struct pci_dn *ppe = PCI_DN(dn); 295 struct pci_dn *ppe = PCI_DN(dn);
296 /* On Power4, always true because eeh_pe_config_addr=0 */ 296 /* On Power4, always true because eeh_pe_config_addr=0 */
297 if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) { 297 if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) {
298 eeh_configure_bridge(ppe); 298 eeh_ops->configure_bridge(dn);
299 eeh_restore_bars(ppe); 299 eeh_restore_bars(ppe);
300 } 300 }
301 dn = dn->sibling; 301 dn = dn->sibling;
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
index 7c8434f902bc..4ed06b24ba49 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -473,7 +473,34 @@ static int pseries_eeh_get_log(struct device_node *dn, int severity, char *drv_l
473 */ 473 */
474static int pseries_eeh_configure_bridge(struct device_node *dn) 474static int pseries_eeh_configure_bridge(struct device_node *dn)
475{ 475{
476 return 0; 476 struct pci_dn *pdn;
477 int config_addr;
478 int ret;
479
480 /* Figure out the PE address */
481 pdn = PCI_DN(dn);
482 config_addr = pdn->eeh_config_addr;
483 if (pdn->eeh_pe_config_addr)
484 config_addr = pdn->eeh_pe_config_addr;
485
486 /* Use new configure-pe function, if supported */
487 if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) {
488 ret = rtas_call(ibm_configure_pe, 3, 1, NULL,
489 config_addr, BUID_HI(pdn->phb->buid),
490 BUID_LO(pdn->phb->buid));
491 } else if (ibm_configure_bridge != RTAS_UNKNOWN_SERVICE) {
492 ret = rtas_call(ibm_configure_bridge, 3, 1, NULL,
493 config_addr, BUID_HI(pdn->phb->buid),
494 BUID_LO(pdn->phb->buid));
495 } else {
496 return -EFAULT;
497 }
498
499 if (ret)
500 pr_warning("%s: Unable to configure bridge %d for %s\n",
501 __func__, ret, dn->full_name);
502
503 return ret;
477} 504}
478 505
479static struct eeh_ops pseries_eeh_ops = { 506static struct eeh_ops pseries_eeh_ops = {