* [PATCH V2] b43: Work around mac80211 race condition that may transmit one packet after queue is stopped
From: Larry Finger @ 2009-07-29 15:54 UTC (permalink / raw)
To: John W Linville, Michael Buesch; +Cc: Johannes Berg, linux-wireless
As shown in http://thread.gmane.org/gmane.linux.kernel.wireless.general/36497,
mac80211 has a bug that allows a call to the TX routine after the queues have
been stopped. This situation will only occur under extreme stress. Although
b43 does not crash when this condition occurs, it does generate a WARN_ON and
also logs a queue overrun message. This patch recognizes b43 is not at fault
and logs a message only when the most verbose debugging mode is enabled. In
the unlikely event that the queue is not stopped when the DMA queue becomes
full, then a warning is issued.
During testing of this patch with one output stream running repeated tcpperf
writes and a second running a flood ping, this routine was entered with
the DMA ring stopped about once per hour. The condition where the DMA queue is
full but the ring has not been stopped has never been seen by me.
Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
---
John,
This patch is 2.6.32 material.
Larry
---
V2 - put WARN_ON in if statement.
dma.c | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
Index: wireless-testing/drivers/net/wireless/b43/dma.c
===================================================================
--- wireless-testing.orig/drivers/net/wireless/b43/dma.c
+++ wireless-testing/drivers/net/wireless/b43/dma.c
@@ -1334,13 +1334,22 @@ int b43_dma_tx(struct b43_wldev *dev, st
spin_lock_irqsave(&ring->lock, flags);
B43_WARN_ON(!ring->tx);
- /* Check if the queue was stopped in mac80211,
- * but we got called nevertheless.
- * That would be a mac80211 bug. */
- B43_WARN_ON(ring->stopped);
- if (unlikely(free_slots(ring) < TX_SLOTS_PER_FRAME)) {
- b43warn(dev->wl, "DMA queue overflow\n");
+ if (unlikely(ring->stopped)) {
+ /* We get here only because of a bug in mac80211.
+ * Because of a race, one packet may be queued after
+ * the queue is stopped, thus we got called when we shouldn't.
+ * For now, just refuse the transmit. */
+ if (b43_debug(dev, B43_DBG_DMAVERBOSE))
+ b43err(dev->wl, "Packet after queue stopped\n");
+ err = -ENOSPC;
+ goto out_unlock;
+ }
+
+ if (unlikely(WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME))) {
+ /* If we get here, we have a real error with the queue
+ * full, but queues not stopped. */
+ b43err(dev->wl, "DMA queue overflow\n");
err = -ENOSPC;
goto out_unlock;
}
^ permalink raw reply
* Re: WARNING: at net/mac80211/agg-tx.c:145
From: Thomas Backlund @ 2009-07-29 16:10 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <1248798501.13742.1.camel@johannes.local>
Johannes Berg skrev:
> On Tue, 2009-07-28 at 19:24 +0300, Thomas Backlund wrote:
>> Hi,
>>
>> Is this known?
>
> I think so. The problem is that on a hw restart the driver clears
> aggregation but mac80211 thinks the session is still up, I think.
>
ok, so is there any fixes to test...
--
Thomas
^ permalink raw reply
* Re: WARNING: at net/mac80211/agg-tx.c:145
From: Johannes Berg @ 2009-07-29 16:25 UTC (permalink / raw)
To: Thomas Backlund; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <4A707463.1000508@mandriva.org>
[-- Attachment #1: Type: text/plain, Size: 451 bytes --]
On Wed, 2009-07-29 at 19:10 +0300, Thomas Backlund wrote:
> Johannes Berg skrev:
> > On Tue, 2009-07-28 at 19:24 +0300, Thomas Backlund wrote:
> >> Hi,
> >>
> >> Is this known?
> >
> > I think so. The problem is that on a hw restart the driver clears
> > aggregation but mac80211 thinks the session is still up, I think.
> >
>
>
> ok, so is there any fixes to test...
No. Just ignore the warning. It's mostly harmless.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: WARNING: at net/mac80211/agg-tx.c:145
From: Thomas Backlund @ 2009-07-29 17:38 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <1248884734.25614.2.camel@johannes.local>
Johannes Berg skrev:
> On Wed, 2009-07-29 at 19:10 +0300, Thomas Backlund wrote:
>> Johannes Berg skrev:
>>> On Tue, 2009-07-28 at 19:24 +0300, Thomas Backlund wrote:
>>>> Hi,
>>>>
>>>> Is this known?
>>> I think so. The problem is that on a hw restart the driver clears
>>> aggregation but mac80211 thinks the session is still up, I think.
>>>
>>
>> ok, so is there any fixes to test...
>
> No. Just ignore the warning. It's mostly harmless.
Not really, today when I hit it, and had to restart the network to get
my internet connection back :-(
When I hit it last time, the network coped with it without problem...
So is it the fw that should be fixed, or the code ?
--
Thomas
^ permalink raw reply
* Re: Pulling rt73 USB stick oopses the kernel
From: Pavel Roskin @ 2009-07-29 18:44 UTC (permalink / raw)
To: Michael Buesch; +Cc: linux-wireless
In-Reply-To: <200907291224.37562.mb@bu3sch.de>
On Wed, 2009-07-29 at 12:24 +0200, Michael Buesch wrote:
> Pulling a rt73 USB stick in operation (packets were injected into the monitor)
> does oops the kernel as follows:
...
> [ 829.269554] BUG kmalloc-16: Redzone overwritten
There are some memory corruption issues with the removal of rt73usb and
rt61pci, but they are hard to track down. Using kmemcheck allows to
catch the first invalid memory access.
That's what I got (that's unloading rt73usb with rmmod while the
interface is up in station mode):
usbcore: deregistering interface driver rt73usb
WARNING: kmemcheck: Caught 64-bit read from freed memory (ffff88012f36b4c0)
58f97781ffffffff58f97781ffffffff4c71000001000000e0e00481ffffffff
f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f f
^
Modules linked in: rt2x00usb rt2x00lib mac80211 cfg80211 [last unloaded: rt73usb]
Pid: 2043, comm: hald Not tainted 2.6.31-rc4-wl #185 G31T-M
RIP: 0010:[<ffffffff8124b476>] [<ffffffff8124b476>] __list_add+0x26/0xa0
RSP: 0018:ffff88012f8f7da0 EFLAGS: 00010046
RAX: ffffffff8177f480 RBX: ffff8800280305a0 RCX: 00000000000004c0
RDX: ffffffff8177f958 RSI: ffff88012f36b4c0 RDI: ffff8800280305a0
RBP: ffff88012f8f7dc0 R08: ffff88012f36b4c0 R09: ffff880028022000
R10: 00000000ffffffff R11: 0000000000000000 R12: ffffffff8177f958
R13: ffff88012f36b4c0 R14: 000000010000714c R15: ffffffff8177f480
FS: 00007ff62a5316f0(0000) GS:ffff880028022000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: ffff88012f890ea8 CR3: 000000012f21e000 CR4: 00000000000006f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff4ff0 DR7: 0000000000000400
[<ffffffff810461f5>] internal_add_timer+0xb5/0x110
[<ffffffff810468b1>] mod_timer+0xe1/0x130
[<ffffffff81046913>] add_timer+0x13/0x20
[<ffffffff8104e03b>] queue_delayed_work_on+0x8b/0xc0
[<ffffffff8104e34c>] queue_delayed_work+0x1c/0x30
[<ffffffff8104e376>] schedule_delayed_work+0x16/0x20
[<ffffffff81081dc8>] vmstat_update+0x38/0x40
[<ffffffff8104dbb4>] worker_thread+0xe4/0x190
[<ffffffff81051816>] kthread+0x96/0xa0
[<ffffffff8100c2ba>] child_rip+0xa/0x20
[<ffffffffffffffff>] 0xffffffffffffffff
__list_add+0x26 corresponds to line 27 in lib/list_debug.c:
WARN(prev->next != next,
"list_add corruption. prev->next should be "
"next (%p), but was %p. (prev=%p).\n",
next, prev->next, prev);
next and prev are accessed in the previous statement, so apparently it's
prev->next that is invalid.
rt73usb is already unloaded at this point. Perhaps it left some timers
registered.
--
Regards,
Pavel Roskin
^ permalink raw reply
* Re: ath5k connection loss (failed to wakeup the MAC Chip)
From: Adrian von Bidder @ 2009-07-29 10:11 UTC (permalink / raw)
To: Nick Kossifidis; +Cc: linux-wireless
In-Reply-To: <40f31dec0907281653g63375736id57f547a8ba12cad@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 3005 bytes --]
Hi,
On Wednesday 29 July 2009 01.53:18 Nick Kossifidis wrote:
> 2009/7/28 Adrian von Bidder <avbidder@fortytwo.ch>:
> > Heyho!
> >
> > (This is using kernel 2.6.31-rc3 as packaged by Debian)
> >
> > While taking a full backup of my laptop, I noticed that after a few
> > 100M the ath5k can't connect to WLAN anymore.
>
> Working on it, can you please post the part when ath5k loads ?
$ dmesg | grep -5 ath5
[ 10.837434] usbcore: registered new interface driver uvcvideo
[ 10.837444] USB Video Class driver (v0.1.0)
[ 11.058396] Synaptics Touchpad, model: 1, fw: 7.2, id: 0x1c0b1, caps: 0xd04771/0xa40000
[ 11.100259] ACPI: WMI: Mapper loaded
[ 11.116172] input: SynPS/2 Synaptics TouchPad as /devices/platform/i8042/serio2/input/input3
[ 11.152799] ath5k 0000:03:00.0: PCI INT A -> GSI 18 (level, low) -> IRQ 18
[ 11.152843] ath5k 0000:03:00.0: setting latency timer to 64
[ 11.152938] ath5k 0000:03:00.0: registered as 'phy0'
[ 11.160210] acer-wmi: Acer Laptop ACPI-WMI Extras
[ 11.160218] acer-wmi: Blacklisted hardware detected - not loading
[ 11.227537] ath: EEPROM regdomain: 0x65
[ 11.227546] ath: EEPROM indicates we should expect a direct regpair map
[ 11.227557] ath: Country alpha2 being used: 00
--
[ 13.449969] ACPI: Video Device [OVGA] (multi-head: yes rom: yes post: no)
[ 13.500020] Clocksource tsc unstable (delta = -353758420 ns)
[ 13.602489] ACPI: AC Adapter [ACAD] (on-line)
[ 13.602714] input: Lid Switch as /devices/LNXSYSTM:00/device:00/PNP0C0D:00/input/input7
[ 13.872882] phy0: Selected rate control algorithm 'minstrel'
[ 13.875055] Registered led device: ath5k-phy0::rx
[ 13.875106] Registered led device: ath5k-phy0::tx
[ 13.875116] ath5k phy0: Atheros AR2425 chip found (MAC: 0xe2, PHY: 0x70)
[ 14.047189] HDA Intel 0000:00:1b.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16
[ 14.047271] HDA Intel 0000:00:1b.0: setting latency timer to 64
[ 14.160144] ACPI: Lid Switch [LID0]
[ 14.160386] input: Sleep Button as /devices/LNXSYSTM:00/device:00/PNP0C0E:00/input/input8
[ 14.160502] ACPI: Sleep Button [SLPB]
(btw, in my case the laptop probably went through suspend to ram/resume
before I started the backup. Don't know if that has any influence.)
cheers
-- vbi
cheers
-- vbi
--
featured product: ClamAV Antivirus - http://www.clamav.net/
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 388 bytes --]
^ permalink raw reply
* Beacon loss - broadcom 4318
From: Jędrek Kaniewski @ 2009-07-29 19:09 UTC (permalink / raw)
To: linux-wireless
Hi, I thought I eventually got my wireless to work but it is not very
reliable. So far I've noticed that it works during the night. It
hardly ever works during the day. The message I get is the following :
wlan0: beacon loss from AP f5ccb638 - sending probe request
wlan0: no probe response from AP f5ccb638 - disassociating
SFW2-OUT-ERROR IN= OUT=wlan0 SRC=192.168.0.16 DST=193.186.32.251
LEN=52 TOS=0x00 PREC=0x00 TTL=64 ID=42930 DF PROTO=TCP SPT=44714
DPT=80 WINDOW=998 RES=0x00 ACK PSH FIN URGP=0 OPT
(0101080A00076C6001CC5044)
wlan0: authenticate with AP f5ccb638
wlan0: authenticate with AP f5ccb638
wlan0: authenticated
wlan0: associate with AP f5ccb638
wlan0: RX ReassocResp from f59a903e (capab=0x431 status=0 aid=2)
wlan0: associated
SFW2-OUT-ERROR IN= OUT=wlan0 SRC=192.168.0.16 DST=193.186.32.251
LEN=52 TOS=0x00 PREC=0x00 TTL=64 ID=53851 DF PROTO=TCP SPT=44722
DPT=80 WINDOW=1002 RES=0x00 ACK PSH FIN URGP=0 OPT
(0101080A000773A001CC5048)
wlan0: beacon loss from AP f5ccb638 - sending probe request
wlan0: no probe response from AP f5ccb638 - disassociating
I googled and it seems that this problem is well known. However, I
didn't manage to find any workarounds.
Anyone could help ?
Cheers,
Jed
^ permalink raw reply
* Re: ath5k connection loss (failed to wakeup the MAC Chip)
From: Ben Greear @ 2009-07-29 19:09 UTC (permalink / raw)
To: Adrian von Bidder; +Cc: Nick Kossifidis, linux-wireless
In-Reply-To: <200907291211.21133@fortytwo.ch>
I'm not sure if it helps, but if I:
load ath5k and let some stations associate (I'm testing virtual
STA logic)
.. wait a bit ...
rmmod ath5k; modprobe ath5k
then it fails to wakeup the MAC chip every time.
But, if I then wait a few seconds, and repeat the rmmod/modprobe commands, then it wakes
up and works fine.
I'm running a hacked kernel (and ath5k/wifi stack), so could be something
I'm doing wrong, but just maybe it will give you a reproducible test
case...
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* [PATCH] rt2x00dev: cancel all work on disconnect
From: Pavel Roskin @ 2009-07-29 20:07 UTC (permalink / raw)
To: linux-wireless, John W. Linville, users; +Cc: Michael Buesch
Signed-off-by: Pavel Roskin <proski@gnu.org>
---
drivers/net/wireless/rt2x00/rt2x00dev.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 658a63b..66b303b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -888,6 +888,13 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
clear_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags);
/*
+ * Cancel all work.
+ */
+ rt2x00link_stop_tuner(rt2x00dev);
+ cancel_work_sync(&rt2x00dev->filter_work);
+ cancel_work_sync(&rt2x00dev->intf_work);
+
+ /*
* Disable radio.
*/
rt2x00lib_disable_radio(rt2x00dev);
^ permalink raw reply related
* [PATCH 2.6.31] cfg80211: add two missing NULL pointer checks
From: Johannes Berg @ 2009-07-29 20:07 UTC (permalink / raw)
To: John Linville; +Cc: linux-wireless
These pointers can be NULL, the is_mesh() case isn't
ever hit in the current kernel, but cmp_ies() can be
hit under certain conditions.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Cc: stable@kernel.org [2.6.29, 2.6.30]
---
net/wireless/scan.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
--- wireless-testing.orig/net/wireless/scan.c 2009-07-29 21:53:49.000000000 +0200
+++ wireless-testing/net/wireless/scan.c 2009-07-29 21:57:27.000000000 +0200
@@ -141,7 +141,7 @@ static int cmp_ies(u8 num, u8 *ies1, siz
if (!ie1 && !ie2)
return 0;
- if (!ie1)
+ if (!ie1 || !ie2)
return -1;
r = memcmp(ie1 + 2, ie2 + 2, min(ie1[1], ie2[1]));
@@ -194,6 +194,8 @@ static bool is_mesh(struct cfg80211_bss
ie = find_ie(WLAN_EID_MESH_CONFIG,
a->information_elements,
a->len_information_elements);
+ if (!ie)
+ return false;
if (ie[1] != IEEE80211_MESH_CONFIG_LEN)
return false;
^ permalink raw reply
* Re: [PATCH 2/2] ath5k: fix CAB queue operation
From: Nick Kossifidis @ 2009-07-29 20:06 UTC (permalink / raw)
To: Bob Copeland; +Cc: linville, jirislaby, lrodriguez, linux-wireless, ath5k-devel
In-Reply-To: <1248877744-7273-2-git-send-email-me@bobcopeland.com>
2009/7/29 Bob Copeland <me@bobcopeland.com>:
> We need to process tx descriptors for all queues (currently main tx
> queue and cabq) which may have triggered the TX completion interrupt.
> Otherwise, the queues can get stuck after sending a few frames.
>
> Also, the CAB queue does need to be DBA (DMA beacon alert) gated, as
> in ath9k and madwifi, instead of beacon sent gated or the CAB frames
> may not be sent at the right time.
>
I think we are doing the wrong thing, CAB queue is supposed to fire
after beacon queue. Ath9k fires up cab queue and beacon queue at the
same time and uses ready time to hold cab queue for a fixed interval.
Try to remove the readytime stuff from cab queue and i guess it'll
work fine (now we fire it after the beacon queue AND wait for a beacon
transmition period).
--
GPG ID: 0xD21DB2DB
As you read this post global entropy rises. Have Fun ;-)
Nick
^ permalink raw reply
* Re: [PATCH v3] mac80211: redefine usage of the mac80211 workqueue
From: John W. Linville @ 2009-07-29 20:00 UTC (permalink / raw)
To: Luis R. Rodriguez; +Cc: linux-wireless
In-Reply-To: <1248733291-10848-1-git-send-email-lrodriguez@atheros.com>
On Mon, Jul 27, 2009 at 03:21:31PM -0700, Luis R. Rodriguez wrote:
> The mac80211 workqueue exists to enable mac80211 and drivers
> to queue their own work on a single threaded workqueue. mac80211
> takes care to flush the workqueue during suspend but we never
> really had requirements on drivers for how they should use
> the workqueue in consideration for suspend.
>
> We extend mac80211 to document how the mac80211 workqueue should
> be used, how it should not be used and finally move raw access to
> the workqueue to mac80211 only. Drivers and mac80211 use helpers
> to queue work onto the mac80211 workqueue:
>
> * ieee80211_queue_work()
> * ieee80211_queue_delayed_work()
>
> These helpers will now warn if mac80211 already completed its
> suspend cycle and someone is trying to queue work. mac80211
> flushes the mac80211 workqueue prior to suspend a few times,
> but we haven't taken the care to ensure drivers won't add more
> work after suspend. To help with this we add a warning when
> someone tries to add work and mac80211 already completed the
> suspend cycle.
>
> Drivers should ensure they cancel any work or delayed work
> in the mac80211 stop() callback.
How are they supposed to do that after you've removed workqueue
from the ieee80211_hw structure? This breaks the compilation of
at76c50x-usb.c...
John
--
John W. Linville Someday the world will need a hero, and you
linville@tuxdriver.com might be all we have. Be ready.
¡Viva Honduras Libre!
^ permalink raw reply
* Re: [ath5k-devel] [PATCH 2/2] ath5k: fix CAB queue operation
From: Bob Copeland @ 2009-07-29 20:30 UTC (permalink / raw)
To: Nick Kossifidis; +Cc: linux-wireless, ath5k-devel, linville, jirislaby
In-Reply-To: <40f31dec0907291306q7e19c9fdib7e9a6dcab89ac21@mail.gmail.com>
On Wed, Jul 29, 2009 at 4:06 PM, Nick Kossifidis<mickflemm@gmail.com> wrote:
> 2009/7/29 Bob Copeland <me@bobcopeland.com>:
> I think we are doing the wrong thing, CAB queue is supposed to fire
> after beacon queue. Ath9k fires up cab queue and beacon queue at the
> same time and uses ready time to hold cab queue for a fixed interval.
> Try to remove the readytime stuff from cab queue and i guess it'll
> work fine (now we fire it after the beacon queue AND wait for a beacon
> transmition period).
Yeah I was getting almost no delivery of buffered frames without that
change, but I didn't check the delivery time to see if they were too
late, which they probably are.
So you are saying keep BCN_SENT_GT, but remove this:
ath5k_hw_reg_write(ah, ((AR5K_TUNE_BEACON_INTERVAL -
(AR5K_TUNE_SW_BEACON_RESP -
AR5K_TUNE_DMA_BEACON_RESP) -
AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
AR5K_QCU_RDYTIMECFG_ENABLE,
AR5K_QUEUE_RDYTIMECFG(queue));
I'll give it ago. Maybe split that part out because the process tx
queue fix is obvious enough.
(Now I see that the similar-to-above-stuff from madwifi is only compat
code and also uses a readyTime like ath9k. Ah.)
--
Bob Copeland %% www.bobcopeland.com
^ permalink raw reply
* Re: [PATCH v3] mac80211: redefine usage of the mac80211 workqueue
From: Luis R. Rodriguez @ 2009-07-29 20:45 UTC (permalink / raw)
To: John W. Linville; +Cc: linux-wireless
In-Reply-To: <20090729200036.GA10056@tuxdriver.com>
On Wed, Jul 29, 2009 at 1:00 PM, John W. Linville<linville@tuxdriver.com> wrote:
> On Mon, Jul 27, 2009 at 03:21:31PM -0700, Luis R. Rodriguez wrote:
>> The mac80211 workqueue exists to enable mac80211 and drivers
>> to queue their own work on a single threaded workqueue. mac80211
>> takes care to flush the workqueue during suspend but we never
>> really had requirements on drivers for how they should use
>> the workqueue in consideration for suspend.
>>
>> We extend mac80211 to document how the mac80211 workqueue should
>> be used, how it should not be used and finally move raw access to
>> the workqueue to mac80211 only. Drivers and mac80211 use helpers
>> to queue work onto the mac80211 workqueue:
>>
>> * ieee80211_queue_work()
>> * ieee80211_queue_delayed_work()
>>
>> These helpers will now warn if mac80211 already completed its
>> suspend cycle and someone is trying to queue work. mac80211
>> flushes the mac80211 workqueue prior to suspend a few times,
>> but we haven't taken the care to ensure drivers won't add more
>> work after suspend. To help with this we add a warning when
>> someone tries to add work and mac80211 already completed the
>> suspend cycle.
>>
>> Drivers should ensure they cancel any work or delayed work
>> in the mac80211 stop() callback.
>
> How are they supposed to do that after you've removed workqueue
> from the ieee80211_hw structure?
They do not refer to the mac80211 workqueue for that, they can cancel
work using cancel_work_sync(their_foo_work_struct).
> This breaks the compilation of
> at76c50x-usb.c...
Strange, I thought I tested that, will retest,
Luis
^ permalink raw reply
* pull request: wireless-2.6 2009-07-29
From: John W. Linville @ 2009-07-29 20:30 UTC (permalink / raw)
To: davem; +Cc: linux-wireless, netdev, linux-kernel
Dave,
Here is a small collection of fixes intended for 2.6.31. Several of
them are small fixes dug-out by the usual static analysis suspects.
There are also a couple of iwlwifi fixes that the Intel team thinks are
important -- they look reasonably safe to me and they should only effect
their drivers. Their are also some small fixes from Luis and Johannes.
Please let me know if there are problems!
Thanks,
John
---
Individual patches are available here:
http://www.kernel.org/pub/linux/kernel/people/linville/wireless-2.6/
---
The following changes since commit 8bae1b2b13beb4cf4c0f119f97640503c2b74b0f:
Don Skidmore (1):
ixgbe: fix for 82599 errata marking UDP checksum errors
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git master
Dan Carpenter (1):
wireless: ERR_PTR vs null
Johannes Berg (2):
iwlwifi: fix TX queue race
mac80211: fix suspend
Luis R. Rodriguez (1):
mac80211: do not queue work after suspend in the dynamic ps timer
Roel Kluin (5):
airo: Buffer overflow
ath9k: Read outside array bounds
iwlwifi: Read outside array bounds
libertas: Read outside array bounds
libertas: Read buffer overflow
reinette chatre (1):
iwlagn: fix minimum number of queues setting
drivers/net/wireless/airo.c | 13 ++++++-------
drivers/net/wireless/ath/ath9k/eeprom.c | 4 ++--
drivers/net/wireless/iwlwifi/iwl-3945.h | 2 +-
drivers/net/wireless/iwlwifi/iwl-dev.h | 6 ++++--
drivers/net/wireless/iwlwifi/iwl-tx.c | 14 ++++++++------
drivers/net/wireless/iwlwifi/iwl3945-base.c | 4 ++--
drivers/net/wireless/iwmc3200wifi/netdev.c | 6 ++----
drivers/net/wireless/libertas/assoc.c | 18 ++++++++----------
drivers/net/wireless/libertas/scan.c | 3 ++-
net/mac80211/mlme.c | 2 +-
net/mac80211/pm.c | 24 +++++++++++++++---------
net/mac80211/rx.c | 12 ++++++++++++
12 files changed, 63 insertions(+), 45 deletions(-)
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index c70604f..8ce5e4c 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -5918,20 +5918,19 @@ static int airo_set_essid(struct net_device *dev,
readSsidRid(local, &SSID_rid);
/* Check if we asked for `any' */
- if(dwrq->flags == 0) {
+ if (dwrq->flags == 0) {
/* Just send an empty SSID list */
memset(&SSID_rid, 0, sizeof(SSID_rid));
} else {
- int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+ unsigned index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
/* Check the size of the string */
- if(dwrq->length > IW_ESSID_MAX_SIZE) {
+ if (dwrq->length > IW_ESSID_MAX_SIZE)
return -E2BIG ;
- }
+
/* Check if index is valid */
- if((index < 0) || (index >= 4)) {
+ if (index >= ARRAY_SIZE(SSID_rid.ssids))
return -EINVAL;
- }
/* Set the SSID */
memset(SSID_rid.ssids[index].ssid, 0,
@@ -6819,7 +6818,7 @@ static int airo_set_txpow(struct net_device *dev,
return -EINVAL;
}
clear_bit (FLAG_RADIO_OFF, &local->flags);
- for (i = 0; cap_rid.txPowerLevels[i] && (i < 8); i++)
+ for (i = 0; i < 8 && cap_rid.txPowerLevels[i]; i++)
if (v == cap_rid.txPowerLevels[i]) {
readConfigRid(local, 1);
local->config.txPower = v;
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index a2fda70..ce0e86c 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -460,7 +460,7 @@ static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah)
integer = swab32(eep->modalHeader.antCtrlCommon);
eep->modalHeader.antCtrlCommon = integer;
- for (i = 0; i < AR5416_MAX_CHAINS; i++) {
+ for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) {
integer = swab32(eep->modalHeader.antCtrlChain[i]);
eep->modalHeader.antCtrlChain[i] = integer;
}
@@ -914,7 +914,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
ctlMode, numCtlModes, isHt40CtlMode,
(pCtlMode[ctlMode] & EXT_ADDITIVE));
- for (i = 0; (i < AR5416_NUM_CTLS) &&
+ for (i = 0; (i < AR5416_EEP4K_NUM_CTLS) &&
pEepData->ctlIndex[i]; i++) {
DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
" LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index fbb3a57..2de6471 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -112,7 +112,7 @@ enum iwl3945_antenna {
#define IWL_TX_FIFO_NONE 7
/* Minimum number of queues. MAX_NUM is defined in hw specific files */
-#define IWL_MIN_NUM_QUEUES 4
+#define IWL39_MIN_NUM_QUEUES 4
#define IEEE80211_DATA_LEN 2304
#define IEEE80211_4ADDR_LEN 30
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index e2d620f..650e20a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -258,8 +258,10 @@ struct iwl_channel_info {
#define IWL_TX_FIFO_HCCA_2 6
#define IWL_TX_FIFO_NONE 7
-/* Minimum number of queues. MAX_NUM is defined in hw specific files */
-#define IWL_MIN_NUM_QUEUES 4
+/* Minimum number of queues. MAX_NUM is defined in hw specific files.
+ * Set the minimum to accommodate the 4 standard TX queues, 1 command
+ * queue, 2 (unused) HCCA queues, and 4 HT queues (one for each AC) */
+#define IWL_MIN_NUM_QUEUES 10
/* Power management (not Tx power) structures */
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 9bbeec9..2e89040 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -720,8 +720,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
goto drop_unlock;
}
- spin_unlock_irqrestore(&priv->lock, flags);
-
hdr_len = ieee80211_hdrlen(fc);
/* Find (or create) index into station table for destination station */
@@ -729,7 +727,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
hdr->addr1);
- goto drop;
+ goto drop_unlock;
}
IWL_DEBUG_TX(priv, "station Id %d\n", sta_id);
@@ -750,14 +748,17 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
swq_id = iwl_virtual_agg_queue_num(swq_id, txq_id);
}
- priv->stations[sta_id].tid[tid].tfds_in_queue++;
}
txq = &priv->txq[txq_id];
q = &txq->q;
txq->swq_id = swq_id;
- spin_lock_irqsave(&priv->lock, flags);
+ if (unlikely(iwl_queue_space(q) < q->high_mark))
+ goto drop_unlock;
+
+ if (ieee80211_is_data_qos(fc))
+ priv->stations[sta_id].tid[tid].tfds_in_queue++;
/* Set up driver data for this TFD */
memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
@@ -902,7 +903,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
drop_unlock:
spin_unlock_irqrestore(&priv->lock, flags);
-drop:
return -1;
}
EXPORT_SYMBOL(iwl_tx_skb);
@@ -1171,6 +1171,8 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn)
IWL_ERR(priv, "Start AGG on invalid station\n");
return -ENXIO;
}
+ if (unlikely(tid >= MAX_TID_COUNT))
+ return -EINVAL;
if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) {
IWL_ERR(priv, "Start AGG when state is not IWL_AGG_OFF !\n");
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 956798f..2f50ab6 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -4018,10 +4018,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
SET_IEEE80211_DEV(hw, &pdev->dev);
if ((iwl3945_mod_params.num_of_queues > IWL39_MAX_NUM_QUEUES) ||
- (iwl3945_mod_params.num_of_queues < IWL_MIN_NUM_QUEUES)) {
+ (iwl3945_mod_params.num_of_queues < IWL39_MIN_NUM_QUEUES)) {
IWL_ERR(priv,
"invalid queues_num, should be between %d and %d\n",
- IWL_MIN_NUM_QUEUES, IWL39_MAX_NUM_QUEUES);
+ IWL39_MIN_NUM_QUEUES, IWL39_MAX_NUM_QUEUES);
err = -EINVAL;
goto out_ieee80211_free_hw;
}
diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c
index aea5ccf..bf294e4 100644
--- a/drivers/net/wireless/iwmc3200wifi/netdev.c
+++ b/drivers/net/wireless/iwmc3200wifi/netdev.c
@@ -106,10 +106,8 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
int ret = 0;
wdev = iwm_wdev_alloc(sizeof_bus, dev);
- if (!wdev) {
- dev_err(dev, "no memory for wireless device instance\n");
- return ERR_PTR(-ENOMEM);
- }
+ if (IS_ERR(wdev))
+ return wdev;
iwm = wdev_to_iwm(wdev);
iwm->bus_ops = if_ops;
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index b9b3741..d699737 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -1,6 +1,7 @@
/* Copyright (C) 2006, Red Hat, Inc. */
#include <linux/types.h>
+#include <linux/kernel.h>
#include <linux/etherdevice.h>
#include <linux/ieee80211.h>
#include <linux/if_arp.h>
@@ -43,21 +44,21 @@ static int get_common_rates(struct lbs_private *priv,
u16 *rates_size)
{
u8 *card_rates = lbs_bg_rates;
- size_t num_card_rates = sizeof(lbs_bg_rates);
int ret = 0, i, j;
- u8 tmp[30];
+ u8 tmp[(ARRAY_SIZE(lbs_bg_rates) - 1) * (*rates_size - 1)];
size_t tmp_size = 0;
/* For each rate in card_rates that exists in rate1, copy to tmp */
- for (i = 0; card_rates[i] && (i < num_card_rates); i++) {
- for (j = 0; rates[j] && (j < *rates_size); j++) {
+ for (i = 0; i < ARRAY_SIZE(lbs_bg_rates) && card_rates[i]; i++) {
+ for (j = 0; j < *rates_size && rates[j]; j++) {
if (rates[j] == card_rates[i])
tmp[tmp_size++] = card_rates[i];
}
}
lbs_deb_hex(LBS_DEB_JOIN, "AP rates ", rates, *rates_size);
- lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates, num_card_rates);
+ lbs_deb_hex(LBS_DEB_JOIN, "card rates ", card_rates,
+ ARRAY_SIZE(lbs_bg_rates));
lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
lbs_deb_join("TX data rate 0x%02x\n", priv->cur_rate);
@@ -69,10 +70,7 @@ static int get_common_rates(struct lbs_private *priv,
lbs_pr_alert("Previously set fixed data rate %#x isn't "
"compatible with the network.\n", priv->cur_rate);
ret = -1;
- goto done;
}
- ret = 0;
-
done:
memset(rates, 0, *rates_size);
*rates_size = min_t(int, tmp_size, *rates_size);
@@ -322,7 +320,7 @@ static int lbs_associate(struct lbs_private *priv,
rates = (struct mrvl_ie_rates_param_set *) pos;
rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
memcpy(&rates->rates, &bss->rates, MAX_RATES);
- tmplen = MAX_RATES;
+ tmplen = min_t(u16, ARRAY_SIZE(rates->rates), MAX_RATES);
if (get_common_rates(priv, rates->rates, &tmplen)) {
ret = -1;
goto done;
@@ -598,7 +596,7 @@ static int lbs_adhoc_join(struct lbs_private *priv,
/* Copy Data rates from the rates recorded in scan response */
memset(cmd.bss.rates, 0, sizeof(cmd.bss.rates));
- ratesize = min_t(u16, sizeof(cmd.bss.rates), MAX_RATES);
+ ratesize = min_t(u16, ARRAY_SIZE(cmd.bss.rates), MAX_RATES);
memcpy(cmd.bss.rates, bss->rates, ratesize);
if (get_common_rates(priv, cmd.bss.rates, &ratesize)) {
lbs_deb_join("ADHOC_JOIN: get_common_rates returned error.\n");
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index 601b542..6c95af3 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -5,6 +5,7 @@
* for sending scan commands to the firmware.
*/
#include <linux/types.h>
+#include <linux/kernel.h>
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
#include <asm/unaligned.h>
@@ -876,7 +877,7 @@ static inline char *lbs_translate_scan(struct lbs_private *priv,
iwe.u.bitrate.disabled = 0;
iwe.u.bitrate.value = 0;
- for (j = 0; bss->rates[j] && (j < sizeof(bss->rates)); j++) {
+ for (j = 0; j < ARRAY_SIZE(bss->rates) && bss->rates[j]; j++) {
/* Bit rate given in 500 kb/s units */
iwe.u.bitrate.value = bss->rates[j] * 500000;
current_val = iwe_stream_add_value(info, start, current_val,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index aca22b0..07e7e41 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -721,7 +721,7 @@ void ieee80211_dynamic_ps_timer(unsigned long data)
{
struct ieee80211_local *local = (void *) data;
- if (local->quiescing)
+ if (local->quiescing || local->suspended)
return;
queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work);
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index 7a549f9..5e3d476 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -55,15 +55,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
rcu_read_unlock();
- /* flush again, in case driver queued work */
- flush_workqueue(local->hw.workqueue);
-
- /* stop hardware - this must stop RX */
- if (local->open_count) {
- ieee80211_led_radio(local, false);
- drv_stop(local);
- }
-
/* remove STAs */
spin_lock_irqsave(&local->sta_lock, flags);
list_for_each_entry(sta, &local->sta_list, list) {
@@ -111,7 +102,22 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
drv_remove_interface(local, &conf);
}
+ /* stop hardware - this must stop RX */
+ if (local->open_count) {
+ ieee80211_led_radio(local, false);
+ drv_stop(local);
+ }
+
+ /*
+ * flush again, in case driver queued work -- it
+ * shouldn't be doing (or cancel everything in the
+ * stop callback) that but better safe than sorry.
+ */
+ flush_workqueue(local->hw.workqueue);
+
local->suspended = true;
+ /* need suspended to be visible before quiescing is false */
+ barrier();
local->quiescing = false;
return 0;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index de5bba7..0936fc2 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2453,6 +2453,18 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
return;
}
+ /*
+ * If we're suspending, it is possible although not too likely
+ * that we'd be receiving frames after having already partially
+ * quiesced the stack. We can't process such frames then since
+ * that might, for example, cause stations to be added or other
+ * driver callbacks be invoked.
+ */
+ if (unlikely(local->quiescing || local->suspended)) {
+ kfree_skb(skb);
+ return;
+ }
+
if (status->flag & RX_FLAG_HT) {
/* rate_idx is MCS index */
if (WARN_ON(status->rate_idx < 0 ||
--
John W. Linville Someday the world will need a hero, and you
linville@tuxdriver.com might be all we have. Be ready.
¡Viva Honduras Libre!
^ permalink raw reply related
* pull request: wireless-next-2.6 2009-07-29
From: John W. Linville @ 2009-07-29 20:54 UTC (permalink / raw)
To: davem; +Cc: linux-wireless, netdev
Dave,
Here is another batch of wireless bits intended for 2.6.32... Once
again, there is no particular theme to the bunch. This does cover the
usual round of driver updates for iwlwifi, ath9k, and others. There are
also some mac80211 and cfg80211 updates, including the final piece for
cfg80211 to supplant wireless extensions -- hooray!
Please let me know if there are problems!
John
P.S. There is a merge-test branch that contains sample merge conflict
resolutions. They are mostly simple.
---
Individual patches are available here:
http://www.kernel.org/pub/linux/kernel/people/linville/wireless-next-2.6/
---
The following changes since commit 70034918930d2e5b68c09bced637228c50d9561a:
Stephen Rothwell (1):
net: fix multiple definitions of setup_w6692
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6.git master
Alexander Beregalov (1):
ar9170: fix build error when !CONFIG_AR9170_LEDS
Gabor Juhos (2):
ath9k: fix race with IEEE80211_CONF_PS checks
ath9k: get rid of unnecessary setpower calls
Helmut Schaa (8):
mac80211: refactor the scan code
mac80211: advance the state machine immediately if no delay is needed
mac80211: introduce a new scan state "decision"
mac80211: Replace {sw, hw}_scanning variables with a bitfield
mac80211: implement basic background scanning
mac80211: rename scan_state to next_scan_state
cfg80211: increase scan result expire time
mac80211: fix an oops in ieee80211_scan_state_set_channel
Johannes Berg (16):
mac80211: cooperate more with network namespaces
cfg80211: make aware of net namespaces
mac80211: allow using network namespaces
mac80211: fix mlme timeouts
mac80211: fix PS-poll response, race
iwlwifi: fix up command sending
iwlwifi: remove command callback return value
cfg80211: fix circular lock dependency (1)
mac80211: fix receiving deauth
nl80211: add missing parameter clearing
cfg80211: fix disassoc while not associated
mac80211: verify info->control.vif is not NULL
cfg80211: combine iwfreq implementations
cfg80211: combine IWAP handlers
cfg80211: combine IWESSID handlers
cfg80211: self-contained wext handling where possible
John W. Linville (1):
ray_cs: remove bogus NULL check at head of ray_get_wireless_stats
Lars Ericsson (1):
rt2x00: Don't alter rt2x00dev->default_ant
Luis R. Rodriguez (4):
ath: map TH to FCC3_WORLD
mac80211: fix MLME issuing of probe requests while scanning
mac80211: fix oops due to missing private data
ath9k: remove unused ATH_PCI_VERSION
Pavel Machek (1):
iwlwifi: fix LED config option
Reinette Chatre (3):
iwlwifi: print packet contents in error case
iwlagn: fix null pointer access during ucode load on 1000
iwlagn: fix sparse warning when compiling without debug
Sujith (7):
mac80211: Add a few 802.11n defines for AMPDU parameters
ath9k: Trivial fix in Kconfig
ath9k: Fix a sparse warning
ath9k: Remove redundant HT macros
ath9k: Cleanup return values
ath9k: Remove a few redundant variables/macros
ath9k: Add debug counters for TX
Vivek Natarajan (2):
ath9k: Add init values for AR9287 based chipsets.
ath9k: Add support for AR9287 based chipsets.
Wey-Yi Guy (7):
iwlwifi: revert to active table when rate is not valid
iwlwifi: critical temperature enter/exit condition
iwlwifi: Thermal Throttling Management - Part 1
iwlwifi: Thermal Throttling Management - part 2
iwlwifi: Thermal Throttling debugfs function
iwlwifi: Name fix for MPDU density for TX aggregation
iwlwifi: debugFs to enable/disable HT40 support
drivers/net/wireless/ath/ar9170/main.c | 2 +
drivers/net/wireless/ath/ath9k/Kconfig | 4 +-
drivers/net/wireless/ath/ath9k/ath9k.h | 11 +-
drivers/net/wireless/ath/ath9k/calib.c | 22 +-
drivers/net/wireless/ath/ath9k/debug.c | 85 ++
drivers/net/wireless/ath/ath9k/debug.h | 54 +
drivers/net/wireless/ath/ath9k/eeprom.c | 1203 +++++++++++++++++++++-
drivers/net/wireless/ath/ath9k/eeprom.h | 163 +++-
drivers/net/wireless/ath/ath9k/hw.c | 133 ++-
drivers/net/wireless/ath/ath9k/hw.h | 5 +-
drivers/net/wireless/ath/ath9k/initvals.h | 1516 +++++++++++++++++++++++++++
drivers/net/wireless/ath/ath9k/main.c | 35 +-
drivers/net/wireless/ath/ath9k/pci.c | 2 +
drivers/net/wireless/ath/ath9k/phy.h | 1 +
drivers/net/wireless/ath/ath9k/xmit.c | 85 +-
drivers/net/wireless/ath/regd_common.h | 2 +-
drivers/net/wireless/iwlwifi/Kconfig | 3 +
drivers/net/wireless/iwlwifi/iwl-1000.c | 77 ++-
drivers/net/wireless/iwlwifi/iwl-3945-led.c | 11 +-
drivers/net/wireless/iwlwifi/iwl-3945.c | 18 +-
drivers/net/wireless/iwlwifi/iwl-3945.h | 9 +-
drivers/net/wireless/iwlwifi/iwl-4965.c | 4 +-
drivers/net/wireless/iwlwifi/iwl-5000.c | 45 +-
drivers/net/wireless/iwlwifi/iwl-6000.c | 59 +-
drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 85 ++-
drivers/net/wireless/iwlwifi/iwl-agn.c | 23 +-
drivers/net/wireless/iwlwifi/iwl-calib.c | 4 +-
drivers/net/wireless/iwlwifi/iwl-commands.h | 7 +
drivers/net/wireless/iwlwifi/iwl-core.c | 35 +-
drivers/net/wireless/iwlwifi/iwl-core.h | 6 +-
drivers/net/wireless/iwlwifi/iwl-debug.h | 2 +
drivers/net/wireless/iwlwifi/iwl-debugfs.c | 84 ++
drivers/net/wireless/iwlwifi/iwl-dev.h | 116 ++-
drivers/net/wireless/iwlwifi/iwl-hcmd.c | 63 +-
drivers/net/wireless/iwlwifi/iwl-led.c | 4 +-
drivers/net/wireless/iwlwifi/iwl-power.c | 526 ++++++++++
drivers/net/wireless/iwlwifi/iwl-power.h | 93 ++
drivers/net/wireless/iwlwifi/iwl-scan.c | 8 +-
drivers/net/wireless/iwlwifi/iwl-sta.c | 48 +-
drivers/net/wireless/iwlwifi/iwl-tx.c | 100 ++-
drivers/net/wireless/iwlwifi/iwl3945-base.c | 20 +-
drivers/net/wireless/iwmc3200wifi/Kconfig | 1 -
drivers/net/wireless/iwmc3200wifi/Makefile | 2 +-
drivers/net/wireless/iwmc3200wifi/iwm.h | 2 -
drivers/net/wireless/iwmc3200wifi/netdev.c | 1 -
drivers/net/wireless/iwmc3200wifi/wext.c | 187 ----
drivers/net/wireless/p54/txrx.c | 2 +-
drivers/net/wireless/ray_cs.c | 3 -
drivers/net/wireless/rt2x00/rt2x00config.c | 12 +-
drivers/net/wireless/rt2x00/rt2x00lib.h | 2 +-
drivers/net/wireless/rt2x00/rt2x00link.c | 4 +-
drivers/net/wireless/rt2x00/rt2x00mac.c | 2 +-
include/linux/ieee80211.h | 25 +
include/linux/nl80211.h | 9 +
include/net/cfg80211.h | 104 +-
include/net/mac80211.h | 4 +
net/core/dev.c | 1 +
net/mac80211/Kconfig | 1 -
net/mac80211/Makefile | 1 -
net/mac80211/cfg.c | 14 +-
net/mac80211/ibss.c | 2 +-
net/mac80211/ieee80211_i.h | 45 +-
net/mac80211/iface.c | 22 +-
net/mac80211/main.c | 3 +-
net/mac80211/mesh.c | 2 +-
net/mac80211/mlme.c | 35 +-
net/mac80211/rx.c | 21 +-
net/mac80211/scan.c | 304 ++++--
net/mac80211/sta_info.h | 13 -
net/mac80211/tx.c | 109 +--
net/mac80211/util.c | 13 +
net/mac80211/wext.c | 235 -----
net/wireless/core.c | 78 ++-
net/wireless/core.h | 8 +-
net/wireless/ibss.c | 13 +-
net/wireless/mlme.c | 8 +
net/wireless/nl80211.c | 206 +++--
net/wireless/scan.c | 25 +-
net/wireless/sme.c | 5 +-
net/wireless/wext-compat.c | 180 +++-
net/wireless/wext-compat.h | 50 +
net/wireless/wext-sme.c | 13 +-
82 files changed, 5381 insertions(+), 1159 deletions(-)
delete mode 100644 drivers/net/wireless/iwmc3200wifi/wext.c
delete mode 100644 net/mac80211/wext.c
create mode 100644 net/wireless/wext-compat.h
Omnibus patch is available here:
http://www.kernel.org/pub/linux/kernel/people/linville/wireless-next-2.6-2009-07-29.patch.bz2
--
John W. Linville Someday the world will need a hero, and you
linville@tuxdriver.com might be all we have. Be ready.
¡Viva Honduras Libre!
^ permalink raw reply
* Re: ath5k connection loss (failed to wakeup the MAC Chip)
From: Nick Kossifidis @ 2009-07-29 21:07 UTC (permalink / raw)
To: Ben Greear; +Cc: Adrian von Bidder, linux-wireless
In-Reply-To: <4A709E55.2070909@candelatech.com>
2009/7/29 Ben Greear <greearb@candelatech.com>:
> I'm not sure if it helps, but if I:
>
> load ath5k and let some stations associate (I'm testing virtual
> STA logic)
>
> .. wait a bit ...
>
> rmmod ath5k; modprobe ath5k
>
> then it fails to wakeup the MAC chip every time.
>
> But, if I then wait a few seconds, and repeat the rmmod/modprobe commands,
> then it wakes
> up and works fine.
>
> I'm running a hacked kernel (and ath5k/wifi stack), so could be something
> I'm doing wrong, but just maybe it will give you a reproducible test
> case...
>
> Thanks,
> Ben
>
Patch on the way ;-)
--
GPG ID: 0xD21DB2DB
As you read this post global entropy rises. Have Fun ;-)
Nick
^ permalink raw reply
* [PATCH 1/2] at76c50x-usb: remove unneeded flush_workqueue() at usb disconnect
From: Luis R. Rodriguez @ 2009-07-29 21:20 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, Luis R. Rodriguez, Kalle Valo
This driver only uses the mac80211 workqueue and mac80211 requires us to
cancel all work at driver stop. Since we now have the cancels in the right
places at stop() we really don't need to flush the mac80211 workqueue so
remove it.
Cc: Kalle Valo <kalle.valo@iki.fi>
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
drivers/net/wireless/at76c50x-usb.c | 4 +---
1 files changed, 1 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index f46e2b3..aff09a1 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -2298,10 +2298,8 @@ static void at76_delete_device(struct at76_priv *priv)
tasklet_kill(&priv->rx_tasklet);
- if (priv->mac80211_registered) {
- flush_workqueue(priv->hw->workqueue);
+ if (priv->mac80211_registered)
ieee80211_unregister_hw(priv->hw);
- }
if (priv->tx_urb) {
usb_kill_urb(priv->tx_urb);
--
1.6.0.4
^ permalink raw reply related
* [PATCH 2/2] mac80211: redefine usage of the mac80211 workqueue
From: Luis R. Rodriguez @ 2009-07-29 21:20 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, Luis R. Rodriguez
In-Reply-To: <1248902442-14621-1-git-send-email-lrodriguez@atheros.com>
The mac80211 workqueue exists to enable mac80211 and drivers
to queue their own work on a single threaded workqueue. mac80211
takes care to flush the workqueue during suspend but we never
really had requirements on drivers for how they should use
the workqueue in consideration for suspend.
We extend mac80211 to document how the mac80211 workqueue should
be used, how it should not be used and finally move raw access to
the workqueue to mac80211 only. Drivers and mac80211 use helpers
to queue work onto the mac80211 workqueue:
* ieee80211_queue_work()
* ieee80211_queue_delayed_work()
These helpers will now warn if mac80211 already completed its
suspend cycle and someone is trying to queue work. mac80211
flushes the mac80211 workqueue prior to suspend a few times,
but we haven't taken the care to ensure drivers won't add more
work after suspend. To help with this we add a warning when
someone tries to add work and mac80211 already completed the
suspend cycle.
Drivers should ensure they cancel any work or delayed work
in the mac80211 stop() callback.
Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
drivers/net/wireless/at76c50x-usb.c | 10 +++---
drivers/net/wireless/ath/ar9170/led.c | 11 ++++--
drivers/net/wireless/ath/ar9170/main.c | 26 ++++++++------
drivers/net/wireless/ath/ath9k/main.c | 15 ++++----
drivers/net/wireless/ath/ath9k/virtual.c | 17 +++++----
drivers/net/wireless/ath/ath9k/xmit.c | 2 +-
drivers/net/wireless/b43/main.c | 8 ++--
drivers/net/wireless/b43/phy_common.c | 2 +-
drivers/net/wireless/b43/pio.c | 2 +-
drivers/net/wireless/b43legacy/main.c | 8 ++--
drivers/net/wireless/p54/led.c | 5 +--
drivers/net/wireless/p54/main.c | 2 +-
drivers/net/wireless/p54/p54spi.c | 4 +-
drivers/net/wireless/p54/txrx.c | 2 +-
drivers/net/wireless/rt2x00/rt2x00dev.c | 2 +-
drivers/net/wireless/rt2x00/rt2x00link.c | 8 ++--
drivers/net/wireless/rt2x00/rt2x00mac.c | 2 +-
drivers/net/wireless/rtl818x/rtl8187_dev.c | 2 +-
drivers/net/wireless/rtl818x/rtl8187_leds.c | 10 +++---
include/net/mac80211.h | 50 ++++++++++++++++++++++----
net/mac80211/ibss.c | 6 ++--
net/mac80211/ieee80211_i.h | 6 +++
net/mac80211/iface.c | 4 +-
net/mac80211/main.c | 8 ++--
net/mac80211/mesh.c | 10 +++---
net/mac80211/mesh_hwmp.c | 4 +-
net/mac80211/mlme.c | 48 ++++++++++++--------------
net/mac80211/pm.c | 2 +-
net/mac80211/scan.c | 8 ++--
net/mac80211/tx.c | 2 +-
net/mac80211/util.c | 41 ++++++++++++++++++++++
31 files changed, 206 insertions(+), 121 deletions(-)
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index aff09a1..7218dba 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -1875,8 +1875,8 @@ static void at76_dwork_hw_scan(struct work_struct *work)
/* FIXME: add maximum time for scan to complete */
if (ret != CMD_STATUS_COMPLETE) {
- queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan,
- SCAN_POLL_INTERVAL);
+ ieee80211_queue_delayed_work(priv->hw, &priv->dwork_hw_scan,
+ SCAN_POLL_INTERVAL);
mutex_unlock(&priv->mtx);
return;
}
@@ -1937,8 +1937,8 @@ static int at76_hw_scan(struct ieee80211_hw *hw,
goto exit;
}
- queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan,
- SCAN_POLL_INTERVAL);
+ ieee80211_queue_delayed_work(priv->hw, &priv->dwork_hw_scan,
+ SCAN_POLL_INTERVAL);
exit:
mutex_unlock(&priv->mtx);
@@ -2027,7 +2027,7 @@ static void at76_configure_filter(struct ieee80211_hw *hw,
} else
return;
- queue_work(hw->workqueue, &priv->work_set_promisc);
+ ieee80211_queue_work(hw, &priv->work_set_promisc);
}
static int at76_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
diff --git a/drivers/net/wireless/ath/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c
index 63fda6c..86c4e79 100644
--- a/drivers/net/wireless/ath/ar9170/led.c
+++ b/drivers/net/wireless/ath/ar9170/led.c
@@ -90,9 +90,12 @@ static void ar9170_update_leds(struct work_struct *work)
ar9170_set_leds_state(ar, led_val);
mutex_unlock(&ar->mutex);
- if (rerun)
- queue_delayed_work(ar->hw->workqueue, &ar->led_work,
- msecs_to_jiffies(blink_delay));
+ if (!rerun)
+ return;
+
+ ieee80211_queue_delayed_work(ar->hw,
+ &ar->led_work,
+ msecs_to_jiffies(blink_delay));
}
static void ar9170_led_brightness_set(struct led_classdev *led,
@@ -110,7 +113,7 @@ static void ar9170_led_brightness_set(struct led_classdev *led,
}
if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled))
- queue_delayed_work(ar->hw->workqueue, &ar->led_work, HZ/10);
+ ieee80211_queue_delayed_work(ar->hw, &ar->led_work, HZ/10);
}
static int ar9170_register_led(struct ar9170 *ar, int i, char *name,
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index 099ed3c..4fc389a 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -595,10 +595,12 @@ static void ar9170_tx_janitor(struct work_struct *work)
ar9170_tx_fake_ampdu_status(ar);
- if (resched)
- queue_delayed_work(ar->hw->workqueue,
- &ar->tx_janitor,
- msecs_to_jiffies(AR9170_JANITOR_DELAY));
+ if (!resched)
+ return;
+
+ ieee80211_queue_delayed_work(ar->hw,
+ &ar->tx_janitor,
+ msecs_to_jiffies(AR9170_JANITOR_DELAY));
}
void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
@@ -648,7 +650,7 @@ void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
* pre-TBTT event
*/
if (ar->vif && ar->vif->type == NL80211_IFTYPE_AP)
- queue_work(ar->hw->workqueue, &ar->beacon_work);
+ ieee80211_queue_work(ar->hw, &ar->beacon_work);
break;
case 0xc2:
@@ -1825,10 +1827,12 @@ static void ar9170_tx(struct ar9170 *ar)
}
}
- if (schedule_garbagecollector)
- queue_delayed_work(ar->hw->workqueue,
- &ar->tx_janitor,
- msecs_to_jiffies(AR9170_JANITOR_DELAY));
+ if (!schedule_garbagecollector)
+ return;
+
+ ieee80211_queue_delayed_work(ar->hw,
+ &ar->tx_janitor,
+ msecs_to_jiffies(AR9170_JANITOR_DELAY));
}
static bool ar9170_tx_ampdu_queue(struct ar9170 *ar, struct sk_buff *skb)
@@ -2157,7 +2161,7 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
}
if (likely(IS_STARTED(ar)))
- queue_work(ar->hw->workqueue, &ar->filter_config_work);
+ ieee80211_queue_work(ar->hw, &ar->filter_config_work);
}
static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
@@ -2415,7 +2419,7 @@ static void ar9170_sta_notify(struct ieee80211_hw *hw,
}
if (IS_STARTED(ar) && ar->filter_changed)
- queue_work(ar->hw->workqueue, &ar->filter_config_work);
+ ieee80211_queue_work(ar->hw, &ar->filter_config_work);
}
static int ar9170_get_stats(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index cf44623..292ac2b 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -973,10 +973,11 @@ static void ath_led_blink_work(struct work_struct *work)
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN,
(sc->sc_flags & SC_OP_LED_ON) ? 1 : 0);
- queue_delayed_work(sc->hw->workqueue, &sc->ath_led_blink_work,
- (sc->sc_flags & SC_OP_LED_ON) ?
- msecs_to_jiffies(sc->led_off_duration) :
- msecs_to_jiffies(sc->led_on_duration));
+ ieee80211_queue_delayed_work(sc->hw,
+ &sc->ath_led_blink_work,
+ (sc->sc_flags & SC_OP_LED_ON) ?
+ msecs_to_jiffies(sc->led_off_duration) :
+ msecs_to_jiffies(sc->led_on_duration));
sc->led_on_duration = sc->led_on_cnt ?
max((ATH_LED_ON_DURATION_IDLE - sc->led_on_cnt), 25) :
@@ -1013,8 +1014,8 @@ static void ath_led_brightness(struct led_classdev *led_cdev,
case LED_FULL:
if (led->led_type == ATH_LED_ASSOC) {
sc->sc_flags |= SC_OP_LED_ASSOCIATED;
- queue_delayed_work(sc->hw->workqueue,
- &sc->ath_led_blink_work, 0);
+ ieee80211_queue_delayed_work(sc->hw,
+ &sc->ath_led_blink_work, 0);
} else if (led->led_type == ATH_LED_RADIO) {
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0);
sc->sc_flags |= SC_OP_LED_ON;
@@ -1972,7 +1973,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
ieee80211_wake_queues(hw);
- queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work, 0);
+ ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
mutex_unlock:
mutex_unlock(&sc->mutex);
diff --git a/drivers/net/wireless/ath/ath9k/virtual.c b/drivers/net/wireless/ath/ath9k/virtual.c
index e1d419e..19b88f8 100644
--- a/drivers/net/wireless/ath/ath9k/virtual.c
+++ b/drivers/net/wireless/ath/ath9k/virtual.c
@@ -351,7 +351,7 @@ void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
* Drop from tasklet to work to allow mutex for channel
* change.
*/
- queue_work(aphy->sc->hw->workqueue,
+ ieee80211_queue_work(aphy->sc->hw,
&aphy->sc->chan_work);
}
}
@@ -367,7 +367,7 @@ static void ath9k_mark_paused(struct ath_wiphy *aphy)
struct ath_softc *sc = aphy->sc;
aphy->state = ATH_WIPHY_PAUSED;
if (!__ath9k_wiphy_pausing(sc))
- queue_work(sc->hw->workqueue, &sc->chan_work);
+ ieee80211_queue_work(sc->hw, &sc->chan_work);
}
static void ath9k_pause_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
@@ -521,7 +521,7 @@ int ath9k_wiphy_select(struct ath_wiphy *aphy)
spin_unlock_bh(&sc->wiphy_lock);
ath_radio_disable(sc);
ath_radio_enable(sc);
- queue_work(aphy->sc->hw->workqueue,
+ ieee80211_queue_work(aphy->sc->hw,
&aphy->sc->chan_work);
return -EBUSY; /* previous select still in progress */
}
@@ -541,7 +541,7 @@ int ath9k_wiphy_select(struct ath_wiphy *aphy)
if (now) {
/* Ready to request channel change immediately */
- queue_work(aphy->sc->hw->workqueue, &aphy->sc->chan_work);
+ ieee80211_queue_work(aphy->sc->hw, &aphy->sc->chan_work);
}
/*
@@ -648,8 +648,9 @@ try_again:
"change\n");
}
- queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work,
- sc->wiphy_scheduler_int);
+ ieee80211_queue_delayed_work(sc->hw,
+ &sc->wiphy_work,
+ sc->wiphy_scheduler_int);
}
void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int)
@@ -657,8 +658,8 @@ void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int)
cancel_delayed_work_sync(&sc->wiphy_work);
sc->wiphy_scheduler_int = msecs_to_jiffies(msec_int);
if (sc->wiphy_scheduler_int)
- queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work,
- sc->wiphy_scheduler_int);
+ ieee80211_queue_delayed_work(sc->hw, &sc->wiphy_work,
+ sc->wiphy_scheduler_int);
}
/* caller must hold wiphy_lock */
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index b7806e2..87762da 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -2063,7 +2063,7 @@ static void ath_tx_complete_poll_work(struct work_struct *work)
ath_reset(sc, false);
}
- queue_delayed_work(sc->hw->workqueue, &sc->tx_complete_work,
+ ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
}
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 3f4360a..f985938 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -1654,7 +1654,7 @@ static void b43_update_templates(struct b43_wl *wl)
wl->current_beacon = beacon;
wl->beacon0_uploaded = 0;
wl->beacon1_uploaded = 0;
- queue_work(wl->hw->workqueue, &wl->beacon_update_trigger);
+ ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger);
}
static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
@@ -2914,7 +2914,7 @@ out_requeue:
delay = msecs_to_jiffies(50);
else
delay = round_jiffies_relative(HZ * 15);
- queue_delayed_work(wl->hw->workqueue, &dev->periodic_work, delay);
+ ieee80211_queue_delayed_work(wl->hw, &dev->periodic_work, delay);
out:
mutex_unlock(&wl->mutex);
}
@@ -2925,7 +2925,7 @@ static void b43_periodic_tasks_setup(struct b43_wldev *dev)
dev->periodic_state = 0;
INIT_DELAYED_WORK(work, b43_periodic_work_handler);
- queue_delayed_work(dev->wl->hw->workqueue, work, 0);
+ ieee80211_queue_delayed_work(dev->wl->hw, work, 0);
}
/* Check if communication with the device works correctly. */
@@ -4871,7 +4871,7 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason)
if (b43_status(dev) < B43_STAT_INITIALIZED)
return;
b43info(dev->wl, "Controller RESET (%s) ...\n", reason);
- queue_work(dev->wl->hw->workqueue, &dev->restart_work);
+ ieee80211_queue_work(dev->wl->hw, &dev->restart_work);
}
#ifdef CONFIG_PM
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
index 6d24162..f537bfe 100644
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -352,7 +352,7 @@ void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags)
/* We must adjust the transmission power in hardware.
* Schedule b43_phy_txpower_adjust_work(). */
- queue_work(dev->wl->hw->workqueue, &dev->wl->txpower_adjust_work);
+ ieee80211_queue_work(dev->wl->hw, &dev->wl->txpower_adjust_work);
}
int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset)
diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c
index 69138e8..73c047d 100644
--- a/drivers/net/wireless/b43/pio.c
+++ b/drivers/net/wireless/b43/pio.c
@@ -783,7 +783,7 @@ void b43_pio_rx(struct b43_pio_rxqueue *q)
{
/* Due to latency issues we must run the RX path in
* a workqueue to be able to schedule between packets. */
- queue_work(q->dev->wl->hw->workqueue, &q->rx_work);
+ ieee80211_queue_work(q->dev->wl->hw, &q->rx_work);
}
static void b43_pio_tx_suspend_queue(struct b43_pio_txqueue *q)
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index c4973c1..b143559 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -1252,7 +1252,7 @@ static void b43legacy_update_templates(struct b43legacy_wl *wl)
wl->current_beacon = beacon;
wl->beacon0_uploaded = 0;
wl->beacon1_uploaded = 0;
- queue_work(wl->hw->workqueue, &wl->beacon_update_trigger);
+ ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger);
}
static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev,
@@ -2300,7 +2300,7 @@ out_requeue:
delay = msecs_to_jiffies(50);
else
delay = round_jiffies_relative(HZ * 15);
- queue_delayed_work(wl->hw->workqueue, &dev->periodic_work, delay);
+ ieee80211_queue_delayed_work(wl->hw, &dev->periodic_work, delay);
out:
mutex_unlock(&wl->mutex);
}
@@ -2311,7 +2311,7 @@ static void b43legacy_periodic_tasks_setup(struct b43legacy_wldev *dev)
dev->periodic_state = 0;
INIT_DELAYED_WORK(work, b43legacy_periodic_work_handler);
- queue_delayed_work(dev->wl->hw->workqueue, work, 0);
+ ieee80211_queue_delayed_work(dev->wl->hw, work, 0);
}
/* Validate access to the chip (SHM) */
@@ -3885,7 +3885,7 @@ void b43legacy_controller_restart(struct b43legacy_wldev *dev,
if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)
return;
b43legacyinfo(dev->wl, "Controller RESET (%s) ...\n", reason);
- queue_work(dev->wl->hw->workqueue, &dev->restart_work);
+ ieee80211_queue_work(dev->wl->hw, &dev->restart_work);
}
#ifdef CONFIG_PM
diff --git a/drivers/net/wireless/p54/led.c b/drivers/net/wireless/p54/led.c
index c00115b..9575ac0 100644
--- a/drivers/net/wireless/p54/led.c
+++ b/drivers/net/wireless/p54/led.c
@@ -61,7 +61,7 @@ static void p54_update_leds(struct work_struct *work)
wiphy_name(priv->hw->wiphy), err);
if (rerun)
- queue_delayed_work(priv->hw->workqueue, &priv->led_work,
+ ieee80211_queue_delayed_work(priv->hw, &priv->led_work,
msecs_to_jiffies(blink_delay));
}
@@ -78,8 +78,7 @@ static void p54_led_brightness_set(struct led_classdev *led_dev,
if ((brightness) && (led->registered)) {
led->toggled++;
- queue_delayed_work(priv->hw->workqueue, &priv->led_work,
- HZ/10);
+ ieee80211_queue_delayed_work(priv->hw, &priv->led_work, HZ/10);
}
}
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index 955f6d7..a0d0e72 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -180,7 +180,7 @@ static int p54_start(struct ieee80211_hw *dev)
goto out;
}
- queue_delayed_work(dev->workqueue, &priv->work, 0);
+ ieee80211_queue_delayed_work(dev, &priv->work, 0);
priv->softled_state = 0;
err = p54_set_leds(priv);
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c
index eef5329..05458d9 100644
--- a/drivers/net/wireless/p54/p54spi.c
+++ b/drivers/net/wireless/p54/p54spi.c
@@ -391,7 +391,7 @@ static irqreturn_t p54spi_interrupt(int irq, void *config)
struct spi_device *spi = config;
struct p54s_priv *priv = dev_get_drvdata(&spi->dev);
- queue_work(priv->hw->workqueue, &priv->work);
+ ieee80211_queue_work(priv->hw, &priv->work);
return IRQ_HANDLED;
}
@@ -479,7 +479,7 @@ static void p54spi_op_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
list_add_tail(&di->tx_list, &priv->tx_pending);
spin_unlock_irqrestore(&priv->tx_lock, flags);
- queue_work(priv->hw->workqueue, &priv->work);
+ ieee80211_queue_work(priv->hw, &priv->work);
}
static void p54spi_work(struct work_struct *work)
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
index c32a0d2..704685f 100644
--- a/drivers/net/wireless/p54/txrx.c
+++ b/drivers/net/wireless/p54/txrx.c
@@ -380,7 +380,7 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
ieee80211_rx_irqsafe(priv->hw, skb);
- queue_delayed_work(priv->hw->workqueue, &priv->work,
+ ieee80211_queue_delayed_work(priv->hw, &priv->work,
msecs_to_jiffies(P54_STATISTICS_UPDATE));
return -1;
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 658a63b..b717afb 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -215,7 +215,7 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
rt2x00lib_beacondone_iter,
rt2x00dev);
- queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->intf_work);
+ ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work);
}
EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c
index 7991568..9178316 100644
--- a/drivers/net/wireless/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/rt2x00/rt2x00link.c
@@ -351,8 +351,8 @@ void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
rt2x00link_reset_tuner(rt2x00dev, false);
- queue_delayed_work(rt2x00dev->hw->workqueue,
- &link->work, LINK_TUNE_INTERVAL);
+ ieee80211_queue_delayed_work(rt2x00dev->hw,
+ &link->work, LINK_TUNE_INTERVAL);
}
void rt2x00link_stop_tuner(struct rt2x00_dev *rt2x00dev)
@@ -461,8 +461,8 @@ static void rt2x00link_tuner(struct work_struct *work)
* Increase tuner counter, and reschedule the next link tuner run.
*/
link->count++;
- queue_delayed_work(rt2x00dev->hw->workqueue,
- &link->work, LINK_TUNE_INTERVAL);
+ ieee80211_queue_delayed_work(rt2x00dev->hw,
+ &link->work, LINK_TUNE_INTERVAL);
}
void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index e92c8f9..81febdf 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -431,7 +431,7 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags))
rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags);
else
- queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work);
+ ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->filter_work);
}
EXPORT_SYMBOL_GPL(rt2x00mac_configure_filter);
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
index c9b9dbe..53f57dc 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -220,7 +220,7 @@ static void rtl8187_tx_cb(struct urb *urb)
* reading a register in the device. We are in interrupt mode
* here, thus queue the skb and finish on a work queue. */
skb_queue_tail(&priv->b_tx_status.queue, skb);
- queue_delayed_work(hw->workqueue, &priv->work, 0);
+ ieee80211_queue_delayed_work(hw, &priv->work, 0);
}
}
diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.c b/drivers/net/wireless/rtl818x/rtl8187_leds.c
index cf9f899..a6cfb7e 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_leds.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_leds.c
@@ -108,11 +108,11 @@ static void rtl8187_led_brightness_set(struct led_classdev *led_dev,
struct rtl8187_priv *priv = hw->priv;
if (brightness == LED_OFF) {
- queue_delayed_work(hw->workqueue, &priv->led_off, 0);
+ ieee80211_queue_delayed_work(hw, &priv->led_off, 0);
/* The LED is off for 1/20 sec so that it just blinks. */
- queue_delayed_work(hw->workqueue, &priv->led_on, HZ / 20);
+ ieee80211_queue_delayed_work(hw, &priv->led_on, HZ / 20);
} else
- queue_delayed_work(hw->workqueue, &priv->led_on, 0);
+ ieee80211_queue_delayed_work(hw, &priv->led_on, 0);
}
static int rtl8187_register_led(struct ieee80211_hw *dev,
@@ -193,7 +193,7 @@ void rtl8187_leds_init(struct ieee80211_hw *dev, u16 custid)
err = rtl8187_register_led(dev, &priv->led_rx, name,
ieee80211_get_rx_led_name(dev), ledpin);
if (!err) {
- queue_delayed_work(dev->workqueue, &priv->led_on, 0);
+ ieee80211_queue_delayed_work(dev, &priv->led_on, 0);
return;
}
/* registration of RX LED failed - unregister TX */
@@ -209,7 +209,7 @@ void rtl8187_leds_exit(struct ieee80211_hw *dev)
struct rtl8187_priv *priv = dev->priv;
/* turn the LED off before exiting */
- queue_delayed_work(dev->workqueue, &priv->led_off, 0);
+ ieee80211_queue_delayed_work(dev, &priv->led_off, 0);
cancel_delayed_work_sync(&priv->led_off);
cancel_delayed_work_sync(&priv->led_on);
rtl8187_unregister_led(&priv->led_rx);
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index d4e09a0..5ed93f4 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -73,6 +73,21 @@
*/
/**
+ * DOC: mac80211 workqueue
+ *
+ * mac80211 provides its own workqueue for drivers and internal mac80211 use.
+ * The workqueue is a single threaded workqueue and can only be accessed by
+ * helpers for sanity checking. Drivers must ensure all work added onto the
+ * mac80211 workqueue should be cancelled on the driver stop() callback.
+ *
+ * mac80211 will flushed the workqueue upon interface removal and during
+ * suspend.
+ *
+ * All work performed on the mac80211 workqueue must not acquire the RTNL lock.
+ *
+ */
+
+/**
* enum ieee80211_max_queues - maximum number of queues
*
* @IEEE80211_MAX_QUEUES: Maximum number of regular device queues.
@@ -913,12 +928,6 @@ enum ieee80211_hw_flags {
*
* @conf: &struct ieee80211_conf, device configuration, don't use.
*
- * @workqueue: single threaded workqueue available for driver use,
- * allocated by mac80211 on registration and flushed when an
- * interface is removed.
- * NOTICE: All work performed on this workqueue must not
- * acquire the RTNL lock.
- *
* @priv: pointer to private area that was allocated for driver use
* along with this structure.
*
@@ -954,7 +963,6 @@ enum ieee80211_hw_flags {
struct ieee80211_hw {
struct ieee80211_conf conf;
struct wiphy *wiphy;
- struct workqueue_struct *workqueue;
const char *rate_control_algorithm;
void *priv;
u32 flags;
@@ -1301,7 +1309,8 @@ enum ieee80211_ampdu_mlme_action {
* is disabled. This should turn off the hardware (at least
* it must turn off frame reception.)
* May be called right after add_interface if that rejects
- * an interface.
+ * an interface. If you added any work onto the mac80211 workqueue
+ * you should ensure to cancel it on this callback.
* Must be implemented.
*
* @add_interface: Called when a netdevice attached to the hardware is
@@ -1928,6 +1937,31 @@ void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw,
void *data);
/**
+ * ieee80211_queue_work - add work onto the mac80211 workqueue
+ *
+ * Drivers and mac80211 use this to add work onto the mac80211 workqueue.
+ * This helper ensures drivers are not queueing work when they should not be.
+ *
+ * @hw: the hardware struct for the interface we are adding work for
+ * @work: the work we want to add onto the mac80211 workqueue
+ */
+void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work);
+
+/**
+ * ieee80211_queue_delayed_work - add work onto the mac80211 workqueue
+ *
+ * Drivers and mac80211 use this to queue delayed work onto the mac80211
+ * workqueue.
+ *
+ * @hw: the hardware struct for the interface we are adding work for
+ * @dwork: delayable work to queue onto the mac80211 workqueue
+ * @delay: number of jiffies to wait before queueing
+ */
+void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
+ struct delayed_work *dwork,
+ unsigned long delay);
+
+/**
* ieee80211_start_tx_ba_session - Start a tx Block Ack session.
* @hw: pointer as obtained from ieee80211_alloc_hw().
* @ra: receiver address of the BA session recipient
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 6e3cca6..920ec87 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -781,7 +781,7 @@ static void ieee80211_ibss_timer(unsigned long data)
}
set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request);
- queue_work(local->hw.workqueue, &ifibss->work);
+ ieee80211_queue_work(&local->hw, &ifibss->work);
}
#ifdef CONFIG_PM
@@ -853,7 +853,7 @@ ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
case IEEE80211_STYPE_PROBE_REQ:
case IEEE80211_STYPE_AUTH:
skb_queue_tail(&sdata->u.ibss.skb_queue, skb);
- queue_work(local->hw.workqueue, &sdata->u.ibss.work);
+ ieee80211_queue_work(&local->hw, &sdata->u.ibss.work);
return RX_QUEUED;
}
@@ -912,7 +912,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
ieee80211_recalc_idle(sdata->local);
set_bit(IEEE80211_IBSS_REQ_RUN, &sdata->u.ibss.request);
- queue_work(sdata->local->hw.workqueue, &sdata->u.ibss.work);
+ ieee80211_queue_work(&sdata->local->hw, &sdata->u.ibss.work);
return 0;
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index aec6853..316825b 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -614,6 +614,12 @@ struct ieee80211_local {
const struct ieee80211_ops *ops;
+ /*
+ * private workqueue to mac80211. mac80211 makes this accessible
+ * via ieee80211_queue_work()
+ */
+ struct workqueue_struct *workqueue;
+
unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES];
/* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */
spinlock_t queue_stop_reason_lock;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index a83087f..8c1284d 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -312,7 +312,7 @@ static int ieee80211_open(struct net_device *dev)
* to fix this.
*/
if (sdata->vif.type == NL80211_IFTYPE_STATION)
- queue_work(local->hw.workqueue, &sdata->u.mgd.work);
+ ieee80211_queue_work(&local->hw, &sdata->u.mgd.work);
netif_tx_start_all_queues(dev);
@@ -551,7 +551,7 @@ static int ieee80211_stop(struct net_device *dev)
ieee80211_led_radio(local, false);
- flush_workqueue(local->hw.workqueue);
+ flush_workqueue(local->workqueue);
tasklet_disable(&local->tx_pending_tasklet);
tasklet_disable(&local->tasklet);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 5e76dd1..22e0738 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -821,9 +821,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (hw->queues > IEEE80211_MAX_QUEUES)
hw->queues = IEEE80211_MAX_QUEUES;
- local->hw.workqueue =
+ local->workqueue =
create_singlethread_workqueue(wiphy_name(local->hw.wiphy));
- if (!local->hw.workqueue) {
+ if (!local->workqueue) {
result = -ENOMEM;
goto fail_workqueue;
}
@@ -913,7 +913,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
sta_info_stop(local);
fail_sta_info:
debugfs_hw_del(local);
- destroy_workqueue(local->hw.workqueue);
+ destroy_workqueue(local->workqueue);
fail_workqueue:
wiphy_unregister(local->hw.wiphy);
fail_wiphy_register:
@@ -955,7 +955,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
skb_queue_purge(&local->skb_queue);
skb_queue_purge(&local->skb_queue_unreliable);
- destroy_workqueue(local->hw.workqueue);
+ destroy_workqueue(local->workqueue);
wiphy_unregister(local->hw.wiphy);
ieee80211_wep_free(local);
ieee80211_led_exit(local);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 9a38269..2f4f518 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -54,7 +54,7 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data)
return;
}
- queue_work(local->hw.workqueue, &ifmsh->work);
+ ieee80211_queue_work(local->hw.workqueue, &ifmsh->work);
}
/**
@@ -357,7 +357,7 @@ static void ieee80211_mesh_path_timer(unsigned long data)
return;
}
- queue_work(local->hw.workqueue, &ifmsh->work);
+ ieee80211_queue_work(local->hw.workqueue, &ifmsh->work);
}
struct mesh_table *mesh_table_grow(struct mesh_table *tbl)
@@ -471,7 +471,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
struct ieee80211_local *local = sdata->local;
ifmsh->housekeeping = true;
- queue_work(local->hw.workqueue, &ifmsh->work);
+ ieee80211_queue_work(local->hw.workqueue, &ifmsh->work);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
BSS_CHANGED_BEACON_ENABLED);
}
@@ -619,7 +619,7 @@ void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list)
if (ieee80211_vif_is_mesh(&sdata->vif))
- queue_work(local->hw.workqueue, &sdata->u.mesh.work);
+ ieee80211_queue_work(local->hw.workqueue, &sdata->u.mesh.work);
rcu_read_unlock();
}
@@ -692,7 +692,7 @@ ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
case IEEE80211_STYPE_PROBE_RESP:
case IEEE80211_STYPE_BEACON:
skb_queue_tail(&ifmsh->skb_queue, skb);
- queue_work(local->hw.workqueue, &ifmsh->work);
+ ieee80211_queue_work(local->hw.workqueue, &ifmsh->work);
return RX_QUEUED;
}
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index e93c37e..11ab71a 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -660,14 +660,14 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
spin_unlock(&ifmsh->mesh_preq_queue_lock);
if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata)))
- queue_work(sdata->local->hw.workqueue, &ifmsh->work);
+ ieee80211_queue_work(sdata->local->hw.workqueue, &ifmsh->work);
else if (time_before(jiffies, ifmsh->last_preq)) {
/* avoid long wait if did not send preqs for a long time
* and jiffies wrapped around
*/
ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1;
- queue_work(sdata->local->hw.workqueue, &ifmsh->work);
+ ieee80211_queue_work(sdata->local->hw.workqueue, &ifmsh->work);
} else
mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq +
min_preq_int_jiff(sdata));
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index ee83125..0779ba1 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -565,7 +565,7 @@ static void ieee80211_chswitch_timer(unsigned long data)
return;
}
- queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work);
+ ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
}
void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
@@ -597,7 +597,7 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
sdata->local->csa_channel = new_ch;
if (sw_elem->count <= 1) {
- queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work);
+ ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work);
} else {
ieee80211_stop_queues_by_reason(&sdata->local->hw,
IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -763,7 +763,7 @@ void ieee80211_dynamic_ps_timer(unsigned long data)
if (local->quiescing || local->suspended)
return;
- queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work);
+ ieee80211_queue_work(&local->hw, &local->dynamic_ps_enable_work);
}
/* MLME */
@@ -950,7 +950,7 @@ ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata,
* due to work needing to be done. Hence, queue the STAs work
* again for that.
*/
- queue_work(local->hw.workqueue, &ifmgd->work);
+ ieee80211_queue_work(&local->hw, &ifmgd->work);
return RX_MGMT_CFG80211_AUTH_TO;
}
@@ -995,7 +995,7 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
* due to work needing to be done. Hence, queue the STAs work
* again for that.
*/
- queue_work(local->hw.workqueue, &ifmgd->work);
+ ieee80211_queue_work(&local->hw, &ifmgd->work);
return RX_MGMT_CFG80211_AUTH_TO;
}
@@ -1124,7 +1124,7 @@ ieee80211_associate(struct ieee80211_sub_if_data *sdata,
* due to work needing to be done. Hence, queue the STAs work
* again for that.
*/
- queue_work(local->hw.workqueue, &ifmgd->work);
+ ieee80211_queue_work(&local->hw, &ifmgd->work);
return RX_MGMT_CFG80211_ASSOC_TO;
}
@@ -1232,8 +1232,7 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif)
{
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
- queue_work(sdata->local->hw.workqueue,
- &sdata->u.mgd.beacon_loss_work);
+ ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.beacon_loss_work);
}
EXPORT_SYMBOL(ieee80211_beacon_loss);
@@ -1888,7 +1887,7 @@ ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
case IEEE80211_STYPE_DISASSOC:
case IEEE80211_STYPE_ACTION:
skb_queue_tail(&sdata->u.mgd.skb_queue, skb);
- queue_work(local->hw.workqueue, &sdata->u.mgd.work);
+ ieee80211_queue_work(&local->hw, &sdata->u.mgd.work);
return RX_QUEUED;
}
@@ -2026,7 +2025,7 @@ static void ieee80211_sta_timer(unsigned long data)
return;
}
- queue_work(local->hw.workqueue, &ifmgd->work);
+ ieee80211_queue_work(&local->hw, &ifmgd->work);
}
static void ieee80211_sta_work(struct work_struct *work)
@@ -2051,13 +2050,11 @@ static void ieee80211_sta_work(struct work_struct *work)
return;
/*
- * Nothing should have been stuffed into the workqueue during
- * the suspend->resume cycle. If this WARN is seen then there
- * is a bug with either the driver suspend or something in
- * mac80211 stuffing into the workqueue which we haven't yet
- * cleared during mac80211's suspend cycle.
+ * ieee80211_queue_work() should have picked up most cases,
+ * here we'll pick the the rest.
*/
- if (WARN_ON(local->suspended))
+ if (WARN(local->suspended, "STA MLME work scheduled while "
+ "going to suspend\n"))
return;
ifmgd = &sdata->u.mgd;
@@ -2113,9 +2110,9 @@ static void ieee80211_sta_work(struct work_struct *work)
mutex_unlock(&ifmgd->mtx);
if (test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request))
- queue_delayed_work(local->hw.workqueue,
- &local->scan_work,
- round_jiffies_relative(0));
+ ieee80211_queue_delayed_work(&local->hw,
+ &local->scan_work,
+ round_jiffies_relative(0));
return;
}
@@ -2196,8 +2193,7 @@ static void ieee80211_sta_bcn_mon_timer(unsigned long data)
if (local->quiescing)
return;
- queue_work(sdata->local->hw.workqueue,
- &sdata->u.mgd.beacon_loss_work);
+ ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.beacon_loss_work);
}
static void ieee80211_sta_conn_mon_timer(unsigned long data)
@@ -2210,7 +2206,7 @@ static void ieee80211_sta_conn_mon_timer(unsigned long data)
if (local->quiescing)
return;
- queue_work(local->hw.workqueue, &ifmgd->monitor_work);
+ ieee80211_queue_work(&local->hw, &ifmgd->monitor_work);
}
static void ieee80211_sta_monitor_work(struct work_struct *work)
@@ -2229,10 +2225,10 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
IEEE80211_STA_CONNECTION_POLL);
/* let's probe the connection once */
- queue_work(sdata->local->hw.workqueue,
+ ieee80211_queue_work(&sdata->local->hw,
&sdata->u.mgd.monitor_work);
/* and do all the other regular work too */
- queue_work(sdata->local->hw.workqueue,
+ ieee80211_queue_work(&sdata->local->hw,
&sdata->u.mgd.work);
}
}
@@ -2393,7 +2389,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
list_add(&wk->list, &sdata->u.mgd.work_list);
mutex_unlock(&ifmgd->mtx);
- queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work);
+ ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work);
return 0;
}
@@ -2467,7 +2463,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
else
ifmgd->flags &= ~IEEE80211_STA_CONTROL_PORT;
- queue_work(sdata->local->hw.workqueue, &sdata->u.mgd.work);
+ ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.work);
err = 0;
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index e79aa7e..1da62e2 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -25,7 +25,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
/* make quiescing visible to timers everywhere */
mb();
- flush_workqueue(local->hw.workqueue);
+ flush_workqueue(local->workqueue);
/* Don't try to run timers while suspended. */
del_timer_sync(&local->sta_cleanup);
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 4573100..244f53f 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -385,8 +385,9 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
spin_unlock_bh(&local->filter_lock);
/* TODO: start scan as soon as all nullfunc frames are ACKed */
- queue_delayed_work(local->hw.workqueue, &local->scan_work,
- IEEE80211_CHANNEL_TIME);
+ ieee80211_queue_delayed_work(&local->hw,
+ &local->scan_work,
+ IEEE80211_CHANNEL_TIME);
return 0;
}
@@ -715,8 +716,7 @@ void ieee80211_scan_work(struct work_struct *work)
}
} while (next_delay == 0);
- queue_delayed_work(local->hw.workqueue, &local->scan_work,
- next_delay);
+ ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay);
}
int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 9b64f1b..d265d6f 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1399,7 +1399,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
ieee80211_stop_queues_by_reason(&local->hw,
IEEE80211_QUEUE_STOP_REASON_PS);
- queue_work(local->hw.workqueue,
+ ieee80211_queue_work(&local->hw,
&local->dynamic_ps_disable_work);
}
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 988a2b8..e006fa6 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -511,6 +511,46 @@ void ieee80211_iterate_active_interfaces_atomic(
}
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
+/*
+ * Nothing should have been stuffed into the workqueue during
+ * the suspend->resume cycle. If this WARN is seen then there
+ * is a bug with either the driver suspend or something in
+ * mac80211 stuffing into the workqueue which we haven't yet
+ * cleared during mac80211's suspend cycle.
+ */
+static bool ieee80211_can_queue_work(struct ieee80211_local *local)
+{
+ if (WARN(local->suspended, "queueing ieee80211 work while "
+ "going to suspend\n"))
+ return false;
+
+ return true;
+}
+
+void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ if (!ieee80211_can_queue_work(local))
+ return;
+
+ queue_work(local->workqueue, work);
+}
+EXPORT_SYMBOL(ieee80211_queue_work);
+
+void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
+ struct delayed_work *dwork,
+ unsigned long delay)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ if (!ieee80211_can_queue_work(local))
+ return;
+
+ queue_delayed_work(local->workqueue, dwork, delay);
+}
+EXPORT_SYMBOL(ieee80211_queue_delayed_work);
+
void ieee802_11_parse_elems(u8 *start, size_t len,
struct ieee802_11_elems *elems)
{
@@ -1113,3 +1153,4 @@ int ieee80211_reconfig(struct ieee80211_local *local)
#endif
return 0;
}
+
--
1.6.0.4
^ permalink raw reply related
* Re: ar9170 DWA 160A
From: Pavel Roskin @ 2009-07-29 21:29 UTC (permalink / raw)
To: Luis R. Rodriguez; +Cc: linux-wireless, otus-devel, Felix Bitterli
In-Reply-To: <43e72e890907281646x731bfcc3v62f17e21bd94bb4@mail.gmail.com>
On Tue, 2009-07-28 at 16:46 -0700, Luis R. Rodriguez wrote:
> We have these listed on ar9170 wiki page as under Dlink DWA160A:
>
> 0x07d1:0x3c10
> 0x0846:0x9010
>
> A user just reported thy purchased DWA160 by mistake thinking it was
> the same but it turns out it has some other wireless chipset. Do any
> of you have a DWA160A that is claimed by ar9170 or should we remove
> this from the list?
The D-Link site doesn't mention DWA160A or DWA-160A at all. It has
DWA-160 only. When downloading the drivers, there is a choice between
"DWA-160" and "DWA-160_REVB". The former has Atheros drivers, the later
has rt2870.
I guess the original "DWA-160" was "rev A", so it could have transformed
to "DWA-160A" somewhere. That said, the online retailers sell "DWA-160"
and not "DWA-160A".
I think we can write that DWA-160 rev A is supported by ar9170 and
DWA-160 rev B is supported by rt2870 in the staging tree.
--
Regards,
Pavel Roskin
^ permalink raw reply
* [PATCH] mac80211: use beacons for connection monitoring
From: Reinette Chatre @ 2009-07-29 21:32 UTC (permalink / raw)
To: johannes; +Cc: linville, linux-wireless, Reinette Chatre
From: Reinette Chatre <reinette.chatre@intel.com>
The connection monitor currently relies on probe requests paired
with probe responses to ensure that a connection is alive. This is
fragile in some environments where probe responses can get lost.
When we receive beacons we can also consider the connection to be
alive, so cancel connection poll instance when we receive a beacon.
The debug message "cancelling probereq poll due to a received beacon"
is removed as part of this change as this case is hit very often after
the above change and debug log receives significant number of these messages.
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
---
net/mac80211/mlme.c | 12 ++++--------
1 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index e3b3156..9cf6153 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1743,14 +1743,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
if (memcmp(bssid, mgmt->bssid, ETH_ALEN) != 0)
return;
- if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: cancelling probereq poll due "
- "to a received beacon\n", sdata->dev->name);
- }
-#endif
- ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL;
+ if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL)) {
+ ifmgd->flags &= ~(IEEE80211_STA_BEACON_POLL |
+ IEEE80211_STA_CONNECTION_POLL);
mutex_lock(&local->iflist_mtx);
ieee80211_recalc_ps(local, -1);
mutex_unlock(&local->iflist_mtx);
--
1.5.6.3
^ permalink raw reply related
* [PATCH 2/2] ath5k: fix CAB queue operation
From: Bob Copeland @ 2009-07-29 21:32 UTC (permalink / raw)
To: linville, jirislaby, mickflemm, lrodriguez
Cc: linux-wireless, ath5k-devel, Bob Copeland
In-Reply-To: <1248877744-7273-2-git-send-email-me@bobcopeland.com>
We need to process tx descriptors for all queues (currently main tx
queue and cabq) which may have triggered the TX completion interrupt.
Otherwise, the queues can get stuck after sending a few frames.
Signed-off-by: Bob Copeland <me@bobcopeland.com>
---
John, hand-edited this one to remove the queue config stuff for now.
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 55ee976..3a1c156 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -2000,9 +2000,12 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
static void
ath5k_tasklet_tx(unsigned long data)
{
+ int i;
struct ath5k_softc *sc = (void *)data;
- ath5k_tx_processq(sc, sc->txq);
+ for (i=0; i < AR5K_NUM_TX_QUEUES; i++)
+ if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i)))
+ ath5k_tx_processq(sc, &sc->txqs[i]);
}
^ permalink raw reply related
* Re: [PATCH] mac80211: use beacons for connection monitoring
From: Ben Greear @ 2009-07-29 21:39 UTC (permalink / raw)
To: Reinette Chatre; +Cc: johannes, linville, linux-wireless
In-Reply-To: <1248903159-17024-1-git-send-email-reinette.chatre@intel.com>
On 07/29/2009 02:32 PM, Reinette Chatre wrote:
> From: Reinette Chatre<reinette.chatre@intel.com>
>
> The connection monitor currently relies on probe requests paired
> with probe responses to ensure that a connection is alive. This is
> fragile in some environments where probe responses can get lost.
> When we receive beacons we can also consider the connection to be
> alive, so cancel connection poll instance when we receive a beacon.
I'm chasing a similar problem while working on virtual STA device
support in ath5k. I was also going to try sending up to 3 polls before
giving up on the connection. Does that seems like a valid thing to do?
I'll try using this patch as well to see if that helps.
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* Re: [PATCH] mac80211: use beacons for connection monitoring
From: Johannes Berg @ 2009-07-29 21:45 UTC (permalink / raw)
To: Reinette Chatre; +Cc: linville, linux-wireless
In-Reply-To: <1248903159-17024-1-git-send-email-reinette.chatre@intel.com>
[-- Attachment #1: Type: text/plain, Size: 939 bytes --]
On Wed, 2009-07-29 at 14:32 -0700, Reinette Chatre wrote:
> From: Reinette Chatre <reinette.chatre@intel.com>
>
> The connection monitor currently relies on probe requests paired
> with probe responses to ensure that a connection is alive. This is
> fragile in some environments where probe responses can get lost.
> When we receive beacons we can also consider the connection to be
> alive, so cancel connection poll instance when we receive a beacon.
>
> The debug message "cancelling probereq poll due to a received beacon"
> is removed as part of this change as this case is hit very often after
> the above change and debug log receives significant number of these messages.
Not doing that was actually intentional -- we want to know whether or
not the connection is working both ways, not just whether we can receive
frames. This can certainly be improved, but I'm not sure this is the
best approach.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [PATCH v3] mac80211: redefine usage of the mac80211 workqueue
From: Luis R. Rodriguez @ 2009-07-29 21:13 UTC (permalink / raw)
To: John W. Linville; +Cc: linux-wireless
In-Reply-To: <43e72e890907291345u5de674fem7b0769f52a7251c5@mail.gmail.com>
On Wed, Jul 29, 2009 at 1:45 PM, Luis R.
Rodriguez<lrodriguez@atheros.com> wrote:
> On Wed, Jul 29, 2009 at 1:00 PM, John W. Linville<linville@tuxdriver.com> wrote:
>> On Mon, Jul 27, 2009 at 03:21:31PM -0700, Luis R. Rodriguez wrote:
>>> The mac80211 workqueue exists to enable mac80211 and drivers
>>> to queue their own work on a single threaded workqueue. mac80211
>>> takes care to flush the workqueue during suspend but we never
>>> really had requirements on drivers for how they should use
>>> the workqueue in consideration for suspend.
>>>
>>> We extend mac80211 to document how the mac80211 workqueue should
>>> be used, how it should not be used and finally move raw access to
>>> the workqueue to mac80211 only. Drivers and mac80211 use helpers
>>> to queue work onto the mac80211 workqueue:
>>>
>>> * ieee80211_queue_work()
>>> * ieee80211_queue_delayed_work()
>>>
>>> These helpers will now warn if mac80211 already completed its
>>> suspend cycle and someone is trying to queue work. mac80211
>>> flushes the mac80211 workqueue prior to suspend a few times,
>>> but we haven't taken the care to ensure drivers won't add more
>>> work after suspend. To help with this we add a warning when
>>> someone tries to add work and mac80211 already completed the
>>> suspend cycle.
>>>
>>> Drivers should ensure they cancel any work or delayed work
>>> in the mac80211 stop() callback.
>>
>> How are they supposed to do that after you've removed workqueue
>> from the ieee80211_hw structure?
>
> They do not refer to the mac80211 workqueue for that, they can cancel
> work using cancel_work_sync(their_foo_work_struct).
>
>> This breaks the compilation of
>> at76c50x-usb.c...
>
> Strange, I thought I tested that, will retest,
Oh ok, sorry about that this requires a patch which I thought I had
sent but it seems I didn't:
at76c50x-usb: remove unneeded flush_workqueue() at usb disconnect
Will send.
Luis
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox