2006-12-10 11:29:26

by matthieu castet

[permalink] [raw]
Subject: 2.6.19 lot's of oops in mmx_copy_page/ mmx_clear_page functions

Hi,

with 2.6.19 I got some random crash and I got kernel opps.
There all happens in mmx_copy_page/ mmx_clear_page functions with
differents process : Xorg, cat, mozilla, ...


What could be the cause of these crashes ?
What can I provide in order to debug this ?


Thanks

Matthieu CASTET



BUG: unable to handle kernel paging request at virtual address fffb9000
printing eip:
c01be1bd
*pde = 00002067
Oops: 0000 [#1]
PREEMPT
Modules linked in: michael_mic arc4 ecb ieee80211_crypt_tkip ehci_hcd
videodev v4l1_compat v4l2_common nfs nfsd exportfs lockd sunrpc sd_mod
sg sr_mod ppdev lp autofs4 button processor ipt_TOS ipt_MASQUERADE
ipt_ULOG ipt_LOG xt_tcpudp xt_state ipt_REJECT ipt_iprange xt_conntrack
iptable_mangle ip_nat_irc ip_nat_ftp iptable_nat ip_nat ip_conntrack_irc
ip_conntrack_ftp ip_conntrack iptable_filter ip_tables x_tables ide_cd
cdrom pcspkr snd_mpu401 ns558 parport_pc parport 8250_pnp 8250
serial_core floppy snd_via82xx snd_mpu401_uart emu10k1_gp gameport
snd_emu10k1_synth snd_emux_synth snd_seq_virmidi snd_seq_midi_emul
snd_seq_oss snd_seq_midi snd_seq_midi_event snd_seq snd_emu10k1
snd_rawmidi snd_ac97_codec snd_ac97_bus snd_pcm_oss snd_mixer_oss
snd_pcm snd_seq_device snd_timer snd_page_alloc snd_util_mem snd_hwdep
snd soundcore mii zd1211rw firmware_class ieee80211softmac ieee80211
ieee80211_crypt via_agp agpgart clip atm nls_iso8859_1 nls_cp437 vfat
fat nls_base reiserfs w83627hf hwmon_vid i2c_isa i2c_core evdev rtc
CPU: 0
EIP: 0060:[<c01be1bd>] Not tainted VLI
EFLAGS: 00010246 (2.6.19 #1)
EIP is at mmx_copy_page+0x51/0x123
eax: fffb9000 ebx: e2db9000 ecx: 00000000 edx: e2db9000
esi: fffb9000 edi: e2db9000 ebp: c17e6040 esp: f671defc
ds: 007b es: 007b ss: 0068
Process automount (pid: 11921, ti=f671c000 task=f7cf0050 task.ti=f671c000)
Stack: fffb9000 eb216040 c0140045 8001003c f5c95e40 f4ee2abc c145b720
00000000
3f302065 f4ee2afc eb216040 f5c95e40 c014145f eb216040 f4f8a800
f4ee2afc
3f302065 393b4393 8001003c f4ee2abc 00000040 f4f8a800 00000000
f671df94
Call Trace:
[<c0140045>] do_wp_page+0x291/0x414
[<c014145f>] __handle_mm_fault+0x7d2/0x873
[<c0112593>] do_page_fault+0x213/0x4dc
[<c0112380>] do_page_fault+0x0/0x4dc
[<c02a01e1>] error_code+0x39/0x40
=======================
Code: f4 ff 0f 0d 06 0f 0d 46 40 0f 0d 86 80 00 00 00 0f 0d 86 c0 00 00
00 0f 0d 86 00 01 00 00 31 c9 89 fa 89 f0 0f 0d 80 40 01 00 00 <0f> 6f
00 0f e7 02 0f 6f 48 08 0f e7 4a 08 0f 6f 50 10 0f e7 52
EIP: [<c01be1bd>] mmx_copy_page+0x51/0x123 SS:ESP 0068:f671defc
<6>note: automount[11921] exited with preempt_count 3



Sumary of Others failures :
/var/log/syslog:Dec 10 10:40:14 localhost kernel: BUG: unable to handle
kernel paging request at virtual address fffb9b20
/var/log/syslog:Dec 10 10:40:14 localhost kernel: EIP is at
mmx_clear_page+0x38/0x7e
/var/log/syslog:Dec 10 10:40:14 localhost kernel: Process iceape-bin
(pid: 7061, ti=f7410000 task=eeb5a070 task.ti=f7410000)
/var/log/syslog:Dec 10 10:40:14 localhost kernel: EIP: [<c01be406>]
mmx_clear_page+0x38/0x7e SS:ESP 0068:f7411eb0
/var/log/syslog:Dec 10 10:40:24 localhost kernel: BUG: unable to handle
kernel paging request at virtual address fffb9a60
/var/log/syslog:Dec 10 10:40:24 localhost kernel: EIP is at
mmx_clear_page+0x38/0x7e
/var/log/syslog:Dec 10 10:40:24 localhost kernel: Process cc1 (pid:
21797, ti=d62ea000 task=e86eb070 task.ti=d62ea000)
/var/log/syslog:Dec 10 10:40:24 localhost kernel: EIP: [<c01be406>]
mmx_clear_page+0x38/0x7e SS:ESP 0068:d62ebeb0
/var/log/syslog:Dec 10 11:12:37 localhost kernel: BUG: unable to handle
kernel paging request at virtual address fffb9000
/var/log/syslog:Dec 10 11:12:37 localhost kernel: EIP is at
mmx_copy_page+0x51/0x123
/var/log/syslog:Dec 10 11:12:37 localhost kernel: Process automount
(pid: 11921, ti=f671c000 task=f7cf0050 task.ti=f671c000)
/var/log/syslog:Dec 10 11:12:37 localhost kernel: EIP: [<c01be1bd>]
mmx_copy_page+0x51/0x123 SS:ESP 0068:f671defc
/var/log/syslog.0:Dec 9 19:21:50 localhost kernel: Process modprobe
(pid: 20516, ti=ee3d8000 task=f649f580 task.ti=ee3d8000)
/var/log/syslog.0:Dec 9 22:15:15 localhost kernel: BUG: unable to
handle kernel paging request at virtual address fffb9000
/var/log/syslog.0:Dec 9 22:15:15 localhost kernel: EIP is at
mmx_clear_page+0x29/0x7e
/var/log/syslog.0:Dec 9 22:15:15 localhost kernel: Process Xorg (pid:
9479, ti=d4ae0000 task=f671ca90 task.ti=d4ae0000)
/var/log/syslog.0:Dec 9 22:15:15 localhost kernel: EIP: [<c01be3f7>]
mmx_clear_page+0x29/0x7e SS:ESP 0068:d4ae1eb0
/var/log/syslog.0:Dec 9 22:15:15 localhost kernel: [<c01be3f7>]
mmx_clear_page+0x29/0x7e
/var/log/syslog.0:Dec 9 22:15:15 localhost kernel: [<c01be3f7>]
mmx_clear_page+0x29/0x7e
/var/log/syslog.0:Dec 10 00:06:31 localhost kernel: BUG: unable to
handle kernel paging request at virtual address fffb9340
/var/log/syslog.0:Dec 10 00:06:31 localhost kernel: EIP is at
mmx_clear_page+0x29/0x7e
/var/log/syslog.0:Dec 10 00:06:31 localhost kernel: Process Xorg (pid:
10450, ti=c758e000 task=d42fa030 task.ti=c758e000)
/var/log/syslog.0:Dec 10 00:06:31 localhost kernel: EIP: [<c01be3f7>]
mmx_clear_page+0x29/0x7e SS:ESP 0068:c758feb0
/var/log/syslog.0:Dec 10 00:06:31 localhost kernel: [<c01be3f7>]
mmx_clear_page+0x29/0x7e
/var/log/syslog.0:Dec 10 00:06:31 localhost kernel: [<c01be3f7>]
mmx_clear_page+0x29/0x7e
/var/log/syslog.0:Dec 10 10:23:00 localhost kernel: BUG: unable to
handle kernel paging request at virtual address fffb9000
/var/log/syslog.0:Dec 10 10:23:00 localhost kernel: EIP is at
mmx_copy_page+0x51/0x123
/var/log/syslog.0:Dec 10 10:23:00 localhost kernel: Process cat (pid:
8977, ti=db79c000 task=df987030 task.ti=db79c000)
/var/log/syslog.0:Dec 10 10:23:00 localhost kernel: EIP: [<c01be1bd>]
mmx_copy_page+0x51/0x123 SS:ESP 0068:db79ddc8


2006-12-10 19:02:10

by Maxime Austruy

[permalink] [raw]
Subject: Re: 2.6.19 lot's of oops in mmx_copy_page/ mmx_clear_page functions


Matthieu,

On Sun, Dec 10, 2006 at 12:32:08PM +0100, matthieu castet wrote:
> Hi,
>
> with 2.6.19 I got some random crash and I got kernel opps.
> There all happens in mmx_copy_page/ mmx_clear_page functions with
> differents process : Xorg, cat, mozilla, ...
>
>
> What could be the cause of these crashes ?
> What can I provide in order to debug this ?

FWIW, I've seen the same oops on my box. My instance was caused by a
combination of:
. zd1211rw calling ieee80211_rx in irq context while it's supposed to
be called in softirq,
. crypto code only expecting to be called in softirq/user context but
not enforcing it. Consequently, it ends up doing
v = kmap_atomic(..., KM_USER0);
even when invoked by the zd1211rw driver in irq context, causing some
corruption.

Given that you have zd1211rw insmod'd, that could be it. I have some
hacks that work around this bug, but Ulrich has a patch ready that
should fix this. Thanks,

Max

>
>
> Thanks
>
> Matthieu CASTET
>
>
>
> BUG: unable to handle kernel paging request at virtual address fffb9000
> printing eip:
> c01be1bd
> *pde = 00002067
> Oops: 0000 [#1]
> PREEMPT
> Modules linked in: michael_mic arc4 ecb ieee80211_crypt_tkip ehci_hcd
> videodev v4l1_compat v4l2_common nfs nfsd exportfs lockd sunrpc sd_mod
> sg sr_mod ppdev lp autofs4 button processor ipt_TOS ipt_MASQUERADE
> ipt_ULOG ipt_LOG xt_tcpudp xt_state ipt_REJECT ipt_iprange xt_conntrack
> iptable_mangle ip_nat_irc ip_nat_ftp iptable_nat ip_nat ip_conntrack_irc
> ip_conntrack_ftp ip_conntrack iptable_filter ip_tables x_tables ide_cd
> cdrom pcspkr snd_mpu401 ns558 parport_pc parport 8250_pnp 8250
> serial_core floppy snd_via82xx snd_mpu401_uart emu10k1_gp gameport
> snd_emu10k1_synth snd_emux_synth snd_seq_virmidi snd_seq_midi_emul
> snd_seq_oss snd_seq_midi snd_seq_midi_event snd_seq snd_emu10k1
> snd_rawmidi snd_ac97_codec snd_ac97_bus snd_pcm_oss snd_mixer_oss
> snd_pcm snd_seq_device snd_timer snd_page_alloc snd_util_mem snd_hwdep
> snd soundcore mii zd1211rw firmware_class ieee80211softmac ieee80211
> ieee80211_crypt via_agp agpgart clip atm nls_iso8859_1 nls_cp437 vfat
> fat nls_base reiserfs w83627hf hwmon_vid i2c_isa i2c_core evdev rtc
> CPU: 0
> EIP: 0060:[<c01be1bd>] Not tainted VLI
> EFLAGS: 00010246 (2.6.19 #1)
> EIP is at mmx_copy_page+0x51/0x123
> eax: fffb9000 ebx: e2db9000 ecx: 00000000 edx: e2db9000
> esi: fffb9000 edi: e2db9000 ebp: c17e6040 esp: f671defc
> ds: 007b es: 007b ss: 0068
> Process automount (pid: 11921, ti=f671c000 task=f7cf0050 task.ti=f671c000)
> Stack: fffb9000 eb216040 c0140045 8001003c f5c95e40 f4ee2abc c145b720
> 00000000
> 3f302065 f4ee2afc eb216040 f5c95e40 c014145f eb216040 f4f8a800
> f4ee2afc
> 3f302065 393b4393 8001003c f4ee2abc 00000040 f4f8a800 00000000
> f671df94
> Call Trace:
> [<c0140045>] do_wp_page+0x291/0x414
> [<c014145f>] __handle_mm_fault+0x7d2/0x873
> [<c0112593>] do_page_fault+0x213/0x4dc
> [<c0112380>] do_page_fault+0x0/0x4dc
> [<c02a01e1>] error_code+0x39/0x40
> =======================
> Code: f4 ff 0f 0d 06 0f 0d 46 40 0f 0d 86 80 00 00 00 0f 0d 86 c0 00 00
> 00 0f 0d 86 00 01 00 00 31 c9 89 fa 89 f0 0f 0d 80 40 01 00 00 <0f> 6f
> 00 0f e7 02 0f 6f 48 08 0f e7 4a 08 0f 6f 50 10 0f e7 52
> EIP: [<c01be1bd>] mmx_copy_page+0x51/0x123 SS:ESP 0068:f671defc
> <6>note: automount[11921] exited with preempt_count 3
>
>
>
> Sumary of Others failures :
> /var/log/syslog:Dec 10 10:40:14 localhost kernel: BUG: unable to handle
> kernel paging request at virtual address fffb9b20
> /var/log/syslog:Dec 10 10:40:14 localhost kernel: EIP is at
> mmx_clear_page+0x38/0x7e
> /var/log/syslog:Dec 10 10:40:14 localhost kernel: Process iceape-bin
> (pid: 7061, ti=f7410000 task=eeb5a070 task.ti=f7410000)
> /var/log/syslog:Dec 10 10:40:14 localhost kernel: EIP: [<c01be406>]
> mmx_clear_page+0x38/0x7e SS:ESP 0068:f7411eb0
> /var/log/syslog:Dec 10 10:40:24 localhost kernel: BUG: unable to handle
> kernel paging request at virtual address fffb9a60
> /var/log/syslog:Dec 10 10:40:24 localhost kernel: EIP is at
> mmx_clear_page+0x38/0x7e
> /var/log/syslog:Dec 10 10:40:24 localhost kernel: Process cc1 (pid:
> 21797, ti=d62ea000 task=e86eb070 task.ti=d62ea000)
> /var/log/syslog:Dec 10 10:40:24 localhost kernel: EIP: [<c01be406>]
> mmx_clear_page+0x38/0x7e SS:ESP 0068:d62ebeb0
> /var/log/syslog:Dec 10 11:12:37 localhost kernel: BUG: unable to handle
> kernel paging request at virtual address fffb9000
> /var/log/syslog:Dec 10 11:12:37 localhost kernel: EIP is at
> mmx_copy_page+0x51/0x123
> /var/log/syslog:Dec 10 11:12:37 localhost kernel: Process automount
> (pid: 11921, ti=f671c000 task=f7cf0050 task.ti=f671c000)
> /var/log/syslog:Dec 10 11:12:37 localhost kernel: EIP: [<c01be1bd>]
> mmx_copy_page+0x51/0x123 SS:ESP 0068:f671defc
> /var/log/syslog.0:Dec 9 19:21:50 localhost kernel: Process modprobe
> (pid: 20516, ti=ee3d8000 task=f649f580 task.ti=ee3d8000)
> /var/log/syslog.0:Dec 9 22:15:15 localhost kernel: BUG: unable to
> handle kernel paging request at virtual address fffb9000
> /var/log/syslog.0:Dec 9 22:15:15 localhost kernel: EIP is at
> mmx_clear_page+0x29/0x7e
> /var/log/syslog.0:Dec 9 22:15:15 localhost kernel: Process Xorg (pid:
> 9479, ti=d4ae0000 task=f671ca90 task.ti=d4ae0000)
> /var/log/syslog.0:Dec 9 22:15:15 localhost kernel: EIP: [<c01be3f7>]
> mmx_clear_page+0x29/0x7e SS:ESP 0068:d4ae1eb0
> /var/log/syslog.0:Dec 9 22:15:15 localhost kernel: [<c01be3f7>]
> mmx_clear_page+0x29/0x7e
> /var/log/syslog.0:Dec 9 22:15:15 localhost kernel: [<c01be3f7>]
> mmx_clear_page+0x29/0x7e
> /var/log/syslog.0:Dec 10 00:06:31 localhost kernel: BUG: unable to
> handle kernel paging request at virtual address fffb9340
> /var/log/syslog.0:Dec 10 00:06:31 localhost kernel: EIP is at
> mmx_clear_page+0x29/0x7e
> /var/log/syslog.0:Dec 10 00:06:31 localhost kernel: Process Xorg (pid:
> 10450, ti=c758e000 task=d42fa030 task.ti=c758e000)
> /var/log/syslog.0:Dec 10 00:06:31 localhost kernel: EIP: [<c01be3f7>]
> mmx_clear_page+0x29/0x7e SS:ESP 0068:c758feb0
> /var/log/syslog.0:Dec 10 00:06:31 localhost kernel: [<c01be3f7>]
> mmx_clear_page+0x29/0x7e
> /var/log/syslog.0:Dec 10 00:06:31 localhost kernel: [<c01be3f7>]
> mmx_clear_page+0x29/0x7e
> /var/log/syslog.0:Dec 10 10:23:00 localhost kernel: BUG: unable to
> handle kernel paging request at virtual address fffb9000
> /var/log/syslog.0:Dec 10 10:23:00 localhost kernel: EIP is at
> mmx_copy_page+0x51/0x123
> /var/log/syslog.0:Dec 10 10:23:00 localhost kernel: Process cat (pid:
> 8977, ti=db79c000 task=df987030 task.ti=db79c000)
> /var/log/syslog.0:Dec 10 10:23:00 localhost kernel: EIP: [<c01be1bd>]
> mmx_copy_page+0x51/0x123 SS:ESP 0068:db79ddc8
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>

2006-12-10 19:25:10

by Ulrich Kunitz

[permalink] [raw]
Subject: Re: 2.6.19 lot's of oops in mmx_copy_page/ mmx_clear_page functions

On 06-12-10 11:02 Maxime Austruy wrote:

>
> Matthieu,
>
> On Sun, Dec 10, 2006 at 12:32:08PM +0100, matthieu castet wrote:
> > Hi,
> >
> > with 2.6.19 I got some random crash and I got kernel opps.
> > There all happens in mmx_copy_page/ mmx_clear_page functions with
> > differents process : Xorg, cat, mozilla, ...
> >
> >
> > What could be the cause of these crashes ?
> > What can I provide in order to debug this ?
>
> FWIW, I've seen the same oops on my box. My instance was caused by a
> combination of:
> . zd1211rw calling ieee80211_rx in irq context while it's supposed to
> be called in softirq,
> . crypto code only expecting to be called in softirq/user context but
> not enforcing it. Consequently, it ends up doing
> v = kmap_atomic(..., KM_USER0);
> even when invoked by the zd1211rw driver in irq context, causing some
> corruption.
>
> Given that you have zd1211rw insmod'd, that could be it. I have some
> hacks that work around this bug, but Ulrich has a patch ready that
> should fix this. Thanks,
>
> Max

Here is the patch against vanilla 2.6.19.

For Linus' latest tree I have sent also patches on netdev.

Users of my out-of-kernel git tree, should look at the branch rx.

Uli

[PATCH] zd1211rw: Call ieee80211_rx in tasklet

The driver called ieee80211_rx in hardware irq context. This
caused a problem withe crypto libraries and was against the
documentation/intention of the ieee80211_rx function. This patch
fixes that.

Signed-off-by: Ulrich Kunitz <[email protected]>
---
drivers/net/wireless/zd1211rw/zd_mac.c | 88 ++++++++++++++++++++++++--------
drivers/net/wireless/zd1211rw/zd_mac.h | 6 ++
drivers/net/wireless/zd1211rw/zd_usb.c | 4 +
3 files changed, 72 insertions(+), 26 deletions(-)

diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index a7d29bd..f52dd3a 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -37,6 +37,8 @@ static void housekeeping_init(struct zd_
static void housekeeping_enable(struct zd_mac *mac);
static void housekeeping_disable(struct zd_mac *mac);

+static void do_rx(unsigned long mac_ptr);
+
int zd_mac_init(struct zd_mac *mac,
struct net_device *netdev,
struct usb_interface *intf)
@@ -47,6 +49,10 @@ int zd_mac_init(struct zd_mac *mac,
spin_lock_init(&mac->lock);
mac->netdev = netdev;

+ skb_queue_head_init(&mac->rx_queue);
+ tasklet_init(&mac->rx_tasklet, do_rx, (unsigned long)mac);
+ tasklet_disable(&mac->rx_tasklet);
+
ieee_init(ieee);
softmac_init(ieee80211_priv(netdev));
zd_chip_init(&mac->chip, netdev, intf);
@@ -132,6 +138,8 @@ out:

void zd_mac_clear(struct zd_mac *mac)
{
+ skb_queue_purge(&mac->rx_queue);
+ tasklet_kill(&mac->rx_tasklet);
zd_chip_clear(&mac->chip);
ZD_ASSERT(!spin_is_locked(&mac->lock));
ZD_MEMCLEAR(mac, sizeof(struct zd_mac));
@@ -160,6 +168,8 @@ int zd_mac_open(struct net_device *netde
struct zd_chip *chip = &mac->chip;
int r;

+ tasklet_enable(&mac->rx_tasklet);
+
r = zd_chip_enable_int(chip);
if (r < 0)
goto out;
@@ -210,6 +220,8 @@ int zd_mac_stop(struct net_device *netde
*/

zd_chip_disable_rx(chip);
+ skb_queue_purge(&mac->rx_queue);
+ tasklet_disable(&mac->rx_tasklet);
housekeeping_disable(mac);
ieee80211softmac_stop(netdev);

@@ -873,45 +885,75 @@ static int fill_rx_stats(struct ieee8021
return 0;
}

-int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length)
+static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb)
{
int r;
struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
struct ieee80211_rx_stats stats;
const struct rx_status *status;
- struct sk_buff *skb;

- if (length < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN +
- IEEE80211_FCS_LEN + sizeof(struct rx_status))
- return -EINVAL;
+ if (skb->len < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN +
+ IEEE80211_FCS_LEN + sizeof(struct rx_status))
+ {
+ dev_warn(zd_mac_dev(mac), "Packet with length %u to small.\n",
+ skb->len);
+ goto free_skb;
+ }

- r = fill_rx_stats(&stats, &status, mac, buffer, length);
- if (r)
- return r;
+ r = fill_rx_stats(&stats, &status, mac, skb->data, skb->len);
+ if (r) {
+ /* Only packets with rx errors are included here. */
+ goto free_skb;
+ }

- length -= ZD_PLCP_HEADER_SIZE+IEEE80211_FCS_LEN+
- sizeof(struct rx_status);
- buffer += ZD_PLCP_HEADER_SIZE;
+ __skb_pull(skb, ZD_PLCP_HEADER_SIZE);
+ __skb_trim(skb, skb->len -
+ (IEEE80211_FCS_LEN + sizeof(struct rx_status)));

- update_qual_rssi(mac, buffer, length, stats.signal, stats.rssi);
+ update_qual_rssi(mac, skb->data, skb->len, stats.signal,
+ status->signal_strength);

- r = filter_rx(ieee, buffer, length, &stats);
- if (r <= 0)
- return r;
+ r = filter_rx(ieee, skb->data, skb->len, &stats);
+ if (r <= 0) {
+ if (r < 0)
+ dev_dbg_f(zd_mac_dev(mac), "Error in packet.\n");
+ goto free_skb;
+ }

- skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length);
- if (!skb)
- return -ENOMEM;
if (ieee->iw_mode == IW_MODE_MONITOR)
- fill_rt_header(skb_put(skb, sizeof(struct zd_rt_hdr)), mac,
+ fill_rt_header(skb_push(skb, sizeof(struct zd_rt_hdr)), mac,
&stats, status);
- memcpy(skb_put(skb, length), buffer, length);

r = ieee80211_rx(ieee, skb, &stats);
- if (!r) {
- ZD_ASSERT(in_irq());
- dev_kfree_skb_irq(skb);
+ if (r)
+ return;
+free_skb:
+ /* We are always in a soft irq. */
+ dev_kfree_skb(skb);
+}
+
+static void do_rx(unsigned long mac_ptr)
+{
+ struct zd_mac *mac = (struct zd_mac *)mac_ptr;
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&mac->rx_queue)) != NULL)
+ zd_mac_rx(mac, skb);
+}
+
+int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length)
+{
+ struct sk_buff *skb;
+
+ skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length);
+ if (!skb) {
+ dev_warn(zd_mac_dev(mac), "Could not allocate skb.\n");
+ return -ENOMEM;
}
+ skb_reserve(skb, sizeof(struct zd_rt_hdr));
+ memcpy(__skb_put(skb, length), buffer, length);
+ skb_queue_tail(&mac->rx_queue, skb);
+ tasklet_schedule(&mac->rx_tasklet);
return 0;
}

diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index b8ea3de..c1bea87 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -133,6 +133,10 @@ struct zd_mac {
/* Unlocked reading possible */
struct iw_statistics iw_stats;
struct housekeeping housekeeping;
+
+ struct tasklet_struct rx_tasklet;
+ struct sk_buff_head rx_queue;
+
unsigned int stats_count;
u8 qual_buffer[ZD_MAC_STATS_BUFFER_SIZE];
u8 rssi_buffer[ZD_MAC_STATS_BUFFER_SIZE];
@@ -174,7 +178,7 @@ int zd_mac_open(struct net_device *netde
int zd_mac_stop(struct net_device *netdev);
int zd_mac_set_mac_address(struct net_device *dev, void *p);

-int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length);
+int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length);

int zd_mac_set_regdomain(struct zd_mac *zd_mac, u8 regdomain);
u8 zd_mac_get_regdomain(struct zd_mac *zd_mac);
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 3faaeb2..4a5f5d5 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -599,13 +599,13 @@ static void handle_rx_packet(struct zd_u
n = l+k;
if (n > length)
return;
- zd_mac_rx(mac, buffer+l, k);
+ zd_mac_rx_irq(mac, buffer+l, k);
if (i >= 2)
return;
l = (n+3) & ~3;
}
} else {
- zd_mac_rx(mac, buffer, length);
+ zd_mac_rx_irq(mac, buffer, length);
}
}

--
1.4.1