wifi: mac80211: basic S1G rx rate reporting support

Introduce basic rate encoding/decoding for S1G stas such that the
usermode rx reporting is relevant as it currently uses VHT calculations
which are obviously wildy different to S1G. Sample iw output (with the
associated iw patches applied):

Connected to 0c:bf:74:00:21:c4 (on wlan0)
        SSID: wifi_halow
        freq: 923.500
        RX: 7325230 bytes (4756 packets)
        TX: 190044 bytes (2238 packets)
        signal: -38 dBm
        rx bitrate: 43.3 MBit/s S1G-MCS 9 8MHz short GI S1G-NSS 1
        tx bitrate: 43.3 MBit/s S1G-MCS 9 8MHz short GI S1G-NSS 1
        bss flags:
        dtim period: 1
        beacon int: 100

Signed-off-by: Lachlan Hodges <lachlan.hodges@morsemicro.com>
Link: https://patch.msgid.link/20260602062224.1792985-1-lachlan.hodges@morsemicro.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Lachlan Hodges 2026-06-02 16:22:24 +10:00 committed by Johannes Berg
parent 5a9c554ff8
commit b3d5193305
4 changed files with 26 additions and 1 deletions

View File

@ -1704,6 +1704,7 @@ enum mac80211_rx_encoding {
RX_ENC_HE,
RX_ENC_EHT,
RX_ENC_UHR,
RX_ENC_S1G,
};
/**

View File

@ -5621,6 +5621,14 @@ void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta,
status->rate_idx, status->nss))
goto drop;
break;
case RX_ENC_S1G:
if (WARN_ONCE(status->rate_idx > 12 ||
!status->nss ||
status->nss > 4,
"Rate marked as an S1G rate but data is invalid: MCS: %d, NSS: %d\n",
status->rate_idx, status->nss))
goto drop;
break;
default:
WARN_ON_ONCE(1);
fallthrough;

View File

@ -2605,6 +2605,13 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u32 rate,
if (STA_STATS_GET(UHR_IM, rate))
rinfo->flags |= RATE_INFO_FLAGS_UHR_IM;
break;
case STA_STATS_RATE_TYPE_S1G:
rinfo->flags = RATE_INFO_FLAGS_S1G_MCS;
rinfo->mcs = STA_STATS_GET(S1G_MCS, rate);
rinfo->nss = STA_STATS_GET(S1G_NSS, rate);
if (STA_STATS_GET(SGI, rate))
rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
break;
}
}

View File

@ -1042,7 +1042,7 @@ enum sta_stats_type {
#define STA_STATS_FIELD_VHT_MCS 0x0000F000
#define STA_STATS_FIELD_VHT_NSS 0x000F0000
/* HT & VHT */
/* HT, VHT & S1G */
#define STA_STATS_FIELD_SGI 0x00100000
/* STA_STATS_RATE_TYPE_HE */
@ -1066,6 +1066,9 @@ enum sta_stats_type {
#define STA_STATS_FIELD_UHR_ELR 0x08000000
#define STA_STATS_FIELD_UHR_IM 0x10000000
/* STA_STATS_RATE_TYPE_S1G */
#define STA_STATS_FIELD_S1G_MCS 0x0000F000
#define STA_STATS_FIELD_S1G_NSS 0x000F0000
#define STA_STATS_FIELD(_n, _v) FIELD_PREP(STA_STATS_FIELD_ ## _n, _v)
#define STA_STATS_GET(_n, _v) FIELD_GET(STA_STATS_FIELD_ ## _n, _v)
@ -1081,6 +1084,7 @@ static inline u32 sta_stats_encode_rate(struct ieee80211_rx_status *s)
switch (s->encoding) {
case RX_ENC_HT:
case RX_ENC_VHT:
case RX_ENC_S1G:
if (s->enc_flags & RX_ENC_FLAG_SHORT_GI)
r |= STA_STATS_FIELD(SGI, 1);
break;
@ -1127,6 +1131,11 @@ static inline u32 sta_stats_encode_rate(struct ieee80211_rx_status *s)
r |= STA_STATS_FIELD(UHR_ELR, s->uhr.elr);
r |= STA_STATS_FIELD(UHR_IM, s->uhr.im);
break;
case RX_ENC_S1G:
r |= STA_STATS_FIELD(TYPE, STA_STATS_RATE_TYPE_S1G);
r |= STA_STATS_FIELD(S1G_NSS, s->nss);
r |= STA_STATS_FIELD(S1G_MCS, s->rate_idx);
break;
default:
WARN_ON(1);
return STA_STATS_RATE_INVALID;