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