Commit 84c9e164 authored by Sujith Manoharan's avatar Sujith Manoharan Committed by John W. Linville

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: default avatarSujith Manoharan <Sujith.Manoharan@atheros.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent e1fe7c38
...@@ -363,6 +363,40 @@ static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb) ...@@ -363,6 +363,40 @@ static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb)
return ret; return ret;
} }
static inline bool check_index(struct sk_buff *skb, u8 idx)
{
struct ath9k_htc_tx_ctl *tx_ctl;
tx_ctl = HTC_SKB_CB(skb);
if ((tx_ctl->type == ATH9K_HTC_AMPDU) &&
(tx_ctl->sta_idx == idx))
return true;
return false;
}
static void hif_usb_sta_drain(void *hif_handle, u8 idx)
{
struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
struct sk_buff *skb, *tmp;
unsigned long flags;
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
skb_queue_walk_safe(&hif_dev->tx.tx_skb_queue, skb, tmp) {
if (check_index(skb, idx)) {
__skb_unlink(skb, &hif_dev->tx.tx_skb_queue);
ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
skb, false);
hif_dev->tx.tx_skb_cnt--;
TX_STAT_INC(skb_failed);
}
}
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
}
static struct ath9k_htc_hif hif_usb = { static struct ath9k_htc_hif hif_usb = {
.transport = ATH9K_HIF_USB, .transport = ATH9K_HIF_USB,
.name = "ath9k_hif_usb", .name = "ath9k_hif_usb",
...@@ -372,6 +406,7 @@ static struct ath9k_htc_hif hif_usb = { ...@@ -372,6 +406,7 @@ static struct ath9k_htc_hif hif_usb = {
.start = hif_usb_start, .start = hif_usb_start,
.stop = hif_usb_stop, .stop = hif_usb_stop,
.sta_drain = hif_usb_sta_drain,
.send = hif_usb_send, .send = hif_usb_send,
}; };
......
...@@ -280,6 +280,7 @@ struct ath9k_htc_tx_ctl { ...@@ -280,6 +280,7 @@ struct ath9k_htc_tx_ctl {
u8 type; /* ATH9K_HTC_* */ u8 type; /* ATH9K_HTC_* */
u8 epid; u8 epid;
u8 txok; u8 txok;
u8 sta_idx;
}; };
static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb) static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb)
......
...@@ -1303,10 +1303,13 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw, ...@@ -1303,10 +1303,13 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw,
struct ieee80211_sta *sta) struct ieee80211_sta *sta)
{ {
struct ath9k_htc_priv *priv = hw->priv; struct ath9k_htc_priv *priv = hw->priv;
struct ath9k_htc_sta *ista;
int ret; int ret;
mutex_lock(&priv->mutex); mutex_lock(&priv->mutex);
ath9k_htc_ps_wakeup(priv); ath9k_htc_ps_wakeup(priv);
ista = (struct ath9k_htc_sta *) sta->drv_priv;
htc_sta_drain(priv->htc, ista->index);
ret = ath9k_htc_remove_station(priv, vif, sta); ret = ath9k_htc_remove_station(priv, vif, sta);
ath9k_htc_ps_restore(priv); ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex); mutex_unlock(&priv->mutex);
......
...@@ -248,6 +248,14 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, ...@@ -248,6 +248,14 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv,
tx_hdr.vif_idx = vif_idx; tx_hdr.vif_idx = vif_idx;
tx_hdr.cookie = slot; tx_hdr.cookie = slot;
/*
* This is a bit redundant but it helps to get
* the per-packet index quickly when draining the
* TX queue in the HIF layer. Otherwise we would
* have to parse the packet contents ...
*/
tx_ctl->sta_idx = sta_idx;
if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
tx_ctl->type = ATH9K_HTC_AMPDU; tx_ctl->type = ATH9K_HTC_AMPDU;
tx_hdr.data_type = ATH9K_HTC_AMPDU; tx_hdr.data_type = ATH9K_HTC_AMPDU;
......
...@@ -310,6 +310,11 @@ void htc_start(struct htc_target *target) ...@@ -310,6 +310,11 @@ void htc_start(struct htc_target *target)
target->hif->start(target->hif_dev); target->hif->start(target->hif_dev);
} }
void htc_sta_drain(struct htc_target *target, u8 idx)
{
target->hif->sta_drain(target->hif_dev, idx);
}
void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle, void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
struct sk_buff *skb, bool txok) struct sk_buff *skb, bool txok)
{ {
......
...@@ -35,6 +35,7 @@ struct ath9k_htc_hif { ...@@ -35,6 +35,7 @@ struct ath9k_htc_hif {
void (*start) (void *hif_handle); void (*start) (void *hif_handle);
void (*stop) (void *hif_handle); void (*stop) (void *hif_handle);
void (*sta_drain) (void *hif_handle, u8 idx);
int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf); int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf);
}; };
...@@ -209,6 +210,7 @@ int htc_send_epid(struct htc_target *target, struct sk_buff *skb, ...@@ -209,6 +210,7 @@ int htc_send_epid(struct htc_target *target, struct sk_buff *skb,
enum htc_endpoint_id epid); enum htc_endpoint_id epid);
void htc_stop(struct htc_target *target); void htc_stop(struct htc_target *target);
void htc_start(struct htc_target *target); void htc_start(struct htc_target *target);
void htc_sta_drain(struct htc_target *target, u8 idx);
void ath9k_htc_rx_msg(struct htc_target *htc_handle, void ath9k_htc_rx_msg(struct htc_target *htc_handle,
struct sk_buff *skb, u32 len, u8 pipe_id); struct sk_buff *skb, u32 len, u8 pipe_id);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment