* [PATCH wireless-next 0/2] wifi: cfg80211/mac80211: optimize station info handling
@ 2026-04-28 9:09 Sarika Sharma
2026-04-28 9:09 ` [PATCH wireless-next 1/2] wifi: cfg80211/mac80211: change memory allocation for link_sinfo structure Sarika Sharma
2026-04-28 9:09 ` [PATCH wireless-next 2/2] wifi: cfg80211/mac80211: set only non-MLO-applicable fields for non-MLO stations Sarika Sharma
0 siblings, 2 replies; 7+ messages in thread
From: Sarika Sharma @ 2026-04-28 9:09 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Sarika Sharma
This series improve memory and logic efficiency in cfg80211 and
mac80211 during NL80211_CMD_GET_STATION. Allocate link_sinfo and
link tidstats objects only for valid links to reduce memory usage.
Avoid setting non-MLO applicable fields for MLO stations to
eliminate redundant operations and simplify the code path.
Sarika Sharma (2):
wifi: cfg80211/mac80211: change memory allocation for link_sinfo
structure
wifi: cfg80211/mac80211: set only non-MLO-applicable fields for
non-MLO stations
include/net/cfg80211.h | 29 ++++++++++++++++---
net/mac80211/ethtool.c | 4 +++
net/mac80211/sta_info.c | 63 ++++++++++++++++++++++++-----------------
net/wireless/nl80211.c | 35 ++++-------------------
net/wireless/util.c | 21 ++++++++++++++
5 files changed, 93 insertions(+), 59 deletions(-)
base-commit: 1f5ffc672165ff851063a5fd044b727ab2517ae3
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH wireless-next 1/2] wifi: cfg80211/mac80211: change memory allocation for link_sinfo structure
2026-04-28 9:09 [PATCH wireless-next 0/2] wifi: cfg80211/mac80211: optimize station info handling Sarika Sharma
@ 2026-04-28 9:09 ` Sarika Sharma
2026-04-28 9:31 ` Johannes Berg
2026-04-28 9:09 ` [PATCH wireless-next 2/2] wifi: cfg80211/mac80211: set only non-MLO-applicable fields for non-MLO stations Sarika Sharma
1 sibling, 1 reply; 7+ messages in thread
From: Sarika Sharma @ 2026-04-28 9:09 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Sarika Sharma
Currently, during the NL80211_CMD_GET_STATION call, cfg80211 allocates
memory for link_sinfo objects for all possible links, regardless
of whether they are valid for the station. However, mac80211 only
fills in link_sinfo for valid links, leading to unnecessary memory
consumption.
To optimize memory usage, introduce an API in cfg80211 to dynamically
allocate link_sinfo and the corresponding link tidstats objects.
Memory is allocated only for valid links during link_sinfo population
in mac80211.
Also, refactor cfg80211_sinfo_release_content() so that link_sinfo is
freed separately, keeping allocation and free paths symmetric.
Signed-off-by: Sarika Sharma <sarika.sharma@oss.qualcomm.com>
---
include/net/cfg80211.h | 29 +++++++++++++++++++++++++----
net/mac80211/ethtool.c | 4 ++++
net/mac80211/sta_info.c | 14 +++++++++-----
net/wireless/nl80211.c | 29 ++++++-----------------------
net/wireless/util.c | 21 +++++++++++++++++++++
5 files changed, 65 insertions(+), 32 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 9d3639ff9c28..7dc12c2877b1 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -9146,6 +9146,29 @@ int cfg80211_sinfo_alloc_tid_stats(struct station_info *sinfo, gfp_t gfp);
int cfg80211_link_sinfo_alloc_tid_stats(struct link_station_info *link_sinfo,
gfp_t gfp);
+/**
+ * cfg80211_alloc_link_sinfo_stats - allocate link_sinfo and per tid-statistics.
+ * @link_sinfo: the station link information
+ * @tidstats: indicate if per-tid stats are required
+ * @gfp: allocation flags
+ *
+ * Return: 0 on success. Non-zero on error.
+ */
+int cfg80211_alloc_link_sinfo_stats(struct link_station_info **link_sinfo,
+ bool tidstats, gfp_t gfp);
+
+/**
+ * cfg80211_free_link_sinfo - free the content and memory allocated for
+ * link_sinfo
+ * @link_sinfo: the link_station information
+ */
+static inline void
+cfg80211_free_link_sinfo(struct link_station_info *link_sinfo)
+{
+ kfree(link_sinfo->pertid);
+ kfree(link_sinfo);
+}
+
/**
* cfg80211_sinfo_release_content - release contents of station info
* @sinfo: the station information
@@ -9159,10 +9182,8 @@ static inline void cfg80211_sinfo_release_content(struct station_info *sinfo)
kfree(sinfo->pertid);
for (int link_id = 0; link_id < ARRAY_SIZE(sinfo->links); link_id++) {
- if (sinfo->links[link_id]) {
- kfree(sinfo->links[link_id]->pertid);
- kfree(sinfo->links[link_id]);
- }
+ if (sinfo->links[link_id])
+ cfg80211_free_link_sinfo(sinfo->links[link_id]);
}
}
diff --git a/net/mac80211/ethtool.c b/net/mac80211/ethtool.c
index 3d365626faa4..780229e6bc6d 100644
--- a/net/mac80211/ethtool.c
+++ b/net/mac80211/ethtool.c
@@ -136,6 +136,8 @@ static void ieee80211_get_stats(struct net_device *dev,
if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG))
data[i] = (u8)sinfo.signal_avg;
i++;
+ if (sinfo.valid_links)
+ cfg80211_sinfo_release_content(&sinfo);
} else {
list_for_each_entry(sta, &local->sta_list, list) {
/* Make sure this station belongs to the proper dev */
@@ -147,6 +149,8 @@ static void ieee80211_get_stats(struct net_device *dev,
i = 0;
ADD_STA_STATS(&sta->deflink);
data[i++] = sdata->tx_handlers_drop;
+ if (sinfo.valid_links)
+ cfg80211_sinfo_release_content(&sinfo);
}
}
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 4c31ef8817ce..6c6fc7641a53 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -2963,8 +2963,7 @@ static void sta_set_link_sinfo(struct sta_info *sta,
BIT_ULL(NL80211_STA_INFO_RX_BITRATE);
}
- if (tidstats && !cfg80211_link_sinfo_alloc_tid_stats(link_sinfo,
- GFP_KERNEL)) {
+ if (tidstats) {
for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++)
sta_set_tidstats(sta, &link_sinfo->pertid[i], i,
link_id);
@@ -3252,6 +3251,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
}
if (sta->sta.valid_links) {
+ struct link_station_info *link_sinfo;
struct ieee80211_link_data *link;
struct link_sta_info *link_sta;
int link_id;
@@ -3267,12 +3267,16 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
link = wiphy_dereference(sdata->local->hw.wiphy,
sdata->link[link_id]);
- if (!link_sta || !sinfo->links[link_id] || !link) {
+ if (!link_sta || !link ||
+ cfg80211_alloc_link_sinfo_stats(&link_sinfo,
+ tidstats,
+ GFP_KERNEL)) {
sinfo->valid_links &= ~BIT(link_id);
continue;
}
- sta_set_link_sinfo(sta, sinfo->links[link_id],
- link, tidstats);
+
+ sta_set_link_sinfo(sta, link_sinfo, link, tidstats);
+ sinfo->links[link_id] = link_sinfo;
}
}
}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f334cdef8958..108583fb2cd2 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -8199,7 +8199,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
u8 mac_addr[ETH_ALEN];
int sta_idx = cb->args[2];
bool sinfo_alloc = false;
- int err, i;
+ int err;
err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev, NULL);
if (err)
@@ -8220,20 +8220,13 @@ static int nl80211_dump_station(struct sk_buff *skb,
while (1) {
memset(&sinfo, 0, sizeof(sinfo));
- for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {
- sinfo.links[i] =
- kzalloc_obj(*sinfo.links[0]);
- if (!sinfo.links[i]) {
- err = -ENOMEM;
- goto out_err;
- }
- sinfo_alloc = true;
- }
-
err = rdev_dump_station(rdev, wdev, sta_idx,
mac_addr, &sinfo);
if (err == -ENOENT)
break;
+
+ sinfo_alloc = true;
+
if (err)
goto out_err;
@@ -8273,7 +8266,7 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
struct station_info sinfo;
struct sk_buff *msg;
u8 *mac_addr = NULL;
- int err, i;
+ int err;
memset(&sinfo, 0, sizeof(sinfo));
@@ -8288,19 +8281,9 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
if (!rdev->ops->get_station)
return -EOPNOTSUPP;
- for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {
- sinfo.links[i] = kzalloc_obj(*sinfo.links[0]);
- if (!sinfo.links[i]) {
- cfg80211_sinfo_release_content(&sinfo);
- return -ENOMEM;
- }
- }
-
err = rdev_get_station(rdev, wdev, mac_addr, &sinfo);
- if (err) {
- cfg80211_sinfo_release_content(&sinfo);
+ if (err)
return err;
- }
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg) {
diff --git a/net/wireless/util.c b/net/wireless/util.c
index cff5a1bd95cc..1e1ae2dab7ad 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -2738,6 +2738,27 @@ int cfg80211_link_sinfo_alloc_tid_stats(struct link_station_info *link_sinfo,
}
EXPORT_SYMBOL(cfg80211_link_sinfo_alloc_tid_stats);
+int cfg80211_alloc_link_sinfo_stats(struct link_station_info **link_sinfo,
+ bool tidstats, gfp_t gfp)
+{
+ int ret;
+
+ *link_sinfo = kzalloc_obj(**link_sinfo, gfp);
+ if (!*link_sinfo)
+ return -ENOMEM;
+
+ if (tidstats) {
+ ret = cfg80211_link_sinfo_alloc_tid_stats(*link_sinfo, gfp);
+ if (ret) {
+ kfree(*link_sinfo);
+ *link_sinfo = NULL;
+ return ret;
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL(cfg80211_alloc_link_sinfo_stats);
+
int cfg80211_sinfo_alloc_tid_stats(struct station_info *sinfo, gfp_t gfp)
{
sinfo->pertid = kzalloc_objs(*(sinfo->pertid), IEEE80211_NUM_TIDS + 1,
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH wireless-next 2/2] wifi: cfg80211/mac80211: set only non-MLO-applicable fields for non-MLO stations
2026-04-28 9:09 [PATCH wireless-next 0/2] wifi: cfg80211/mac80211: optimize station info handling Sarika Sharma
2026-04-28 9:09 ` [PATCH wireless-next 1/2] wifi: cfg80211/mac80211: change memory allocation for link_sinfo structure Sarika Sharma
@ 2026-04-28 9:09 ` Sarika Sharma
1 sibling, 0 replies; 7+ messages in thread
From: Sarika Sharma @ 2026-04-28 9:09 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, Sarika Sharma
Currently, in sta_set_sinfo() during the NL80211_CMD_GET_STATION call,
mac80211 sets certain non-MLO applicable fields with default values
even for MLO stations. These fields are later cleared in cfg80211
before the data is sent to userspace, resulting in unnecessary operations.
Hence, avoid setting these fields for MLO stations to simplify the
code and eliminate redundant processing.
Signed-off-by: Sarika Sharma <sarika.sharma@oss.qualcomm.com>
---
net/mac80211/sta_info.c | 49 +++++++++++++++++++++++------------------
net/wireless/nl80211.c | 6 -----
2 files changed, 28 insertions(+), 27 deletions(-)
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 6c6fc7641a53..5307dc30595a 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -3150,27 +3150,6 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
}
}
- /* for the average - if pcpu_rx_stats isn't set - rxstats must point to
- * the sta->rx_stats struct, so the check here is fine with and without
- * pcpu statistics
- */
- if (last_rxstats->chains &&
- !(sinfo->filled & (BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL) |
- BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)))) {
- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL);
- if (!sta->deflink.pcpu_rx_stats)
- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG);
-
- sinfo->chains = last_rxstats->chains;
-
- for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) {
- sinfo->chain_signal[i] =
- last_rxstats->chain_signal_last[i];
- sinfo->chain_signal_avg[i] =
- -ewma_signal_read(&sta->deflink.rx_stats_avg.chain_signal[i]);
- }
- }
-
if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE)) &&
!sta->sta.valid_links &&
ieee80211_rate_valid(&sta->deflink.tx_stats.last_rate)) {
@@ -3278,6 +3257,34 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo,
sta_set_link_sinfo(sta, link_sinfo, link, tidstats);
sinfo->links[link_id] = link_sinfo;
}
+ } else {
+ /*
+ * Set non-MLO applicable fields.
+ * For the average: if pcpu_rx_stats isn't set, rxstats must
+ * point to the sta->rx_stats struct, so the check here is fine
+ * with and without per-CPU statistics.
+ */
+ if (last_rxstats->chains &&
+ !(sinfo->filled &
+ (BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL) |
+ BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)))) {
+ sinfo->filled |=
+ BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL);
+ if (!sta->deflink.pcpu_rx_stats)
+ sinfo->filled |=
+ BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG);
+
+ sinfo->chains = last_rxstats->chains;
+
+ for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) {
+ struct ewma_signal chain_signal =
+ sta->deflink.rx_stats_avg.chain_signal[i];
+ sinfo->chain_signal[i] =
+ last_rxstats->chain_signal_last[i];
+ sinfo->chain_signal_avg[i] =
+ -ewma_signal_read(&chain_signal);
+ }
+ }
}
}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 108583fb2cd2..2a62be4f574a 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -8182,12 +8182,6 @@ static void cfg80211_sta_set_mld_sinfo(struct station_info *sinfo)
BIT(NL80211_TID_STATS_TX_MSDU_FAILED);
}
}
-
- /* Reset sinfo->filled bits to exclude fields which don't make
- * much sense at the MLO level.
- */
- sinfo->filled &= ~BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL);
- sinfo->filled &= ~BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG);
}
static int nl80211_dump_station(struct sk_buff *skb,
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH wireless-next 1/2] wifi: cfg80211/mac80211: change memory allocation for link_sinfo structure
2026-04-28 9:09 ` [PATCH wireless-next 1/2] wifi: cfg80211/mac80211: change memory allocation for link_sinfo structure Sarika Sharma
@ 2026-04-28 9:31 ` Johannes Berg
2026-04-29 6:08 ` Sarika Sharma
0 siblings, 1 reply; 7+ messages in thread
From: Johannes Berg @ 2026-04-28 9:31 UTC (permalink / raw)
To: Sarika Sharma; +Cc: linux-wireless
On Tue, 2026-04-28 at 14:39 +0530, Sarika Sharma wrote:
>
> +int cfg80211_alloc_link_sinfo_stats(struct link_station_info **link_sinfo,
really?
johannes
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH wireless-next 1/2] wifi: cfg80211/mac80211: change memory allocation for link_sinfo structure
2026-04-28 9:31 ` Johannes Berg
@ 2026-04-29 6:08 ` Sarika Sharma
2026-04-29 6:16 ` Johannes Berg
0 siblings, 1 reply; 7+ messages in thread
From: Sarika Sharma @ 2026-04-29 6:08 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
On 28-04-2026 15:01, Johannes Berg wrote:
> On Tue, 2026-04-28 at 14:39 +0530, Sarika Sharma wrote:
>>
>> +int cfg80211_alloc_link_sinfo_stats(struct link_station_info **link_sinfo,
>
> really?
>
> johannes
So, this helper API I introduced in cfg80211 since struct
link_station_info is defined and primarily used
there. Keeping allocation and lifetime management in cfg80211 ensures
consistent ownership and cleanup once the link_station_info is consumed.
Please let me know if I understood your concern correctly, or if you
were referring to something else in this patch.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH wireless-next 1/2] wifi: cfg80211/mac80211: change memory allocation for link_sinfo structure
2026-04-29 6:08 ` Sarika Sharma
@ 2026-04-29 6:16 ` Johannes Berg
2026-04-29 7:24 ` Sarika Sharma
0 siblings, 1 reply; 7+ messages in thread
From: Johannes Berg @ 2026-04-29 6:16 UTC (permalink / raw)
To: Sarika Sharma; +Cc: linux-wireless
On Wed, 2026-04-29 at 11:38 +0530, Sarika Sharma wrote:
>
> On 28-04-2026 15:01, Johannes Berg wrote:
> > On Tue, 2026-04-28 at 14:39 +0530, Sarika Sharma wrote:
> > >
> > > +int cfg80211_alloc_link_sinfo_stats(struct link_station_info **link_sinfo,
> >
> > really?
> >
> > johannes
>
> So, this helper API I introduced in cfg80211 since struct
> link_station_info is defined and primarily used
> there. Keeping allocation and lifetime management in cfg80211 ensures
> consistent ownership and cleanup once the link_station_info is consumed.
>
> Please let me know if I understood your concern correctly, or if you
> were referring to something else in this patch.
Hah, right. I was merely thinking of returning an error and using a
double-pointer for assignment. There are better ways of doing that.
johannes
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH wireless-next 1/2] wifi: cfg80211/mac80211: change memory allocation for link_sinfo structure
2026-04-29 6:16 ` Johannes Berg
@ 2026-04-29 7:24 ` Sarika Sharma
0 siblings, 0 replies; 7+ messages in thread
From: Sarika Sharma @ 2026-04-29 7:24 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
On 29-04-2026 11:46, Johannes Berg wrote:
> On Wed, 2026-04-29 at 11:38 +0530, Sarika Sharma wrote:
>>
>> On 28-04-2026 15:01, Johannes Berg wrote:
>>> On Tue, 2026-04-28 at 14:39 +0530, Sarika Sharma wrote:
>>>>
>>>> +int cfg80211_alloc_link_sinfo_stats(struct link_station_info **link_sinfo,
>>>
>>> really?
>>>
>>> johannes
>>
>> So, this helper API I introduced in cfg80211 since struct
>> link_station_info is defined and primarily used
>> there. Keeping allocation and lifetime management in cfg80211 ensures
>> consistent ownership and cleanup once the link_station_info is consumed.
>>
>> Please let me know if I understood your concern correctly, or if you
>> were referring to something else in this patch.
>
> Hah, right. I was merely thinking of returning an error and using a
> double-pointer for assignment. There are better ways of doing that.
>
> johannes
Thanks for the clarification. I can rework this to use a simpler pattern.
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-04-29 7:24 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-28 9:09 [PATCH wireless-next 0/2] wifi: cfg80211/mac80211: optimize station info handling Sarika Sharma
2026-04-28 9:09 ` [PATCH wireless-next 1/2] wifi: cfg80211/mac80211: change memory allocation for link_sinfo structure Sarika Sharma
2026-04-28 9:31 ` Johannes Berg
2026-04-29 6:08 ` Sarika Sharma
2026-04-29 6:16 ` Johannes Berg
2026-04-29 7:24 ` Sarika Sharma
2026-04-28 9:09 ` [PATCH wireless-next 2/2] wifi: cfg80211/mac80211: set only non-MLO-applicable fields for non-MLO stations Sarika Sharma
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox