diff options
author | Russell King (Oracle) <rmk+kernel@armlinux.org.uk> | 2024-05-23 08:37:47 +0100 |
---|---|---|
committer | Russell King (Oracle) <rmk+kernel@armlinux.org.uk> | 2025-04-04 15:28:29 +0100 |
commit | d09e192b851cf39b715e54f9bd80e78397f17618 (patch) | |
tree | 6bd2206f070440ddd49af861230e84b4c4aa2d1a | |
parent | 38fec10eb60d687e30c8c6b5420d86e8149f7557 (diff) |
net: wlcore: implement .flush_sta operation
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
-rw-r--r-- | drivers/net/wireless/ti/wlcore/main.c | 10 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wlcore/tx.c | 47 | ||||
-rw-r--r-- | drivers/net/wireless/ti/wlcore/tx.h | 1 |
3 files changed, 58 insertions, 0 deletions
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 8fb58a5d911c..5c05023f5e28 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -5656,6 +5656,15 @@ static void wlcore_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, wl1271_tx_flush(wl); } +static void wlcore_op_flush_sta(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct wl1271 *wl = hw->priv; + + wl1271_tx_flush_sta(wl, sta); +} + static int wlcore_op_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel *chan, @@ -6045,6 +6054,7 @@ static const struct ieee80211_ops wl1271_ops = { .channel_switch = wl12xx_op_channel_switch, .channel_switch_beacon = wlcore_op_channel_switch_beacon, .flush = wlcore_op_flush, + .flush_sta = wlcore_op_flush_sta, .remain_on_channel = wlcore_op_remain_on_channel, .cancel_remain_on_channel = wlcore_op_cancel_remain_on_channel, .add_chanctx = wlcore_op_add_chanctx, diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c index 464587d16ab2..9d6b5115db09 100644 --- a/drivers/net/wireless/ti/wlcore/tx.c +++ b/drivers/net/wireless/ti/wlcore/tx.c @@ -1181,6 +1181,53 @@ out: } EXPORT_SYMBOL_GPL(wl1271_tx_flush); +void wl1271_tx_flush_sta(struct wl1271 *wl, struct ieee80211_sta *sta) +{ + u8 hlid = wl1271_station(sta)->hlid; + bool frames_queued = false; + unsigned long timeout; + int i; + + mutex_lock(&wl->mutex); + /* Flush queued packets for the link associated with this station */ + wl1271_tx_reset_link_queues(wl, hlid); + + /* Wait for any frames to be transmitted */ + timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT); + while (!time_after(jiffies, timeout)) { + frames_queued = false; + + /* Are there any frames for this hlid? */ + for (i = 0; i < WLCORE_MAX_TX_DESCRIPTORS; i++) { + struct wl1271_tx_hw_descr *desc; + struct sk_buff *skb; + + skb = wl->tx_frames[i]; + if (!skb) + continue; + + desc = (struct wl1271_tx_hw_descr *)skb->data; + if (desc->hlid == hlid) { + frames_queued = true; + break; + } + } + + if (!frames_queued) + break; + + mutex_unlock(&wl->mutex); + msleep(20); + mutex_lock(&wl->mutex); + } + + if (frames_queued) + wl1271_warning("Unable to flush all frames for station %pM\n", + sta->addr); + + mutex_unlock(&wl->mutex); +} + u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set) { if (WARN_ON(!rate_set)) diff --git a/drivers/net/wireless/ti/wlcore/tx.h b/drivers/net/wireless/ti/wlcore/tx.h index 9069bcf87158..e113ecca1b1d 100644 --- a/drivers/net/wireless/ti/wlcore/tx.h +++ b/drivers/net/wireless/ti/wlcore/tx.h @@ -232,6 +232,7 @@ int wlcore_tx_complete(struct wl1271 *wl); void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif); void wl12xx_tx_reset(struct wl1271 *wl); void wl1271_tx_flush(struct wl1271 *wl); +void wl1271_tx_flush_sta(struct wl1271 *wl, struct ieee80211_sta *sta); u8 wlcore_rate_to_idx(struct wl1271 *wl, u8 rate, enum nl80211_band band); u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, enum nl80211_band rate_band); |