aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorSujith Manoharan <Sujith.Manoharan@atheros.com>2010-12-28 03:58:05 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-01-04 14:42:59 -0500
commitff8f59b5bbdf1527235b8c88d859c7d23691324f (patch)
tree7431f65095cef7dac5815816b0fb4ef8719feac4 /drivers/net/wireless
parentee832d3e9e72abf83931205a2f5379944be501c2 (diff)
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: Sujith Manoharan <Sujith.Manoharan@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c40
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.h1
2 files changed, 37 insertions, 4 deletions
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index c20c8c8201a2..5ab3084eb9cb 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -153,16 +153,36 @@ static void hif_usb_tx_cb(struct urb *urb)
153 case -ENODEV: 153 case -ENODEV:
154 case -ESHUTDOWN: 154 case -ESHUTDOWN:
155 /* 155 /*
156 * The URB has been killed, free the SKBs 156 * The URB has been killed, free the SKBs.
157 * and return.
158 */ 157 */
159 ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); 158 ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
160 return; 159
160 /*
161 * If the URBs are being flushed, no need to add this
162 * URB to the free list.
163 */
164 spin_lock(&hif_dev->tx.tx_lock);
165 if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) {
166 spin_unlock(&hif_dev->tx.tx_lock);
167 return;
168 }
169 spin_unlock(&hif_dev->tx.tx_lock);
170
171 /*
172 * In the stop() case, this URB has to be added to
173 * the free list.
174 */
175 goto add_free;
161 default: 176 default:
162 break; 177 break;
163 } 178 }
164 179
165 /* Check if TX has been stopped */ 180 /*
181 * Check if TX has been stopped, this is needed because
182 * this CB could have been invoked just after the TX lock
183 * was released in hif_stop() and kill_urb() hasn't been
184 * called yet.
185 */
166 spin_lock(&hif_dev->tx.tx_lock); 186 spin_lock(&hif_dev->tx.tx_lock);
167 if (hif_dev->tx.flags & HIF_USB_TX_STOP) { 187 if (hif_dev->tx.flags & HIF_USB_TX_STOP) {
168 spin_unlock(&hif_dev->tx.tx_lock); 188 spin_unlock(&hif_dev->tx.tx_lock);
@@ -314,6 +334,7 @@ static void hif_usb_start(void *hif_handle, u8 pipe_id)
314static void hif_usb_stop(void *hif_handle, u8 pipe_id) 334static void hif_usb_stop(void *hif_handle, u8 pipe_id)
315{ 335{
316 struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; 336 struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
337 struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
317 unsigned long flags; 338 unsigned long flags;
318 339
319 spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); 340 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 hif_dev->tx.tx_skb_cnt = 0; 342 hif_dev->tx.tx_skb_cnt = 0;
322 hif_dev->tx.flags |= HIF_USB_TX_STOP; 343 hif_dev->tx.flags |= HIF_USB_TX_STOP;
323 spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); 344 spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
345
346 /* The pending URBs have to be canceled. */
347 list_for_each_entry_safe(tx_buf, tx_buf_tmp,
348 &hif_dev->tx.tx_pending, list) {
349 usb_kill_urb(tx_buf->urb);
350 }
324} 351}
325 352
326static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb, 353static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb,
@@ -587,6 +614,7 @@ free:
587static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev) 614static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
588{ 615{
589 struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL; 616 struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
617 unsigned long flags;
590 618
591 list_for_each_entry_safe(tx_buf, tx_buf_tmp, 619 list_for_each_entry_safe(tx_buf, tx_buf_tmp,
592 &hif_dev->tx.tx_buf, list) { 620 &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 kfree(tx_buf); 625 kfree(tx_buf);
598 } 626 }
599 627
628 spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
629 hif_dev->tx.flags |= HIF_USB_TX_FLUSH;
630 spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
631
600 list_for_each_entry_safe(tx_buf, tx_buf_tmp, 632 list_for_each_entry_safe(tx_buf, tx_buf_tmp,
601 &hif_dev->tx.tx_pending, list) { 633 &hif_dev->tx.tx_pending, list) {
602 usb_kill_urb(tx_buf->urb); 634 usb_kill_urb(tx_buf->urb);
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h
index e4a5e2e79541..7b9d863d4035 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.h
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.h
@@ -64,6 +64,7 @@ struct tx_buf {
64}; 64};
65 65
66#define HIF_USB_TX_STOP BIT(0) 66#define HIF_USB_TX_STOP BIT(0)
67#define HIF_USB_TX_FLUSH BIT(1)
67 68
68struct hif_usb_tx { 69struct hif_usb_tx {
69 u8 flags; 70 u8 flags;