he.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * HE handling
  4. *
  5. * Copyright(c) 2017 Intel Deutschland GmbH
  6. * Copyright(c) 2019-2025 Intel Corporation
  7. */
  8. #include "ieee80211_i.h"
  9. #include "rate.h"
  10. static void
  11. ieee80211_update_from_he_6ghz_capa(const struct ieee80211_he_6ghz_capa *he_6ghz_capa,
  12. struct link_sta_info *link_sta)
  13. {
  14. struct sta_info *sta = link_sta->sta;
  15. enum ieee80211_smps_mode smps_mode;
  16. if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
  17. sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
  18. switch (le16_get_bits(he_6ghz_capa->capa,
  19. IEEE80211_HE_6GHZ_CAP_SM_PS)) {
  20. case WLAN_HT_CAP_SM_PS_INVALID:
  21. case WLAN_HT_CAP_SM_PS_STATIC:
  22. smps_mode = IEEE80211_SMPS_STATIC;
  23. break;
  24. case WLAN_HT_CAP_SM_PS_DYNAMIC:
  25. smps_mode = IEEE80211_SMPS_DYNAMIC;
  26. break;
  27. case WLAN_HT_CAP_SM_PS_DISABLED:
  28. smps_mode = IEEE80211_SMPS_OFF;
  29. break;
  30. }
  31. link_sta->pub->smps_mode = smps_mode;
  32. } else {
  33. link_sta->pub->smps_mode = IEEE80211_SMPS_OFF;
  34. }
  35. switch (le16_get_bits(he_6ghz_capa->capa,
  36. IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN)) {
  37. case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
  38. link_sta->pub->agg.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_11454;
  39. break;
  40. case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991:
  41. link_sta->pub->agg.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_7991;
  42. break;
  43. case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895:
  44. default:
  45. link_sta->pub->agg.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_3895;
  46. break;
  47. }
  48. ieee80211_sta_recalc_aggregates(&sta->sta);
  49. link_sta->pub->he_6ghz_capa = *he_6ghz_capa;
  50. }
  51. static void ieee80211_he_mcs_disable(__le16 *he_mcs)
  52. {
  53. u32 i;
  54. for (i = 0; i < 8; i++)
  55. *he_mcs |= cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << i * 2);
  56. }
  57. static void ieee80211_he_mcs_intersection(__le16 *he_own_rx, __le16 *he_peer_rx,
  58. __le16 *he_own_tx, __le16 *he_peer_tx)
  59. {
  60. u32 i;
  61. u16 own_rx, own_tx, peer_rx, peer_tx;
  62. for (i = 0; i < 8; i++) {
  63. own_rx = le16_to_cpu(*he_own_rx);
  64. own_rx = (own_rx >> i * 2) & IEEE80211_HE_MCS_NOT_SUPPORTED;
  65. own_tx = le16_to_cpu(*he_own_tx);
  66. own_tx = (own_tx >> i * 2) & IEEE80211_HE_MCS_NOT_SUPPORTED;
  67. peer_rx = le16_to_cpu(*he_peer_rx);
  68. peer_rx = (peer_rx >> i * 2) & IEEE80211_HE_MCS_NOT_SUPPORTED;
  69. peer_tx = le16_to_cpu(*he_peer_tx);
  70. peer_tx = (peer_tx >> i * 2) & IEEE80211_HE_MCS_NOT_SUPPORTED;
  71. if (peer_tx != IEEE80211_HE_MCS_NOT_SUPPORTED) {
  72. if (own_rx == IEEE80211_HE_MCS_NOT_SUPPORTED)
  73. peer_tx = IEEE80211_HE_MCS_NOT_SUPPORTED;
  74. else if (own_rx < peer_tx)
  75. peer_tx = own_rx;
  76. }
  77. if (peer_rx != IEEE80211_HE_MCS_NOT_SUPPORTED) {
  78. if (own_tx == IEEE80211_HE_MCS_NOT_SUPPORTED)
  79. peer_rx = IEEE80211_HE_MCS_NOT_SUPPORTED;
  80. else if (own_tx < peer_rx)
  81. peer_rx = own_tx;
  82. }
  83. *he_peer_rx &=
  84. ~cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << i * 2);
  85. *he_peer_rx |= cpu_to_le16(peer_rx << i * 2);
  86. *he_peer_tx &=
  87. ~cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << i * 2);
  88. *he_peer_tx |= cpu_to_le16(peer_tx << i * 2);
  89. }
  90. }
  91. void
  92. ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
  93. struct ieee80211_supported_band *sband,
  94. const u8 *he_cap_ie, u8 he_cap_len,
  95. const struct ieee80211_he_6ghz_capa *he_6ghz_capa,
  96. struct link_sta_info *link_sta)
  97. {
  98. struct ieee80211_sta_he_cap *he_cap = &link_sta->pub->he_cap;
  99. const struct ieee80211_sta_he_cap *own_he_cap_ptr;
  100. struct ieee80211_sta_he_cap own_he_cap;
  101. struct ieee80211_he_cap_elem *he_cap_ie_elem = (void *)he_cap_ie;
  102. u8 he_ppe_size;
  103. u8 mcs_nss_size;
  104. u8 he_total_size;
  105. bool own_160, peer_160, own_80p80, peer_80p80;
  106. memset(he_cap, 0, sizeof(*he_cap));
  107. if (!he_cap_ie)
  108. return;
  109. own_he_cap_ptr =
  110. ieee80211_get_he_iftype_cap_vif(sband, &sdata->vif);
  111. if (!own_he_cap_ptr)
  112. return;
  113. own_he_cap = *own_he_cap_ptr;
  114. /* Make sure size is OK */
  115. mcs_nss_size = ieee80211_he_mcs_nss_size(he_cap_ie_elem);
  116. he_ppe_size =
  117. ieee80211_he_ppe_size(he_cap_ie[sizeof(he_cap->he_cap_elem) +
  118. mcs_nss_size],
  119. he_cap_ie_elem->phy_cap_info);
  120. he_total_size = sizeof(he_cap->he_cap_elem) + mcs_nss_size +
  121. he_ppe_size;
  122. if (he_cap_len < he_total_size)
  123. return;
  124. memcpy(&he_cap->he_cap_elem, he_cap_ie, sizeof(he_cap->he_cap_elem));
  125. /* HE Tx/Rx HE MCS NSS Support Field */
  126. memcpy(&he_cap->he_mcs_nss_supp,
  127. &he_cap_ie[sizeof(he_cap->he_cap_elem)], mcs_nss_size);
  128. /* Check if there are (optional) PPE Thresholds */
  129. if (he_cap->he_cap_elem.phy_cap_info[6] &
  130. IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT)
  131. memcpy(he_cap->ppe_thres,
  132. &he_cap_ie[sizeof(he_cap->he_cap_elem) + mcs_nss_size],
  133. he_ppe_size);
  134. he_cap->has_he = true;
  135. link_sta->cur_max_bandwidth = ieee80211_sta_cap_rx_bw(link_sta);
  136. link_sta->pub->bandwidth = ieee80211_sta_cur_vht_bw(link_sta);
  137. if (sband->band == NL80211_BAND_6GHZ && he_6ghz_capa)
  138. ieee80211_update_from_he_6ghz_capa(he_6ghz_capa, link_sta);
  139. ieee80211_he_mcs_intersection(&own_he_cap.he_mcs_nss_supp.rx_mcs_80,
  140. &he_cap->he_mcs_nss_supp.rx_mcs_80,
  141. &own_he_cap.he_mcs_nss_supp.tx_mcs_80,
  142. &he_cap->he_mcs_nss_supp.tx_mcs_80);
  143. own_160 = own_he_cap.he_cap_elem.phy_cap_info[0] &
  144. IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
  145. peer_160 = he_cap->he_cap_elem.phy_cap_info[0] &
  146. IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
  147. if (peer_160 && own_160) {
  148. ieee80211_he_mcs_intersection(&own_he_cap.he_mcs_nss_supp.rx_mcs_160,
  149. &he_cap->he_mcs_nss_supp.rx_mcs_160,
  150. &own_he_cap.he_mcs_nss_supp.tx_mcs_160,
  151. &he_cap->he_mcs_nss_supp.tx_mcs_160);
  152. } else if (peer_160 && !own_160) {
  153. ieee80211_he_mcs_disable(&he_cap->he_mcs_nss_supp.rx_mcs_160);
  154. ieee80211_he_mcs_disable(&he_cap->he_mcs_nss_supp.tx_mcs_160);
  155. he_cap->he_cap_elem.phy_cap_info[0] &=
  156. ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
  157. }
  158. own_80p80 = own_he_cap.he_cap_elem.phy_cap_info[0] &
  159. IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
  160. peer_80p80 = he_cap->he_cap_elem.phy_cap_info[0] &
  161. IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
  162. if (peer_80p80 && own_80p80) {
  163. ieee80211_he_mcs_intersection(&own_he_cap.he_mcs_nss_supp.rx_mcs_80p80,
  164. &he_cap->he_mcs_nss_supp.rx_mcs_80p80,
  165. &own_he_cap.he_mcs_nss_supp.tx_mcs_80p80,
  166. &he_cap->he_mcs_nss_supp.tx_mcs_80p80);
  167. } else if (peer_80p80 && !own_80p80) {
  168. ieee80211_he_mcs_disable(&he_cap->he_mcs_nss_supp.rx_mcs_80p80);
  169. ieee80211_he_mcs_disable(&he_cap->he_mcs_nss_supp.tx_mcs_80p80);
  170. he_cap->he_cap_elem.phy_cap_info[0] &=
  171. ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
  172. }
  173. }
  174. void
  175. ieee80211_he_op_ie_to_bss_conf(struct ieee80211_vif *vif,
  176. const struct ieee80211_he_operation *he_op_ie)
  177. {
  178. memset(&vif->bss_conf.he_oper, 0, sizeof(vif->bss_conf.he_oper));
  179. if (!he_op_ie)
  180. return;
  181. vif->bss_conf.he_oper.params = __le32_to_cpu(he_op_ie->he_oper_params);
  182. vif->bss_conf.he_oper.nss_set = __le16_to_cpu(he_op_ie->he_mcs_nss_set);
  183. }
  184. void
  185. ieee80211_he_spr_ie_to_bss_conf(struct ieee80211_vif *vif,
  186. const struct ieee80211_he_spr *he_spr_ie_elem)
  187. {
  188. struct ieee80211_he_obss_pd *he_obss_pd =
  189. &vif->bss_conf.he_obss_pd;
  190. const u8 *data;
  191. memset(he_obss_pd, 0, sizeof(*he_obss_pd));
  192. if (!he_spr_ie_elem)
  193. return;
  194. he_obss_pd->sr_ctrl = he_spr_ie_elem->he_sr_control;
  195. data = he_spr_ie_elem->optional;
  196. if (he_spr_ie_elem->he_sr_control &
  197. IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT)
  198. he_obss_pd->non_srg_max_offset = *data++;
  199. if (he_spr_ie_elem->he_sr_control &
  200. IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT) {
  201. he_obss_pd->min_offset = *data++;
  202. he_obss_pd->max_offset = *data++;
  203. memcpy(he_obss_pd->bss_color_bitmap, data, 8);
  204. data += 8;
  205. memcpy(he_obss_pd->partial_bssid_bitmap, data, 8);
  206. he_obss_pd->enable = true;
  207. }
  208. }
  209. static void ieee80211_link_sta_rc_update_omi(struct ieee80211_link_data *link,
  210. struct link_sta_info *link_sta)
  211. {
  212. struct ieee80211_sub_if_data *sdata = link->sdata;
  213. struct ieee80211_supported_band *sband;
  214. enum ieee80211_sta_rx_bandwidth new_bw;
  215. enum nl80211_band band;
  216. band = link->conf->chanreq.oper.chan->band;
  217. sband = sdata->local->hw.wiphy->bands[band];
  218. new_bw = ieee80211_sta_cur_vht_bw(link_sta);
  219. if (link_sta->pub->bandwidth == new_bw)
  220. return;
  221. link_sta->pub->bandwidth = new_bw;
  222. rate_control_rate_update(sdata->local, sband, link_sta,
  223. IEEE80211_RC_BW_CHANGED);
  224. }
  225. bool ieee80211_prepare_rx_omi_bw(struct ieee80211_link_sta *pub_link_sta,
  226. enum ieee80211_sta_rx_bandwidth bw)
  227. {
  228. struct sta_info *sta = container_of(pub_link_sta->sta,
  229. struct sta_info, sta);
  230. struct ieee80211_local *local = sta->sdata->local;
  231. struct link_sta_info *link_sta =
  232. sdata_dereference(sta->link[pub_link_sta->link_id], sta->sdata);
  233. struct ieee80211_link_data *link =
  234. sdata_dereference(sta->sdata->link[pub_link_sta->link_id],
  235. sta->sdata);
  236. struct ieee80211_chanctx_conf *conf;
  237. struct ieee80211_chanctx *chanctx;
  238. bool ret;
  239. if (WARN_ON(!link || !link_sta || link_sta->pub != pub_link_sta))
  240. return false;
  241. conf = sdata_dereference(link->conf->chanctx_conf, sta->sdata);
  242. if (WARN_ON(!conf))
  243. return false;
  244. trace_api_prepare_rx_omi_bw(local, sta->sdata, link_sta, bw);
  245. chanctx = container_of(conf, typeof(*chanctx), conf);
  246. if (link_sta->rx_omi_bw_staging == bw) {
  247. ret = false;
  248. goto trace;
  249. }
  250. /* must call this API in pairs */
  251. if (WARN_ON(link_sta->rx_omi_bw_tx != link_sta->rx_omi_bw_staging ||
  252. link_sta->rx_omi_bw_rx != link_sta->rx_omi_bw_staging)) {
  253. ret = false;
  254. goto trace;
  255. }
  256. if (bw < link_sta->rx_omi_bw_staging) {
  257. link_sta->rx_omi_bw_tx = bw;
  258. ieee80211_link_sta_rc_update_omi(link, link_sta);
  259. } else {
  260. link_sta->rx_omi_bw_rx = bw;
  261. ieee80211_recalc_chanctx_min_def(local, chanctx);
  262. }
  263. link_sta->rx_omi_bw_staging = bw;
  264. ret = true;
  265. trace:
  266. trace_api_return_bool(local, ret);
  267. return ret;
  268. }
  269. EXPORT_SYMBOL_GPL(ieee80211_prepare_rx_omi_bw);
  270. void ieee80211_finalize_rx_omi_bw(struct ieee80211_link_sta *pub_link_sta)
  271. {
  272. struct sta_info *sta = container_of(pub_link_sta->sta,
  273. struct sta_info, sta);
  274. struct ieee80211_local *local = sta->sdata->local;
  275. struct link_sta_info *link_sta =
  276. sdata_dereference(sta->link[pub_link_sta->link_id], sta->sdata);
  277. struct ieee80211_link_data *link =
  278. sdata_dereference(sta->sdata->link[pub_link_sta->link_id],
  279. sta->sdata);
  280. struct ieee80211_chanctx_conf *conf;
  281. struct ieee80211_chanctx *chanctx;
  282. if (WARN_ON(!link || !link_sta || link_sta->pub != pub_link_sta))
  283. return;
  284. conf = sdata_dereference(link->conf->chanctx_conf, sta->sdata);
  285. if (WARN_ON(!conf))
  286. return;
  287. trace_api_finalize_rx_omi_bw(local, sta->sdata, link_sta);
  288. chanctx = container_of(conf, typeof(*chanctx), conf);
  289. if (link_sta->rx_omi_bw_tx != link_sta->rx_omi_bw_staging) {
  290. /* rate control in finalize only when widening bandwidth */
  291. WARN_ON(link_sta->rx_omi_bw_tx > link_sta->rx_omi_bw_staging);
  292. link_sta->rx_omi_bw_tx = link_sta->rx_omi_bw_staging;
  293. ieee80211_link_sta_rc_update_omi(link, link_sta);
  294. }
  295. if (link_sta->rx_omi_bw_rx != link_sta->rx_omi_bw_staging) {
  296. /* channel context in finalize only when narrowing bandwidth */
  297. WARN_ON(link_sta->rx_omi_bw_rx < link_sta->rx_omi_bw_staging);
  298. link_sta->rx_omi_bw_rx = link_sta->rx_omi_bw_staging;
  299. ieee80211_recalc_chanctx_min_def(local, chanctx);
  300. }
  301. trace_api_return_void(local);
  302. }
  303. EXPORT_SYMBOL_GPL(ieee80211_finalize_rx_omi_bw);