Commit ff8f59b5 authored by Sujith Manoharan's avatar Sujith Manoharan Committed by John W. Linville

ath9k_htc: Handle pending URBs properly

When doing a channel change, the pending URBs have to be killed
properly on calling htc_stop().

This fixes the probe response timeout seen when sending UDP traffic at
a high rate and running background scan at the same time.

Cc: stable <stable@kernel.org>
Signed-off-by: default avatarSujith Manoharan <Sujith.Manoharan@atheros.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent ee832d3e
...@@ -153,16 +153,36 @@ static void hif_usb_tx_cb(struct urb *urb) ...@@ -153,16 +153,36 @@ static void hif_usb_tx_cb(struct urb *urb)
case -ENODEV: case -ENODEV:
case -ESHUTDOWN: case -ESHUTDOWN:
/* /*
* The URB has been killed, free the SKBs * The URB has been killed, free the SKBs.
* and return.
*/ */
ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
return;
/*
* If the URBs are being flushed, no need to add this
* URB to the free list.
*/
spin_lock(&hif_dev->tx.tx_lock);
if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) {
spin_unlock(&hif_dev->tx.tx_lock);
return;
}
spin_unlock(&hif_dev->tx.tx_lock);
/*
* In the stop() case, this URB has to be added to
* the free list.
*/
goto add_free;
default: default:
break; break;
} }
/* Check if TX has been stopped */ /*
* Check if TX has been stopped, this is needed because
* this CB could have been invoked just after the TX lock
* was released in hif_stop() and kill_urb() hasn't been
* called yet.
*/
spin_lock(&hif_dev->tx.tx_lock); spin_lock(&hif_dev->tx.tx_lock);
if (hif_dev->tx.flags & HIF_USB_TX_STOP) { if (hif_dev->tx.flags & HIF_USB_TX_STOP) {
spin_unlock(&hif_dev->tx.tx_lock); spin_unlock(&hif_dev->tx.tx_lock);
...@@ -314,6 +334,7 @@ static void hif_usb_start(void *hif_handle, u8 pipe_id) ...@@ -314,6 +334,7 @@ static void hif_usb_start(void *hif_handle, u8 pipe_id)
static void hif_usb_stop(void *hif_handle, u8 pipe_id) static void hif_usb_stop(void *hif_handle, u8 pipe_id)
{ {
struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
...@@ -321,6 +342,12 @@ static void hif_usb_stop(void *hif_handle, u8 pipe_id) ...@@ -321,6 +342,12 @@ static void hif_usb_stop(void *hif_handle, u8 pipe_id)
hif_dev->tx.tx_skb_cnt = 0; hif_dev->tx.tx_skb_cnt = 0;
hif_dev->tx.flags |= HIF_USB_TX_STOP; hif_dev->tx.flags |= HIF_USB_TX_STOP;
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
/* The pending URBs have to be canceled. */
list_for_each_entry_safe(tx_buf, tx_buf_tmp,
&hif_dev->tx.tx_pending, list) {
usb_kill_urb(tx_buf->urb);
}
} }
static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb, static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb,
...@@ -587,6 +614,7 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb) ...@@ -587,6 +614,7 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev) static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
{ {
struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL; struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
unsigned long flags;
list_for_each_entry_safe(tx_buf, tx_buf_tmp, list_for_each_entry_safe(tx_buf, tx_buf_tmp,
&hif_dev->tx.tx_buf, list) { &hif_dev->tx.tx_buf, list) {
...@@ -597,6 +625,10 @@ static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev) ...@@ -597,6 +625,10 @@ static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
kfree(tx_buf); kfree(tx_buf);
} }
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
hif_dev->tx.flags |= HIF_USB_TX_FLUSH;
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
list_for_each_entry_safe(tx_buf, tx_buf_tmp, list_for_each_entry_safe(tx_buf, tx_buf_tmp,
&hif_dev->tx.tx_pending, list) { &hif_dev->tx.tx_pending, list) {
usb_kill_urb(tx_buf->urb); usb_kill_urb(tx_buf->urb);
......
...@@ -64,6 +64,7 @@ struct tx_buf { ...@@ -64,6 +64,7 @@ struct tx_buf {
}; };
#define HIF_USB_TX_STOP BIT(0) #define HIF_USB_TX_STOP BIT(0)
#define HIF_USB_TX_FLUSH BIT(1)
struct hif_usb_tx { struct hif_usb_tx {
u8 flags; u8 flags;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment