summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGavin Shan <shangw@linux.vnet.ibm.com>2013-06-20 13:20:56 +0800
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-06-20 17:05:48 +1000
commit51fb5f563274de01e47ad2cbdd48018557926fe3 (patch)
treeb91a352b42c828ce6603c08d5f660d58d8cd0001
parent8cdb283371241d298332c44d7c722e26d9858ec1 (diff)
powerpc/eeh: Make eeh_init() public
For EEH on PowerNV platform, we will do EEH probe based on the real PCI devices. The PCI devices are available after PCI probe. So we have to call eeh_init() explicitly on PowerNV platform after PCI probe. The patch also does EEH probe for PowerNV platform in eeh_init(). Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--arch/powerpc/include/asm/eeh.h8
-rw-r--r--arch/powerpc/kernel/eeh.c22
2 files changed, 27 insertions, 3 deletions
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index f3b49d6d525..beb3cbcb76f 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -132,7 +132,7 @@ struct eeh_ops {
char *name;
int (*init)(void);
void* (*of_probe)(struct device_node *dn, void *flag);
- void* (*dev_probe)(struct pci_dev *dev, void *flag);
+ int (*dev_probe)(struct pci_dev *dev, void *flag);
int (*set_option)(struct eeh_pe *pe, int option);
int (*get_pe_addr)(struct eeh_pe *pe);
int (*get_state)(struct eeh_pe *pe, int *state);
@@ -196,6 +196,7 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe);
void *eeh_dev_init(struct device_node *dn, void *data);
void eeh_dev_phb_init_dynamic(struct pci_controller *phb);
+int __init eeh_init(void);
int __init eeh_ops_register(struct eeh_ops *ops);
int __exit eeh_ops_unregister(const char *name);
unsigned long eeh_check_failure(const volatile void __iomem *token,
@@ -224,6 +225,11 @@ void eeh_remove_bus_device(struct pci_dev *, int);
#else /* !CONFIG_EEH */
+static inline int eeh_init(void)
+{
+ return 0;
+}
+
static inline void *eeh_dev_init(struct device_node *dn, void *data)
{
return NULL;
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index 8a834519308..c865c5f54b1 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -674,11 +674,21 @@ int __exit eeh_ops_unregister(const char *name)
* Even if force-off is set, the EEH hardware is still enabled, so that
* newer systems can boot.
*/
-static int __init eeh_init(void)
+int __init eeh_init(void)
{
struct pci_controller *hose, *tmp;
struct device_node *phb;
- int ret;
+ static int cnt = 0;
+ int ret = 0;
+
+ /*
+ * We have to delay the initialization on PowerNV after
+ * the PCI hierarchy tree has been built because the PEs
+ * are figured out based on PCI devices instead of device
+ * tree nodes
+ */
+ if (machine_is(powernv) && cnt++ <= 0)
+ return ret;
/* call platform initialization function */
if (!eeh_ops) {
@@ -700,6 +710,14 @@ static int __init eeh_init(void)
phb = hose->dn;
traverse_pci_devices(phb, eeh_ops->of_probe, NULL);
}
+ } else if (eeh_probe_mode_dev()) {
+ list_for_each_entry_safe(hose, tmp,
+ &hose_list, list_node)
+ pci_walk_bus(hose->bus, eeh_ops->dev_probe, NULL);
+ } else {
+ pr_warning("%s: Invalid probe mode %d\n",
+ __func__, eeh_probe_mode);
+ return -EINVAL;
}
if (eeh_subsystem_enabled)