ath9k_htc: Simplify TX URB management
[safe/jmp/linux-2.6] / drivers / net / wireless / ath / ath9k / hif_usb.c
index 3091bb3..cee5feb 100644 (file)
@@ -93,14 +93,24 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev,
        return ret;
 }
 
+static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev,
+                                        struct sk_buff_head *list)
+{
+       struct sk_buff *skb;
+
+       while ((skb = __skb_dequeue(list)) != NULL) {
+               dev_kfree_skb_any(skb);
+               TX_STAT_INC(skb_dropped);
+       }
+}
+
 static void hif_usb_tx_cb(struct urb *urb)
 {
        struct tx_buf *tx_buf = (struct tx_buf *) urb->context;
        struct hif_device_usb *hif_dev = tx_buf->hif_dev;
        struct sk_buff *skb;
-       bool drop, flush;
 
-       if (!hif_dev)
+       if (!hif_dev || !tx_buf)
                return;
 
        switch (urb->status) {
@@ -108,57 +118,47 @@ static void hif_usb_tx_cb(struct urb *urb)
                break;
        case -ENOENT:
        case -ECONNRESET:
-               break;
        case -ENODEV:
        case -ESHUTDOWN:
+               /*
+                * The URB has been killed, free the SKBs
+                * and return.
+                */
+               ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
                return;
        default:
                break;
        }
 
-       if (tx_buf) {
-               spin_lock(&hif_dev->tx.tx_lock);
-               drop = !!(hif_dev->tx.flags & HIF_USB_TX_STOP);
-               flush = !!(hif_dev->tx.flags & HIF_USB_TX_FLUSH);
-               spin_unlock(&hif_dev->tx.tx_lock);
-
-               while ((skb = __skb_dequeue(&tx_buf->skb_queue)) != NULL) {
-                       if (!drop && !flush) {
-                               ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
-                                                         skb, 1);
-                               TX_STAT_INC(skb_completed);
-                       } else {
-                               dev_kfree_skb_any(skb);
-                               TX_STAT_INC(skb_dropped);
-                       }
-               }
-
-               if (flush)
-                       return;
-
-               tx_buf->len = tx_buf->offset = 0;
-               __skb_queue_head_init(&tx_buf->skb_queue);
-
-               spin_lock(&hif_dev->tx.tx_lock);
-               list_del(&tx_buf->list);
-               list_add_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
-               hif_dev->tx.tx_buf_cnt++;
-               if (!drop)
-                       __hif_usb_tx(hif_dev); /* Check for pending SKBs */
-               TX_STAT_INC(buf_completed);
+       /* Check if TX has been stopped */
+       spin_lock(&hif_dev->tx.tx_lock);
+       if (hif_dev->tx.flags & HIF_USB_TX_STOP) {
                spin_unlock(&hif_dev->tx.tx_lock);
-       }
-}
-
-static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev,
-                                        struct sk_buff_head *list)
-{
-       struct sk_buff *skb;
-
-       while ((skb = __skb_dequeue(list)) != NULL) {
-               dev_kfree_skb_any(skb);
-               TX_STAT_INC(skb_dropped);
-       }
+               ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
+               goto add_free;
+       }
+       spin_unlock(&hif_dev->tx.tx_lock);
+
+       /* Complete the queued SKBs. */
+       while ((skb = __skb_dequeue(&tx_buf->skb_queue)) != NULL) {
+               ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
+                                         skb, 1);
+               TX_STAT_INC(skb_completed);
+       }
+
+add_free:
+       /* Re-initialize the SKB queue */
+       tx_buf->len = tx_buf->offset = 0;
+       __skb_queue_head_init(&tx_buf->skb_queue);
+
+       /* Add this TX buffer to the free list */
+       spin_lock(&hif_dev->tx.tx_lock);
+       list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
+       hif_dev->tx.tx_buf_cnt++;
+       if (!(hif_dev->tx.flags & HIF_USB_TX_STOP))
+               __hif_usb_tx(hif_dev); /* Check for pending SKBs */
+       TX_STAT_INC(buf_completed);
+       spin_unlock(&hif_dev->tx.tx_lock);
 }
 
 /* TX lock has to be taken */
@@ -178,8 +178,7 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev)
                return 0;
 
        tx_buf = list_first_entry(&hif_dev->tx.tx_buf, struct tx_buf, list);
-       list_del(&tx_buf->list);
-       list_add_tail(&tx_buf->list, &hif_dev->tx.tx_pending);
+       list_move_tail(&tx_buf->list, &hif_dev->tx.tx_pending);
        hif_dev->tx.tx_buf_cnt--;
 
        tx_skb_cnt = min_t(u16, hif_dev->tx.tx_skb_cnt, MAX_TX_AGGR_NUM);
@@ -548,20 +547,17 @@ free:
 
 static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
 {
-       unsigned long flags;
        struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
 
-       list_for_each_entry_safe(tx_buf, tx_buf_tmp, &hif_dev->tx.tx_buf, list) {
+       list_for_each_entry_safe(tx_buf, tx_buf_tmp,
+                                &hif_dev->tx.tx_buf, list) {
+               usb_kill_urb(tx_buf->urb);
                list_del(&tx_buf->list);
                usb_free_urb(tx_buf->urb);
                kfree(tx_buf->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,
                                 &hif_dev->tx.tx_pending, list) {
                usb_kill_urb(tx_buf->urb);
@@ -570,10 +566,6 @@ static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
                kfree(tx_buf->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);
 }
 
 static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev)