Thread (19 messages) 19 messages, 5 authors, 2007-12-28

Re: [2.6.23.9] hostap_plx locks up PC when reading PCI I/O memory

From: Andrew Morton <akpm@linux-foundation.org>
Date: 2007-12-12 01:11:54
Also in: lkml

On Sun, 9 Dec 2007 19:41:58 +0000 (GMT)
Chris Rankin [off-list ref] wrote:
Hi,

I've recently been having trouble loading the hostap_plx 802.11b wireless networking driver, and
this evening I managed to narrow the problem down to these lines of code by copying code from
hostap_plx into a "test driver" until the test driver also locked the PC up:

        /* read CIS; it is in even offsets in the beginning of attr_mem */
        for (i = 0; i < CIS_MAX_LEN; i++)
                cis[i] = readb(attr_mem + 2 * i);

If I comment these lines out then my test driver just complains about the garbage CIS information
and fails gracefully. Leave these lines in and my PC freezes instantly.

These lines are part of the prism2_plx_check_cis() function, which is called when the module first
loads. CIX_MAX_LEN is a #define for 256, and cis is a u8* pointer previously allocated as:

cis = kmalloc(CIS_MAX_LEN, GFP_KERNEL);

attr_mem is one of the function's paramters, and is defined as void __iomem *attr_mem.

As far as I can tell, the PCI I/O memory information is correct, and matches what lspci tells me:

00:0e.0 Network controller: Netgear MA301 802.11b Wireless PCI Adapter (rev 02)
        Subsystem: Netgear MA301 802.11b Wireless PCI Adapter
        Control: I/O+ Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+
FastB2B-
        Status: Cap- 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR-
<PERR-
        Interrupt: pin A routed to IRQ 5
        Region 1: I/O ports at 1000 [size=128]
        Region 2: Memory at e8002000 (32-bit, non-prefetchable) [size=4K]
        Region 3: I/O ports at 1080 [size=64]

so there is apparently 4K of I/O memory at 0xe8002000.

Can anyone help me understand why my PC is locking up when it executes this code, please?
I guess something like this:

--- a/drivers/net/wireless/hostap/hostap_plx.c~a
+++ a/drivers/net/wireless/hostap/hostap_plx.c
@@ -343,13 +343,14 @@ static int prism2_plx_check_cis(void __i
 	int i, pos;
 	unsigned int rmsz, rasz, manfid1, manfid2;
 	struct prism2_plx_manfid *manfid;
+	int len = min(CIS_MAX_LEN, attr_len);
 
-	cis = kmalloc(CIS_MAX_LEN, GFP_KERNEL);
+	cis = kmalloc(len, GFP_KERNEL);
 	if (cis == NULL)
 		return -ENOMEM;
 
 	/* read CIS; it is in even offsets in the beginning of attr_mem */
-	for (i = 0; i < CIS_MAX_LEN; i++)
+	for (i = 0; i < len; i++)
 		cis[i] = readb(attr_mem + 2 * i);
 	printk(KERN_DEBUG "%s: CIS: %02x %02x %02x %02x %02x %02x ...\n",
 	       dev_info, cis[0], cis[1], cis[2], cis[3], cis[4], cis[5]);
@@ -361,8 +362,8 @@ static int prism2_plx_check_cis(void __i
 	manfid1 = manfid2 = 0;
 
 	pos = 0;
-	while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) {
-		if (pos + 2 + cis[pos + 1] > CIS_MAX_LEN)
+	while (pos < len - 1 && cis[pos] != CISTPL_END) {
+		if (pos + 2 + cis[pos + 1] > len)
 			goto cis_error;
 
 		switch (cis[pos]) {
@@ -401,7 +402,7 @@ static int prism2_plx_check_cis(void __i
 		pos += cis[pos + 1] + 2;
 	}
 
-	if (pos >= CIS_MAX_LEN || cis[pos] != CISTPL_END)
+	if (pos >= len || cis[pos] != CISTPL_END)
 		goto cis_error;
 
 	for (manfid = prism2_plx_known_manfids; manfid->manfid1 != 0; manfid++)
_

would be a bit safer, but looking at your /proc/iomem I doubt if it will
fix anything.

It might be interesting to see what value of `i' is causing it to fall
over.

Did any earlier version of the 2.6 kernel work OK?
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help