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 /**
2739434af1SGhanshyam Agrawal * eeh_set_pe_aux_size - Set PE auxiliary data size
2839434af1SGhanshyam Agrawal * @size: PE auxiliary data size in bytes
29bb593c00SGavin Shan *
3039434af1SGhanshyam Agrawal * Set PE auxiliary 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 *
5300ddbbb89SBjorn Helgaas * Record that a PE has been isolated by marking the PE and its 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 */
6741541a213SMaciej W. Rozycki if (!edev->pdev->link_active_reporting) {
6751541a213SMaciej 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;
852*a1216e62SGanesh Goudar struct pci_bus *bus = NULL;
853317f06deSGavin Shan
8544eb0799fSGavin Shan if (pe->type & EEH_PE_PHB)
8554eb0799fSGavin Shan return pe->phb->bus;
8568cdb2833SGavin Shan
8574eb0799fSGavin Shan /* The primary bus might be cached during probe time */
8584eb0799fSGavin Shan if (pe->state & EEH_PE_PRI_BUS)
8594eb0799fSGavin Shan return pe->bus;
8604eb0799fSGavin Shan
8614eb0799fSGavin Shan /* Retrieve the parent PCI bus of first (top) PCI device */
86280e65b00SSam Bobroff edev = list_first_entry_or_null(&pe->edevs, struct eeh_dev, entry);
863*a1216e62SGanesh Goudar pci_lock_rescan_remove();
864317f06deSGavin Shan pdev = eeh_dev_to_pci_dev(edev);
865317f06deSGavin Shan if (pdev)
866*a1216e62SGanesh Goudar bus = pdev->bus;
867*a1216e62SGanesh Goudar pci_unlock_rescan_remove();
868317f06deSGavin Shan
869*a1216e62SGanesh Goudar return bus;
870317f06deSGavin Shan }
871