aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/hif_usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/hif_usb.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c46
1 files changed, 39 insertions, 7 deletions
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 22b68b3c8566..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);
@@ -993,16 +1025,16 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface)
993{ 1025{
994 struct usb_device *udev = interface_to_usbdev(interface); 1026 struct usb_device *udev = interface_to_usbdev(interface);
995 struct hif_device_usb *hif_dev = usb_get_intfdata(interface); 1027 struct hif_device_usb *hif_dev = usb_get_intfdata(interface);
1028 bool unplugged = (udev->state == USB_STATE_NOTATTACHED) ? true : false;
996 1029
997 if (hif_dev) { 1030 if (hif_dev) {
998 ath9k_htc_hw_deinit(hif_dev->htc_handle, 1031 ath9k_htc_hw_deinit(hif_dev->htc_handle, unplugged);
999 (udev->state == USB_STATE_NOTATTACHED) ? true : false);
1000 ath9k_htc_hw_free(hif_dev->htc_handle); 1032 ath9k_htc_hw_free(hif_dev->htc_handle);
1001 ath9k_hif_usb_dev_deinit(hif_dev); 1033 ath9k_hif_usb_dev_deinit(hif_dev);
1002 usb_set_intfdata(interface, NULL); 1034 usb_set_intfdata(interface, NULL);
1003 } 1035 }
1004 1036
1005 if (hif_dev->flags & HIF_USB_START) 1037 if (!unplugged && (hif_dev->flags & HIF_USB_START))
1006 ath9k_hif_usb_reboot(udev); 1038 ath9k_hif_usb_reboot(udev);
1007 1039
1008 kfree(hif_dev); 1040 kfree(hif_dev);