Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

authored by

Benjamin Herrenschmidt and committed by
Michael Ellerman
b9fde58d e19b205b

+40 -60
+2 -6
arch/powerpc/include/asm/eeh.h
··· 200 200 struct eeh_ops { 201 201 char *name; 202 202 int (*init)(void); 203 - int (*post_init)(void); 204 203 void* (*probe)(struct pci_dn *pdn, void *data); 205 204 int (*set_option)(struct eeh_pe *pe, int option); 206 205 int (*get_pe_addr)(struct eeh_pe *pe); ··· 274 275 275 276 struct eeh_dev *eeh_dev_init(struct pci_dn *pdn); 276 277 void eeh_dev_phb_init_dynamic(struct pci_controller *phb); 277 - int eeh_init(void); 278 + void eeh_probe_devices(void); 278 279 int __init eeh_ops_register(struct eeh_ops *ops); 279 280 int __exit eeh_ops_unregister(const char *name); 280 281 int eeh_check_failure(const volatile void __iomem *token); ··· 320 321 return false; 321 322 } 322 323 323 - static inline int eeh_init(void) 324 - { 325 - return 0; 326 - } 324 + static inline void eeh_probe_devices(void) { } 327 325 328 326 static inline void *eeh_dev_init(struct pci_dn *pdn, void *data) 329 327 {
+14 -32
arch/powerpc/kernel/eeh.c
··· 972 972 .notifier_call = eeh_reboot_notifier, 973 973 }; 974 974 975 + void eeh_probe_devices(void) 976 + { 977 + struct pci_controller *hose, *tmp; 978 + struct pci_dn *pdn; 979 + 980 + /* Enable EEH for all adapters */ 981 + list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { 982 + pdn = hose->pci_data; 983 + traverse_pci_dn(pdn, eeh_ops->probe, NULL); 984 + } 985 + } 986 + 975 987 /** 976 988 * eeh_init - EEH initialization 977 989 * ··· 999 987 * Even if force-off is set, the EEH hardware is still enabled, so that 1000 988 * newer systems can boot. 1001 989 */ 1002 - int eeh_init(void) 990 + static int eeh_init(void) 1003 991 { 1004 992 struct pci_controller *hose, *tmp; 1005 - struct pci_dn *pdn; 1006 - static int cnt = 0; 1007 993 int ret = 0; 1008 - 1009 - /* 1010 - * We have to delay the initialization on PowerNV after 1011 - * the PCI hierarchy tree has been built because the PEs 1012 - * are figured out based on PCI devices instead of device 1013 - * tree nodes 1014 - */ 1015 - if (machine_is(powernv) && cnt++ <= 0) 1016 - return ret; 1017 994 1018 995 /* Register reboot notifier */ 1019 996 ret = register_reboot_notifier(&eeh_reboot_nb); ··· 1029 1028 if (ret) 1030 1029 return ret; 1031 1030 1032 - /* Enable EEH for all adapters */ 1033 - list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { 1034 - pdn = hose->pci_data; 1035 - traverse_pci_dn(pdn, eeh_ops->probe, NULL); 1036 - } 1037 - 1038 - /* 1039 - * Call platform post-initialization. Actually, It's good chance 1040 - * to inform platform that EEH is ready to supply service if the 1041 - * I/O cache stuff has been built up. 1042 - */ 1043 - if (eeh_ops->post_init) { 1044 - ret = eeh_ops->post_init(); 1045 - if (ret) 1046 - return ret; 1047 - } 1031 + eeh_probe_devices(); 1048 1032 1049 1033 if (eeh_enabled()) 1050 1034 pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n"); ··· 1742 1756 eeh_clear_flag(EEH_FORCE_DISABLED); 1743 1757 else 1744 1758 eeh_add_flag(EEH_FORCE_DISABLED); 1745 - 1746 - /* Notify the backend */ 1747 - if (eeh_ops->post_init) 1748 - eeh_ops->post_init(); 1749 1759 1750 1760 return 0; 1751 1761 }
+22 -20
arch/powerpc/platforms/powernv/eeh-powernv.c
··· 41 41 #include "powernv.h" 42 42 #include "pci.h" 43 43 44 - static bool pnv_eeh_nb_init = false; 45 44 static int eeh_event_irq = -EINVAL; 46 45 47 46 static int pnv_eeh_init(void) ··· 196 197 * been built. If the I/O cache staff has been built, EEH is 197 198 * ready to supply service. 198 199 */ 199 - static int pnv_eeh_post_init(void) 200 + int pnv_eeh_post_init(void) 200 201 { 201 202 struct pci_controller *hose; 202 203 struct pnv_phb *phb; 203 204 int ret = 0; 204 205 206 + /* Probe devices & build address cache */ 207 + eeh_probe_devices(); 208 + eeh_addr_cache_build(); 209 + 205 210 /* Register OPAL event notifier */ 206 - if (!pnv_eeh_nb_init) { 207 - eeh_event_irq = opal_event_request(ilog2(OPAL_EVENT_PCI_ERROR)); 208 - if (eeh_event_irq < 0) { 209 - pr_err("%s: Can't register OPAL event interrupt (%d)\n", 210 - __func__, eeh_event_irq); 211 - return eeh_event_irq; 212 - } 211 + eeh_event_irq = opal_event_request(ilog2(OPAL_EVENT_PCI_ERROR)); 212 + if (eeh_event_irq < 0) { 213 + pr_err("%s: Can't register OPAL event interrupt (%d)\n", 214 + __func__, eeh_event_irq); 215 + return eeh_event_irq; 216 + } 213 217 214 - ret = request_irq(eeh_event_irq, pnv_eeh_event, 215 - IRQ_TYPE_LEVEL_HIGH, "opal-eeh", NULL); 216 - if (ret < 0) { 217 - irq_dispose_mapping(eeh_event_irq); 218 - pr_err("%s: Can't request OPAL event interrupt (%d)\n", 219 - __func__, eeh_event_irq); 220 - return ret; 221 - } 222 - 223 - pnv_eeh_nb_init = true; 218 + ret = request_irq(eeh_event_irq, pnv_eeh_event, 219 + IRQ_TYPE_LEVEL_HIGH, "opal-eeh", NULL); 220 + if (ret < 0) { 221 + irq_dispose_mapping(eeh_event_irq); 222 + pr_err("%s: Can't request OPAL event interrupt (%d)\n", 223 + __func__, eeh_event_irq); 224 + return ret; 224 225 } 225 226 226 227 if (!eeh_enabled()) ··· 364 365 365 366 /* Skip for PCI-ISA bridge */ 366 367 if ((pdn->class_code >> 8) == PCI_CLASS_BRIDGE_ISA) 368 + return NULL; 369 + 370 + /* Skip if we haven't probed yet */ 371 + if (phb->ioda.pe_rmap[config_addr] == IODA_INVALID_PE) 367 372 return NULL; 368 373 369 374 /* Initialize eeh device */ ··· 1734 1731 static struct eeh_ops pnv_eeh_ops = { 1735 1732 .name = "powernv", 1736 1733 .init = pnv_eeh_init, 1737 - .post_init = pnv_eeh_post_init, 1738 1734 .probe = pnv_eeh_probe, 1739 1735 .set_option = pnv_eeh_set_option, 1740 1736 .get_pe_addr = pnv_eeh_get_pe_addr,
+1 -2
arch/powerpc/platforms/powernv/pci-ioda.c
··· 3293 3293 pnv_pci_ioda_create_dbgfs(); 3294 3294 3295 3295 #ifdef CONFIG_EEH 3296 - eeh_init(); 3297 - eeh_addr_cache_build(); 3296 + pnv_eeh_post_init(); 3298 3297 #endif 3299 3298 } 3300 3299
+1
arch/powerpc/platforms/powernv/pci.h
··· 234 234 extern void pnv_set_msi_irq_chip(struct pnv_phb *phb, unsigned int virq); 235 235 extern bool pnv_pci_enable_device_hook(struct pci_dev *dev); 236 236 extern void pnv_pci_ioda2_set_bypass(struct pnv_ioda_pe *pe, bool enable); 237 + extern int pnv_eeh_post_init(void); 237 238 238 239 extern void pe_level_printk(const struct pnv_ioda_pe *pe, const char *level, 239 240 const char *fmt, ...);