diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 8533b88974b2..38c0cabe52bf 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -731,12 +731,38 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb) kfree(rx_buf); } +static void ath9k_hif_usb_reg_in_resubmit(struct work_struct *work) +{ + struct rx_buf *rx_buf = container_of(work, + struct rx_buf, + work); + struct hif_device_usb *hif_dev = rx_buf->hif_dev; + struct urb *urb = rx_buf->urb; + int ret; + + if (!hif_dev || !urb) + goto free_rx_buf; + + usb_anchor_urb(urb, &hif_dev->reg_in_submitted); + ret = usb_submit_urb(urb, GFP_KERNEL); + if (ret) { + usb_unanchor_urb(urb); + goto free_skb; + } + return; + +free_skb: + kfree_skb(rx_buf->skb); +free_rx_buf: + kfree(rx_buf); + urb->context = NULL; +} + 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,13 +812,9 @@ 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; - } - + rx_buf->urb = urb; + INIT_WORK(&rx_buf->work, ath9k_hif_usb_reg_in_resubmit); + schedule_work(&rx_buf->work); return; free_skb: kfree_skb(skb); diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h index b3e66b0485a5..7c2a8d2c1cca 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.h +++ b/drivers/net/wireless/ath/ath9k/hif_usb.h @@ -89,6 +89,8 @@ struct tx_buf { struct rx_buf { struct sk_buff *skb; struct hif_device_usb *hif_dev; + struct urb *urb; + struct work_struct work; }; #define HIF_USB_TX_STOP BIT(0)