summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King (Oracle) <rmk+kernel@armlinux.org.uk>2024-05-23 08:37:47 +0100
committerRussell King (Oracle) <rmk+kernel@armlinux.org.uk>2025-04-04 15:28:29 +0100
commitd09e192b851cf39b715e54f9bd80e78397f17618 (patch)
tree6bd2206f070440ddd49af861230e84b4c4aa2d1a
parent38fec10eb60d687e30c8c6b5420d86e8149f7557 (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.c10
-rw-r--r--drivers/net/wireless/ti/wlcore/tx.c47
-rw-r--r--drivers/net/wireless/ti/wlcore/tx.h1
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);