diff options
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hif_usb.c | 35 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_main.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_hst.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_hst.h | 2 |
6 files changed, 54 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index b3f23c2be73..7fae79d1666 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c | |||
@@ -363,6 +363,40 @@ static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb) | |||
363 | return ret; | 363 | return ret; |
364 | } | 364 | } |
365 | 365 | ||
366 | static inline bool check_index(struct sk_buff *skb, u8 idx) | ||
367 | { | ||
368 | struct ath9k_htc_tx_ctl *tx_ctl; | ||
369 | |||
370 | tx_ctl = HTC_SKB_CB(skb); | ||
371 | |||
372 | if ((tx_ctl->type == ATH9K_HTC_AMPDU) && | ||
373 | (tx_ctl->sta_idx == idx)) | ||
374 | return true; | ||
375 | |||
376 | return false; | ||
377 | } | ||
378 | |||
379 | static void hif_usb_sta_drain(void *hif_handle, u8 idx) | ||
380 | { | ||
381 | struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle; | ||
382 | struct sk_buff *skb, *tmp; | ||
383 | unsigned long flags; | ||
384 | |||
385 | spin_lock_irqsave(&hif_dev->tx.tx_lock, flags); | ||
386 | |||
387 | skb_queue_walk_safe(&hif_dev->tx.tx_skb_queue, skb, tmp) { | ||
388 | if (check_index(skb, idx)) { | ||
389 | __skb_unlink(skb, &hif_dev->tx.tx_skb_queue); | ||
390 | ath9k_htc_txcompletion_cb(hif_dev->htc_handle, | ||
391 | skb, false); | ||
392 | hif_dev->tx.tx_skb_cnt--; | ||
393 | TX_STAT_INC(skb_failed); | ||
394 | } | ||
395 | } | ||
396 | |||
397 | spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags); | ||
398 | } | ||
399 | |||
366 | static struct ath9k_htc_hif hif_usb = { | 400 | static struct ath9k_htc_hif hif_usb = { |
367 | .transport = ATH9K_HIF_USB, | 401 | .transport = ATH9K_HIF_USB, |
368 | .name = "ath9k_hif_usb", | 402 | .name = "ath9k_hif_usb", |
@@ -372,6 +406,7 @@ static struct ath9k_htc_hif hif_usb = { | |||
372 | 406 | ||
373 | .start = hif_usb_start, | 407 | .start = hif_usb_start, |
374 | .stop = hif_usb_stop, | 408 | .stop = hif_usb_stop, |
409 | .sta_drain = hif_usb_sta_drain, | ||
375 | .send = hif_usb_send, | 410 | .send = hif_usb_send, |
376 | }; | 411 | }; |
377 | 412 | ||
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 0d2e2b10358..41823fd6d9a 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h | |||
@@ -280,6 +280,7 @@ struct ath9k_htc_tx_ctl { | |||
280 | u8 type; /* ATH9K_HTC_* */ | 280 | u8 type; /* ATH9K_HTC_* */ |
281 | u8 epid; | 281 | u8 epid; |
282 | u8 txok; | 282 | u8 txok; |
283 | u8 sta_idx; | ||
283 | }; | 284 | }; |
284 | 285 | ||
285 | static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb) | 286 | static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb) |
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index fb9ff1188a0..ae85cc4373f 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c | |||
@@ -1303,10 +1303,13 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw, | |||
1303 | struct ieee80211_sta *sta) | 1303 | struct ieee80211_sta *sta) |
1304 | { | 1304 | { |
1305 | struct ath9k_htc_priv *priv = hw->priv; | 1305 | struct ath9k_htc_priv *priv = hw->priv; |
1306 | struct ath9k_htc_sta *ista; | ||
1306 | int ret; | 1307 | int ret; |
1307 | 1308 | ||
1308 | mutex_lock(&priv->mutex); | 1309 | mutex_lock(&priv->mutex); |
1309 | ath9k_htc_ps_wakeup(priv); | 1310 | ath9k_htc_ps_wakeup(priv); |
1311 | ista = (struct ath9k_htc_sta *) sta->drv_priv; | ||
1312 | htc_sta_drain(priv->htc, ista->index); | ||
1310 | ret = ath9k_htc_remove_station(priv, vif, sta); | 1313 | ret = ath9k_htc_remove_station(priv, vif, sta); |
1311 | ath9k_htc_ps_restore(priv); | 1314 | ath9k_htc_ps_restore(priv); |
1312 | mutex_unlock(&priv->mutex); | 1315 | 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 9e0c34b0a79..0790070a7f6 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | |||
@@ -248,6 +248,14 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, | |||
248 | tx_hdr.vif_idx = vif_idx; | 248 | tx_hdr.vif_idx = vif_idx; |
249 | tx_hdr.cookie = slot; | 249 | tx_hdr.cookie = slot; |
250 | 250 | ||
251 | /* | ||
252 | * This is a bit redundant but it helps to get | ||
253 | * the per-packet index quickly when draining the | ||
254 | * TX queue in the HIF layer. Otherwise we would | ||
255 | * have to parse the packet contents ... | ||
256 | */ | ||
257 | tx_ctl->sta_idx = sta_idx; | ||
258 | |||
251 | if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { | 259 | if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { |
252 | tx_ctl->type = ATH9K_HTC_AMPDU; | 260 | tx_ctl->type = ATH9K_HTC_AMPDU; |
253 | tx_hdr.data_type = ATH9K_HTC_AMPDU; | 261 | tx_hdr.data_type = ATH9K_HTC_AMPDU; |
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c index 7ced8ab1ae4..5c76352b131 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.c +++ b/drivers/net/wireless/ath/ath9k/htc_hst.c | |||
@@ -310,6 +310,11 @@ void htc_start(struct htc_target *target) | |||
310 | target->hif->start(target->hif_dev); | 310 | target->hif->start(target->hif_dev); |
311 | } | 311 | } |
312 | 312 | ||
313 | void htc_sta_drain(struct htc_target *target, u8 idx) | ||
314 | { | ||
315 | target->hif->sta_drain(target->hif_dev, idx); | ||
316 | } | ||
317 | |||
313 | void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, | 318 | void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, |
314 | struct sk_buff *skb, bool txok) | 319 | struct sk_buff *skb, bool txok) |
315 | { | 320 | { |
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h index 191e3c0837a..cb9174ade53 100644 --- a/drivers/net/wireless/ath/ath9k/htc_hst.h +++ b/drivers/net/wireless/ath/ath9k/htc_hst.h | |||
@@ -35,6 +35,7 @@ struct ath9k_htc_hif { | |||
35 | 35 | ||
36 | void (*start) (void *hif_handle); | 36 | void (*start) (void *hif_handle); |
37 | void (*stop) (void *hif_handle); | 37 | void (*stop) (void *hif_handle); |
38 | void (*sta_drain) (void *hif_handle, u8 idx); | ||
38 | int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf); | 39 | int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf); |
39 | }; | 40 | }; |
40 | 41 | ||
@@ -209,6 +210,7 @@ int htc_send_epid(struct htc_target *target, struct sk_buff *skb, | |||
209 | enum htc_endpoint_id epid); | 210 | enum htc_endpoint_id epid); |
210 | void htc_stop(struct htc_target *target); | 211 | void htc_stop(struct htc_target *target); |
211 | void htc_start(struct htc_target *target); | 212 | void htc_start(struct htc_target *target); |
213 | void htc_sta_drain(struct htc_target *target, u8 idx); | ||
212 | 214 | ||
213 | void ath9k_htc_rx_msg(struct htc_target *htc_handle, | 215 | void ath9k_htc_rx_msg(struct htc_target *htc_handle, |
214 | struct sk_buff *skb, u32 len, u8 pipe_id); | 216 | struct sk_buff *skb, u32 len, u8 pipe_id); |