1b8b572e1SStephen Rothwell /* 2b8b572e1SStephen Rothwell * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation. 3cb3bc9d0SGavin Shan * Copyright 2001-2012 IBM Corporation. 4b8b572e1SStephen Rothwell * 5b8b572e1SStephen Rothwell * This program is free software; you can redistribute it and/or modify 6b8b572e1SStephen Rothwell * it under the terms of the GNU General Public License as published by 7b8b572e1SStephen Rothwell * the Free Software Foundation; either version 2 of the License, or 8b8b572e1SStephen Rothwell * (at your option) any later version. 9b8b572e1SStephen Rothwell * 10b8b572e1SStephen Rothwell * This program is distributed in the hope that it will be useful, 11b8b572e1SStephen Rothwell * but WITHOUT ANY WARRANTY; without even the implied warranty of 12b8b572e1SStephen Rothwell * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13b8b572e1SStephen Rothwell * GNU General Public License for more details. 14b8b572e1SStephen Rothwell * 15b8b572e1SStephen Rothwell * You should have received a copy of the GNU General Public License 16b8b572e1SStephen Rothwell * along with this program; if not, write to the Free Software 17b8b572e1SStephen Rothwell * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18b8b572e1SStephen Rothwell */ 19b8b572e1SStephen Rothwell 208b8da358SBenjamin Herrenschmidt #ifndef _POWERPC_EEH_H 218b8da358SBenjamin Herrenschmidt #define _POWERPC_EEH_H 22b8b572e1SStephen Rothwell #ifdef __KERNEL__ 23b8b572e1SStephen Rothwell 24b8b572e1SStephen Rothwell #include <linux/init.h> 25b8b572e1SStephen Rothwell #include <linux/list.h> 26b8b572e1SStephen Rothwell #include <linux/string.h> 275a71978eSGavin Shan #include <linux/time.h> 2805ec424eSGavin Shan #include <linux/atomic.h> 29b8b572e1SStephen Rothwell 30ed3e81ffSGavin Shan #include <uapi/asm/eeh.h> 31ed3e81ffSGavin Shan 32b8b572e1SStephen Rothwell struct pci_dev; 33b8b572e1SStephen Rothwell struct pci_bus; 34e8e9b34cSGavin Shan struct pci_dn; 35b8b572e1SStephen Rothwell 36b8b572e1SStephen Rothwell #ifdef CONFIG_EEH 37b8b572e1SStephen Rothwell 388a5ad356SGavin Shan /* EEH subsystem flags */ 39dc561fb9SGavin Shan #define EEH_ENABLED 0x01 /* EEH enabled */ 40dc561fb9SGavin Shan #define EEH_FORCE_DISABLED 0x02 /* EEH disabled */ 41dc561fb9SGavin Shan #define EEH_PROBE_MODE_DEV 0x04 /* From PCI device */ 42dc561fb9SGavin Shan #define EEH_PROBE_MODE_DEVTREE 0x08 /* From device tree */ 432aa5cf9eSGavin Shan #define EEH_VALID_PE_ZERO 0x10 /* PE#0 is valid */ 442aa5cf9eSGavin Shan #define EEH_ENABLE_IO_FOR_LOG 0x20 /* Enable IO for log */ 452aa5cf9eSGavin Shan #define EEH_EARLY_DUMP_LOG 0x40 /* Dump log immediately */ 468a5ad356SGavin Shan 47aa1e6374SGavin Shan /* 4826833a50SGavin Shan * Delay for PE reset, all in ms 4926833a50SGavin Shan * 5026833a50SGavin Shan * PCI specification has reset hold time of 100 milliseconds. 5126833a50SGavin Shan * We have 250 milliseconds here. The PCI bus settlement time 5226833a50SGavin Shan * is specified as 1.5 seconds and we have 1.8 seconds. 5326833a50SGavin Shan */ 5426833a50SGavin Shan #define EEH_PE_RST_HOLD_TIME 250 5526833a50SGavin Shan #define EEH_PE_RST_SETTLE_TIME 1800 5626833a50SGavin Shan 5726833a50SGavin Shan /* 58968f968fSGavin Shan * The struct is used to trace PE related EEH functionality. 59968f968fSGavin Shan * In theory, there will have one instance of the struct to 60027dfac6SMichael Ellerman * be created against particular PE. In nature, PEs correlate 61968f968fSGavin Shan * to each other. the struct has to reflect that hierarchy in 62968f968fSGavin Shan * order to easily pick up those affected PEs when one particular 63968f968fSGavin Shan * PE has EEH errors. 64968f968fSGavin Shan * 65968f968fSGavin Shan * Also, one particular PE might be composed of PCI device, PCI 66968f968fSGavin Shan * bus and its subordinate components. The struct also need ship 67968f968fSGavin Shan * the information. Further more, one particular PE is only meaingful 68968f968fSGavin Shan * in the corresponding PHB. Therefore, the root PEs should be created 69968f968fSGavin Shan * against existing PHBs in on-to-one fashion. 70968f968fSGavin Shan */ 715efc3ad7SGavin Shan #define EEH_PE_INVALID (1 << 0) /* Invalid */ 725efc3ad7SGavin Shan #define EEH_PE_PHB (1 << 1) /* PHB PE */ 735efc3ad7SGavin Shan #define EEH_PE_DEVICE (1 << 2) /* Device PE */ 745efc3ad7SGavin Shan #define EEH_PE_BUS (1 << 3) /* Bus PE */ 75c29fa27dSWei Yang #define EEH_PE_VF (1 << 4) /* VF PE */ 76968f968fSGavin Shan 77968f968fSGavin Shan #define EEH_PE_ISOLATED (1 << 0) /* Isolated PE */ 78968f968fSGavin Shan #define EEH_PE_RECOVERING (1 << 1) /* Recovering PE */ 798a6b3710SGavin Shan #define EEH_PE_CFG_BLOCKED (1 << 2) /* Block config access */ 8028bf36f9SGavin Shan #define EEH_PE_RESET (1 << 3) /* PE reset in progress */ 81968f968fSGavin Shan 82807a827dSGavin Shan #define EEH_PE_KEEP (1 << 8) /* Keep PE on hotplug */ 83b6541db1SGavin Shan #define EEH_PE_CFG_RESTRICTED (1 << 9) /* Block config on error */ 84432227e9SGavin Shan #define EEH_PE_REMOVED (1 << 10) /* Removed permanently */ 8505ba75f8SGavin Shan #define EEH_PE_PRI_BUS (1 << 11) /* Cached primary bus */ 86807a827dSGavin Shan 87968f968fSGavin Shan struct eeh_pe { 88968f968fSGavin Shan int type; /* PE type: PHB/Bus/Device */ 89968f968fSGavin Shan int state; /* PE EEH dependent mode */ 90968f968fSGavin Shan int config_addr; /* Traditional PCI address */ 91968f968fSGavin Shan int addr; /* PE configuration address */ 92968f968fSGavin Shan struct pci_controller *phb; /* Associated PHB */ 938cdb2833SGavin Shan struct pci_bus *bus; /* Top PCI bus for bus PE */ 94968f968fSGavin Shan int check_count; /* Times of ignored error */ 95968f968fSGavin Shan int freeze_count; /* Times of froze up */ 96edfd17ffSArnd Bergmann time64_t tstamp; /* Time on first-time freeze */ 97968f968fSGavin Shan int false_positives; /* Times of reported #ff's */ 9805ec424eSGavin Shan atomic_t pass_dev_cnt; /* Count of passed through devs */ 99968f968fSGavin Shan struct eeh_pe *parent; /* Parent PE */ 100bb593c00SGavin Shan void *data; /* PE auxillary data */ 10180e65b00SSam Bobroff struct list_head child_list; /* List of PEs below this PE */ 10280e65b00SSam Bobroff struct list_head child; /* Memb. child_list/eeh_phb_pe */ 10380e65b00SSam Bobroff struct list_head edevs; /* List of eeh_dev in this PE */ 104968f968fSGavin Shan }; 105968f968fSGavin Shan 1069feed42eSGavin Shan #define eeh_pe_for_each_dev(pe, edev, tmp) \ 10780e65b00SSam Bobroff list_for_each_entry_safe(edev, tmp, &pe->edevs, entry) 1085b663529SGavin Shan 109309ed3a7SSam Bobroff #define eeh_for_each_pe(root, pe) \ 110309ed3a7SSam Bobroff for (pe = root; pe; pe = eeh_pe_next(pe, root)) 111309ed3a7SSam Bobroff 11205ec424eSGavin Shan static inline bool eeh_pe_passed(struct eeh_pe *pe) 11305ec424eSGavin Shan { 11405ec424eSGavin Shan return pe ? !!atomic_read(&pe->pass_dev_cnt) : false; 11505ec424eSGavin Shan } 11605ec424eSGavin Shan 117968f968fSGavin Shan /* 118eb740b5fSGavin Shan * The struct is used to trace EEH state for the associated 119eb740b5fSGavin Shan * PCI device node or PCI device. In future, it might 120eb740b5fSGavin Shan * represent PE as well so that the EEH device to form 121eb740b5fSGavin Shan * another tree except the currently existing tree of PCI 122eb740b5fSGavin Shan * buses and PCI devices 123eb740b5fSGavin Shan */ 1244b83bd45SGavin Shan #define EEH_DEV_BRIDGE (1 << 0) /* PCI bridge */ 1254b83bd45SGavin Shan #define EEH_DEV_ROOT_PORT (1 << 1) /* PCIe root port */ 1264b83bd45SGavin Shan #define EEH_DEV_DS_PORT (1 << 2) /* Downstream port */ 1274b83bd45SGavin Shan #define EEH_DEV_IRQ_DISABLED (1 << 3) /* Interrupt disabled */ 1284b83bd45SGavin Shan #define EEH_DEV_DISCONNECTED (1 << 4) /* Removing from PE */ 129eb740b5fSGavin Shan 130f26c7a03SGavin Shan #define EEH_DEV_NO_HANDLER (1 << 8) /* No error handler */ 131f26c7a03SGavin Shan #define EEH_DEV_SYSFS (1 << 9) /* Sysfs created */ 132d2b0f6f7SGavin Shan #define EEH_DEV_REMOVED (1 << 10) /* Removed permanently */ 133ab55d218SGavin Shan 134eb740b5fSGavin Shan struct eeh_dev { 135eb740b5fSGavin Shan int mode; /* EEH mode */ 136eb740b5fSGavin Shan int class_code; /* Class code of the device */ 137eb740b5fSGavin Shan int pe_config_addr; /* PE config address */ 138eb740b5fSGavin Shan u32 config_space[16]; /* Saved PCI config space */ 1392a18dfc6SGavin Shan int pcix_cap; /* Saved PCIx capability */ 1402a18dfc6SGavin Shan int pcie_cap; /* Saved PCIe capability */ 1412a18dfc6SGavin Shan int aer_cap; /* Saved AER capability */ 1429312bc5bSWei Yang int af_cap; /* Saved AF capability */ 143968f968fSGavin Shan struct eeh_pe *pe; /* Associated PE */ 14480e65b00SSam Bobroff struct list_head entry; /* Membership in eeh_pe.edevs */ 14580e65b00SSam Bobroff struct list_head rmv_entry; /* Membership in rmv_list */ 146e8e9b34cSGavin Shan struct pci_dn *pdn; /* Associated PCI device node */ 147eb740b5fSGavin Shan struct pci_dev *pdev; /* Associated PCI device */ 14867086e32SWei Yang bool in_error; /* Error flag for edev */ 14939218cd0SWei Yang struct pci_dev *physfn; /* Associated SRIOV PF */ 150eb740b5fSGavin Shan }; 151eb740b5fSGavin Shan 152e8e9b34cSGavin Shan static inline struct pci_dn *eeh_dev_to_pdn(struct eeh_dev *edev) 153e8e9b34cSGavin Shan { 154e8e9b34cSGavin Shan return edev ? edev->pdn : NULL; 155e8e9b34cSGavin Shan } 156e8e9b34cSGavin Shan 157eb740b5fSGavin Shan static inline struct pci_dev *eeh_dev_to_pci_dev(struct eeh_dev *edev) 158eb740b5fSGavin Shan { 1592d5c1216SGavin Shan return edev ? edev->pdev : NULL; 160eb740b5fSGavin Shan } 161eb740b5fSGavin Shan 1622a58222fSWei Yang static inline struct eeh_pe *eeh_dev_to_pe(struct eeh_dev* edev) 1632a58222fSWei Yang { 1642a58222fSWei Yang return edev ? edev->pe : NULL; 1652a58222fSWei Yang } 1662a58222fSWei Yang 1677e4e7867SGavin Shan /* Return values from eeh_ops::next_error */ 1687e4e7867SGavin Shan enum { 1697e4e7867SGavin Shan EEH_NEXT_ERR_NONE = 0, 1707e4e7867SGavin Shan EEH_NEXT_ERR_INF, 1717e4e7867SGavin Shan EEH_NEXT_ERR_FROZEN_PE, 1727e4e7867SGavin Shan EEH_NEXT_ERR_FENCED_PHB, 1737e4e7867SGavin Shan EEH_NEXT_ERR_DEAD_PHB, 1747e4e7867SGavin Shan EEH_NEXT_ERR_DEAD_IOC 1757e4e7867SGavin Shan }; 1767e4e7867SGavin Shan 177eb740b5fSGavin Shan /* 178aa1e6374SGavin Shan * The struct is used to trace the registered EEH operation 179aa1e6374SGavin Shan * callback functions. Actually, those operation callback 180aa1e6374SGavin Shan * functions are heavily platform dependent. That means the 181aa1e6374SGavin Shan * platform should register its own EEH operation callback 182aa1e6374SGavin Shan * functions before any EEH further operations. 183aa1e6374SGavin Shan */ 1848fb8f709SGavin Shan #define EEH_OPT_DISABLE 0 /* EEH disable */ 1858fb8f709SGavin Shan #define EEH_OPT_ENABLE 1 /* EEH enable */ 1868fb8f709SGavin Shan #define EEH_OPT_THAW_MMIO 2 /* MMIO enable */ 1878fb8f709SGavin Shan #define EEH_OPT_THAW_DMA 3 /* DMA enable */ 1880d5ee520SGavin Shan #define EEH_OPT_FREEZE_PE 4 /* Freeze PE */ 189eb594a47SGavin Shan #define EEH_STATE_UNAVAILABLE (1 << 0) /* State unavailable */ 190eb594a47SGavin Shan #define EEH_STATE_NOT_SUPPORT (1 << 1) /* EEH not supported */ 191eb594a47SGavin Shan #define EEH_STATE_RESET_ACTIVE (1 << 2) /* Active reset */ 192eb594a47SGavin Shan #define EEH_STATE_MMIO_ACTIVE (1 << 3) /* Active MMIO */ 193eb594a47SGavin Shan #define EEH_STATE_DMA_ACTIVE (1 << 4) /* Active DMA */ 194eb594a47SGavin Shan #define EEH_STATE_MMIO_ENABLED (1 << 5) /* MMIO enabled */ 195eb594a47SGavin Shan #define EEH_STATE_DMA_ENABLED (1 << 6) /* DMA enabled */ 1962652481fSGavin Shan #define EEH_RESET_DEACTIVATE 0 /* Deactivate the PE reset */ 1972652481fSGavin Shan #define EEH_RESET_HOT 1 /* Hot reset */ 1982652481fSGavin Shan #define EEH_RESET_FUNDAMENTAL 3 /* Fundamental reset */ 1998d633291SGavin Shan #define EEH_LOG_TEMP 1 /* EEH temporary error log */ 2008d633291SGavin Shan #define EEH_LOG_PERM 2 /* EEH permanent error log */ 201eb594a47SGavin Shan 202aa1e6374SGavin Shan struct eeh_ops { 203aa1e6374SGavin Shan char *name; 204aa1e6374SGavin Shan int (*init)(void); 205ff57b454SGavin Shan void* (*probe)(struct pci_dn *pdn, void *data); 206371a395dSGavin Shan int (*set_option)(struct eeh_pe *pe, int option); 207371a395dSGavin Shan int (*get_pe_addr)(struct eeh_pe *pe); 208fef7f905SSam Bobroff int (*get_state)(struct eeh_pe *pe, int *delay); 209371a395dSGavin Shan int (*reset)(struct eeh_pe *pe, int option); 210371a395dSGavin Shan int (*get_log)(struct eeh_pe *pe, int severity, char *drv_log, unsigned long len); 211371a395dSGavin Shan int (*configure_bridge)(struct eeh_pe *pe); 212131c123aSGavin Shan int (*err_inject)(struct eeh_pe *pe, int type, int func, 213131c123aSGavin Shan unsigned long addr, unsigned long mask); 2140bd78587SGavin Shan int (*read_config)(struct pci_dn *pdn, int where, int size, u32 *val); 2150bd78587SGavin Shan int (*write_config)(struct pci_dn *pdn, int where, int size, u32 val); 2168a6b1bc7SGavin Shan int (*next_error)(struct eeh_pe **pe); 2170bd78587SGavin Shan int (*restore_config)(struct pci_dn *pdn); 21867923cfcSBryant G. Ly int (*notify_resume)(struct pci_dn *pdn); 219aa1e6374SGavin Shan }; 220aa1e6374SGavin Shan 2218a5ad356SGavin Shan extern int eeh_subsystem_flags; 22246ee7c3cSOliver O'Halloran extern u32 eeh_max_freezes; 223*6b493f60SOliver O'Halloran extern bool eeh_debugfs_no_recover; 224aa1e6374SGavin Shan extern struct eeh_ops *eeh_ops; 2254907581dSGavin Shan extern raw_spinlock_t confirm_error_lock; 226d7bb8862SGavin Shan 22705b1721dSGavin Shan static inline void eeh_add_flag(int flag) 228d7bb8862SGavin Shan { 2298a5ad356SGavin Shan eeh_subsystem_flags |= flag; 230d7bb8862SGavin Shan } 231d7bb8862SGavin Shan 23205b1721dSGavin Shan static inline void eeh_clear_flag(int flag) 233d7bb8862SGavin Shan { 23405b1721dSGavin Shan eeh_subsystem_flags &= ~flag; 235d7bb8862SGavin Shan } 236d7bb8862SGavin Shan 23705b1721dSGavin Shan static inline bool eeh_has_flag(int flag) 238d7bb8862SGavin Shan { 23905b1721dSGavin Shan return !!(eeh_subsystem_flags & flag); 24005b1721dSGavin Shan } 24105b1721dSGavin Shan 24205b1721dSGavin Shan static inline bool eeh_enabled(void) 24305b1721dSGavin Shan { 24454644927SSam Bobroff return eeh_has_flag(EEH_ENABLED) && !eeh_has_flag(EEH_FORCE_DISABLED); 245d7bb8862SGavin Shan } 246646a8499SGavin Shan 2474907581dSGavin Shan static inline void eeh_serialize_lock(unsigned long *flags) 2484907581dSGavin Shan { 2494907581dSGavin Shan raw_spin_lock_irqsave(&confirm_error_lock, *flags); 2504907581dSGavin Shan } 2514907581dSGavin Shan 2524907581dSGavin Shan static inline void eeh_serialize_unlock(unsigned long flags) 2534907581dSGavin Shan { 2544907581dSGavin Shan raw_spin_unlock_irqrestore(&confirm_error_lock, flags); 2554907581dSGavin Shan } 2564907581dSGavin Shan 25734a286a4SSam Bobroff static inline bool eeh_state_active(int state) 25834a286a4SSam Bobroff { 25934a286a4SSam Bobroff return (state & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) 26034a286a4SSam Bobroff == (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE); 26134a286a4SSam Bobroff } 26234a286a4SSam Bobroff 263d6c4932fSSam Bobroff typedef void *(*eeh_edev_traverse_func)(struct eeh_dev *edev, void *flag); 264d6c4932fSSam Bobroff typedef void *(*eeh_pe_traverse_func)(struct eeh_pe *pe, void *flag); 265bb593c00SGavin Shan void eeh_set_pe_aux_size(int size); 266cad5cef6SGreg Kroah-Hartman int eeh_phb_pe_create(struct pci_controller *phb); 267fef7f905SSam Bobroff int eeh_wait_state(struct eeh_pe *pe, int max_wait); 2689ff67433SGavin Shan struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb); 269309ed3a7SSam Bobroff struct eeh_pe *eeh_pe_next(struct eeh_pe *pe, struct eeh_pe *root); 2708bae6a23SAlexey Kardashevskiy struct eeh_pe *eeh_pe_get(struct pci_controller *phb, 2718bae6a23SAlexey Kardashevskiy int pe_no, int config_addr); 2729b84348cSGavin Shan int eeh_add_to_parent_pe(struct eeh_dev *edev); 273807a827dSGavin Shan int eeh_rmv_from_parent_pe(struct eeh_dev *edev); 2745a71978eSGavin Shan void eeh_pe_update_time_stamp(struct eeh_pe *pe); 275f5c57710SGavin Shan void *eeh_pe_traverse(struct eeh_pe *root, 276d6c4932fSSam Bobroff eeh_pe_traverse_func fn, void *flag); 2779e6d2cf6SGavin Shan void *eeh_pe_dev_traverse(struct eeh_pe *root, 278d6c4932fSSam Bobroff eeh_edev_traverse_func fn, void *flag); 2799e6d2cf6SGavin Shan void eeh_pe_restore_bars(struct eeh_pe *pe); 280357b2f3dSGavin Shan const char *eeh_pe_loc_get(struct eeh_pe *pe); 2819b3c76f0SGavin Shan struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe); 28255037d17SGavin Shan 2838cc7581cSGavin Shan struct eeh_dev *eeh_dev_init(struct pci_dn *pdn); 284cad5cef6SGreg Kroah-Hartman void eeh_dev_phb_init_dynamic(struct pci_controller *phb); 285b9fde58dSBenjamin Herrenschmidt void eeh_probe_devices(void); 286aa1e6374SGavin Shan int __init eeh_ops_register(struct eeh_ops *ops); 287aa1e6374SGavin Shan int __exit eeh_ops_unregister(const char *name); 2883e938052SGavin Shan int eeh_check_failure(const volatile void __iomem *token); 289f8f7d63fSGavin Shan int eeh_dev_check_failure(struct eeh_dev *edev); 290eeb6361fSGavin Shan void eeh_addr_cache_build(void); 291ff57b454SGavin Shan void eeh_add_device_early(struct pci_dn *); 292ff57b454SGavin Shan void eeh_add_device_tree_early(struct pci_dn *); 293f2856491SGavin Shan void eeh_add_device_late(struct pci_dev *); 294b8b572e1SStephen Rothwell void eeh_add_device_tree_late(struct pci_bus *); 2956a040ce7SThadeu Lima de Souza Cascardo void eeh_add_sysfs_files(struct pci_bus *); 296807a827dSGavin Shan void eeh_remove_device(struct pci_dev *); 297188fdea6SSam Bobroff int eeh_unfreeze_pe(struct eeh_pe *pe); 2985cfb20b9SGavin Shan int eeh_pe_reset_and_recover(struct eeh_pe *pe); 299212d16cdSGavin Shan int eeh_dev_open(struct pci_dev *pdev); 300212d16cdSGavin Shan void eeh_dev_release(struct pci_dev *pdev); 301212d16cdSGavin Shan struct eeh_pe *eeh_iommu_group_to_pe(struct iommu_group *group); 302212d16cdSGavin Shan int eeh_pe_set_option(struct eeh_pe *pe, int option); 303212d16cdSGavin Shan int eeh_pe_get_state(struct eeh_pe *pe); 3041ef52073SSam Bobroff int eeh_pe_reset(struct eeh_pe *pe, int option, bool include_passed); 305212d16cdSGavin Shan int eeh_pe_configure(struct eeh_pe *pe); 306ec33d36eSGavin Shan int eeh_pe_inject_err(struct eeh_pe *pe, int type, int func, 307ec33d36eSGavin Shan unsigned long addr, unsigned long mask); 30864ba3dc7SBryant G. Ly int eeh_restore_vf_config(struct pci_dn *pdn); 309b8b572e1SStephen Rothwell 310b8b572e1SStephen Rothwell /** 311b8b572e1SStephen Rothwell * EEH_POSSIBLE_ERROR() -- test for possible MMIO failure. 312b8b572e1SStephen Rothwell * 313b8b572e1SStephen Rothwell * If this macro yields TRUE, the caller relays to eeh_check_failure() 314b8b572e1SStephen Rothwell * which does further tests out of line. 315b8b572e1SStephen Rothwell */ 3162ec5a0adSGavin Shan #define EEH_POSSIBLE_ERROR(val, type) ((val) == (type)~0 && eeh_enabled()) 317b8b572e1SStephen Rothwell 318b8b572e1SStephen Rothwell /* 319b8b572e1SStephen Rothwell * Reads from a device which has been isolated by EEH will return 320b8b572e1SStephen Rothwell * all 1s. This macro gives an all-1s value of the given size (in 321b8b572e1SStephen Rothwell * bytes: 1, 2, or 4) for comparing with the result of a read. 322b8b572e1SStephen Rothwell */ 323b8b572e1SStephen Rothwell #define EEH_IO_ERROR_VALUE(size) (~0U >> ((4 - (size)) * 8)) 324b8b572e1SStephen Rothwell 325b8b572e1SStephen Rothwell #else /* !CONFIG_EEH */ 326eb740b5fSGavin Shan 3272ec5a0adSGavin Shan static inline bool eeh_enabled(void) 3282ec5a0adSGavin Shan { 3292ec5a0adSGavin Shan return false; 3302ec5a0adSGavin Shan } 3312ec5a0adSGavin Shan 332b9fde58dSBenjamin Herrenschmidt static inline void eeh_probe_devices(void) { } 33351fb5f56SGavin Shan 334e8e9b34cSGavin Shan static inline void *eeh_dev_init(struct pci_dn *pdn, void *data) 335eb740b5fSGavin Shan { 336eb740b5fSGavin Shan return NULL; 337eb740b5fSGavin Shan } 338eb740b5fSGavin Shan 339eb740b5fSGavin Shan static inline void eeh_dev_phb_init_dynamic(struct pci_controller *phb) { } 340eb740b5fSGavin Shan 3413e938052SGavin Shan static inline int eeh_check_failure(const volatile void __iomem *token) 342b8b572e1SStephen Rothwell { 3433e938052SGavin Shan return 0; 344b8b572e1SStephen Rothwell } 345b8b572e1SStephen Rothwell 346f8f7d63fSGavin Shan #define eeh_dev_check_failure(x) (0) 347b8b572e1SStephen Rothwell 3483ab96a02SGavin Shan static inline void eeh_addr_cache_build(void) { } 349b8b572e1SStephen Rothwell 350ff57b454SGavin Shan static inline void eeh_add_device_early(struct pci_dn *pdn) { } 351f2856491SGavin Shan 352ff57b454SGavin Shan static inline void eeh_add_device_tree_early(struct pci_dn *pdn) { } 353b8b572e1SStephen Rothwell 354f2856491SGavin Shan static inline void eeh_add_device_late(struct pci_dev *dev) { } 355f2856491SGavin Shan 356b8b572e1SStephen Rothwell static inline void eeh_add_device_tree_late(struct pci_bus *bus) { } 357b8b572e1SStephen Rothwell 3586a040ce7SThadeu Lima de Souza Cascardo static inline void eeh_add_sysfs_files(struct pci_bus *bus) { } 3596a040ce7SThadeu Lima de Souza Cascardo 360807a827dSGavin Shan static inline void eeh_remove_device(struct pci_dev *dev) { } 361646a8499SGavin Shan 362b8b572e1SStephen Rothwell #define EEH_POSSIBLE_ERROR(val, type) (0) 363b8b572e1SStephen Rothwell #define EEH_IO_ERROR_VALUE(size) (-1UL) 364b8b572e1SStephen Rothwell #endif /* CONFIG_EEH */ 365b8b572e1SStephen Rothwell 3668b8da358SBenjamin Herrenschmidt #ifdef CONFIG_PPC64 367b8b572e1SStephen Rothwell /* 368b8b572e1SStephen Rothwell * MMIO read/write operations with EEH support. 369b8b572e1SStephen Rothwell */ 370b8b572e1SStephen Rothwell static inline u8 eeh_readb(const volatile void __iomem *addr) 371b8b572e1SStephen Rothwell { 372b8b572e1SStephen Rothwell u8 val = in_8(addr); 373b8b572e1SStephen Rothwell if (EEH_POSSIBLE_ERROR(val, u8)) 3743e938052SGavin Shan eeh_check_failure(addr); 375b8b572e1SStephen Rothwell return val; 376b8b572e1SStephen Rothwell } 377b8b572e1SStephen Rothwell 378b8b572e1SStephen Rothwell static inline u16 eeh_readw(const volatile void __iomem *addr) 379b8b572e1SStephen Rothwell { 380b8b572e1SStephen Rothwell u16 val = in_le16(addr); 381b8b572e1SStephen Rothwell if (EEH_POSSIBLE_ERROR(val, u16)) 3823e938052SGavin Shan eeh_check_failure(addr); 383b8b572e1SStephen Rothwell return val; 384b8b572e1SStephen Rothwell } 385b8b572e1SStephen Rothwell 386b8b572e1SStephen Rothwell static inline u32 eeh_readl(const volatile void __iomem *addr) 387b8b572e1SStephen Rothwell { 388b8b572e1SStephen Rothwell u32 val = in_le32(addr); 389b8b572e1SStephen Rothwell if (EEH_POSSIBLE_ERROR(val, u32)) 3903e938052SGavin Shan eeh_check_failure(addr); 391b8b572e1SStephen Rothwell return val; 392b8b572e1SStephen Rothwell } 393b8b572e1SStephen Rothwell 394b8b572e1SStephen Rothwell static inline u64 eeh_readq(const volatile void __iomem *addr) 395b8b572e1SStephen Rothwell { 396b8b572e1SStephen Rothwell u64 val = in_le64(addr); 397b8b572e1SStephen Rothwell if (EEH_POSSIBLE_ERROR(val, u64)) 3983e938052SGavin Shan eeh_check_failure(addr); 399b8b572e1SStephen Rothwell return val; 400b8b572e1SStephen Rothwell } 401b8b572e1SStephen Rothwell 402b8b572e1SStephen Rothwell static inline u16 eeh_readw_be(const volatile void __iomem *addr) 403b8b572e1SStephen Rothwell { 404b8b572e1SStephen Rothwell u16 val = in_be16(addr); 405b8b572e1SStephen Rothwell if (EEH_POSSIBLE_ERROR(val, u16)) 4063e938052SGavin Shan eeh_check_failure(addr); 407b8b572e1SStephen Rothwell return val; 408b8b572e1SStephen Rothwell } 409b8b572e1SStephen Rothwell 410b8b572e1SStephen Rothwell static inline u32 eeh_readl_be(const volatile void __iomem *addr) 411b8b572e1SStephen Rothwell { 412b8b572e1SStephen Rothwell u32 val = in_be32(addr); 413b8b572e1SStephen Rothwell if (EEH_POSSIBLE_ERROR(val, u32)) 4143e938052SGavin Shan eeh_check_failure(addr); 415b8b572e1SStephen Rothwell return val; 416b8b572e1SStephen Rothwell } 417b8b572e1SStephen Rothwell 418b8b572e1SStephen Rothwell static inline u64 eeh_readq_be(const volatile void __iomem *addr) 419b8b572e1SStephen Rothwell { 420b8b572e1SStephen Rothwell u64 val = in_be64(addr); 421b8b572e1SStephen Rothwell if (EEH_POSSIBLE_ERROR(val, u64)) 4223e938052SGavin Shan eeh_check_failure(addr); 423b8b572e1SStephen Rothwell return val; 424b8b572e1SStephen Rothwell } 425b8b572e1SStephen Rothwell 426b8b572e1SStephen Rothwell static inline void eeh_memcpy_fromio(void *dest, const 427b8b572e1SStephen Rothwell volatile void __iomem *src, 428b8b572e1SStephen Rothwell unsigned long n) 429b8b572e1SStephen Rothwell { 430b8b572e1SStephen Rothwell _memcpy_fromio(dest, src, n); 431b8b572e1SStephen Rothwell 432b8b572e1SStephen Rothwell /* Look for ffff's here at dest[n]. Assume that at least 4 bytes 433b8b572e1SStephen Rothwell * were copied. Check all four bytes. 434b8b572e1SStephen Rothwell */ 435b8b572e1SStephen Rothwell if (n >= 4 && EEH_POSSIBLE_ERROR(*((u32 *)(dest + n - 4)), u32)) 4363e938052SGavin Shan eeh_check_failure(src); 437b8b572e1SStephen Rothwell } 438b8b572e1SStephen Rothwell 439b8b572e1SStephen Rothwell /* in-string eeh macros */ 440b8b572e1SStephen Rothwell static inline void eeh_readsb(const volatile void __iomem *addr, void * buf, 441b8b572e1SStephen Rothwell int ns) 442b8b572e1SStephen Rothwell { 443b8b572e1SStephen Rothwell _insb(addr, buf, ns); 444b8b572e1SStephen Rothwell if (EEH_POSSIBLE_ERROR((*(((u8*)buf)+ns-1)), u8)) 4453e938052SGavin Shan eeh_check_failure(addr); 446b8b572e1SStephen Rothwell } 447b8b572e1SStephen Rothwell 448b8b572e1SStephen Rothwell static inline void eeh_readsw(const volatile void __iomem *addr, void * buf, 449b8b572e1SStephen Rothwell int ns) 450b8b572e1SStephen Rothwell { 451b8b572e1SStephen Rothwell _insw(addr, buf, ns); 452b8b572e1SStephen Rothwell if (EEH_POSSIBLE_ERROR((*(((u16*)buf)+ns-1)), u16)) 4533e938052SGavin Shan eeh_check_failure(addr); 454b8b572e1SStephen Rothwell } 455b8b572e1SStephen Rothwell 456b8b572e1SStephen Rothwell static inline void eeh_readsl(const volatile void __iomem *addr, void * buf, 457b8b572e1SStephen Rothwell int nl) 458b8b572e1SStephen Rothwell { 459b8b572e1SStephen Rothwell _insl(addr, buf, nl); 460b8b572e1SStephen Rothwell if (EEH_POSSIBLE_ERROR((*(((u32*)buf)+nl-1)), u32)) 4613e938052SGavin Shan eeh_check_failure(addr); 462b8b572e1SStephen Rothwell } 463b8b572e1SStephen Rothwell 4645ca85ae6SOliver O'Halloran 4655ca85ae6SOliver O'Halloran void eeh_cache_debugfs_init(void); 4665ca85ae6SOliver O'Halloran 4678b8da358SBenjamin Herrenschmidt #endif /* CONFIG_PPC64 */ 468b8b572e1SStephen Rothwell #endif /* __KERNEL__ */ 4698b8da358SBenjamin Herrenschmidt #endif /* _POWERPC_EEH_H */ 470