1 /*
2 * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for
6 * any purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
8 * copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /**
21 * DOC: wlan_hdd_he.c
22 *
23 * WLAN Host Device Driver file for 802.11ax (High Efficiency) support.
24 *
25 */
26
27 #include "wlan_hdd_main.h"
28 #include "wlan_hdd_he.h"
29 #include "osif_sync.h"
30 #include "wma_he.h"
31 #include "wlan_utility.h"
32 #include "wlan_mlme_ucfg_api.h"
33 #include "spatial_reuse_ucfg_api.h"
34 #include "cdp_txrx_host_stats.h"
35 #include "wlan_policy_mgr_i.h"
36 #include "wlan_objmgr_vdev_obj.h"
37 #include "wlan_hdd_object_manager.h"
38
39 const struct nla_policy
40 wlan_hdd_sr_policy[QCA_WLAN_VENDOR_ATTR_SR_MAX + 1] = {
41 [QCA_WLAN_VENDOR_ATTR_SR_OPERATION] = {.type = NLA_U8},
42 [QCA_WLAN_VENDOR_ATTR_SR_PARAMS] = {.type = NLA_NESTED},
43 [QCA_WLAN_VENDOR_ATTR_SR_STATS] = {.type = NLA_NESTED},
44 };
45
46 static const struct nla_policy
47 qca_wlan_vendor_srp_param_policy[QCA_WLAN_VENDOR_ATTR_SR_PARAMS_MAX + 1] = {
48 [QCA_WLAN_VENDOR_ATTR_SR_PARAMS_HESIGA_VAL15_ENABLE] = {
49 .type = NLA_FLAG},
50 [QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_DISALLOW] = {
51 .type = NLA_FLAG},
52 [QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MIN_OFFSET] = {
53 .type = NLA_U8},
54 [QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MAX_OFFSET] = {
55 .type = NLA_U8},
56 [QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_MAX_OFFSET] = {
57 .type = NLA_U8},
58 [QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_PD_THRESHOLD] = {
59 .type = NLA_S32},
60 [QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_PD_THRESHOLD] = {
61 .type = NLA_S32},
62 [QCA_WLAN_VENDOR_ATTR_SR_PARAMS_REASON_CODE] = {.type = NLA_U32},
63
64 };
65
hdd_update_tgt_he_cap(struct hdd_context * hdd_ctx,struct wma_tgt_cfg * cfg)66 void hdd_update_tgt_he_cap(struct hdd_context *hdd_ctx,
67 struct wma_tgt_cfg *cfg)
68 {
69 QDF_STATUS status;
70 tDot11fIEhe_cap he_cap_ini = {0};
71 uint8_t value = 0;
72
73 status = ucfg_mlme_cfg_get_vht_tx_bfee_ant_supp(hdd_ctx->psoc,
74 &value);
75 if (!QDF_IS_STATUS_SUCCESS(status))
76 hdd_err("unable to get tx_bfee_ant_supp");
77
78 he_cap_ini.bfee_sts_lt_80 = value;
79 sme_update_tgt_he_cap(hdd_ctx->mac_handle, cfg, &he_cap_ini);
80
81 ucfg_mlme_update_tgt_he_cap(hdd_ctx->psoc, cfg);
82 }
83
wlan_hdd_check_11ax_support(struct hdd_beacon_data * beacon,struct sap_config * config)84 void wlan_hdd_check_11ax_support(struct hdd_beacon_data *beacon,
85 struct sap_config *config)
86 {
87 const uint8_t *ie;
88
89 ie = wlan_get_ext_ie_ptr_from_ext_id(HE_CAP_OUI_TYPE, HE_CAP_OUI_SIZE,
90 beacon->tail, beacon->tail_len);
91 if (ie)
92 config->SapHw_mode = eCSR_DOT11_MODE_11ax;
93 }
94
hdd_update_he_cap_in_cfg(struct hdd_context * hdd_ctx)95 int hdd_update_he_cap_in_cfg(struct hdd_context *hdd_ctx)
96 {
97 uint32_t val;
98 uint32_t val1 = 0;
99 QDF_STATUS status;
100 int ret;
101 uint8_t enable_ul_ofdma, enable_ul_mimo;
102
103 status = ucfg_mlme_cfg_get_he_ul_mumimo(hdd_ctx->psoc, &val);
104 if (QDF_IS_STATUS_ERROR(status)) {
105 hdd_err("could not get CFG_HE_UL_MUMIMO");
106 return qdf_status_to_os_return(status);
107 }
108
109 /* In val,
110 * Bit 1 - corresponds to UL MIMO
111 * Bit 2 - corresponds to UL OFDMA
112 */
113 ret = ucfg_mlme_cfg_get_enable_ul_mimo(hdd_ctx->psoc,
114 &enable_ul_mimo);
115 if (ret)
116 return ret;
117 ret = ucfg_mlme_cfg_get_enable_ul_ofdm(hdd_ctx->psoc,
118 &enable_ul_ofdma);
119 if (ret)
120 return ret;
121 if (val & 0x1 || (val >> 1) & 0x1)
122 val1 = enable_ul_mimo & 0x1;
123
124 if ((val >> 1) & 0x1)
125 val1 |= ((enable_ul_ofdma & 0x1) << 1);
126
127 ret = ucfg_mlme_cfg_set_he_ul_mumimo(hdd_ctx->psoc, val1);
128
129 return ret;
130 }
131
132 /*
133 * __wlan_hdd_cfg80211_get_he_cap() - get HE Capabilities
134 * @wiphy: Pointer to wiphy
135 * @wdev: Pointer to wdev
136 * @data: Pointer to data
137 * @data_len: Data length
138 *
139 * Return: 0 if success, non-zero for failure
140 */
141 static int
__wlan_hdd_cfg80211_get_he_cap(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)142 __wlan_hdd_cfg80211_get_he_cap(struct wiphy *wiphy,
143 struct wireless_dev *wdev,
144 const void *data,
145 int data_len)
146 {
147 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
148 int ret;
149 QDF_STATUS status;
150 struct sk_buff *reply_skb;
151 uint32_t nl_buf_len;
152 struct he_capability he_cap;
153 uint8_t he_supported = 0;
154
155 hdd_enter();
156 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
157 hdd_err("Command not allowed in FTM mode");
158 return -EPERM;
159 }
160
161 ret = wlan_hdd_validate_context(hdd_ctx);
162 if (0 != ret)
163 return ret;
164
165 nl_buf_len = NLMSG_HDRLEN;
166 if (sme_is_feature_supported_by_fw(DOT11AX)) {
167 he_supported = 1;
168
169 status = wma_get_he_capabilities(&he_cap);
170 if (QDF_STATUS_SUCCESS != status)
171 return -EINVAL;
172 } else {
173 hdd_info("11AX: HE not supported, send only QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED");
174 }
175
176 if (he_supported) {
177 nl_buf_len += NLA_HDRLEN + sizeof(he_supported) +
178 NLA_HDRLEN + sizeof(he_cap.phy_cap) +
179 NLA_HDRLEN + sizeof(he_cap.mac_cap) +
180 NLA_HDRLEN + sizeof(he_cap.mcs) +
181 NLA_HDRLEN + sizeof(he_cap.ppet.numss_m1) +
182 NLA_HDRLEN + sizeof(he_cap.ppet.ru_bit_mask) +
183 NLA_HDRLEN +
184 sizeof(he_cap.ppet.ppet16_ppet8_ru3_ru0);
185 } else {
186 nl_buf_len += NLA_HDRLEN + sizeof(he_supported);
187 }
188
189 hdd_info("11AX: he_supported: %d", he_supported);
190
191 reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, nl_buf_len);
192 if (!reply_skb) {
193 hdd_err("Allocate reply_skb failed");
194 return -EINVAL;
195 }
196
197 if (nla_put_u8(reply_skb,
198 QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED, he_supported))
199 goto nla_put_failure;
200
201 /* No need to populate other attributes if HE is not supported */
202 if (0 == he_supported)
203 goto end;
204
205 if (nla_put_u32(reply_skb,
206 QCA_WLAN_VENDOR_ATTR_MAC_CAPAB, he_cap.mac_cap) ||
207 nla_put_u32(reply_skb,
208 QCA_WLAN_VENDOR_ATTR_HE_MCS, he_cap.mcs) ||
209 nla_put_u32(reply_skb,
210 QCA_WLAN_VENDOR_ATTR_NUM_SS, he_cap.ppet.numss_m1) ||
211 nla_put_u32(reply_skb,
212 QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK,
213 he_cap.ppet.ru_bit_mask) ||
214 nla_put(reply_skb,
215 QCA_WLAN_VENDOR_ATTR_PHY_CAPAB,
216 sizeof(u32) * HE_MAX_PHY_CAP_SIZE, he_cap.phy_cap) ||
217 nla_put(reply_skb, QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD,
218 sizeof(u32) * PSOC_HOST_MAX_NUM_SS,
219 he_cap.ppet.ppet16_ppet8_ru3_ru0))
220 goto nla_put_failure;
221 end:
222 ret = wlan_cfg80211_vendor_cmd_reply(reply_skb);
223 hdd_exit();
224 return ret;
225
226 nla_put_failure:
227 hdd_err("nla put fail");
228 wlan_cfg80211_vendor_free_skb(reply_skb);
229 return -EINVAL;
230 }
231
wlan_hdd_cfg80211_get_he_cap(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)232 int wlan_hdd_cfg80211_get_he_cap(struct wiphy *wiphy,
233 struct wireless_dev *wdev,
234 const void *data,
235 int data_len)
236 {
237 struct osif_psoc_sync *psoc_sync;
238 int errno;
239
240 errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync);
241 if (errno)
242 return errno;
243
244 errno = __wlan_hdd_cfg80211_get_he_cap(wiphy, wdev, data, data_len);
245
246 osif_psoc_sync_op_stop(psoc_sync);
247
248 return errno;
249 }
250
251 #ifdef WLAN_FEATURE_SR
252 static QDF_STATUS
hdd_sr_event_convert_reason_code(enum sr_osif_reason_code sr_osif_rc,enum qca_wlan_sr_reason_code * sr_nl_rc)253 hdd_sr_event_convert_reason_code(enum sr_osif_reason_code sr_osif_rc,
254 enum qca_wlan_sr_reason_code *sr_nl_rc)
255 {
256 QDF_STATUS status = QDF_STATUS_SUCCESS;
257
258 switch (sr_osif_rc) {
259 case SR_REASON_CODE_ROAMING:
260 *sr_nl_rc = QCA_WLAN_SR_REASON_CODE_ROAMING;
261 break;
262 case SR_REASON_CODE_CONCURRENCY:
263 *sr_nl_rc = QCA_WLAN_SR_REASON_CODE_CONCURRENCY;
264 break;
265 default:
266 status = QDF_STATUS_E_INVAL;
267 }
268
269 return status;
270 }
271
272 static QDF_STATUS
hdd_sr_event_convert_operation(enum sr_osif_operation sr_osif_oper,enum qca_wlan_sr_operation * sr_nl_oper)273 hdd_sr_event_convert_operation(enum sr_osif_operation sr_osif_oper,
274 enum qca_wlan_sr_operation *sr_nl_oper)
275 {
276 QDF_STATUS status = QDF_STATUS_SUCCESS;
277
278 switch (sr_osif_oper) {
279 case SR_OPERATION_SUSPEND:
280 *sr_nl_oper = QCA_WLAN_SR_OPERATION_SR_SUSPEND;
281 break;
282 case SR_OPERATION_RESUME:
283 *sr_nl_oper = QCA_WLAN_SR_OPERATION_SR_RESUME;
284 break;
285 case SR_OPERATION_UPDATE_PARAMS:
286 *sr_nl_oper = QCA_WLAN_SR_OPERATION_UPDATE_PARAMS;
287 break;
288 default:
289 status = QDF_STATUS_E_INVAL;
290 }
291
292 return status;
293 }
294
hdd_sr_pack_suspend_resume_event(struct sk_buff * skb,enum qca_wlan_sr_operation sr_nl_oper,enum qca_wlan_sr_reason_code sr_nl_rc,uint8_t srg_max_pd_offset,uint8_t srg_min_pd_offset,uint8_t non_srg_max_pd_offset)295 static QDF_STATUS hdd_sr_pack_suspend_resume_event(
296 struct sk_buff *skb,
297 enum qca_wlan_sr_operation sr_nl_oper,
298 enum qca_wlan_sr_reason_code sr_nl_rc,
299 uint8_t srg_max_pd_offset,
300 uint8_t srg_min_pd_offset,
301 uint8_t non_srg_max_pd_offset)
302 {
303 struct nlattr *attr;
304 QDF_STATUS status = QDF_STATUS_E_FAULT;
305
306 if (((sr_nl_rc != QCA_WLAN_SR_REASON_CODE_CONCURRENCY) &&
307 (sr_nl_rc != QCA_WLAN_SR_REASON_CODE_ROAMING)) ||
308 ((sr_nl_oper != QCA_WLAN_SR_OPERATION_SR_SUSPEND) &&
309 (sr_nl_oper != QCA_WLAN_SR_OPERATION_SR_RESUME))) {
310 hdd_err("SR operation is invalid");
311 status = QDF_STATUS_E_INVAL;
312 goto sr_events_end;
313 }
314
315 if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_SR_OPERATION, sr_nl_oper)) {
316 hdd_err("failed to put attr SR Operation");
317 goto sr_events_end;
318 }
319
320 attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_SR_PARAMS);
321 if (!attr) {
322 hdd_err("nesting failed");
323 goto sr_events_end;
324 }
325
326 if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_SR_PARAMS_REASON_CODE,
327 sr_nl_rc)) {
328 hdd_err("failed to put attr SR Reascon Code");
329 goto sr_events_end;
330 }
331 if (sr_nl_rc == QCA_WLAN_SR_REASON_CODE_ROAMING &&
332 sr_nl_oper == QCA_WLAN_SR_OPERATION_SR_RESUME) {
333 if (nla_put_u32(
334 skb,
335 QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MIN_OFFSET,
336 srg_min_pd_offset)) {
337 hdd_err("srg_pd_min_offset put fail");
338 goto sr_events_end;
339 }
340 if (nla_put_u32(
341 skb,
342 QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MAX_OFFSET,
343 srg_max_pd_offset)) {
344 hdd_err("srg_pd_min_offset put fail");
345 goto sr_events_end;
346 }
347 if (nla_put_u32(
348 skb,
349 QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_MAX_OFFSET,
350 non_srg_max_pd_offset)) {
351 hdd_err("non_srg_pd_offset put fail");
352 goto sr_events_end;
353 }
354 }
355 status = QDF_STATUS_SUCCESS;
356 nla_nest_end(skb, attr);
357
358 sr_events_end:
359 return status;
360 }
361
hdd_sr_osif_events(struct wlan_objmgr_vdev * vdev,enum sr_osif_operation sr_osif_oper,enum sr_osif_reason_code sr_osif_rc)362 static void hdd_sr_osif_events(struct wlan_objmgr_vdev *vdev,
363 enum sr_osif_operation sr_osif_oper,
364 enum sr_osif_reason_code sr_osif_rc)
365 {
366 struct hdd_adapter *adapter;
367 struct wireless_dev *wdev;
368 struct wiphy *wiphy;
369 struct sk_buff *skb;
370 uint32_t idx = QCA_NL80211_VENDOR_SUBCMD_SR_INDEX;
371 uint32_t len = NLMSG_HDRLEN;
372 uint8_t non_srg_max_pd_offset = 0;
373 uint8_t srg_max_pd_offset = 0;
374 uint8_t srg_min_pd_offset = 0;
375 QDF_STATUS status;
376 enum qca_wlan_sr_operation sr_nl_oper;
377 enum qca_wlan_sr_reason_code sr_nl_rc;
378 struct wlan_hdd_link_info *link_info;
379
380 if (!vdev) {
381 hdd_err("Null VDEV");
382 return;
383 }
384
385 link_info = wlan_hdd_get_link_info_from_objmgr(vdev);
386 if (!link_info) {
387 hdd_err("Null adapter");
388 return;
389 }
390
391 adapter = link_info->adapter;
392 wlan_vdev_mlme_get_srg_pd_offset(vdev, &srg_max_pd_offset,
393 &srg_min_pd_offset);
394 non_srg_max_pd_offset = wlan_vdev_mlme_get_non_srg_pd_offset(vdev);
395 status = hdd_sr_event_convert_operation(sr_osif_oper, &sr_nl_oper);
396 if (QDF_IS_STATUS_ERROR(status)) {
397 hdd_err("Invalid SR Operation: %d", sr_osif_oper);
398 return;
399 }
400 status = hdd_sr_event_convert_reason_code(sr_osif_rc, &sr_nl_rc);
401 if (QDF_IS_STATUS_ERROR(status)) {
402 hdd_err("Invalid SR Reason Code: %d", sr_osif_rc);
403 return;
404 }
405
406 hdd_debug("SR Operation: %u SR Reason Code: %u",
407 sr_nl_oper, sr_nl_rc);
408 switch (sr_nl_oper) {
409 case QCA_WLAN_SR_OPERATION_SR_SUSPEND:
410 case QCA_WLAN_SR_OPERATION_SR_RESUME:
411 if (sr_nl_rc == QCA_WLAN_SR_REASON_CODE_CONCURRENCY ||
412 sr_nl_rc == QCA_WLAN_SR_REASON_CODE_ROAMING) {
413 wiphy = adapter->hdd_ctx->wiphy;
414 wdev = &adapter->wdev;
415 /* QCA_WLAN_VENDOR_ATTR_SR_OPERATION */
416 len += nla_total_size(sizeof(uint8_t));
417 /* QCA_WLAN_VENDOR_ATTR_SR_PARAMS_REASON_CODE */
418 len += nla_total_size(sizeof(uint32_t));
419 /* QCA_WLAN_VENDOR_ATTR_SR_PARAMS */
420 len += nla_total_size(0);
421 /*
422 * In case of resume due to roaming additional config
423 * params are required to be sent.
424 */
425 if (sr_nl_rc == QCA_WLAN_SR_REASON_CODE_ROAMING &&
426 sr_nl_oper == QCA_WLAN_SR_OPERATION_SR_RESUME) {
427 /* SR_PARAMS_SRG_OBSS_PD_MIN_OFFSET */
428 len += nla_total_size(sizeof(int32_t));
429 /* SR_PARAMS_SRG_OBSS_PD_MAX_OFFSET */
430 len += nla_total_size(sizeof(int32_t));
431 /* SR_PARAMS_NON_SRG_OBSS_PD_MAX_OFFSET */
432 len += nla_total_size(sizeof(int32_t));
433 }
434 skb = wlan_cfg80211_vendor_event_alloc(wiphy, wdev,
435 len, idx,
436 GFP_KERNEL);
437 if (!skb) {
438 hdd_err("wlan_cfg80211_vendor_event_alloc failed");
439 return;
440 }
441 status = hdd_sr_pack_suspend_resume_event(
442 skb, sr_nl_oper, sr_nl_rc,
443 srg_max_pd_offset, srg_min_pd_offset,
444 non_srg_max_pd_offset);
445 if (QDF_IS_STATUS_ERROR(status)) {
446 wlan_cfg80211_vendor_free_skb(skb);
447 return;
448 }
449
450 wlan_cfg80211_vendor_event(skb, GFP_KERNEL);
451 hdd_debug("SR cfg80211 event is sent");
452 } else {
453 hdd_debug("SR Reason code not supported");
454 }
455 break;
456 default:
457 hdd_debug("SR Operation not supported");
458 break;
459 }
460 }
461
hdd_sr_register_callbacks(struct hdd_context * hdd_ctx)462 void hdd_sr_register_callbacks(struct hdd_context *hdd_ctx)
463 {
464 ucfg_spatial_reuse_register_cb(hdd_ctx->psoc, hdd_sr_osif_events);
465 }
466
hdd_get_srp_stats_len(void)467 static int hdd_get_srp_stats_len(void)
468 {
469 struct cdp_pdev_obss_pd_stats_tlv stats;
470 uint32_t len = NLMSG_HDRLEN;
471
472 len += nla_total_size(sizeof(stats.num_srg_ppdu_success)) +
473 nla_total_size(sizeof(stats.num_srg_ppdu_tried)) +
474 nla_total_size(sizeof(stats.num_srg_opportunities)) +
475 nla_total_size(sizeof(stats.num_non_srg_ppdu_success)) +
476 nla_total_size(sizeof(stats.num_non_srg_ppdu_tried)) +
477 nla_total_size(sizeof(stats.num_non_srg_opportunities));
478
479 return len;
480 }
481
hdd_get_srp_param_len(void)482 static int hdd_get_srp_param_len(void)
483 {
484 uint32_t len = NLMSG_HDRLEN;
485
486 len += nla_total_size(sizeof(bool)) +
487 nla_total_size(sizeof(bool))+
488 nla_total_size(sizeof(uint8_t))+
489 nla_total_size(sizeof(uint8_t))+
490 nla_total_size(sizeof(uint8_t));
491
492 return len;
493 }
494
495 static int
hdd_add_param_info(struct sk_buff * skb,uint8_t srg_max_pd_offset,uint8_t srg_min_pd_offset,uint8_t non_srg_pd_offset,uint8_t sr_ctrl,int idx)496 hdd_add_param_info(struct sk_buff *skb, uint8_t srg_max_pd_offset,
497 uint8_t srg_min_pd_offset, uint8_t non_srg_pd_offset,
498 uint8_t sr_ctrl, int idx)
499 {
500 struct nlattr *nla_attr;
501 bool non_srg_obss_pd_disallow = sr_ctrl & NON_SRG_PD_SR_DISALLOWED;
502 bool hesega_val_15_enable = sr_ctrl & HE_SIG_VAL_15_ALLOWED;
503
504 nla_attr = nla_nest_start(skb, idx);
505 if (!nla_attr)
506 goto fail;
507 hdd_debug("SR params of connected AP srg_max_pd_offset %d srg_min_pd_offset %d non_srg_pd_offset %d non_srg_obss_pd_disallow %d hesega_val_15_enable %d",
508 srg_max_pd_offset, srg_min_pd_offset, non_srg_pd_offset,
509 non_srg_obss_pd_disallow, hesega_val_15_enable);
510
511 if (nla_put_u32(skb,
512 QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MIN_OFFSET,
513 srg_min_pd_offset)) {
514 hdd_err("srg_pd_min_offset put fail");
515 goto fail;
516 }
517 if (nla_put_u32(skb,
518 QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MAX_OFFSET,
519 srg_max_pd_offset)) {
520 hdd_err("srg_pd_min_offset put fail");
521 goto fail;
522 }
523 if (nla_put_u32(
524 skb,
525 QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_MAX_OFFSET,
526 non_srg_pd_offset)) {
527 hdd_err("non_srg_pd_offset put fail");
528 goto fail;
529 }
530 if (non_srg_obss_pd_disallow && nla_put_flag(
531 skb,
532 QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_DISALLOW)) {
533 hdd_err("non_srg_obss_pd_disallow put fail or enabled");
534 goto fail;
535 }
536 if (hesega_val_15_enable && nla_put_flag(
537 skb,
538 QCA_WLAN_VENDOR_ATTR_SR_PARAMS_HESIGA_VAL15_ENABLE)) {
539 hdd_err("hesega_val_15_enable put fail or disabled");
540 goto fail;
541 }
542
543 nla_nest_end(skb, nla_attr);
544 return 0;
545 fail:
546 return -EINVAL;
547 }
548 static int
hdd_add_stats_info(struct sk_buff * skb,struct cdp_pdev_obss_pd_stats_tlv * stats)549 hdd_add_stats_info(struct sk_buff *skb,
550 struct cdp_pdev_obss_pd_stats_tlv *stats)
551 {
552 struct nlattr *nla_attr;
553
554 nla_attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_SR_STATS);
555 if (!nla_attr)
556 goto fail;
557
558 hdd_debug("SR stats - srg: ppdu_success %d tried %d opportunities %d non-srg: ppdu_success %d tried %d opportunities %d",
559 stats->num_srg_ppdu_success, stats->num_srg_ppdu_tried,
560 stats->num_srg_opportunities, stats->num_non_srg_ppdu_success,
561 stats->num_non_srg_ppdu_tried,
562 stats->num_non_srg_opportunities);
563 if (nla_put_u32(skb,
564 QCA_WLAN_VENDOR_ATTR_SR_STATS_SRG_TX_PPDU_SUCCESS_COUNT,
565 stats->num_srg_ppdu_success)) {
566 hdd_err("num_srg_ppdu_success put fail");
567 goto fail;
568 }
569 if (nla_put_u32(skb,
570 QCA_WLAN_VENDOR_ATTR_SR_STATS_SRG_TX_PPDU_TRIED_COUNT,
571 stats->num_srg_ppdu_tried)) {
572 hdd_err("num_srg_ppdu_tried put fail");
573 goto fail;
574 }
575 if (nla_put_u32(
576 skb,
577 QCA_WLAN_VENDOR_ATTR_SR_STATS_SRG_TX_OPPORTUNITIES_COUNT,
578 stats->num_srg_opportunities)) {
579 hdd_err("num_srg_opportunities put fail");
580 goto fail;
581 }
582 if (nla_put_u32(
583 skb,
584 QCA_WLAN_VENDOR_ATTR_SR_STATS_NON_SRG_TX_PPDU_SUCCESS_COUNT,
585 stats->num_non_srg_ppdu_success)) {
586 hdd_err("num_non_srg_ppdu_success put fail");
587 goto fail;
588 }
589 if (nla_put_u32(
590 skb,
591 QCA_WLAN_VENDOR_ATTR_SR_STATS_NON_SRG_TX_PPDU_TRIED_COUNT,
592 stats->num_non_srg_ppdu_tried)) {
593 hdd_err("num_non_srg_ppdu_tried put fail");
594 goto fail;
595 }
596 if (nla_put_u32(
597 skb,
598 QCA_WLAN_VENDOR_ATTR_SR_STATS_NON_SRG_TX_OPPORTUNITIES_COUNT,
599 stats->num_non_srg_opportunities)) {
600 hdd_err("num_non_srg_opportunities put fail");
601 goto fail;
602 }
603 nla_nest_end(skb, nla_attr);
604 return 0;
605 fail:
606 return -EINVAL;
607 }
608
hdd_get_sr_stats(struct hdd_context * hdd_ctx,uint8_t mac_id,struct cdp_pdev_obss_pd_stats_tlv * stats)609 static int hdd_get_sr_stats(struct hdd_context *hdd_ctx, uint8_t mac_id,
610 struct cdp_pdev_obss_pd_stats_tlv *stats)
611 {
612 ol_txrx_soc_handle soc;
613 uint8_t pdev_id;
614 struct cdp_txrx_stats_req req = {0};
615
616 soc = cds_get_context(QDF_MODULE_ID_SOC);
617 if (!soc) {
618 hdd_err("invalid soc");
619 return -EINVAL;
620 }
621
622 req.mac_id = mac_id;
623 pdev_id = wlan_objmgr_pdev_get_pdev_id(hdd_ctx->pdev);
624 cdp_get_pdev_obss_pd_stats(soc, pdev_id, stats, &req);
625 if (!stats) {
626 hdd_err("invalid stats");
627 return -EINVAL;
628 }
629 return 0;
630 }
631
hdd_clear_sr_stats(struct hdd_context * hdd_ctx,uint8_t mac_id)632 static int hdd_clear_sr_stats(struct hdd_context *hdd_ctx, uint8_t mac_id)
633 {
634 QDF_STATUS status;
635 ol_txrx_soc_handle soc;
636 uint8_t pdev_id;
637 struct cdp_txrx_stats_req req = {0};
638
639 soc = cds_get_context(QDF_MODULE_ID_SOC);
640 if (!soc) {
641 hdd_err("invalid soc");
642 return -EINVAL;
643 }
644
645 req.mac_id = mac_id;
646 pdev_id = wlan_objmgr_pdev_get_pdev_id(hdd_ctx->pdev);
647 status = cdp_clear_pdev_obss_pd_stats(soc, pdev_id, &req);
648 if (QDF_IS_STATUS_ERROR(status)) {
649 hdd_err("Unable to clear stats");
650 return -EAGAIN;
651 }
652 return 0;
653 }
654
655 /**
656 * hdd_check_mode_support_for_sr: Check if SR allowed or not
657 * @adapter: hdd adapter
658 * @sr_ctrl: sr ctrl ie
659 *
660 * Return: true if provided mode supports SR else flase
661 */
hdd_check_mode_support_for_sr(struct hdd_adapter * adapter,uint8_t sr_ctrl)662 static bool hdd_check_mode_support_for_sr(struct hdd_adapter *adapter,
663 uint8_t sr_ctrl)
664 {
665 if ((adapter->device_mode == QDF_STA_MODE) &&
666 (!hdd_cm_is_vdev_connected(adapter->deflink) ||
667 ((sr_ctrl & NON_SRG_PD_SR_DISALLOWED) &&
668 !(sr_ctrl & SRG_INFO_PRESENT)))) {
669 hdd_err("mode %d doesn't supports SR", adapter->device_mode);
670 return false;
671 }
672 return true;
673 }
674
675 /**
676 * __wlan_hdd_cfg80211_sr_operations: To handle SR operation
677 *
678 * @wiphy: wiphy structure
679 * @wdev: wireless dev
680 * @data: vendor command data
681 * @data_len: data len
682 *
683 * return: success/failure code
684 */
__wlan_hdd_cfg80211_sr_operations(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)685 static int __wlan_hdd_cfg80211_sr_operations(struct wiphy *wiphy,
686 struct wireless_dev *wdev,
687 const void *data, int data_len)
688 {
689 QDF_STATUS status;
690 uint32_t id;
691 bool is_sr_enable = false;
692 int32_t srg_pd_threshold = 0;
693 int32_t non_srg_pd_threshold = 0;
694 uint8_t sr_he_siga_val15_allowed = true;
695 uint8_t mac_id, sr_ctrl, non_srg_max_pd_offset;
696 uint8_t srg_min_pd_offset = 0, srg_max_pd_offset = 0;
697 uint32_t nl_buf_len;
698 int ret;
699 struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
700 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev);
701 struct wlan_objmgr_vdev *vdev;
702 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SR_MAX + 1];
703 struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_SR_PARAMS_MAX + 1] = {0};
704 enum qca_wlan_sr_operation sr_oper;
705 struct nlattr *sr_oper_attr;
706 struct nlattr *sr_param_attr;
707 struct sk_buff *skb;
708 struct cdp_pdev_obss_pd_stats_tlv stats;
709 uint8_t sr_device_modes;
710
711 hdd_enter_dev(wdev->netdev);
712
713 ret = wlan_hdd_validate_context(hdd_ctx);
714 if (ret)
715 return ret;
716
717 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam() ||
718 QDF_GLOBAL_MONITOR_MODE == hdd_get_conparam()) {
719 hdd_err("Command not allowed in FTM or Monitor mode");
720 return -EPERM;
721 }
722
723 vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink,
724 WLAN_HDD_ID_OBJ_MGR);
725 if (!vdev) {
726 hdd_err("Null VDEV");
727 return -EINVAL;
728 }
729 /**
730 * Reject command if SR concurrency is not allowed and
731 * only STA mode is set in ini to enable SR.
732 **/
733 ucfg_mlme_get_sr_enable_modes(hdd_ctx->psoc, &sr_device_modes);
734 if (!(sr_device_modes & (1 << adapter->device_mode))) {
735 hdd_debug("SR operation not allowed for mode %d",
736 adapter->device_mode);
737 ret = -EINVAL;
738 goto exit;
739 }
740
741 if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
742 hdd_err("Driver Modules are closed");
743 ret = -EINVAL;
744 goto exit;
745 }
746 if (!sme_is_feature_supported_by_fw(DOT11AX)) {
747 hdd_err("11AX is not supported");
748 ret = -EINVAL;
749 goto exit;
750 }
751 status = ucfg_spatial_reuse_operation_allowed(hdd_ctx->psoc, vdev);
752 if (QDF_IS_STATUS_ERROR(status)) {
753 hdd_err("SR operations not allowed status: %u", status);
754 hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR);
755 return qdf_status_to_os_return(status);
756 }
757 if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SR_MAX, data,
758 data_len, wlan_hdd_sr_policy)) {
759 hdd_err("invalid attr");
760 ret = -EINVAL;
761 goto exit;
762 }
763
764 id = QCA_WLAN_VENDOR_ATTR_SR_OPERATION;
765 sr_oper_attr = tb[id];
766 if (!sr_oper_attr) {
767 hdd_err("SR operation not specified");
768 ret = -EINVAL;
769 goto exit;
770 }
771
772 sr_oper = nla_get_u8(sr_oper_attr);
773 hdd_debug("SR Operation 0x%x", sr_oper);
774
775 ucfg_spatial_reuse_get_sr_config(vdev, &sr_ctrl, &non_srg_max_pd_offset,
776 &is_sr_enable);
777
778 if (!hdd_check_mode_support_for_sr(adapter, sr_ctrl) &&
779 (sr_oper != QCA_WLAN_SR_OPERATION_GET_PARAMS)) {
780 hdd_err("SR operation not allowed, sr_ctrl = %x, mode = %d",
781 sr_ctrl, adapter->device_mode);
782 ret = -EINVAL;
783 goto exit;
784 }
785
786 if (sr_oper != QCA_WLAN_SR_OPERATION_SR_ENABLE && !is_sr_enable) {
787 hdd_err("SR operation not allowed");
788 ret = -EINVAL;
789 goto exit;
790 }
791
792 id = QCA_WLAN_VENDOR_ATTR_SR_PARAMS;
793 sr_param_attr = tb[id];
794 if (sr_param_attr) {
795 ret = wlan_cfg80211_nla_parse_nested(
796 tb2, QCA_WLAN_VENDOR_ATTR_SR_PARAMS_MAX,
797 sr_param_attr,
798 qca_wlan_vendor_srp_param_policy);
799 if (ret) {
800 hdd_err("sr_param_attr parse failed");
801 goto exit;
802 }
803 }
804 switch (sr_oper) {
805 case QCA_WLAN_SR_OPERATION_SR_ENABLE:
806 case QCA_WLAN_SR_OPERATION_SR_DISABLE:
807 if (sr_oper == QCA_WLAN_SR_OPERATION_SR_ENABLE) {
808 is_sr_enable = true;
809 } else {
810 is_sr_enable = false;
811 if (!wlan_vdev_mlme_get_he_spr_enabled(vdev)) {
812 hdd_debug("SR not enabled, reject disable command");
813 ret = -EINVAL;
814 goto exit;
815 }
816 }
817 /**
818 * As per currenct implementation from userspace same
819 * PD threshold value is configured for both SRG and
820 * NON-SRG and fw will decide further based on BSS color
821 * So only SRG param is parsed and set as pd threshold
822 */
823 if (is_sr_enable &&
824 tb2[QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_PD_THRESHOLD]) {
825 srg_pd_threshold =
826 nla_get_s32(
827 tb2[QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_PD_THRESHOLD]);
828 wlan_vdev_mlme_set_pd_threshold_present(vdev, true);
829 }
830
831 if (is_sr_enable &&
832 tb2[QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_PD_THRESHOLD]) {
833 non_srg_pd_threshold =
834 nla_get_s32(
835 tb2[QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_PD_THRESHOLD]
836 );
837 wlan_vdev_mlme_set_pd_threshold_present(vdev, true);
838 }
839
840 hdd_debug("setting sr enable %d with pd threshold srg: %d non srg: %d",
841 is_sr_enable, srg_pd_threshold, non_srg_pd_threshold);
842 /* Set the variables */
843 ucfg_spatial_reuse_set_sr_enable(vdev, is_sr_enable);
844 status = ucfg_spatial_reuse_setup_req(vdev, hdd_ctx->pdev,
845 is_sr_enable,
846 srg_pd_threshold,
847 non_srg_pd_threshold);
848 if (status != QDF_STATUS_SUCCESS) {
849 hdd_err("failed to enable Spatial Reuse feature");
850 ret = -EINVAL;
851 goto exit;
852 }
853
854 break;
855 case QCA_WLAN_SR_OPERATION_GET_STATS:
856 status = policy_mgr_get_mac_id_by_session_id(
857 hdd_ctx->psoc,
858 adapter->deflink->vdev_id,
859 &mac_id);
860 if (QDF_IS_STATUS_ERROR(status)) {
861 hdd_err("Failed to get mac_id for vdev_id: %u",
862 adapter->deflink->vdev_id); {
863 ret = -EAGAIN;
864 goto exit;
865 }
866 }
867 if (hdd_get_sr_stats(hdd_ctx, mac_id, &stats)) {
868 ret = -EINVAL;
869 goto exit;
870 }
871 nl_buf_len = hdd_get_srp_stats_len();
872 skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
873 nl_buf_len);
874 if (!skb) {
875 hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
876 ret = -ENOMEM;
877 goto exit;
878 }
879 if (hdd_add_stats_info(skb, &stats)) {
880 wlan_cfg80211_vendor_free_skb(skb);
881 ret = -EINVAL;
882 goto exit;
883 }
884
885 ret = wlan_cfg80211_vendor_cmd_reply(skb);
886 break;
887 case QCA_WLAN_SR_OPERATION_CLEAR_STATS:
888 status = policy_mgr_get_mac_id_by_session_id(
889 hdd_ctx->psoc,
890 adapter->deflink->vdev_id,
891 &mac_id);
892 if (QDF_IS_STATUS_ERROR(status)) {
893 hdd_err("Failed to get mac_id for vdev_id: %u",
894 adapter->deflink->vdev_id);
895 ret = -EAGAIN;
896 goto exit;
897 }
898 if (hdd_clear_sr_stats(hdd_ctx, mac_id)) {
899 ret = -EAGAIN;
900 goto exit;
901 }
902 break;
903 case QCA_WLAN_SR_OPERATION_PSR_AND_NON_SRG_OBSS_PD_PROHIBIT:
904 if (tb2[QCA_WLAN_VENDOR_ATTR_SR_PARAMS_HESIGA_VAL15_ENABLE])
905 sr_he_siga_val15_allowed = nla_get_u8(
906 tb2[QCA_WLAN_VENDOR_ATTR_SR_PARAMS_HESIGA_VAL15_ENABLE]
907 );
908 if (!sr_he_siga_val15_allowed) {
909 hdd_err("invalid sr_he_siga_val15_enable param");
910 ret = -EINVAL;
911 goto exit;
912 }
913 if (!QDF_IS_STATUS_SUCCESS(ucfg_spatial_reuse_send_sr_prohibit(
914 vdev, sr_he_siga_val15_allowed))) {
915 hdd_debug("Prohibit command can not be sent");
916 ret = -EINVAL;
917 goto exit;
918 }
919 break;
920 case QCA_WLAN_SR_OPERATION_PSR_AND_NON_SRG_OBSS_PD_ALLOW:
921 if (!QDF_IS_STATUS_SUCCESS(ucfg_spatial_reuse_send_sr_prohibit(
922 vdev, false))) {
923 hdd_debug("Prohibit command can not be sent");
924 ret = -EINVAL;
925 goto exit;
926 }
927 break;
928 case QCA_WLAN_SR_OPERATION_GET_PARAMS:
929 wlan_vdev_mlme_get_srg_pd_offset(vdev, &srg_max_pd_offset,
930 &srg_min_pd_offset);
931 non_srg_max_pd_offset =
932 wlan_vdev_mlme_get_non_srg_pd_offset(vdev);
933 sr_ctrl = wlan_vdev_mlme_get_sr_ctrl(vdev);
934 nl_buf_len = hdd_get_srp_param_len();
935 skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
936 nl_buf_len);
937 if (!skb) {
938 hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
939 ret = -ENOMEM;
940 goto exit;
941 }
942 if (hdd_add_param_info(skb, srg_max_pd_offset,
943 srg_min_pd_offset, non_srg_max_pd_offset,
944 sr_ctrl,
945 QCA_WLAN_VENDOR_ATTR_SR_PARAMS)) {
946 wlan_cfg80211_vendor_free_skb(skb);
947 ret = -EINVAL;
948 goto exit;
949 }
950
951 ret = wlan_cfg80211_vendor_cmd_reply(skb);
952 break;
953 default:
954 hdd_err("Invalid SR Operation");
955 ret = -EINVAL;
956 break;
957 }
958
959 hdd_exit();
960 exit:
961 hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR);
962 return ret;
963 }
964
wlan_hdd_cfg80211_sr_operations(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)965 int wlan_hdd_cfg80211_sr_operations(struct wiphy *wiphy,
966 struct wireless_dev *wdev,
967 const void *data, int data_len)
968 {
969 struct osif_psoc_sync *psoc_sync;
970 int errno;
971
972 errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync);
973 if (errno)
974 return errno;
975
976 errno = __wlan_hdd_cfg80211_sr_operations(wiphy, wdev, data, data_len);
977
978 osif_psoc_sync_op_stop(psoc_sync);
979
980 return errno;
981 }
982 #endif
983