-/* $OpenBSD: if_iwx.c,v 1.155 2023/03/06 10:24:15 stsp Exp $ */
+/* $OpenBSD: if_iwx.c,v 1.156 2023/03/06 10:28:04 stsp Exp $ */
/*
* Copyright (c) 2014, 2016 genua gmbh <info@genua.de>
int iwx_rs_rval2idx(uint8_t);
uint16_t iwx_rs_ht_rates(struct iwx_softc *, struct ieee80211_node *, int);
uint16_t iwx_rs_vht_rates(struct iwx_softc *, struct ieee80211_node *, int);
+int iwx_rs_init_v3(struct iwx_softc *, struct iwx_node *);
+int iwx_rs_init_v4(struct iwx_softc *, struct iwx_node *);
int iwx_rs_init(struct iwx_softc *, struct iwx_node *);
int iwx_enable_data_tx_queues(struct iwx_softc *);
int iwx_phy_ctxt_update(struct iwx_softc *, struct iwx_phy_ctxt *,
}
int
-iwx_rs_init(struct iwx_softc *sc, struct iwx_node *in)
+iwx_rs_init_v3(struct iwx_softc *sc, struct iwx_node *in)
{
struct ieee80211_node *ni = &in->in_ni;
struct ieee80211_rateset *rs = &ni->ni_rates;
- struct iwx_tlc_config_cmd cfg_cmd;
+ struct iwx_tlc_config_cmd_v3 cfg_cmd;
uint32_t cmd_id;
int i;
size_t cmd_size = sizeof(cfg_cmd);
if (ni->ni_flags & IEEE80211_NODE_VHT) {
cfg_cmd.mode = IWX_TLC_MNG_MODE_VHT;
- cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_HT_BW_NONE_160] =
+ cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_MCS_PER_BW_80] =
htole16(iwx_rs_vht_rates(sc, ni, 1));
- cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_HT_BW_NONE_160] =
+ cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_MCS_PER_BW_80] =
htole16(iwx_rs_vht_rates(sc, ni, 2));
} else if (ni->ni_flags & IEEE80211_NODE_HT) {
cfg_cmd.mode = IWX_TLC_MNG_MODE_HT;
- cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_HT_BW_NONE_160] =
+ cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_MCS_PER_BW_80] =
htole16(iwx_rs_ht_rates(sc, ni,
IEEE80211_HT_RATESET_SISO));
- cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_HT_BW_NONE_160] =
+ cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_MCS_PER_BW_80] =
htole16(iwx_rs_ht_rates(sc, ni,
IEEE80211_HT_RATESET_MIMO2));
} else
return iwx_send_cmd_pdu(sc, cmd_id, IWX_CMD_ASYNC, cmd_size, &cfg_cmd);
}
+int
+iwx_rs_init_v4(struct iwx_softc *sc, struct iwx_node *in)
+{
+ struct ieee80211_node *ni = &in->in_ni;
+ struct ieee80211_rateset *rs = &ni->ni_rates;
+ struct iwx_tlc_config_cmd_v4 cfg_cmd;
+ uint32_t cmd_id;
+ int i;
+ size_t cmd_size = sizeof(cfg_cmd);
+
+ memset(&cfg_cmd, 0, sizeof(cfg_cmd));
+
+ for (i = 0; i < rs->rs_nrates; i++) {
+ uint8_t rval = rs->rs_rates[i] & IEEE80211_RATE_VAL;
+ int idx = iwx_rs_rval2idx(rval);
+ if (idx == -1)
+ return EINVAL;
+ cfg_cmd.non_ht_rates |= (1 << idx);
+ }
+
+ if (ni->ni_flags & IEEE80211_NODE_VHT) {
+ cfg_cmd.mode = IWX_TLC_MNG_MODE_VHT;
+ cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_MCS_PER_BW_80] =
+ htole16(iwx_rs_vht_rates(sc, ni, 1));
+ cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_MCS_PER_BW_80] =
+ htole16(iwx_rs_vht_rates(sc, ni, 2));
+ } else if (ni->ni_flags & IEEE80211_NODE_HT) {
+ cfg_cmd.mode = IWX_TLC_MNG_MODE_HT;
+ cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_MCS_PER_BW_80] =
+ htole16(iwx_rs_ht_rates(sc, ni,
+ IEEE80211_HT_RATESET_SISO));
+ cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_MCS_PER_BW_80] =
+ htole16(iwx_rs_ht_rates(sc, ni,
+ IEEE80211_HT_RATESET_MIMO2));
+ } else
+ cfg_cmd.mode = IWX_TLC_MNG_MODE_NON_HT;
+
+ cfg_cmd.sta_id = IWX_STATION_ID;
+ if (in->in_phyctxt->vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_80)
+ cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_80MHZ;
+ else if (in->in_phyctxt->sco == IEEE80211_HTOP0_SCO_SCA ||
+ in->in_phyctxt->sco == IEEE80211_HTOP0_SCO_SCB)
+ cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_40MHZ;
+ else
+ cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_20MHZ;
+ cfg_cmd.chains = IWX_TLC_MNG_CHAIN_A_MSK | IWX_TLC_MNG_CHAIN_B_MSK;
+ if (ni->ni_flags & IEEE80211_NODE_VHT)
+ cfg_cmd.max_mpdu_len = htole16(3895);
+ else
+ cfg_cmd.max_mpdu_len = htole16(3839);
+ if (ni->ni_flags & IEEE80211_NODE_HT) {
+ if (ieee80211_node_supports_ht_sgi20(ni)) {
+ cfg_cmd.sgi_ch_width_supp |= (1 <<
+ IWX_TLC_MNG_CH_WIDTH_20MHZ);
+ }
+ if (ieee80211_node_supports_ht_sgi40(ni)) {
+ cfg_cmd.sgi_ch_width_supp |= (1 <<
+ IWX_TLC_MNG_CH_WIDTH_40MHZ);
+ }
+ }
+ if ((ni->ni_flags & IEEE80211_NODE_VHT) &&
+ ieee80211_node_supports_vht_sgi80(ni))
+ cfg_cmd.sgi_ch_width_supp |= (1 << IWX_TLC_MNG_CH_WIDTH_80MHZ);
+
+ cmd_id = iwx_cmd_id(IWX_TLC_MNG_CONFIG_CMD, IWX_DATA_PATH_GROUP, 0);
+ return iwx_send_cmd_pdu(sc, cmd_id, IWX_CMD_ASYNC, cmd_size, &cfg_cmd);
+}
+
+int
+iwx_rs_init(struct iwx_softc *sc, struct iwx_node *in)
+{
+ int cmd_ver;
+
+ cmd_ver = iwx_lookup_cmd_ver(sc, IWX_DATA_PATH_GROUP,
+ IWX_TLC_MNG_CONFIG_CMD);
+ if (cmd_ver == 4)
+ return iwx_rs_init_v4(sc, in);
+ return iwx_rs_init_v3(sc, in);
+}
+
void
iwx_rs_update(struct iwx_softc *sc, struct iwx_tlc_update_notif *notif)
{
-/* $OpenBSD: if_iwxreg.h,v 1.43 2023/03/06 10:24:15 stsp Exp $ */
+/* $OpenBSD: if_iwxreg.h,v 1.44 2023/03/06 10:28:04 stsp Exp $ */
/*-
* Based on BSD-licensed source modules in the Linux iwlwifi driver,
* @IWX_TLC_MNG_CH_WIDTH_40MHZ: 40MHZ channel
* @IWX_TLC_MNG_CH_WIDTH_80MHZ: 80MHZ channel
* @IWX_TLC_MNG_CH_WIDTH_160MHZ: 160MHZ channel
- * @IWX_TLC_MNG_CH_WIDTH_LAST: maximum value
+ * @IWX_TLC_MNG_CH_WIDTH_320MHZ: 320MHZ channel
*/
enum iwx_tlc_mng_cfg_cw {
IWX_TLC_MNG_CH_WIDTH_20MHZ,
IWX_TLC_MNG_CH_WIDTH_40MHZ,
IWX_TLC_MNG_CH_WIDTH_80MHZ,
IWX_TLC_MNG_CH_WIDTH_160MHZ,
- IWX_TLC_MNG_CH_WIDTH_LAST = IWX_TLC_MNG_CH_WIDTH_160MHZ,
+ IWX_TLC_MNG_CH_WIDTH_320MHZ,
};
/**
* @IWX_TLC_MNG_MODE_HT: enable HT
* @IWX_TLC_MNG_MODE_VHT: enable VHT
* @IWX_TLC_MNG_MODE_HE: enable HE
- * @IWX_TLC_MNG_MODE_INVALID: invalid value
- * @IWX_TLC_MNG_MODE_NUM: a count of possible modes
+ * @IWX_TLC_MNG_MODE_EHT: enable EHT
*/
enum iwx_tlc_mng_cfg_mode {
IWX_TLC_MNG_MODE_CCK = 0,
IWX_TLC_MNG_MODE_HT,
IWX_TLC_MNG_MODE_VHT,
IWX_TLC_MNG_MODE_HE,
- IWX_TLC_MNG_MODE_INVALID,
- IWX_TLC_MNG_MODE_NUM = IWX_TLC_MNG_MODE_INVALID,
+ IWX_TLC_MNG_MODE_EHT,
};
/**
#define IWX_TLC_NSS_2 1
#define IWX_TLC_NSS_MAX 2
-#define IWX_TLC_HT_BW_NONE_160 0
-#define IWX_TLC_HT_BW_160 1
/**
- * struct iwx_tlc_config_cmd - TLC configuration
+ * IWX_TLC_MCS_PER_BW - mcs index per BW
+ * @IWX_TLC_MCS_PER_BW_80: mcs for bw - 20Hhz, 40Hhz, 80Hhz
+ * @IWX_TLC_MCS_PER_BW_160: mcs for bw - 160Mhz
+ * @IWX_TLC_MCS_PER_BW_320: mcs for bw - 320Mhz
+ * @IWX_TLC_MCS_PER_BW_NUM_V3: number of entries up to version 3
+ * @IWX_TLC_MCS_PER_BW_NUM_V4: number of entries from version 4
+ */
+#define IWX_TLC_MCS_PER_BW_80 0
+#define IWX_TLC_MCS_PER_BW_160 1
+#define IWX_TLC_MCS_PER_BW_320 2
+#define IWX_TLC_MCS_PER_BW_NUM_V3 (IWX_TLC_MCS_PER_BW_160 + 1)
+#define IWX_TLC_MCS_PER_BW_NUM_V4 (IWX_TLC_MCS_PER_BW_320 + 1)
+
+/**
+ * struct iwx_tlc_config_cmd_v3 - TLC configuration version 3
* @sta_id: station id
* @reserved1: reserved
* @max_ch_width: max supported channel width from @enum iwx_tlc_mng_cfg_cw
* @amsdu: 1 = TX amsdu is supported, 0 = not supported
* @flags: bitmask of IWX_TLC_MNG_CFG_*
* @non_ht_rates: bitmap of supported legacy rates
- * @ht_rates: bitmap of &enum iwx_tlc_mng_ht_rates, per <nss, channel-width>
+ * @ht_rates: MCS index 0 - 11, per <nss, channel-width>
* pair (0 - 80mhz width and below, 1 - 160mhz).
* @max_mpdu_len: max MPDU length, in bytes
* @sgi_ch_width_supp: bitmap of SGI support per channel width
- * use (1 << @enum iwx_tlc_mng_cfg_cw)
+ * use (1 << IWX_TLC_MNG_CFG_CW_*)
* @reserved2: reserved
* @max_tx_op: max TXOP in uSecs for all AC (BK, BE, VO, VI),
* set zero for no limit.
*/
-struct iwx_tlc_config_cmd {
+struct iwx_tlc_config_cmd_v3 {
uint8_t sta_id;
uint8_t reserved1[3];
uint8_t max_ch_width;
uint8_t amsdu;
uint16_t flags;
uint16_t non_ht_rates;
- uint16_t ht_rates[IWX_TLC_NSS_MAX][2];
+ uint16_t ht_rates[IWX_TLC_NSS_MAX][IWX_TLC_MCS_PER_BW_NUM_V3];
uint16_t max_mpdu_len;
uint8_t sgi_ch_width_supp;
uint8_t reserved2;
uint32_t max_tx_op;
} __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_3 */
+/**
+ * struct iwx_tlc_config_cmd_v4 - TLC configuration
+ * @sta_id: station id
+ * @reserved1: reserved
+ * @max_ch_width: max supported channel width from @enum iwx_tlc_mng_cfg_cw
+ * @mode: &enum iwx_tlc_mng_cfg_mode
+ * @chains: bitmask of IWX_TLC_MNG_CHAIN_*_MSK
+ * @sgi_ch_width_supp: bitmap of SGI support per channel width
+ * use (1 << IWX_TLC_MNG_CFG_CW_*)
+ * @flags: bitmask of IWX_TLC_MNG_CFG_*
+ * @non_ht_rates: bitmap of supported legacy rates
+ * @ht_rates: MCS index 0 - 11, per <nss, channel-width>
+ * pair (0 - 80mhz width and below, 1 - 160mhz, 2 - 320mhz).
+ * @max_mpdu_len: max MPDU length, in bytes
+ * @max_tx_op: max TXOP in uSecs for all AC (BK, BE, VO, VI),
+ * set zero for no limit.
+ */
+struct iwx_tlc_config_cmd_v4 {
+ uint8_t sta_id;
+ uint8_t reserved1[3];
+ uint8_t max_ch_width;
+ uint8_t mode;
+ uint8_t chains;
+ uint8_t sgi_ch_width_supp;
+ uint16_t flags;
+ uint16_t non_ht_rates;
+ uint16_t ht_rates[IWX_TLC_NSS_MAX][IWX_TLC_MCS_PER_BW_NUM_V4];
+ uint16_t max_mpdu_len;
+ uint16_t max_tx_op;
+} __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_4 */
+
/**
* @IWX_TLC_NOTIF_FLAG_RATE: last initial rate update
* @IWX_TLC_NOTIF_FLAG_AMSDU: umsdu parameters update
* @sta_id: station id
* @reserved: reserved
* @flags: bitmap of notifications reported
- * @rate: current initial rate
+ * @rate: current initial rate; using rate_n_flags version 1 if notification
+ * version is < 3 at run-time, else rate_n_flags version 2
* @amsdu_size: Max AMSDU size, in bytes
* @amsdu_enabled: bitmap for per-TID AMSDU enablement
*/