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