xref: /wlan-dirver/qca-wifi-host-cmn/umac/wifi_pos/src/wifi_pos_main.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
1 /*
2  * Copyright (c) 2012-2021 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: wifi_pos_main.c
21  * This file defines the important functions pertinent to
22  * wifi positioning to initialize and de-initialize the component.
23  */
24 #include "target_if_wifi_pos.h"
25 #include "wifi_pos_oem_interface_i.h"
26 #include "wifi_pos_utils_i.h"
27 #include "wifi_pos_api.h"
28 #include "wifi_pos_main_i.h"
29 #include "wifi_pos_ucfg_i.h"
30 #include "wlan_objmgr_cmn.h"
31 #include "wlan_objmgr_global_obj.h"
32 #include "wlan_objmgr_psoc_obj.h"
33 #include "wlan_objmgr_pdev_obj.h"
34 #include "wlan_objmgr_vdev_obj.h"
35 #include "wlan_ptt_sock_svc.h"
36 
37 #ifndef CNSS_GENL
38 #include <wlan_objmgr_global_obj_i.h>
39 #endif
40 
41 #include "wlan_reg_services_api.h"
42 /* forward declartion */
43 struct regulatory_channel;
44 
45 #define REG_SET_CHANNEL_REG_POWER(reg_info_1, val) do { \
46 	reg_info_1 &= 0xff00ffff;           \
47 	reg_info_1 |= ((val & 0xff) << 16); \
48 } while (0)
49 
50 /* max tx power is in 1 dBm units */
51 #define REG_SET_CHANNEL_MAX_TX_POWER(reg_info_2, val) do { \
52 	reg_info_2 &= 0xffff00ff;              \
53 	reg_info_2 |= ((val & 0xff) << 8);     \
54 } while (0)
55 
56 /* channel info consists of 6 bits of channel mode */
57 
58 #define REG_SET_CHANNEL_MODE(reg_channel, val) do { \
59 	(reg_channel)->info &= 0xffffffc0;            \
60 	(reg_channel)->info |= (val);                 \
61 } while (0)
62 
63 /*
64  * obj mgr api to iterate over vdevs does not provide a direct array or vdevs,
65  * rather takes a callback that is called for every vdev. wifi pos needs to
66  * store device mode and vdev id of all active vdevs and provide this info to
67  * user space as part of APP registration response. due to this, vdev_idx is
68  * used to identify how many vdevs have been populated by obj manager API.
69  */
70 static uint32_t vdev_idx;
71 
72 /**
73  * wifi_pos_get_tlv_support: indicates if firmware supports TLV wifi pos msg
74  * @psoc: psoc object
75  *
76  * Return: status of operation
77  */
78 static bool wifi_pos_get_tlv_support(struct wlan_objmgr_psoc *psoc)
79 {
80 	/* this is TBD */
81 	return true;
82 }
83 
84 struct wlan_lmac_if_wifi_pos_tx_ops *
85 	wifi_pos_get_tx_ops(struct wlan_objmgr_psoc *psoc)
86 {
87 	struct wlan_lmac_if_tx_ops *tx_ops;
88 
89 	if (!psoc) {
90 		wifi_pos_err("psoc is null");
91 		return NULL;
92 	}
93 
94 	tx_ops = wlan_psoc_get_lmac_if_txops(psoc);
95 	if (!tx_ops) {
96 		wifi_pos_err("tx_ops is NULL");
97 		return NULL;
98 	}
99 
100 	return &tx_ops->wifi_pos_tx_ops;
101 }
102 
103 #ifdef CNSS_GENL
104 static uint8_t *
105 wifi_pos_prepare_reg_resp(uint32_t *rsp_len,
106 			  struct app_reg_rsp_vdev_info *vdevs_info)
107 {
108 	uint32_t *nl_sign;
109 	uint8_t *resp_buf;
110 	struct wifi_app_reg_rsp *app_reg_rsp;
111 
112 	/*
113 	 * allocate ENHNC_FLAGS_LEN i.e. 4bytes extra memory in app_reg_resp
114 	 * to indicate NLA type response is supported for OEM request
115 	 * commands.
116 	 */
117 	*rsp_len = (sizeof(struct app_reg_rsp_vdev_info) * vdev_idx)
118 			+ sizeof(uint8_t) + ENHNC_FLAGS_LEN;
119 	resp_buf = qdf_mem_malloc(*rsp_len);
120 	if (!resp_buf)
121 		return NULL;
122 
123 	app_reg_rsp = (struct wifi_app_reg_rsp *)resp_buf;
124 	app_reg_rsp->num_inf = vdev_idx;
125 	qdf_mem_copy(&app_reg_rsp->vdevs, vdevs_info,
126 		     sizeof(struct app_reg_rsp_vdev_info) * vdev_idx);
127 
128 	nl_sign = (uint32_t *)&app_reg_rsp->vdevs[vdev_idx];
129 	*nl_sign |= NL_ENABLE_OEM_REQ_RSP;
130 
131 	return resp_buf;
132 }
133 
134 /**
135  * wifi_pos_get_host_pdev_id: Get host pdev_id
136  * @psoc: Pointer to psoc object
137  * @tgt_pdev_id: target_pdev_id
138  * @host_pdev_id: host pdev_id
139  *
140  * Return: QDF_STATUS_SUCCESS in case of success, error codes in case of failure
141  */
142 static QDF_STATUS wifi_pos_get_host_pdev_id(
143 		struct wlan_objmgr_psoc *psoc, uint32_t tgt_pdev_id,
144 		uint32_t *host_pdev_id)
145 {
146 	/* pdev_id in FW starts from 1. So convert it to
147 	 * host id by decrementing it.
148 	 * zero has special meaning due to backward
149 	 * compatibility. Dont change it.
150 	 */
151 	if (tgt_pdev_id)
152 		*host_pdev_id = tgt_pdev_id - 1;
153 	else
154 		*host_pdev_id = tgt_pdev_id;
155 
156 	return QDF_STATUS_SUCCESS;
157 }
158 #else
159 static uint8_t *
160 wifi_pos_prepare_reg_resp(uint32_t *rsp_len,
161 			  struct app_reg_rsp_vdev_info *vdevs_info)
162 {
163 	uint8_t *resp_buf;
164 	struct wifi_app_reg_rsp *app_reg_rsp;
165 
166 	*rsp_len = (sizeof(struct app_reg_rsp_vdev_info) * vdev_idx)
167 			+ sizeof(uint8_t);
168 	resp_buf = qdf_mem_malloc(*rsp_len);
169 	if (!resp_buf)
170 		return NULL;
171 
172 	app_reg_rsp = (struct wifi_app_reg_rsp *)resp_buf;
173 	app_reg_rsp->num_inf = vdev_idx;
174 	qdf_mem_copy(&app_reg_rsp->vdevs, vdevs_info,
175 		     sizeof(struct app_reg_rsp_vdev_info) * vdev_idx);
176 
177 	return resp_buf;
178 }
179 
180 static QDF_STATUS wifi_pos_get_host_pdev_id(
181 		struct wlan_objmgr_psoc *psoc, uint32_t tgt_pdev_id,
182 		uint32_t *host_pdev_id)
183 {
184 	struct wlan_lmac_if_wifi_pos_tx_ops *tx_ops;
185 
186 	tx_ops = wifi_pos_get_tx_ops(psoc);
187 	if (!tx_ops) {
188 		qdf_print("tx ops null");
189 		return QDF_STATUS_E_NULL_VALUE;
190 	}
191 
192 	if (!tx_ops->wifi_pos_convert_pdev_id_target_to_host) {
193 		wifi_pos_err("wifi_pos_convert_pdev_id_target_to_host is null");
194 		return QDF_STATUS_E_NULL_VALUE;
195 	}
196 
197 	return tx_ops->wifi_pos_convert_pdev_id_target_to_host(
198 			psoc, tgt_pdev_id, host_pdev_id);
199 }
200 #endif
201 
202 static QDF_STATUS wifi_pos_process_data_req(struct wlan_objmgr_psoc *psoc,
203 					struct wifi_pos_req_msg *req)
204 {
205 	uint8_t idx;
206 	uint32_t sub_type = 0;
207 	uint32_t channel_mhz = 0;
208 	uint32_t host_pdev_id = 0, tgt_pdev_id = 0;
209 	uint32_t offset;
210 	struct oem_data_req data_req;
211 	struct wlan_lmac_if_wifi_pos_tx_ops *tx_ops;
212 	struct wlan_objmgr_pdev *pdev;
213 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
214 				wifi_pos_get_psoc_priv_obj(wifi_pos_get_psoc());
215 	QDF_STATUS status;
216 
217 
218 	if (!wifi_pos_obj) {
219 		wifi_pos_err("wifi_pos priv obj is null");
220 		return QDF_STATUS_E_INVAL;
221 	}
222 
223 	wifi_pos_debug("Received data req pid(%d), len(%d)",
224 			req->pid, req->buf_len);
225 
226 	/* look for fields */
227 	if (req->field_info_buf)
228 		for (idx = 0; idx < req->field_info_buf->count; idx++) {
229 			offset = req->field_info_buf->fields[idx].offset;
230 			/*
231 			 * replace following reads with read_api based on
232 			 * length
233 			 */
234 			if (req->field_info_buf->fields[idx].id ==
235 					META_DATA_SUB_TYPE) {
236 				sub_type = *((uint32_t *)&req->buf[offset]);
237 				continue;
238 			}
239 
240 			if (req->field_info_buf->fields[idx].id ==
241 					META_DATA_CHANNEL_MHZ) {
242 				channel_mhz = *((uint32_t *)&req->buf[offset]);
243 				continue;
244 			}
245 
246 			if (req->field_info_buf->fields[idx].id ==
247 					META_DATA_PDEV) {
248 				tgt_pdev_id = *((uint32_t *)&req->buf[offset]);
249 				status = wifi_pos_get_host_pdev_id(
250 						psoc, tgt_pdev_id,
251 						&host_pdev_id);
252 				if (QDF_IS_STATUS_ERROR(status)) {
253 					wifi_pos_err("failed to get host pdev_id, tgt_pdev_id = %d",
254 						     tgt_pdev_id);
255 					return QDF_STATUS_E_INVAL;
256 				}
257 				continue;
258 			}
259 		}
260 
261 	switch (sub_type) {
262 	case TARGET_OEM_CAPABILITY_REQ:
263 		/* TBD */
264 		break;
265 	case TARGET_OEM_CONFIGURE_LCR:
266 		/* TBD */
267 		break;
268 	case TARGET_OEM_CONFIGURE_LCI:
269 		/* TBD */
270 		break;
271 	case TARGET_OEM_MEASUREMENT_REQ:
272 		/* TBD */
273 		break;
274 	case TARGET_OEM_CONFIGURE_FTMRR:
275 		wifi_pos_debug("FTMRR request");
276 		if (wifi_pos_obj->wifi_pos_send_action)
277 			wifi_pos_obj->wifi_pos_send_action(psoc, sub_type,
278 							   req->buf,
279 							   req->buf_len);
280 		break;
281 	case TARGET_OEM_CONFIGURE_WRU:
282 		wifi_pos_debug("WRU request");
283 		if (wifi_pos_obj->wifi_pos_send_action)
284 			wifi_pos_obj->wifi_pos_send_action(psoc, sub_type,
285 							   req->buf,
286 							   req->buf_len);
287 		break;
288 	default:
289 		wifi_pos_debug("invalid sub type or not passed");
290 
291 		tx_ops = wifi_pos_get_tx_ops(psoc);
292 		if (!tx_ops) {
293 			wifi_pos_err("tx ops null");
294 			return QDF_STATUS_E_INVAL;
295 		}
296 
297 		pdev = wlan_objmgr_get_pdev_by_id(psoc, host_pdev_id,
298 						  WLAN_WIFI_POS_CORE_ID);
299 		if (!pdev) {
300 			wifi_pos_err("pdev null");
301 			return QDF_STATUS_E_INVAL;
302 		}
303 		data_req.data_len = req->buf_len;
304 		data_req.data = req->buf;
305 		tx_ops->data_req_tx(pdev, &data_req);
306 		wlan_objmgr_pdev_release_ref(pdev,
307 					     WLAN_WIFI_POS_CORE_ID);
308 		break;
309 	}
310 
311 	return QDF_STATUS_SUCCESS;
312 }
313 
314 static QDF_STATUS wifi_pos_process_set_cap_req(struct wlan_objmgr_psoc *psoc,
315 					struct wifi_pos_req_msg *req)
316 {
317 	int error_code;
318 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
319 				wifi_pos_get_psoc_priv_obj(psoc);
320 	struct wifi_pos_user_defined_caps *caps =
321 				(struct wifi_pos_user_defined_caps *)req->buf;
322 
323 	if (!wifi_pos_obj) {
324 		wifi_pos_err("wifi_pos priv obj is null");
325 		return QDF_STATUS_E_INVAL;
326 	}
327 
328 	wifi_pos_debug("Received set cap req pid(%d), len(%d)",
329 			req->pid, req->buf_len);
330 
331 	wifi_pos_obj->ftm_rr = caps->ftm_rr;
332 	wifi_pos_obj->lci_capability = caps->lci_capability;
333 	error_code = qdf_status_to_os_return(QDF_STATUS_SUCCESS);
334 	wifi_pos_obj->wifi_pos_send_rsp(psoc, wifi_pos_obj->app_pid,
335 					WIFI_POS_CMD_SET_CAPS,
336 					sizeof(error_code),
337 					(uint8_t *)&error_code);
338 
339 	return QDF_STATUS_SUCCESS;
340 }
341 
342 static QDF_STATUS wifi_pos_process_get_cap_req(struct wlan_objmgr_psoc *psoc,
343 					struct wifi_pos_req_msg *req)
344 {
345 	struct wifi_pos_oem_get_cap_rsp cap_rsp = { { {0} } };
346 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
347 					wifi_pos_get_psoc_priv_obj(psoc);
348 
349 	if (!wifi_pos_obj) {
350 		wifi_pos_err("wifi_pos priv obj is null");
351 		return QDF_STATUS_E_INVAL;
352 	}
353 
354 	wifi_pos_debug("Received get cap req pid(%d), len(%d)",
355 		       req->pid, req->buf_len);
356 
357 	wifi_pos_populate_caps(psoc, &cap_rsp.driver_cap);
358 	cap_rsp.user_defined_cap.ftm_rr = wifi_pos_obj->ftm_rr;
359 	cap_rsp.user_defined_cap.lci_capability = wifi_pos_obj->lci_capability;
360 
361 	wifi_pos_obj->wifi_pos_send_rsp(psoc, wifi_pos_obj->app_pid,
362 					WIFI_POS_CMD_GET_CAPS,
363 					sizeof(cap_rsp),
364 					(uint8_t *)&cap_rsp);
365 
366 	return QDF_STATUS_SUCCESS;
367 }
368 
369 QDF_STATUS wifi_pos_send_report_resp(struct wlan_objmgr_psoc *psoc,
370 				     int req_id, uint8_t *dest_mac,
371 				     int err_code)
372 {
373 	struct wifi_pos_err_msg_report err_report = {0};
374 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
375 					wifi_pos_get_psoc_priv_obj(psoc);
376 
377 	if (!wifi_pos_obj) {
378 		wifi_pos_err("wifi_pos priv obj is null");
379 		return QDF_STATUS_E_INVAL;
380 	}
381 
382 	err_report.msg_tag_len = OEM_MSG_RSP_HEAD_TAG_ID << 16;
383 	err_report.msg_tag_len |= (sizeof(err_report) -
384 				   sizeof(err_report.err_rpt)) & 0x0000FFFF;
385 	err_report.msg_subtype = TARGET_OEM_ERROR_REPORT_RSP;
386 	err_report.req_id = req_id & 0xFFFF;
387 	err_report.req_id |= ((err_code & 0xFF) << 16);
388 	err_report.req_id |= (0x1 << 24);
389 	err_report.time_left = 0xFFFFFFFF;
390 	err_report.err_rpt.tag_len = OEM_MEAS_RSP_HEAD_TAG_ID << 16;
391 	err_report.err_rpt.tag_len |=
392 				(sizeof(struct wifi_pos_err_rpt)) & 0x0000FFFF;
393 	memcpy(&err_report.err_rpt.dest_mac, dest_mac, QDF_MAC_ADDR_SIZE);
394 
395 	wifi_pos_obj->wifi_pos_send_rsp(psoc, wifi_pos_obj->app_pid,
396 			WIFI_POS_CMD_OEM_DATA,
397 			sizeof(err_report),
398 			(uint8_t *)&err_report);
399 
400 	return QDF_STATUS_SUCCESS;
401 }
402 
403 static QDF_STATUS wifi_pos_get_vht_ch_width(struct wlan_objmgr_psoc *psoc,
404 					    enum phy_ch_width *ch_width)
405 {
406 	struct wlan_lmac_if_wifi_pos_tx_ops *tx_ops;
407 
408 	tx_ops = wifi_pos_get_tx_ops(psoc);
409 	if (!tx_ops) {
410 		qdf_print("tx ops null");
411 		return QDF_STATUS_E_NULL_VALUE;
412 	}
413 
414 	if (!tx_ops->wifi_pos_get_vht_ch_width) {
415 		wifi_pos_err("wifi pos get vht ch width is null");
416 		return QDF_STATUS_E_NULL_VALUE;
417 	}
418 
419 	return tx_ops->wifi_pos_get_vht_ch_width(
420 			psoc, ch_width);
421 }
422 
423 static void wifi_update_channel_bw_info(struct wlan_objmgr_psoc *psoc,
424 					struct wlan_objmgr_pdev *pdev,
425 					uint16_t freq,
426 					struct wifi_pos_channel_power *chan)
427 {
428 	struct ch_params ch_params = {0};
429 	uint16_t sec_ch_2g = 0;
430 	struct wifi_pos_psoc_priv_obj *wifi_pos_psoc =
431 		wifi_pos_get_psoc_priv_obj(wifi_pos_get_psoc());
432 	uint32_t phy_mode;
433 	QDF_STATUS status;
434 
435 	if (!wifi_pos_psoc) {
436 		wifi_pos_err("wifi_pos priv obj is null");
437 		return;
438 	}
439 
440 	status = wifi_pos_get_vht_ch_width(psoc, &ch_params.ch_width);
441 
442 	if (QDF_IS_STATUS_ERROR(status)) {
443 		wifi_pos_err("can not get vht ch width");
444 		return;
445 	}
446 
447 	wlan_reg_set_channel_params_for_freq(pdev, freq,
448 					     sec_ch_2g, &ch_params);
449 	chan->band_center_freq1 = ch_params.mhz_freq_seg0;
450 
451 	if (wifi_pos_psoc->wifi_pos_get_fw_phy_mode_for_freq) {
452 		wifi_pos_psoc->wifi_pos_get_fw_phy_mode_for_freq(
453 				freq, ch_params.ch_width, &phy_mode);
454 		chan->phy_mode = phy_mode;
455 	}
456 }
457 
458 /**
459  * wifi_pos_get_valid_channels: Get the list of valid channels from the
460  * given channel list
461  * @chan_freqs: Channel frequencies to be validated
462  * @num_ch: NUmber of channels in the channel list to be validated
463  * @valid_channel_list: Pointer to valid channel list
464  *
465  * Return: Number of valid channels in the given list
466  */
467 static uint32_t wifi_pos_get_valid_channels(qdf_freq_t *chan_freqs,
468 					    uint32_t num_ch,
469 					    qdf_freq_t *valid_channel_list)
470 {
471 	uint32_t i, num_valid_channels = 0;
472 
473 	for (i = 0; i < num_ch; i++) {
474 		if (wlan_reg_get_chan_enum_for_freq(chan_freqs[i]) ==
475 		    INVALID_CHANNEL)
476 			continue;
477 		valid_channel_list[num_valid_channels++] = chan_freqs[i];
478 	}
479 	return num_valid_channels;
480 }
481 
482 static void wifi_pos_pdev_iterator(struct wlan_objmgr_psoc *psoc,
483 				   void *obj, void *arg)
484 {
485 	QDF_STATUS status;
486 	uint8_t num_channels;
487 	struct wlan_objmgr_pdev *pdev = obj;
488 	struct wifi_pos_channel_list *chan_list = arg;
489 	struct channel_power *ch_info = NULL;
490 	struct wifi_pos_channel_power *wifi_pos_ch;
491 	int i;
492 
493 	if (!chan_list) {
494 		wifi_pos_err("wifi_pos priv arg is null");
495 		return;
496 	}
497 
498 	wifi_pos_ch = &chan_list->chan_info[chan_list->num_channels];
499 
500 	ch_info = (struct channel_power *)qdf_mem_malloc(
501 			sizeof(*ch_info) * NUM_CHANNELS);
502 	if (!ch_info) {
503 		wifi_pos_err("ch_info is null");
504 		return;
505 	}
506 
507 	status = wlan_reg_get_channel_list_with_power_for_freq(pdev, ch_info,
508 							       &num_channels);
509 
510 	if (QDF_IS_STATUS_ERROR(status)) {
511 		wifi_pos_err("Failed to get valid channel list");
512 		qdf_mem_free(ch_info);
513 		return;
514 	}
515 
516 	if ((chan_list->num_channels + num_channels) > NUM_CHANNELS) {
517 		wifi_pos_err("Invalid number of channels");
518 		qdf_mem_free(ch_info);
519 		return;
520 	}
521 
522 	for (i = 0; i < num_channels; i++) {
523 		wifi_pos_ch[i].ch_power.center_freq = ch_info[i].center_freq;
524 		wifi_pos_ch[i].ch_power.chan_num = ch_info[i].chan_num;
525 		wifi_pos_ch[i].ch_power.tx_power = ch_info[i].tx_power;
526 		wifi_pos_ch[i].is_dfs_chan =
527 			wlan_reg_is_dfs_for_freq(pdev, ch_info[i].center_freq);
528 		wifi_update_channel_bw_info(
529 				psoc, pdev,
530 				ch_info[i].center_freq, &wifi_pos_ch[i]);
531 	}
532 
533 	chan_list->num_channels += num_channels;
534 	qdf_mem_free(ch_info);
535 }
536 
537 #ifdef CNSS_GENL
538 static bool wifi_pos_is_resp_version_valid(uint32_t rsp_version)
539 {
540 	return (rsp_version == WIFI_POS_RSP_V2_NL) ? true : false;
541 }
542 
543 static void wifi_pos_get_ch_info(struct wlan_objmgr_psoc *psoc,
544 				 struct wifi_pos_channel_list *chan_list)
545 {
546 	wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP,
547 				     wifi_pos_pdev_iterator,
548 				     chan_list, true, WLAN_WIFI_POS_CORE_ID);
549 	wifi_pos_debug("num channels: %d", chan_list->num_channels);
550 }
551 
552 #else
553 static bool wifi_pos_is_resp_version_valid(uint32_t rsp_version)
554 {
555 	return ((rsp_version == WIFI_POS_RSP_V2_NL) ||
556 		(rsp_version == WIFI_POS_RSP_V1_FLAT_MEMORY)) ?
557 		true : false;
558 }
559 
560 static void wifi_pos_get_ch_info(struct wlan_objmgr_psoc *psoc,
561 				 struct wifi_pos_channel_list *chan_list)
562 {
563 	uint8_t index;
564 
565 	for (index = 0; index < WLAN_OBJMGR_MAX_DEVICES; index++) {
566 		if (g_umac_glb_obj->psoc[index]) {
567 			wlan_objmgr_iterate_obj_list(
568 					g_umac_glb_obj->psoc[index],
569 					WLAN_PDEV_OP, wifi_pos_pdev_iterator,
570 					chan_list, true, WLAN_WIFI_POS_CORE_ID);
571 		}
572 	}
573 
574 	wifi_pos_notice("num channels: %d", chan_list->num_channels);
575 }
576 #endif
577 
578 static QDF_STATUS wifi_pos_process_ch_info_req(struct wlan_objmgr_psoc *psoc,
579 					struct wifi_pos_req_msg *req)
580 {
581 	uint8_t idx;
582 	uint8_t *buf = NULL;
583 	uint32_t len, i, freq;
584 	qdf_freq_t *chan_freqs = NULL;
585 	bool oem_6g_support_disable;
586 	uint8_t *channels = req->buf;
587 	struct wlan_objmgr_pdev *pdev;
588 	uint32_t num_ch = req->buf_len;
589 	qdf_freq_t valid_channel_list[NUM_CHANNELS];
590 	uint32_t num_valid_channels = 0;
591 	struct wifi_pos_ch_info_rsp *ch_info;
592 	struct wifi_pos_channel_list *ch_list = NULL;
593 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
594 					wifi_pos_get_psoc_priv_obj(psoc);
595 	QDF_STATUS ret_val;
596 	struct wifi_pos_channel_power *ch;
597 
598 	if (!wifi_pos_obj) {
599 		wifi_pos_err("wifi_pos priv obj is null");
600 		return QDF_STATUS_E_INVAL;
601 	}
602 
603 	wifi_pos_debug("Received ch info req pid(%d), len(%d)",
604 			req->pid, req->buf_len);
605 
606 	/* get first pdev since we need that only for freq and dfs state */
607 	pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, WLAN_WIFI_POS_CORE_ID);
608 	if (!pdev) {
609 		wifi_pos_err("pdev get API failed");
610 		return QDF_STATUS_E_INVAL;
611 	}
612 	if (num_ch > NUM_CHANNELS) {
613 		wifi_pos_err("Invalid number of channels");
614 		ret_val = QDF_STATUS_E_INVAL;
615 		goto cleanup;
616 	}
617 
618 	chan_freqs = qdf_mem_malloc(NUM_CHANNELS * (sizeof(*chan_freqs)));
619 	if (!chan_freqs) {
620 		ret_val = QDF_STATUS_E_NOMEM;
621 		goto cleanup;
622 	}
623 
624 	ch_list = qdf_mem_malloc(sizeof(*ch_list));
625 	if (!ch_list) {
626 		ret_val = QDF_STATUS_E_NOMEM;
627 		goto cleanup;
628 	}
629 
630 	ch = ch_list->chan_info;
631 
632 	if ((num_ch == 0) &&
633 	    wifi_pos_is_resp_version_valid(req->rsp_version)) {
634 		wifi_pos_get_ch_info(psoc, ch_list);
635 		qdf_spin_lock_bh(&wifi_pos_obj->wifi_pos_lock);
636 		oem_6g_support_disable = wifi_pos_obj->oem_6g_support_disable;
637 		qdf_spin_unlock_bh(&wifi_pos_obj->wifi_pos_lock);
638 
639 		/* ch_list has the frequencies in order of 2.4g, 5g & 6g */
640 		for (i = 0; i < ch_list->num_channels; i++) {
641 			freq = ch[i].ch_power.center_freq;
642 			if (oem_6g_support_disable &&
643 			    WLAN_REG_IS_6GHZ_CHAN_FREQ(freq))
644 				continue;
645 			num_valid_channels++;
646 		}
647 	} else {
648 		for (i = 0; i < NUM_CHANNELS; i++)
649 			chan_freqs[i] =
650 			    wlan_reg_chan_band_to_freq(pdev, channels[i],
651 						       BIT(REG_BAND_5G) |
652 						       BIT(REG_BAND_2G));
653 		/* v1 has ch_list with frequencies in order of 2.4g, 5g only */
654 		num_valid_channels = wifi_pos_get_valid_channels(
655 							chan_freqs, num_ch,
656 							 valid_channel_list);
657 		for (i = 0; i < num_valid_channels; i++) {
658 			ch[i].ch_power.center_freq = valid_channel_list[i];
659 			ch[i].ch_power.chan_num = wlan_reg_freq_to_chan(
660 					pdev, ch[i].ch_power.center_freq);
661 			ch[i].ch_power.tx_power =
662 				wlan_reg_get_channel_reg_power_for_freq(
663 						pdev,
664 						ch[i].ch_power.center_freq);
665 			ch[i].is_dfs_chan = wlan_reg_is_dfs_for_freq(
666 						pdev,
667 						ch[i].ch_power.center_freq);
668 
669 			wifi_update_channel_bw_info(psoc, pdev,
670 						    ch[i].ch_power.center_freq,
671 						    &ch[i]);
672 		}
673 	}
674 
675 	len = sizeof(uint8_t) + sizeof(struct wifi_pos_ch_info_rsp) *
676 			num_valid_channels;
677 	buf = qdf_mem_malloc(len);
678 	if (!buf) {
679 		ret_val = QDF_STATUS_E_NOMEM;
680 		goto cleanup;
681 	}
682 
683 	/* First byte of message body will have num of channels */
684 	buf[0] = num_valid_channels;
685 	ch_info = (struct wifi_pos_ch_info_rsp *)&buf[1];
686 	for (idx = 0; idx < num_valid_channels; idx++) {
687 		ch_info[idx].reserved0 = 0;
688 		ch_info[idx].chan_id = ch[idx].ch_power.chan_num;
689 		ch_info[idx].mhz = ch[idx].ch_power.center_freq;
690 		ch_info[idx].band_center_freq1 = ch[idx].band_center_freq1;
691 		ch_info[idx].band_center_freq2 = 0;
692 		ch_info[idx].info = 0;
693 
694 		REG_SET_CHANNEL_REG_POWER(ch_info[idx].reg_info_1,
695 					  ch[idx].ch_power.tx_power);
696 		REG_SET_CHANNEL_MAX_TX_POWER(ch_info[idx].reg_info_2,
697 					     ch[idx].ch_power.tx_power);
698 
699 		if (ch[i].is_dfs_chan)
700 			WIFI_POS_SET_DFS(ch_info[idx].info);
701 
702 		if (ch[i].phy_mode)
703 			REG_SET_CHANNEL_MODE(&ch_info[idx], ch[i].phy_mode);
704 	}
705 
706 	wifi_pos_obj->wifi_pos_send_rsp(psoc, wifi_pos_obj->app_pid,
707 					WIFI_POS_CMD_GET_CH_INFO,
708 					len, buf);
709 	ret_val = QDF_STATUS_SUCCESS;
710 
711 cleanup:
712 	qdf_mem_free(buf);
713 	qdf_mem_free(ch_list);
714 	qdf_mem_free(chan_freqs);
715 	wlan_objmgr_pdev_release_ref(pdev, WLAN_WIFI_POS_CORE_ID);
716 
717 	return ret_val;
718 }
719 
720 static void wifi_pos_vdev_iterator(struct wlan_objmgr_psoc *psoc,
721 				   void *vdev, void *arg)
722 {
723 	struct app_reg_rsp_vdev_info *vdev_info = arg;
724 
725 	vdev_info[vdev_idx].dev_mode = wlan_vdev_mlme_get_opmode(vdev);
726 	vdev_info[vdev_idx].vdev_id = wlan_vdev_get_id(vdev);
727 	vdev_idx++;
728 }
729 
730 #ifdef CNSS_GENL
731 static void wifi_pos_get_vdev_list(struct wlan_objmgr_psoc *psoc,
732 				   struct app_reg_rsp_vdev_info *vdevs_info)
733 {
734 	wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
735 				     wifi_pos_vdev_iterator,
736 				     vdevs_info, true, WLAN_WIFI_POS_CORE_ID);
737 }
738 #else
739 /* For WIN, WIFI POS command registration is called only for the first
740  * PSOC. Hence, iterate through all the PSOCs and send the vdev list
741  * to LOWI.
742  */
743 static void wifi_pos_get_vdev_list(struct wlan_objmgr_psoc *psoc,
744 				   struct app_reg_rsp_vdev_info *vdevs_info)
745 {
746 	uint8_t index;
747 
748 	for (index = 0; index < WLAN_OBJMGR_MAX_DEVICES; index++) {
749 		if (g_umac_glb_obj->psoc[index]) {
750 			wlan_objmgr_iterate_obj_list(
751 					g_umac_glb_obj->psoc[index],
752 					WLAN_VDEV_OP, wifi_pos_vdev_iterator,
753 					vdevs_info, true,
754 					WLAN_WIFI_POS_CORE_ID);
755 		}
756 	}
757 }
758 #endif
759 
760 static QDF_STATUS wifi_pos_process_app_reg_req(struct wlan_objmgr_psoc *psoc,
761 					struct wifi_pos_req_msg *req)
762 {
763 	QDF_STATUS ret = QDF_STATUS_SUCCESS;
764 	uint8_t err = 0, *app_reg_rsp;
765 	uint32_t rsp_len;
766 	char *sign_str = NULL;
767 	struct app_reg_rsp_vdev_info vdevs_info[WLAN_UMAC_PSOC_MAX_VDEVS]
768 								= { { 0 } };
769 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
770 			wifi_pos_get_psoc_priv_obj(psoc);
771 
772 	if (!wifi_pos_obj) {
773 		wifi_pos_err("wifi_pos priv obj is null");
774 		return QDF_STATUS_E_INVAL;
775 	}
776 
777 	wifi_pos_debug("Received App Req Req pid(%d), len(%d)",
778 			req->pid, req->buf_len);
779 
780 	sign_str = (char *)req->buf;
781 	/* Registration request is only allowed for QTI Application */
782 	if ((OEM_APP_SIGNATURE_LEN != req->buf_len) ||
783 		(strncmp(sign_str, OEM_APP_SIGNATURE_STR,
784 			 OEM_APP_SIGNATURE_LEN))) {
785 		wifi_pos_err("Invalid signature pid(%d)", req->pid);
786 		ret = QDF_STATUS_E_PERM;
787 		err = OEM_ERR_INVALID_SIGNATURE;
788 		goto app_reg_failed;
789 	}
790 
791 	wifi_pos_debug("Valid App Req Req from pid(%d)", req->pid);
792 	qdf_spin_lock_bh(&wifi_pos_obj->wifi_pos_lock);
793 	wifi_pos_obj->is_app_registered = true;
794 	wifi_pos_obj->app_pid = req->pid;
795 	qdf_spin_unlock_bh(&wifi_pos_obj->wifi_pos_lock);
796 
797 	vdev_idx = 0;
798 
799 	wifi_pos_get_vdev_list(psoc, vdevs_info);
800 
801 	app_reg_rsp = wifi_pos_prepare_reg_resp(&rsp_len, vdevs_info);
802 	if (!app_reg_rsp) {
803 		ret = QDF_STATUS_E_NOMEM;
804 		err = OEM_ERR_NULL_CONTEXT;
805 		goto app_reg_failed;
806 	}
807 
808 	if (!vdev_idx)
809 		wifi_pos_debug("no active vdev");
810 
811 	vdev_idx = 0;
812 	wifi_pos_obj->wifi_pos_send_rsp(psoc, req->pid,
813 					WIFI_POS_CMD_REGISTRATION,
814 					rsp_len, (uint8_t *)app_reg_rsp);
815 
816 	qdf_mem_free(app_reg_rsp);
817 	return ret;
818 
819 app_reg_failed:
820 
821 	wifi_pos_obj->wifi_pos_send_rsp(psoc, req->pid, WIFI_POS_CMD_ERROR,
822 					sizeof(err), &err);
823 	return ret;
824 }
825 
826 /**
827  * wifi_pos_tlv_callback: wifi pos msg handler registered for TLV type req
828  * @wmi_msg: wmi type request msg
829  *
830  * Return: status of operation
831  */
832 static QDF_STATUS wifi_pos_tlv_callback(struct wlan_objmgr_psoc *psoc,
833 					struct wifi_pos_req_msg *req)
834 {
835 	wifi_pos_debug("enter: msg_type: %d", req->msg_type);
836 	switch (req->msg_type) {
837 	case WIFI_POS_CMD_REGISTRATION:
838 		return wifi_pos_process_app_reg_req(psoc, req);
839 	case WIFI_POS_CMD_OEM_DATA:
840 		return wifi_pos_process_data_req(psoc, req);
841 	case WIFI_POS_CMD_GET_CH_INFO:
842 		return wifi_pos_process_ch_info_req(psoc, req);
843 	case WIFI_POS_CMD_SET_CAPS:
844 		return wifi_pos_process_set_cap_req(psoc, req);
845 	case WIFI_POS_CMD_GET_CAPS:
846 		return wifi_pos_process_get_cap_req(psoc, req);
847 	default:
848 		wifi_pos_err("invalid request type");
849 		break;
850 	}
851 	return 0;
852 }
853 
854 /**
855  * wifi_pos_non_tlv_callback: wifi pos msg handler registered for non-TLV
856  * type req
857  * @wmi_msg: wmi type request msg
858  *
859  * Return: status of operation
860  */
861 static QDF_STATUS wifi_pos_non_tlv_callback(struct wlan_objmgr_psoc *psoc,
862 					    struct wifi_pos_req_msg *req)
863 {
864 	return QDF_STATUS_SUCCESS;
865 }
866 
867 QDF_STATUS wifi_pos_convert_host_pdev_id_to_target(
868 		struct wlan_objmgr_psoc *psoc, uint32_t host_pdev_id,
869 		uint32_t *target_pdev_id)
870 {
871 	struct wlan_lmac_if_wifi_pos_tx_ops *tx_ops;
872 
873 	tx_ops = wifi_pos_get_tx_ops(psoc);
874 	if (!tx_ops) {
875 		wifi_pos_err("tx_ops is null");
876 		return QDF_STATUS_E_NULL_VALUE;
877 	}
878 
879 	if (!tx_ops->wifi_pos_convert_pdev_id_host_to_target) {
880 		wifi_pos_err("wifi_pos_convert_pdev_id_host_to_target is null");
881 		return QDF_STATUS_E_NULL_VALUE;
882 	}
883 
884 	return tx_ops->wifi_pos_convert_pdev_id_host_to_target(
885 			psoc, host_pdev_id, target_pdev_id);
886 }
887 
888 QDF_STATUS wifi_pos_psoc_obj_created_notification(
889 		struct wlan_objmgr_psoc *psoc, void *arg_list)
890 {
891 	QDF_STATUS status;
892 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj;
893 
894 	/*
895 	 * this is for WIN, if they have multiple psoc, we dont want to create
896 	 * multiple priv object. Since there is just one LOWI app registered to
897 	 * one driver, avoid 2nd private object with another psoc.
898 	 */
899 	if (wifi_pos_get_psoc()) {
900 		wifi_pos_debug("global psoc obj already set. do not allocate another psoc private object");
901 		return QDF_STATUS_SUCCESS;
902 	} else {
903 		wifi_pos_debug("setting global pos object");
904 		wifi_pos_set_psoc(psoc);
905 	}
906 
907 	/* initialize wifi-pos psoc priv object */
908 	wifi_pos_obj = qdf_mem_malloc(sizeof(*wifi_pos_obj));
909 	if (!wifi_pos_obj) {
910 		wifi_pos_clear_psoc();
911 		return QDF_STATUS_E_NOMEM;
912 	}
913 
914 	qdf_spinlock_create(&wifi_pos_obj->wifi_pos_lock);
915 	/* Register TLV or non-TLV callbacks depending on target fw version */
916 	if (wifi_pos_get_tlv_support(psoc))
917 		wifi_pos_obj->wifi_pos_req_handler = wifi_pos_tlv_callback;
918 	else
919 		wifi_pos_obj->wifi_pos_req_handler = wifi_pos_non_tlv_callback;
920 
921 	/*
922 	 * MGMT Rx is not handled in this phase since wifi pos only uses few
923 	 * measurement subtypes under RRM_RADIO_MEASURE_REQ. Rest of them are
924 	 * used for 80211k. That part is not yet converged and still follows
925 	 * legacy MGMT Rx to work. Action frame in new TXRX can be registered
926 	 * at per ACTION Frame type granularity only.
927 	 */
928 
929 	status = wlan_objmgr_psoc_component_obj_attach(psoc,
930 						WLAN_UMAC_COMP_WIFI_POS,
931 						wifi_pos_obj,
932 						QDF_STATUS_SUCCESS);
933 
934 	if (QDF_IS_STATUS_ERROR(status)) {
935 		wifi_pos_err("obj attach with psoc failed with status: %d",
936 				status);
937 		qdf_spinlock_destroy(&wifi_pos_obj->wifi_pos_lock);
938 		qdf_mem_free(wifi_pos_obj);
939 		wifi_pos_clear_psoc();
940 	}
941 
942 	return status;
943 }
944 
945 QDF_STATUS  wifi_pos_psoc_obj_destroyed_notification(
946 		struct wlan_objmgr_psoc *psoc, void *arg_list)
947 {
948 	QDF_STATUS status;
949 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj = NULL;
950 
951 	if (wifi_pos_get_psoc() == psoc) {
952 		wifi_pos_debug("deregistering wifi_pos_psoc object");
953 		wifi_pos_clear_psoc();
954 	} else {
955 		wifi_pos_warn("un-related PSOC closed. do nothing");
956 		return QDF_STATUS_SUCCESS;
957 	}
958 
959 	wifi_pos_obj = wifi_pos_get_psoc_priv_obj(psoc);
960 	if (!wifi_pos_obj) {
961 		wifi_pos_err("wifi_pos_obj is NULL");
962 		return QDF_STATUS_E_FAULT;
963 	}
964 
965 	target_if_wifi_pos_deinit_dma_rings(psoc);
966 
967 	status = wlan_objmgr_psoc_component_obj_detach(psoc,
968 						WLAN_UMAC_COMP_WIFI_POS,
969 						wifi_pos_obj);
970 	if (status != QDF_STATUS_SUCCESS)
971 		wifi_pos_err("wifi_pos_obj detach failed");
972 
973 	wifi_pos_debug("wifi_pos_obj deleted with status %d", status);
974 	qdf_spinlock_destroy(&wifi_pos_obj->wifi_pos_lock);
975 	qdf_mem_free(wifi_pos_obj);
976 
977 	return status;
978 }
979 
980 int wifi_pos_oem_rsp_handler(struct wlan_objmgr_psoc *psoc,
981 			     struct oem_data_rsp *oem_rsp)
982 {
983 	uint32_t len;
984 	uint8_t *data;
985 	uint32_t app_pid;
986 	struct wifi_pos_psoc_priv_obj *priv;
987 	wifi_pos_send_rsp_handler wifi_pos_send_rsp;
988 
989 	priv = wifi_pos_get_psoc_priv_obj(wifi_pos_get_psoc());
990 	if (!priv) {
991 		wifi_pos_err("private object is NULL");
992 		return -EINVAL;
993 	}
994 
995 	qdf_spin_lock_bh(&priv->wifi_pos_lock);
996 	app_pid = priv->app_pid;
997 	wifi_pos_send_rsp = priv->wifi_pos_send_rsp;
998 	qdf_spin_unlock_bh(&priv->wifi_pos_lock);
999 
1000 	len = oem_rsp->rsp_len_1 + oem_rsp->rsp_len_2 + oem_rsp->dma_len;
1001 	if (oem_rsp->rsp_len_1 > OEM_DATA_RSP_SIZE ||
1002 			oem_rsp->rsp_len_2 > OEM_DATA_RSP_SIZE) {
1003 		wifi_pos_err("invalid length of Oem Data response");
1004 		return -EINVAL;
1005 	}
1006 
1007 	if (!wifi_pos_send_rsp) {
1008 		wifi_pos_err("invalid response handler");
1009 		return -EINVAL;
1010 	}
1011 
1012 	wifi_pos_debug("oem data rsp, len: %d to pid: %d", len, app_pid);
1013 
1014 	if (oem_rsp->rsp_len_2 + oem_rsp->dma_len) {
1015 		/* stitch togther the msg data_1 + CIR/CFR + data_2 */
1016 		data = qdf_mem_malloc(len);
1017 		if (!data)
1018 			return -ENOMEM;
1019 
1020 		qdf_mem_copy(data, oem_rsp->data_1, oem_rsp->rsp_len_1);
1021 		qdf_mem_copy(&data[oem_rsp->rsp_len_1],
1022 			     oem_rsp->vaddr, oem_rsp->dma_len);
1023 		qdf_mem_copy(&data[oem_rsp->rsp_len_1 + oem_rsp->dma_len],
1024 			     oem_rsp->data_2, oem_rsp->rsp_len_2);
1025 
1026 		wifi_pos_send_rsp(psoc, app_pid, WIFI_POS_CMD_OEM_DATA, len,
1027 				  data);
1028 		qdf_mem_free(data);
1029 	} else {
1030 		wifi_pos_send_rsp(psoc, app_pid, WIFI_POS_CMD_OEM_DATA,
1031 				  oem_rsp->rsp_len_1, oem_rsp->data_1);
1032 	}
1033 
1034 	return 0;
1035 }
1036 
1037 void wifi_pos_register_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops)
1038 {
1039 	struct wlan_lmac_if_wifi_pos_rx_ops *wifi_pos_rx_ops;
1040 
1041 	wifi_pos_rx_ops = &rx_ops->wifi_pos_rx_ops;
1042 	wifi_pos_rx_ops->oem_rsp_event_rx = wifi_pos_oem_rsp_handler;
1043 }
1044 
1045 QDF_STATUS wifi_pos_populate_caps(struct wlan_objmgr_psoc *psoc,
1046 			   struct wifi_pos_driver_caps *caps)
1047 {
1048 	uint16_t i, count = 0;
1049 	uint32_t freq;
1050 	struct wifi_pos_psoc_priv_obj *wifi_pos_obj =
1051 					wifi_pos_get_psoc_priv_obj(psoc);
1052 	struct wifi_pos_channel_list *ch_list = NULL;
1053 
1054 	wifi_pos_debug("Enter");
1055 	if (!wifi_pos_obj) {
1056 		wifi_pos_err("wifi_pos_obj is null");
1057 		return QDF_STATUS_E_NULL_VALUE;
1058 	}
1059 
1060 	ch_list = qdf_mem_malloc(sizeof(*ch_list));
1061 	if (!ch_list)
1062 		return QDF_STATUS_E_NOMEM;
1063 
1064 	strlcpy(caps->oem_target_signature,
1065 		OEM_TARGET_SIGNATURE,
1066 		OEM_TARGET_SIGNATURE_LEN);
1067 	caps->oem_target_type = wifi_pos_obj->oem_target_type;
1068 	caps->oem_fw_version = wifi_pos_obj->oem_fw_version;
1069 	caps->driver_version.major = wifi_pos_obj->driver_version.major;
1070 	caps->driver_version.minor = wifi_pos_obj->driver_version.minor;
1071 	caps->driver_version.patch = wifi_pos_obj->driver_version.patch;
1072 	caps->driver_version.build = wifi_pos_obj->driver_version.build;
1073 	caps->allowed_dwell_time_min = wifi_pos_obj->allowed_dwell_time_min;
1074 	caps->allowed_dwell_time_max = wifi_pos_obj->allowed_dwell_time_max;
1075 	caps->curr_dwell_time_min = wifi_pos_obj->current_dwell_time_min;
1076 	caps->curr_dwell_time_max = wifi_pos_obj->current_dwell_time_max;
1077 	caps->supported_bands = wlan_objmgr_psoc_get_band_capability(psoc);
1078 	wifi_pos_get_ch_info(psoc, ch_list);
1079 
1080 	/* copy valid channels list to caps */
1081 	for (i = 0; i < ch_list->num_channels; i++) {
1082 		freq = ch_list->chan_info[i].ch_power.center_freq;
1083 		if (WLAN_REG_IS_6GHZ_CHAN_FREQ(freq))
1084 			continue;
1085 		caps->channel_list[count++] =
1086 			ch_list->chan_info[i].ch_power.chan_num;
1087 	}
1088 	caps->num_channels = count;
1089 	qdf_mem_free(ch_list);
1090 	return QDF_STATUS_SUCCESS;
1091 }
1092