Commit b9fde58d authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Michael Ellerman

powerpc/powernv: Rework EEH initialization on powernv

Remove the post_init callback which is only used
by powernv, we can just call it explicitly from
the powernv code.

This partially kills the ability to "disable" eeh at
runtime via debugfs as this was calling that same
callback again, but this is both unused and broken
in several ways. If we want to revive it, we need
to create a dedicated enable/disable callback on the
backend that does the right thing.

Let the bulk of eeh initialize normally at
core_initcall() like it does on pseries by removing
the hack in eeh_init() that delays it.

Instead we make sure our eeh->probe cleanly bails
out of the PEs haven't been created yet and we force
a re-probe where we used to call eeh_init() again.
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: default avatarRussell Currey <ruscur@russell.cc>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent e19b205b
...@@ -200,7 +200,6 @@ enum { ...@@ -200,7 +200,6 @@ enum {
struct eeh_ops { struct eeh_ops {
char *name; char *name;
int (*init)(void); int (*init)(void);
int (*post_init)(void);
void* (*probe)(struct pci_dn *pdn, void *data); void* (*probe)(struct pci_dn *pdn, void *data);
int (*set_option)(struct eeh_pe *pe, int option); int (*set_option)(struct eeh_pe *pe, int option);
int (*get_pe_addr)(struct eeh_pe *pe); int (*get_pe_addr)(struct eeh_pe *pe);
...@@ -275,7 +274,7 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe); ...@@ -275,7 +274,7 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe);
struct eeh_dev *eeh_dev_init(struct pci_dn *pdn); struct eeh_dev *eeh_dev_init(struct pci_dn *pdn);
void eeh_dev_phb_init_dynamic(struct pci_controller *phb); void eeh_dev_phb_init_dynamic(struct pci_controller *phb);
int eeh_init(void); void eeh_probe_devices(void);
int __init eeh_ops_register(struct eeh_ops *ops); int __init eeh_ops_register(struct eeh_ops *ops);
int __exit eeh_ops_unregister(const char *name); int __exit eeh_ops_unregister(const char *name);
int eeh_check_failure(const volatile void __iomem *token); int eeh_check_failure(const volatile void __iomem *token);
...@@ -321,10 +320,7 @@ static inline bool eeh_enabled(void) ...@@ -321,10 +320,7 @@ static inline bool eeh_enabled(void)
return false; return false;
} }
static inline int eeh_init(void) static inline void eeh_probe_devices(void) { }
{
return 0;
}
static inline void *eeh_dev_init(struct pci_dn *pdn, void *data) static inline void *eeh_dev_init(struct pci_dn *pdn, void *data)
{ {
......
...@@ -972,6 +972,18 @@ static struct notifier_block eeh_reboot_nb = { ...@@ -972,6 +972,18 @@ static struct notifier_block eeh_reboot_nb = {
.notifier_call = eeh_reboot_notifier, .notifier_call = eeh_reboot_notifier,
}; };
void eeh_probe_devices(void)
{
struct pci_controller *hose, *tmp;
struct pci_dn *pdn;
/* Enable EEH for all adapters */
list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
pdn = hose->pci_data;
traverse_pci_dn(pdn, eeh_ops->probe, NULL);
}
}
/** /**
* eeh_init - EEH initialization * eeh_init - EEH initialization
* *
...@@ -987,22 +999,11 @@ static struct notifier_block eeh_reboot_nb = { ...@@ -987,22 +999,11 @@ static struct notifier_block eeh_reboot_nb = {
* Even if force-off is set, the EEH hardware is still enabled, so that * Even if force-off is set, the EEH hardware is still enabled, so that
* newer systems can boot. * newer systems can boot.
*/ */
int eeh_init(void) static int eeh_init(void)
{ {
struct pci_controller *hose, *tmp; struct pci_controller *hose, *tmp;
struct pci_dn *pdn;
static int cnt = 0;
int ret = 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;
/* Register reboot notifier */ /* Register reboot notifier */
ret = register_reboot_notifier(&eeh_reboot_nb); ret = register_reboot_notifier(&eeh_reboot_nb);
if (ret) { if (ret) {
...@@ -1028,22 +1029,7 @@ int eeh_init(void) ...@@ -1028,22 +1029,7 @@ int eeh_init(void)
if (ret) if (ret)
return ret; return ret;
/* Enable EEH for all adapters */ eeh_probe_devices();
list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
pdn = hose->pci_data;
traverse_pci_dn(pdn, eeh_ops->probe, NULL);
}
/*
* Call platform post-initialization. Actually, It's good chance
* to inform platform that EEH is ready to supply service if the
* I/O cache stuff has been built up.
*/
if (eeh_ops->post_init) {
ret = eeh_ops->post_init();
if (ret)
return ret;
}
if (eeh_enabled()) if (eeh_enabled())
pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n"); pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n");
...@@ -1757,10 +1743,6 @@ static int eeh_enable_dbgfs_set(void *data, u64 val) ...@@ -1757,10 +1743,6 @@ static int eeh_enable_dbgfs_set(void *data, u64 val)
else else
eeh_add_flag(EEH_FORCE_DISABLED); eeh_add_flag(EEH_FORCE_DISABLED);
/* Notify the backend */
if (eeh_ops->post_init)
eeh_ops->post_init();
return 0; return 0;
} }
......
...@@ -41,7 +41,6 @@ ...@@ -41,7 +41,6 @@
#include "powernv.h" #include "powernv.h"
#include "pci.h" #include "pci.h"
static bool pnv_eeh_nb_init = false;
static int eeh_event_irq = -EINVAL; static int eeh_event_irq = -EINVAL;
static int pnv_eeh_init(void) static int pnv_eeh_init(void)
...@@ -197,31 +196,31 @@ PNV_EEH_DBGFS_ENTRY(inbB, 0xE10); ...@@ -197,31 +196,31 @@ PNV_EEH_DBGFS_ENTRY(inbB, 0xE10);
* been built. If the I/O cache staff has been built, EEH is * been built. If the I/O cache staff has been built, EEH is
* ready to supply service. * ready to supply service.
*/ */
static int pnv_eeh_post_init(void) int pnv_eeh_post_init(void)
{ {
struct pci_controller *hose; struct pci_controller *hose;
struct pnv_phb *phb; struct pnv_phb *phb;
int ret = 0; int ret = 0;
/* Register OPAL event notifier */ /* Probe devices & build address cache */
if (!pnv_eeh_nb_init) { eeh_probe_devices();
eeh_event_irq = opal_event_request(ilog2(OPAL_EVENT_PCI_ERROR)); eeh_addr_cache_build();
if (eeh_event_irq < 0) {
pr_err("%s: Can't register OPAL event interrupt (%d)\n",
__func__, eeh_event_irq);
return eeh_event_irq;
}
ret = request_irq(eeh_event_irq, pnv_eeh_event, /* Register OPAL event notifier */
IRQ_TYPE_LEVEL_HIGH, "opal-eeh", NULL); eeh_event_irq = opal_event_request(ilog2(OPAL_EVENT_PCI_ERROR));
if (ret < 0) { if (eeh_event_irq < 0) {
irq_dispose_mapping(eeh_event_irq); pr_err("%s: Can't register OPAL event interrupt (%d)\n",
pr_err("%s: Can't request OPAL event interrupt (%d)\n", __func__, eeh_event_irq);
__func__, eeh_event_irq); return eeh_event_irq;
return ret; }
}
pnv_eeh_nb_init = true; ret = request_irq(eeh_event_irq, pnv_eeh_event,
IRQ_TYPE_LEVEL_HIGH, "opal-eeh", NULL);
if (ret < 0) {
irq_dispose_mapping(eeh_event_irq);
pr_err("%s: Can't request OPAL event interrupt (%d)\n",
__func__, eeh_event_irq);
return ret;
} }
if (!eeh_enabled()) if (!eeh_enabled())
...@@ -367,6 +366,10 @@ static void *pnv_eeh_probe(struct pci_dn *pdn, void *data) ...@@ -367,6 +366,10 @@ static void *pnv_eeh_probe(struct pci_dn *pdn, void *data)
if ((pdn->class_code >> 8) == PCI_CLASS_BRIDGE_ISA) if ((pdn->class_code >> 8) == PCI_CLASS_BRIDGE_ISA)
return NULL; return NULL;
/* Skip if we haven't probed yet */
if (phb->ioda.pe_rmap[config_addr] == IODA_INVALID_PE)
return NULL;
/* Initialize eeh device */ /* Initialize eeh device */
edev->class_code = pdn->class_code; edev->class_code = pdn->class_code;
edev->mode &= 0xFFFFFF00; edev->mode &= 0xFFFFFF00;
...@@ -1731,7 +1734,6 @@ static int pnv_eeh_restore_config(struct pci_dn *pdn) ...@@ -1731,7 +1734,6 @@ static int pnv_eeh_restore_config(struct pci_dn *pdn)
static struct eeh_ops pnv_eeh_ops = { static struct eeh_ops pnv_eeh_ops = {
.name = "powernv", .name = "powernv",
.init = pnv_eeh_init, .init = pnv_eeh_init,
.post_init = pnv_eeh_post_init,
.probe = pnv_eeh_probe, .probe = pnv_eeh_probe,
.set_option = pnv_eeh_set_option, .set_option = pnv_eeh_set_option,
.get_pe_addr = pnv_eeh_get_pe_addr, .get_pe_addr = pnv_eeh_get_pe_addr,
......
...@@ -3293,8 +3293,7 @@ static void pnv_pci_ioda_fixup(void) ...@@ -3293,8 +3293,7 @@ static void pnv_pci_ioda_fixup(void)
pnv_pci_ioda_create_dbgfs(); pnv_pci_ioda_create_dbgfs();
#ifdef CONFIG_EEH #ifdef CONFIG_EEH
eeh_init(); pnv_eeh_post_init();
eeh_addr_cache_build();
#endif #endif
} }
......
...@@ -234,6 +234,7 @@ extern struct pnv_ioda_pe *pnv_ioda_get_pe(struct pci_dev *dev); ...@@ -234,6 +234,7 @@ extern struct pnv_ioda_pe *pnv_ioda_get_pe(struct pci_dev *dev);
extern void pnv_set_msi_irq_chip(struct pnv_phb *phb, unsigned int virq); extern void pnv_set_msi_irq_chip(struct pnv_phb *phb, unsigned int virq);
extern bool pnv_pci_enable_device_hook(struct pci_dev *dev); extern bool pnv_pci_enable_device_hook(struct pci_dev *dev);
extern void pnv_pci_ioda2_set_bypass(struct pnv_ioda_pe *pe, bool enable); extern void pnv_pci_ioda2_set_bypass(struct pnv_ioda_pe *pe, bool enable);
extern int pnv_eeh_post_init(void);
extern void pe_level_printk(const struct pnv_ioda_pe *pe, const char *level, extern void pe_level_printk(const struct pnv_ioda_pe *pe, const char *level,
const char *fmt, ...); const char *fmt, ...);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment