diff mbox series

[V3,3/3] ath11k: add support for setting fixed HE rate/gi/ltf

Message ID 20200429145708.25992-3-john@phrozen.org (mailing list archive)
State New, archived
Headers show
Series [V3,1/3] nl80211: add support for setting fixed HE rate/gi/ltf | expand

Commit Message

John Crispin April 29, 2020, 2:57 p.m. UTC
From: Miles Hu <milehu@codeaurora.org>

This patch adds ath11k support for setting fixed HE rate/gi/ltf values that
we are now able to send to the kernel using nl80211. The added code is
reusing parts of the existing code path already used for HT/VHT. The new
helpers are symmetric to how we do it for HT/VHT.

Signed-off-by: Miles Hu <milehu@codeaurora.org>
Signed-off-by: John Crispin <john@phrozen.org>
---
 drivers/net/wireless/ath/ath11k/mac.c | 350 +++++++++++++++++++++++---
 drivers/net/wireless/ath/ath11k/wmi.h |   1 +
 2 files changed, 323 insertions(+), 28 deletions(-)

Comments

Kalle Valo April 30, 2020, 8:46 a.m. UTC | #1
John Crispin <john@phrozen.org> writes:

> From: Miles Hu <milehu@codeaurora.org>
>
> This patch adds ath11k support for setting fixed HE rate/gi/ltf values that
> we are now able to send to the kernel using nl80211. The added code is
> reusing parts of the existing code path already used for HT/VHT. The new
> helpers are symmetric to how we do it for HT/VHT.
>
> Signed-off-by: Miles Hu <milehu@codeaurora.org>
> Signed-off-by: John Crispin <john@phrozen.org>

[...]

> +		if (he_ltf != 0xFF) {
> +			vdev_param = WMI_VDEV_PARAM_HE_LTF;
> +				/* start from 1 */
> +				he_ltf += 1;

Indentation looks weird here, but I can fix that during commit.
kernel test robot May 1, 2020, 2:14 a.m. UTC | #2
Hi John,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on mac80211/master]
[also build test WARNING on ath6kl/ath-next v5.7-rc3]
[cannot apply to mac80211-next/master next-20200430]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]

url:    https://github.com/0day-ci/linux/commits/John-Crispin/nl80211-add-support-for-setting-fixed-HE-rate-gi-ltf/20200430-040802
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211.git master
reproduce:
        # apt-get install sparse
        # sparse version: v0.6.1-191-gc51a0382-dirty
        make ARCH=x86_64 allmodconfig
        make C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__'

If you fix the issue, kindly add following tag as appropriate
Reported-by: kbuild test robot <lkp@intel.com>


sparse warnings: (new ones prefixed by >>)

>> drivers/net/wireless/ath/ath11k/mac.c:1310:27: sparse: sparse: incorrect type in assignment (different base types) @@    expected restricted __le16 [usertype] v @@    got tricted __le16 [usertype] v @@
>> drivers/net/wireless/ath/ath11k/mac.c:1310:27: sparse:    expected restricted __le16 [usertype] v
>> drivers/net/wireless/ath/ath11k/mac.c:1310:27: sparse:    got unsigned short [usertype]
>> drivers/net/wireless/ath/ath11k/mac.c:1311:83: sparse: sparse: incorrect type in assignment (different base types) @@    expected unsigned int @@    got restricted __le16unsigned int @@
>> drivers/net/wireless/ath/ath11k/mac.c:1311:83: sparse:    expected unsigned int
>> drivers/net/wireless/ath/ath11k/mac.c:1311:83: sparse:    got restricted __le16 [usertype] v
   drivers/net/wireless/ath/ath11k/mac.c:1313:27: sparse: sparse: incorrect type in assignment (different base types) @@    expected restricted __le16 [usertype] v @@    got tricted __le16 [usertype] v @@
   drivers/net/wireless/ath/ath11k/mac.c:1313:27: sparse:    expected restricted __le16 [usertype] v
   drivers/net/wireless/ath/ath11k/mac.c:1313:27: sparse:    got unsigned short [usertype]
>> drivers/net/wireless/ath/ath11k/mac.c:1314:58: sparse: sparse: incorrect type in argument 1 (different base types) @@    expected unsigned short [assigned] [usertype] tx_mcs_set @@    got  short [assigned] [usertype] tx_mcs_set @@
>> drivers/net/wireless/ath/ath11k/mac.c:1314:58: sparse:    expected unsigned short [assigned] [usertype] tx_mcs_set
   drivers/net/wireless/ath/ath11k/mac.c:1314:58: sparse:    got restricted __le16 [usertype] v
>> drivers/net/wireless/ath/ath11k/mac.c:1314:27: sparse: sparse: incorrect type in assignment (different base types) @@    expected restricted __le16 [usertype] v @@    got 16 [usertype] v @@
   drivers/net/wireless/ath/ath11k/mac.c:1314:27: sparse:    expected restricted __le16 [usertype] v
>> drivers/net/wireless/ath/ath11k/mac.c:1314:27: sparse:    got unsigned short
   drivers/net/wireless/ath/ath11k/mac.c:1315:83: sparse: sparse: incorrect type in assignment (different base types) @@    expected unsigned int @@    got restricted __le16unsigned int @@
   drivers/net/wireless/ath/ath11k/mac.c:1315:83: sparse:    expected unsigned int
   drivers/net/wireless/ath/ath11k/mac.c:1315:83: sparse:    got restricted __le16 [usertype] v
   drivers/net/wireless/ath/ath11k/mac.c:1320:19: sparse: sparse: incorrect type in assignment (different base types) @@    expected restricted __le16 [usertype] v @@    got tricted __le16 [usertype] v @@
   drivers/net/wireless/ath/ath11k/mac.c:1320:19: sparse:    expected restricted __le16 [usertype] v
   drivers/net/wireless/ath/ath11k/mac.c:1320:19: sparse:    got unsigned short [usertype]
   drivers/net/wireless/ath/ath11k/mac.c:1321:73: sparse: sparse: incorrect type in assignment (different base types) @@    expected unsigned int @@    got restricted __le16unsigned int @@
   drivers/net/wireless/ath/ath11k/mac.c:1321:73: sparse:    expected unsigned int
   drivers/net/wireless/ath/ath11k/mac.c:1321:73: sparse:    got restricted __le16 [usertype] v
   drivers/net/wireless/ath/ath11k/mac.c:1323:19: sparse: sparse: incorrect type in assignment (different base types) @@    expected restricted __le16 [usertype] v @@    got tricted __le16 [usertype] v @@
   drivers/net/wireless/ath/ath11k/mac.c:1323:19: sparse:    expected restricted __le16 [usertype] v
   drivers/net/wireless/ath/ath11k/mac.c:1323:19: sparse:    got unsigned short [usertype]
   drivers/net/wireless/ath/ath11k/mac.c:1324:50: sparse: sparse: incorrect type in argument 1 (different base types) @@    expected unsigned short [assigned] [usertype] tx_mcs_set @@    got  short [assigned] [usertype] tx_mcs_set @@
   drivers/net/wireless/ath/ath11k/mac.c:1324:50: sparse:    expected unsigned short [assigned] [usertype] tx_mcs_set
   drivers/net/wireless/ath/ath11k/mac.c:1324:50: sparse:    got restricted __le16 [usertype] v
   drivers/net/wireless/ath/ath11k/mac.c:1324:19: sparse: sparse: incorrect type in assignment (different base types) @@    expected restricted __le16 [usertype] v @@    got 16 [usertype] v @@
   drivers/net/wireless/ath/ath11k/mac.c:1324:19: sparse:    expected restricted __le16 [usertype] v
   drivers/net/wireless/ath/ath11k/mac.c:1324:19: sparse:    got unsigned short
   drivers/net/wireless/ath/ath11k/mac.c:1325:73: sparse: sparse: incorrect type in assignment (different base types) @@    expected unsigned int @@    got restricted __le16unsigned int @@
   drivers/net/wireless/ath/ath11k/mac.c:1325:73: sparse:    expected unsigned int
   drivers/net/wireless/ath/ath11k/mac.c:1325:73: sparse:    got restricted __le16 [usertype] v
   drivers/net/wireless/ath/ath11k/mac.c:1333:19: sparse: sparse: incorrect type in assignment (different base types) @@    expected restricted __le16 [usertype] v @@    got tricted __le16 [usertype] v @@
   drivers/net/wireless/ath/ath11k/mac.c:1333:19: sparse:    expected restricted __le16 [usertype] v
   drivers/net/wireless/ath/ath11k/mac.c:1333:19: sparse:    got unsigned short [usertype]
   drivers/net/wireless/ath/ath11k/mac.c:1334:72: sparse: sparse: incorrect type in assignment (different base types) @@    expected unsigned int @@    got restricted __le16unsigned int @@
   drivers/net/wireless/ath/ath11k/mac.c:1334:72: sparse:    expected unsigned int
   drivers/net/wireless/ath/ath11k/mac.c:1334:72: sparse:    got restricted __le16 [usertype] v
   drivers/net/wireless/ath/ath11k/mac.c:1336:19: sparse: sparse: incorrect type in assignment (different base types) @@    expected restricted __le16 [usertype] v @@    got tricted __le16 [usertype] v @@
   drivers/net/wireless/ath/ath11k/mac.c:1336:19: sparse:    expected restricted __le16 [usertype] v
   drivers/net/wireless/ath/ath11k/mac.c:1336:19: sparse:    got unsigned short [usertype]
   drivers/net/wireless/ath/ath11k/mac.c:1337:50: sparse: sparse: incorrect type in argument 1 (different base types) @@    expected unsigned short [assigned] [usertype] tx_mcs_set @@    got  short [assigned] [usertype] tx_mcs_set @@
   drivers/net/wireless/ath/ath11k/mac.c:1337:50: sparse:    expected unsigned short [assigned] [usertype] tx_mcs_set
   drivers/net/wireless/ath/ath11k/mac.c:1337:50: sparse:    got restricted __le16 [usertype] v
   drivers/net/wireless/ath/ath11k/mac.c:1337:19: sparse: sparse: incorrect type in assignment (different base types) @@    expected restricted __le16 [usertype] v @@    got 16 [usertype] v @@
   drivers/net/wireless/ath/ath11k/mac.c:1337:19: sparse:    expected restricted __le16 [usertype] v
   drivers/net/wireless/ath/ath11k/mac.c:1337:19: sparse:    got unsigned short
   drivers/net/wireless/ath/ath11k/mac.c:1338:72: sparse: sparse: incorrect type in assignment (different base types) @@    expected unsigned int @@    got restricted __le16unsigned int @@
   drivers/net/wireless/ath/ath11k/mac.c:1338:72: sparse:    expected unsigned int
   drivers/net/wireless/ath/ath11k/mac.c:1338:72: sparse:    got restricted __le16 [usertype] v
>> drivers/net/wireless/ath/ath11k/mac.c:5292:47: sparse: sparse: incorrect type in return expression (different base types) @@    expected unsigned short @@    got restricted __le16 conunsigned short @@
>> drivers/net/wireless/ath/ath11k/mac.c:5292:47: sparse:    expected unsigned short
>> drivers/net/wireless/ath/ath11k/mac.c:5292:47: sparse:    got restricted __le16 const [usertype] tx_mcs_80p80
   drivers/net/wireless/ath/ath11k/mac.c:5296:47: sparse: sparse: incorrect type in return expression (different base types) @@    expected unsigned short @@    got restricted __le16 conunsigned short @@
   drivers/net/wireless/ath/ath11k/mac.c:5296:47: sparse:    expected unsigned short
>> drivers/net/wireless/ath/ath11k/mac.c:5296:47: sparse:    got restricted __le16 const [usertype] tx_mcs_160
   drivers/net/wireless/ath/ath11k/mac.c:5298:39: sparse: sparse: incorrect type in return expression (different base types) @@    expected unsigned short @@    got restricted __le16 conunsigned short @@
   drivers/net/wireless/ath/ath11k/mac.c:5298:39: sparse:    expected unsigned short
>> drivers/net/wireless/ath/ath11k/mac.c:5298:39: sparse:    got restricted __le16 const [usertype] tx_mcs_80
>> drivers/net/wireless/ath/ath11k/mac.c:5288:5: sparse: sparse: symbol 'ath11k_mac_get_tx_mcs_map' was not declared. Should it be static?
>> drivers/net/wireless/ath/ath11k/mac.c:5339:22: sparse: sparse: cast to restricted __le16

Please review and possibly fold the followup patch.

vim +1310 drivers/net/wireless/ath/ath11k/mac.c

f4740f8f367c7c Miles Hu     2020-04-29  1231  
d5c65159f28953 Kalle Valo   2019-11-23  1232  static void ath11k_peer_assoc_h_he(struct ath11k *ar,
d5c65159f28953 Kalle Valo   2019-11-23  1233  				   struct ieee80211_vif *vif,
d5c65159f28953 Kalle Valo   2019-11-23  1234  				   struct ieee80211_sta *sta,
d5c65159f28953 Kalle Valo   2019-11-23  1235  				   struct peer_assoc_params *arg)
d5c65159f28953 Kalle Valo   2019-11-23  1236  {
f4740f8f367c7c Miles Hu     2020-04-29  1237  	struct ath11k_vif *arvif = (void *)vif->drv_priv;
f4740f8f367c7c Miles Hu     2020-04-29  1238  	struct cfg80211_chan_def def;
9f056ed8ee01ad John Crispin 2019-11-25  1239  	const struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
f4740f8f367c7c Miles Hu     2020-04-29  1240  	enum nl80211_band band;
f4740f8f367c7c Miles Hu     2020-04-29  1241  	const u16 *he_mcs_mask;
f4740f8f367c7c Miles Hu     2020-04-29  1242  	u8 max_nss, he_mcs;
f4740f8f367c7c Miles Hu     2020-04-29  1243  	__le16 he_tx_mcs = 0, v = 0;
f4740f8f367c7c Miles Hu     2020-04-29  1244  	int i;
f4740f8f367c7c Miles Hu     2020-04-29  1245  
f4740f8f367c7c Miles Hu     2020-04-29  1246  	if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
f4740f8f367c7c Miles Hu     2020-04-29  1247  		return;
9f056ed8ee01ad John Crispin 2019-11-25  1248  
9f056ed8ee01ad John Crispin 2019-11-25  1249  	if (!he_cap->has_he)
9f056ed8ee01ad John Crispin 2019-11-25  1250  		return;
9f056ed8ee01ad John Crispin 2019-11-25  1251  
f4740f8f367c7c Miles Hu     2020-04-29  1252  	band = def.chan->band;
f4740f8f367c7c Miles Hu     2020-04-29  1253  	he_mcs_mask = arvif->bitrate_mask.control[band].he_mcs;
f4740f8f367c7c Miles Hu     2020-04-29  1254  
f4740f8f367c7c Miles Hu     2020-04-29  1255  	if (ath11k_peer_assoc_h_he_masked(he_mcs_mask))
f4740f8f367c7c Miles Hu     2020-04-29  1256  		return;
f4740f8f367c7c Miles Hu     2020-04-29  1257  
9f056ed8ee01ad John Crispin 2019-11-25  1258  	arg->he_flag = true;
9f056ed8ee01ad John Crispin 2019-11-25  1259  
9f056ed8ee01ad John Crispin 2019-11-25  1260  	memcpy(&arg->peer_he_cap_macinfo, he_cap->he_cap_elem.mac_cap_info,
9f056ed8ee01ad John Crispin 2019-11-25  1261  	       sizeof(arg->peer_he_cap_macinfo));
9f056ed8ee01ad John Crispin 2019-11-25  1262  	memcpy(&arg->peer_he_cap_phyinfo, he_cap->he_cap_elem.phy_cap_info,
9f056ed8ee01ad John Crispin 2019-11-25  1263  	       sizeof(arg->peer_he_cap_phyinfo));
9f056ed8ee01ad John Crispin 2019-11-25  1264  	memcpy(&arg->peer_he_ops, &vif->bss_conf.he_operation,
9f056ed8ee01ad John Crispin 2019-11-25  1265  	       sizeof(arg->peer_he_ops));
9f056ed8ee01ad John Crispin 2019-11-25  1266  
9f056ed8ee01ad John Crispin 2019-11-25  1267  	/* the top most byte is used to indicate BSS color info */
9f056ed8ee01ad John Crispin 2019-11-25  1268  	arg->peer_he_ops &= 0xffffff;
9f056ed8ee01ad John Crispin 2019-11-25  1269  
9f056ed8ee01ad John Crispin 2019-11-25  1270  	if (he_cap->he_cap_elem.phy_cap_info[6] &
9f056ed8ee01ad John Crispin 2019-11-25  1271  	    IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) {
9f056ed8ee01ad John Crispin 2019-11-25  1272  		int bit = 7;
9f056ed8ee01ad John Crispin 2019-11-25  1273  		int nss, ru;
9f056ed8ee01ad John Crispin 2019-11-25  1274  
9f056ed8ee01ad John Crispin 2019-11-25  1275  		arg->peer_ppet.numss_m1 = he_cap->ppe_thres[0] &
9f056ed8ee01ad John Crispin 2019-11-25  1276  					  IEEE80211_PPE_THRES_NSS_MASK;
9f056ed8ee01ad John Crispin 2019-11-25  1277  		arg->peer_ppet.ru_bit_mask =
9f056ed8ee01ad John Crispin 2019-11-25  1278  			(he_cap->ppe_thres[0] &
9f056ed8ee01ad John Crispin 2019-11-25  1279  			 IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK) >>
9f056ed8ee01ad John Crispin 2019-11-25  1280  			IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS;
9f056ed8ee01ad John Crispin 2019-11-25  1281  
9f056ed8ee01ad John Crispin 2019-11-25  1282  		for (nss = 0; nss <= arg->peer_ppet.numss_m1; nss++) {
9f056ed8ee01ad John Crispin 2019-11-25  1283  			for (ru = 0; ru < 4; ru++) {
9f056ed8ee01ad John Crispin 2019-11-25  1284  				u32 val = 0;
9f056ed8ee01ad John Crispin 2019-11-25  1285  				int i;
9f056ed8ee01ad John Crispin 2019-11-25  1286  
9f056ed8ee01ad John Crispin 2019-11-25  1287  				if ((arg->peer_ppet.ru_bit_mask & BIT(ru)) == 0)
9f056ed8ee01ad John Crispin 2019-11-25  1288  					continue;
9f056ed8ee01ad John Crispin 2019-11-25  1289  				for (i = 0; i < 6; i++) {
9f056ed8ee01ad John Crispin 2019-11-25  1290  					val >>= 1;
9f056ed8ee01ad John Crispin 2019-11-25  1291  					val |= ((he_cap->ppe_thres[bit / 8] >>
9f056ed8ee01ad John Crispin 2019-11-25  1292  						 (bit % 8)) & 0x1) << 5;
9f056ed8ee01ad John Crispin 2019-11-25  1293  					bit++;
9f056ed8ee01ad John Crispin 2019-11-25  1294  				}
9f056ed8ee01ad John Crispin 2019-11-25  1295  				arg->peer_ppet.ppet16_ppet8_ru3_ru0[nss] |=
9f056ed8ee01ad John Crispin 2019-11-25  1296  								val << (ru * 6);
9f056ed8ee01ad John Crispin 2019-11-25  1297  			}
9f056ed8ee01ad John Crispin 2019-11-25  1298  		}
9f056ed8ee01ad John Crispin 2019-11-25  1299  	}
9f056ed8ee01ad John Crispin 2019-11-25  1300  
6d293d447670da John Crispin 2019-11-25  1301  	if (he_cap->he_cap_elem.mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_TWT_RES)
6d293d447670da John Crispin 2019-11-25  1302  		arg->twt_responder = true;
6d293d447670da John Crispin 2019-11-25  1303  	if (he_cap->he_cap_elem.mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_TWT_REQ)
6d293d447670da John Crispin 2019-11-25  1304  		arg->twt_requester = true;
6d293d447670da John Crispin 2019-11-25  1305  
9f056ed8ee01ad John Crispin 2019-11-25  1306  	switch (sta->bandwidth) {
9f056ed8ee01ad John Crispin 2019-11-25  1307  	case IEEE80211_STA_RX_BW_160:
9f056ed8ee01ad John Crispin 2019-11-25  1308  		if (he_cap->he_cap_elem.phy_cap_info[0] &
9f056ed8ee01ad John Crispin 2019-11-25  1309  		    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) {
9f056ed8ee01ad John Crispin 2019-11-25 @1310  			v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80p80);
9f056ed8ee01ad John Crispin 2019-11-25 @1311  			arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] = v;
9f056ed8ee01ad John Crispin 2019-11-25  1312  
9f056ed8ee01ad John Crispin 2019-11-25  1313  			v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80p80);
f4740f8f367c7c Miles Hu     2020-04-29 @1314  			v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask);
9f056ed8ee01ad John Crispin 2019-11-25  1315  			arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] = v;
9f056ed8ee01ad John Crispin 2019-11-25  1316  
9f056ed8ee01ad John Crispin 2019-11-25  1317  			arg->peer_he_mcs_count++;
f4740f8f367c7c Miles Hu     2020-04-29  1318  			he_tx_mcs = v;
9f056ed8ee01ad John Crispin 2019-11-25  1319  		}
9f056ed8ee01ad John Crispin 2019-11-25  1320  		v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160);
9f056ed8ee01ad John Crispin 2019-11-25  1321  		arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v;
9f056ed8ee01ad John Crispin 2019-11-25  1322  
9f056ed8ee01ad John Crispin 2019-11-25  1323  		v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_160);
f4740f8f367c7c Miles Hu     2020-04-29  1324  		v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask);
9f056ed8ee01ad John Crispin 2019-11-25  1325  		arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v;
9f056ed8ee01ad John Crispin 2019-11-25  1326  
9f056ed8ee01ad John Crispin 2019-11-25  1327  		arg->peer_he_mcs_count++;
f4740f8f367c7c Miles Hu     2020-04-29  1328  		if (!he_tx_mcs)
f4740f8f367c7c Miles Hu     2020-04-29  1329  			he_tx_mcs = v;
9f056ed8ee01ad John Crispin 2019-11-25  1330  		/* fall through */
9f056ed8ee01ad John Crispin 2019-11-25  1331  
9f056ed8ee01ad John Crispin 2019-11-25  1332  	default:
9f056ed8ee01ad John Crispin 2019-11-25  1333  		v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80);
9f056ed8ee01ad John Crispin 2019-11-25  1334  		arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v;
9f056ed8ee01ad John Crispin 2019-11-25  1335  
9f056ed8ee01ad John Crispin 2019-11-25  1336  		v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80);
f4740f8f367c7c Miles Hu     2020-04-29 @1337  		v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask);
9f056ed8ee01ad John Crispin 2019-11-25 @1338  		arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v;
9f056ed8ee01ad John Crispin 2019-11-25  1339  
9f056ed8ee01ad John Crispin 2019-11-25  1340  		arg->peer_he_mcs_count++;
f4740f8f367c7c Miles Hu     2020-04-29  1341  		if (!he_tx_mcs)
f4740f8f367c7c Miles Hu     2020-04-29  1342  			he_tx_mcs = v;
9f056ed8ee01ad John Crispin 2019-11-25  1343  		break;
9f056ed8ee01ad John Crispin 2019-11-25  1344  	}
f4740f8f367c7c Miles Hu     2020-04-29  1345  	/* Calculate peer NSS capability from HE capabilities if STA
f4740f8f367c7c Miles Hu     2020-04-29  1346  	 * supports HE.
f4740f8f367c7c Miles Hu     2020-04-29  1347  	 */
f4740f8f367c7c Miles Hu     2020-04-29  1348  	for (i = 0, max_nss = 0, he_mcs = 0; i < NL80211_HE_NSS_MAX; i++) {
f4740f8f367c7c Miles Hu     2020-04-29  1349  		he_mcs = __le16_to_cpu(he_tx_mcs) >> (2 * i) & 3;
f4740f8f367c7c Miles Hu     2020-04-29  1350  
f4740f8f367c7c Miles Hu     2020-04-29  1351  		if (he_mcs != IEEE80211_HE_MCS_NOT_SUPPORTED &&
f4740f8f367c7c Miles Hu     2020-04-29  1352  		    he_mcs_mask[i])
f4740f8f367c7c Miles Hu     2020-04-29  1353  			max_nss = i + 1;
f4740f8f367c7c Miles Hu     2020-04-29  1354  	}
f4740f8f367c7c Miles Hu     2020-04-29  1355  	arg->peer_nss = min(sta->rx_nss, max_nss);
f4740f8f367c7c Miles Hu     2020-04-29  1356  
f4740f8f367c7c Miles Hu     2020-04-29  1357  	ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
f4740f8f367c7c Miles Hu     2020-04-29  1358  		   "mac he peer %pM nss %d mcs cnt %d\n",
f4740f8f367c7c Miles Hu     2020-04-29  1359  		   sta->addr, arg->peer_nss, arg->peer_he_mcs_count);
d5c65159f28953 Kalle Valo   2019-11-23  1360  }
d5c65159f28953 Kalle Valo   2019-11-23  1361  

