aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2014-05-04 19:29:03 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-06-11 03:04:16 -0400
commit1ad7a72c5e57bc6a7a3190c580df14dc3642febf (patch)
tree37c000d1386347ccfd8cd24bdc959a99d32dcb7a /arch/powerpc/kernel
parent2c66599206938412d1781171953d565652ca3b93 (diff)
powerpc/eeh: Report frozen parent PE prior to child PE
When we have the corner case of frozen parent and child PE at the same time, we have to handle the frozen parent PE prior to the child. Without clearning the frozen state on parent PE, the child PE can't be recovered successfully. The patch searches the EEH PE hierarchy tree and returns the toppest frozen PE to be handled. It ensures the frozen parent PE will be handled prior to child PE. Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/eeh.c27
1 files changed, 24 insertions, 3 deletions
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index 7051ea3101b9..c25064b7d667 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -358,10 +358,11 @@ out:
358int eeh_dev_check_failure(struct eeh_dev *edev) 358int eeh_dev_check_failure(struct eeh_dev *edev)
359{ 359{
360 int ret; 360 int ret;
361 int active_flags = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE);
361 unsigned long flags; 362 unsigned long flags;
362 struct device_node *dn; 363 struct device_node *dn;
363 struct pci_dev *dev; 364 struct pci_dev *dev;
364 struct eeh_pe *pe; 365 struct eeh_pe *pe, *parent_pe;
365 int rc = 0; 366 int rc = 0;
366 const char *location; 367 const char *location;
367 368
@@ -439,14 +440,34 @@ int eeh_dev_check_failure(struct eeh_dev *edev)
439 */ 440 */
440 if ((ret < 0) || 441 if ((ret < 0) ||
441 (ret == EEH_STATE_NOT_SUPPORT) || 442 (ret == EEH_STATE_NOT_SUPPORT) ||
442 (ret & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) == 443 ((ret & active_flags) == active_flags)) {
443 (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) {
444 eeh_stats.false_positives++; 444 eeh_stats.false_positives++;
445 pe->false_positives++; 445 pe->false_positives++;
446 rc = 0; 446 rc = 0;
447 goto dn_unlock; 447 goto dn_unlock;
448 } 448 }
449 449
450 /*
451 * It should be corner case that the parent PE has been
452 * put into frozen state as well. We should take care
453 * that at first.
454 */
455 parent_pe = pe->parent;
456 while (parent_pe) {
457 /* Hit the ceiling ? */
458 if (parent_pe->type & EEH_PE_PHB)
459 break;
460
461 /* Frozen parent PE ? */
462 ret = eeh_ops->get_state(parent_pe, NULL);
463 if (ret > 0 &&
464 (ret & active_flags) != active_flags)
465 pe = parent_pe;
466
467 /* Next parent level */
468 parent_pe = parent_pe->parent;
469 }
470
450 eeh_stats.slot_resets++; 471 eeh_stats.slot_resets++;
451 472
452 /* Avoid repeated reports of this failure, including problems 473 /* Avoid repeated reports of this failure, including problems