aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/eeh_pe.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/eeh_pe.c')
-rw-r--r--arch/powerpc/kernel/eeh_pe.c58
1 files changed, 25 insertions, 33 deletions
diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c
index 016588a6f5ed..f9450537e335 100644
--- a/arch/powerpc/kernel/eeh_pe.c
+++ b/arch/powerpc/kernel/eeh_pe.c
@@ -149,8 +149,8 @@ static struct eeh_pe *eeh_pe_next(struct eeh_pe *pe,
149 * callback returns something other than NULL, or no more PEs 149 * callback returns something other than NULL, or no more PEs
150 * to be traversed. 150 * to be traversed.
151 */ 151 */
152static void *eeh_pe_traverse(struct eeh_pe *root, 152void *eeh_pe_traverse(struct eeh_pe *root,
153 eeh_traverse_func fn, void *flag) 153 eeh_traverse_func fn, void *flag)
154{ 154{
155 struct eeh_pe *pe; 155 struct eeh_pe *pe;
156 void *ret; 156 void *ret;
@@ -176,7 +176,7 @@ void *eeh_pe_dev_traverse(struct eeh_pe *root,
176 eeh_traverse_func fn, void *flag) 176 eeh_traverse_func fn, void *flag)
177{ 177{
178 struct eeh_pe *pe; 178 struct eeh_pe *pe;
179 struct eeh_dev *edev; 179 struct eeh_dev *edev, *tmp;
180 void *ret; 180 void *ret;
181 181
182 if (!root) { 182 if (!root) {
@@ -186,7 +186,7 @@ void *eeh_pe_dev_traverse(struct eeh_pe *root,
186 186
187 /* Traverse root PE */ 187 /* Traverse root PE */
188 for (pe = root; pe; pe = eeh_pe_next(pe, root)) { 188 for (pe = root; pe; pe = eeh_pe_next(pe, root)) {
189 eeh_pe_for_each_dev(pe, edev) { 189 eeh_pe_for_each_dev(pe, edev, tmp) {
190 ret = fn(edev, flag); 190 ret = fn(edev, flag);
191 if (ret) 191 if (ret)
192 return ret; 192 return ret;
@@ -333,7 +333,7 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
333 while (parent) { 333 while (parent) {
334 if (!(parent->type & EEH_PE_INVALID)) 334 if (!(parent->type & EEH_PE_INVALID))
335 break; 335 break;
336 parent->type &= ~EEH_PE_INVALID; 336 parent->type &= ~(EEH_PE_INVALID | EEH_PE_KEEP);
337 parent = parent->parent; 337 parent = parent->parent;
338 } 338 }
339 pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n", 339 pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n",
@@ -397,21 +397,20 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
397/** 397/**
398 * eeh_rmv_from_parent_pe - Remove one EEH device from the associated PE 398 * eeh_rmv_from_parent_pe - Remove one EEH device from the associated PE
399 * @edev: EEH device 399 * @edev: EEH device
400 * @purge_pe: remove PE or not
401 * 400 *
402 * The PE hierarchy tree might be changed when doing PCI hotplug. 401 * The PE hierarchy tree might be changed when doing PCI hotplug.
403 * Also, the PCI devices or buses could be removed from the system 402 * Also, the PCI devices or buses could be removed from the system
404 * during EEH recovery. So we have to call the function remove the 403 * during EEH recovery. So we have to call the function remove the
405 * corresponding PE accordingly if necessary. 404 * corresponding PE accordingly if necessary.
406 */ 405 */
407int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe) 406int eeh_rmv_from_parent_pe(struct eeh_dev *edev)
408{ 407{
409 struct eeh_pe *pe, *parent, *child; 408 struct eeh_pe *pe, *parent, *child;
410 int cnt; 409 int cnt;
411 410
412 if (!edev->pe) { 411 if (!edev->pe) {
413 pr_warning("%s: No PE found for EEH device %s\n", 412 pr_debug("%s: No PE found for EEH device %s\n",
414 __func__, edev->dn->full_name); 413 __func__, edev->dn->full_name);
415 return -EEXIST; 414 return -EEXIST;
416 } 415 }
417 416
@@ -431,7 +430,7 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe)
431 if (pe->type & EEH_PE_PHB) 430 if (pe->type & EEH_PE_PHB)
432 break; 431 break;
433 432
434 if (purge_pe) { 433 if (!(pe->state & EEH_PE_KEEP)) {
435 if (list_empty(&pe->edevs) && 434 if (list_empty(&pe->edevs) &&
436 list_empty(&pe->child_list)) { 435 list_empty(&pe->child_list)) {
437 list_del(&pe->child); 436 list_del(&pe->child);
@@ -502,7 +501,7 @@ static void *__eeh_pe_state_mark(void *data, void *flag)
502{ 501{
503 struct eeh_pe *pe = (struct eeh_pe *)data; 502 struct eeh_pe *pe = (struct eeh_pe *)data;
504 int state = *((int *)flag); 503 int state = *((int *)flag);
505 struct eeh_dev *tmp; 504 struct eeh_dev *edev, *tmp;
506 struct pci_dev *pdev; 505 struct pci_dev *pdev;
507 506
508 /* 507 /*
@@ -512,8 +511,8 @@ static void *__eeh_pe_state_mark(void *data, void *flag)
512 * the PCI device driver. 511 * the PCI device driver.
513 */ 512 */
514 pe->state |= state; 513 pe->state |= state;
515 eeh_pe_for_each_dev(pe, tmp) { 514 eeh_pe_for_each_dev(pe, edev, tmp) {
516 pdev = eeh_dev_to_pci_dev(tmp); 515 pdev = eeh_dev_to_pci_dev(edev);
517 if (pdev) 516 if (pdev)
518 pdev->error_state = pci_channel_io_frozen; 517 pdev->error_state = pci_channel_io_frozen;
519 } 518 }
@@ -579,7 +578,7 @@ void eeh_pe_state_clear(struct eeh_pe *pe, int state)
579 * blocked on normal path during the stage. So we need utilize 578 * blocked on normal path during the stage. So we need utilize
580 * eeh operations, which is always permitted. 579 * eeh operations, which is always permitted.
581 */ 580 */
582static void eeh_bridge_check_link(struct pci_dev *pdev, 581static void eeh_bridge_check_link(struct eeh_dev *edev,
583 struct device_node *dn) 582 struct device_node *dn)
584{ 583{
585 int cap; 584 int cap;
@@ -590,16 +589,17 @@ static void eeh_bridge_check_link(struct pci_dev *pdev,
590 * We only check root port and downstream ports of 589 * We only check root port and downstream ports of
591 * PCIe switches 590 * PCIe switches
592 */ 591 */
593 if (!pci_is_pcie(pdev) || 592 if (!(edev->mode & (EEH_DEV_ROOT_PORT | EEH_DEV_DS_PORT)))
594 (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT &&
595 pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM))
596 return; 593 return;
597 594
598 pr_debug("%s: Check PCIe link for %s ...\n", 595 pr_debug("%s: Check PCIe link for %04x:%02x:%02x.%01x ...\n",
599 __func__, pci_name(pdev)); 596 __func__, edev->phb->global_number,
597 edev->config_addr >> 8,
598 PCI_SLOT(edev->config_addr & 0xFF),
599 PCI_FUNC(edev->config_addr & 0xFF));
600 600
601 /* Check slot status */ 601 /* Check slot status */
602 cap = pdev->pcie_cap; 602 cap = edev->pcie_cap;
603 eeh_ops->read_config(dn, cap + PCI_EXP_SLTSTA, 2, &val); 603 eeh_ops->read_config(dn, cap + PCI_EXP_SLTSTA, 2, &val);
604 if (!(val & PCI_EXP_SLTSTA_PDS)) { 604 if (!(val & PCI_EXP_SLTSTA_PDS)) {
605 pr_debug(" No card in the slot (0x%04x) !\n", val); 605 pr_debug(" No card in the slot (0x%04x) !\n", val);
@@ -653,8 +653,7 @@ static void eeh_bridge_check_link(struct pci_dev *pdev,
653#define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) 653#define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF))
654#define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)]) 654#define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)])
655 655
656static void eeh_restore_bridge_bars(struct pci_dev *pdev, 656static void eeh_restore_bridge_bars(struct eeh_dev *edev,
657 struct eeh_dev *edev,
658 struct device_node *dn) 657 struct device_node *dn)
659{ 658{
660 int i; 659 int i;
@@ -680,7 +679,7 @@ static void eeh_restore_bridge_bars(struct pci_dev *pdev,
680 eeh_ops->write_config(dn, PCI_COMMAND, 4, edev->config_space[1]); 679 eeh_ops->write_config(dn, PCI_COMMAND, 4, edev->config_space[1]);
681 680
682 /* Check the PCIe link is ready */ 681 /* Check the PCIe link is ready */
683 eeh_bridge_check_link(pdev, dn); 682 eeh_bridge_check_link(edev, dn);
684} 683}
685 684
686static void eeh_restore_device_bars(struct eeh_dev *edev, 685static void eeh_restore_device_bars(struct eeh_dev *edev,
@@ -729,19 +728,12 @@ static void eeh_restore_device_bars(struct eeh_dev *edev,
729 */ 728 */
730static void *eeh_restore_one_device_bars(void *data, void *flag) 729static void *eeh_restore_one_device_bars(void *data, void *flag)
731{ 730{
732 struct pci_dev *pdev = NULL;
733 struct eeh_dev *edev = (struct eeh_dev *)data; 731 struct eeh_dev *edev = (struct eeh_dev *)data;
734 struct device_node *dn = eeh_dev_to_of_node(edev); 732 struct device_node *dn = eeh_dev_to_of_node(edev);
735 733
736 /* Trace the PCI bridge */ 734 /* Do special restore for bridges */
737 if (eeh_probe_mode_dev()) { 735 if (edev->mode & EEH_DEV_BRIDGE)
738 pdev = eeh_dev_to_pci_dev(edev); 736 eeh_restore_bridge_bars(edev, dn);
739 if (pdev->hdr_type != PCI_HEADER_TYPE_BRIDGE)
740 pdev = NULL;
741 }
742
743 if (pdev)
744 eeh_restore_bridge_bars(pdev, edev, dn);
745 else 737 else
746 eeh_restore_device_bars(edev, dn); 738 eeh_restore_device_bars(edev, dn);
747 739