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

powerpc/eeh: Trace eeh device from I/O cache

The idea comes from Benjamin Herrenschmidt. The eeh cache helps
fetching the pci device according to the given I/O address. Since
the eeh cache is serving for eeh, it's reasonable for eeh cache
to trace eeh device except pci device.

The patch make eeh cache to trace eeh device. Also, the major
eeh entry function eeh_dn_check_failure has been renamed to
eeh_dev_check_failure since it will take eeh device as input
parameter.

Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

authored by

Gavin Shan and committed by
Benjamin Herrenschmidt
f8f7d63f d7bb8862

+28 -32
+2 -5
arch/powerpc/include/asm/eeh.h
··· 196 196 int __exit eeh_ops_unregister(const char *name); 197 197 unsigned long eeh_check_failure(const volatile void __iomem *token, 198 198 unsigned long val); 199 - int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev); 199 + int eeh_dev_check_failure(struct eeh_dev *edev); 200 200 void __init pci_addr_cache_build(void); 201 201 void eeh_add_device_tree_early(struct device_node *); 202 202 void eeh_add_device_tree_late(struct pci_bus *); ··· 231 231 return val; 232 232 } 233 233 234 - static inline int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) 235 - { 236 - return 0; 237 - } 234 + #define eeh_dev_check_failure(x) (0) 238 235 239 236 static inline void pci_addr_cache_build(void) { } 240 237
+2
arch/powerpc/include/asm/pci-bridge.h
··· 184 184 { 185 185 return PCI_DN(dn)->edev; 186 186 } 187 + #else 188 + #define of_node_to_eeh_dev(x) (NULL) 187 189 #endif 188 190 189 191 /** Find the bus corresponding to the indicated device node */
+1 -1
arch/powerpc/include/asm/ppc-pci.h
··· 50 50 void pci_addr_cache_build(void); 51 51 void pci_addr_cache_insert_device(struct pci_dev *dev); 52 52 void pci_addr_cache_remove_device(struct pci_dev *dev); 53 - struct pci_dev *pci_addr_cache_get_device(unsigned long addr); 53 + struct eeh_dev *pci_addr_cache_get_device(unsigned long addr); 54 54 void eeh_slot_error_detail(struct eeh_pe *pe, int severity); 55 55 int eeh_pci_enable(struct eeh_pe *pe, int function); 56 56 int eeh_reset_pe(struct eeh_pe *);
+1 -1
arch/powerpc/kernel/rtas_pci.c
··· 81 81 return PCIBIOS_DEVICE_NOT_FOUND; 82 82 83 83 if (returnval == EEH_IO_ERROR_VALUE(size) && 84 - eeh_dn_check_failure (pdn->node, NULL)) 84 + eeh_dev_check_failure(of_node_to_eeh_dev(pdn->node))) 85 85 return PCIBIOS_DEVICE_NOT_FOUND; 86 86 87 87 return PCIBIOS_SUCCESSFUL;
+14 -19
arch/powerpc/platforms/pseries/eeh.c
··· 270 270 } 271 271 272 272 /** 273 - * eeh_dn_check_failure - Check if all 1's data is due to EEH slot freeze 274 - * @dn: device node 275 - * @dev: pci device, if known 273 + * eeh_dev_check_failure - Check if all 1's data is due to EEH slot freeze 274 + * @edev: eeh device 276 275 * 277 276 * Check for an EEH failure for the given device node. Call this 278 277 * routine if the result of a read was all 0xff's and you want to ··· 283 284 * 284 285 * It is safe to call this routine in an interrupt context. 285 286 */ 286 - int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) 287 + int eeh_dev_check_failure(struct eeh_dev *edev) 287 288 { 288 289 int ret; 289 290 unsigned long flags; 291 + struct device_node *dn; 292 + struct pci_dev *dev; 290 293 struct eeh_pe *pe; 291 - struct eeh_dev *edev; 292 294 int rc = 0; 293 295 const char *location; 294 296 ··· 298 298 if (!eeh_subsystem_enabled) 299 299 return 0; 300 300 301 - if (dn) { 302 - edev = of_node_to_eeh_dev(dn); 303 - } else if (dev) { 304 - edev = pci_dev_to_eeh_dev(dev); 305 - dn = pci_device_to_OF_node(dev); 306 - } else { 301 + if (!edev) { 307 302 eeh_stats.no_dn++; 308 303 return 0; 309 304 } 305 + dn = eeh_dev_to_of_node(edev); 306 + dev = eeh_dev_to_pci_dev(edev); 310 307 pe = edev->pe; 311 308 312 309 /* Access to IO BARs might get this far and still not want checking. */ ··· 390 393 return rc; 391 394 } 392 395 393 - EXPORT_SYMBOL_GPL(eeh_dn_check_failure); 396 + EXPORT_SYMBOL_GPL(eeh_dev_check_failure); 394 397 395 398 /** 396 399 * eeh_check_failure - Check if all 1's data is due to EEH slot freeze ··· 407 410 unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val) 408 411 { 409 412 unsigned long addr; 410 - struct pci_dev *dev; 411 - struct device_node *dn; 413 + struct eeh_dev *edev; 412 414 413 415 /* Finding the phys addr + pci device; this is pretty quick. */ 414 416 addr = eeh_token_to_phys((unsigned long __force) token); 415 - dev = pci_addr_cache_get_device(addr); 416 - if (!dev) { 417 + edev = pci_addr_cache_get_device(addr); 418 + if (!edev) { 417 419 eeh_stats.no_device++; 418 420 return val; 419 421 } 420 422 421 - dn = pci_device_to_OF_node(dev); 422 - eeh_dn_check_failure(dn, dev); 423 + eeh_dev_check_failure(edev); 423 424 424 - pci_dev_put(dev); 425 + pci_dev_put(eeh_dev_to_pci_dev(edev)); 425 426 return val; 426 427 } 427 428
+8 -6
arch/powerpc/platforms/pseries/eeh_cache.c
··· 50 50 struct rb_node rb_node; 51 51 unsigned long addr_lo; 52 52 unsigned long addr_hi; 53 + struct eeh_dev *edev; 53 54 struct pci_dev *pcidev; 54 55 unsigned int flags; 55 56 }; ··· 60 59 spinlock_t piar_lock; 61 60 } pci_io_addr_cache_root; 62 61 63 - static inline struct pci_dev *__pci_addr_cache_get_device(unsigned long addr) 62 + static inline struct eeh_dev *__pci_addr_cache_get_device(unsigned long addr) 64 63 { 65 64 struct rb_node *n = pci_io_addr_cache_root.rb_root.rb_node; 66 65 ··· 75 74 n = n->rb_right; 76 75 } else { 77 76 pci_dev_get(piar->pcidev); 78 - return piar->pcidev; 77 + return piar->edev; 79 78 } 80 79 } 81 80 } ··· 93 92 * from zero (that is, they do *not* have pci_io_addr added in). 94 93 * It is safe to call this function within an interrupt. 95 94 */ 96 - struct pci_dev *pci_addr_cache_get_device(unsigned long addr) 95 + struct eeh_dev *pci_addr_cache_get_device(unsigned long addr) 97 96 { 98 - struct pci_dev *dev; 97 + struct eeh_dev *edev; 99 98 unsigned long flags; 100 99 101 100 spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); 102 - dev = __pci_addr_cache_get_device(addr); 101 + edev = __pci_addr_cache_get_device(addr); 103 102 spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags); 104 - return dev; 103 + return edev; 105 104 } 106 105 107 106 #ifdef DEBUG ··· 159 158 pci_dev_get(dev); 160 159 piar->addr_lo = alo; 161 160 piar->addr_hi = ahi; 161 + piar->edev = pci_dev_to_eeh_dev(dev); 162 162 piar->pcidev = dev; 163 163 piar->flags = flags; 164 164