diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/platforms/powernv/eeh-ioda.c | 41 |
1 files changed, 40 insertions, 1 deletions
diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c index a3eebd193dfe..2b7689ed5d18 100644 --- a/arch/powerpc/platforms/powernv/eeh-ioda.c +++ b/arch/powerpc/platforms/powernv/eeh-ioda.c @@ -18,6 +18,7 @@ #include <linux/irq.h> #include <linux/kernel.h> #include <linux/msi.h> +#include <linux/notifier.h> #include <linux/pci.h> #include <linux/string.h> @@ -42,6 +43,26 @@ #endif static char *hub_diag = NULL; +static int ioda_eeh_nb_init = 0; + +static int ioda_eeh_event(struct notifier_block *nb, + unsigned long events, void *change) +{ + uint64_t changed_evts = (uint64_t)change; + + /* We simply send special EEH event */ + if ((changed_evts & OPAL_EVENT_PCI_ERROR) && + (events & OPAL_EVENT_PCI_ERROR)) + eeh_send_failure_event(NULL); + + return 0; +} + +static struct notifier_block ioda_eeh_nb = { + .notifier_call = ioda_eeh_event, + .next = NULL, + .priority = 0 +}; /** * ioda_eeh_post_init - Chip dependent post initialization @@ -54,6 +75,19 @@ static char *hub_diag = NULL; static int ioda_eeh_post_init(struct pci_controller *hose) { struct pnv_phb *phb = hose->private_data; + int ret; + + /* Register OPAL event notifier */ + if (!ioda_eeh_nb_init) { + ret = opal_notifier_register(&ioda_eeh_nb); + if (ret) { + pr_err("%s: Can't register OPAL event notifier (%d)\n", + __func__, ret); + return ret; + } + + ioda_eeh_nb_init = 1; + } /* FIXME: Enable it for PHB3 later */ if (phb->type == PNV_PHB_IODA1) { @@ -736,8 +770,13 @@ static int ioda_eeh_next_error(struct eeh_pe **pe) long rc; int ret = 1; - /* While running here, it's safe to purge the event queue */ + /* + * While running here, it's safe to purge the event queue. + * And we should keep the cached OPAL notifier event sychronized + * between the kernel and firmware. + */ eeh_remove_event(NULL); + opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul); list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { /* |