aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorGavin Shan <shangw@linux.vnet.ibm.com>2012-09-11 15:16:16 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-09-18 01:02:49 -0400
commit5efc3ad7325d81b5a8e09bc14d5e21ce7272d934 (patch)
treeff0a1f68d7aeabddd8c5e9cd2b8070ccbd3749da /arch/powerpc
parentddadb6b8e88979a00ac44fba9c92896eec113bd1 (diff)
powerpc/eeh: Introduce EEH_PE_INVALID type PE
When EEH error happens on the PE whose PCI devices don't have attached drivers. In function eeh_handle_event(), the default value PCI_ERS_RESULT_NONE will be returned after iterating all drivers of those PCI devices belonging to the PE. Actually, we don't have installed drivers for the PCI devices. Under the circumstance, we will remove the corresponding PCI bus of the PE, including the associated EEH devices and PE instance. However, we still need the information stored in the PE instance to do PE reset after that. So it's unsafe to free the PE instance. The patch introduces EEH_PE_INVALID type PE to address the issue. When the PCI bus and the corresponding attached EEH devices are removed, we will mark the PE as EEH_PE_INVALID. At later point, the PE will be changed to EEH_PE_DEVICE or EEH_PE_BUS when the corresponding EEH devices are attached again. Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/include/asm/eeh.h7
-rw-r--r--arch/powerpc/platforms/pseries/eeh_pe.c50
2 files changed, 43 insertions, 14 deletions
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index 58c5ee61e70..afeb40086fb 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -45,9 +45,10 @@ struct device_node;
45 * in the corresponding PHB. Therefore, the root PEs should be created 45 * in the corresponding PHB. Therefore, the root PEs should be created
46 * against existing PHBs in on-to-one fashion. 46 * against existing PHBs in on-to-one fashion.
47 */ 47 */
48#define EEH_PE_PHB 1 /* PHB PE */ 48#define EEH_PE_INVALID (1 << 0) /* Invalid */
49#define EEH_PE_DEVICE 2 /* Device PE */ 49#define EEH_PE_PHB (1 << 1) /* PHB PE */
50#define EEH_PE_BUS 3 /* Bus PE */ 50#define EEH_PE_DEVICE (1 << 2) /* Device PE */
51#define EEH_PE_BUS (1 << 3) /* Bus PE */
51 52
52#define EEH_PE_ISOLATED (1 << 0) /* Isolated PE */ 53#define EEH_PE_ISOLATED (1 << 0) /* Isolated PE */
53#define EEH_PE_RECOVERING (1 << 1) /* Recovering PE */ 54#define EEH_PE_RECOVERING (1 << 1) /* Recovering PE */
diff --git a/arch/powerpc/platforms/pseries/eeh_pe.c b/arch/powerpc/platforms/pseries/eeh_pe.c
index 904123c7657..51fc56abb7a 100644
--- a/arch/powerpc/platforms/pseries/eeh_pe.c
+++ b/arch/powerpc/platforms/pseries/eeh_pe.c
@@ -107,7 +107,7 @@ static struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb)
107 * the PE for PHB has been determined when that 107 * the PE for PHB has been determined when that
108 * was created. 108 * was created.
109 */ 109 */
110 if (pe->type == EEH_PE_PHB && 110 if ((pe->type & EEH_PE_PHB) &&
111 pe->phb == phb) { 111 pe->phb == phb) {
112 eeh_unlock(); 112 eeh_unlock();
113 return pe; 113 return pe;
@@ -219,7 +219,7 @@ static void *__eeh_pe_get(void *data, void *flag)
219 struct eeh_dev *edev = (struct eeh_dev *)flag; 219 struct eeh_dev *edev = (struct eeh_dev *)flag;
220 220
221 /* Unexpected PHB PE */ 221 /* Unexpected PHB PE */
222 if (pe->type == EEH_PE_PHB) 222 if (pe->type & EEH_PE_PHB)
223 return NULL; 223 return NULL;
224 224
225 /* We prefer PE address */ 225 /* We prefer PE address */
@@ -314,7 +314,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
314 * components. 314 * components.
315 */ 315 */
316 pe = eeh_pe_get(edev); 316 pe = eeh_pe_get(edev);
317 if (pe) { 317 if (pe && !(pe->type & EEH_PE_INVALID)) {
318 if (!edev->pe_config_addr) { 318 if (!edev->pe_config_addr) {
319 pr_err("%s: PE with addr 0x%x already exists\n", 319 pr_err("%s: PE with addr 0x%x already exists\n",
320 __func__, edev->config_addr); 320 __func__, edev->config_addr);
@@ -331,6 +331,24 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
331 edev->dn->full_name, pe->addr); 331 edev->dn->full_name, pe->addr);
332 332
333 return 0; 333 return 0;
334 } else if (pe && (pe->type & EEH_PE_INVALID)) {
335 list_add_tail(&edev->list, &pe->edevs);
336 edev->pe = pe;
337 /*
338 * We're running to here because of PCI hotplug caused by
339 * EEH recovery. We need clear EEH_PE_INVALID until the top.
340 */
341 parent = pe;
342 while (parent) {
343 if (!(parent->type & EEH_PE_INVALID))
344 break;
345 parent->type &= ~EEH_PE_INVALID;
346 parent = parent->parent;
347 }
348 pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n",
349 edev->dn->full_name, pe->addr, pe->parent->addr);
350
351 return 0;
334 } 352 }
335 353
336 /* Create a new EEH PE */ 354 /* Create a new EEH PE */
@@ -385,7 +403,8 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
385 */ 403 */
386int eeh_rmv_from_parent_pe(struct eeh_dev *edev) 404int eeh_rmv_from_parent_pe(struct eeh_dev *edev)
387{ 405{
388 struct eeh_pe *pe, *parent; 406 struct eeh_pe *pe, *parent, *child;
407 int cnt;
389 408
390 if (!edev->pe) { 409 if (!edev->pe) {
391 pr_warning("%s: No PE found for EEH device %s\n", 410 pr_warning("%s: No PE found for EEH device %s\n",
@@ -406,13 +425,22 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev)
406 */ 425 */
407 while (1) { 426 while (1) {
408 parent = pe->parent; 427 parent = pe->parent;
409 if (pe->type == EEH_PE_PHB) 428 if (pe->type & EEH_PE_PHB)
410 break; 429 break;
411 430
412 if (list_empty(&pe->edevs) && 431 if (list_empty(&pe->edevs)) {
413 list_empty(&pe->child_list)) { 432 cnt = 0;
414 list_del(&pe->child); 433 list_for_each_entry(child, &pe->child_list, child) {
415 kfree(pe); 434 if (!(pe->type & EEH_PE_INVALID)) {
435 cnt++;
436 break;
437 }
438 }
439
440 if (!cnt)
441 pe->type |= EEH_PE_INVALID;
442 else
443 break;
416 } 444 }
417 445
418 pe = parent; 446 pe = parent;
@@ -578,9 +606,9 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe)
578 struct eeh_dev *edev; 606 struct eeh_dev *edev;
579 struct pci_dev *pdev; 607 struct pci_dev *pdev;
580 608
581 if (pe->type == EEH_PE_PHB) { 609 if (pe->type & EEH_PE_PHB) {
582 bus = pe->phb->bus; 610 bus = pe->phb->bus;
583 } else if (pe->type == EEH_PE_BUS) { 611 } else if (pe->type & EEH_PE_BUS) {
584 edev = list_first_entry(&pe->edevs, struct eeh_dev, list); 612 edev = list_first_entry(&pe->edevs, struct eeh_dev, list);
585 pdev = eeh_dev_to_pci_dev(edev); 613 pdev = eeh_dev_to_pci_dev(edev);
586 if (pdev) 614 if (pdev)