:::::: The code at line 1310 was first introduced by commit
:::::: 9f056ed8ee01ad6898db49707cdc70ce923be3d0 ath11k: add HE support

:::::: TO: John Crispin <john@phrozen.org>
:::::: CC: Kalle Valo <kvalo@codeaurora.org>

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff mbox series

Patch

diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c
index e28f5a348be6..aef012912003 100644
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -268,6 +268,18 @@  ath11k_mac_max_vht_nss(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
 	return 1;
 }
 
+static u32
+ath11k_mac_max_he_nss(const u16 he_mcs_mask[NL80211_HE_NSS_MAX])
+{
+	int nss;
+
+	for (nss = NL80211_HE_NSS_MAX - 1; nss >= 0; nss--)
+		if (he_mcs_mask[nss])
+			return nss + 1;
+
+	return 1;
+}
+
 static u8 ath11k_parse_mpdudensity(u8 mpdudensity)
 {
 /* 802.11n D2.0 defined values for "Minimum MPDU Start Spacing":
@@ -1151,17 +1163,98 @@  static void ath11k_peer_assoc_h_vht(struct ath11k *ar,
 	/* TODO: rxnss_override */
 }
 
+static int ath11k_mac_get_max_he_mcs_map(u16 mcs_map, int nss)
+{
+	switch ((mcs_map >> (2 * nss)) & 0x3) {
+	case IEEE80211_HE_MCS_SUPPORT_0_7: return BIT(8) - 1;
+	case IEEE80211_HE_MCS_SUPPORT_0_9: return BIT(10) - 1;
+	case IEEE80211_HE_MCS_SUPPORT_0_11: return BIT(12) - 1;
+	}
+	return 0;
+}
+
+static u16 ath11k_peer_assoc_h_he_limit(u16 tx_mcs_set,
+					const u16 he_mcs_limit[NL80211_HE_NSS_MAX])
+{
+	int idx_limit;
+	int nss;
+	u16 mcs_map;
+	u16 mcs;
+
+	for (nss = 0; nss < NL80211_HE_NSS_MAX; nss++) {
+		mcs_map = ath11k_mac_get_max_he_mcs_map(tx_mcs_set, nss) &
+			  he_mcs_limit[nss];
+
+		if (mcs_map)
+			idx_limit = fls(mcs_map) - 1;
+		else
+			idx_limit = -1;
+
+		switch (idx_limit) {
+		case 0 ... 7:
+			mcs = IEEE80211_HE_MCS_SUPPORT_0_7;
+			break;
+		case 8:
+		case 9:
+			mcs = IEEE80211_HE_MCS_SUPPORT_0_9;
+			break;
+		case 10:
+		case 11:
+			mcs = IEEE80211_HE_MCS_SUPPORT_0_11;
+			break;
+		default:
+			WARN_ON(1);
+			/* fall through */
+		case -1:
+			mcs = IEEE80211_HE_MCS_NOT_SUPPORTED;
+			break;
+		}
+
+		tx_mcs_set &= ~(0x3 << (nss * 2));
+		tx_mcs_set |= mcs << (nss * 2);
+	}
+
+	return tx_mcs_set;
+}
+
+static bool
+ath11k_peer_assoc_h_he_masked(const u16 he_mcs_mask[NL80211_HE_NSS_MAX])
+{
+	int nss;
+
+	for (nss = 0; nss < NL80211_HE_NSS_MAX; nss++)
+		if (he_mcs_mask[nss])
+			return false;
+
+	return true;
+}
+
 static void ath11k_peer_assoc_h_he(struct ath11k *ar,
 				   struct ieee80211_vif *vif,
 				   struct ieee80211_sta *sta,
 				   struct peer_assoc_params *arg)
 {
+	struct ath11k_vif *arvif = (void *)vif->drv_priv;
+	struct cfg80211_chan_def def;
 	const struct ieee80211_sta_he_cap *he_cap = &sta->he_cap;
-	u16 v;
+	enum nl80211_band band;
+	const u16 *he_mcs_mask;
+	u8 max_nss, he_mcs;
+	__le16 he_tx_mcs = 0, v = 0;
+	int i;
+
+	if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
+		return;
 
 	if (!he_cap->has_he)
 		return;
 
+	band = def.chan->band;
+	he_mcs_mask = arvif->bitrate_mask.control[band].he_mcs;
+
+	if (ath11k_peer_assoc_h_he_masked(he_mcs_mask))
+		return;
+
 	arg->he_flag = true;
 
 	memcpy(&arg->peer_he_cap_macinfo, he_cap->he_cap_elem.mac_cap_info,
@@ -1218,17 +1311,22 @@  static void ath11k_peer_assoc_h_he(struct ath11k *ar,
 			arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] = v;
 
 			v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80p80);
+			v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask);
 			arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] = v;
 
 			arg->peer_he_mcs_count++;
