powerpc/eeh: Trace PCI bus from PE
authorGavin Shan <shangw@linux.vnet.ibm.com>
Thu, 20 Jun 2013 05:20:55 +0000 (13:20 +0800)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Thu, 20 Jun 2013 07:05:45 +0000 (17:05 +1000)
There're several types of PEs can be supported for now: PHB, Bus
and Device dependent PE. For PCI bus dependent PE, tracing the
corresponding PCI bus from PE (struct eeh_pe) would make the code
more efficient. The patch also enables the retrieval of PCI bus based
on the PCI bus dependent PE.

Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/include/asm/eeh.h
arch/powerpc/kernel/eeh_pe.c

index acdfcaaf5c361c8ed836b02e629db9663bf2a47b..f3b49d6d5259ab67b4d22476d88a6a78c3b25a3a 100644 (file)
@@ -59,6 +59,7 @@ struct eeh_pe {
        int config_addr;                /* Traditional PCI address      */
        int addr;                       /* PE configuration address     */
        struct pci_controller *phb;     /* Associated PHB               */
+       struct pci_bus *bus;            /* Top PCI bus for bus PE       */
        int check_count;                /* Times of ignored error       */
        int freeze_count;               /* Times of froze up            */
        int false_positives;            /* Times of reported #ff's      */
index 3d2dcf5afc295c4843a3c76a11840fe8c3d42e5d..c96366758acfea8ff0301177f0d280c2fd74fbc4 100644 (file)
@@ -364,6 +364,17 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
        pe->addr        = edev->pe_config_addr;
        pe->config_addr = edev->config_addr;
 
+       /*
+        * While doing PE reset, we probably hot-reset the
+        * upstream bridge. However, the PCI devices including
+        * the associated EEH devices might be removed when EEH
+        * core is doing recovery. So that won't safe to retrieve
+        * the bridge through downstream EEH device. We have to
+        * trace the parent PCI bus, then the upstream bridge.
+        */
+       if (eeh_probe_mode_dev())
+               pe->bus = eeh_dev_to_pci_dev(edev)->bus;
+
        /*
         * Put the new EEH PE into hierarchy tree. If the parent
         * can't be found, the newly created PE will be attached
@@ -641,12 +652,18 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe)
                bus = pe->phb->bus;
        } else if (pe->type & EEH_PE_BUS ||
                   pe->type & EEH_PE_DEVICE) {
+               if (pe->bus) {
+                       bus = pe->bus;
+                       goto out;
+               }
+
                edev = list_first_entry(&pe->edevs, struct eeh_dev, list);
                pdev = eeh_dev_to_pci_dev(edev);
                if (pdev)
                        bus = pdev->bus;
        }
 
+out:
        eeh_unlock();
 
        return bus;