xref: /wlan-dirver/qca-wifi-host-cmn/os_if/linux/spectral/src/wlan_cfg80211_spectral.c (revision 11f5a63a6cbdda84849a730de22f0a71e635d58c)
1 /*
2  * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /**
20  * DOC: defines driver functions interfacing with linux kernel
21  */
22 
23 #include <qdf_list.h>
24 #include <qdf_status.h>
25 #include <linux/wireless.h>
26 #include <linux/netdevice.h>
27 #include <net/cfg80211.h>
28 #include <wlan_cfg80211.h>
29 #include <wlan_osif_priv.h>
30 #include <qdf_mem.h>
31 #include <wlan_spectral_ucfg_api.h>
32 #include <wlan_cfg80211_spectral.h>
33 #include <spectral_ioctl.h>
34 #include "qal_devcfg.h"
35 
36 static const struct nla_policy spectral_scan_policy[
37 		QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX + 1] = {
38 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SCAN_COUNT] = {
39 							.type = NLA_U32},
40 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SCAN_PERIOD] = {
41 							.type = NLA_U32},
42 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_PRIORITY] = {
43 							.type = NLA_U32},
44 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_SIZE] = {
45 							.type = NLA_U32},
46 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_GC_ENA] = {
47 							.type = NLA_U32},
48 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RESTART_ENA] = {
49 							.type = NLA_U32},
50 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_NOISE_FLOOR_REF] = {
51 							.type = NLA_U32},
52 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_INIT_DELAY] = {
53 							.type = NLA_U32},
54 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_NB_TONE_THR] = {
55 							.type = NLA_U32},
56 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_STR_BIN_THR] = {
57 							.type = NLA_U32},
58 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_WB_RPT_MODE] = {
59 							.type = NLA_U32},
60 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RSSI_RPT_MODE] = {
61 							.type = NLA_U32},
62 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RSSI_THR] = {
63 							.type = NLA_U32},
64 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_PWR_FORMAT] = {
65 							.type = NLA_U32},
66 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RPT_MODE] = {
67 							.type = NLA_U32},
68 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_BIN_SCALE] = {
69 							.type = NLA_U32},
70 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DBM_ADJ] = {
71 							.type = NLA_U32},
72 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_CHN_MASK] = {
73 							.type = NLA_U32},
74 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE] = {
75 							.type = NLA_U32},
76 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COOKIE] = {
77 							.type = NLA_U64},
78 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_PERIOD] = {
79 							.type = NLA_U32},
80 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SHORT_REPORT] = {
81 							.type = NLA_U32},
82 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DEBUG_LEVEL] = {
83 							.type = NLA_U32},
84 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FREQUENCY] = {
85 							.type = NLA_U32},
86 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_MODE] = {
87 						.type = NLA_U32},
88 };
89 
90 static void wlan_spectral_intit_config(struct spectral_config *config_req)
91 {
92 	config_req->ss_period =          SPECTRAL_PHYERR_PARAM_NOVAL;
93 	config_req->ss_count =           SPECTRAL_PHYERR_PARAM_NOVAL;
94 	config_req->ss_fft_period =      SPECTRAL_PHYERR_PARAM_NOVAL;
95 	config_req->ss_short_report =    SPECTRAL_PHYERR_PARAM_NOVAL;
96 	config_req->ss_spectral_pri =    SPECTRAL_PHYERR_PARAM_NOVAL;
97 	config_req->ss_fft_size =        SPECTRAL_PHYERR_PARAM_NOVAL;
98 	config_req->ss_gc_ena =          SPECTRAL_PHYERR_PARAM_NOVAL;
99 	config_req->ss_restart_ena =     SPECTRAL_PHYERR_PARAM_NOVAL;
100 	config_req->ss_noise_floor_ref = SPECTRAL_PHYERR_PARAM_NOVAL;
101 	config_req->ss_init_delay =      SPECTRAL_PHYERR_PARAM_NOVAL;
102 	config_req->ss_nb_tone_thr =     SPECTRAL_PHYERR_PARAM_NOVAL;
103 	config_req->ss_str_bin_thr =     SPECTRAL_PHYERR_PARAM_NOVAL;
104 	config_req->ss_wb_rpt_mode =     SPECTRAL_PHYERR_PARAM_NOVAL;
105 	config_req->ss_rssi_rpt_mode =   SPECTRAL_PHYERR_PARAM_NOVAL;
106 	config_req->ss_rssi_thr =        SPECTRAL_PHYERR_PARAM_NOVAL;
107 	config_req->ss_pwr_format =      SPECTRAL_PHYERR_PARAM_NOVAL;
108 	config_req->ss_rpt_mode =        SPECTRAL_PHYERR_PARAM_NOVAL;
109 	config_req->ss_bin_scale =       SPECTRAL_PHYERR_PARAM_NOVAL;
110 	config_req->ss_dbm_adj =         SPECTRAL_PHYERR_PARAM_NOVAL;
111 	config_req->ss_chn_mask =        SPECTRAL_PHYERR_PARAM_NOVAL;
112 	config_req->ss_frequency =       SPECTRAL_PHYERR_PARAM_NOVAL;
113 }
114 
115 /**
116  * convert_spectral_mode_nl_to_internal() - Get Spectral mode
117  * @nl_spectral_mode: Spectral mode in vendor attribute
118  * @mode: Converted Spectral mode
119  *
120  * Return: QDF_STATUS_SUCCESS on success, else QDF_STATUS_E_FAILURE
121  */
122 static QDF_STATUS
123 convert_spectral_mode_nl_to_internal
124 		(enum qca_wlan_vendor_spectral_scan_mode nl_spectral_mode,
125 		 enum spectral_scan_mode *mode)
126 {
127 	switch (nl_spectral_mode) {
128 	case QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_NORMAL:
129 		*mode = SPECTRAL_SCAN_MODE_NORMAL;
130 		break;
131 
132 	case QCA_WLAN_VENDOR_SPECTRAL_SCAN_MODE_AGILE:
133 		*mode = SPECTRAL_SCAN_MODE_AGILE;
134 		break;
135 
136 	default:
137 		osif_err("Invalid spectral mode %u", nl_spectral_mode);
138 		return QDF_STATUS_E_FAILURE;
139 	}
140 
141 	return QDF_STATUS_SUCCESS;
142 }
143 
144 /**
145  * convert_spectral_err_code_internal_to_nl() - Get Spectral error code
146  * @spectral_err_code: Spectral error code used internally
147  * @nl_err_code: Spectral error code for cfg80211
148  *
149  * Return: QDF_STATUS_SUCCESS on success, else QDF_STATUS_E_FAILURE
150  */
151 static QDF_STATUS
152 convert_spectral_err_code_internal_to_nl
153 		(enum spectral_cp_error_code spectral_err_code,
154 		 enum qca_wlan_vendor_spectral_scan_error_code *nl_err_code)
155 {
156 	switch (spectral_err_code) {
157 	case SPECTRAL_SCAN_ERR_PARAM_UNSUPPORTED:
158 		*nl_err_code =
159 			QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_UNSUPPORTED;
160 		break;
161 
162 	case SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED:
163 		*nl_err_code =
164 			QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_MODE_UNSUPPORTED;
165 		break;
166 
167 	case SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE:
168 		*nl_err_code =
169 			QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_INVALID_VALUE;
170 		break;
171 
172 	case SPECTRAL_SCAN_ERR_PARAM_NOT_INITIALIZED:
173 		*nl_err_code =
174 			QCA_WLAN_VENDOR_SPECTRAL_SCAN_ERR_PARAM_NOT_INITIALIZED;
175 		break;
176 
177 	default:
178 		osif_err("Invalid spectral error code %u", spectral_err_code);
179 		return QDF_STATUS_E_FAILURE;
180 	}
181 
182 	return QDF_STATUS_SUCCESS;
183 }
184 
185 int wlan_cfg80211_spectral_scan_config_and_start(struct wiphy *wiphy,
186 						 struct wlan_objmgr_pdev *pdev,
187 						 const void *data,
188 						 int data_len)
189 {
190 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX + 1];
191 	struct spectral_config config_req;
192 	QDF_STATUS status;
193 	uint64_t cookie;
194 	struct sk_buff *skb;
195 	uint32_t spectral_dbg_level;
196 	uint32_t scan_req_type = 0;
197 	struct spectral_cp_request sscan_req;
198 	enum spectral_scan_mode sscan_mode = SPECTRAL_SCAN_MODE_NORMAL;
199 	uint16_t skb_len;
200 
201 	if (wlan_cfg80211_nla_parse(
202 			tb,
203 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX,
204 			data,
205 			data_len,
206 			spectral_scan_policy)) {
207 		osif_err("Invalid Spectral Scan config ATTR");
208 		return -EINVAL;
209 	}
210 
211 	wlan_spectral_intit_config(&config_req);
212 
213 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SCAN_COUNT])
214 		config_req.ss_count = nla_get_u32(tb
215 			[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SCAN_COUNT]);
216 
217 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SCAN_PERIOD])
218 		config_req.ss_period = nla_get_u32(tb
219 		[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SCAN_PERIOD]);
220 
221 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_PRIORITY])
222 		config_req.ss_spectral_pri = nla_get_u32(tb
223 			[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_PRIORITY]);
224 
225 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_SIZE])
226 		config_req.ss_fft_size = nla_get_u32(tb
227 			[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_SIZE]);
228 
229 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_GC_ENA])
230 		config_req.ss_gc_ena = nla_get_u32(tb
231 			[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_GC_ENA]);
232 
233 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RESTART_ENA])
234 		config_req.ss_restart_ena = nla_get_u32(tb
235 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RESTART_ENA]);
236 
237 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_NOISE_FLOOR_REF])
238 		config_req.ss_noise_floor_ref = nla_get_u32(tb
239 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_NOISE_FLOOR_REF]);
240 
241 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_INIT_DELAY])
242 		config_req.ss_init_delay = nla_get_u32(tb
243 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_INIT_DELAY]);
244 
245 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_NB_TONE_THR])
246 		config_req.ss_nb_tone_thr = nla_get_u32(tb
247 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_NB_TONE_THR]);
248 
249 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_STR_BIN_THR])
250 		config_req.ss_str_bin_thr = nla_get_u32(tb
251 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_STR_BIN_THR]);
252 
253 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_WB_RPT_MODE])
254 		config_req.ss_wb_rpt_mode = nla_get_u32(tb
255 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_WB_RPT_MODE]);
256 
257 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RSSI_RPT_MODE])
258 		config_req.ss_rssi_rpt_mode = nla_get_u32(tb
259 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RSSI_RPT_MODE]);
260 
261 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RSSI_THR])
262 		config_req.ss_rssi_thr = nla_get_u32(tb
263 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RSSI_THR]);
264 
265 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_PWR_FORMAT])
266 		config_req.ss_pwr_format = nla_get_u32(tb
267 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_PWR_FORMAT]);
268 
269 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RPT_MODE])
270 		config_req.ss_rpt_mode = nla_get_u32(tb
271 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RPT_MODE]);
272 
273 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_BIN_SCALE])
274 		config_req.ss_bin_scale = nla_get_u32(tb
275 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_BIN_SCALE]);
276 
277 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DBM_ADJ])
278 		config_req.ss_dbm_adj = nla_get_u32(tb
279 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DBM_ADJ]);
280 
281 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_CHN_MASK])
282 		config_req.ss_chn_mask = nla_get_u32(tb
283 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_CHN_MASK]);
284 
285 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_PERIOD])
286 		config_req.ss_fft_period = nla_get_u32(tb
287 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_PERIOD]);
288 
289 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SHORT_REPORT])
290 		config_req.ss_short_report = nla_get_u32(tb
291 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SHORT_REPORT]);
292 
293 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FREQUENCY])
294 		config_req.ss_frequency = nla_get_u32(tb
295 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FREQUENCY]);
296 
297 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_MODE]) {
298 		status = convert_spectral_mode_nl_to_internal(nla_get_u32(tb
299 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_MODE]), &sscan_mode);
300 
301 		if (QDF_IS_STATUS_ERROR(status))
302 			return -EINVAL;
303 	}
304 
305 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DEBUG_LEVEL]) {
306 		spectral_dbg_level = nla_get_u32(tb
307 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DEBUG_LEVEL]);
308 		sscan_req.ss_mode = sscan_mode;
309 		sscan_req.debug_req.spectral_dbg_level = spectral_dbg_level;
310 		sscan_req.req_id = SPECTRAL_SET_DEBUG_LEVEL;
311 		status = ucfg_spectral_control(pdev, &sscan_req);
312 		if (QDF_IS_STATUS_ERROR(status))
313 			return -EINVAL;
314 	}
315 
316 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE])
317 		scan_req_type = nla_get_u32(tb
318 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE]);
319 
320 	skb_len = NLMSG_HDRLEN;
321 	/* QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_ERROR_CODE */
322 	skb_len += NLA_HDRLEN + sizeof(u32);
323 	/* QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COOKIE */
324 	skb_len += NLA_HDRLEN + sizeof(u64);
325 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, skb_len);
326 	if (!skb) {
327 		osif_err(" reply skb alloc failed");
328 		return -ENOMEM;
329 	}
330 
331 	if (CONFIG_REQUESTED(scan_req_type)) {
332 		sscan_req.ss_mode = sscan_mode;
333 		sscan_req.req_id = SPECTRAL_SET_CONFIG;
334 		qdf_mem_copy(&sscan_req.config_req.sscan_config, &config_req,
335 			     qdf_min(sizeof(sscan_req.config_req.sscan_config),
336 				     sizeof(config_req)));
337 		status = ucfg_spectral_control(pdev, &sscan_req);
338 		if (QDF_IS_STATUS_ERROR(status)) {
339 			enum qca_wlan_vendor_spectral_scan_error_code
340 							spectral_nl_err_code;
341 
342 			/* No error reasons populated, just return error */
343 			if (sscan_req.config_req.sscan_err_code ==
344 					SPECTRAL_SCAN_ERR_INVALID) {
345 				kfree_skb(skb);
346 				return qdf_status_to_os_return(status);
347 			}
348 
349 			status = convert_spectral_err_code_internal_to_nl
350 					(sscan_req.config_req.sscan_err_code,
351 					 &spectral_nl_err_code);
352 			if (QDF_IS_STATUS_ERROR(status)) {
353 				kfree_skb(skb);
354 				return -EINVAL;
355 			}
356 
357 			if (nla_put_u32
358 			    (skb,
359 			     QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_ERROR_CODE,
360 			     spectral_nl_err_code)) {
361 				kfree_skb(skb);
362 				return -EINVAL;
363 			}
364 		}
365 	}
366 
367 	if (SCAN_REQUESTED(scan_req_type)) {
368 		sscan_req.ss_mode = sscan_mode;
369 		sscan_req.req_id = SPECTRAL_ACTIVATE_SCAN;
370 		status = ucfg_spectral_control(pdev, &sscan_req);
371 		if (QDF_IS_STATUS_ERROR(status)) {
372 			enum qca_wlan_vendor_spectral_scan_error_code
373 							spectral_nl_err_code;
374 
375 			/* No error reasons populated, just return error */
376 			if (sscan_req.action_req.sscan_err_code ==
377 					SPECTRAL_SCAN_ERR_INVALID) {
378 				kfree_skb(skb);
379 				return qdf_status_to_os_return(status);
380 			}
381 
382 			status = convert_spectral_err_code_internal_to_nl
383 					(sscan_req.action_req.sscan_err_code,
384 					 &spectral_nl_err_code);
385 			if (QDF_IS_STATUS_ERROR(status)) {
386 				kfree_skb(skb);
387 				return -EINVAL;
388 			}
389 
390 			if (nla_put_u32
391 			    (skb,
392 			     QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_ERROR_CODE,
393 			     spectral_nl_err_code)) {
394 				kfree_skb(skb);
395 				return -EINVAL;
396 			}
397 		}
398 	}
399 
400 	cookie = 0;
401 	if (wlan_cfg80211_nla_put_u64(skb,
402 				      QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COOKIE,
403 				      cookie)) {
404 		kfree_skb(skb);
405 		return -EINVAL;
406 	}
407 
408 	qal_devcfg_send_response((qdf_nbuf_t)skb);
409 
410 	return 0;
411 }
412 
413 int wlan_cfg80211_spectral_scan_stop(struct wiphy *wiphy,
414 				     struct wlan_objmgr_pdev *pdev,
415 				     const void *data,
416 				     int data_len)
417 {
418 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX + 1];
419 	QDF_STATUS status;
420 	struct spectral_cp_request sscan_req;
421 	enum spectral_scan_mode sscan_mode = SPECTRAL_SCAN_MODE_NORMAL;
422 	struct sk_buff *skb;
423 
424 	if (wlan_cfg80211_nla_parse(
425 			tb,
426 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX,
427 			data,
428 			data_len,
429 			spectral_scan_policy)) {
430 		osif_err("Invalid Spectral Scan stop ATTR");
431 		return -EINVAL;
432 	}
433 
434 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_MODE]) {
435 		status = convert_spectral_mode_nl_to_internal(nla_get_u32(tb
436 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_MODE]), &sscan_mode);
437 
438 		if (QDF_IS_STATUS_ERROR(status))
439 			return -EINVAL;
440 	}
441 
442 	sscan_req.ss_mode = sscan_mode;
443 	sscan_req.req_id = SPECTRAL_STOP_SCAN;
444 	status = ucfg_spectral_control(pdev, &sscan_req);
445 	if (QDF_IS_STATUS_ERROR(status)) {
446 		enum qca_wlan_vendor_spectral_scan_error_code
447 						spectral_nl_err_code;
448 
449 		/* No error reasons populated, just return error */
450 		if (sscan_req.action_req.sscan_err_code ==
451 				SPECTRAL_SCAN_ERR_INVALID)
452 			return qdf_status_to_os_return(status);
453 
454 		status = convert_spectral_err_code_internal_to_nl
455 				(sscan_req.action_req.sscan_err_code,
456 				 &spectral_nl_err_code);
457 		if (QDF_IS_STATUS_ERROR(status))
458 			return -EINVAL;
459 
460 		skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, NLMSG_HDRLEN +
461 					sizeof(u32) + NLA_HDRLEN);
462 		if (!skb) {
463 			osif_err(" reply skb alloc failed");
464 			return -ENOMEM;
465 		}
466 
467 		if (nla_put_u32
468 		    (skb,
469 		     QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_ERROR_CODE,
470 		     spectral_nl_err_code)) {
471 			kfree_skb(skb);
472 			return -EINVAL;
473 		}
474 		qal_devcfg_send_response((qdf_nbuf_t)skb);
475 	}
476 
477 	return 0;
478 }
479 
480 int wlan_cfg80211_spectral_scan_get_config(struct wiphy *wiphy,
481 					   struct wlan_objmgr_pdev *pdev,
482 					   const void *data,
483 					   int data_len)
484 {
485 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX + 1];
486 	struct spectral_config *sconfig;
487 	uint32_t spectral_dbg_level;
488 	struct sk_buff *skb;
489 	struct spectral_cp_request sscan_req;
490 	enum spectral_scan_mode sscan_mode = SPECTRAL_SCAN_MODE_NORMAL;
491 	QDF_STATUS status;
492 
493 	if (wlan_cfg80211_nla_parse(
494 			tb,
495 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX,
496 			data,
497 			data_len,
498 			spectral_scan_policy)) {
499 		osif_err("Invalid Spectral Scan config ATTR");
500 		return -EINVAL;
501 	}
502 
503 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_MODE]) {
504 		status = convert_spectral_mode_nl_to_internal(nla_get_u32(tb
505 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_MODE]), &sscan_mode);
506 
507 		if (QDF_IS_STATUS_ERROR(status))
508 			return -EINVAL;
509 	}
510 
511 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, (sizeof(u32) +
512 		NLA_HDRLEN) * QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX +
513 		NLMSG_HDRLEN);
514 	if (!skb) {
515 		osif_err(" reply skb alloc failed");
516 		return -ENOMEM;
517 	}
518 
519 	sscan_req.ss_mode = sscan_mode;
520 	sscan_req.req_id = SPECTRAL_GET_CONFIG;
521 	status = ucfg_spectral_control(pdev, &sscan_req);
522 	sconfig = &sscan_req.config_req.sscan_config;
523 	if (nla_put_u32(skb,
524 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SCAN_COUNT,
525 			sconfig->ss_count) ||
526 	    nla_put_u32(skb,
527 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SCAN_PERIOD,
528 			sconfig->ss_period) ||
529 	    nla_put_u32(skb,
530 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_PRIORITY,
531 			sconfig->ss_spectral_pri) ||
532 	    nla_put_u32(skb,
533 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_SIZE,
534 			sconfig->ss_fft_size) ||
535 	    nla_put_u32(skb,
536 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_GC_ENA,
537 			sconfig->ss_gc_ena) ||
538 	    nla_put_u32(skb,
539 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RESTART_ENA,
540 			sconfig->ss_restart_ena) ||
541 	    nla_put_u32(
542 		skb,
543 		QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_NOISE_FLOOR_REF,
544 		sconfig->ss_noise_floor_ref) ||
545 	    nla_put_u32(skb,
546 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_INIT_DELAY,
547 			sconfig->ss_init_delay) ||
548 	    nla_put_u32(skb,
549 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_NB_TONE_THR,
550 			sconfig->ss_nb_tone_thr) ||
551 	    nla_put_u32(skb,
552 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_STR_BIN_THR,
553 			sconfig->ss_str_bin_thr) ||
554 	    nla_put_u32(skb,
555 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_WB_RPT_MODE,
556 			sconfig->ss_wb_rpt_mode) ||
557 	    nla_put_u32(skb,
558 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RSSI_RPT_MODE,
559 			sconfig->ss_rssi_rpt_mode) ||
560 	    nla_put_u32(skb,
561 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RSSI_THR,
562 			sconfig->ss_rssi_thr) ||
563 	    nla_put_u32(skb,
564 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_PWR_FORMAT,
565 			sconfig->ss_pwr_format) ||
566 	    nla_put_u32(skb,
567 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RPT_MODE,
568 			sconfig->ss_rpt_mode) ||
569 	    nla_put_u32(skb,
570 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_BIN_SCALE,
571 			sconfig->ss_bin_scale) ||
572 	    nla_put_u32(skb,
573 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DBM_ADJ,
574 			sconfig->ss_dbm_adj) ||
575 	    nla_put_u32(skb,
576 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_CHN_MASK,
577 			sconfig->ss_chn_mask) ||
578 	    nla_put_u32(skb,
579 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_PERIOD,
580 			sconfig->ss_fft_period) ||
581 	    nla_put_u32(skb,
582 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SHORT_REPORT,
583 			sconfig->ss_short_report) ||
584 	    nla_put_u32(skb,
585 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FREQUENCY,
586 			sconfig->ss_frequency)) {
587 		kfree_skb(skb);
588 		return -EINVAL;
589 	}
590 
591 	sscan_req.ss_mode = sscan_mode;
592 	sscan_req.req_id = SPECTRAL_GET_DEBUG_LEVEL;
593 	status = ucfg_spectral_control(pdev, &sscan_req);
594 	spectral_dbg_level = sscan_req.debug_req.spectral_dbg_level;
595 	if (nla_put_u32(skb,
596 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DEBUG_LEVEL,
597 			spectral_dbg_level)) {
598 		kfree_skb(skb);
599 		return -EINVAL;
600 	}
601 	qal_devcfg_send_response((qdf_nbuf_t)skb);
602 
603 	return 0;
604 }
605 
606 int wlan_cfg80211_spectral_scan_get_cap(struct wiphy *wiphy,
607 					struct wlan_objmgr_pdev *pdev,
608 					const void *data,
609 					int data_len)
610 {
611 	struct spectral_caps *scaps;
612 	struct sk_buff *skb;
613 	struct spectral_cp_request sscan_req;
614 	QDF_STATUS status;
615 
616 	sscan_req.req_id = SPECTRAL_GET_CAPABILITY_INFO;
617 	status = ucfg_spectral_control(pdev, &sscan_req);
618 	scaps = &sscan_req.caps_req.sscan_caps;
619 
620 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, (sizeof(u32) +
621 		NLA_HDRLEN) * QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_MAX +
622 		NLMSG_HDRLEN);
623 	if (!skb) {
624 		osif_err(" reply skb alloc failed");
625 		return -ENOMEM;
626 	}
627 
628 	if (scaps->phydiag_cap)
629 		if (nla_put_flag(
630 			skb,
631 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_PHYDIAG))
632 			goto fail;
633 
634 	if (scaps->radar_cap)
635 		if (nla_put_flag(skb,
636 				 QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_RADAR))
637 			goto fail;
638 
639 	if (scaps->spectral_cap)
640 		if (nla_put_flag(
641 			skb,
642 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_SPECTRAL))
643 			goto fail;
644 
645 	if (scaps->advncd_spectral_cap)
646 		if (nla_put_flag(
647 		skb,
648 		QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_ADVANCED_SPECTRAL))
649 			goto fail;
650 
651 	if (nla_put_u32(skb,
652 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_HW_GEN,
653 			scaps->hw_gen))
654 		goto fail;
655 
656 	if (scaps->is_scaling_params_populated) {
657 		if (nla_put_u16(
658 			skb,
659 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_FORMULA_ID,
660 			scaps->formula_id))
661 			goto fail;
662 
663 		if (nla_put_u16(
664 			skb,
665 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_LOW_LEVEL_OFFSET,
666 			scaps->low_level_offset))
667 			goto fail;
668 
669 		if (nla_put_u16(
670 		       skb,
671 		       QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_HIGH_LEVEL_OFFSET,
672 		       scaps->high_level_offset))
673 			goto fail;
674 
675 		if (nla_put_u16(
676 			skb,
677 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_RSSI_THR,
678 			scaps->rssi_thr))
679 			goto fail;
680 
681 		if (nla_put_u8(
682 		    skb,
683 		    QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_DEFAULT_AGC_MAX_GAIN,
684 		    scaps->default_agc_max_gain))
685 			goto fail;
686 	}
687 
688 	if (scaps->agile_spectral_cap) {
689 		int ret;
690 
691 		ret = nla_put_flag
692 			(skb,
693 			 QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AGILE_SPECTRAL);
694 		if (ret)
695 			goto fail;
696 	}
697 
698 	if (scaps->agile_spectral_cap_160) {
699 		int ret;
700 
701 		ret = nla_put_flag
702 		    (skb,
703 		     QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AGILE_SPECTRAL_160);
704 		if (ret)
705 			goto fail;
706 	}
707 	if (scaps->agile_spectral_cap_80p80) {
708 		int ret;
709 
710 		ret = nla_put_flag
711 		  (skb,
712 		   QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AGILE_SPECTRAL_80_80);
713 		if (ret)
714 			goto fail;
715 	}
716 	qal_devcfg_send_response((qdf_nbuf_t)skb);
717 
718 	return 0;
719 
720 fail:
721 	kfree_skb(skb);
722 	return -EINVAL;
723 }
724 
725 int wlan_cfg80211_spectral_scan_get_diag_stats(struct wiphy *wiphy,
726 					       struct wlan_objmgr_pdev *pdev,
727 					       const void *data,
728 					       int data_len)
729 {
730 	struct spectral_diag_stats *spetcral_diag;
731 	struct sk_buff *skb;
732 	struct spectral_cp_request sscan_req;
733 	QDF_STATUS status;
734 
735 	sscan_req.req_id = SPECTRAL_GET_DIAG_STATS;
736 	status = ucfg_spectral_control(pdev, &sscan_req);
737 	spetcral_diag = &sscan_req.diag_req.sscan_diag;
738 
739 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, (sizeof(u64) +
740 		NLA_HDRLEN) * QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_MAX +
741 		NLMSG_HDRLEN);
742 	if (!skb) {
743 		osif_err(" reply skb alloc failed");
744 		return -ENOMEM;
745 	}
746 
747 	if (wlan_cfg80211_nla_put_u64(
748 		skb,
749 		QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_SIG_MISMATCH,
750 		spetcral_diag->spectral_mismatch) ||
751 	    wlan_cfg80211_nla_put_u64(
752 		skb,
753 		QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_SEC80_SFFT_INSUFFLEN,
754 		spetcral_diag->spectral_sec80_sfft_insufflen) ||
755 	    wlan_cfg80211_nla_put_u64(
756 		skb,
757 		QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_NOSEC80_SFFT,
758 		spetcral_diag->spectral_no_sec80_sfft) ||
759 	    wlan_cfg80211_nla_put_u64(
760 		skb,
761 		QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_VHTSEG1ID_MISMATCH,
762 		spetcral_diag->spectral_vhtseg1id_mismatch) ||
763 	    wlan_cfg80211_nla_put_u64(
764 		skb,
765 		QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_VHTSEG2ID_MISMATCH,
766 		spetcral_diag->spectral_vhtseg2id_mismatch)) {
767 		kfree_skb(skb);
768 		return -EINVAL;
769 	}
770 	qal_devcfg_send_response((qdf_nbuf_t)skb);
771 
772 	return 0;
773 }
774 
775 int wlan_cfg80211_spectral_scan_get_status(struct wiphy *wiphy,
776 					   struct wlan_objmgr_pdev *pdev,
777 					   const void *data,
778 					   int data_len)
779 {
780 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_MAX + 1];
781 	struct spectral_scan_state sscan_state = { 0 };
782 	struct sk_buff *skb;
783 	struct spectral_cp_request sscan_req;
784 	enum spectral_scan_mode sscan_mode = SPECTRAL_SCAN_MODE_NORMAL;
785 	QDF_STATUS status;
786 
787 	if (wlan_cfg80211_nla_parse(
788 			tb,
789 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_MAX,
790 			data,
791 			data_len,
792 			NULL)) {
793 		osif_err("Invalid Spectral Scan config ATTR");
794 		return -EINVAL;
795 	}
796 
797 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_MODE]) {
798 		status = convert_spectral_mode_nl_to_internal(nla_get_u32(tb
799 		[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_MODE]), &sscan_mode);
800 
801 		if (QDF_IS_STATUS_ERROR(status))
802 			return -EINVAL;
803 	}
804 
805 	/* Sending a request and extracting response from it has to be atomic */
806 	sscan_req.ss_mode = sscan_mode;
807 	sscan_req.req_id = SPECTRAL_IS_ACTIVE;
808 	status = ucfg_spectral_control(pdev, &sscan_req);
809 	sscan_state.is_active = sscan_req.status_req.is_active;
810 
811 	sscan_req.ss_mode = sscan_mode;
812 	sscan_req.req_id = SPECTRAL_IS_ENABLED;
813 	status = ucfg_spectral_control(pdev, &sscan_req);
814 	sscan_state.is_enabled = sscan_req.status_req.is_enabled;
815 
816 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 2 * (sizeof(u32) +
817 		NLA_HDRLEN) + NLMSG_HDRLEN);
818 	if (!skb) {
819 		osif_err(" reply skb alloc failed");
820 		return -ENOMEM;
821 	}
822 
823 	if (sscan_state.is_enabled)
824 		if (nla_put_flag(
825 			skb,
826 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_IS_ENABLED))
827 			goto fail;
828 
829 	if (sscan_state.is_active)
830 		if (nla_put_flag(
831 			skb,
832 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_IS_ACTIVE))
833 			goto fail;
834 	qal_devcfg_send_response((qdf_nbuf_t)skb);
835 
836 	return 0;
837 fail:
838 	kfree_skb(skb);
839 	return -EINVAL;
840 }
841