Commit dabc88cb authored by Johannes Berg's avatar Johannes Berg Committed by Miri Korenblit
Browse files

wifi: iwlwifi: handle v3 rates



For UHR, a version 3 of the rate API is being added, which
increases the number of bits used for MCSes by shifting the
NSS bit up. Handle that.

Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Link: https://patch.msgid.link/20250505215513.84cde65a603f.Ic3119ef77cbc6461abd2a6bda104c0d236adcc8d@changeid


Signed-off-by: default avatarMiri Korenblit <miriam.rachel.korenblit@intel.com>
parent 871197bf
Loading
Loading
Loading
Loading
+50 −15
Original line number Diff line number Diff line
@@ -213,7 +213,8 @@ enum iwl_tlc_update_flags {
 * @sta_id: station id
 * @reserved: reserved
 * @flags: bitmap of notifications reported
 * @rate: current initial rate
 * @rate: current initial rate, format depends on the notification
 *	version
 * @amsdu_size: Max AMSDU size, in bytes
 * @amsdu_enabled: bitmap for per-TID AMSDU enablement
 */
@@ -224,7 +225,7 @@ struct iwl_tlc_update_notif {
	__le32 rate;
	__le32 amsdu_size;
	__le32 amsdu_enabled;
} __packed; /* TLC_MNG_UPDATE_NTFY_API_S_VER_2 */
} __packed; /* TLC_MNG_UPDATE_NTFY_API_S_VER_2, _VER_3, _VER_4 */

/**
 * enum iwl_tlc_debug_types - debug options
@@ -427,6 +428,7 @@ enum {

/* Bit 4-5: (0) SISO, (1) MIMO2 (2) MIMO3 */
#define RATE_VHT_MCS_RATE_CODE_MSK	0xf
#define RATE_VHT_MCS_NSS_MSK		0x30

/*
 * Legacy OFDM rate format for bits 7:0
@@ -541,7 +543,7 @@ enum {
#define RATE_MCS_CTS_REQUIRED_POS  (31)
#define RATE_MCS_CTS_REQUIRED_MSK  (0x1 << RATE_MCS_CTS_REQUIRED_POS)

/* rate_n_flags bit field version 2
/* rate_n_flags bit field version 2 and 3
 *
 * The 32-bit value has different layouts in the low 8 bits depending on the
 * format. There are three formats, HT, VHT and legacy (11abg, with subformats
@@ -553,6 +555,7 @@ enum {
 * (0) Legacy CCK (1) Legacy OFDM (2) High-throughput (HT)
 * (3) Very High-throughput (VHT) (4) High-efficiency (HE)
 * (5) Extremely High-throughput (EHT)
 * (6) Ultra High Reliability (UHR) (v3 rate format only)
 */
#define RATE_MCS_MOD_TYPE_POS		8
#define RATE_MCS_MOD_TYPE_MSK		(0x7 << RATE_MCS_MOD_TYPE_POS)
@@ -562,14 +565,15 @@ enum {
#define RATE_MCS_MOD_TYPE_VHT		(3 << RATE_MCS_MOD_TYPE_POS)
#define RATE_MCS_MOD_TYPE_HE		(4 << RATE_MCS_MOD_TYPE_POS)
#define RATE_MCS_MOD_TYPE_EHT		(5 << RATE_MCS_MOD_TYPE_POS)
#define RATE_MCS_MOD_TYPE_UHR		(6 << RATE_MCS_MOD_TYPE_POS)

/*
 * Legacy CCK rate format for bits 0:3:
 *
 * (0) 0xa - 1 Mbps
 * (1) 0x14 - 2 Mbps
 * (2) 0x37 - 5.5 Mbps
 * (3) 0x6e - 11 nbps
 * (0) 1 Mbps
 * (1) 2 Mbps
 * (2) 5.5 Mbps
 * (3) 11 Mbps
 *
 * Legacy OFDM rate format for bis 3:0:
 *
@@ -586,15 +590,19 @@ enum {
#define RATE_LEGACY_RATE_MSK		0x7

/*
 * HT, VHT, HE, EHT rate format for bits 3:0
 * HT, VHT, HE, EHT, UHR rate format
 * Version 2: (not applicable for UHR)
 *   3-0: MCS
 *   4: NSS==2 indicator
 *
 * Version 3:
 *   4-0: MCS
 *   5: NSS==2 indicator
 */
#define RATE_HT_MCS_CODE_MSK		0x7
#define RATE_MCS_NSS_MSK		0x10
#define RATE_MCS_CODE_MSK		0xf
#define RATE_HT_MCS_INDEX(r)		((((r) & RATE_MCS_NSS_MSK) >> 1) | \
#define RATE_MCS_NSS_MSK_V2		0x10
#define RATE_MCS_NSS_MSK		0x20
#define RATE_MCS_CODE_MSK		0x1f
#define RATE_HT_MCS_INDEX(r)		((((r) & RATE_MCS_NSS_MSK) >> 2) | \
					 ((r) & RATE_HT_MCS_CODE_MSK))

