162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2001  Dave Engebretsen & Todd Inglett IBM Corporation.
462306a36Sopenharmony_ci * Copyright 2001-2012 IBM Corporation.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#ifndef _POWERPC_EEH_H
862306a36Sopenharmony_ci#define _POWERPC_EEH_H
962306a36Sopenharmony_ci#ifdef __KERNEL__
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/init.h>
1262306a36Sopenharmony_ci#include <linux/list.h>
1362306a36Sopenharmony_ci#include <linux/string.h>
1462306a36Sopenharmony_ci#include <linux/time.h>
1562306a36Sopenharmony_ci#include <linux/atomic.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <uapi/asm/eeh.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistruct pci_dev;
2062306a36Sopenharmony_cistruct pci_bus;
2162306a36Sopenharmony_cistruct pci_dn;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#ifdef CONFIG_EEH
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* EEH subsystem flags */
2662306a36Sopenharmony_ci#define EEH_ENABLED		0x01	/* EEH enabled			     */
2762306a36Sopenharmony_ci#define EEH_FORCE_DISABLED	0x02	/* EEH disabled			     */
2862306a36Sopenharmony_ci#define EEH_PROBE_MODE_DEV	0x04	/* From PCI device		     */
2962306a36Sopenharmony_ci#define EEH_PROBE_MODE_DEVTREE	0x08	/* From device tree		     */
3062306a36Sopenharmony_ci#define EEH_ENABLE_IO_FOR_LOG	0x20	/* Enable IO for log		     */
3162306a36Sopenharmony_ci#define EEH_EARLY_DUMP_LOG	0x40	/* Dump log immediately		     */
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/*
3462306a36Sopenharmony_ci * Delay for PE reset, all in ms
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * PCI specification has reset hold time of 100 milliseconds.
3762306a36Sopenharmony_ci * We have 250 milliseconds here. The PCI bus settlement time
3862306a36Sopenharmony_ci * is specified as 1.5 seconds and we have 1.8 seconds.
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_ci#define EEH_PE_RST_HOLD_TIME		250
4162306a36Sopenharmony_ci#define EEH_PE_RST_SETTLE_TIME		1800
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/*
4462306a36Sopenharmony_ci * The struct is used to trace PE related EEH functionality.
4562306a36Sopenharmony_ci * In theory, there will have one instance of the struct to
4662306a36Sopenharmony_ci * be created against particular PE. In nature, PEs correlate
4762306a36Sopenharmony_ci * to each other. the struct has to reflect that hierarchy in
4862306a36Sopenharmony_ci * order to easily pick up those affected PEs when one particular
4962306a36Sopenharmony_ci * PE has EEH errors.
5062306a36Sopenharmony_ci *
5162306a36Sopenharmony_ci * Also, one particular PE might be composed of PCI device, PCI
5262306a36Sopenharmony_ci * bus and its subordinate components. The struct also need ship
5362306a36Sopenharmony_ci * the information. Further more, one particular PE is only meaingful
5462306a36Sopenharmony_ci * in the corresponding PHB. Therefore, the root PEs should be created
5562306a36Sopenharmony_ci * against existing PHBs in on-to-one fashion.
5662306a36Sopenharmony_ci */
5762306a36Sopenharmony_ci#define EEH_PE_INVALID	(1 << 0)	/* Invalid   */
5862306a36Sopenharmony_ci#define EEH_PE_PHB	(1 << 1)	/* PHB PE    */
5962306a36Sopenharmony_ci#define EEH_PE_DEVICE 	(1 << 2)	/* Device PE */
6062306a36Sopenharmony_ci#define EEH_PE_BUS	(1 << 3)	/* Bus PE    */
6162306a36Sopenharmony_ci#define EEH_PE_VF	(1 << 4)	/* VF PE     */
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define EEH_PE_ISOLATED		(1 << 0)	/* Isolated PE		*/
6462306a36Sopenharmony_ci#define EEH_PE_RECOVERING	(1 << 1)	/* Recovering PE	*/
6562306a36Sopenharmony_ci#define EEH_PE_CFG_BLOCKED	(1 << 2)	/* Block config access	*/
6662306a36Sopenharmony_ci#define EEH_PE_RESET		(1 << 3)	/* PE reset in progress */
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#define EEH_PE_KEEP		(1 << 8)	/* Keep PE on hotplug	*/
6962306a36Sopenharmony_ci#define EEH_PE_CFG_RESTRICTED	(1 << 9)	/* Block config on error */
7062306a36Sopenharmony_ci#define EEH_PE_REMOVED		(1 << 10)	/* Removed permanently	*/
7162306a36Sopenharmony_ci#define EEH_PE_PRI_BUS		(1 << 11)	/* Cached primary bus   */
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistruct eeh_pe {
7462306a36Sopenharmony_ci	int type;			/* PE type: PHB/Bus/Device	*/
7562306a36Sopenharmony_ci	int state;			/* PE EEH dependent mode	*/
7662306a36Sopenharmony_ci	int addr;			/* PE configuration address	*/
7762306a36Sopenharmony_ci	struct pci_controller *phb;	/* Associated PHB		*/
7862306a36Sopenharmony_ci	struct pci_bus *bus;		/* Top PCI bus for bus PE	*/
7962306a36Sopenharmony_ci	int check_count;		/* Times of ignored error	*/
8062306a36Sopenharmony_ci	int freeze_count;		/* Times of froze up		*/
8162306a36Sopenharmony_ci	time64_t tstamp;		/* Time on first-time freeze	*/
8262306a36Sopenharmony_ci	int false_positives;		/* Times of reported #ff's	*/
8362306a36Sopenharmony_ci	atomic_t pass_dev_cnt;		/* Count of passed through devs	*/
8462306a36Sopenharmony_ci	struct eeh_pe *parent;		/* Parent PE			*/
8562306a36Sopenharmony_ci	void *data;			/* PE auxillary data		*/
8662306a36Sopenharmony_ci	struct list_head child_list;	/* List of PEs below this PE	*/
8762306a36Sopenharmony_ci	struct list_head child;		/* Memb. child_list/eeh_phb_pe	*/
8862306a36Sopenharmony_ci	struct list_head edevs;		/* List of eeh_dev in this PE	*/
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci#ifdef CONFIG_STACKTRACE
9162306a36Sopenharmony_ci	/*
9262306a36Sopenharmony_ci	 * Saved stack trace. When we find a PE freeze in eeh_dev_check_failure
9362306a36Sopenharmony_ci	 * the stack trace is saved here so we can print it in the recovery
9462306a36Sopenharmony_ci	 * thread if it turns out to due to a real problem rather than
9562306a36Sopenharmony_ci	 * a hot-remove.
9662306a36Sopenharmony_ci	 *
9762306a36Sopenharmony_ci	 * A max of 64 entries might be overkill, but it also might not be.
9862306a36Sopenharmony_ci	 */
9962306a36Sopenharmony_ci	unsigned long stack_trace[64];
10062306a36Sopenharmony_ci	int trace_entries;
10162306a36Sopenharmony_ci#endif /* CONFIG_STACKTRACE */
10262306a36Sopenharmony_ci};
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci#define eeh_pe_for_each_dev(pe, edev, tmp) \
10562306a36Sopenharmony_ci		list_for_each_entry_safe(edev, tmp, &pe->edevs, entry)
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci#define eeh_for_each_pe(root, pe) \
10862306a36Sopenharmony_ci	for (pe = root; pe; pe = eeh_pe_next(pe, root))
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic inline bool eeh_pe_passed(struct eeh_pe *pe)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	return pe ? !!atomic_read(&pe->pass_dev_cnt) : false;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/*
11662306a36Sopenharmony_ci * The struct is used to trace EEH state for the associated
11762306a36Sopenharmony_ci * PCI device node or PCI device. In future, it might
11862306a36Sopenharmony_ci * represent PE as well so that the EEH device to form
11962306a36Sopenharmony_ci * another tree except the currently existing tree of PCI
12062306a36Sopenharmony_ci * buses and PCI devices
12162306a36Sopenharmony_ci */
12262306a36Sopenharmony_ci#define EEH_DEV_BRIDGE		(1 << 0)	/* PCI bridge		*/
12362306a36Sopenharmony_ci#define EEH_DEV_ROOT_PORT	(1 << 1)	/* PCIe root port	*/
12462306a36Sopenharmony_ci#define EEH_DEV_DS_PORT		(1 << 2)	/* Downstream port	*/
12562306a36Sopenharmony_ci#define EEH_DEV_IRQ_DISABLED	(1 << 3)	/* Interrupt disabled	*/
12662306a36Sopenharmony_ci#define EEH_DEV_DISCONNECTED	(1 << 4)	/* Removing from PE	*/
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci#define EEH_DEV_NO_HANDLER	(1 << 8)	/* No error handler	*/
12962306a36Sopenharmony_ci#define EEH_DEV_SYSFS		(1 << 9)	/* Sysfs created	*/
13062306a36Sopenharmony_ci#define EEH_DEV_REMOVED		(1 << 10)	/* Removed permanently	*/
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistruct eeh_dev {
13362306a36Sopenharmony_ci	int mode;			/* EEH mode			*/
13462306a36Sopenharmony_ci	int bdfn;			/* bdfn of device (for cfg ops) */
13562306a36Sopenharmony_ci	struct pci_controller *controller;
13662306a36Sopenharmony_ci	int pe_config_addr;		/* PE config address		*/
13762306a36Sopenharmony_ci	u32 config_space[16];		/* Saved PCI config space	*/
13862306a36Sopenharmony_ci	int pcix_cap;			/* Saved PCIx capability	*/
13962306a36Sopenharmony_ci	int pcie_cap;			/* Saved PCIe capability	*/
14062306a36Sopenharmony_ci	int aer_cap;			/* Saved AER capability		*/
14162306a36Sopenharmony_ci	int af_cap;			/* Saved AF capability		*/
14262306a36Sopenharmony_ci	struct eeh_pe *pe;		/* Associated PE		*/
14362306a36Sopenharmony_ci	struct list_head entry;		/* Membership in eeh_pe.edevs	*/
14462306a36Sopenharmony_ci	struct list_head rmv_entry;	/* Membership in rmv_list	*/
14562306a36Sopenharmony_ci	struct pci_dn *pdn;		/* Associated PCI device node	*/
14662306a36Sopenharmony_ci	struct pci_dev *pdev;		/* Associated PCI device	*/
14762306a36Sopenharmony_ci	bool in_error;			/* Error flag for edev		*/
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	/* VF specific properties */
15062306a36Sopenharmony_ci	struct pci_dev *physfn;		/* Associated SRIOV PF		*/
15162306a36Sopenharmony_ci	int vf_index;			/* Index of this VF 		*/
15262306a36Sopenharmony_ci};
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci/* "fmt" must be a simple literal string */
15562306a36Sopenharmony_ci#define EEH_EDEV_PRINT(level, edev, fmt, ...) \
15662306a36Sopenharmony_ci	pr_##level("PCI %04x:%02x:%02x.%x#%04x: EEH: " fmt, \
15762306a36Sopenharmony_ci	(edev)->controller->global_number, PCI_BUSNO((edev)->bdfn), \
15862306a36Sopenharmony_ci	PCI_SLOT((edev)->bdfn), PCI_FUNC((edev)->bdfn), \
15962306a36Sopenharmony_ci	((edev)->pe ? (edev)->pe_config_addr : 0xffff), ##__VA_ARGS__)
16062306a36Sopenharmony_ci#define eeh_edev_dbg(edev, fmt, ...) EEH_EDEV_PRINT(debug, (edev), fmt, ##__VA_ARGS__)
16162306a36Sopenharmony_ci#define eeh_edev_info(edev, fmt, ...) EEH_EDEV_PRINT(info, (edev), fmt, ##__VA_ARGS__)
16262306a36Sopenharmony_ci#define eeh_edev_warn(edev, fmt, ...) EEH_EDEV_PRINT(warn, (edev), fmt, ##__VA_ARGS__)
16362306a36Sopenharmony_ci#define eeh_edev_err(edev, fmt, ...) EEH_EDEV_PRINT(err, (edev), fmt, ##__VA_ARGS__)
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic inline struct pci_dn *eeh_dev_to_pdn(struct eeh_dev *edev)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	return edev ? edev->pdn : NULL;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic inline struct pci_dev *eeh_dev_to_pci_dev(struct eeh_dev *edev)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	return edev ? edev->pdev : NULL;
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic inline struct eeh_pe *eeh_dev_to_pe(struct eeh_dev* edev)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	return edev ? edev->pe : NULL;
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci/* Return values from eeh_ops::next_error */
18162306a36Sopenharmony_cienum {
18262306a36Sopenharmony_ci	EEH_NEXT_ERR_NONE = 0,
18362306a36Sopenharmony_ci	EEH_NEXT_ERR_INF,
18462306a36Sopenharmony_ci	EEH_NEXT_ERR_FROZEN_PE,
18562306a36Sopenharmony_ci	EEH_NEXT_ERR_FENCED_PHB,
18662306a36Sopenharmony_ci	EEH_NEXT_ERR_DEAD_PHB,
18762306a36Sopenharmony_ci	EEH_NEXT_ERR_DEAD_IOC
18862306a36Sopenharmony_ci};
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci/*
19162306a36Sopenharmony_ci * The struct is used to trace the registered EEH operation
19262306a36Sopenharmony_ci * callback functions. Actually, those operation callback
19362306a36Sopenharmony_ci * functions are heavily platform dependent. That means the
19462306a36Sopenharmony_ci * platform should register its own EEH operation callback
19562306a36Sopenharmony_ci * functions before any EEH further operations.
19662306a36Sopenharmony_ci */
19762306a36Sopenharmony_ci#define EEH_OPT_DISABLE		0	/* EEH disable	*/
19862306a36Sopenharmony_ci#define EEH_OPT_ENABLE		1	/* EEH enable	*/
19962306a36Sopenharmony_ci#define EEH_OPT_THAW_MMIO	2	/* MMIO enable	*/
20062306a36Sopenharmony_ci#define EEH_OPT_THAW_DMA	3	/* DMA enable	*/
20162306a36Sopenharmony_ci#define EEH_OPT_FREEZE_PE	4	/* Freeze PE	*/
20262306a36Sopenharmony_ci#define EEH_STATE_UNAVAILABLE	(1 << 0)	/* State unavailable	*/
20362306a36Sopenharmony_ci#define EEH_STATE_NOT_SUPPORT	(1 << 1)	/* EEH not supported	*/
20462306a36Sopenharmony_ci#define EEH_STATE_RESET_ACTIVE	(1 << 2)	/* Active reset		*/
20562306a36Sopenharmony_ci#define EEH_STATE_MMIO_ACTIVE	(1 << 3)	/* Active MMIO		*/
20662306a36Sopenharmony_ci#define EEH_STATE_DMA_ACTIVE	(1 << 4)	/* Active DMA		*/
20762306a36Sopenharmony_ci#define EEH_STATE_MMIO_ENABLED	(1 << 5)	/* MMIO enabled		*/
20862306a36Sopenharmony_ci#define EEH_STATE_DMA_ENABLED	(1 << 6)	/* DMA enabled		*/
20962306a36Sopenharmony_ci#define EEH_RESET_DEACTIVATE	0	/* Deactivate the PE reset	*/
21062306a36Sopenharmony_ci#define EEH_RESET_HOT		1	/* Hot reset			*/
21162306a36Sopenharmony_ci#define EEH_RESET_FUNDAMENTAL	3	/* Fundamental reset		*/
21262306a36Sopenharmony_ci#define EEH_LOG_TEMP		1	/* EEH temporary error log	*/
21362306a36Sopenharmony_ci#define EEH_LOG_PERM		2	/* EEH permanent error log	*/
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistruct eeh_ops {
21662306a36Sopenharmony_ci	char *name;
21762306a36Sopenharmony_ci	struct eeh_dev *(*probe)(struct pci_dev *pdev);
21862306a36Sopenharmony_ci	int (*set_option)(struct eeh_pe *pe, int option);
21962306a36Sopenharmony_ci	int (*get_state)(struct eeh_pe *pe, int *delay);
22062306a36Sopenharmony_ci	int (*reset)(struct eeh_pe *pe, int option);
22162306a36Sopenharmony_ci	int (*get_log)(struct eeh_pe *pe, int severity, char *drv_log, unsigned long len);
22262306a36Sopenharmony_ci	int (*configure_bridge)(struct eeh_pe *pe);
22362306a36Sopenharmony_ci	int (*err_inject)(struct eeh_pe *pe, int type, int func,
22462306a36Sopenharmony_ci			  unsigned long addr, unsigned long mask);
22562306a36Sopenharmony_ci	int (*read_config)(struct eeh_dev *edev, int where, int size, u32 *val);
22662306a36Sopenharmony_ci	int (*write_config)(struct eeh_dev *edev, int where, int size, u32 val);
22762306a36Sopenharmony_ci	int (*next_error)(struct eeh_pe **pe);
22862306a36Sopenharmony_ci	int (*restore_config)(struct eeh_dev *edev);
22962306a36Sopenharmony_ci	int (*notify_resume)(struct eeh_dev *edev);
23062306a36Sopenharmony_ci};
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ciextern int eeh_subsystem_flags;
23362306a36Sopenharmony_ciextern u32 eeh_max_freezes;
23462306a36Sopenharmony_ciextern bool eeh_debugfs_no_recover;
23562306a36Sopenharmony_ciextern struct eeh_ops *eeh_ops;
23662306a36Sopenharmony_ciextern raw_spinlock_t confirm_error_lock;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic inline void eeh_add_flag(int flag)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	eeh_subsystem_flags |= flag;
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cistatic inline void eeh_clear_flag(int flag)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	eeh_subsystem_flags &= ~flag;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic inline bool eeh_has_flag(int flag)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci        return !!(eeh_subsystem_flags & flag);
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic inline bool eeh_enabled(void)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	return eeh_has_flag(EEH_ENABLED) && !eeh_has_flag(EEH_FORCE_DISABLED);
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic inline void eeh_serialize_lock(unsigned long *flags)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	raw_spin_lock_irqsave(&confirm_error_lock, *flags);
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic inline void eeh_serialize_unlock(unsigned long flags)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&confirm_error_lock, flags);
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic inline bool eeh_state_active(int state)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	return (state & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE))
27162306a36Sopenharmony_ci	== (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE);
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_citypedef void (*eeh_edev_traverse_func)(struct eeh_dev *edev, void *flag);
27562306a36Sopenharmony_citypedef void *(*eeh_pe_traverse_func)(struct eeh_pe *pe, void *flag);
27662306a36Sopenharmony_civoid eeh_set_pe_aux_size(int size);
27762306a36Sopenharmony_ciint eeh_phb_pe_create(struct pci_controller *phb);
27862306a36Sopenharmony_ciint eeh_wait_state(struct eeh_pe *pe, int max_wait);
27962306a36Sopenharmony_cistruct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb);
28062306a36Sopenharmony_cistruct eeh_pe *eeh_pe_next(struct eeh_pe *pe, struct eeh_pe *root);
28162306a36Sopenharmony_cistruct eeh_pe *eeh_pe_get(struct pci_controller *phb, int pe_no);
28262306a36Sopenharmony_ciint eeh_pe_tree_insert(struct eeh_dev *edev, struct eeh_pe *new_pe_parent);
28362306a36Sopenharmony_ciint eeh_pe_tree_remove(struct eeh_dev *edev);
28462306a36Sopenharmony_civoid eeh_pe_update_time_stamp(struct eeh_pe *pe);
28562306a36Sopenharmony_civoid *eeh_pe_traverse(struct eeh_pe *root,
28662306a36Sopenharmony_ci		      eeh_pe_traverse_func fn, void *flag);
28762306a36Sopenharmony_civoid eeh_pe_dev_traverse(struct eeh_pe *root,
28862306a36Sopenharmony_ci			 eeh_edev_traverse_func fn, void *flag);
28962306a36Sopenharmony_civoid eeh_pe_restore_bars(struct eeh_pe *pe);
29062306a36Sopenharmony_ciconst char *eeh_pe_loc_get(struct eeh_pe *pe);
29162306a36Sopenharmony_cistruct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_civoid eeh_show_enabled(void);
29462306a36Sopenharmony_ciint __init eeh_init(struct eeh_ops *ops);
29562306a36Sopenharmony_ciint eeh_check_failure(const volatile void __iomem *token);
29662306a36Sopenharmony_ciint eeh_dev_check_failure(struct eeh_dev *edev);
29762306a36Sopenharmony_civoid eeh_addr_cache_init(void);
29862306a36Sopenharmony_civoid eeh_probe_device(struct pci_dev *pdev);
29962306a36Sopenharmony_civoid eeh_remove_device(struct pci_dev *);
30062306a36Sopenharmony_ciint eeh_unfreeze_pe(struct eeh_pe *pe);
30162306a36Sopenharmony_ciint eeh_pe_reset_and_recover(struct eeh_pe *pe);
30262306a36Sopenharmony_ciint eeh_dev_open(struct pci_dev *pdev);
30362306a36Sopenharmony_civoid eeh_dev_release(struct pci_dev *pdev);
30462306a36Sopenharmony_cistruct eeh_pe *eeh_iommu_group_to_pe(struct iommu_group *group);
30562306a36Sopenharmony_ciint eeh_pe_set_option(struct eeh_pe *pe, int option);
30662306a36Sopenharmony_ciint eeh_pe_get_state(struct eeh_pe *pe);
30762306a36Sopenharmony_ciint eeh_pe_reset(struct eeh_pe *pe, int option, bool include_passed);
30862306a36Sopenharmony_ciint eeh_pe_configure(struct eeh_pe *pe);
30962306a36Sopenharmony_ciint eeh_pe_inject_err(struct eeh_pe *pe, int type, int func,
31062306a36Sopenharmony_ci		      unsigned long addr, unsigned long mask);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci/**
31362306a36Sopenharmony_ci * EEH_POSSIBLE_ERROR() -- test for possible MMIO failure.
31462306a36Sopenharmony_ci *
31562306a36Sopenharmony_ci * If this macro yields TRUE, the caller relays to eeh_check_failure()
31662306a36Sopenharmony_ci * which does further tests out of line.
31762306a36Sopenharmony_ci */
31862306a36Sopenharmony_ci#define EEH_POSSIBLE_ERROR(val, type)	((val) == (type)~0 && eeh_enabled())
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci/*
32162306a36Sopenharmony_ci * Reads from a device which has been isolated by EEH will return
32262306a36Sopenharmony_ci * all 1s.  This macro gives an all-1s value of the given size (in
32362306a36Sopenharmony_ci * bytes: 1, 2, or 4) for comparing with the result of a read.
32462306a36Sopenharmony_ci */
32562306a36Sopenharmony_ci#define EEH_IO_ERROR_VALUE(size)	(~0U >> ((4 - (size)) * 8))
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci#else /* !CONFIG_EEH */
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_cistatic inline bool eeh_enabled(void)
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci        return false;
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic inline void eeh_show_enabled(void) { }
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic inline int eeh_check_failure(const volatile void __iomem *token)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	return 0;
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci#define eeh_dev_check_failure(x) (0)
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic inline void eeh_addr_cache_init(void) { }
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_cistatic inline void eeh_probe_device(struct pci_dev *dev) { }
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic inline void eeh_remove_device(struct pci_dev *dev) { }
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci#define EEH_POSSIBLE_ERROR(val, type) (0)
35062306a36Sopenharmony_ci#define EEH_IO_ERROR_VALUE(size) (-1UL)
35162306a36Sopenharmony_cistatic inline int eeh_phb_pe_create(struct pci_controller *phb) { return 0; }
35262306a36Sopenharmony_ci#endif /* CONFIG_EEH */
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci#if defined(CONFIG_PPC_PSERIES) && defined(CONFIG_EEH)
35562306a36Sopenharmony_civoid pseries_eeh_init_edev_recursive(struct pci_dn *pdn);
35662306a36Sopenharmony_ci#endif
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci#ifdef CONFIG_PPC64
35962306a36Sopenharmony_ci/*
36062306a36Sopenharmony_ci * MMIO read/write operations with EEH support.
36162306a36Sopenharmony_ci */
36262306a36Sopenharmony_cistatic inline u8 eeh_readb(const volatile void __iomem *addr)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	u8 val = in_8(addr);
36562306a36Sopenharmony_ci	if (EEH_POSSIBLE_ERROR(val, u8))
36662306a36Sopenharmony_ci		eeh_check_failure(addr);
36762306a36Sopenharmony_ci	return val;
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_cistatic inline u16 eeh_readw(const volatile void __iomem *addr)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	u16 val = in_le16(addr);
37362306a36Sopenharmony_ci	if (EEH_POSSIBLE_ERROR(val, u16))
37462306a36Sopenharmony_ci		eeh_check_failure(addr);
37562306a36Sopenharmony_ci	return val;
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cistatic inline u32 eeh_readl(const volatile void __iomem *addr)
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci	u32 val = in_le32(addr);
38162306a36Sopenharmony_ci	if (EEH_POSSIBLE_ERROR(val, u32))
38262306a36Sopenharmony_ci		eeh_check_failure(addr);
38362306a36Sopenharmony_ci	return val;
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistatic inline u64 eeh_readq(const volatile void __iomem *addr)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	u64 val = in_le64(addr);
38962306a36Sopenharmony_ci	if (EEH_POSSIBLE_ERROR(val, u64))
39062306a36Sopenharmony_ci		eeh_check_failure(addr);
39162306a36Sopenharmony_ci	return val;
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic inline u16 eeh_readw_be(const volatile void __iomem *addr)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	u16 val = in_be16(addr);
39762306a36Sopenharmony_ci	if (EEH_POSSIBLE_ERROR(val, u16))
39862306a36Sopenharmony_ci		eeh_check_failure(addr);
39962306a36Sopenharmony_ci	return val;
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic inline u32 eeh_readl_be(const volatile void __iomem *addr)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	u32 val = in_be32(addr);
40562306a36Sopenharmony_ci	if (EEH_POSSIBLE_ERROR(val, u32))
40662306a36Sopenharmony_ci		eeh_check_failure(addr);
40762306a36Sopenharmony_ci	return val;
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_cistatic inline u64 eeh_readq_be(const volatile void __iomem *addr)
41162306a36Sopenharmony_ci{
41262306a36Sopenharmony_ci	u64 val = in_be64(addr);
41362306a36Sopenharmony_ci	if (EEH_POSSIBLE_ERROR(val, u64))
41462306a36Sopenharmony_ci		eeh_check_failure(addr);
41562306a36Sopenharmony_ci	return val;
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic inline void eeh_memcpy_fromio(void *dest, const
41962306a36Sopenharmony_ci				     volatile void __iomem *src,
42062306a36Sopenharmony_ci				     unsigned long n)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	_memcpy_fromio(dest, src, n);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	/* Look for ffff's here at dest[n].  Assume that at least 4 bytes
42562306a36Sopenharmony_ci	 * were copied. Check all four bytes.
42662306a36Sopenharmony_ci	 */
42762306a36Sopenharmony_ci	if (n >= 4 && EEH_POSSIBLE_ERROR(*((u32 *)(dest + n - 4)), u32))
42862306a36Sopenharmony_ci		eeh_check_failure(src);
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci/* in-string eeh macros */
43262306a36Sopenharmony_cistatic inline void eeh_readsb(const volatile void __iomem *addr, void * buf,
43362306a36Sopenharmony_ci			      int ns)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	_insb(addr, buf, ns);
43662306a36Sopenharmony_ci	if (EEH_POSSIBLE_ERROR((*(((u8*)buf)+ns-1)), u8))
43762306a36Sopenharmony_ci		eeh_check_failure(addr);
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic inline void eeh_readsw(const volatile void __iomem *addr, void * buf,
44162306a36Sopenharmony_ci			      int ns)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	_insw(addr, buf, ns);
44462306a36Sopenharmony_ci	if (EEH_POSSIBLE_ERROR((*(((u16*)buf)+ns-1)), u16))
44562306a36Sopenharmony_ci		eeh_check_failure(addr);
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cistatic inline void eeh_readsl(const volatile void __iomem *addr, void * buf,
44962306a36Sopenharmony_ci			      int nl)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	_insl(addr, buf, nl);
45262306a36Sopenharmony_ci	if (EEH_POSSIBLE_ERROR((*(((u32*)buf)+nl-1)), u32))
45362306a36Sopenharmony_ci		eeh_check_failure(addr);
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_civoid __init eeh_cache_debugfs_init(void);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci#endif /* CONFIG_PPC64 */
46062306a36Sopenharmony_ci#endif /* __KERNEL__ */
46162306a36Sopenharmony_ci#endif /* _POWERPC_EEH_H */
462