xref: /wlan-dirver/qca-wifi-host-cmn/os_if/linux/spectral/src/wlan_cfg80211_spectral.c (revision 4865edfd190c086bbe2c69aae12a8226f877b91e)
1 /*
2  * Copyright (c) 2017-2018 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 
35 static const struct nla_policy spectral_scan_policy[
36 		QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX + 1] = {
37 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SCAN_COUNT] = {
38 							.type = NLA_U32},
39 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SCAN_PERIOD] = {
40 							.type = NLA_U32},
41 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_PRIORITY] = {
42 							.type = NLA_U32},
43 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_SIZE] = {
44 							.type = NLA_U32},
45 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_GC_ENA] = {
46 							.type = NLA_U32},
47 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RESTART_ENA] = {
48 							.type = NLA_U32},
49 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_NOISE_FLOOR_REF] = {
50 							.type = NLA_U32},
51 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_INIT_DELAY] = {
52 							.type = NLA_U32},
53 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_NB_TONE_THR] = {
54 							.type = NLA_U32},
55 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_STR_BIN_THR] = {
56 							.type = NLA_U32},
57 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_WB_RPT_MODE] = {
58 							.type = NLA_U32},
59 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RSSI_RPT_MODE] = {
60 							.type = NLA_U32},
61 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RSSI_THR] = {
62 							.type = NLA_U32},
63 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_PWR_FORMAT] = {
64 							.type = NLA_U32},
65 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RPT_MODE] = {
66 							.type = NLA_U32},
67 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_BIN_SCALE] = {
68 							.type = NLA_U32},
69 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DBM_ADJ] = {
70 							.type = NLA_U32},
71 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_CHN_MASK] = {
72 							.type = NLA_U32},
73 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE] = {
74 							.type = NLA_U32},
75 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COOKIE] = {
76 							.type = NLA_U64},
77 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_PERIOD] = {
78 							.type = NLA_U32},
79 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SHORT_REPORT] = {
80 							.type = NLA_U32},
81 	[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DEBUG_LEVEL] = {
82 							.type = NLA_U32},
83 };
84 
85 static void wlan_spectral_intit_config(struct spectral_config *config_req)
86 {
87 	config_req->ss_period =          SPECTRAL_PHYERR_PARAM_NOVAL;
88 	config_req->ss_count =           SPECTRAL_PHYERR_PARAM_NOVAL;
89 	config_req->ss_fft_period =      SPECTRAL_PHYERR_PARAM_NOVAL;
90 	config_req->ss_short_report =    SPECTRAL_PHYERR_PARAM_NOVAL;
91 	config_req->ss_spectral_pri =    SPECTRAL_PHYERR_PARAM_NOVAL;
92 	config_req->ss_fft_size =        SPECTRAL_PHYERR_PARAM_NOVAL;
93 	config_req->ss_gc_ena =          SPECTRAL_PHYERR_PARAM_NOVAL;
94 	config_req->ss_restart_ena =     SPECTRAL_PHYERR_PARAM_NOVAL;
95 	config_req->ss_noise_floor_ref = SPECTRAL_PHYERR_PARAM_NOVAL;
96 	config_req->ss_init_delay =      SPECTRAL_PHYERR_PARAM_NOVAL;
97 	config_req->ss_nb_tone_thr =     SPECTRAL_PHYERR_PARAM_NOVAL;
98 	config_req->ss_str_bin_thr =     SPECTRAL_PHYERR_PARAM_NOVAL;
99 	config_req->ss_wb_rpt_mode =     SPECTRAL_PHYERR_PARAM_NOVAL;
100 	config_req->ss_rssi_rpt_mode =   SPECTRAL_PHYERR_PARAM_NOVAL;
101 	config_req->ss_rssi_thr =        SPECTRAL_PHYERR_PARAM_NOVAL;
102 	config_req->ss_pwr_format =      SPECTRAL_PHYERR_PARAM_NOVAL;
103 	config_req->ss_rpt_mode =        SPECTRAL_PHYERR_PARAM_NOVAL;
104 	config_req->ss_bin_scale =       SPECTRAL_PHYERR_PARAM_NOVAL;
105 	config_req->ss_dbm_adj =         SPECTRAL_PHYERR_PARAM_NOVAL;
106 	config_req->ss_chn_mask =        SPECTRAL_PHYERR_PARAM_NOVAL;
107 }
108 
109 static int wlan_spectral_set_config(struct wlan_objmgr_pdev *pdev,
110 				    struct spectral_config *config_req)
111 {
112 	int status;
113 
114 	status = ucfg_spectral_control(pdev,
115 				       SPECTRAL_SET_CONFIG,
116 				       config_req,
117 				       sizeof(struct spectral_config),
118 				       NULL,
119 				       NULL);
120 	if (status < 0)
121 		return -EINVAL;
122 
123 	return 0;
124 }
125 
126 static int wlan_spectral_set_debug_level(struct wlan_objmgr_pdev *pdev,
127 					 uint32_t spectral_dbg_level)
128 {
129 	int status;
130 
131 	status = ucfg_spectral_control(pdev,
132 				       SPECTRAL_SET_DEBUG_LEVEL,
133 				       &spectral_dbg_level,
134 				       sizeof(uint32_t),
135 				       NULL,
136 				       NULL);
137 	if (status < 0)
138 		return -EINVAL;
139 
140 	return 0;
141 }
142 
143 static int wlan_spectral_get_debug_level(struct wlan_objmgr_pdev *pdev,
144 					 uint32_t *spectral_dbg_level)
145 {
146 	int status;
147 	uint32_t outsize;
148 
149 	outsize = sizeof(uint32_t);
150 	status = ucfg_spectral_control(pdev,
151 				       SPECTRAL_GET_DEBUG_LEVEL,
152 				       NULL,
153 				       0,
154 				       spectral_dbg_level,
155 				       &outsize);
156 	if (status < 0)
157 		return -EINVAL;
158 
159 	return 0;
160 }
161 
162 static int wlan_spectral_get_config(struct wlan_objmgr_pdev *pdev,
163 				    struct spectral_config *config_req)
164 {
165 	int status;
166 	uint32_t outsize;
167 
168 	outsize = sizeof(struct spectral_config);
169 	status = ucfg_spectral_control(pdev,
170 				       SPECTRAL_GET_CONFIG,
171 				       NULL,
172 				       0,
173 				       config_req,
174 				       &outsize);
175 	if (status < 0)
176 		return -EINVAL;
177 
178 	return 0;
179 }
180 
181 static int wlan_spectral_get_cap(struct wlan_objmgr_pdev *pdev,
182 				 struct spectral_caps *spectral_cap)
183 {
184 	int status;
185 	uint32_t outsize;
186 
187 	outsize = sizeof(struct spectral_caps);
188 	status = ucfg_spectral_control(pdev,
189 				       SPECTRAL_GET_CAPABILITY_INFO,
190 				       NULL,
191 				       0,
192 				       spectral_cap,
193 				       &outsize);
194 	if (status < 0)
195 		return -EINVAL;
196 
197 	return 0;
198 }
199 
200 static int wlan_spectral_get_diag_stats(
201 		struct wlan_objmgr_pdev *pdev,
202 		struct spectral_diag_stats *spectral_diag)
203 {
204 	int status;
205 	uint32_t outsize;
206 
207 	outsize = sizeof(struct spectral_diag_stats);
208 	status = ucfg_spectral_control(pdev,
209 				       SPECTRAL_GET_DIAG_STATS,
210 				       NULL,
211 				       0,
212 				       spectral_diag,
213 				       &outsize);
214 	if (status < 0)
215 		return -EINVAL;
216 
217 	return 0;
218 }
219 
220 static int wlan_spectral_scan_get_status(
221 		struct wlan_objmgr_pdev *pdev,
222 		struct spectral_scan_state *sscan_state)
223 {
224 	uint32_t is_active;
225 	uint32_t is_enabled;
226 	int status;
227 	uint32_t outsize;
228 
229 	outsize = sizeof(uint32_t);
230 	status = ucfg_spectral_control(pdev,
231 				       SPECTRAL_IS_ACTIVE,
232 				       NULL,
233 				       0,
234 				       &is_active,
235 				       &outsize);
236 	if (status < 0)
237 		return -EINVAL;
238 
239 	sscan_state->is_active = is_active;
240 
241 	outsize = sizeof(uint32_t);
242 	status = ucfg_spectral_control(pdev,
243 				       SPECTRAL_IS_ENABLED,
244 				       NULL,
245 				       0,
246 				       &is_enabled,
247 				       &outsize);
248 	if (status < 0)
249 		return -EINVAL;
250 
251 	sscan_state->is_enabled = is_enabled;
252 
253 	return 0;
254 }
255 
256 static int wlan_start_spectral_scan(struct wlan_objmgr_pdev *pdev)
257 {
258 	int status;
259 
260 	status = ucfg_spectral_control(pdev,
261 				       SPECTRAL_ACTIVATE_SCAN,
262 				       NULL,
263 				       0,
264 				       NULL,
265 				       NULL);
266 	if (status < 0)
267 		return -EINVAL;
268 
269 	return 0;
270 }
271 
272 static int wlan_stop_spectral_scan(struct wlan_objmgr_pdev *pdev)
273 {
274 	int status;
275 
276 	status = ucfg_spectral_control(pdev,
277 				       SPECTRAL_STOP_SCAN,
278 				       NULL,
279 				       0,
280 				       NULL,
281 				       NULL);
282 	if (status < 0)
283 		return -EINVAL;
284 
285 	return 0;
286 }
287 
288 int wlan_cfg80211_spectral_scan_config_and_start(struct wiphy *wiphy,
289 						 struct wlan_objmgr_pdev *pdev,
290 						 const void *data,
291 						 int data_len)
292 {
293 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX + 1];
294 	struct spectral_config config_req;
295 	QDF_STATUS status;
296 	uint64_t cookie;
297 	struct sk_buff *skb;
298 	uint32_t spectral_dbg_level;
299 	uint32_t scan_req_type = 0;
300 
301 	if (wlan_cfg80211_nla_parse(
302 			tb,
303 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX,
304 			data,
305 			data_len,
306 			spectral_scan_policy)) {
307 		qdf_print("Invalid Spectral Scan config ATTR");
308 		return -EINVAL;
309 	}
310 
311 	wlan_spectral_intit_config(&config_req);
312 
313 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SCAN_COUNT])
314 		config_req.ss_count = nla_get_u32(tb
315 			[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SCAN_COUNT]);
316 
317 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SCAN_PERIOD])
318 		config_req.ss_period = nla_get_u32(tb
319 		[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SCAN_PERIOD]);
320 
321 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_PRIORITY])
322 		config_req.ss_spectral_pri = nla_get_u32(tb
323 			[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_PRIORITY]);
324 
325 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_SIZE])
326 		config_req.ss_fft_size = nla_get_u32(tb
327 			[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_SIZE]);
328 
329 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_GC_ENA])
330 		config_req.ss_gc_ena = nla_get_u32(tb
331 			[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_GC_ENA]);
332 
333 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RESTART_ENA])
334 		config_req.ss_restart_ena = nla_get_u32(tb
335 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RESTART_ENA]);
336 
337 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_NOISE_FLOOR_REF])
338 		config_req.ss_noise_floor_ref = nla_get_u32(tb
339 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_NOISE_FLOOR_REF]);
340 
341 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_INIT_DELAY])
342 		config_req.ss_init_delay = nla_get_u32(tb
343 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_INIT_DELAY]);
344 
345 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_NB_TONE_THR])
346 		config_req.ss_nb_tone_thr = nla_get_u32(tb
347 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_NB_TONE_THR]);
348 
349 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_STR_BIN_THR])
350 		config_req.ss_str_bin_thr = nla_get_u32(tb
351 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_STR_BIN_THR]);
352 
353 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_WB_RPT_MODE])
354 		config_req.ss_wb_rpt_mode = nla_get_u32(tb
355 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_WB_RPT_MODE]);
356 
357 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RSSI_RPT_MODE])
358 		config_req.ss_rssi_rpt_mode = nla_get_u32(tb
359 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RSSI_RPT_MODE]);
360 
361 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RSSI_THR])
362 		config_req.ss_rssi_thr = nla_get_u32(tb
363 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RSSI_THR]);
364 
365 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_PWR_FORMAT])
366 		config_req.ss_pwr_format = nla_get_u32(tb
367 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_PWR_FORMAT]);
368 
369 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RPT_MODE])
370 		config_req.ss_rpt_mode = nla_get_u32(tb
371 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RPT_MODE]);
372 
373 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_BIN_SCALE])
374 		config_req.ss_bin_scale = nla_get_u32(tb
375 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_BIN_SCALE]);
376 
377 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DBM_ADJ])
378 		config_req.ss_dbm_adj = nla_get_u32(tb
379 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DBM_ADJ]);
380 
381 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_CHN_MASK])
382 		config_req.ss_chn_mask = nla_get_u32(tb
383 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_CHN_MASK]);
384 
385 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_PERIOD])
386 		config_req.ss_fft_period = nla_get_u32(tb
387 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_PERIOD]);
388 
389 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SHORT_REPORT])
390 		config_req.ss_short_report = nla_get_u32(tb
391 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SHORT_REPORT]);
392 
393 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DEBUG_LEVEL]) {
394 		spectral_dbg_level = nla_get_u32(tb
395 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DEBUG_LEVEL]);
396 		status = wlan_spectral_set_debug_level(pdev,
397 						       spectral_dbg_level);
398 		if (QDF_STATUS_SUCCESS != status)
399 			return -EINVAL;
400 	}
401 
402 	if (tb[QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE])
403 		scan_req_type = nla_get_u32(tb
404 		   [QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_REQUEST_TYPE]);
405 
406 	if (CONFIG_REQUESTED(scan_req_type)) {
407 		status = wlan_spectral_set_config(pdev, &config_req);
408 		if (QDF_STATUS_SUCCESS != status)
409 			return -EINVAL;
410 	}
411 
412 	if (SCAN_REQUESTED(scan_req_type)) {
413 		status = wlan_start_spectral_scan(pdev);
414 		if (QDF_STATUS_SUCCESS != status)
415 			return -EINVAL;
416 	}
417 
418 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u64) +
419 		NLA_HDRLEN + NLMSG_HDRLEN);
420 	if (!skb) {
421 		qdf_print(" reply skb alloc failed");
422 		return -ENOMEM;
423 	}
424 
425 	cookie = 0;
426 	if (wlan_cfg80211_nla_put_u64(skb,
427 				      QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_COOKIE,
428 				      cookie)) {
429 		kfree_skb(skb);
430 		return -EINVAL;
431 	}
432 
433 	cfg80211_vendor_cmd_reply(skb);
434 
435 	return 0;
436 }
437 
438 int wlan_cfg80211_spectral_scan_stop(struct wiphy *wiphy,
439 				     struct wlan_objmgr_pdev *pdev,
440 				     const void *data,
441 				     int data_len)
442 {
443 	QDF_STATUS status;
444 
445 	status = wlan_stop_spectral_scan(pdev);
446 	if (QDF_STATUS_SUCCESS != status)
447 		return -EINVAL;
448 	return 0;
449 }
450 
451 int wlan_cfg80211_spectral_scan_get_config(struct wiphy *wiphy,
452 					   struct wlan_objmgr_pdev *pdev,
453 					   const void *data,
454 					   int data_len)
455 {
456 	struct spectral_config config_buf;
457 	uint32_t spectral_dbg_level;
458 	struct sk_buff *skb;
459 
460 	wlan_spectral_get_config(pdev, &config_buf);
461 	wlan_spectral_get_debug_level(pdev, &spectral_dbg_level);
462 
463 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, (21 * sizeof(u32)) +
464 		NLA_HDRLEN + NLMSG_HDRLEN);
465 	if (!skb) {
466 		qdf_print(" reply skb alloc failed");
467 		return -ENOMEM;
468 	}
469 
470 	if (nla_put_u32(skb,
471 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SCAN_COUNT,
472 			config_buf.ss_count) ||
473 	    nla_put_u32(skb,
474 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SCAN_PERIOD,
475 			config_buf.ss_period) ||
476 	    nla_put_u32(skb,
477 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_PRIORITY,
478 			config_buf.ss_spectral_pri) ||
479 	    nla_put_u32(skb,
480 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_SIZE,
481 			config_buf.ss_fft_size) ||
482 	    nla_put_u32(skb,
483 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_GC_ENA,
484 			config_buf.ss_gc_ena) ||
485 	    nla_put_u32(skb,
486 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RESTART_ENA,
487 			config_buf.ss_restart_ena) ||
488 	    nla_put_u32(
489 		skb,
490 		QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_NOISE_FLOOR_REF,
491 		config_buf.ss_noise_floor_ref) ||
492 	    nla_put_u32(skb,
493 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_INIT_DELAY,
494 			config_buf.ss_init_delay) ||
495 	    nla_put_u32(skb,
496 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_NB_TONE_THR,
497 			config_buf.ss_nb_tone_thr) ||
498 	    nla_put_u32(skb,
499 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_STR_BIN_THR,
500 			config_buf.ss_str_bin_thr) ||
501 	    nla_put_u32(skb,
502 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_WB_RPT_MODE,
503 			config_buf.ss_wb_rpt_mode) ||
504 	    nla_put_u32(skb,
505 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RSSI_RPT_MODE,
506 			config_buf.ss_rssi_rpt_mode) ||
507 	    nla_put_u32(skb,
508 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RSSI_THR,
509 			config_buf.ss_rssi_thr) ||
510 	    nla_put_u32(skb,
511 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_PWR_FORMAT,
512 			config_buf.ss_pwr_format) ||
513 	    nla_put_u32(skb,
514 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_RPT_MODE,
515 			config_buf.ss_rpt_mode) ||
516 	    nla_put_u32(skb,
517 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_BIN_SCALE,
518 			config_buf.ss_bin_scale) ||
519 	    nla_put_u32(skb,
520 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DBM_ADJ,
521 			config_buf.ss_dbm_adj) ||
522 	    nla_put_u32(skb,
523 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_CHN_MASK,
524 			config_buf.ss_chn_mask) ||
525 	    nla_put_u32(skb,
526 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_FFT_PERIOD,
527 			config_buf.ss_fft_period) ||
528 	    nla_put_u32(skb,
529 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_SHORT_REPORT,
530 			config_buf.ss_short_report) ||
531 	    nla_put_u32(skb,
532 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_DEBUG_LEVEL,
533 			spectral_dbg_level)) {
534 		kfree_skb(skb);
535 		return -EINVAL;
536 	}
537 	cfg80211_vendor_cmd_reply(skb);
538 
539 	return 0;
540 }
541 
542 int wlan_cfg80211_spectral_scan_get_cap(struct wiphy *wiphy,
543 					struct wlan_objmgr_pdev *pdev,
544 					const void *data,
545 					int data_len)
546 {
547 	struct spectral_caps spectral_cap;
548 	struct sk_buff *skb;
549 
550 	wlan_spectral_get_cap(pdev, &spectral_cap);
551 
552 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 5 * sizeof(u32) +
553 		NLA_HDRLEN + NLMSG_HDRLEN);
554 	if (!skb) {
555 		qdf_print(" reply skb alloc failed");
556 		return -ENOMEM;
557 	}
558 
559 	if (spectral_cap.phydiag_cap)
560 		if (nla_put_flag(
561 			skb,
562 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_PHYDIAG))
563 			goto fail;
564 
565 	if (spectral_cap.radar_cap)
566 		if (nla_put_flag(skb,
567 				 QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_RADAR))
568 			goto fail;
569 
570 	if (spectral_cap.spectral_cap)
571 		if (nla_put_flag(
572 			skb,
573 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_SPECTRAL))
574 			goto fail;
575 
576 	if (spectral_cap.advncd_spectral_cap)
577 		if (nla_put_flag(
578 		skb,
579 		QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_ADVANCED_SPECTRAL))
580 			goto fail;
581 
582 	if (nla_put_u32(skb,
583 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_HW_GEN,
584 			spectral_cap.hw_gen))
585 		goto fail;
586 
587 	cfg80211_vendor_cmd_reply(skb);
588 
589 	return 0;
590 
591 fail:
592 	kfree_skb(skb);
593 	return -EINVAL;
594 }
595 
596 int wlan_cfg80211_spectral_scan_get_diag_stats(struct wiphy *wiphy,
597 					       struct wlan_objmgr_pdev *pdev,
598 					       const void *data,
599 					       int data_len)
600 {
601 	struct spectral_diag_stats spetcral_diag;
602 	struct sk_buff *skb;
603 
604 	wlan_spectral_get_diag_stats(pdev, &spetcral_diag);
605 
606 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 5 * sizeof(u64) +
607 		NLA_HDRLEN + NLMSG_HDRLEN);
608 	if (!skb) {
609 		qdf_print(" reply skb alloc failed");
610 		return -ENOMEM;
611 	}
612 
613 	if (wlan_cfg80211_nla_put_u64(
614 		skb,
615 		QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_SIG_MISMATCH,
616 		spetcral_diag.spectral_mismatch) ||
617 	    wlan_cfg80211_nla_put_u64(
618 		skb,
619 		QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_SEC80_SFFT_INSUFFLEN,
620 		spetcral_diag.spectral_sec80_sfft_insufflen) ||
621 	    wlan_cfg80211_nla_put_u64(
622 		skb,
623 		QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_NOSEC80_SFFT,
624 		spetcral_diag.spectral_no_sec80_sfft) ||
625 	    wlan_cfg80211_nla_put_u64(
626 		skb,
627 		QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_VHTSEG1ID_MISMATCH,
628 		spetcral_diag.spectral_vhtseg1id_mismatch) ||
629 	    wlan_cfg80211_nla_put_u64(
630 		skb,
631 		QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_DIAG_VHTSEG2ID_MISMATCH,
632 		spetcral_diag.spectral_vhtseg2id_mismatch)) {
633 		kfree_skb(skb);
634 		return -EINVAL;
635 	}
636 	cfg80211_vendor_cmd_reply(skb);
637 
638 	return 0;
639 }
640 
641 int wlan_cfg80211_spectral_scan_get_status(struct wiphy *wiphy,
642 					   struct wlan_objmgr_pdev *pdev,
643 					   const void *data,
644 					   int data_len)
645 {
646 	struct spectral_scan_state sscan_state = { 0 };
647 	struct sk_buff *skb;
648 
649 	skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, 2 * sizeof(u32) +
650 		NLA_HDRLEN + NLMSG_HDRLEN);
651 	if (!skb) {
652 		qdf_print(" reply skb alloc failed");
653 		return -ENOMEM;
654 	}
655 
656 	wlan_spectral_scan_get_status(pdev, &sscan_state);
657 
658 	if (sscan_state.is_enabled)
659 		if (nla_put_flag(
660 			skb,
661 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_IS_ENABLED))
662 			goto fail;
663 
664 	if (sscan_state.is_active)
665 		if (nla_put_flag(
666 			skb,
667 			QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_STATUS_IS_ACTIVE))
668 			goto fail;
669 	cfg80211_vendor_cmd_reply(skb);
670 	return 0;
671 
672 fail:
673 	kfree_skb(skb);
674 	return -EINVAL;
675 }
676