diff options
author | Gavin Shan <shangw@linux.vnet.ibm.com> | 2014-02-12 02:24:54 -0500 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2014-02-16 19:19:38 -0500 |
commit | 5b2e198e50f6ba57081586b853163ea1bb95f1a8 (patch) | |
tree | 6c9e5a60e96ac81a9ebe7157609b4c9970d389d6 /arch | |
parent | 24b659a13866b935eca72748ce725279bd3c4466 (diff) |
powerpc/powernv: Rework EEH reset
When doing reset in order to recover the affected PE, we issue
hot reset on PE primary bus if it's not root bus. Otherwise, we
issue hot or fundamental reset on root port or PHB accordingly.
For the later case, we didn't cover the situation where PE only
includes root port and it potentially causes kernel crash upon
EEH error to the PE.
The patch reworks the logic of EEH reset to improve the code
readability and also avoid the kernel crash.
Cc: stable@vger.kernel.org
Reported-by: Thadeu Lima de Souza Cascardo <cascardo@linux.vnet.ibm.com>
Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/platforms/powernv/eeh-ioda.c | 29 |
1 files changed, 4 insertions, 25 deletions
diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c index e1e71618b70c..fcb79cffdb66 100644 --- a/arch/powerpc/platforms/powernv/eeh-ioda.c +++ b/arch/powerpc/platforms/powernv/eeh-ioda.c | |||
@@ -489,8 +489,7 @@ static int ioda_eeh_bridge_reset(struct pci_controller *hose, | |||
489 | static int ioda_eeh_reset(struct eeh_pe *pe, int option) | 489 | static int ioda_eeh_reset(struct eeh_pe *pe, int option) |
490 | { | 490 | { |
491 | struct pci_controller *hose = pe->phb; | 491 | struct pci_controller *hose = pe->phb; |
492 | struct eeh_dev *edev; | 492 | struct pci_bus *bus; |
493 | struct pci_dev *dev; | ||
494 | int ret; | 493 | int ret; |
495 | 494 | ||
496 | /* | 495 | /* |
@@ -519,31 +518,11 @@ static int ioda_eeh_reset(struct eeh_pe *pe, int option) | |||
519 | if (pe->type & EEH_PE_PHB) { | 518 | if (pe->type & EEH_PE_PHB) { |
520 | ret = ioda_eeh_phb_reset(hose, option); | 519 | ret = ioda_eeh_phb_reset(hose, option); |
521 | } else { | 520 | } else { |
522 | if (pe->type & EEH_PE_DEVICE) { | 521 | bus = eeh_pe_bus_get(pe); |
523 | /* | 522 | if (pci_is_root_bus(bus)) |
524 | * If it's device PE, we didn't refer to the parent | ||
525 | * PCI bus yet. So we have to figure it out indirectly. | ||
526 | */ | ||
527 | edev = list_first_entry(&pe->edevs, | ||
528 | struct eeh_dev, list); | ||
529 | dev = eeh_dev_to_pci_dev(edev); | ||
530 | dev = dev->bus->self; | ||
531 | } else { | ||
532 | /* | ||
533 | * If it's bus PE, the parent PCI bus is already there | ||
534 | * and just pick it up. | ||
535 | */ | ||
536 | dev = pe->bus->self; | ||
537 | } | ||
538 | |||
539 | /* | ||
540 | * Do reset based on the fact that the direct upstream bridge | ||
541 | * is root bridge (port) or not. | ||
542 | */ | ||
543 | if (dev->bus->number == 0) | ||
544 | ret = ioda_eeh_root_reset(hose, option); | 523 | ret = ioda_eeh_root_reset(hose, option); |
545 | else | 524 | else |
546 | ret = ioda_eeh_bridge_reset(hose, dev, option); | 525 | ret = ioda_eeh_bridge_reset(hose, bus->self, option); |
547 | } | 526 | } |
548 | 527 | ||
549 | return ret; | 528 | return ret; |