powerpc/eeh: pseries platform EEH configure bridge
authorGavin Shan <shangw@linux.vnet.ibm.com>
Mon, 27 Feb 2012 20:04:01 +0000 (20:04 +0000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Fri, 9 Mar 2012 00:11:11 +0000 (11:11 +1100)
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>
arch/powerpc/include/asm/ppc-pci.h
arch/powerpc/platforms/pseries/eeh.c
arch/powerpc/platforms/pseries/eeh_driver.c
arch/powerpc/platforms/pseries/eeh_pseries.c

index bd1a84f652922ddbc641e4eda98dd0d32e28b36b..b4b18d82b79bbbdba90a926c7a5d6e0e8eb2d28a 100644 (file)
@@ -57,7 +57,6 @@ void eeh_slot_error_detail (struct pci_dn *pdn, int severity);
 int eeh_pci_enable(struct pci_dn *pdn, int function);
 int eeh_reset_pe(struct pci_dn *);
 void eeh_restore_bars(struct pci_dn *);
-void eeh_configure_bridge(struct pci_dn *);
 int rtas_write_config(struct pci_dn *, int where, int size, u32 val);
 int rtas_read_config(struct pci_dn *, int where, int size, u32 *val);
 void eeh_mark_slot(struct device_node *dn, int mode_flag);
index 39fcecb1c16b7a90a8e71f5399aed307e19a61ee..bd4ed83863f8f9aab7952308ed545a09ec4d2f0d 100644 (file)
 /* Time to wait for a PCI slot to report status, in milliseconds */
 #define PCI_BUS_RESET_WAIT_MSEC (60*1000)
 
-/* RTAS tokens */
-static int ibm_configure_bridge;
-static int ibm_configure_pe;
-
 /* Platform dependent EEH operations */
 struct eeh_ops *eeh_ops = NULL;
 
@@ -229,7 +225,7 @@ void eeh_slot_error_detail(struct pci_dn *pdn, int severity)
        pci_regs_buf[0] = 0;
 
        eeh_pci_enable(pdn, EEH_OPT_THAW_MMIO);
-       eeh_configure_bridge(pdn);
+       eeh_ops->configure_bridge(pdn->node);
        eeh_restore_bars(pdn);
        loglen = eeh_gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN);
 
@@ -809,41 +805,6 @@ static void eeh_save_bars(struct pci_dn *pdn)
                rtas_read_config(pdn, i * 4, 4, &pdn->config_space[i]);
 }
 
-/**
- * eeh_configure_bridge - Configure PCI bridges for the indicated PE
- * @pdn: PCI device node
- *
- * PCI bridges might be included in PE. In order to make the PE work
- * again. The included PCI bridges should be recovered after the PE
- * encounters frozen state.
- */
-void eeh_configure_bridge(struct pci_dn *pdn)
-{
-       int config_addr;
-       int rc;
-       int token;
-
-       /* Use PE configuration address, if present */
-       config_addr = pdn->eeh_config_addr;
-       if (pdn->eeh_pe_config_addr)
-               config_addr = pdn->eeh_pe_config_addr;
-
-       /* Use new configure-pe function, if supported */
-       if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE)
-               token = ibm_configure_pe;
-       else
-               token = ibm_configure_bridge;
-
-       rc = rtas_call(token, 3, 1, NULL,
-                      config_addr,
-                      BUID_HI(pdn->phb->buid),
-                      BUID_LO(pdn->phb->buid));
-       if (rc) {
-               printk(KERN_WARNING "EEH: Unable to configure device bridge (%d) for %s\n",
-                       rc, pdn->node->full_name);
-       }
-}
-
 /**
  * eeh_early_enable - Early enable EEH on the indicated device
  * @dn: device node
@@ -1027,9 +988,6 @@ void __init eeh_init(void)
        if (np == NULL)
                return;
 
-       ibm_configure_bridge = rtas_token("ibm,configure-bridge");
-       ibm_configure_pe = rtas_token("ibm,configure-pe");
-
        /* Enable EEH for all adapters.  Note that eeh requires buid's */
        for (phb = of_find_node_by_name(NULL, "pci"); phb;
             phb = of_find_node_by_name(phb, "pci")) {
index 68403573a1f4b5e7cb320dafd41eaf3d7cbcbfef..61450e1b3f7d31c51b1f3bb8cdb3437826342b05 100644 (file)
@@ -295,7 +295,7 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)
                struct pci_dn *ppe = PCI_DN(dn);
                /* On Power4, always true because eeh_pe_config_addr=0 */
                if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) {
-                       eeh_configure_bridge(ppe);
+                       eeh_ops->configure_bridge(dn);
                        eeh_restore_bars(ppe);
                }
                dn = dn->sibling;
index 7c8434f902bc14b2802cdd30ec9c7b28e4c87c02..4ed06b24ba495718618ef519d55052f69a73e713 100644 (file)
@@ -473,7 +473,34 @@ static int pseries_eeh_get_log(struct device_node *dn, int severity, char *drv_l
  */
 static int pseries_eeh_configure_bridge(struct device_node *dn)
 {
-       return 0;
+       struct pci_dn *pdn;
+       int config_addr;
+       int ret;
+
+       /* Figure out the PE address */
+       pdn = PCI_DN(dn);
+       config_addr = pdn->eeh_config_addr;
+       if (pdn->eeh_pe_config_addr)
+               config_addr = pdn->eeh_pe_config_addr;
+
+       /* Use new configure-pe function, if supported */
+       if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) {
+               ret = rtas_call(ibm_configure_pe, 3, 1, NULL,
+                               config_addr, BUID_HI(pdn->phb->buid),
+                               BUID_LO(pdn->phb->buid));
+       } else if (ibm_configure_bridge != RTAS_UNKNOWN_SERVICE) {
+               ret = rtas_call(ibm_configure_bridge, 3, 1, NULL,
+                               config_addr, BUID_HI(pdn->phb->buid),
+                               BUID_LO(pdn->phb->buid));
+       } else {
+               return -EFAULT;
+       }
+
+       if (ret)
+               pr_warning("%s: Unable to configure bridge %d for %s\n",
+                       __func__, ret, dn->full_name);
+
+       return ret;
 }
 
 static struct eeh_ops pseries_eeh_ops = {