From: Christian Lamparter <chunkeey@web.de>
To: Larry Finger <Larry.Finger@lwfinger.net>
Cc: wireless <linux-wireless@vger.kernel.org>
Subject: Re: p54usb problems
Date: Fri, 19 Dec 2008 02:54:23 +0100 [thread overview]
Message-ID: <200812190254.23731.chunkeey@web.de> (raw)
In-Reply-To: <4949B566.20008@lwfinger.net>
[-- Attachment #1: Type: text/plain, Size: 1159 bytes --]
On Thursday 18 December 2008 03:28:54 Larry Finger wrote:
> Christian Lamparter wrote:
> > hmm, I wonder why it's a "order:1" allocation, even on x86-64 the skb_shared_struct is less than 300 bytes
> > and the maximum rx_mtu size about 3240 so there should be room left.... of course, it's not really a big
> > deal for p54, since we don't have to support frames larger RTS or Fragmentation threshold anyway...
> > but what about 11n devices? aren't they suffer from the same problems under load?
>
> The actual size requested is 520 bytes bigger than what is asked for plus the L1
> cache alignment, which is getting close to 4000 bytes. If I missed something, it
> could be over 4096.
>
> Larry
Oh well, looks like iwlwifi had this problems as well:
http://git.kernel.org/?p=linux/kernel/git/linville/wireless-testing.git;a=commit;h=7b52beeab30692f4b92c8efc9f806794c6b03473
anyway, I've attached an early RFC, in which the RX refilling is offloaded into a workqueue.
The locking is a maybe a bit overkill, and make C=2 produces a warning, (not to mention checkpatch.pl ;) )
but it didn't crash/freeze/burn here and Its really late here.
Regards,
Chr
[-- Attachment #2: p54usb-refill-work.diff --]
[-- Type: text/x-patch, Size: 6375 bytes --]
diff -Nurp a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
--- a/drivers/net/wireless/p54/p54usb.c 2008-12-19 00:31:46.000000000 +0100
+++ b/drivers/net/wireless/p54/p54usb.c 2008-12-19 02:42:05.000000000 +0100
@@ -85,6 +85,7 @@ static void p54u_rx_cb(struct urb *urb)
struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
struct ieee80211_hw *dev = info->dev;
struct p54u_priv *priv = dev->priv;
+ unsigned long flags;
skb_unlink(skb, &priv->rx_queue);
@@ -103,17 +104,17 @@ static void p54u_rx_cb(struct urb *urb)
}
if (p54_rx(dev, skb)) {
- skb = dev_alloc_skb(priv->common.rx_mtu + 32);
- if (unlikely(!skb)) {
- /* TODO check rx queue length and refill *somewhere* */
- return;
- }
-
- info = (struct p54u_rx_info *) skb->cb;
- info->urb = urb;
- info->dev = dev;
- urb->transfer_buffer = skb_tail_pointer(skb);
- urb->context = skb;
+ spin_lock_irqsave(&priv->refill_lock, flags);
+ list_add_tail(&urb->urb_list, &priv->refill_list);
+ spin_unlock_irqrestore(&priv->refill_lock, flags);
+ urb->transfer_buffer = NULL;
+ urb->context = NULL;
+
+ /*
+ * don't let the usb stack free the urb.
+ */
+ usb_get_urb(urb);
+ schedule_work(&priv->work);
} else {
if (priv->hw_type == P54U_NET2280)
skb_push(skb, priv->common.tx_hdr_len);
@@ -128,13 +129,13 @@ static void p54u_rx_cb(struct urb *urb)
WARN_ON(1);
urb->transfer_buffer = skb_tail_pointer(skb);
}
- }
- skb_queue_tail(&priv->rx_queue, skb);
- usb_anchor_urb(urb, &priv->submitted);
- if (usb_submit_urb(urb, GFP_ATOMIC)) {
- skb_unlink(skb, &priv->rx_queue);
- usb_unanchor_urb(urb);
- dev_kfree_skb_irq(skb);
+
+ usb_anchor_urb(urb, &priv->submitted);
+ if (usb_submit_urb(urb, GFP_ATOMIC)) {
+ usb_unanchor_urb(urb);
+ dev_kfree_skb_irq(skb);
+ } else
+ skb_queue_tail(&priv->rx_queue, skb);
}
}
@@ -152,58 +153,101 @@ static void p54u_tx_cb(struct urb *urb)
static void p54u_tx_dummy_cb(struct urb *urb) { }
+static void p54u_free_refill(struct ieee80211_hw *dev)
+{
+ struct p54u_priv *priv = dev->priv;
+ struct urb *entry, *tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->refill_lock, flags);
+ list_for_each_entry_safe(entry, tmp, &priv->refill_list, urb_list) {
+ list_del(&entry->urb_list);
+ usb_free_urb(entry);
+ }
+ spin_unlock_irqrestore(&priv->refill_lock, flags);
+}
+
static void p54u_free_urbs(struct ieee80211_hw *dev)
{
struct p54u_priv *priv = dev->priv;
usb_kill_anchored_urbs(&priv->submitted);
+ cancel_work_sync(&priv->work);
+ p54u_free_refill(dev);
}
-static int p54u_init_urbs(struct ieee80211_hw *dev)
+static int p54u_refill_rx(struct ieee80211_hw *dev)
{
struct p54u_priv *priv = dev->priv;
- struct urb *entry = NULL;
- struct sk_buff *skb;
- struct p54u_rx_info *info;
- int ret = 0;
+ struct urb* entry, *tmp;
+ unsigned long flags, flags2;
+
+ spin_lock_irqsave(&priv->refill_lock, flags);
+ list_for_each_entry_safe(entry, tmp, &priv->refill_list, urb_list) {
+ struct p54u_rx_info *info;
+ struct sk_buff *skb;
- while (skb_queue_len(&priv->rx_queue) < 32) {
+ list_del(&entry->urb_list);
+ spin_unlock_irqrestore(&priv->refill_lock, flags);
skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
- if (!skb) {
- ret = -ENOMEM;
- goto err;
- }
- entry = usb_alloc_urb(0, GFP_KERNEL);
- if (!entry) {
- ret = -ENOMEM;
- goto err;
+
+ if (unlikely(!skb)) {
+ spin_lock_irqsave(&priv->refill_lock, flags);
+ list_add(&entry->urb_list, &priv->refill_list);
+ continue;
}
usb_fill_bulk_urb(entry, priv->udev,
usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
skb_tail_pointer(skb),
priv->common.rx_mtu + 32, p54u_rx_cb, skb);
+
info = (struct p54u_rx_info *) skb->cb;
info->urb = entry;
info->dev = dev;
- skb_queue_tail(&priv->rx_queue, skb);
+ spin_lock_irqsave(&priv->rx_queue.lock, flags2);
+ __skb_queue_tail(&priv->rx_queue, skb);
usb_anchor_urb(entry, &priv->submitted);
- ret = usb_submit_urb(entry, GFP_KERNEL);
- if (ret) {
- skb_unlink(skb, &priv->rx_queue);
- usb_unanchor_urb(entry);
- goto err;
+ if (usb_submit_urb(entry, GFP_ATOMIC)) {
+ __skb_unlink(skb, &priv->rx_queue);
+ spin_unlock_irqrestore(&priv->rx_queue.lock, flags2);
+ spin_lock_irqsave(&priv->refill_lock, flags);
+ list_add_tail(&entry->urb_list, &priv->refill_list);
+ spin_unlock_irqrestore(&priv->refill_lock, flags);
+ kfree_skb(skb);
}
+ spin_unlock_irqrestore(&priv->rx_queue.lock, flags2);
usb_free_urb(entry);
- entry = NULL;
+ spin_lock_irqsave(&priv->refill_lock, flags);
}
-
+ spin_unlock_irqrestore(&priv->refill_lock, flags);
return 0;
+}
+
+static int p54u_init_urbs(struct ieee80211_hw *dev)
+{
+ struct p54u_priv *priv = dev->priv;
+ struct urb *entry;
+ unsigned long flags;
+ int ret = 0;
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ entry = usb_alloc_urb(0, GFP_KERNEL);
+ if (!entry) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ spin_lock_irqsave(&priv->refill_lock, flags);
+ list_add_tail(&entry->urb_list, &priv->refill_list);
+ spin_unlock_irqrestore(&priv->refill_lock, flags);
+ }
+
+ p54u_refill_rx(dev);
err:
- usb_free_urb(entry);
- kfree_skb(skb);
- p54u_free_urbs(dev);
+ p54u_free_refill(dev);
return ret;
}
@@ -834,6 +878,12 @@ static int p54u_upload_firmware_net2280(
return err;
}
+static void p54u_work(struct work_struct *work)
+{
+ struct p54u_priv *priv = container_of(work, struct p54u_priv, work);
+ p54u_refill_rx(priv->common.hw);
+}
+
static int p54u_open(struct ieee80211_hw *dev)
{
struct p54u_priv *priv = dev->priv;
@@ -924,6 +974,9 @@ static int __devinit p54u_probe(struct u
skb_queue_head_init(&priv->rx_queue);
init_usb_anchor(&priv->submitted);
+ INIT_WORK(&priv->work, p54u_work);
+ spin_lock_init(&priv->refill_lock);
+ INIT_LIST_HEAD(&priv->refill_list);
p54u_open(dev);
err = p54_read_eeprom(dev);
diff -Nurp a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h
--- a/drivers/net/wireless/p54/p54usb.h 2008-12-19 00:31:48.000000000 +0100
+++ b/drivers/net/wireless/p54/p54usb.h 2008-12-19 01:33:06.000000000 +0100
@@ -134,6 +134,9 @@ struct p54u_priv {
spinlock_t lock;
struct sk_buff_head rx_queue;
struct usb_anchor submitted;
+ spinlock_t refill_lock;
+ struct list_head refill_list;
+ struct work_struct work;
};
#endif /* P54USB_H */
next prev parent reply other threads:[~2008-12-19 1:54 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-12-17 21:55 p54usb problems Larry Finger
2008-12-17 22:33 ` Christian Lamparter
2008-12-18 2:28 ` Larry Finger
2008-12-19 1:54 ` Christian Lamparter [this message]
[not found] <200812190306.52254.chunkeey@web.de>
2008-12-19 15:44 ` Larry Finger
2008-12-19 17:03 ` Christian Lamparter
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=200812190254.23731.chunkeey@web.de \
--to=chunkeey@web.de \
--cc=Larry.Finger@lwfinger.net \
--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).