aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c106
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.h1
2 files changed, 49 insertions, 58 deletions
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 3091bb3cef9..cee5febb8a4 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -93,14 +93,24 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev,
93 return ret; 93 return ret;
94} 94}
95 95
96static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev,
97 struct sk_buff_head *list)
98{
99 struct sk_buff *skb;
100
101 while ((skb = __skb_dequeue(list)) != NULL) {
102 dev_kfree_skb_any(skb);
103 TX_STAT_INC(skb_dropped);
104 }
105}
106
96static void hif_usb_tx_cb(struct urb *urb) 107static void hif_usb_tx_cb(struct urb *urb)
97{ 108{
98 struct tx_buf *tx_buf = (struct tx_buf *) urb->context; 109 struct tx_buf *tx_buf = (struct tx_buf *) urb->context;
99 struct hif_device_usb *hif_dev = tx_buf->hif_dev; 110 struct hif_device_usb *hif_dev = tx_buf->hif_dev;
100 struct sk_buff *skb; 111 struct sk_buff *skb;
101 bool drop, flush;
102 112
103 if (!hif_dev) 113 if (!hif_dev || !tx_buf)
104 return; 114 return;
105 115
106 switch (urb->status) { 116 switch (urb->status) {
@@ -108,57 +118,47 @@ static void hif_usb_tx_cb(struct urb *urb)
108 break; 118 break;
109 case -ENOENT: 119 case -ENOENT:
110 case -ECONNRESET: 120 case -ECONNRESET:
111 break;
112 case -ENODEV: 121 case -ENODEV:
113 case -ESHUTDOWN: 122 case -ESHUTDOWN:
123 /*
124 * The URB has been killed, free the SKBs
125 * and return.
126 */
127 ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
114 return; 128 return;
115 default: 129 default:
116 break; 130 break;
117 } 131 }
118 132
119 if (tx_buf) { 133 /* Check if TX has been stopped */
120 spin_lock(&hif_dev->tx.tx_lock); 134 spin_lock(&hif_dev->tx.tx_lock);
121 drop = !!(hif_dev->tx.flags & HIF_USB_TX_STOP); 135 if (hif_dev->tx.flags & HIF_USB_TX_STOP) {
122 flush = !!(hif_dev->tx.flags & HIF_USB_TX_FLUSH);
123 spin_unlock(&hif_dev->tx.tx_lock);
124
125 while ((skb = __skb_dequeue(&tx_buf->skb_queue)) != NULL) {
126 if (!drop && !flush) {
127 ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
128 skb, 1);
129 TX_STAT_INC(skb_completed);
130 } else {
131 dev_kfree_skb_any(skb);
132 TX_STAT_INC(skb_dropped);
133 }
134 }
135
136 if (flush)
137 return;
138
139 tx_buf->len = tx_buf->offset = 0;
140 __skb_queue_head_init(&tx_buf->skb_queue);
141
142 spin_lock(&hif_dev->tx.tx_lock);
143 list_del(&tx_buf->list);
144 list_add_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
145 hif_dev->tx.tx_buf_cnt++;
146 if (!drop)
147 __hif_usb_tx(hif_dev); /* Check for pending SKBs */
148 TX_STAT_INC(buf_completed);
149 spin_unlock(&hif_dev->tx.tx_lock); 136 spin_unlock(&hif_dev->tx.tx_lock);
150 } 137 ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
151} 138 goto add_free;
152 139 }
153static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev, 140 spin_unlock(&hif_dev->tx.tx_lock);
154 struct sk_buff_head *list) 141
155{ 142 /* Complete the queued SKBs. */
156 struct sk_buff *skb; 143 while ((skb = __skb_dequeue(&tx_buf->skb_queue)) != NULL) {
157 144 ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
158 while ((skb = __skb_dequeue(list)) != NULL) { 145 skb, 1);
159 dev_kfree_skb_any(skb); 146 TX_STAT_INC(skb_completed);
160 TX_STAT_INC(skb_dropped); 147 }
161 } 148
149add_free:
150 /* Re-initialize the SKB queue */
151 tx_buf->len = tx_buf->offset = 0;
152 __skb_queue_head_init(&tx_buf->skb_queue);
153
154 /* Add this TX buffer to the free list */
155 spin_lock(&hif_dev->tx.tx_lock);
156 list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
157 hif_dev->tx.tx_buf_cnt++;
158 if (!(hif_dev->tx.flags & HIF_USB_TX_STOP))
159 __hif_usb_tx(hif_dev); /* Check for pending SKBs */
160 TX_STAT_INC(buf_completed);
161 spin_unlock(&hif_dev->tx.tx_lock);
162} 162}
163 163
164/* TX lock has to be taken */ 164/* TX lock has to be taken */
@@ -178,8 +178,7 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev)
178 return 0; 178 return 0;
179 179
180 tx_buf = list_first_entry(&hif_dev->tx.tx_buf, struct tx_buf, list); 180 tx_buf = list_first_entry(&hif_dev->tx.tx_buf, struct tx_buf, list);
181 list_del(&tx_buf->list); 181 list_move_tail(&tx_buf->list, &hif_dev->tx.tx_pending);
182 list_add_tail(&tx_buf->list, &hif_dev->tx.tx_pending);
183 hif_dev->tx.tx_buf_cnt--; 182 hif_dev->tx.tx_buf_cnt--;
184 183
185 tx_skb_cnt = min_t(u16, hif_dev->tx.tx_skb_cnt, MAX_TX_AGGR_NUM); 184 tx_skb_cnt = min_t(u16, hif_dev->tx.tx_skb_cnt, MAX_TX_AGGR_NUM);
@@ -548,20 +547,17 @@ free:
548 547
549static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev) 548static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
550{ 549{
551 unsigned long flags;
552 struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL; 550 struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
553 551
554 list_for_each_entry_safe(tx_buf, tx_buf_tmp, &hif_dev->tx.tx_buf, list) { 552 list_for_each_entry_safe(tx_buf, tx_buf_tmp,
553 &hif_dev->tx.tx_buf, list) {
554 usb_kill_urb(tx_buf->urb);
555 list_del(&tx_buf->list); 555 list_del(&tx_buf->list);
556 usb_free_urb(tx_buf->urb); 556 usb_free_urb(tx_buf->urb);
557 kfree(tx_buf->buf); 557 kfree(tx_buf->buf);
558 kfree(tx_buf); 558 kfree(tx_buf);
559 } 559 }
560 560
561 spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
562 hif_dev->tx.flags |= HIF_USB_TX_FLUSH;
563 spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
564
565 list_for_each_entry_safe(tx_buf, tx_buf_tmp, 561 list_for_each_entry_safe(tx_buf, tx_buf_tmp,
566 &hif_dev->tx.tx_pending, list) { 562 &hif_dev->tx.tx_pending, list) {
567 usb_kill_urb(tx_buf->urb); 563 usb_kill_urb(tx_buf->urb);
@@ -570,10 +566,6 @@ static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
570 kfree(tx_buf->buf); 566 kfree(tx_buf->buf);
571 kfree(tx_buf); 567 kfree(tx_buf);
572 } 568 }
573
574 spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
575 hif_dev->tx.flags &= ~HIF_USB_TX_FLUSH;
576 spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
577} 569}
578 570
579static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev) 571static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev)
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h
index 7d49a8af420..0aca49b6fcb 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.h
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.h
@@ -61,7 +61,6 @@ struct tx_buf {
61}; 61};
62 62
63#define HIF_USB_TX_STOP BIT(0) 63#define HIF_USB_TX_STOP BIT(0)
64#define HIF_USB_TX_FLUSH BIT(1)
65 64
66struct hif_usb_tx { 65struct hif_usb_tx {
67 u8 flags; 66 u8 flags;