Commit f8f7d63f authored by Gavin Shan's avatar Gavin Shan Committed by Benjamin Herrenschmidt

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: default avatarGavin Shan <shangw@linux.vnet.ibm.com>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent d7bb8862
...@@ -196,7 +196,7 @@ int __init eeh_ops_register(struct eeh_ops *ops); ...@@ -196,7 +196,7 @@ 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);
unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long eeh_check_failure(const volatile void __iomem *token,
unsigned long val); unsigned long val);
int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev); int eeh_dev_check_failure(struct eeh_dev *edev);
void __init pci_addr_cache_build(void); void __init pci_addr_cache_build(void);
void eeh_add_device_tree_early(struct device_node *); void eeh_add_device_tree_early(struct device_node *);
void eeh_add_device_tree_late(struct pci_bus *); void eeh_add_device_tree_late(struct pci_bus *);
...@@ -231,10 +231,7 @@ static inline unsigned long eeh_check_failure(const volatile void __iomem *token ...@@ -231,10 +231,7 @@ static inline unsigned long eeh_check_failure(const volatile void __iomem *token
return val; return val;
} }
static inline int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) #define eeh_dev_check_failure(x) (0)
{
return 0;
}
static inline void pci_addr_cache_build(void) { } static inline void pci_addr_cache_build(void) { }
......
...@@ -184,6 +184,8 @@ static inline struct eeh_dev *of_node_to_eeh_dev(struct device_node *dn) ...@@ -184,6 +184,8 @@ static inline struct eeh_dev *of_node_to_eeh_dev(struct device_node *dn)
{ {
return PCI_DN(dn)->edev; return PCI_DN(dn)->edev;
} }
#else
#define of_node_to_eeh_dev(x) (NULL)
#endif #endif
/** Find the bus corresponding to the indicated device node */ /** Find the bus corresponding to the indicated device node */
......
...@@ -50,7 +50,7 @@ extern int rtas_setup_phb(struct pci_controller *phb); ...@@ -50,7 +50,7 @@ extern int rtas_setup_phb(struct pci_controller *phb);
void pci_addr_cache_build(void); void pci_addr_cache_build(void);
void pci_addr_cache_insert_device(struct pci_dev *dev); void pci_addr_cache_insert_device(struct pci_dev *dev);
void pci_addr_cache_remove_device(struct pci_dev *dev); void pci_addr_cache_remove_device(struct pci_dev *dev);
struct pci_dev *pci_addr_cache_get_device(unsigned long addr); struct eeh_dev *pci_addr_cache_get_device(unsigned long addr);
void eeh_slot_error_detail(struct eeh_pe *pe, int severity); void eeh_slot_error_detail(struct eeh_pe *pe, int severity);
int eeh_pci_enable(struct eeh_pe *pe, int function); int eeh_pci_enable(struct eeh_pe *pe, int function);
int eeh_reset_pe(struct eeh_pe *); int eeh_reset_pe(struct eeh_pe *);
......
...@@ -81,7 +81,7 @@ int rtas_read_config(struct pci_dn *pdn, int where, int size, u32 *val) ...@@ -81,7 +81,7 @@ int rtas_read_config(struct pci_dn *pdn, int where, int size, u32 *val)
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
if (returnval == EEH_IO_ERROR_VALUE(size) && if (returnval == EEH_IO_ERROR_VALUE(size) &&
eeh_dn_check_failure (pdn->node, NULL)) eeh_dev_check_failure(of_node_to_eeh_dev(pdn->node)))
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
return PCIBIOS_SUCCESSFUL; return PCIBIOS_SUCCESSFUL;
......
...@@ -270,9 +270,8 @@ static inline unsigned long eeh_token_to_phys(unsigned long token) ...@@ -270,9 +270,8 @@ static inline unsigned long eeh_token_to_phys(unsigned long token)
} }
/** /**
* eeh_dn_check_failure - Check if all 1's data is due to EEH slot freeze * eeh_dev_check_failure - Check if all 1's data is due to EEH slot freeze
* @dn: device node * @edev: eeh device
* @dev: pci device, if known
* *
* Check for an EEH failure for the given device node. Call this * Check for an EEH failure for the given device node. Call this
* routine if the result of a read was all 0xff's and you want to * routine if the result of a read was all 0xff's and you want to
...@@ -284,12 +283,13 @@ static inline unsigned long eeh_token_to_phys(unsigned long token) ...@@ -284,12 +283,13 @@ static inline unsigned long eeh_token_to_phys(unsigned long token)
* *
* It is safe to call this routine in an interrupt context. * It is safe to call this routine in an interrupt context.
*/ */
int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) int eeh_dev_check_failure(struct eeh_dev *edev)
{ {
int ret; int ret;
unsigned long flags; unsigned long flags;
struct device_node *dn;
struct pci_dev *dev;
struct eeh_pe *pe; struct eeh_pe *pe;
struct eeh_dev *edev;
int rc = 0; int rc = 0;
const char *location; const char *location;
...@@ -298,15 +298,12 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) ...@@ -298,15 +298,12 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
if (!eeh_subsystem_enabled) if (!eeh_subsystem_enabled)
return 0; return 0;
if (dn) { if (!edev) {
edev = of_node_to_eeh_dev(dn);
} else if (dev) {
edev = pci_dev_to_eeh_dev(dev);
dn = pci_device_to_OF_node(dev);
} else {
eeh_stats.no_dn++; eeh_stats.no_dn++;
return 0; return 0;
} }
dn = eeh_dev_to_of_node(edev);
dev = eeh_dev_to_pci_dev(edev);
pe = edev->pe; pe = edev->pe;
/* Access to IO BARs might get this far and still not want checking. */ /* Access to IO BARs might get this far and still not want checking. */
...@@ -393,7 +390,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) ...@@ -393,7 +390,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(eeh_dn_check_failure); EXPORT_SYMBOL_GPL(eeh_dev_check_failure);
/** /**
* eeh_check_failure - Check if all 1's data is due to EEH slot freeze * eeh_check_failure - Check if all 1's data is due to EEH slot freeze
...@@ -410,21 +407,19 @@ EXPORT_SYMBOL_GPL(eeh_dn_check_failure); ...@@ -410,21 +407,19 @@ EXPORT_SYMBOL_GPL(eeh_dn_check_failure);
unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val) unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val)
{ {
unsigned long addr; unsigned long addr;
struct pci_dev *dev; struct eeh_dev *edev;
struct device_node *dn;
/* Finding the phys addr + pci device; this is pretty quick. */ /* Finding the phys addr + pci device; this is pretty quick. */
addr = eeh_token_to_phys((unsigned long __force) token); addr = eeh_token_to_phys((unsigned long __force) token);
dev = pci_addr_cache_get_device(addr); edev = pci_addr_cache_get_device(addr);
if (!dev) { if (!edev) {
eeh_stats.no_device++; eeh_stats.no_device++;
return val; return val;
} }
dn = pci_device_to_OF_node(dev); eeh_dev_check_failure(edev);
eeh_dn_check_failure(dn, dev);
pci_dev_put(dev); pci_dev_put(eeh_dev_to_pci_dev(edev));
return val; return val;
} }
......
...@@ -50,6 +50,7 @@ struct pci_io_addr_range { ...@@ -50,6 +50,7 @@ struct pci_io_addr_range {
struct rb_node rb_node; struct rb_node rb_node;
unsigned long addr_lo; unsigned long addr_lo;
unsigned long addr_hi; unsigned long addr_hi;
struct eeh_dev *edev;
struct pci_dev *pcidev; struct pci_dev *pcidev;
unsigned int flags; unsigned int flags;
}; };
...@@ -59,7 +60,7 @@ static struct pci_io_addr_cache { ...@@ -59,7 +60,7 @@ static struct pci_io_addr_cache {
spinlock_t piar_lock; spinlock_t piar_lock;
} pci_io_addr_cache_root; } pci_io_addr_cache_root;
static inline struct pci_dev *__pci_addr_cache_get_device(unsigned long addr) static inline struct eeh_dev *__pci_addr_cache_get_device(unsigned long addr)
{ {
struct rb_node *n = pci_io_addr_cache_root.rb_root.rb_node; struct rb_node *n = pci_io_addr_cache_root.rb_root.rb_node;
...@@ -74,7 +75,7 @@ static inline struct pci_dev *__pci_addr_cache_get_device(unsigned long addr) ...@@ -74,7 +75,7 @@ static inline struct pci_dev *__pci_addr_cache_get_device(unsigned long addr)
n = n->rb_right; n = n->rb_right;
} else { } else {
pci_dev_get(piar->pcidev); pci_dev_get(piar->pcidev);
return piar->pcidev; return piar->edev;
} }
} }
} }
...@@ -92,15 +93,15 @@ static inline struct pci_dev *__pci_addr_cache_get_device(unsigned long addr) ...@@ -92,15 +93,15 @@ static inline struct pci_dev *__pci_addr_cache_get_device(unsigned long addr)
* from zero (that is, they do *not* have pci_io_addr added in). * from zero (that is, they do *not* have pci_io_addr added in).
* It is safe to call this function within an interrupt. * It is safe to call this function within an interrupt.
*/ */
struct pci_dev *pci_addr_cache_get_device(unsigned long addr) struct eeh_dev *pci_addr_cache_get_device(unsigned long addr)
{ {
struct pci_dev *dev; struct eeh_dev *edev;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags);
dev = __pci_addr_cache_get_device(addr); edev = __pci_addr_cache_get_device(addr);
spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags); spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags);
return dev; return edev;
} }
#ifdef DEBUG #ifdef DEBUG
...@@ -158,6 +159,7 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo, ...@@ -158,6 +159,7 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo,
pci_dev_get(dev); pci_dev_get(dev);
piar->addr_lo = alo; piar->addr_lo = alo;
piar->addr_hi = ahi; piar->addr_hi = ahi;
piar->edev = pci_dev_to_eeh_dev(dev);
piar->pcidev = dev; piar->pcidev = dev;
piar->flags = flags; piar->flags = flags;
......
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