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