From: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
To: linux-wireless@vger.kernel.org
Cc: Daniel Drake <dsd@gentoo.org>, Ulrich Kunitz <kune@deine-taler.de>
Subject: [RFC PATCH 01/17] zd1211rw: fix tx-queue disabling
Date: Wed, 05 Jan 2011 01:47:54 +0200 [thread overview]
Message-ID: <20110104234754.25309.54906.stgit@fate.lan> (raw)
In-Reply-To: <20110104234745.25309.72030.stgit@fate.lan>
When stress testing AP-mode I hit OOPS when unpluging or rmmodding
driver.
It appears that when tx-queue is disabled, tx-urbs might be left pending.
These can cause ehci to call non-existing tx_urb_complete() (after rmmod)
or uninitialized/reseted private structure (after disconnect()). Add skb
queue for submitted packets and unlink pending urbs on zd_usb_disable_tx().
Part of the problem seems to be usb->free_urb_list that isn't always
working as it should, causing machine freeze when trying to free the list
in zd_usb_disable_tx(). Caching free urbs isn't what other drivers seem
to be doing (usbnet for example) so strip free_usb_list.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
---
drivers/net/wireless/zd1211rw/zd_usb.c | 113 ++++++++++++++------------------
drivers/net/wireless/zd1211rw/zd_usb.h | 3 -
2 files changed, 51 insertions(+), 65 deletions(-)
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 06041cb..ed5379b 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -778,15 +778,34 @@ void zd_usb_disable_rx(struct zd_usb *usb)
void zd_usb_disable_tx(struct zd_usb *usb)
{
struct zd_usb_tx *tx = &usb->tx;
+ struct sk_buff_head *q = &tx->submitted_queue;
+ struct sk_buff *skb, *skbnext;
unsigned long flags;
- struct list_head *pos, *n;
+ int qlen;
spin_lock_irqsave(&tx->lock, flags);
- list_for_each_safe(pos, n, &tx->free_urb_list) {
- list_del(pos);
- usb_free_urb(list_entry(pos, struct urb, urb_list));
- }
tx->enabled = 0;
+ spin_unlock(&tx->lock);
+
+ /* unlink all submitted tx-urbs */
+ spin_lock(&q->lock);
+ skb_queue_walk_safe(q, skb, skbnext) {
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ usb_unlink_urb(info->rate_driver_data[1]);
+ }
+ qlen = skb_queue_len(q);
+ spin_unlock(&q->lock);
+
+ /* wait until unlink has completed */
+ while (qlen > 0) {
+ msleep(20);
+
+ spin_lock(&q->lock);
+ qlen = skb_queue_len(q);
+ spin_unlock(&q->lock);
+ }
+
+ spin_lock(&tx->lock);
tx->submitted_urbs = 0;
/* The stopped state is ignored, relying on ieee80211_wake_queues()
* in a potentionally following zd_usb_enable_tx().
@@ -814,56 +833,6 @@ void zd_usb_enable_tx(struct zd_usb *usb)
spin_unlock_irqrestore(&tx->lock, flags);
}
-/**
- * alloc_tx_urb - provides an tx URB
- * @usb: a &struct zd_usb pointer
- *
- * Allocates a new URB. If possible takes the urb from the free list in
- * usb->tx.
- */
-static struct urb *alloc_tx_urb(struct zd_usb *usb)
-{
- struct zd_usb_tx *tx = &usb->tx;
- unsigned long flags;
- struct list_head *entry;
- struct urb *urb;
-
- spin_lock_irqsave(&tx->lock, flags);
- if (list_empty(&tx->free_urb_list)) {
- urb = usb_alloc_urb(0, GFP_ATOMIC);
- goto out;
- }
- entry = tx->free_urb_list.next;
- list_del(entry);
- urb = list_entry(entry, struct urb, urb_list);
-out:
- spin_unlock_irqrestore(&tx->lock, flags);
- return urb;
-}
-
-/**
- * free_tx_urb - frees a used tx URB
- * @usb: a &struct zd_usb pointer
- * @urb: URB to be freed
- *
- * Frees the transmission URB, which means to put it on the free URB
- * list.
- */
-static void free_tx_urb(struct zd_usb *usb, struct urb *urb)
-{
- struct zd_usb_tx *tx = &usb->tx;
- unsigned long flags;
-
- spin_lock_irqsave(&tx->lock, flags);
- if (!tx->enabled) {
- usb_free_urb(urb);
- goto out;
- }
- list_add(&urb->urb_list, &tx->free_urb_list);
-out:
- spin_unlock_irqrestore(&tx->lock, flags);
-}
-
static void tx_dec_submitted_urbs(struct zd_usb *usb)
{
struct zd_usb_tx *tx = &usb->tx;
@@ -878,7 +847,7 @@ static void tx_dec_submitted_urbs(struct zd_usb *usb)
spin_unlock_irqrestore(&tx->lock, flags);
}
-static void tx_inc_submitted_urbs(struct zd_usb *usb)
+static void tx_inc_submitted_urbs(struct zd_usb *usb, struct urb *urb)
{
struct zd_usb_tx *tx = &usb->tx;
unsigned long flags;
@@ -929,8 +898,9 @@ free_urb:
*/
info = IEEE80211_SKB_CB(skb);
usb = &zd_hw_mac(info->rate_driver_data[0])->chip.usb;
+ skb_unlink(skb, &usb->tx.submitted_queue);
zd_mac_tx_to_dev(skb, urb->status);
- free_tx_urb(usb, urb);
+ usb_free_urb(urb);
tx_dec_submitted_urbs(usb);
return;
resubmit:
@@ -955,11 +925,22 @@ resubmit:
*/
int zd_usb_tx(struct zd_usb *usb, struct sk_buff *skb)
{
- int r;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ int r, enabled;
struct usb_device *udev = zd_usb_to_usbdev(usb);
struct urb *urb;
+ struct zd_usb_tx *tx = &usb->tx;
+ unsigned long flags;
- urb = alloc_tx_urb(usb);
+ spin_lock_irqsave(&tx->lock, flags);
+ enabled = tx->enabled;
+ spin_unlock_irqrestore(&tx->lock, flags);
+ if (!enabled) {
+ r = -ENOENT;
+ goto out;
+ }
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
r = -ENOMEM;
goto out;
@@ -968,13 +949,18 @@ int zd_usb_tx(struct zd_usb *usb, struct sk_buff *skb)
usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT),
skb->data, skb->len, tx_urb_complete, skb);
+ info->rate_driver_data[1] = urb;
+ skb_queue_tail(&tx->submitted_queue, skb);
+
r = usb_submit_urb(urb, GFP_ATOMIC);
- if (r)
+ if (r) {
+ skb_unlink(skb, &tx->submitted_queue);
goto error;
- tx_inc_submitted_urbs(usb);
+ }
+ tx_inc_submitted_urbs(usb, urb);
return 0;
error:
- free_tx_urb(usb, urb);
+ usb_free_urb(urb);
out:
return r;
}
@@ -1007,7 +993,7 @@ static inline void init_usb_tx(struct zd_usb *usb)
spin_lock_init(&tx->lock);
tx->enabled = 0;
tx->stopped = 0;
- INIT_LIST_HEAD(&tx->free_urb_list);
+ skb_queue_head_init(&tx->submitted_queue);
tx->submitted_urbs = 0;
}
@@ -1240,6 +1226,7 @@ static void disconnect(struct usb_interface *intf)
ieee80211_unregister_hw(hw);
/* Just in case something has gone wrong! */
+ zd_usb_disable_tx(usb);
zd_usb_disable_rx(usb);
zd_usb_disable_int(usb);
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
index 1b1655c..b71baa0 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.h
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -185,7 +185,6 @@ struct zd_usb_rx {
/**
* struct zd_usb_tx - structure used for transmitting frames
* @lock: lock for transmission
- * @free_urb_list: list of free URBs, contains all the URBs, which can be used
* @submitted_urbs: atomic integer that counts the URBs having sent to the
* device, which haven't been completed
* @enabled: enabled flag, indicates whether tx is enabled
@@ -193,7 +192,7 @@ struct zd_usb_rx {
*/
struct zd_usb_tx {
spinlock_t lock;
- struct list_head free_urb_list;
+ struct sk_buff_head submitted_queue;
int submitted_urbs;
int enabled;
int stopped;
next prev parent reply other threads:[~2011-01-04 23:47 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-01-04 23:47 [RFC PATCH 0/17] zd1211rw: add support for AP mode Jussi Kivilinna
2011-01-04 23:47 ` Jussi Kivilinna [this message]
2011-01-04 23:48 ` [RFC PATCH 02/17] zd1211rw: cancel process_intr work on zd_chip_disable_int() Jussi Kivilinna
2011-01-04 23:48 ` [RFC PATCH 03/17] zd1211rw: fix beacon interval setup Jussi Kivilinna
2011-01-04 23:48 ` [RFC PATCH 04/17] zd1211rw: move set_multicast_hash and set_rx_filter from workers to configure_filter Jussi Kivilinna
2011-01-04 23:48 ` [RFC PATCH 05/17] zd1211rw: move set_rts_cts_work to bss_info_changed Jussi Kivilinna
2011-01-04 23:48 ` [RFC PATCH 06/17] zd1211rw: support setting BSSID for AP mode Jussi Kivilinna
2011-01-04 23:48 ` [RFC PATCH 07/17] zd1211rw: fix ack_pending in filter_ack causing tx-packet ordering problem on monitor Jussi Kivilinna
2011-01-04 23:48 ` [RFC PATCH 08/17] zd1211rw: let zd_set_beacon_interval() set dtim_period and add AP-beacon flag Jussi Kivilinna
2011-01-04 23:49 ` [RFC PATCH 09/17] zd1211rw: implement seq_num for IEEE80211_TX_CTL_ASSIGN_SEQ Jussi Kivilinna
2011-01-04 23:49 ` [RFC PATCH 10/17] zd1211rw: implement beacon fetching and handling ieee80211_get_buffered_bc() Jussi Kivilinna
2011-01-06 21:46 ` Christian Lamparter
2011-01-06 21:55 ` Johannes Berg
2011-01-09 15:46 ` Jussi Kivilinna
2011-01-09 20:33 ` Christian Lamparter
2011-01-19 18:49 ` Jussi Kivilinna
2011-01-19 20:22 ` Christian Lamparter
2011-01-20 8:16 ` Jussi Kivilinna
2011-01-20 9:13 ` Helmut Schaa
2011-01-20 17:43 ` Christian Lamparter
2011-01-04 23:49 ` [RFC PATCH 11/17] zd1211rw: add beacon watchdog and setting HW beacon more failsafe Jussi Kivilinna
2011-01-04 23:49 ` [RFC PATCH 12/17] zd1211rw: batch beacon config commands together Jussi Kivilinna
2011-01-04 23:49 ` [RFC PATCH 13/17] zd1211rw: use stack for small cmd-buffers Jussi Kivilinna
2011-01-05 9:27 ` Johannes Berg
2011-01-06 18:55 ` Dan Williams
2011-01-06 21:53 ` Jussi Kivilinna
2011-01-04 23:49 ` [RFC PATCH 14/17] zd1211rw: lower hw command timeouts Jussi Kivilinna
2011-01-04 23:49 ` [RFC PATCH 15/17] zd1211rw: collect driver settings and add function to restore theim Jussi Kivilinna
2011-01-04 23:50 ` [RFC PATCH 16/17] zd1211rw: add tx watchdog Jussi Kivilinna
2011-01-04 23:50 ` [RFC PATCH 17/17] zd1211rw: enable NL80211_IFTYPE_AP Jussi Kivilinna
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20110104234754.25309.54906.stgit@fate.lan \
--to=jussi.kivilinna@mbnet.fi \
--cc=dsd@gentoo.org \
--cc=kune@deine-taler.de \
--cc=linux-wireless@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).