/* Bits 7-5: reserved */
@@ -810,11 +818,38 @@ struct iwl_lq_cmd {
}; /* LINK_QUALITY_CMD_API_S_VER_1 */

u8 iwl_fw_rate_idx_to_plcp(int idx);
u32 iwl_new_rate_from_v1(u32 rate_v1);
const struct iwl_rate_mcs_info *iwl_rate_mcs(int idx);
const char *iwl_rs_pretty_ant(u8 ant);
const char *iwl_rs_pretty_bw(int bw);
int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate);
bool iwl_he_is_sgi(u32 rate_n_flags);

static inline u32 iwl_v3_rate_from_v2_v3(__le32 rate, bool fw_v3)
{
	u32 val;

	if (fw_v3)
		return le32_to_cpu(rate);

	val = le32_to_cpu(rate) & ~RATE_MCS_NSS_MSK_V2;
	val |= u32_encode_bits(le32_get_bits(rate, RATE_MCS_NSS_MSK_V2),
			       RATE_MCS_NSS_MSK);

	return val;
}

static inline __le32 iwl_v3_rate_to_v2_v3(u32 rate, bool fw_v3)
{
	__le32 val;

	if (fw_v3)
		return cpu_to_le32(rate);

	val = cpu_to_le32(rate & ~RATE_MCS_NSS_MSK);
	val |= le32_encode_bits(u32_get_bits(rate, RATE_MCS_NSS_MSK),
				RATE_MCS_NSS_MSK_V2);

	return val;
}

#endif /* __iwl_fw_api_rs_h__ */
+9 −7
Original line number Diff line number Diff line
@@ -640,7 +640,9 @@ struct iwl_rx_mpdu_desc_v3 {
	 */
	__le32 reserved[1];
} __packed; /* RX_MPDU_RES_START_API_S_VER_3,
	       RX_MPDU_RES_START_API_S_VER_5 */
	     * RX_MPDU_RES_START_API_S_VER_5,
	     * RX_MPDU_RES_START_API_S_VER_6
	     */

/**
 * struct iwl_rx_mpdu_desc - RX MPDU descriptor
@@ -724,8 +726,10 @@ struct iwl_rx_mpdu_desc {
		struct iwl_rx_mpdu_desc_v3 v3;
	};
} __packed; /* RX_MPDU_RES_START_API_S_VER_3,
	       RX_MPDU_RES_START_API_S_VER_4,
	       RX_MPDU_RES_START_API_S_VER_5 */
	     * RX_MPDU_RES_START_API_S_VER_4,
	     * RX_MPDU_RES_START_API_S_VER_5,
	     * RX_MPDU_RES_START_API_S_VER_6
	     */

#define IWL_RX_DESC_SIZE_V1 offsetofend(struct iwl_rx_mpdu_desc, v1)

