diff options
author | Christian Lamparter <chunkeey@web.de> | 2009-07-06 15:17:56 +0200 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-07-10 15:02:30 -0400 |
commit | 6d541a684d7eb72c71eaba82b09a360c96609134 (patch) | |
tree | 7f96d9eae6ad0aa232678e576248744f98804220 | |
parent | 1be491fca12ff599c37ceaf7e9042ebee9f0068e (diff) |
p54usb: fix stalls caused by urb allocation failures
This patch squashes a few old bugs, which have been around since
the initial version of p54usb in one form or another.
we never freed a orphaned frame, when were denied the resources,
which are necessary to pass the data into the usb subsystem.
As a result we could end up with a full queue that wasn't emptied,
until the device was brought down.
Signed-off-by: Christian Lamparter <chunkeey@web.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/p54/p54usb.c | 36 |
1 files changed, 17 insertions, 19 deletions
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 461d88f5ceb..e44460ff149 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -246,8 +246,10 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb) struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr); data_urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!data_urb) + if (!data_urb) { + p54_free_skb(dev, skb); return; + } hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len); hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id; @@ -269,27 +271,22 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb) static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54u_priv *priv = dev->priv; - struct urb *int_urb, *data_urb; + struct urb *int_urb = NULL, *data_urb = NULL; struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr); - struct net2280_reg_write *reg; - int err = 0; + struct net2280_reg_write *reg = NULL; + int err = -ENOMEM; reg = kmalloc(sizeof(*reg), GFP_ATOMIC); if (!reg) - return; + goto out; int_urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!int_urb) { - kfree(reg); - return; - } + if (!int_urb) + goto out; data_urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!data_urb) { - kfree(reg); - usb_free_urb(int_urb); - return; - } + if (!data_urb) + goto out; reg->port = cpu_to_le16(NET2280_DEV_U32); reg->addr = cpu_to_le32(P54U_DEV_BASE); @@ -304,11 +301,12 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb) p54u_tx_dummy_cb, dev); /* - * This flag triggers a code path in the USB subsystem that will - * free what's inside the transfer_buffer after the callback routine - * has completed. + * URB_FREE_BUFFER triggers a code path in the USB subsystem that will + * free what is inside the transfer_buffer after the last reference to + * the int_urb is dropped. */ int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET; + reg = NULL; usb_fill_bulk_urb(data_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), @@ -329,12 +327,12 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb) usb_unanchor_urb(data_urb); goto out; } - out: +out: usb_free_urb(int_urb); usb_free_urb(data_urb); if (err) { - skb_pull(skb, sizeof(*hdr)); + kfree(reg); p54_free_skb(dev, skb); } } |