@@ -1575,7 +1575,7 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
memset(&rx_status, 0, sizeof(rx_status));
rx_status.flag |= RX_FLAG_MACTIME_START;
rx_status.freq = chan->center_freq;
- rx_status.freq_offset = chan->freq_offset ? 1 : 0;
+ rx_status.freq_offset = chan->freq_offset;
rx_status.band = chan->band;
if (info->control.rates[0].flags & IEEE80211_TX_RC_VHT_MCS) {
rx_status.rate_idx =
@@ -863,6 +863,10 @@ enum mac80211_tx_info_flags {
#define IEEE80211_TX_CTL_STBC_SHIFT 23
#define IEEE80211_TX_RC_S1G_MCS IEEE80211_TX_RC_VHT_MCS
+#define IEEE80211_TX_RC_2_MHZ_WIDTH IEEE80211_TX_RC_MCS
+#define IEEE80211_TX_RC_4_MHZ_WIDTH IEEE80211_TX_RC_40_MHZ_WIDTH
+#define IEEE80211_TX_RC_8_MHZ_WIDTH IEEE80211_TX_RC_80_MHZ_WIDTH
+#define IEEE80211_TX_RC_16_MHZ_WIDTH IEEE80211_TX_RC_160_MHZ_WIDTH
/**
* enum mac80211_tx_control_flags - flags to describe transmit control
@@ -1051,6 +1055,20 @@ ieee80211_rate_get_vht_nss(const struct ieee80211_tx_rate *rate)
return (rate->idx >> 4) + 1;
}
+static inline u8
+ieee80211_rate_get_s1g_mcs(const struct ieee80211_tx_rate *rate)
+{
+ /* S1G uses the same MCS encoding as VHT */
+ return ieee80211_rate_get_vht_mcs(rate);
+}
+
+static inline u8
+ieee80211_rate_get_s1g_nss(const struct ieee80211_tx_rate *rate)
+{
+ /* S1G uses the same NSS encoding as VHT */
+ return ieee80211_rate_get_vht_nss(rate);
+}
+
/**
* struct ieee80211_tx_info - skb transmit information
*
@@ -1435,6 +1453,7 @@ enum mac80211_rx_encoding {
RX_ENC_HT,
RX_ENC_VHT,
RX_ENC_HE,
+ RX_ENC_S1G,
};
/**
@@ -1491,10 +1510,11 @@ struct ieee80211_rx_status {
u32 device_timestamp;
u32 ampdu_reference;
u32 flag;
- u16 freq: 13, freq_offset: 1;
+ u16 freq;
+ u16 freq_offset;
u8 enc_flags;
- u8 encoding:2, bw:3, he_ru:3;
- u8 he_gi:2, he_dcm:1;
+ u8 encoding:3, bw:5;
+ u8 he_ru:3, he_gi:2, he_dcm:1;
u8 rate_idx;
u8 nss;
u8 rx_flags;
@@ -1510,8 +1530,7 @@ struct ieee80211_rx_status {
static inline u32
ieee80211_rx_status_to_khz(struct ieee80211_rx_status *rx_status)
{
- return MHZ_TO_KHZ(rx_status->freq) +
- (rx_status->freq_offset ? 500 : 0);
+ return MHZ_TO_KHZ(rx_status->freq) + rx_status->freq_offset;
}
/**
@@ -6568,6 +6587,9 @@ bool rate_usable_index_exists(struct ieee80211_supported_band *sband,
{
unsigned int i;
+ if (sband->band == NL80211_BAND_S1GHZ)
+ return true;
+
for (i = 0; i < sband->n_bitrates; i++)
if (rate_supported(sta, sband->band, i))
return true;
@@ -747,8 +747,16 @@ void sta_set_rate_info_tx(struct sta_info *sta,
const struct ieee80211_tx_rate *rate,
struct rate_info *rinfo)
{
+ struct ieee80211_supported_band *sband;
+
+ sband = ieee80211_get_sband(sta->sdata);
rinfo->flags = 0;
- if (rate->flags & IEEE80211_TX_RC_MCS) {
+ if (rate->flags & IEEE80211_TX_RC_S1G_MCS &&
+ sband->band == NL80211_BAND_S1GHZ) {
+ rinfo->flags |= RATE_INFO_FLAGS_S1G_MCS;
+ rinfo->mcs = ieee80211_rate_get_s1g_mcs(rate);
+ rinfo->nss = ieee80211_rate_get_s1g_nss(rate);
+ } else if (rate->flags & IEEE80211_TX_RC_MCS) {
rinfo->flags |= RATE_INFO_FLAGS_MCS;
rinfo->mcs = rate->idx;
} else if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
@@ -756,25 +764,37 @@ void sta_set_rate_info_tx(struct sta_info *sta,
rinfo->mcs = ieee80211_rate_get_vht_mcs(rate);
rinfo->nss = ieee80211_rate_get_vht_nss(rate);
} else {
- struct ieee80211_supported_band *sband;
int shift = ieee80211_vif_get_shift(&sta->sdata->vif);
u16 brate;
- sband = ieee80211_get_sband(sta->sdata);
WARN_ON_ONCE(sband && !sband->bitrates);
if (sband && sband->bitrates) {
brate = sband->bitrates[rate->idx].bitrate;
rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift);
}
}
- if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
- rinfo->bw = RATE_INFO_BW_40;
- else if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
- rinfo->bw = RATE_INFO_BW_80;
- else if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
- rinfo->bw = RATE_INFO_BW_160;
- else
- rinfo->bw = RATE_INFO_BW_20;
+ if (sband->band == NL80211_BAND_S1GHZ) {
+ if (rate->flags & IEEE80211_TX_RC_2_MHZ_WIDTH)
+ rinfo->bw = RATE_INFO_BW_2;
+ else if (rate->flags & IEEE80211_TX_RC_4_MHZ_WIDTH)
+ rinfo->bw = RATE_INFO_BW_4;
+ else if (rate->flags & IEEE80211_TX_RC_8_MHZ_WIDTH)
+ rinfo->bw = RATE_INFO_BW_8;
+ else if (rate->flags & IEEE80211_TX_RC_16_MHZ_WIDTH)
+ rinfo->bw = RATE_INFO_BW_16;
+ else
+ rinfo->bw = RATE_INFO_BW_1;
+ } else {
+ if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ rinfo->bw = RATE_INFO_BW_40;
+ else if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
+ rinfo->bw = RATE_INFO_BW_80;
+ else if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
+ rinfo->bw = RATE_INFO_BW_160;
+ else
+ rinfo->bw = RATE_INFO_BW_20;
+ }
+
if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
}
@@ -5106,6 +5106,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 > 10 ||
+ !status->nss ||
+ status->nss > 8,
+ "Rate marked as a 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;
@@ -2295,6 +2295,13 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u32 rate,
rinfo->he_ru_alloc = STA_STATS_GET(HE_RU, rate);
rinfo->he_dcm = STA_STATS_GET(HE_DCM, rate);
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;
}
}
@@ -935,6 +935,8 @@ enum sta_stats_type {
#define STA_STATS_FIELD_VHT_NSS GENMASK( 7, 4)
#define STA_STATS_FIELD_HE_MCS GENMASK( 3, 0)
#define STA_STATS_FIELD_HE_NSS GENMASK( 7, 4)
+#define STA_STATS_FIELD_S1G_MCS GENMASK( 3, 0)
+#define STA_STATS_FIELD_S1G_NSS GENMASK( 7, 4)
#define STA_STATS_FIELD_BW GENMASK(11, 8)
#define STA_STATS_FIELD_SGI GENMASK(12, 12)
#define STA_STATS_FIELD_TYPE GENMASK(15, 13)
@@ -979,6 +981,11 @@ static inline u32 sta_stats_encode_rate(struct ieee80211_rx_status *s)
r |= STA_STATS_FIELD(HE_RU, s->he_ru);
r |= STA_STATS_FIELD(HE_DCM, s->he_dcm);
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;
@@ -3929,7 +3929,7 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
u64 ts = status->mactime;
struct rate_info ri;
u16 rate;
- u8 n_ltf;
+ u8 n_ltf, guard_factor;
if (WARN_ON(!ieee80211_have_rx_timestamp(status)))
return 0;
@@ -4016,6 +4016,34 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
ts += 4 * n_ltf;
}
+ break;
+ case RX_ENC_S1G:
+ /* Set to duration of S1G OFDM symbol with normal GI */
+ guard_factor = 40;
+ ri.flags |= RATE_INFO_FLAGS_S1G_MCS;
+ ri.mcs = status->rate_idx;
+ ri.nss = status->nss;
+ if (status->enc_flags & RX_ENC_FLAG_SHORT_GI) {
+ ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
+ guard_factor = 36;
+ }
+
+ /*
+ * See 80211-2020, section 23.3.2 for S1G PPDU
+ * format and 23.3.6 for timing-related parameters.
+ * Here using the general structure for S1G_1M as
+ * in figure 23-3.
+ */
+ if (status->flag & RX_FLAG_MACTIME_PLCP_START) {
+ mpdu_offset += 2;
+ ts += (14 * guard_factor);
+
+ /* Add S1G-LTFs per streams */
+ n_ltf = (ri.nss != 1) && (ri.nss % 2) ?
+ ri.nss + 1 : ri.nss;
+ ts += (guard_factor * n_ltf);
+ }
+
break;
default:
WARN_ON(1);
Add support for receiving and transmitting S1G frames. Signed-off-by: Kieran Frewen <kieran.frewen@morsemicro.com> --- drivers/net/wireless/mac80211_hwsim.c | 2 +- include/net/mac80211.h | 32 ++++++++++++++++---- net/mac80211/cfg.c | 42 ++++++++++++++++++++------- net/mac80211/rx.c | 8 +++++ net/mac80211/sta_info.c | 7 +++++ net/mac80211/sta_info.h | 7 +++++ net/mac80211/util.c | 30 ++++++++++++++++++- 7 files changed, 110 insertions(+), 18 deletions(-)