diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hif_usb.c | 116 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hif_usb.h | 1 |
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 | ||
127 | static 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 | |||
170 | static 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 | |||
127 | static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev, | 211 | static 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 | ||
313 | static void hif_usb_start(void *hif_handle) | 406 | static 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 | ||
344 | static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb) | 439 | static 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 | ||
662 | static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev) | 759 | static 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; |