[PATCH] Bugfix: powerpc/eeh: Wrong place to call pci_get_slot()

Mike Qiu qiudayu at linux.vnet.ibm.com
Mon Jul 14 18:19:23 EST 2014


[  121.133381] WARNING: at drivers/pci/search.c:223
[  121.133422] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 3.16.0-rc3+ #72
[  121.133424] task: c000000001367af0 ti: c000000001444000 task.ti: c000000001444000
[  121.133425] NIP: c000000000497b70 LR: c000000000037530 CTR: 000000003003d114
[  121.133427] REGS: c000000001446fa0 TRAP: 0700   Not tainted  (3.16.0-rc3+)
[  121.133428] MSR: 9000000000029032 <SF,HV,EE,ME,IR,DR,RI>  CR: 48002422  XER: 20000000
[  121.133433] CFAR: c00000000003752c SOFTE: 0
GPR00: c000000000037530 c000000001447220 c000000001448c30 c0000003bca1dc00
GPR04: 0000000000000000 c000000000066064 9000000000009032 0000000000000008
GPR08: 0000000000000007 0000000000000001 0000000000000100 000000003003d200
GPR12: 0000000044002482 c00000000fee0000 0000000000000000 c0000000015e8830
GPR16: c0000000015e8c30 0000000000000000 c0000000015e8430 c0000000015e8030
GPR20: c000000001348c30 c000000001482180 0000000000000000 0000000000000000
GPR24: 0000000000200200 c0000003bc243500 c0000003feff4070 c0000003bcec3000
GPR28: c0000000014cac00 c0000003bca1dc00 0000000000000000 0000000000000000
[  121.133454] NIP [c000000000497b70] .pci_get_slot+0x40/0x110
[  121.133457] LR [c000000000037530] .eeh_pe_loc_get+0x150/0x190
[  121.133458] Call Trace:
[  121.133461] [c000000001447220] [c000000000721730] .of_get_property+0x30/0x60 (unreliable)
[  121.133464] [c0000000014472b0] [c000000000037530] .eeh_pe_loc_get+0x150/0x190
[  121.133466] [c000000001447340] [c000000000034684] .eeh_dev_check_failure+0x1b4/0x550
[  121.133468] [c0000000014473f0] [c000000000034ab0] .eeh_check_failure+0x90/0xf0
[  121.133493] [c000000001447490] [d000000002c03e84] .lpfc_sli_check_eratt+0x504/0x7c0 [lpfc]
[  121.133501] [c000000001447520] [d000000002c041a4] .lpfc_poll_eratt+0x64/0x100 [lpfc]
[  121.133504] [c0000000014475a0] [c0000000000b45b4] .call_timer_fn+0x64/0x190
[  121.133506] [c000000001447650] [c0000000000b4d1c] .run_timer_softirq+0x2cc/0x3e0
[  121.133508] [c000000001447760] [c0000000000a90c8] .__do_softirq+0x198/0x3c0
[  121.133510] [c000000001447880] [c0000000000a9658] .irq_exit+0xc8/0x110
[  121.133513] [c000000001447900] [c00000000001e010] .timer_interrupt+0xa0/0xe0
[  121.133515] [c000000001447980] [c0000000000026d8] decrementer_common+0x158/0x180
[  121.133518] --- Exception: 901 at .arch_local_irq_restore+0x74/0x90

pci_get_slot() should not be used in interrupt. But eeh subsystem do
the error checking in interrupt in this situation.

This patch is to solve this issue.

Signed-off-by: Mike Qiu <qiudayu at linux.vnet.ibm.com>
---
 arch/powerpc/kernel/eeh_pe.c | 29 ++++++++++++++++++++++++++---
 1 file changed, 26 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c
index fbd01eb..6f4bfee 100644
--- a/arch/powerpc/kernel/eeh_pe.c
+++ b/arch/powerpc/kernel/eeh_pe.c
@@ -792,6 +792,28 @@ void eeh_pe_restore_bars(struct eeh_pe *pe)
 }
 
 /**
+ * __dn_get_pdev - Retrieve the pci_dev from device_node by bus/devfn
+ * @dn: device_node of the pci_dev
+ * @data: the pci device's bus/devfn
+ *
+ * Retrieve the pci_dev using the given device_node and bus/devfn.
+ */
+void *__dn_get_pdev(struct device_node *dn, void *data)
+{
+	struct pci_dn *pdn = PCI_DN(dn);
+	int busno = *((int *)data) >> 8;
+	int devfn = *((int *)data) & 0xff;
+
+	if (!pdn)
+		return NULL;
+
+	if (pdn->busno == busno && pdn->devfn == devfn)
+		return pdn->pcidev;
+
+	return NULL;
+}
+
+/**
  * eeh_pe_loc_get - Retrieve location code binding to the given PE
  * @pe: EEH PE
  *
@@ -807,6 +829,7 @@ const char *eeh_pe_loc_get(struct eeh_pe *pe)
 	struct pci_dev *pdev;
 	struct device_node *dn;
 	const char *loc;
+	int bdevfn;
 
 	if (!bus)
 		return "N/A";
@@ -823,7 +846,9 @@ const char *eeh_pe_loc_get(struct eeh_pe *pe)
 		if (loc)
 			return loc;
 
-		pdev = pci_get_slot(bus, 0x0);
+		/* Get the root port */
+		bdevfn = (bus->number) << 8 || 0x0;
+		pdev = traverse_pci_devices(hose->dn, __dn_get_pdev, &bdevfn);
 	} else {
 		pdev = bus->self;
 	}
@@ -846,8 +871,6 @@ const char *eeh_pe_loc_get(struct eeh_pe *pe)
 		loc = "N/A";
 
 out:
-	if (pci_is_root_bus(bus) && pdev)
-		pci_dev_put(pdev);
 	return loc;
 }
 
-- 
1.8.1.4



More information about the Linuxppc-dev mailing list