diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 8533b88974b2..3ce598167731 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -731,12 +731,43 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb) kfree(rx_buf); } +struct reg_in_work { + struct urb *urb; + struct hif_device_usb *hif_dev; + struct work_struct work; +}; + +static void ath9k_hif_usb_reg_in_resubmit(struct work_struct *work) +{ + struct reg_in_work *rw = container_of(work, + struct reg_in_work, + work); + struct urb *urb = rw->urb; + struct rx_buf *rx_buf = urb->context; + + int ret; + + usb_anchor_urb(rw->urb, &rw->hif_dev->reg_in_submitted); + ret = usb_submit_urb(rw->urb, GFP_KERNEL); + usb_put_urb(rw->urb); + + if (ret) { + usb_unanchor_urb(rw->urb); + if (rx_buf) { + kfree_skb(rx_buf->skb); + kfree(rx_buf); + urb->context = NULL; + } + } + + kfree(rw); +} + static void ath9k_hif_usb_reg_in_cb(struct urb *urb) { struct rx_buf *rx_buf = urb->context; struct hif_device_usb *hif_dev = rx_buf->hif_dev; struct sk_buff *skb = rx_buf->skb; - int ret; if (!skb) return; @@ -786,14 +817,20 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb) } resubmit: - usb_anchor_urb(urb, &hif_dev->reg_in_submitted); - ret = usb_submit_urb(urb, GFP_ATOMIC); - if (ret) { - usb_unanchor_urb(urb); - goto free_skb; + { + struct reg_in_work *rw; + + rw = kmalloc_obj(*rw, GFP_ATOMIC); + if (!rw) + goto free_skb; + + rw->urb = urb; + rw->hif_dev = hif_dev; + usb_get_urb(urb); + INIT_WORK(&rw->work, ath9k_hif_usb_reg_in_resubmit); + schedule_work(&rw->work); + return; } - - return; free_skb: kfree_skb(skb); free_rx_buf: