aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSujith Manoharan <Sujith.Manoharan@atheros.com>2011-04-13 01:56:11 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-04-13 15:24:16 -0400
commit84c9e164468bd707e52b440e1c34bc3c85299332 (patch)
tree3abb317396af9864ccbe185f2d204471c50d89db
parente1fe7c38d39f8f6ebdffc3a55e2ec6e2ec0d1872 (diff)
ath9k_htc: Drain packets on station removal
When a station entry is removed, there could still be pending packets destined for that station in the HIF layer. Sending these to the target is not necessary, so drain them in the driver itself. Signed-off-by: Sujith Manoharan <Sujith.Manoharan@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c35
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_txrx.c8
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_hst.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_hst.h2
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
366static 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
379static 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
366static struct ath9k_htc_hif hif_usb = { 400static 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
285static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb) 286static 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
313void htc_sta_drain(struct htc_target *target, u8 idx)
314{
315 target->hif->sta_drain(target->hif_dev, idx);
316}
317
313void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, 318void 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);
210void htc_stop(struct htc_target *target); 211void htc_stop(struct htc_target *target);
211void htc_start(struct htc_target *target); 212void htc_start(struct htc_target *target);
213void htc_sta_drain(struct htc_target *target, u8 idx);
212 214
213void ath9k_htc_rx_msg(struct htc_target *htc_handle, 215void 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);