| From 5b2e198e50f6ba57081586b853163ea1bb95f1a8 Mon Sep 17 00:00:00 2001 |
| From: Gavin Shan <shangw@linux.vnet.ibm.com> |
| Date: Wed, 12 Feb 2014 15:24:54 +0800 |
| Subject: powerpc/powernv: Rework EEH reset |
| |
| From: Gavin Shan <shangw@linux.vnet.ibm.com> |
| |
| commit 5b2e198e50f6ba57081586b853163ea1bb95f1a8 upstream. |
| |
| 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. |
| |
| 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> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/powerpc/platforms/powernv/eeh-ioda.c | 29 ++++------------------------- |
| 1 file changed, 4 insertions(+), 25 deletions(-) |
| |
| --- a/arch/powerpc/platforms/powernv/eeh-ioda.c |
| +++ b/arch/powerpc/platforms/powernv/eeh-ioda.c |
| @@ -490,8 +490,7 @@ static int ioda_eeh_bridge_reset(struct |
| static int ioda_eeh_reset(struct eeh_pe *pe, int option) |
| { |
| struct pci_controller *hose = pe->phb; |
| - struct eeh_dev *edev; |
| - struct pci_dev *dev; |
| + struct pci_bus *bus; |
| int ret; |
| |
| /* |
| @@ -520,31 +519,11 @@ static int ioda_eeh_reset(struct eeh_pe |
| if (pe->type & EEH_PE_PHB) { |
| ret = ioda_eeh_phb_reset(hose, option); |
| } else { |
| - if (pe->type & EEH_PE_DEVICE) { |
| - /* |
| - * If it's device PE, we didn't refer to the parent |
| - * PCI bus yet. So we have to figure it out indirectly. |
| - */ |
| - edev = list_first_entry(&pe->edevs, |
| - struct eeh_dev, list); |
| - dev = eeh_dev_to_pci_dev(edev); |
| - dev = dev->bus->self; |
| - } else { |
| - /* |
| - * If it's bus PE, the parent PCI bus is already there |
| - * and just pick it up. |
| - */ |
| - dev = pe->bus->self; |
| - } |
| - |
| - /* |
| - * Do reset based on the fact that the direct upstream bridge |
| - * is root bridge (port) or not. |
| - */ |
| - if (dev->bus->number == 0) |
| + bus = eeh_pe_bus_get(pe); |
| + if (pci_is_root_bus(bus)) |
| ret = ioda_eeh_root_reset(hose, option); |
| else |
| - ret = ioda_eeh_bridge_reset(hose, dev, option); |
| + ret = ioda_eeh_bridge_reset(hose, bus->self, option); |
| } |
| |
| return ret; |