aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorSujith Manoharan <Sujith.Manoharan@atheros.com>2011-04-13 01:56:46 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-04-13 15:24:34 -0400
commit2f80194c90caea3668d0e3739518bf100449a813 (patch)
treee5b60d2bb06af20fe77198166cf21c0f60103a28 /drivers/net
parent859c3ca1e4608615788dc6cbc199210fe4b5efa2 (diff)
ath9k_htc: Use separate URB pool for management frames
Beacon transmission needs to involve as little latency as possible after receiving a SWBA event from the target. Since packets are buffered to use TX stream mode, beacon frames sometimes gets queued up and are not sent out immediately. Fix this by decoupling management frame transmission from the normal data path and send them out immediately. Signed-off-by: Sujith Manoharan <Sujith.Manoharan@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c116
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.h1
2 files changed, 108 insertions, 9 deletions
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 7fae79d16665..3b0efab65131 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -78,7 +78,7 @@ static void hif_usb_regout_cb(struct urb *urb)
78 78
79 if (cmd) { 79 if (cmd) {
80 ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle, 80 ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle,
81 cmd->skb, 1); 81 cmd->skb, true);
82 kfree(cmd); 82 kfree(cmd);
83 } 83 }
84 84
@@ -124,6 +124,90 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev,
124 return ret; 124 return ret;
125} 125}
126 126
127static void hif_usb_mgmt_cb(struct urb *urb)
128{
129 struct cmd_buf *cmd = (struct cmd_buf *)urb->context;
130 struct hif_device_usb *hif_dev = cmd->hif_dev;
131 bool txok = true;
132
133 if (!cmd || !cmd->skb || !cmd->hif_dev)
134 return;
135
136 switch (urb->status) {
137 case 0:
138 break;
139 case -ENOENT:
140 case -ECONNRESET:
141 case -ENODEV:
142 case -ESHUTDOWN:
143 txok = false;
144
145 /*
146 * If the URBs are being flushed, no need to complete
147 * this packet.
148 */
149 spin_lock(&hif_dev->tx.tx_lock);
150 if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) {
151 spin_unlock(&hif_dev->tx.tx_lock);
152 dev_kfree_skb_any(cmd->skb);
153 kfree(cmd);
154 return;
155 }
156 spin_unlock(&hif_dev->tx.tx_lock);
157
158 break;
159 default:
160 txok = false;
161 break;
162 }
163
164 skb_pull(cmd->skb, 4);
165 ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle,
166 cmd->skb, txok);
167 kfree(cmd);
168}
169
170static int hif_usb_send_mgmt(struct hif_device_usb *hif_dev,
171 struct sk_buff *skb)
172{
173 struct urb *urb;
174 struct cmd_buf *cmd;
175 int ret = 0;
176 __le16 *hdr;
177
178 urb = usb_alloc_urb(0, GFP_ATOMIC);
179 if (urb == NULL)
180 return -ENOMEM;
181
182 cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
183 if (cmd == NULL) {
184 usb_free_urb(urb);
185 return -ENOMEM;
186 }
187
188 cmd->skb = skb;
189 cmd->hif_dev = hif_dev;
190
191 hdr = (__le16 *) skb_push(skb, 4);
192 *hdr++ = cpu_to_le16(skb->len - 4);
193 *hdr++ = cpu_to_le16(ATH_USB_TX_STREAM_MODE_TAG);
194
195 usb_fill_bulk_urb(urb, hif_dev->udev,
196 usb_sndbulkpipe(hif_dev->udev, USB_WLAN_TX_PIPE),
197 skb->data, skb->len,
198 hif_usb_mgmt_cb, cmd);
199
200 usb_anchor_urb(urb, &hif_dev->mgmt_submitted);
201 ret = usb_submit_urb(urb, GFP_ATOMIC);
202 if (ret) {
203 usb_unanchor_urb(urb);
204 kfree(cmd);
205 }
206 usb_free_urb(urb);
207
208 return ret;
209}
210
127static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev, 211static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev,
128 struct sk_buff_head *list) 212 struct sk_buff_head *list)
129{ 213{
@@ -275,6 +359,7 @@ static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb)
275{ 359{
276 struct ath9k_htc_tx_ctl *tx_ctl; 360 struct ath9k_htc_tx_ctl *tx_ctl;
277 unsigned long flags; 361 unsigned long flags;
362 int ret = 0;
278 363
279 spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); 364 spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
280 365
@@ -289,25 +374,33 @@ static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb)
289 return -ENOMEM; 374 return -ENOMEM;
290 } 375 }
291 376
292 __skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb); 377 spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
293 hif_dev->tx.tx_skb_cnt++;
294 378
295 tx_ctl = HTC_SKB_CB(skb); 379 tx_ctl = HTC_SKB_CB(skb);
296 380
297 /* Send normal/mgmt/beacon frames immediately */ 381 /* Mgmt/Beacon frames don't use the TX buffer pool */
298 if (tx_ctl->type != ATH9K_HTC_AMPDU) 382 if ((tx_ctl->type == ATH9K_HTC_MGMT) ||
299 __hif_usb_tx(hif_dev); 383 (tx_ctl->type == ATH9K_HTC_BEACON)) {
384 ret = hif_usb_send_mgmt(hif_dev, skb);
385 }
386
387 spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
388
389 if ((tx_ctl->type == ATH9K_HTC_NORMAL) ||
390 (tx_ctl->type == ATH9K_HTC_AMPDU)) {
391 __skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb);
392 hif_dev->tx.tx_skb_cnt++;
393 }
300 394
301 /* Check if AMPDUs have to be sent immediately */ 395 /* Check if AMPDUs have to be sent immediately */
302 if ((tx_ctl->type == ATH9K_HTC_AMPDU) && 396 if ((hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) &&
303 (hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) &&
304 (hif_dev->tx.tx_skb_cnt < 2)) { 397 (hif_dev->tx.tx_skb_cnt < 2)) {
305 __hif_usb_tx(hif_dev); 398 __hif_usb_tx(hif_dev);
306 } 399 }
307 400
308 spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); 401 spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
309 402
310 return 0; 403 return ret;
311} 404}
312 405
313static void hif_usb_start(void *hif_handle) 406static void hif_usb_start(void *hif_handle)
@@ -339,6 +432,8 @@ static void hif_usb_stop(void *hif_handle)
339 &hif_dev->tx.tx_pending, list) { 432 &hif_dev->tx.tx_pending, list) {
340 usb_kill_urb(tx_buf->urb); 433 usb_kill_urb(tx_buf->urb);
341 } 434 }
435
436 usb_kill_anchored_urbs(&hif_dev->mgmt_submitted);
342} 437}
343 438
344static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb) 439static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb)
@@ -657,6 +752,8 @@ static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
657 kfree(tx_buf->buf); 752 kfree(tx_buf->buf);
658 kfree(tx_buf); 753 kfree(tx_buf);
659 } 754 }
755
756 usb_kill_anchored_urbs(&hif_dev->mgmt_submitted);
660} 757}
661 758
662static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev) 759static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev)
@@ -668,6 +765,7 @@ static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev)
668 INIT_LIST_HEAD(&hif_dev->tx.tx_pending); 765 INIT_LIST_HEAD(&hif_dev->tx.tx_pending);
669 spin_lock_init(&hif_dev->tx.tx_lock); 766 spin_lock_init(&hif_dev->tx.tx_lock);
670 __skb_queue_head_init(&hif_dev->tx.tx_skb_queue); 767 __skb_queue_head_init(&hif_dev->tx.tx_skb_queue);
768 init_usb_anchor(&hif_dev->mgmt_submitted);
671 769
672 for (i = 0; i < MAX_TX_URB_NUM; i++) { 770 for (i = 0; i < MAX_TX_URB_NUM; i++) {
673 tx_buf = kzalloc(sizeof(struct tx_buf), GFP_KERNEL); 771 tx_buf = kzalloc(sizeof(struct tx_buf), GFP_KERNEL);
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h
index 8b98d646e91a..f59df48a86e2 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.h
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.h
@@ -93,6 +93,7 @@ struct hif_device_usb {
93 struct usb_anchor regout_submitted; 93 struct usb_anchor regout_submitted;
94 struct usb_anchor rx_submitted; 94 struct usb_anchor rx_submitted;
95 struct usb_anchor reg_in_submitted; 95 struct usb_anchor reg_in_submitted;
96 struct usb_anchor mgmt_submitted;
96 struct sk_buff *remain_skb; 97 struct sk_buff *remain_skb;
97 const char *fw_name; 98 const char *fw_name;
98 int rx_remain_len; 99 int rx_remain_len;