@@ -821,7 +825,7 @@ struct iwl_rx_no_data {
 *	15:8 chain-B, measured at FINA time (FINA_ENERGY), 16:23 channel
 * @on_air_rise_time: GP2 during on air rise
 * @fr_time: frame time
 * @rate: rate/mcs of frame
 * @rate: rate/mcs of frame, format depends on the notification version
 * @phy_info: &enum iwl_rx_phy_eht_data0 and &enum iwl_rx_phy_info_type
 * @rx_vec: DW-12:9 raw RX vectors from DSP according to modulation type.
 *	for VHT: OFDM_RX_VECTOR_SIGA1_OUT, OFDM_RX_VECTOR_SIGA2_OUT
@@ -837,9 +841,7 @@ struct iwl_rx_no_data_ver_3 {
	__le32 rate;
	__le32 phy_info[2];
	__le32 rx_vec[4];
} __packed; /* RX_NO_DATA_NTFY_API_S_VER_1,
	       RX_NO_DATA_NTFY_API_S_VER_2
	       RX_NO_DATA_NTFY_API_S_VER_3 */
} __packed; /* RX_NO_DATA_NTFY_API_S_VER_3, _VER_4 */

struct iwl_frame_release {
	u8 baid;
+10 −5
Original line number Diff line number Diff line
@@ -286,7 +286,7 @@ struct iwl_tx_cmd_gen2 {
 * @offload_assist: TX offload configuration
 * @dram_info: FW internal DRAM storage
 * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is
 *	cleared. Combination of RATE_MCS_*
 *	cleared. Combination of RATE_MCS_*; format depends on version
 * @reserved: reserved
 * @hdr: 802.11 header
 */
@@ -298,7 +298,10 @@ struct iwl_tx_cmd_gen3 {
	__le32 rate_n_flags;
	u8 reserved[8];
	struct ieee80211_hdr hdr[];
} __packed; /* TX_CMD_API_S_VER_8, TX_CMD_API_S_VER_10 */
} __packed; /* TX_CMD_API_S_VER_8,
	     * TX_CMD_API_S_VER_10,
	     * TX_CMD_API_S_VER_11
	     */

/*
 * TX response related data
@@ -549,7 +552,7 @@ struct iwl_tx_resp_v3 {
 * @failure_rts: num of failures due to unsuccessful RTS
 * @failure_frame: num failures due to no ACK (unused for agg)
 * @initial_rate: for non-agg: rate of the successful Tx. For agg: rate of the
 *	Tx of all the batch. RATE_MCS_*
 *	Tx of all the batch. RATE_MCS_*; format depends on command version
 * @wireless_media_time: for non-agg: RTS + CTS + frame tx attempts time + ACK.
 *	for agg: RTS + CTS + aggregation tx time + block-ack time.
 *	in usec.
@@ -600,8 +603,10 @@ struct iwl_tx_resp {
	__le16 reserved2;
	struct agg_tx_status status;
} __packed; /* TX_RSP_API_S_VER_6,
	       TX_RSP_API_S_VER_7,
	       TX_RSP_API_S_VER_8 */
	     * TX_RSP_API_S_VER_7,
	     * TX_RSP_API_S_VER_8,
	     * TX_RSP_API_S_VER_9
	     */

/**
 * struct iwl_mvm_ba_notif - notifies about reception of BA
+0 −98
Original line number Diff line number Diff line
@@ -91,104 +91,6 @@ const char *iwl_rs_pretty_bw(int bw)
}
IWL_EXPORT_SYMBOL(iwl_rs_pretty_bw);

static u32 iwl_legacy_rate_to_fw_idx(u32 rate_n_flags)
{
	int rate = rate_n_flags & RATE_LEGACY_RATE_MSK_V1;
	int idx;
	bool ofdm = !(rate_n_flags & RATE_MCS_CCK_MSK_V1);
	int offset = ofdm ? IWL_FIRST_OFDM_RATE : 0;
	int last = ofdm ? IWL_RATE_COUNT_LEGACY : IWL_FIRST_OFDM_RATE;

	for (idx = offset; idx < last; idx++)
		if (iwl_fw_rate_idx_to_plcp(idx) == rate)
			return idx - offset;
	return IWL_RATE_INVALID;
}

u32 iwl_new_rate_from_v1(u32 rate_v1)
{
	u32 rate_v2 = 0;
	u32 dup = 0;

	if (rate_v1 == 0)
		return rate_v1;
	/* convert rate */
	if (rate_v1 & RATE_MCS_HT_MSK_V1) {
		u32 nss = 0;

		rate_v2 |= RATE_MCS_MOD_TYPE_HT;
		rate_v2 |=
			rate_v1 & RATE_HT_MCS_RATE_CODE_MSK_V1;
		nss = (rate_v1 & RATE_HT_MCS_MIMO2_MSK) >>
			RATE_HT_MCS_NSS_POS_V1;
		rate_v2 |= u32_encode_bits(nss, RATE_MCS_NSS_MSK);
	} else if (rate_v1 & RATE_MCS_VHT_MSK_V1 ||
		   rate_v1 & RATE_MCS_HE_MSK_V1) {
		rate_v2 |= rate_v1 & RATE_VHT_MCS_RATE_CODE_MSK;

		rate_v2 |= rate_v1 & RATE_MCS_NSS_MSK;

		if (rate_v1 & RATE_MCS_HE_MSK_V1) {
			u32 he_type_bits = rate_v1 & RATE_MCS_HE_TYPE_MSK_V1;
			u32 he_type = he_type_bits >> RATE_MCS_HE_TYPE_POS_V1;
			u32 he_106t = (rate_v1 & RATE_MCS_HE_106T_MSK_V1) >>
				RATE_MCS_HE_106T_POS_V1;
			u32 he_gi_ltf = (rate_v1 & RATE_MCS_HE_GI_LTF_MSK_V1) >>
				RATE_MCS_HE_GI_LTF_POS;

			if ((he_type_bits == RATE_MCS_HE_TYPE_SU ||
			     he_type_bits == RATE_MCS_HE_TYPE_EXT_SU) &&
			    he_gi_ltf == RATE_MCS_HE_SU_4_LTF)
				/* the new rate have an additional bit to
				 * represent the value 4 rather then using SGI
				 * bit for this purpose - as it was done in the old
				 * rate */
				he_gi_ltf += (rate_v1 & RATE_MCS_SGI_MSK_V1) >>
					RATE_MCS_SGI_POS_V1;

			rate_v2 |= he_gi_ltf << RATE_MCS_HE_GI_LTF_POS;
			rate_v2 |= he_type << RATE_MCS_HE_TYPE_POS;
			rate_v2 |= he_106t << RATE_MCS_HE_106T_POS;
			rate_v2 |= rate_v1 & RATE_HE_DUAL_CARRIER_MODE_MSK;
			rate_v2 |= RATE_MCS_MOD_TYPE_HE;
		} else {
			rate_v2 |= RATE_MCS_MOD_TYPE_VHT;
		}
	/* if legacy format */
	} else {
		u32 legacy_rate = iwl_legacy_rate_to_fw_idx(rate_v1);

		if (WARN_ON_ONCE(legacy_rate == IWL_RATE_INVALID))
			legacy_rate = (rate_v1 & RATE_MCS_CCK_MSK_V1) ?
				IWL_FIRST_CCK_RATE : IWL_FIRST_OFDM_RATE;

		rate_v2 |= legacy_rate;
		if (!(rate_v1 & RATE_MCS_CCK_MSK_V1))
			rate_v2 |= RATE_MCS_MOD_TYPE_LEGACY_OFDM;
	}