+			he_tx_mcs = v;
 		}
 		v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160);
 		arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v;
 
 		v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_160);
+		v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask);
 		arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v;
 
 		arg->peer_he_mcs_count++;
+		if (!he_tx_mcs)
+			he_tx_mcs = v;
 		/* fall through */
 
 	default:
@@ -1236,11 +1334,29 @@  static void ath11k_peer_assoc_h_he(struct ath11k *ar,
 		arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v;
 
 		v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80);
+		v = ath11k_peer_assoc_h_he_limit(v, he_mcs_mask);
 		arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v;
 
 		arg->peer_he_mcs_count++;
+		if (!he_tx_mcs)
+			he_tx_mcs = v;
 		break;
 	}
+	/* Calculate peer NSS capability from HE capabilities if STA
+	 * supports HE.
+	 */
+	for (i = 0, max_nss = 0, he_mcs = 0; i < NL80211_HE_NSS_MAX; i++) {
+		he_mcs = __le16_to_cpu(he_tx_mcs) >> (2 * i) & 3;
+
+		if (he_mcs != IEEE80211_HE_MCS_NOT_SUPPORTED &&
+		    he_mcs_mask[i])
+			max_nss = i + 1;
+	}
+	arg->peer_nss = min(sta->rx_nss, max_nss);
+
+	ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
+		   "mac he peer %pM nss %d mcs cnt %d\n",
+		   sta->addr, arg->peer_nss, arg->peer_he_mcs_count);
 }
 
 static void ath11k_peer_assoc_h_smps(struct ieee80211_sta *sta,
@@ -1443,6 +1559,7 @@  static void ath11k_peer_assoc_h_phymode(struct ath11k *ar,
 	enum nl80211_band band;
 	const u8 *ht_mcs_mask;
 	const u16 *vht_mcs_mask;
+	const u16 *he_mcs_mask;
 	enum wmi_phy_mode phymode = MODE_UNKNOWN;
 
 	if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
@@ -1451,10 +1568,12 @@  static void ath11k_peer_assoc_h_phymode(struct ath11k *ar,
 	band = def.chan->band;
 	ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs;
 	vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs;
+	he_mcs_mask = arvif->bitrate_mask.control[band].he_mcs;
 
 	switch (band) {
 	case NL80211_BAND_2GHZ:
-		if (sta->he_cap.has_he) {
+		if (sta->he_cap.has_he &&
+		    !ath11k_peer_assoc_h_he_masked(he_mcs_mask)) {
 			if (sta->bandwidth == IEEE80211_STA_RX_BW_80)
 				phymode = MODE_11AX_HE80_2G;
 			else if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
@@ -1481,7 +1600,8 @@  static void ath11k_peer_assoc_h_phymode(struct ath11k *ar,
 		break;
 	case NL80211_BAND_5GHZ:
 		/* Check HE first */
-		if (sta->he_cap.has_he) {
+		if (sta->he_cap.has_he &&
+		    !ath11k_peer_assoc_h_he_masked(he_mcs_mask)) {
 			phymode = ath11k_mac_get_phymode_he(ar, sta);
 		} else if (sta->vht_cap.vht_supported &&
 		    !ath11k_peer_assoc_h_vht_masked(vht_mcs_mask)) {
@@ -2412,6 +2532,20 @@  ath11k_mac_bitrate_mask_num_vht_rates(struct ath11k *ar,
 	return num_rates;
 }
 
+static int
+ath11k_mac_bitrate_mask_num_he_rates(struct ath11k *ar,
+				     enum nl80211_band band,
+				     const struct cfg80211_bitrate_mask *mask)
+{
+	int num_rates = 0;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mask->control[band].he_mcs); i++)
+		num_rates += hweight16(mask->control[band].he_mcs[i]);
+
+	return num_rates;
+}
+
 static int
 ath11k_mac_set_peer_vht_fixed_rate(struct ath11k_vif *arvif,
 				   struct ieee80211_sta *sta,
@@ -2458,6 +2592,52 @@  ath11k_mac_set_peer_vht_fixed_rate(struct ath11k_vif *arvif,
 	return ret;
 }
 
+static int
+ath11k_mac_set_peer_he_fixed_rate(struct ath11k_vif *arvif,
+				  struct ieee80211_sta *sta,
+				  const struct cfg80211_bitrate_mask *mask,
+				  enum nl80211_band band)
+{
+	struct ath11k *ar = arvif->ar;
+	u8 he_rate, nss;
+	u32 rate_code;
+	int ret, i;
+
+	lockdep_assert_held(&ar->conf_mutex);
+
+	nss = 0;
+
+	for (i = 0; i < ARRAY_SIZE(mask->control[band].he_mcs); i++) {
+		if (hweight16(mask->control[band].he_mcs[i]) == 1) {
+			nss = i + 1;
+			he_rate = ffs(mask->control[band].he_mcs[i]) - 1;
+		}
+	}
+
+	if (!nss) {
+		ath11k_warn(ar->ab, "No single HE Fixed rate found to set for %pM",
+			    sta->addr);
+		return -EINVAL;
+	}
+
+	ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
+		   "Setting Fixed HE Rate for peer %pM. Device will not switch to any other selected rates",
+		   sta->addr);
+
+	rate_code = ATH11K_HW_RATE_CODE(he_rate, nss - 1,
+					WMI_RATE_PREAMBLE_HE);
+	ret = ath11k_wmi_set_peer_param(ar, sta->addr,
+					arvif->vdev_id,
+					WMI_PEER_PARAM_FIXED_RATE,
+					rate_code);
+	if (ret)
+		ath11k_warn(ar->ab,
+			    "failed to update STA %pM Fixed Rate %d: %d\n",
+			     sta->addr, rate_code, ret);
+
+	return ret;
+}
+
 static int ath11k_station_assoc(struct ath11k *ar,
 				struct ieee80211_vif *vif,
 				struct ieee80211_sta *sta,
@@ -2576,8 +2756,9 @@  static void ath11k_sta_rc_update_wk(struct work_struct *wk)
 	enum nl80211_band band;
 	const u8 *ht_mcs_mask;
 	const u16 *vht_mcs_mask;
+	const u16 *he_mcs_mask;
 	u32 changed, bw, nss, smps;
-	int err, num_vht_rates;
+	int err, num_vht_rates,  num_he_rates;
 	const struct cfg80211_bitrate_mask *mask;
 	struct peer_assoc_params peer_arg;
 
@@ -2592,6 +2773,7 @@  static void ath11k_sta_rc_update_wk(struct work_struct *wk)
 	band = def.chan->band;
 	ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs;
 	vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs;
+	he_mcs_mask = arvif->bitrate_mask.control[band].he_mcs;
 
 	spin_lock_bh(&ar->data_lock);
 
@@ -2607,8 +2789,9 @@  static void ath11k_sta_rc_update_wk(struct work_struct *wk)
 	mutex_lock(&ar->conf_mutex);
 
 	nss = max_t(u32, 1, nss);
-	nss = min(nss, max(ath11k_mac_max_ht_nss(ht_mcs_mask),
-			   ath11k_mac_max_vht_nss(vht_mcs_mask)));
+	nss = min(nss, max(max(ath11k_mac_max_ht_nss(ht_mcs_mask),
+			       ath11k_mac_max_vht_nss(vht_mcs_mask)),
+			   ath11k_mac_max_he_nss(he_mcs_mask)));
 
 	if (changed & IEEE80211_RC_BW_CHANGED) {
 		err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
@@ -2644,6 +2827,8 @@  static void ath11k_sta_rc_update_wk(struct work_struct *wk)
 		mask = &arvif->bitrate_mask;
 		num_vht_rates = ath11k_mac_bitrate_mask_num_vht_rates(ar, band,
 								      mask);
+		num_he_rates = ath11k_mac_bitrate_mask_num_he_rates(ar, band,
+								    mask);
 
 		/* Peer_assoc_prepare will reject vht rates in
 		 * bitrate_mask if its not available in range format and
@@ -2659,6 +2844,9 @@  static void ath11k_sta_rc_update_wk(struct work_struct *wk)
 		if (sta->vht_cap.vht_supported && num_vht_rates == 1) {
 			ath11k_mac_set_peer_vht_fixed_rate(arvif, sta, mask,
 							   band);
+		} else if (sta->he_cap.has_he && num_he_rates == 1) {
+			ath11k_mac_set_peer_he_fixed_rate(arvif, sta, mask,
+							  band);
 		} else {
 			/* If the peer is non-VHT or no fixed VHT rate
 			 * is provided in the new bitrate mask we set the
@@ -4097,6 +4285,8 @@  static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
 		       sizeof(arvif->bitrate_mask.control[i].ht_mcs));
 		memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff,
 		       sizeof(arvif->bitrate_mask.control[i].vht_mcs));
+		memset(arvif->bitrate_mask.control[i].he_mcs, 0xff,
+		       sizeof(arvif->bitrate_mask.control[i].he_mcs));
 	}
 
 	bit = __ffs64(ab->free_vdev_map);
@@ -5022,9 +5212,25 @@  ath11k_mac_has_single_legacy_rate(struct ath11k *ar,
 	if (ath11k_mac_bitrate_mask_num_vht_rates(ar, band, mask))
 		return false;
 
+	if (ath11k_mac_bitrate_mask_num_he_rates(ar, band, mask))
+		return false;
+
 	return num_rates == 1;
 }
 
+u16 ath11k_mac_get_tx_mcs_map(const struct ieee80211_sta_he_cap *he_cap)
+{
+	if (he_cap->he_cap_elem.phy_cap_info[0] &
+	    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
+		return he_cap->he_mcs_nss_supp.tx_mcs_80p80;
+
+	if (he_cap->he_cap_elem.phy_cap_info[0] &
+	    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G)
+		return he_cap->he_mcs_nss_supp.tx_mcs_160;
+
+	return he_cap->he_mcs_nss_supp.tx_mcs_80;
+}
+
 static bool
 ath11k_mac_bitrate_mask_get_single_nss(struct ath11k *ar,
 				       enum nl80211_band band,
@@ -5033,8 +5239,10 @@  ath11k_mac_bitrate_mask_get_single_nss(struct ath11k *ar,
 {
 	struct ieee80211_supported_band *sband = &ar->mac.sbands[band];
 	u16 vht_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map);
+	u16 he_mcs_map = 0;
 	u8 ht_nss_mask = 0;
 	u8 vht_nss_mask = 0;
+	u8 he_nss_mask = 0;
 	int i;
 
 	/* No need to consider legacy here. Basic rates are always present
@@ -5061,7 +5269,19 @@  ath11k_mac_bitrate_mask_get_single_nss(struct ath11k *ar,
 			return false;
 	}
 
-	if (ht_nss_mask != vht_nss_mask)
+	he_mcs_map = le16_to_cpu(ath11k_mac_get_tx_mcs_map(&sband->iftype_data->he_cap));
+
+	for (i = 0; i < ARRAY_SIZE(mask->control[band].he_mcs); i++) {
+		if (mask->control[band].he_mcs[i] == 0)
+			continue;
+		else if (mask->control[band].he_mcs[i] ==
+			 ath11k_mac_get_max_he_mcs_map(he_mcs_map, i))
+			he_nss_mask |= BIT(i);
+		else
+			return false;
+	}
+
+	if (ht_nss_mask != vht_nss_mask || ht_nss_mask != he_nss_mask)
 		return false;
 
 	if (ht_nss_mask == 0)
@@ -5109,7 +5329,8 @@  ath11k_mac_get_single_legacy_rate(struct ath11k *ar,
 }
 
 static int ath11k_mac_set_fixed_rate_params(struct ath11k_vif *arvif,
-					    u32 rate, u8 nss, u8 sgi, u8 ldpc)
+					    u32 rate, u8 nss, u8 sgi, u8 ldpc,
+					    u8 he_gi, u8 he_ltf)
 {
 	struct ath11k *ar = arvif->ar;
 	u32 vdev_param;
@@ -5120,15 +5341,16 @@  static int ath11k_mac_set_fixed_rate_params(struct ath11k_vif *arvif,
 	ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac set fixed rate params vdev %i rate 0x%02hhx nss %hhu sgi %hhu\n",
 		   arvif->vdev_id, rate, nss, sgi);
 
-	vdev_param = WMI_VDEV_PARAM_FIXED_RATE;
-	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
-					    vdev_param, rate);
-	if (ret) {
-		ath11k_warn(ar->ab, "failed to set fixed rate param 0x%02x: %d\n",
-			    rate, ret);
-		return ret;
+	if (!arvif->vif->bss_conf.he_support) {
+		vdev_param = WMI_VDEV_PARAM_FIXED_RATE;
+		ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+						    vdev_param, rate);
+		if (ret) {
+			ath11k_warn(ar->ab, "failed to set fixed rate param 0x%02x: %d\n",
+				    rate, ret);
+			return ret;
+		}
 	}
-
 	vdev_param = WMI_VDEV_PARAM_NSS;
 	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
 					    vdev_param, nss);
@@ -5138,15 +5360,6 @@  static int ath11k_mac_set_fixed_rate_params(struct ath11k_vif *arvif,
 		return ret;
 	}
 
-	vdev_param = WMI_VDEV_PARAM_SGI;
-	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
-					    vdev_param, sgi);
-	if (ret) {
-		ath11k_warn(ar->ab, "failed to set sgi param %d: %d\n",
-			    sgi, ret);
-		return ret;
-	}
-
 	vdev_param = WMI_VDEV_PARAM_LDPC;
 	ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
 					    vdev_param, ldpc);
@@ -5156,6 +5369,43 @@  static int ath11k_mac_set_fixed_rate_params(struct ath11k_vif *arvif,
 		return ret;
 	}
 
+	if (arvif->vif->bss_conf.he_support) {
+		if (he_gi != 0xFF) {
+			vdev_param = WMI_VDEV_PARAM_SGI;
+			/* 0.8 = 0, 1.6 = 2 and 3.2 = 3. */
+			if (he_gi)
+				he_gi += 1;
+			ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+							    vdev_param, he_gi);
+			if (ret) {
+				ath11k_warn(ar->ab, "failed to set hegi param %d: %d\n",
+					    sgi, ret);
+				return ret;
+			}
+		}
+		if (he_ltf != 0xFF) {
+			vdev_param = WMI_VDEV_PARAM_HE_LTF;
+				/* start from 1 */
+				he_ltf += 1;
+			ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+							    vdev_param, he_ltf);
+			if (ret) {
+				ath11k_warn(ar->ab, "failed to set heltf param %d: %d\n",
+					    he_ltf, ret);
+					return ret;
+			}
+		}
+	} else {
+		vdev_param = WMI_VDEV_PARAM_SGI;
+		ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+						    vdev_param, sgi);
+		if (ret) {
+			ath11k_warn(ar->ab, "failed to set sgi param %d: %d\n",
+				    sgi, ret);
+			return ret;
+		}
+	}
+
 	return 0;
 }
 
@@ -5184,6 +5434,31 @@  ath11k_mac_vht_mcs_range_present(struct ath11k *ar,
 	return true;
 }
 
+static bool
+ath11k_mac_he_mcs_range_present(struct ath11k *ar,
+				enum nl80211_band band,
+				const struct cfg80211_bitrate_mask *mask)
+{
+	int i;
+	u16 he_mcs;
+
+	for (i = 0; i < NL80211_HE_NSS_MAX; i++) {
+		he_mcs = mask->control[band].he_mcs[i];
+
+		switch (he_mcs) {
+		case 0:
+		case BIT(8) - 1:
+		case BIT(10) - 1:
+		case BIT(12) - 1:
+			break;
+		default:
+			return false;
+		}
+	}
+
+	return true;
+}
+
 static void ath11k_mac_set_bitrate_mask_iter(void *data,
 					     struct ieee80211_sta *sta)
 {
@@ -5226,6 +5501,9 @@  ath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
 	enum nl80211_band band;
 	const u8 *ht_mcs_mask;
 	const u16 *vht_mcs_mask;
+	const u16 *he_mcs_mask;
+	u8 he_ltf = 0;
+	u8 he_gi = 0;
 	u32 rate;
 	u8 nss;
 	u8 sgi;
@@ -5240,12 +5518,16 @@  ath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
 	band = def.chan->band;
 	ht_mcs_mask = mask->control[band].ht_mcs;
 	vht_mcs_mask = mask->control[band].vht_mcs;
+	he_mcs_mask = mask->control[band].he_mcs;
 	ldpc = !!(ar->ht_cap_info & WMI_HT_CAP_LDPC);
 
 	sgi = mask->control[band].gi;
 	if (sgi == NL80211_TXRATE_FORCE_LGI)
 		return -EINVAL;
 
+	he_gi = mask->control[band].he_gi;
+	he_ltf = mask->control[band].he_ltf;
+
 	/* mac80211 doesn't support sending a fixed HT/VHT MCS alone, rather it
 	 * requires passing atleast one of used basic rates along with them.
 	 * Fixed rate setting across different preambles(legacy, HT, VHT) is
@@ -5272,8 +5554,9 @@  ath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
 	} else {
 		rate = WMI_FIXED_RATE_NONE;
 		nss = min_t(u32, ar->num_tx_chains,
-			    max(ath11k_mac_max_ht_nss(ht_mcs_mask),
-				ath11k_mac_max_vht_nss(vht_mcs_mask)));
+			    max(max(ath11k_mac_max_ht_nss(ht_mcs_mask),
+				    ath11k_mac_max_vht_nss(vht_mcs_mask)),
+				ath11k_mac_max_he_nss(he_mcs_mask)));
 
 		/* If multiple rates across different preambles are given
 		 * we can reconfigure this info with all peers using PEER_ASSOC
@@ -5308,6 +5591,16 @@  ath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
 			return -EINVAL;
 		}
 
+		num_rates = ath11k_mac_bitrate_mask_num_he_rates(ar, band,
+								 mask);
+
+		if (!ath11k_mac_he_mcs_range_present(ar, band, mask) &&
+		    num_rates > 1) {
+			ath11k_warn(ar->ab,
+				    "Setting more than one HE MCS Value in bitrate mask not supported\n");
+			return -EINVAL;
+		}
+
 		ieee80211_iterate_stations_atomic(ar->hw,
 						  ath11k_mac_disable_peer_fixed_rate,
 						  arvif);
@@ -5324,7 +5617,8 @@  ath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
 
 	mutex_lock(&ar->conf_mutex);
 
-	ret = ath11k_mac_set_fixed_rate_params(arvif, rate, nss, sgi, ldpc);
+	ret = ath11k_mac_set_fixed_rate_params(arvif, rate, nss, sgi, ldpc,
+					       he_gi, he_ltf);
 	if (ret) {
 		ath11k_warn(ar->ab, "failed to set fixed rate params on vdev %i: %d\n",
 			    arvif->vdev_id, ret);
diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h
index 742fcd6e37a3..82929415e119 100644
--- a/drivers/net/wireless/ath/ath11k/wmi.h
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
@@ -1008,6 +1008,7 @@  enum wmi_tlv_vdev_param {
 	WMI_VDEV_PARAM_HE_RANGE_EXT,
 	WMI_VDEV_PARAM_ENABLE_BCAST_PROBE_RESPONSE,
 	WMI_VDEV_PARAM_FILS_MAX_CHANNEL_GUARD_TIME,
+	WMI_VDEV_PARAM_HE_LTF = 0x74,
 	WMI_VDEV_PARAM_BA_MODE = 0x7e,
 	WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE = 0x87,
 	WMI_VDEV_PARAM_PROTOTYPE = 0x8000,