xref: /openbmc/linux/arch/powerpc/kernel/eeh_pe.c (revision 1541a213)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2317f06deSGavin Shan /*
3317f06deSGavin Shan  * The file intends to implement PE based on the information from
4317f06deSGavin Shan  * platforms. Basically, there have 3 types of PEs: PHB/Bus/Device.
5317f06deSGavin Shan  * All the PEs should be organized as hierarchy tree. The first level
6317f06deSGavin Shan  * of the tree will be associated to existing PHBs since the particular
7317f06deSGavin Shan  * PE is only meaningful in one PHB domain.
8317f06deSGavin Shan  *
9317f06deSGavin Shan  * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2012.
10317f06deSGavin Shan  */
11317f06deSGavin Shan 
12652defedSGavin Shan #include <linux/delay.h>
13317f06deSGavin Shan #include <linux/export.h>
14317f06deSGavin Shan #include <linux/gfp.h>
15317f06deSGavin Shan #include <linux/kernel.h>
16e6f6390aSChristophe Leroy #include <linux/of.h>
17317f06deSGavin Shan #include <linux/pci.h>
18317f06deSGavin Shan #include <linux/string.h>
19317f06deSGavin Shan 
20317f06deSGavin Shan #include <asm/pci-bridge.h>
21317f06deSGavin Shan #include <asm/ppc-pci.h>
22317f06deSGavin Shan 
23bb593c00SGavin Shan static int eeh_pe_aux_size = 0;
24317f06deSGavin Shan static LIST_HEAD(eeh_phb_pe);
25317f06deSGavin Shan 
26317f06deSGavin Shan /**
27bb593c00SGavin Shan  * eeh_set_pe_aux_size - Set PE auxillary data size
28bb593c00SGavin Shan  * @size: PE auxillary data size
29bb593c00SGavin Shan  *
30bb593c00SGavin Shan  * Set PE auxillary data size
31bb593c00SGavin Shan  */
eeh_set_pe_aux_size(int size)32bb593c00SGavin Shan void eeh_set_pe_aux_size(int size)
33bb593c00SGavin Shan {
34bb593c00SGavin Shan 	if (size < 0)
35bb593c00SGavin Shan 		return;
36bb593c00SGavin Shan 
37bb593c00SGavin Shan 	eeh_pe_aux_size = size;
38bb593c00SGavin Shan }
39bb593c00SGavin Shan 
40bb593c00SGavin Shan /**
41317f06deSGavin Shan  * eeh_pe_alloc - Allocate PE
42317f06deSGavin Shan  * @phb: PCI controller
43317f06deSGavin Shan  * @type: PE type
44317f06deSGavin Shan  *
45317f06deSGavin Shan  * Allocate PE instance dynamically.
46317f06deSGavin Shan  */
eeh_pe_alloc(struct pci_controller * phb,int type)47317f06deSGavin Shan static struct eeh_pe *eeh_pe_alloc(struct pci_controller *phb, int type)
48317f06deSGavin Shan {
49317f06deSGavin Shan 	struct eeh_pe *pe;
50bb593c00SGavin Shan 	size_t alloc_size;
51bb593c00SGavin Shan 
52bb593c00SGavin Shan 	alloc_size = sizeof(struct eeh_pe);
53bb593c00SGavin Shan 	if (eeh_pe_aux_size) {
54bb593c00SGavin Shan 		alloc_size = ALIGN(alloc_size, cache_line_size());
55bb593c00SGavin Shan 		alloc_size += eeh_pe_aux_size;
56bb593c00SGavin Shan 	}
57317f06deSGavin Shan 
58317f06deSGavin Shan 	/* Allocate PHB PE */
59bb593c00SGavin Shan 	pe = kzalloc(alloc_size, GFP_KERNEL);
60317f06deSGavin Shan 	if (!pe) return NULL;
61317f06deSGavin Shan 
62317f06deSGavin Shan 	/* Initialize PHB PE */
63317f06deSGavin Shan 	pe->type = type;
64317f06deSGavin Shan 	pe->phb = phb;
65317f06deSGavin Shan 	INIT_LIST_HEAD(&pe->child_list);
66317f06deSGavin Shan 	INIT_LIST_HEAD(&pe->edevs);
67317f06deSGavin Shan 
68bb593c00SGavin Shan 	pe->data = (void *)pe + ALIGN(sizeof(struct eeh_pe),
69bb593c00SGavin Shan 				      cache_line_size());
70317f06deSGavin Shan 	return pe;
71317f06deSGavin Shan }
72317f06deSGavin Shan 
73317f06deSGavin Shan /**
74317f06deSGavin Shan  * eeh_phb_pe_create - Create PHB PE
75317f06deSGavin Shan  * @phb: PCI controller
76317f06deSGavin Shan  *
77317f06deSGavin Shan  * The function should be called while the PHB is detected during
78317f06deSGavin Shan  * system boot or PCI hotplug in order to create PHB PE.
79317f06deSGavin Shan  */
eeh_phb_pe_create(struct pci_controller * phb)80317f06deSGavin Shan int eeh_phb_pe_create(struct pci_controller *phb)
81317f06deSGavin Shan {
82317f06deSGavin Shan 	struct eeh_pe *pe;
83317f06deSGavin Shan 
84317f06deSGavin Shan 	/* Allocate PHB PE */
85317f06deSGavin Shan 	pe = eeh_pe_alloc(phb, EEH_PE_PHB);
86317f06deSGavin Shan 	if (!pe) {
87317f06deSGavin Shan 		pr_err("%s: out of memory!\n", __func__);
88317f06deSGavin Shan 		return -ENOMEM;
89317f06deSGavin Shan 	}
90317f06deSGavin Shan 
91317f06deSGavin Shan 	/* Put it into the list */
92317f06deSGavin Shan 	list_add_tail(&pe->child, &eeh_phb_pe);
93317f06deSGavin Shan 
941f52f176SRussell Currey 	pr_debug("EEH: Add PE for PHB#%x\n", phb->global_number);
95317f06deSGavin Shan 
96317f06deSGavin Shan 	return 0;
97317f06deSGavin Shan }
98317f06deSGavin Shan 
99317f06deSGavin Shan /**
100fef7f905SSam Bobroff  * eeh_wait_state - Wait for PE state
101fef7f905SSam Bobroff  * @pe: EEH PE
102fef7f905SSam Bobroff  * @max_wait: maximal period in millisecond
103fef7f905SSam Bobroff  *
104fef7f905SSam Bobroff  * Wait for the state of associated PE. It might take some time
105fef7f905SSam Bobroff  * to retrieve the PE's state.
106fef7f905SSam Bobroff  */
eeh_wait_state(struct eeh_pe * pe,int max_wait)107fef7f905SSam Bobroff int eeh_wait_state(struct eeh_pe *pe, int max_wait)
108fef7f905SSam Bobroff {
109fef7f905SSam Bobroff 	int ret;
110fef7f905SSam Bobroff 	int mwait;
111fef7f905SSam Bobroff 
112fef7f905SSam Bobroff 	/*
113fef7f905SSam Bobroff 	 * According to PAPR, the state of PE might be temporarily
114fef7f905SSam Bobroff 	 * unavailable. Under the circumstance, we have to wait
115fef7f905SSam Bobroff 	 * for indicated time determined by firmware. The maximal
116fef7f905SSam Bobroff 	 * wait time is 5 minutes, which is acquired from the original
117fef7f905SSam Bobroff 	 * EEH implementation. Also, the original implementation
118fef7f905SSam Bobroff 	 * also defined the minimal wait time as 1 second.
119fef7f905SSam Bobroff 	 */
120fef7f905SSam Bobroff #define EEH_STATE_MIN_WAIT_TIME	(1000)
121fef7f905SSam Bobroff #define EEH_STATE_MAX_WAIT_TIME	(300 * 1000)
122fef7f905SSam Bobroff 
123fef7f905SSam Bobroff 	while (1) {
124fef7f905SSam Bobroff 		ret = eeh_ops->get_state(pe, &mwait);
125fef7f905SSam Bobroff 
126fef7f905SSam Bobroff 		if (ret != EEH_STATE_UNAVAILABLE)
127fef7f905SSam Bobroff 			return ret;
128fef7f905SSam Bobroff 
129fef7f905SSam Bobroff 		if (max_wait <= 0) {
130fef7f905SSam Bobroff 			pr_warn("%s: Timeout when getting PE's state (%d)\n",
131fef7f905SSam Bobroff 				__func__, max_wait);
132fef7f905SSam Bobroff 			return EEH_STATE_NOT_SUPPORT;
133fef7f905SSam Bobroff 		}
134fef7f905SSam Bobroff 
135fef7f905SSam Bobroff 		if (mwait < EEH_STATE_MIN_WAIT_TIME) {
136fef7f905SSam Bobroff 			pr_warn("%s: Firmware returned bad wait value %d\n",
137fef7f905SSam Bobroff 				__func__, mwait);
138fef7f905SSam Bobroff 			mwait = EEH_STATE_MIN_WAIT_TIME;
139fef7f905SSam Bobroff 		} else if (mwait > EEH_STATE_MAX_WAIT_TIME) {
140fef7f905SSam Bobroff 			pr_warn("%s: Firmware returned too long wait value %d\n",
141fef7f905SSam Bobroff 				__func__, mwait);
142fef7f905SSam Bobroff 			mwait = EEH_STATE_MAX_WAIT_TIME;
143fef7f905SSam Bobroff 		}
144fef7f905SSam Bobroff 
145fef7f905SSam Bobroff 		msleep(min(mwait, max_wait));
146fef7f905SSam Bobroff 		max_wait -= mwait;
147fef7f905SSam Bobroff 	}
148fef7f905SSam Bobroff }
149fef7f905SSam Bobroff 
150fef7f905SSam Bobroff /**
151317f06deSGavin Shan  * eeh_phb_pe_get - Retrieve PHB PE based on the given PHB
152317f06deSGavin Shan  * @phb: PCI controller
153317f06deSGavin Shan  *
154317f06deSGavin Shan  * The overall PEs form hierarchy tree. The first layer of the
155317f06deSGavin Shan  * hierarchy tree is composed of PHB PEs. The function is used
156317f06deSGavin Shan  * to retrieve the corresponding PHB PE according to the given PHB.
157317f06deSGavin Shan  */
eeh_phb_pe_get(struct pci_controller * phb)1589ff67433SGavin Shan struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb)
159317f06deSGavin Shan {
160317f06deSGavin Shan 	struct eeh_pe *pe;
161317f06deSGavin Shan 
162317f06deSGavin Shan 	list_for_each_entry(pe, &eeh_phb_pe, child) {
163317f06deSGavin Shan 		/*
164317f06deSGavin Shan 		 * Actually, we needn't check the type since
165317f06deSGavin Shan 		 * the PE for PHB has been determined when that
166317f06deSGavin Shan 		 * was created.
167317f06deSGavin Shan 		 */
168317f06deSGavin Shan 		if ((pe->type & EEH_PE_PHB) && pe->phb == phb)
169317f06deSGavin Shan 			return pe;
170317f06deSGavin Shan 	}
171317f06deSGavin Shan 
172317f06deSGavin Shan 	return NULL;
173317f06deSGavin Shan }
174317f06deSGavin Shan 
175317f06deSGavin Shan /**
176317f06deSGavin Shan  * eeh_pe_next - Retrieve the next PE in the tree
177317f06deSGavin Shan  * @pe: current PE
178317f06deSGavin Shan  * @root: root PE
179317f06deSGavin Shan  *
180317f06deSGavin Shan  * The function is used to retrieve the next PE in the
181317f06deSGavin Shan  * hierarchy PE tree.
182317f06deSGavin Shan  */
eeh_pe_next(struct eeh_pe * pe,struct eeh_pe * root)183309ed3a7SSam Bobroff struct eeh_pe *eeh_pe_next(struct eeh_pe *pe, struct eeh_pe *root)
184317f06deSGavin Shan {
185317f06deSGavin Shan 	struct list_head *next = pe->child_list.next;
186317f06deSGavin Shan 
187317f06deSGavin Shan 	if (next == &pe->child_list) {
188317f06deSGavin Shan 		while (1) {
189317f06deSGavin Shan 			if (pe == root)
190317f06deSGavin Shan 				return NULL;
191317f06deSGavin Shan 			next = pe->child.next;
192317f06deSGavin Shan 			if (next != &pe->parent->child_list)
193317f06deSGavin Shan 				break;
194317f06deSGavin Shan 			pe = pe->parent;
195317f06deSGavin Shan 		}
196317f06deSGavin Shan 	}
197317f06deSGavin Shan 
198317f06deSGavin Shan 	return list_entry(next, struct eeh_pe, child);
199317f06deSGavin Shan }
200317f06deSGavin Shan 
201317f06deSGavin Shan /**
202317f06deSGavin Shan  * eeh_pe_traverse - Traverse PEs in the specified PHB
203317f06deSGavin Shan  * @root: root PE
204317f06deSGavin Shan  * @fn: callback
205317f06deSGavin Shan  * @flag: extra parameter to callback
206317f06deSGavin Shan  *
207317f06deSGavin Shan  * The function is used to traverse the specified PE and its
208317f06deSGavin Shan  * child PEs. The traversing is to be terminated once the
209317f06deSGavin Shan  * callback returns something other than NULL, or no more PEs
210317f06deSGavin Shan  * to be traversed.
211317f06deSGavin Shan  */
eeh_pe_traverse(struct eeh_pe * root,eeh_pe_traverse_func fn,void * flag)212f5c57710SGavin Shan void *eeh_pe_traverse(struct eeh_pe *root,
213d6c4932fSSam Bobroff 		      eeh_pe_traverse_func fn, void *flag)
214317f06deSGavin Shan {
215317f06deSGavin Shan 	struct eeh_pe *pe;
216317f06deSGavin Shan 	void *ret;
217317f06deSGavin Shan 
218309ed3a7SSam Bobroff 	eeh_for_each_pe(root, pe) {
219317f06deSGavin Shan 		ret = fn(pe, flag);
220317f06deSGavin Shan 		if (ret) return ret;
221317f06deSGavin Shan 	}
222317f06deSGavin Shan 
223317f06deSGavin Shan 	return NULL;
224317f06deSGavin Shan }
225317f06deSGavin Shan 
226317f06deSGavin Shan /**
227317f06deSGavin Shan  * eeh_pe_dev_traverse - Traverse the devices from the PE
228317f06deSGavin Shan  * @root: EEH PE
229317f06deSGavin Shan  * @fn: function callback
230317f06deSGavin Shan  * @flag: extra parameter to callback
231317f06deSGavin Shan  *
232317f06deSGavin Shan  * The function is used to traverse the devices of the specified
233317f06deSGavin Shan  * PE and its child PEs.
234317f06deSGavin Shan  */
eeh_pe_dev_traverse(struct eeh_pe * root,eeh_edev_traverse_func fn,void * flag)235cef50c67SSam Bobroff void eeh_pe_dev_traverse(struct eeh_pe *root,
236d6c4932fSSam Bobroff 			  eeh_edev_traverse_func fn, void *flag)
237317f06deSGavin Shan {
238317f06deSGavin Shan 	struct eeh_pe *pe;
2399feed42eSGavin Shan 	struct eeh_dev *edev, *tmp;
240317f06deSGavin Shan 
241317f06deSGavin Shan 	if (!root) {
2420dae2743SGavin Shan 		pr_warn("%s: Invalid PE %p\n",
2430dae2743SGavin Shan 			__func__, root);
244cef50c67SSam Bobroff 		return;
245317f06deSGavin Shan 	}
246317f06deSGavin Shan 
247317f06deSGavin Shan 	/* Traverse root PE */
248cef50c67SSam Bobroff 	eeh_for_each_pe(root, pe)
249cef50c67SSam Bobroff 		eeh_pe_for_each_dev(pe, edev, tmp)
250cef50c67SSam Bobroff 			fn(edev, flag);
251317f06deSGavin Shan }
252317f06deSGavin Shan 
253317f06deSGavin Shan /**
254317f06deSGavin Shan  * __eeh_pe_get - Check the PE address
255317f06deSGavin Shan  *
256317f06deSGavin Shan  * For one particular PE, it can be identified by PE address
257317f06deSGavin Shan  * or tranditional BDF address. BDF address is composed of
258317f06deSGavin Shan  * Bus/Device/Function number. The extra data referred by flag
259317f06deSGavin Shan  * indicates which type of address should be used.
260317f06deSGavin Shan  */
__eeh_pe_get(struct eeh_pe * pe,void * flag)261d6c4932fSSam Bobroff static void *__eeh_pe_get(struct eeh_pe *pe, void *flag)
262317f06deSGavin Shan {
26335d64734SOliver O'Halloran 	int *target_pe = flag;
264317f06deSGavin Shan 
26535d64734SOliver O'Halloran 	/* PHB PEs are special and should be ignored */
266317f06deSGavin Shan 	if (pe->type & EEH_PE_PHB)
267317f06deSGavin Shan 		return NULL;
268317f06deSGavin Shan 
26935d64734SOliver O'Halloran 	if (*target_pe == pe->addr)
270317f06deSGavin Shan 		return pe;
271317f06deSGavin Shan 
272317f06deSGavin Shan 	return NULL;
273317f06deSGavin Shan }
274317f06deSGavin Shan 
275317f06deSGavin Shan /**
276317f06deSGavin Shan  * eeh_pe_get - Search PE based on the given address
2778bae6a23SAlexey Kardashevskiy  * @phb: PCI controller
2788bae6a23SAlexey Kardashevskiy  * @pe_no: PE number
279317f06deSGavin Shan  *
280317f06deSGavin Shan  * Search the corresponding PE based on the specified address which
281317f06deSGavin Shan  * is included in the eeh device. The function is used to check if
282317f06deSGavin Shan  * the associated PE has been created against the PE address. It's
283317f06deSGavin Shan  * notable that the PE address has 2 format: traditional PE address
284317f06deSGavin Shan  * which is composed of PCI bus/device/function number, or unified
285317f06deSGavin Shan  * PE address.
286317f06deSGavin Shan  */
eeh_pe_get(struct pci_controller * phb,int pe_no)28735d64734SOliver O'Halloran struct eeh_pe *eeh_pe_get(struct pci_controller *phb, int pe_no)
288317f06deSGavin Shan {
2898bae6a23SAlexey Kardashevskiy 	struct eeh_pe *root = eeh_phb_pe_get(phb);
290317f06deSGavin Shan 
29135d64734SOliver O'Halloran 	return eeh_pe_traverse(root, __eeh_pe_get, &pe_no);
292317f06deSGavin Shan }
293317f06deSGavin Shan 
294317f06deSGavin Shan /**
295d923ab7aSOliver O'Halloran  * eeh_pe_tree_insert - Add EEH device to parent PE
296317f06deSGavin Shan  * @edev: EEH device
297a131bfc6SOliver O'Halloran  * @new_pe_parent: PE to create additional PEs under
298317f06deSGavin Shan  *
299a131bfc6SOliver O'Halloran  * Add EEH device to the PE in edev->pe_config_addr. If a PE already
300a131bfc6SOliver O'Halloran  * exists with that address then @edev is added to that PE. Otherwise
301a131bfc6SOliver O'Halloran  * a new PE is created and inserted into the PE tree as a child of
302a131bfc6SOliver O'Halloran  * @new_pe_parent.
303a131bfc6SOliver O'Halloran  *
304a131bfc6SOliver O'Halloran  * If @new_pe_parent is NULL then the new PE will be inserted under
30587c78b61SMichael Ellerman  * directly under the PHB.
306317f06deSGavin Shan  */
eeh_pe_tree_insert(struct eeh_dev * edev,struct eeh_pe * new_pe_parent)307a131bfc6SOliver O'Halloran int eeh_pe_tree_insert(struct eeh_dev *edev, struct eeh_pe *new_pe_parent)
308317f06deSGavin Shan {
30931595ae5SOliver O'Halloran 	struct pci_controller *hose = edev->controller;
310317f06deSGavin Shan 	struct eeh_pe *pe, *parent;
311317f06deSGavin Shan 
312317f06deSGavin Shan 	/*
313317f06deSGavin Shan 	 * Search the PE has been existing or not according
314317f06deSGavin Shan 	 * to the PE address. If that has been existing, the
315317f06deSGavin Shan 	 * PE should be composed of PCI bus and its subordinate
316317f06deSGavin Shan 	 * components.
317317f06deSGavin Shan 	 */
31835d64734SOliver O'Halloran 	pe = eeh_pe_get(hose, edev->pe_config_addr);
31927d4396eSSam Bobroff 	if (pe) {
32027d4396eSSam Bobroff 		if (pe->type & EEH_PE_INVALID) {
32180e65b00SSam Bobroff 			list_add_tail(&edev->entry, &pe->edevs);
322317f06deSGavin Shan 			edev->pe = pe;
323317f06deSGavin Shan 			/*
324317f06deSGavin Shan 			 * We're running to here because of PCI hotplug caused by
325317f06deSGavin Shan 			 * EEH recovery. We need clear EEH_PE_INVALID until the top.
326317f06deSGavin Shan 			 */
327317f06deSGavin Shan 			parent = pe;
328317f06deSGavin Shan 			while (parent) {
329317f06deSGavin Shan 				if (!(parent->type & EEH_PE_INVALID))
330317f06deSGavin Shan 					break;
331473af09bSSam Bobroff 				parent->type &= ~EEH_PE_INVALID;
332317f06deSGavin Shan 				parent = parent->parent;
333317f06deSGavin Shan 			}
334317f06deSGavin Shan 
335a131bfc6SOliver O'Halloran 			eeh_edev_dbg(edev, "Added to existing PE (parent: PE#%x)\n",
3361ff8f36fSSam Bobroff 				     pe->parent->addr);
33727d4396eSSam Bobroff 		} else {
33827d4396eSSam Bobroff 			/* Mark the PE as type of PCI bus */
33927d4396eSSam Bobroff 			pe->type = EEH_PE_BUS;
34027d4396eSSam Bobroff 			edev->pe = pe;
34127d4396eSSam Bobroff 
34227d4396eSSam Bobroff 			/* Put the edev to PE */
34327d4396eSSam Bobroff 			list_add_tail(&edev->entry, &pe->edevs);
34427d4396eSSam Bobroff 			eeh_edev_dbg(edev, "Added to bus PE\n");
34527d4396eSSam Bobroff 		}
346317f06deSGavin Shan 		return 0;
347317f06deSGavin Shan 	}
348317f06deSGavin Shan 
349317f06deSGavin Shan 	/* Create a new EEH PE */
350c29fa27dSWei Yang 	if (edev->physfn)
35131595ae5SOliver O'Halloran 		pe = eeh_pe_alloc(hose, EEH_PE_VF);
352c29fa27dSWei Yang 	else
35331595ae5SOliver O'Halloran 		pe = eeh_pe_alloc(hose, EEH_PE_DEVICE);
354317f06deSGavin Shan 	if (!pe) {
355317f06deSGavin Shan 		pr_err("%s: out of memory!\n", __func__);
356317f06deSGavin Shan 		return -ENOMEM;
357317f06deSGavin Shan 	}
358269e5833SOliver O'Halloran 
359317f06deSGavin Shan 	pe->addr = edev->pe_config_addr;
360317f06deSGavin Shan 
361317f06deSGavin Shan 	/*
362317f06deSGavin Shan 	 * Put the new EEH PE into hierarchy tree. If the parent
363317f06deSGavin Shan 	 * can't be found, the newly created PE will be attached
364317f06deSGavin Shan 	 * to PHB directly. Otherwise, we have to associate the
365317f06deSGavin Shan 	 * PE with its parent.
366317f06deSGavin Shan 	 */
367a131bfc6SOliver O'Halloran 	if (!new_pe_parent) {
368a131bfc6SOliver O'Halloran 		new_pe_parent = eeh_phb_pe_get(hose);
369a131bfc6SOliver O'Halloran 		if (!new_pe_parent) {
370317f06deSGavin Shan 			pr_err("%s: No PHB PE is found (PHB Domain=%d)\n",
37131595ae5SOliver O'Halloran 				__func__, hose->global_number);
372317f06deSGavin Shan 			edev->pe = NULL;
373317f06deSGavin Shan 			kfree(pe);
374317f06deSGavin Shan 			return -EEXIST;
375317f06deSGavin Shan 		}
376317f06deSGavin Shan 	}
377a131bfc6SOliver O'Halloran 
378a131bfc6SOliver O'Halloran 	/* link new PE into the tree */
379a131bfc6SOliver O'Halloran 	pe->parent = new_pe_parent;
380a131bfc6SOliver O'Halloran 	list_add_tail(&pe->child, &new_pe_parent->child_list);
381317f06deSGavin Shan 
382317f06deSGavin Shan 	/*
383317f06deSGavin Shan 	 * Put the newly created PE into the child list and
384317f06deSGavin Shan 	 * link the EEH device accordingly.
385317f06deSGavin Shan 	 */
38680e65b00SSam Bobroff 	list_add_tail(&edev->entry, &pe->edevs);
387317f06deSGavin Shan 	edev->pe = pe;
388a131bfc6SOliver O'Halloran 	eeh_edev_dbg(edev, "Added to new (parent: PE#%x)\n",
389a131bfc6SOliver O'Halloran 		     new_pe_parent->addr);
390317f06deSGavin Shan 
391317f06deSGavin Shan 	return 0;
392317f06deSGavin Shan }
393317f06deSGavin Shan 
394317f06deSGavin Shan /**
395d923ab7aSOliver O'Halloran  * eeh_pe_tree_remove - Remove one EEH device from the associated PE
396317f06deSGavin Shan  * @edev: EEH device
397317f06deSGavin Shan  *
398317f06deSGavin Shan  * The PE hierarchy tree might be changed when doing PCI hotplug.
399317f06deSGavin Shan  * Also, the PCI devices or buses could be removed from the system
400317f06deSGavin Shan  * during EEH recovery. So we have to call the function remove the
401317f06deSGavin Shan  * corresponding PE accordingly if necessary.
402317f06deSGavin Shan  */
eeh_pe_tree_remove(struct eeh_dev * edev)403d923ab7aSOliver O'Halloran int eeh_pe_tree_remove(struct eeh_dev *edev)
404317f06deSGavin Shan {
405317f06deSGavin Shan 	struct eeh_pe *pe, *parent, *child;
406799abe28SOliver O'Halloran 	bool keep, recover;
407317f06deSGavin Shan 	int cnt;
408317f06deSGavin Shan 
4099a3eda26SSam Bobroff 	pe = eeh_dev_to_pe(edev);
4109a3eda26SSam Bobroff 	if (!pe) {
4111ff8f36fSSam Bobroff 		eeh_edev_dbg(edev, "No PE found for device.\n");
412317f06deSGavin Shan 		return -EEXIST;
413317f06deSGavin Shan 	}
414317f06deSGavin Shan 
415317f06deSGavin Shan 	/* Remove the EEH device */
416317f06deSGavin Shan 	edev->pe = NULL;
41780e65b00SSam Bobroff 	list_del(&edev->entry);
418317f06deSGavin Shan 
419317f06deSGavin Shan 	/*
420317f06deSGavin Shan 	 * Check if the parent PE includes any EEH devices.
421317f06deSGavin Shan 	 * If not, we should delete that. Also, we should
422317f06deSGavin Shan 	 * delete the parent PE if it doesn't have associated
423317f06deSGavin Shan 	 * child PEs and EEH devices.
424317f06deSGavin Shan 	 */
425317f06deSGavin Shan 	while (1) {
426317f06deSGavin Shan 		parent = pe->parent;
427799abe28SOliver O'Halloran 
428799abe28SOliver O'Halloran 		/* PHB PEs should never be removed */
429317f06deSGavin Shan 		if (pe->type & EEH_PE_PHB)
430317f06deSGavin Shan 			break;
431317f06deSGavin Shan 
432799abe28SOliver O'Halloran 		/*
433799abe28SOliver O'Halloran 		 * XXX: KEEP is set while resetting a PE. I don't think it's
434799abe28SOliver O'Halloran 		 * ever set without RECOVERING also being set. I could
435799abe28SOliver O'Halloran 		 * be wrong though so catch that with a WARN.
436799abe28SOliver O'Halloran 		 */
437799abe28SOliver O'Halloran 		keep = !!(pe->state & EEH_PE_KEEP);
438799abe28SOliver O'Halloran 		recover = !!(pe->state & EEH_PE_RECOVERING);
439799abe28SOliver O'Halloran 		WARN_ON(keep && !recover);
440799abe28SOliver O'Halloran 
441799abe28SOliver O'Halloran 		if (!keep && !recover) {
442317f06deSGavin Shan 			if (list_empty(&pe->edevs) &&
443317f06deSGavin Shan 			    list_empty(&pe->child_list)) {
444317f06deSGavin Shan 				list_del(&pe->child);
445317f06deSGavin Shan 				kfree(pe);
446317f06deSGavin Shan 			} else {
447317f06deSGavin Shan 				break;
448317f06deSGavin Shan 			}
449317f06deSGavin Shan 		} else {
450799abe28SOliver O'Halloran 			/*
451799abe28SOliver O'Halloran 			 * Mark the PE as invalid. At the end of the recovery
452799abe28SOliver O'Halloran 			 * process any invalid PEs will be garbage collected.
453799abe28SOliver O'Halloran 			 *
454799abe28SOliver O'Halloran 			 * We need to delay the free()ing of them since we can
455799abe28SOliver O'Halloran 			 * remove edev's while traversing the PE tree which
456799abe28SOliver O'Halloran 			 * might trigger the removal of a PE and we can't
457799abe28SOliver O'Halloran 			 * deal with that (yet).
458799abe28SOliver O'Halloran 			 */
459317f06deSGavin Shan 			if (list_empty(&pe->edevs)) {
460317f06deSGavin Shan 				cnt = 0;
461317f06deSGavin Shan 				list_for_each_entry(child, &pe->child_list, child) {
462317f06deSGavin Shan 					if (!(child->type & EEH_PE_INVALID)) {
463317f06deSGavin Shan 						cnt++;
464317f06deSGavin Shan 						break;
465317f06deSGavin Shan 					}
466317f06deSGavin Shan 				}
467317f06deSGavin Shan 
468317f06deSGavin Shan 				if (!cnt)
469317f06deSGavin Shan 					pe->type |= EEH_PE_INVALID;
470317f06deSGavin Shan 				else
471317f06deSGavin Shan 					break;
472317f06deSGavin Shan 			}
473317f06deSGavin Shan 		}
474317f06deSGavin Shan 
475317f06deSGavin Shan 		pe = parent;
476317f06deSGavin Shan 	}
477317f06deSGavin Shan 
478317f06deSGavin Shan 	return 0;
479317f06deSGavin Shan }
480317f06deSGavin Shan 
481317f06deSGavin Shan /**
4825a71978eSGavin Shan  * eeh_pe_update_time_stamp - Update PE's frozen time stamp
4835a71978eSGavin Shan  * @pe: EEH PE
4845a71978eSGavin Shan  *
4855a71978eSGavin Shan  * We have time stamp for each PE to trace its time of getting
4865a71978eSGavin Shan  * frozen in last hour. The function should be called to update
4875a71978eSGavin Shan  * the time stamp on first error of the specific PE. On the other
4885a71978eSGavin Shan  * handle, we needn't account for errors happened in last hour.
4895a71978eSGavin Shan  */
eeh_pe_update_time_stamp(struct eeh_pe * pe)4905a71978eSGavin Shan void eeh_pe_update_time_stamp(struct eeh_pe *pe)
4915a71978eSGavin Shan {
492edfd17ffSArnd Bergmann 	time64_t tstamp;
4935a71978eSGavin Shan 
4945a71978eSGavin Shan 	if (!pe) return;
4955a71978eSGavin Shan 
4965a71978eSGavin Shan 	if (pe->freeze_count <= 0) {
4975a71978eSGavin Shan 		pe->freeze_count = 0;
498edfd17ffSArnd Bergmann 		pe->tstamp = ktime_get_seconds();
4995a71978eSGavin Shan 	} else {
500edfd17ffSArnd Bergmann 		tstamp = ktime_get_seconds();
501edfd17ffSArnd Bergmann 		if (tstamp - pe->tstamp > 3600) {
5025a71978eSGavin Shan 			pe->tstamp = tstamp;
5035a71978eSGavin Shan 			pe->freeze_count = 0;
5045a71978eSGavin Shan 		}
5055a71978eSGavin Shan 	}
5065a71978eSGavin Shan }
5075a71978eSGavin Shan 
5085a71978eSGavin Shan /**
509317f06deSGavin Shan  * eeh_pe_state_mark - Mark specified state for PE and its associated device
510317f06deSGavin Shan  * @pe: EEH PE
511317f06deSGavin Shan  *
512317f06deSGavin Shan  * EEH error affects the current PE and its child PEs. The function
513317f06deSGavin Shan  * is used to mark appropriate state for the affected PEs and the
514317f06deSGavin Shan  * associated devices.
515317f06deSGavin Shan  */
eeh_pe_state_mark(struct eeh_pe * root,int state)516e762bb89SSam Bobroff void eeh_pe_state_mark(struct eeh_pe *root, int state)
517317f06deSGavin Shan {
518e762bb89SSam Bobroff 	struct eeh_pe *pe;
519e762bb89SSam Bobroff 
520e762bb89SSam Bobroff 	eeh_for_each_pe(root, pe)
521e762bb89SSam Bobroff 		if (!(pe->state & EEH_PE_REMOVED))
522e762bb89SSam Bobroff 			pe->state |= state;
523317f06deSGavin Shan }
524e0056b0aSGavin Shan EXPORT_SYMBOL_GPL(eeh_pe_state_mark);
525317f06deSGavin Shan 
526e762bb89SSam Bobroff /**
527e762bb89SSam Bobroff  * eeh_pe_mark_isolated
528e762bb89SSam Bobroff  * @pe: EEH PE
529e762bb89SSam Bobroff  *
530e762bb89SSam Bobroff  * Record that a PE has been isolated by marking the PE and it's children as
531e762bb89SSam Bobroff  * EEH_PE_ISOLATED (and EEH_PE_CFG_BLOCKED, if required) and their PCI devices
532e762bb89SSam Bobroff  * as pci_channel_io_frozen.
533e762bb89SSam Bobroff  */
eeh_pe_mark_isolated(struct eeh_pe * root)534e762bb89SSam Bobroff void eeh_pe_mark_isolated(struct eeh_pe *root)
535e762bb89SSam Bobroff {
536e762bb89SSam Bobroff 	struct eeh_pe *pe;
537e762bb89SSam Bobroff 	struct eeh_dev *edev;
538e762bb89SSam Bobroff 	struct pci_dev *pdev;
539e762bb89SSam Bobroff 
540e762bb89SSam Bobroff 	eeh_pe_state_mark(root, EEH_PE_ISOLATED);
541e762bb89SSam Bobroff 	eeh_for_each_pe(root, pe) {
542e762bb89SSam Bobroff 		list_for_each_entry(edev, &pe->edevs, entry) {
543e762bb89SSam Bobroff 			pdev = eeh_dev_to_pci_dev(edev);
544e762bb89SSam Bobroff 			if (pdev)
545e762bb89SSam Bobroff 				pdev->error_state = pci_channel_io_frozen;
546e762bb89SSam Bobroff 		}
547e762bb89SSam Bobroff 		/* Block PCI config access if required */
548e762bb89SSam Bobroff 		if (pe->state & EEH_PE_CFG_RESTRICTED)
549e762bb89SSam Bobroff 			pe->state |= EEH_PE_CFG_BLOCKED;
550e762bb89SSam Bobroff 	}
551e762bb89SSam Bobroff }
552e762bb89SSam Bobroff EXPORT_SYMBOL_GPL(eeh_pe_mark_isolated);
553e762bb89SSam Bobroff 
__eeh_pe_dev_mode_mark(struct eeh_dev * edev,void * flag)554cef50c67SSam Bobroff static void __eeh_pe_dev_mode_mark(struct eeh_dev *edev, void *flag)
555d2b0f6f7SGavin Shan {
556d2b0f6f7SGavin Shan 	int mode = *((int *)flag);
557d2b0f6f7SGavin Shan 
558d2b0f6f7SGavin Shan 	edev->mode |= mode;
559d2b0f6f7SGavin Shan }
560d2b0f6f7SGavin Shan 
561d2b0f6f7SGavin Shan /**
562d2b0f6f7SGavin Shan  * eeh_pe_dev_state_mark - Mark state for all device under the PE
563d2b0f6f7SGavin Shan  * @pe: EEH PE
564d2b0f6f7SGavin Shan  *
565d2b0f6f7SGavin Shan  * Mark specific state for all child devices of the PE.
566d2b0f6f7SGavin Shan  */
eeh_pe_dev_mode_mark(struct eeh_pe * pe,int mode)567d2b0f6f7SGavin Shan void eeh_pe_dev_mode_mark(struct eeh_pe *pe, int mode)
568d2b0f6f7SGavin Shan {
569d2b0f6f7SGavin Shan 	eeh_pe_dev_traverse(pe, __eeh_pe_dev_mode_mark, &mode);
570d2b0f6f7SGavin Shan }
571d2b0f6f7SGavin Shan 
572317f06deSGavin Shan /**
5739ed5ca66SSam Bobroff  * eeh_pe_state_clear - Clear state for the PE
574317f06deSGavin Shan  * @data: EEH PE
5759ed5ca66SSam Bobroff  * @state: state
5769ed5ca66SSam Bobroff  * @include_passed: include passed-through devices?
577317f06deSGavin Shan  *
578317f06deSGavin Shan  * The function is used to clear the indicated state from the
579317f06deSGavin Shan  * given PE. Besides, we also clear the check count of the PE
580317f06deSGavin Shan  * as well.
581317f06deSGavin Shan  */
eeh_pe_state_clear(struct eeh_pe * root,int state,bool include_passed)5829ed5ca66SSam Bobroff void eeh_pe_state_clear(struct eeh_pe *root, int state, bool include_passed)
583317f06deSGavin Shan {
5849ed5ca66SSam Bobroff 	struct eeh_pe *pe;
58522fca179SGavin Shan 	struct eeh_dev *edev, *tmp;
58622fca179SGavin Shan 	struct pci_dev *pdev;
587317f06deSGavin Shan 
5889ed5ca66SSam Bobroff 	eeh_for_each_pe(root, pe) {
589d2b0f6f7SGavin Shan 		/* Keep the state of permanently removed PE intact */
590432227e9SGavin Shan 		if (pe->state & EEH_PE_REMOVED)
5919ed5ca66SSam Bobroff 			continue;
5929ed5ca66SSam Bobroff 
5939ed5ca66SSam Bobroff 		if (!include_passed && eeh_pe_passed(pe))
5949ed5ca66SSam Bobroff 			continue;
595d2b0f6f7SGavin Shan 
596317f06deSGavin Shan 		pe->state &= ~state;
597d2b0f6f7SGavin Shan 
59822fca179SGavin Shan 		/*
59922fca179SGavin Shan 		 * Special treatment on clearing isolated state. Clear
60022fca179SGavin Shan 		 * check count since last isolation and put all affected
60122fca179SGavin Shan 		 * devices to normal state.
60222fca179SGavin Shan 		 */
60322fca179SGavin Shan 		if (!(state & EEH_PE_ISOLATED))
6049ed5ca66SSam Bobroff 			continue;
60522fca179SGavin Shan 
606317f06deSGavin Shan 		pe->check_count = 0;
60722fca179SGavin Shan 		eeh_pe_for_each_dev(pe, edev, tmp) {
60822fca179SGavin Shan 			pdev = eeh_dev_to_pci_dev(edev);
60922fca179SGavin Shan 			if (!pdev)
61022fca179SGavin Shan 				continue;
61122fca179SGavin Shan 
61222fca179SGavin Shan 			pdev->error_state = pci_channel_io_normal;
61322fca179SGavin Shan 		}
614317f06deSGavin Shan 
615b6541db1SGavin Shan 		/* Unblock PCI config access if required */
616b6541db1SGavin Shan 		if (pe->state & EEH_PE_CFG_RESTRICTED)
617b6541db1SGavin Shan 			pe->state &= ~EEH_PE_CFG_BLOCKED;
618317f06deSGavin Shan 	}
619317f06deSGavin Shan }
620317f06deSGavin Shan 
621652defedSGavin Shan /*
622652defedSGavin Shan  * Some PCI bridges (e.g. PLX bridges) have primary/secondary
623652defedSGavin Shan  * buses assigned explicitly by firmware, and we probably have
624652defedSGavin Shan  * lost that after reset. So we have to delay the check until
625652defedSGavin Shan  * the PCI-CFG registers have been restored for the parent
626652defedSGavin Shan  * bridge.
627317f06deSGavin Shan  *
628652defedSGavin Shan  * Don't use normal PCI-CFG accessors, which probably has been
629652defedSGavin Shan  * blocked on normal path during the stage. So we need utilize
630652defedSGavin Shan  * eeh operations, which is always permitted.
631317f06deSGavin Shan  */
eeh_bridge_check_link(struct eeh_dev * edev)6320bd78587SGavin Shan static void eeh_bridge_check_link(struct eeh_dev *edev)
633652defedSGavin Shan {
634652defedSGavin Shan 	int cap;
635652defedSGavin Shan 	uint32_t val;
636652defedSGavin Shan 	int timeout = 0;
637652defedSGavin Shan 
638652defedSGavin Shan 	/*
639652defedSGavin Shan 	 * We only check root port and downstream ports of
640652defedSGavin Shan 	 * PCIe switches
641652defedSGavin Shan 	 */
6424b83bd45SGavin Shan 	if (!(edev->mode & (EEH_DEV_ROOT_PORT | EEH_DEV_DS_PORT)))
643652defedSGavin Shan 		return;
644652defedSGavin Shan 
6451ff8f36fSSam Bobroff 	eeh_edev_dbg(edev, "Checking PCIe link...\n");
646652defedSGavin Shan 
647652defedSGavin Shan 	/* Check slot status */
6484b83bd45SGavin Shan 	cap = edev->pcie_cap;
64917d2a487SOliver O'Halloran 	eeh_ops->read_config(edev, cap + PCI_EXP_SLTSTA, 2, &val);
650652defedSGavin Shan 	if (!(val & PCI_EXP_SLTSTA_PDS)) {
6511ff8f36fSSam Bobroff 		eeh_edev_dbg(edev, "No card in the slot (0x%04x) !\n", val);
652652defedSGavin Shan 		return;
653652defedSGavin Shan 	}
654652defedSGavin Shan 
655652defedSGavin Shan 	/* Check power status if we have the capability */
65617d2a487SOliver O'Halloran 	eeh_ops->read_config(edev, cap + PCI_EXP_SLTCAP, 2, &val);
657652defedSGavin Shan 	if (val & PCI_EXP_SLTCAP_PCP) {
65817d2a487SOliver O'Halloran 		eeh_ops->read_config(edev, cap + PCI_EXP_SLTCTL, 2, &val);
659652defedSGavin Shan 		if (val & PCI_EXP_SLTCTL_PCC) {
6601ff8f36fSSam Bobroff 			eeh_edev_dbg(edev, "In power-off state, power it on ...\n");
661652defedSGavin Shan 			val &= ~(PCI_EXP_SLTCTL_PCC | PCI_EXP_SLTCTL_PIC);
662652defedSGavin Shan 			val |= (0x0100 & PCI_EXP_SLTCTL_PIC);
66317d2a487SOliver O'Halloran 			eeh_ops->write_config(edev, cap + PCI_EXP_SLTCTL, 2, val);
664652defedSGavin Shan 			msleep(2 * 1000);
665652defedSGavin Shan 		}
666652defedSGavin Shan 	}
667652defedSGavin Shan 
668652defedSGavin Shan 	/* Enable link */
66917d2a487SOliver O'Halloran 	eeh_ops->read_config(edev, cap + PCI_EXP_LNKCTL, 2, &val);
670652defedSGavin Shan 	val &= ~PCI_EXP_LNKCTL_LD;
67117d2a487SOliver O'Halloran 	eeh_ops->write_config(edev, cap + PCI_EXP_LNKCTL, 2, val);
672652defedSGavin Shan 
673652defedSGavin Shan 	/* Check link */
674*1541a213SMaciej W. Rozycki 	if (!edev->pdev->link_active_reporting) {
675*1541a213SMaciej W. Rozycki 		eeh_edev_dbg(edev, "No link reporting capability\n");
676652defedSGavin Shan 		msleep(1000);
677652defedSGavin Shan 		return;
678652defedSGavin Shan 	}
679652defedSGavin Shan 
680652defedSGavin Shan 	/* Wait the link is up until timeout (5s) */
681652defedSGavin Shan 	timeout = 0;
682652defedSGavin Shan 	while (timeout < 5000) {
683652defedSGavin Shan 		msleep(20);
684652defedSGavin Shan 		timeout += 20;
685652defedSGavin Shan 
68617d2a487SOliver O'Halloran 		eeh_ops->read_config(edev, cap + PCI_EXP_LNKSTA, 2, &val);
687652defedSGavin Shan 		if (val & PCI_EXP_LNKSTA_DLLLA)
688652defedSGavin Shan 			break;
689652defedSGavin Shan 	}
690652defedSGavin Shan 
691652defedSGavin Shan 	if (val & PCI_EXP_LNKSTA_DLLLA)
6921ff8f36fSSam Bobroff 		eeh_edev_dbg(edev, "Link up (%s)\n",
693652defedSGavin Shan 			 (val & PCI_EXP_LNKSTA_CLS_2_5GB) ? "2.5GB" : "5GB");
694652defedSGavin Shan 	else
6951ff8f36fSSam Bobroff 		eeh_edev_dbg(edev, "Link not ready (0x%04x)\n", val);
696652defedSGavin Shan }
697652defedSGavin Shan 
698652defedSGavin Shan #define BYTE_SWAP(OFF)	(8*((OFF)/4)+3-(OFF))
699652defedSGavin Shan #define SAVED_BYTE(OFF)	(((u8 *)(edev->config_space))[BYTE_SWAP(OFF)])
700652defedSGavin Shan 
eeh_restore_bridge_bars(struct eeh_dev * edev)7010bd78587SGavin Shan static void eeh_restore_bridge_bars(struct eeh_dev *edev)
702652defedSGavin Shan {
703652defedSGavin Shan 	int i;
704652defedSGavin Shan 
705652defedSGavin Shan 	/*
706652defedSGavin Shan 	 * Device BARs: 0x10 - 0x18
707652defedSGavin Shan 	 * Bus numbers and windows: 0x18 - 0x30
708652defedSGavin Shan 	 */
709652defedSGavin Shan 	for (i = 4; i < 13; i++)
71017d2a487SOliver O'Halloran 		eeh_ops->write_config(edev, i*4, 4, edev->config_space[i]);
711652defedSGavin Shan 	/* Rom: 0x38 */
71217d2a487SOliver O'Halloran 	eeh_ops->write_config(edev, 14*4, 4, edev->config_space[14]);
713652defedSGavin Shan 
714652defedSGavin Shan 	/* Cache line & Latency timer: 0xC 0xD */
71517d2a487SOliver O'Halloran 	eeh_ops->write_config(edev, PCI_CACHE_LINE_SIZE, 1,
716652defedSGavin Shan                 SAVED_BYTE(PCI_CACHE_LINE_SIZE));
71717d2a487SOliver O'Halloran 	eeh_ops->write_config(edev, PCI_LATENCY_TIMER, 1,
718652defedSGavin Shan 		SAVED_BYTE(PCI_LATENCY_TIMER));
719652defedSGavin Shan 	/* Max latency, min grant, interrupt ping and line: 0x3C */
72017d2a487SOliver O'Halloran 	eeh_ops->write_config(edev, 15*4, 4, edev->config_space[15]);
721652defedSGavin Shan 
722652defedSGavin Shan 	/* PCI Command: 0x4 */
72317d2a487SOliver O'Halloran 	eeh_ops->write_config(edev, PCI_COMMAND, 4, edev->config_space[1] |
72413a83eacSMichael Neuling 			      PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
725652defedSGavin Shan 
726652defedSGavin Shan 	/* Check the PCIe link is ready */
7270bd78587SGavin Shan 	eeh_bridge_check_link(edev);
728652defedSGavin Shan }
729652defedSGavin Shan 
eeh_restore_device_bars(struct eeh_dev * edev)7300bd78587SGavin Shan static void eeh_restore_device_bars(struct eeh_dev *edev)
731317f06deSGavin Shan {
732317f06deSGavin Shan 	int i;
733317f06deSGavin Shan 	u32 cmd;
734317f06deSGavin Shan 
735317f06deSGavin Shan 	for (i = 4; i < 10; i++)
73617d2a487SOliver O'Halloran 		eeh_ops->write_config(edev, i*4, 4, edev->config_space[i]);
737317f06deSGavin Shan 	/* 12 == Expansion ROM Address */
73817d2a487SOliver O'Halloran 	eeh_ops->write_config(edev, 12*4, 4, edev->config_space[12]);
739317f06deSGavin Shan 
74017d2a487SOliver O'Halloran 	eeh_ops->write_config(edev, PCI_CACHE_LINE_SIZE, 1,
741317f06deSGavin Shan 		SAVED_BYTE(PCI_CACHE_LINE_SIZE));
74217d2a487SOliver O'Halloran 	eeh_ops->write_config(edev, PCI_LATENCY_TIMER, 1,
743317f06deSGavin Shan 		SAVED_BYTE(PCI_LATENCY_TIMER));
744317f06deSGavin Shan 
745317f06deSGavin Shan 	/* max latency, min grant, interrupt pin and line */
74617d2a487SOliver O'Halloran 	eeh_ops->write_config(edev, 15*4, 4, edev->config_space[15]);
747317f06deSGavin Shan 
748317f06deSGavin Shan 	/*
749317f06deSGavin Shan 	 * Restore PERR & SERR bits, some devices require it,
750317f06deSGavin Shan 	 * don't touch the other command bits
751317f06deSGavin Shan 	 */
75217d2a487SOliver O'Halloran 	eeh_ops->read_config(edev, PCI_COMMAND, 4, &cmd);
753317f06deSGavin Shan 	if (edev->config_space[1] & PCI_COMMAND_PARITY)
754317f06deSGavin Shan 		cmd |= PCI_COMMAND_PARITY;
755317f06deSGavin Shan 	else
756317f06deSGavin Shan 		cmd &= ~PCI_COMMAND_PARITY;
757317f06deSGavin Shan 	if (edev->config_space[1] & PCI_COMMAND_SERR)
758317f06deSGavin Shan 		cmd |= PCI_COMMAND_SERR;
759317f06deSGavin Shan 	else
760317f06deSGavin Shan 		cmd &= ~PCI_COMMAND_SERR;
76117d2a487SOliver O'Halloran 	eeh_ops->write_config(edev, PCI_COMMAND, 4, cmd);
762652defedSGavin Shan }
763652defedSGavin Shan 
764652defedSGavin Shan /**
765652defedSGavin Shan  * eeh_restore_one_device_bars - Restore the Base Address Registers for one device
766652defedSGavin Shan  * @data: EEH device
767652defedSGavin Shan  * @flag: Unused
768652defedSGavin Shan  *
769652defedSGavin Shan  * Loads the PCI configuration space base address registers,
770652defedSGavin Shan  * the expansion ROM base address, the latency timer, and etc.
771652defedSGavin Shan  * from the saved values in the device node.
772652defedSGavin Shan  */
eeh_restore_one_device_bars(struct eeh_dev * edev,void * flag)773cef50c67SSam Bobroff static void eeh_restore_one_device_bars(struct eeh_dev *edev, void *flag)
774652defedSGavin Shan {
775f5c57710SGavin Shan 	/* Do special restore for bridges */
7764b83bd45SGavin Shan 	if (edev->mode & EEH_DEV_BRIDGE)
7770bd78587SGavin Shan 		eeh_restore_bridge_bars(edev);
778652defedSGavin Shan 	else
7790bd78587SGavin Shan 		eeh_restore_device_bars(edev);
780317f06deSGavin Shan 
7810c2c7652SOliver O'Halloran 	if (eeh_ops->restore_config)
7820c2c7652SOliver O'Halloran 		eeh_ops->restore_config(edev);
783317f06deSGavin Shan }
784317f06deSGavin Shan 
785317f06deSGavin Shan /**
786317f06deSGavin Shan  * eeh_pe_restore_bars - Restore the PCI config space info
787317f06deSGavin Shan  * @pe: EEH PE
788317f06deSGavin Shan  *
789317f06deSGavin Shan  * This routine performs a recursive walk to the children
790317f06deSGavin Shan  * of this device as well.
791317f06deSGavin Shan  */
eeh_pe_restore_bars(struct eeh_pe * pe)792317f06deSGavin Shan void eeh_pe_restore_bars(struct eeh_pe *pe)
793317f06deSGavin Shan {
794317f06deSGavin Shan 	/*
795317f06deSGavin Shan 	 * We needn't take the EEH lock since eeh_pe_dev_traverse()
796317f06deSGavin Shan 	 * will take that.
797317f06deSGavin Shan 	 */
798317f06deSGavin Shan 	eeh_pe_dev_traverse(pe, eeh_restore_one_device_bars, NULL);
799317f06deSGavin Shan }
800317f06deSGavin Shan 
801317f06deSGavin Shan /**
802357b2f3dSGavin Shan  * eeh_pe_loc_get - Retrieve location code binding to the given PE
803357b2f3dSGavin Shan  * @pe: EEH PE
804357b2f3dSGavin Shan  *
805357b2f3dSGavin Shan  * Retrieve the location code of the given PE. If the primary PE bus
806357b2f3dSGavin Shan  * is root bus, we will grab location code from PHB device tree node
807357b2f3dSGavin Shan  * or root port. Otherwise, the upstream bridge's device tree node
808357b2f3dSGavin Shan  * of the primary PE bus will be checked for the location code.
809357b2f3dSGavin Shan  */
eeh_pe_loc_get(struct eeh_pe * pe)810357b2f3dSGavin Shan const char *eeh_pe_loc_get(struct eeh_pe *pe)
811357b2f3dSGavin Shan {
812357b2f3dSGavin Shan 	struct pci_bus *bus = eeh_pe_bus_get(pe);
8137e56f627SGavin Shan 	struct device_node *dn;
8149e5c6e5aSMike Qiu 	const char *loc = NULL;
815357b2f3dSGavin Shan 
8167e56f627SGavin Shan 	while (bus) {
8177e56f627SGavin Shan 		dn = pci_bus_to_OF_node(bus);
8187e56f627SGavin Shan 		if (!dn) {
8197e56f627SGavin Shan 			bus = bus->parent;
8207e56f627SGavin Shan 			continue;
821357b2f3dSGavin Shan 		}
822357b2f3dSGavin Shan 
8237e56f627SGavin Shan 		if (pci_is_root_bus(bus))
8247e56f627SGavin Shan 			loc = of_get_property(dn, "ibm,io-base-loc-code", NULL);
8257e56f627SGavin Shan 		else
8267e56f627SGavin Shan 			loc = of_get_property(dn, "ibm,slot-location-code",
8277e56f627SGavin Shan 					      NULL);
828357b2f3dSGavin Shan 
8297e56f627SGavin Shan 		if (loc)
8307e56f627SGavin Shan 			return loc;
8317e56f627SGavin Shan 
8327e56f627SGavin Shan 		bus = bus->parent;
8337e56f627SGavin Shan 	}
8347e56f627SGavin Shan 
8357e56f627SGavin Shan 	return "N/A";
836357b2f3dSGavin Shan }
837357b2f3dSGavin Shan 
838357b2f3dSGavin Shan /**
839317f06deSGavin Shan  * eeh_pe_bus_get - Retrieve PCI bus according to the given PE
840317f06deSGavin Shan  * @pe: EEH PE
841317f06deSGavin Shan  *
842317f06deSGavin Shan  * Retrieve the PCI bus according to the given PE. Basically,
843317f06deSGavin Shan  * there're 3 types of PEs: PHB/Bus/Device. For PHB PE, the
844317f06deSGavin Shan  * primary PCI bus will be retrieved. The parent bus will be
845317f06deSGavin Shan  * returned for BUS PE. However, we don't have associated PCI
846317f06deSGavin Shan  * bus for DEVICE PE.
847317f06deSGavin Shan  */
eeh_pe_bus_get(struct eeh_pe * pe)848317f06deSGavin Shan struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe)
849317f06deSGavin Shan {
850317f06deSGavin Shan 	struct eeh_dev *edev;
851317f06deSGavin Shan 	struct pci_dev *pdev;
852317f06deSGavin Shan 
8534eb0799fSGavin Shan 	if (pe->type & EEH_PE_PHB)
8544eb0799fSGavin Shan 		return pe->phb->bus;
8558cdb2833SGavin Shan 
8564eb0799fSGavin Shan 	/* The primary bus might be cached during probe time */
8574eb0799fSGavin Shan 	if (pe->state & EEH_PE_PRI_BUS)
8584eb0799fSGavin Shan 		return pe->bus;
8594eb0799fSGavin Shan 
8604eb0799fSGavin Shan 	/* Retrieve the parent PCI bus of first (top) PCI device */
86180e65b00SSam Bobroff 	edev = list_first_entry_or_null(&pe->edevs, struct eeh_dev, entry);
862317f06deSGavin Shan 	pdev = eeh_dev_to_pci_dev(edev);
863317f06deSGavin Shan 	if (pdev)
8644eb0799fSGavin Shan 		return pdev->bus;
865317f06deSGavin Shan 
8664eb0799fSGavin Shan 	return NULL;
867317f06deSGavin Shan }
868