diff options
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hif_usb.c | 55 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc.h | 6 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_debug.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_gpio.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_main.c | 15 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 31 |
6 files changed, 69 insertions, 49 deletions
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 0b63a48462c7..db07e7b93204 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c | |||
@@ -131,7 +131,19 @@ static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev, | |||
131 | 131 | ||
132 | while ((skb = __skb_dequeue(list)) != NULL) { | 132 | while ((skb = __skb_dequeue(list)) != NULL) { |
133 | dev_kfree_skb_any(skb); | 133 | dev_kfree_skb_any(skb); |
134 | TX_STAT_INC(skb_dropped); | 134 | } |
135 | } | ||
136 | |||
137 | static inline void ath9k_skb_queue_complete(struct hif_device_usb *hif_dev, | ||
138 | struct sk_buff_head *queue, | ||
139 | bool txok) | ||
140 | { | ||
141 | struct sk_buff *skb; | ||
142 | |||
143 | while ((skb = __skb_dequeue(queue)) != NULL) { | ||
144 | ath9k_htc_txcompletion_cb(hif_dev->htc_handle, | ||
145 | skb, txok); | ||
146 | (txok) ? TX_STAT_INC(skb_success) : TX_STAT_INC(skb_failed); | ||
135 | } | 147 | } |
136 | } | 148 | } |
137 | 149 | ||
@@ -139,7 +151,7 @@ static void hif_usb_tx_cb(struct urb *urb) | |||
139 | { | 151 | { |
140 | struct tx_buf *tx_buf = (struct tx_buf *) urb->context; | 152 | struct tx_buf *tx_buf = (struct tx_buf *) urb->context; |
141 | struct hif_device_usb *hif_dev; | 153 | struct hif_device_usb *hif_dev; |
142 | struct sk_buff *skb; | 154 | bool txok = true; |
143 | 155 | ||
144 | if (!tx_buf || !tx_buf->hif_dev) | 156 | if (!tx_buf || !tx_buf->hif_dev) |
145 | return; | 157 | return; |
@@ -153,10 +165,7 @@ static void hif_usb_tx_cb(struct urb *urb) | |||
153 | case -ECONNRESET: | 165 | case -ECONNRESET: |
154 | case -ENODEV: | 166 | case -ENODEV: |
155 | case -ESHUTDOWN: | 167 | case -ESHUTDOWN: |
156 | /* | 168 | txok = false; |
157 | * The URB has been killed, free the SKBs. | ||
158 | */ | ||
159 | ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); | ||
160 | 169 | ||
161 | /* | 170 | /* |
162 | * If the URBs are being flushed, no need to add this | 171 | * If the URBs are being flushed, no need to add this |
@@ -165,41 +174,19 @@ static void hif_usb_tx_cb(struct urb *urb) | |||
165 | spin_lock(&hif_dev->tx.tx_lock); | 174 | spin_lock(&hif_dev->tx.tx_lock); |
166 | if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) { | 175 | if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) { |
167 | spin_unlock(&hif_dev->tx.tx_lock); | 176 | spin_unlock(&hif_dev->tx.tx_lock); |
177 | ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); | ||
168 | return; | 178 | return; |
169 | } | 179 | } |
170 | spin_unlock(&hif_dev->tx.tx_lock); | 180 | spin_unlock(&hif_dev->tx.tx_lock); |
171 | 181 | ||
172 | /* | 182 | break; |
173 | * In the stop() case, this URB has to be added to | ||
174 | * the free list. | ||
175 | */ | ||
176 | goto add_free; | ||
177 | default: | 183 | default: |
184 | txok = false; | ||
178 | break; | 185 | break; |
179 | } | 186 | } |
180 | 187 | ||
181 | /* | 188 | ath9k_skb_queue_complete(hif_dev, &tx_buf->skb_queue, txok); |
182 | * Check if TX has been stopped, this is needed because | ||
183 | * this CB could have been invoked just after the TX lock | ||
184 | * was released in hif_stop() and kill_urb() hasn't been | ||
185 | * called yet. | ||
186 | */ | ||
187 | spin_lock(&hif_dev->tx.tx_lock); | ||
188 | if (hif_dev->tx.flags & HIF_USB_TX_STOP) { | ||
189 | spin_unlock(&hif_dev->tx.tx_lock); | ||
190 | ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); | ||
191 | goto add_free; | ||
192 | } | ||
193 | spin_unlock(&hif_dev->tx.tx_lock); | ||
194 | |||
195 | /* Complete the queued SKBs. */ | ||
196 | while ((skb = __skb_dequeue(&tx_buf->skb_queue)) != NULL) { | ||
197 | ath9k_htc_txcompletion_cb(hif_dev->htc_handle, | ||
198 | skb, 1); | ||
199 | TX_STAT_INC(skb_completed); | ||
200 | } | ||
201 | 189 | ||
202 | add_free: | ||
203 | /* Re-initialize the SKB queue */ | 190 | /* Re-initialize the SKB queue */ |
204 | tx_buf->len = tx_buf->offset = 0; | 191 | tx_buf->len = tx_buf->offset = 0; |
205 | __skb_queue_head_init(&tx_buf->skb_queue); | 192 | __skb_queue_head_init(&tx_buf->skb_queue); |
@@ -272,7 +259,7 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev) | |||
272 | ret = usb_submit_urb(tx_buf->urb, GFP_ATOMIC); | 259 | ret = usb_submit_urb(tx_buf->urb, GFP_ATOMIC); |
273 | if (ret) { | 260 | if (ret) { |
274 | tx_buf->len = tx_buf->offset = 0; | 261 | tx_buf->len = tx_buf->offset = 0; |
275 | ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue); | 262 | ath9k_skb_queue_complete(hif_dev, &tx_buf->skb_queue, false); |
276 | __skb_queue_head_init(&tx_buf->skb_queue); | 263 | __skb_queue_head_init(&tx_buf->skb_queue); |
277 | list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf); | 264 | list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf); |
278 | hif_dev->tx.tx_buf_cnt++; | 265 | hif_dev->tx.tx_buf_cnt++; |
@@ -342,7 +329,7 @@ static void hif_usb_stop(void *hif_handle, u8 pipe_id) | |||
342 | unsigned long flags; | 329 | unsigned long flags; |
343 | 330 | ||
344 | spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); | 331 | spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); |
345 | ath9k_skb_queue_purge(hif_dev, &hif_dev->tx.tx_skb_queue); | 332 | ath9k_skb_queue_complete(hif_dev, &hif_dev->tx.tx_skb_queue, false); |
346 | hif_dev->tx.tx_skb_cnt = 0; | 333 | hif_dev->tx.tx_skb_cnt = 0; |
347 | hif_dev->tx.flags |= HIF_USB_TX_STOP; | 334 | hif_dev->tx.flags |= HIF_USB_TX_STOP; |
348 | spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); | 335 | spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); |
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 45cf75579438..0d2e2b10358d 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h | |||
@@ -271,6 +271,7 @@ struct ath9k_htc_tx { | |||
271 | u8 flags; | 271 | u8 flags; |
272 | int queued_cnt; | 272 | int queued_cnt; |
273 | struct sk_buff_head tx_queue; | 273 | struct sk_buff_head tx_queue; |
274 | struct sk_buff_head tx_failed; | ||
274 | DECLARE_BITMAP(tx_slot, MAX_TX_BUF_NUM); | 275 | DECLARE_BITMAP(tx_slot, MAX_TX_BUF_NUM); |
275 | spinlock_t tx_lock; | 276 | spinlock_t tx_lock; |
276 | }; | 277 | }; |
@@ -305,8 +306,8 @@ struct ath_tx_stats { | |||
305 | u32 buf_queued; | 306 | u32 buf_queued; |
306 | u32 buf_completed; | 307 | u32 buf_completed; |
307 | u32 skb_queued; | 308 | u32 skb_queued; |
308 | u32 skb_completed; | 309 | u32 skb_success; |
309 | u32 skb_dropped; | 310 | u32 skb_failed; |
310 | u32 cab_queued; | 311 | u32 cab_queued; |
311 | u32 queue_stats[WME_NUM_AC]; | 312 | u32 queue_stats[WME_NUM_AC]; |
312 | }; | 313 | }; |
@@ -544,6 +545,7 @@ void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv); | |||
544 | void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv); | 545 | void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv); |
545 | int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv); | 546 | int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv); |
546 | void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot); | 547 | void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot); |
548 | void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv); | ||
547 | 549 | ||
548 | int ath9k_rx_init(struct ath9k_htc_priv *priv); | 550 | int ath9k_rx_init(struct ath9k_htc_priv *priv); |
549 | void ath9k_rx_cleanup(struct ath9k_htc_priv *priv); | 551 | void ath9k_rx_cleanup(struct ath9k_htc_priv *priv); |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index 6fc6cb749362..91a486cca32a 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c | |||
@@ -88,11 +88,11 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf, | |||
88 | "%20s : %10u\n", "SKBs queued", | 88 | "%20s : %10u\n", "SKBs queued", |
89 | priv->debug.tx_stats.skb_queued); | 89 | priv->debug.tx_stats.skb_queued); |
90 | len += snprintf(buf + len, sizeof(buf) - len, | 90 | len += snprintf(buf + len, sizeof(buf) - len, |
91 | "%20s : %10u\n", "SKBs completed", | 91 | "%20s : %10u\n", "SKBs success", |
92 | priv->debug.tx_stats.skb_completed); | 92 | priv->debug.tx_stats.skb_success); |
93 | len += snprintf(buf + len, sizeof(buf) - len, | 93 | len += snprintf(buf + len, sizeof(buf) - len, |
94 | "%20s : %10u\n", "SKBs dropped", | 94 | "%20s : %10u\n", "SKBs failed", |
95 | priv->debug.tx_stats.skb_dropped); | 95 | priv->debug.tx_stats.skb_failed); |
96 | len += snprintf(buf + len, sizeof(buf) - len, | 96 | len += snprintf(buf + len, sizeof(buf) - len, |
97 | "%20s : %10u\n", "CAB queued", | 97 | "%20s : %10u\n", "CAB queued", |
98 | priv->debug.tx_stats.cab_queued); | 98 | priv->debug.tx_stats.cab_queued); |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index 92e4b312a98b..dc0b33d01210 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c | |||
@@ -429,9 +429,8 @@ void ath9k_htc_radio_disable(struct ieee80211_hw *hw) | |||
429 | 429 | ||
430 | /* Stop TX */ | 430 | /* Stop TX */ |
431 | ieee80211_stop_queues(hw); | 431 | ieee80211_stop_queues(hw); |
432 | htc_stop(priv->htc); | 432 | ath9k_htc_tx_drain(priv); |
433 | WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); | 433 | WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); |
434 | skb_queue_purge(&priv->tx.tx_queue); | ||
435 | 434 | ||
436 | /* Stop RX */ | 435 | /* Stop RX */ |
437 | WMI_CMD(WMI_STOP_RECV_CMDID); | 436 | WMI_CMD(WMI_STOP_RECV_CMDID); |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index c7e056b40e1d..fb9ff1188a0a 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c | |||
@@ -193,7 +193,9 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv) | |||
193 | 193 | ||
194 | ath9k_htc_stop_ani(priv); | 194 | ath9k_htc_stop_ani(priv); |
195 | ieee80211_stop_queues(priv->hw); | 195 | ieee80211_stop_queues(priv->hw); |
196 | htc_stop(priv->htc); | 196 | |
197 | ath9k_htc_tx_drain(priv); | ||
198 | |||
197 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | 199 | WMI_CMD(WMI_DISABLE_INTR_CMDID); |
198 | WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); | 200 | WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); |
199 | WMI_CMD(WMI_STOP_RECV_CMDID); | 201 | WMI_CMD(WMI_STOP_RECV_CMDID); |
@@ -248,7 +250,9 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, | |||
248 | fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); | 250 | fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); |
249 | 251 | ||
250 | ath9k_htc_ps_wakeup(priv); | 252 | ath9k_htc_ps_wakeup(priv); |
251 | htc_stop(priv->htc); | 253 | |
254 | ath9k_htc_tx_drain(priv); | ||
255 | |||
252 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | 256 | WMI_CMD(WMI_DISABLE_INTR_CMDID); |
253 | WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); | 257 | WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); |
254 | WMI_CMD(WMI_STOP_RECV_CMDID); | 258 | WMI_CMD(WMI_STOP_RECV_CMDID); |
@@ -263,6 +267,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, | |||
263 | 267 | ||
264 | if (!fastcc) | 268 | if (!fastcc) |
265 | caldata = &priv->caldata; | 269 | caldata = &priv->caldata; |
270 | |||
266 | ret = ath9k_hw_reset(ah, hchan, caldata, fastcc); | 271 | ret = ath9k_hw_reset(ah, hchan, caldata, fastcc); |
267 | if (ret) { | 272 | if (ret) { |
268 | ath_err(common, | 273 | ath_err(common, |
@@ -960,16 +965,14 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) | |||
960 | } | 965 | } |
961 | 966 | ||
962 | ath9k_htc_ps_wakeup(priv); | 967 | ath9k_htc_ps_wakeup(priv); |
963 | htc_stop(priv->htc); | 968 | |
964 | WMI_CMD(WMI_DISABLE_INTR_CMDID); | 969 | WMI_CMD(WMI_DISABLE_INTR_CMDID); |
965 | WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); | 970 | WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); |
966 | WMI_CMD(WMI_STOP_RECV_CMDID); | 971 | WMI_CMD(WMI_STOP_RECV_CMDID); |
967 | 972 | ||
968 | tasklet_kill(&priv->rx_tasklet); | 973 | tasklet_kill(&priv->rx_tasklet); |
969 | tasklet_kill(&priv->tx_tasklet); | ||
970 | |||
971 | skb_queue_purge(&priv->tx.tx_queue); | ||
972 | 974 | ||
975 | ath9k_htc_tx_drain(priv); | ||
973 | ath9k_wmi_event_drain(priv); | 976 | ath9k_wmi_event_drain(priv); |
974 | 977 | ||
975 | mutex_unlock(&priv->mutex); | 978 | mutex_unlock(&priv->mutex); |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 944440c84c49..9e0c34b0a794 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | |||
@@ -423,6 +423,26 @@ send_mac80211: | |||
423 | ieee80211_tx_status(priv->hw, skb); | 423 | ieee80211_tx_status(priv->hw, skb); |
424 | } | 424 | } |
425 | 425 | ||
426 | void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv) | ||
427 | { | ||
428 | struct sk_buff *skb = NULL; | ||
429 | |||
430 | /* | ||
431 | * Ensure that all pending TX frames are flushed, | ||
432 | * and that the TX completion tasklet is killed. | ||
433 | */ | ||
434 | htc_stop(priv->htc); | ||
435 | tasklet_kill(&priv->tx_tasklet); | ||
436 | |||
437 | while ((skb = skb_dequeue(&priv->tx.tx_queue)) != NULL) { | ||
438 | ath9k_htc_tx_process(priv, skb); | ||
439 | } | ||
440 | |||
441 | while ((skb = skb_dequeue(&priv->tx.tx_failed)) != NULL) { | ||
442 | ath9k_htc_tx_process(priv, skb); | ||
443 | } | ||
444 | } | ||
445 | |||
426 | void ath9k_tx_tasklet(unsigned long data) | 446 | void ath9k_tx_tasklet(unsigned long data) |
427 | { | 447 | { |
428 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; | 448 | struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; |
@@ -432,6 +452,10 @@ void ath9k_tx_tasklet(unsigned long data) | |||
432 | ath9k_htc_tx_process(priv, skb); | 452 | ath9k_htc_tx_process(priv, skb); |
433 | } | 453 | } |
434 | 454 | ||
455 | while ((skb = skb_dequeue(&priv->tx.tx_failed)) != NULL) { | ||
456 | ath9k_htc_tx_process(priv, skb); | ||
457 | } | ||
458 | |||
435 | /* Wake TX queues if needed */ | 459 | /* Wake TX queues if needed */ |
436 | ath9k_htc_check_wake_queues(priv); | 460 | ath9k_htc_check_wake_queues(priv); |
437 | } | 461 | } |
@@ -445,13 +469,18 @@ void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, | |||
445 | tx_ctl = HTC_SKB_CB(skb); | 469 | tx_ctl = HTC_SKB_CB(skb); |
446 | tx_ctl->txok = txok; | 470 | tx_ctl->txok = txok; |
447 | 471 | ||
448 | skb_queue_tail(&priv->tx.tx_queue, skb); | 472 | if (txok) |
473 | skb_queue_tail(&priv->tx.tx_queue, skb); | ||
474 | else | ||
475 | skb_queue_tail(&priv->tx.tx_failed, skb); | ||
476 | |||
449 | tasklet_schedule(&priv->tx_tasklet); | 477 | tasklet_schedule(&priv->tx_tasklet); |
450 | } | 478 | } |
451 | 479 | ||
452 | int ath9k_tx_init(struct ath9k_htc_priv *priv) | 480 | int ath9k_tx_init(struct ath9k_htc_priv *priv) |
453 | { | 481 | { |
454 | skb_queue_head_init(&priv->tx.tx_queue); | 482 | skb_queue_head_init(&priv->tx.tx_queue); |
483 | skb_queue_head_init(&priv->tx.tx_failed); | ||
455 | return 0; | 484 | return 0; |
456 | } | 485 | } |
457 | 486 | ||