diff options
author | Christian Lamparter <chunkeey@web.de> | 2009-07-06 09:17:56 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-07-10 15:02:30 -0400 |
commit | 6d541a684d7eb72c71eaba82b09a360c96609134 (patch) | |
tree | 7f96d9eae6ad0aa232678e576248744f98804220 /drivers | |
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>
Diffstat (limited to 'drivers')
-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 461d88f5ceb7..e44460ff149c 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) | |||
246 | struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr); | 246 | struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr); |
247 | 247 | ||
248 | data_urb = usb_alloc_urb(0, GFP_ATOMIC); | 248 | data_urb = usb_alloc_urb(0, GFP_ATOMIC); |
249 | if (!data_urb) | 249 | if (!data_urb) { |
250 | p54_free_skb(dev, skb); | ||
250 | return; | 251 | return; |
252 | } | ||
251 | 253 | ||
252 | hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len); | 254 | hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len); |
253 | hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id; | 255 | 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) | |||
269 | static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb) | 271 | static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb) |
270 | { | 272 | { |
271 | struct p54u_priv *priv = dev->priv; | 273 | struct p54u_priv *priv = dev->priv; |
272 | struct urb *int_urb, *data_urb; | 274 | struct urb *int_urb = NULL, *data_urb = NULL; |
273 | struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr); | 275 | struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr); |
274 | struct net2280_reg_write *reg; | 276 | struct net2280_reg_write *reg = NULL; |
275 | int err = 0; | 277 | int err = -ENOMEM; |
276 | 278 | ||
277 | reg = kmalloc(sizeof(*reg), GFP_ATOMIC); | 279 | reg = kmalloc(sizeof(*reg), GFP_ATOMIC); |
278 | if (!reg) | 280 | if (!reg) |
279 | return; | 281 | goto out; |
280 | 282 | ||
281 | int_urb = usb_alloc_urb(0, GFP_ATOMIC); | 283 | int_urb = usb_alloc_urb(0, GFP_ATOMIC); |
282 | if (!int_urb) { | 284 | if (!int_urb) |
283 | kfree(reg); | 285 | goto out; |
284 | return; | ||
285 | } | ||
286 | 286 | ||
287 | data_urb = usb_alloc_urb(0, GFP_ATOMIC); | 287 | data_urb = usb_alloc_urb(0, GFP_ATOMIC); |
288 | if (!data_urb) { | 288 | if (!data_urb) |
289 | kfree(reg); | 289 | goto out; |
290 | usb_free_urb(int_urb); | ||
291 | return; | ||
292 | } | ||
293 | 290 | ||
294 | reg->port = cpu_to_le16(NET2280_DEV_U32); | 291 | reg->port = cpu_to_le16(NET2280_DEV_U32); |
295 | reg->addr = cpu_to_le32(P54U_DEV_BASE); | 292 | 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) | |||
304 | p54u_tx_dummy_cb, dev); | 301 | p54u_tx_dummy_cb, dev); |
305 | 302 | ||
306 | /* | 303 | /* |
307 | * This flag triggers a code path in the USB subsystem that will | 304 | * URB_FREE_BUFFER triggers a code path in the USB subsystem that will |
308 | * free what's inside the transfer_buffer after the callback routine | 305 | * free what is inside the transfer_buffer after the last reference to |
309 | * has completed. | 306 | * the int_urb is dropped. |
310 | */ | 307 | */ |
311 | int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET; | 308 | int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET; |
309 | reg = NULL; | ||
312 | 310 | ||
313 | usb_fill_bulk_urb(data_urb, priv->udev, | 311 | usb_fill_bulk_urb(data_urb, priv->udev, |
314 | usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), | 312 | usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), |
@@ -329,12 +327,12 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
329 | usb_unanchor_urb(data_urb); | 327 | usb_unanchor_urb(data_urb); |
330 | goto out; | 328 | goto out; |
331 | } | 329 | } |
332 | out: | 330 | out: |
333 | usb_free_urb(int_urb); | 331 | usb_free_urb(int_urb); |
334 | usb_free_urb(data_urb); | 332 | usb_free_urb(data_urb); |
335 | 333 | ||
336 | if (err) { | 334 | if (err) { |
337 | skb_pull(skb, sizeof(*hdr)); | 335 | kfree(reg); |
338 | p54_free_skb(dev, skb); | 336 | p54_free_skb(dev, skb); |
339 | } | 337 | } |
340 | } | 338 | } |