	/* convert flags */
	if (rate_v1 & RATE_MCS_LDPC_MSK_V1)
		rate_v2 |= RATE_MCS_LDPC_MSK;
	rate_v2 |= (rate_v1 & RATE_MCS_CHAN_WIDTH_MSK_V1) |
		(rate_v1 & RATE_MCS_ANT_AB_MSK) |
		(rate_v1 & RATE_MCS_STBC_MSK) |
		(rate_v1 & RATE_MCS_BF_MSK);

	dup = (rate_v1 & RATE_MCS_DUP_MSK_V1) >> RATE_MCS_DUP_POS_V1;
	if (dup) {
		rate_v2 |= RATE_MCS_DUP_MSK;
		rate_v2 |= dup << RATE_MCS_CHAN_WIDTH_POS;
	}

	if ((!(rate_v1 & RATE_MCS_HE_MSK_V1)) &&
	    (rate_v1 & RATE_MCS_SGI_MSK_V1))
		rate_v2 |= RATE_MCS_SGI_MSK;

	return rate_v2;
}
IWL_EXPORT_SYMBOL(iwl_new_rate_from_v1);

int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate)
{
	char *type;
+20 −2
Original line number Diff line number Diff line
@@ -999,8 +999,8 @@ void iwl_mld_add_link_debugfs(struct ieee80211_hw *hw,
		mld_link_dir = debugfs_create_dir("iwlmld", dir);
}

static ssize_t iwl_dbgfs_fixed_rate_write(struct iwl_mld *mld, char *buf,
					  size_t count, void *data)
static ssize_t _iwl_dbgfs_fixed_rate_write(struct iwl_mld *mld, char *buf,
					   size_t count, void *data, bool v3)
{
	struct ieee80211_link_sta *link_sta = data;
	struct iwl_mld_link_sta *mld_link_sta;
@@ -1022,6 +1022,10 @@ static ssize_t iwl_dbgfs_fixed_rate_write(struct iwl_mld *mld, char *buf,
	if (iwl_mld_dbgfs_fw_cmd_disabled(mld))
		return -EIO;

	/* input is in FW format (v2 or v3) so convert to v3 */
	rate = iwl_v3_rate_from_v2_v3(cpu_to_le32(rate), v3);
	rate = le32_to_cpu(iwl_v3_rate_to_v2_v3(rate, mld->fw_rates_ver_3));

	ret = iwl_mld_send_tlc_dhc(mld, fw_sta_id,
				   partial ? IWL_TLC_DEBUG_PARTIAL_FIXED_RATE :
					     IWL_TLC_DEBUG_FIXED_RATE,
@@ -1035,6 +1039,18 @@ static ssize_t iwl_dbgfs_fixed_rate_write(struct iwl_mld *mld, char *buf,
	return ret ? : count;
}

static ssize_t iwl_dbgfs_fixed_rate_write(struct iwl_mld *mld, char *buf,
					  size_t count, void *data)
{
	return _iwl_dbgfs_fixed_rate_write(mld, buf, count, data, false);
}

static ssize_t iwl_dbgfs_fixed_rate_v3_write(struct iwl_mld *mld, char *buf,
					     size_t count, void *data)
{
	return _iwl_dbgfs_fixed_rate_write(mld, buf, count, data, true);
}

static ssize_t iwl_dbgfs_tlc_dhc_write(struct iwl_mld *mld, char *buf,
				       size_t count, void *data)
{
@@ -1074,6 +1090,7 @@ static ssize_t iwl_dbgfs_tlc_dhc_write(struct iwl_mld *mld, char *buf,

LINK_STA_WIPHY_DEBUGFS_WRITE_OPS(tlc_dhc, 64);
LINK_STA_WIPHY_DEBUGFS_WRITE_OPS(fixed_rate, 64);
LINK_STA_WIPHY_DEBUGFS_WRITE_OPS(fixed_rate_v3, 64);

void iwl_mld_add_link_sta_debugfs(struct ieee80211_hw *hw,
				  struct ieee80211_vif *vif,
@@ -1081,5 +1098,6 @@ void iwl_mld_add_link_sta_debugfs(struct ieee80211_hw *hw,
				  struct dentry *dir)
{
	LINK_STA_DEBUGFS_ADD_FILE(fixed_rate, dir, 0200);
	LINK_STA_DEBUGFS_ADD_FILE(fixed_rate_v3, dir, 0200);
	LINK_STA_DEBUGFS_ADD_FILE(tlc_dhc, dir, 0200);
}
Loading