1 /*
2  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include "os_if_qmi.h"
18 #include "os_if_qmi_wifi_driver_service_v01.h"
19 #include <qdf_util.h>
20 #include "wlan_qmi_public_struct.h"
21 #include "wlan_dp_ucfg_api.h"
22 
23 static struct qmi_handle qmi_wfds;
24 
25 /*
26  * os_if_ce_dir_qmi_to_wfds_type() - Convert ce direction from internal
27  *  type to type used in QMI message
28  * @ce_dir: internal ce direction
29  *
30  * Return: ce direction in QMI type
31  */
32 static enum wifi_drv_qmi_pipe_dir_v01
os_if_ce_dir_qmi_to_wfds_type(enum wlan_qmi_wfds_pipe_dir ce_dir)33 os_if_ce_dir_qmi_to_wfds_type(enum wlan_qmi_wfds_pipe_dir ce_dir)
34 {
35 	switch (ce_dir) {
36 	case QMI_WFDS_PIPEDIR_NONE:
37 		return WFDS_PIPEDIR_NONE_V01;
38 	case QMI_WFDS_PIPEDIR_IN:
39 		return WFDS_PIPEDIR_IN_V01;
40 	case QMI_WFDS_PIPEDIR_OUT:
41 		return WFDS_PIPEDIR_OUT_V01;
42 	default:
43 		return WIFI_DRV_QMI_PIPE_DIR_MAX_VAL_V01;
44 	}
45 }
46 
47 /*
48  * os_if_srng_dir_qmi_to_wfds_type() - Convert srng direction from internal
49  *  type to type used in QMI message
50  * @srng_dir: internal srng direction
51  *
52  * Return: srng direction in QMI type
53  */
54 static enum wifi_drv_qmi_srng_direction_v01
os_if_srng_dir_qmi_to_wfds_type(enum wlan_qmi_wfds_srng_dir srng_dir)55 os_if_srng_dir_qmi_to_wfds_type(enum wlan_qmi_wfds_srng_dir srng_dir)
56 {
57 	switch (srng_dir) {
58 	case QMI_WFDS_SRNG_SOURCE_RING:
59 		return WFDS_SRNG_SOURCE_RING_V01;
60 	case QMI_WFDS_SRNG_DESTINATION_RING:
61 		return WFDS_SRNG_DESTINATION_RING_V01;
62 	default:
63 		return WIFI_DRV_QMI_SRNG_DIRECTION_MAX_VAL_V01;
64 	}
65 }
66 
67 /*
68  * os_if_qmi_wfds_send_config_msg() - Send config message to QMI server
69  *  to QMI server
70  * @src_info: source information to be filled in QMI message
71  *
72  * Return: QDF status
73  */
74 static QDF_STATUS
os_if_qmi_wfds_send_config_msg(struct wlan_qmi_wfds_config_req_msg * src_info)75 os_if_qmi_wfds_send_config_msg(struct wlan_qmi_wfds_config_req_msg *src_info)
76 {
77 	struct wfds_config_req_msg_v01 *req;
78 	struct wfds_gen_resp_msg_v01 *resp;
79 	struct qmi_txn txn;
80 	QDF_STATUS status;
81 	uint8_t i;
82 
83 	req = qdf_mem_malloc(sizeof(*req));
84 	if (!req)
85 		return QDF_STATUS_E_NOMEM;
86 
87 	resp = qdf_mem_malloc(sizeof(*resp));
88 	if (!resp) {
89 		qdf_mem_free(req);
90 		return QDF_STATUS_E_NOMEM;
91 	}
92 
93 	if (src_info->ce_info_len > QMI_WFDS_CE_MAX_SRNG) {
94 		status = QDF_STATUS_E_INVAL;
95 		goto out;
96 	}
97 
98 	req->ce_info_len = src_info->ce_info_len;
99 	for (i = 0; i < req->ce_info_len; i++) {
100 		req->ce_info[i].ce_id = src_info->ce_info[i].ce_id;
101 		req->ce_info[i].ce_dir =
102 		     os_if_ce_dir_qmi_to_wfds_type(src_info->ce_info[i].ce_dir);
103 		req->ce_info[i].srng_info.ring_id =
104 			src_info->ce_info[i].srng_info.ring_id;
105 		req->ce_info[i].srng_info.dir =
106 			os_if_srng_dir_qmi_to_wfds_type(src_info->ce_info[i].srng_info.dir);
107 		req->ce_info[i].srng_info.num_entries =
108 			src_info->ce_info[i].srng_info.num_entries;
109 		req->ce_info[i].srng_info.entry_size =
110 			src_info->ce_info[i].srng_info.entry_size;
111 		req->ce_info[i].srng_info.ring_base_paddr =
112 			src_info->ce_info[i].srng_info.ring_base_paddr;
113 		req->ce_info[i].srng_info.hp_paddr =
114 			src_info->ce_info[i].srng_info.hp_paddr;
115 		req->ce_info[i].srng_info.tp_paddr =
116 			src_info->ce_info[i].srng_info.tp_paddr;
117 	}
118 
119 	req->rx_refill_ring.ring_id = src_info->rx_refill_ring.ring_id;
120 	req->rx_refill_ring.dir =
121 		os_if_srng_dir_qmi_to_wfds_type(src_info->rx_refill_ring.dir);
122 	req->rx_refill_ring.num_entries = src_info->rx_refill_ring.num_entries;
123 	req->rx_refill_ring.entry_size = src_info->rx_refill_ring.entry_size;
124 	req->rx_refill_ring.ring_base_paddr =
125 				src_info->rx_refill_ring.ring_base_paddr;
126 	req->rx_refill_ring.hp_paddr = src_info->rx_refill_ring.hp_paddr;
127 	req->rx_refill_ring.tp_paddr = src_info->rx_refill_ring.tp_paddr;
128 
129 	req->shadow_rdptr_mem_paddr = src_info->shadow_rdptr_mem_paddr;
130 	req->shadow_rdptr_mem_size = src_info->shadow_rdptr_mem_size;
131 	req->shadow_wrptr_mem_paddr = src_info->shadow_wrptr_mem_paddr;
132 	req->shadow_wrptr_mem_size = src_info->shadow_wrptr_mem_size;
133 	req->rx_pkt_tlv_len = src_info->rx_pkt_tlv_len;
134 	req->rx_rbm = src_info->rx_rbm;
135 	req->pcie_bar_pa = src_info->pcie_bar_pa;
136 	req->pci_slot = src_info->pci_slot;
137 	req->lpass_ep_id = src_info->lpass_ep_id;
138 
139 	status = os_if_qmi_txn_init(&qmi_wfds, &txn, wfds_gen_resp_msg_v01_ei,
140 				    resp);
141 	if (QDF_IS_STATUS_ERROR(status)) {
142 		osif_info("QMI txn init failed for WFDS config message %d",
143 			  status);
144 		goto out;
145 	}
146 
147 	status = os_if_qmi_send_request(&qmi_wfds, NULL, &txn,
148 					QMI_WFDS_CONFIG_REQ_V01,
149 					WFDS_CONFIG_REQ_MSG_V01_MAX_MSG_LEN,
150 					wfds_config_req_msg_v01_ei, req);
151 	if (QDF_IS_STATUS_ERROR(status)) {
152 		osif_info("QMI WFDS config send request failed %d", status);
153 		os_if_qmi_txn_cancel(&txn);
154 		goto out;
155 	}
156 
157 	status = os_if_qmi_txn_wait(&txn, QMI_WFDS_TIMEOUT_JF);
158 	if (QDF_IS_STATUS_ERROR(status)) {
159 		osif_info("Wait for QMI WFDS config response timed out %d",
160 			  status);
161 		goto out;
162 	}
163 
164 	qdf_assert(resp->resp.result == QMI_RESULT_SUCCESS_V01);
165 
166 out:
167 	qdf_mem_free(resp);
168 	qdf_mem_free(req);
169 
170 	return status;
171 }
172 
173 /*
174  * os_if_qmi_wfds_send_req_mem_msg() - Send Request Memory message to QMI server
175  * @src_info: source information to be filled in QMI message
176  *
177  * Return: QDF status
178  */
179 static QDF_STATUS
os_if_qmi_wfds_send_req_mem_msg(struct wlan_qmi_wfds_mem_req_msg * src_info)180 os_if_qmi_wfds_send_req_mem_msg(struct wlan_qmi_wfds_mem_req_msg *src_info)
181 {
182 	struct wfds_mem_req_msg_v01 *req;
183 	struct wfds_gen_resp_msg_v01 *resp;
184 	struct qmi_txn txn;
185 	QDF_STATUS status;
186 	uint8_t i;
187 	uint16_t j;
188 
189 	req = qdf_mem_malloc(sizeof(*req));
190 	if (!req)
191 		return QDF_STATUS_E_NOMEM;
192 
193 	resp = qdf_mem_malloc(sizeof(*resp));
194 	if (!resp) {
195 		qdf_mem_free(req);
196 		return QDF_STATUS_E_NOMEM;
197 	}
198 
199 	if (src_info->mem_arena_page_info_len > QMI_WFDS_MEM_ARENA_MAX) {
200 		status = QDF_STATUS_E_INVAL;
201 		goto out;
202 	}
203 
204 	req->mem_arena_page_info_len = src_info->mem_arena_page_info_len;
205 	for (i = 0; i < req->mem_arena_page_info_len; i++) {
206 		req->mem_arena_page_info[i].num_entries_per_page =
207 			src_info->mem_arena_page_info[i].num_entries_per_page;
208 		req->mem_arena_page_info[i].page_dma_addr_len =
209 			src_info->mem_arena_page_info[i].page_dma_addr_len;
210 
211 		if (src_info->mem_arena_page_info[i].page_dma_addr_len >
212 		    QMI_WFDS_PAGE_INFO_ARRAY_MAX_SIZE) {
213 			status = QDF_STATUS_E_INVAL;
214 			goto out;
215 		}
216 
217 		for (j = 0; j < req->mem_arena_page_info[i].page_dma_addr_len;
218 		     j++)
219 			req->mem_arena_page_info[i].page_dma_addr[j] =
220 			      src_info->mem_arena_page_info[i].page_dma_addr[j];
221 	}
222 
223 	status = os_if_qmi_txn_init(&qmi_wfds, &txn, wfds_gen_resp_msg_v01_ei,
224 				    resp);
225 	if (QDF_IS_STATUS_ERROR(status)) {
226 		osif_info("QMI txn init failed for WFDS mem req message %d",
227 			  status);
228 		goto out;
229 	}
230 
231 	status = os_if_qmi_send_request(&qmi_wfds, NULL, &txn,
232 					QMI_WFDS_MEM_REQ_V01,
233 					WFDS_MEM_REQ_MSG_V01_MAX_MSG_LEN,
234 					wfds_mem_req_msg_v01_ei, req);
235 	if (QDF_IS_STATUS_ERROR(status)) {
236 		osif_info("QMI WFDS mem request send failed %d", status);
237 		os_if_qmi_txn_cancel(&txn);
238 		goto out;
239 	}
240 
241 	status = os_if_qmi_txn_wait(&txn, QMI_WFDS_TIMEOUT_JF);
242 	if (QDF_IS_STATUS_ERROR(status)) {
243 		osif_info("Wait for QMI WFDS mem response timed out %d",
244 			  status);
245 		goto out;
246 	}
247 
248 	qdf_assert(resp->resp.result == QMI_RESULT_SUCCESS_V01);
249 
250 out:
251 	qdf_mem_free(resp);
252 	qdf_mem_free(req);
253 
254 	return status;
255 }
256 
257 /*
258  * os_if_qmi_wfds_send_misc_req_msg() - Send misc req message to QMI server
259  * @is_ssr: true if SSR is in progress else false
260  *
261  * Return: QDF status
262  */
263 static QDF_STATUS
os_if_qmi_wfds_send_misc_req_msg(bool is_ssr)264 os_if_qmi_wfds_send_misc_req_msg(bool is_ssr)
265 {
266 	struct wfds_misc_req_msg_v01 *req;
267 	struct wfds_gen_resp_msg_v01 *resp;
268 	struct qmi_txn txn;
269 	QDF_STATUS status;
270 
271 	req = qdf_mem_malloc(sizeof(*req));
272 	if (!req)
273 		return QDF_STATUS_E_NOMEM;
274 
275 	resp = qdf_mem_malloc(sizeof(*resp));
276 	if (!resp) {
277 		qdf_mem_free(req);
278 		return QDF_STATUS_E_NOMEM;
279 	}
280 
281 	req->event = (is_ssr) ? WFDS_EVENT_WLAN_SSR_V01 :
282 			WFDS_EVENT_WLAN_HOST_RMMOD_V01;
283 
284 	status = os_if_qmi_txn_init(&qmi_wfds, &txn, wfds_gen_resp_msg_v01_ei,
285 				    resp);
286 	if (QDF_IS_STATUS_ERROR(status)) {
287 		osif_info("QMI txn for WFDS misc request failed %d",
288 			  status);
289 		goto out;
290 	}
291 
292 	status = os_if_qmi_send_request(&qmi_wfds, NULL, &txn,
293 					QMI_WFDS_MISC_REQ_V01,
294 					WFDS_MISC_REQ_MSG_V01_MAX_MSG_LEN,
295 					wfds_misc_req_msg_v01_ei, req);
296 	if (QDF_IS_STATUS_ERROR(status)) {
297 		osif_info("QMI WFDS misc request send failed %d", status);
298 		os_if_qmi_txn_cancel(&txn);
299 		goto out;
300 	}
301 
302 	status = os_if_qmi_txn_wait(&txn, QMI_WFDS_TIMEOUT_JF);
303 	if (QDF_IS_STATUS_ERROR(status)) {
304 		osif_info("Failed to wait for WFDS misc response %d", status);
305 		goto out;
306 	}
307 
308 	qdf_assert(resp->resp.result == QMI_RESULT_SUCCESS_V01);
309 
310 out:
311 	qdf_mem_free(resp);
312 	qdf_mem_free(req);
313 
314 	return status;
315 }
316 
317 /*
318  * os_if_srng_dir_qmi_to_wfds_type() - Convert status from internal
319  *  type to type used in QMI message
320  * @status: internal status
321  *
322  * Return: status in QMI type
323  */
324 static uint8_t
os_if_status_qmi_to_wfds_type(enum wlan_qmi_wfds_status status)325 os_if_status_qmi_to_wfds_type(enum wlan_qmi_wfds_status status)
326 {
327 	switch (status) {
328 	case QMI_WFDS_STATUS_SUCCESS:
329 		return QMI_RESULT_SUCCESS_V01;
330 	case QMI_WFDS_STATUS_FAILURE:
331 	default:
332 		return QMI_RESULT_FAILURE_V01;
333 	}
334 }
335 
336 /*
337  * os_if_qmi_wfds_ipcc_map_n_cfg_msg() - Send the IPCC map and configure message
338  *  to QMI server
339  * @src_info: source information to be filled in QMI message
340  *
341  * Return: QDF status
342  */
343 static QDF_STATUS
os_if_qmi_wfds_ipcc_map_n_cfg_msg(struct wlan_qmi_wfds_ipcc_map_n_cfg_req_msg * src_info)344 os_if_qmi_wfds_ipcc_map_n_cfg_msg(struct wlan_qmi_wfds_ipcc_map_n_cfg_req_msg *src_info)
345 {
346 	struct wfds_ipcc_map_n_cfg_req_msg_v01 *req;
347 	struct wfds_gen_resp_msg_v01 *resp;
348 	struct qmi_txn txn;
349 	QDF_STATUS status;
350 
351 	req = qdf_mem_malloc(sizeof(*req));
352 	if (!req)
353 		return QDF_STATUS_E_NOMEM;
354 
355 	resp = qdf_mem_malloc(sizeof(*resp));
356 	if (!resp) {
357 		qdf_mem_free(req);
358 		return QDF_STATUS_E_NOMEM;
359 	}
360 
361 	req->status = os_if_status_qmi_to_wfds_type(src_info->status);
362 
363 	status = os_if_qmi_txn_init(&qmi_wfds, &txn, wfds_gen_resp_msg_v01_ei,
364 				    resp);
365 	if (QDF_IS_STATUS_ERROR(status)) {
366 		osif_info("QMI txn init failed for WFDS ipcc cfg req message %d",
367 			  status);
368 		goto out;
369 	}
370 
371 	status = os_if_qmi_send_request(&qmi_wfds, NULL, &txn,
372 				    QMI_WFDS_IPCC_MAP_N_CFG_REQ_V01,
373 				    WFDS_IPCC_MAP_N_CFG_REQ_MSG_V01_MAX_MSG_LEN,
374 				    wfds_ipcc_map_n_cfg_req_msg_v01_ei, req);
375 	if (QDF_IS_STATUS_ERROR(status)) {
376 		osif_info("QMI WFDS IPCC cfg request send failed %d", status);
377 		os_if_qmi_txn_cancel(&txn);
378 		goto out;
379 	}
380 
381 	status = os_if_qmi_txn_wait(&txn, QMI_WFDS_TIMEOUT_JF);
382 	if (QDF_IS_STATUS_ERROR(status)) {
383 		osif_info("Wait for QMI WFDS IPCC response timed out %d",
384 			  status);
385 		goto out;
386 	}
387 
388 	qdf_assert(resp->resp.result == QMI_RESULT_SUCCESS_V01);
389 
390 out:
391 	qdf_mem_free(resp);
392 	qdf_mem_free(req);
393 
394 	return status;
395 }
396 
397 /*
398  * os_if_qmi_wfds_request_mem_ind_cb() - Process request memory indication
399  *  received from QMI server
400  * @qmi_hdl: QMI handle
401  * @sq: pointer to QRTR sock address
402  * @qmi_txn: pointer to QMI transaction
403  * @data: pointer to QMI data
404  *
405  * Return: None
406  */
os_if_qmi_wfds_request_mem_ind_cb(struct qmi_handle * qmi_hdl,struct sockaddr_qrtr * sq,struct qmi_txn * qmi_txn,const void * data)407 static void os_if_qmi_wfds_request_mem_ind_cb(struct qmi_handle *qmi_hdl,
408 					      struct sockaddr_qrtr *sq,
409 					      struct qmi_txn *qmi_txn,
410 					      const void *data)
411 {
412 	struct wfds_mem_ind_msg_v01 *src_info =
413 				(struct wfds_mem_ind_msg_v01 *)data;
414 	struct wlan_qmi_wfds_mem_ind_msg mem_ind_msg = {0};
415 	uint8_t i;
416 
417 	if (!qmi_hdl || !qmi_txn)
418 		return;
419 
420 	if (src_info->mem_arena_info_len > QMI_WFDS_MEM_ARENA_MAX) {
421 		osif_info("Memory arena information array size %d exceeds max length",
422 			  src_info->mem_arena_info_len);
423 		return;
424 	}
425 
426 	mem_ind_msg.mem_arena_info_len = src_info->mem_arena_info_len;
427 	for (i = 0; i < src_info->mem_arena_info_len; i++) {
428 		mem_ind_msg.mem_arena_info[i].entry_size =
429 				src_info->mem_arena_info[i].entry_size;
430 		mem_ind_msg.mem_arena_info[i].num_entries =
431 				src_info->mem_arena_info[i].num_entries;
432 	}
433 
434 	ucfg_dp_wfds_handle_request_mem_ind(&mem_ind_msg);
435 }
436 
437 /*
438  * os_if_wfds_ipcc_map_n_cfg_ind_cb() - Process IPCC map and configure
439  *  indication received from QMI server
440  * @qmi_hdl: QMI handle
441  * @sq: pointer to QRTR sock address
442  * @qmi_txn: pointer to QMI transaction
443  * @data: pointer to QMI data
444  *
445  * Return: None
446  */
os_if_wfds_ipcc_map_n_cfg_ind_cb(struct qmi_handle * qmi_hdl,struct sockaddr_qrtr * sq,struct qmi_txn * qmi_txn,const void * data)447 static void os_if_wfds_ipcc_map_n_cfg_ind_cb(struct qmi_handle *qmi_hdl,
448 					     struct sockaddr_qrtr *sq,
449 					     struct qmi_txn *qmi_txn,
450 					     const void *data)
451 {
452 	struct wfds_ipcc_map_n_cfg_ind_msg_v01 *src_info =
453 		(struct wfds_ipcc_map_n_cfg_ind_msg_v01 *)data;
454 	struct wlan_qmi_wfds_ipcc_map_n_cfg_ind_msg ipcc_ind_msg = {0};
455 	uint8_t i;
456 
457 	if (!qmi_hdl || !qmi_txn)
458 		return;
459 
460 	if (src_info->ipcc_ce_info_len > QMI_WFDS_CE_MAX_SRNG) {
461 		osif_info("IPCC CE information array size %d exceeds max length",
462 			  src_info->ipcc_ce_info_len);
463 		return;
464 	}
465 
466 	ipcc_ind_msg.ipcc_ce_info_len = src_info->ipcc_ce_info_len;
467 	for (i = 0; i < src_info->ipcc_ce_info_len; i++) {
468 		ipcc_ind_msg.ipcc_ce_info[i].ce_id =
469 				src_info->ipcc_ce_info[i].ce_id;
470 		ipcc_ind_msg.ipcc_ce_info[i].ipcc_trig_addr =
471 				src_info->ipcc_ce_info[i].ipcc_trig_addr;
472 		ipcc_ind_msg.ipcc_ce_info[i].ipcc_trig_data =
473 				src_info->ipcc_ce_info[i].ipcc_trig_data;
474 	}
475 
476 	ucfg_dp_wfds_handle_ipcc_map_n_cfg_ind(&ipcc_ind_msg);
477 }
478 
479 QDF_STATUS
os_if_qmi_wfds_send_ut_cmd_req_msg(struct os_if_qmi_wfds_ut_cmd_info * cmd_info)480 os_if_qmi_wfds_send_ut_cmd_req_msg(struct os_if_qmi_wfds_ut_cmd_info *cmd_info)
481 {
482 	struct wfds_ut_cmd_req_msg_v01 *req;
483 	struct wfds_gen_resp_msg_v01 *resp;
484 	struct qmi_txn txn;
485 	QDF_STATUS status;
486 	int i;
487 
488 	req = qdf_mem_malloc(sizeof(*req));
489 	if (!req)
490 		return QDF_STATUS_E_NOMEM;
491 
492 	resp = qdf_mem_malloc(sizeof(*resp));
493 	if (!resp) {
494 		qdf_mem_free(req);
495 		return QDF_STATUS_E_NOMEM;
496 	}
497 
498 	req->cmd = (enum wifi_drv_qmi_ut_cmd_v01)cmd_info->cmd;
499 	req->duration = cmd_info->duration;
500 	req->flush_period = cmd_info->flush_period;
501 	req->num_pkts = cmd_info->num_pkts;
502 	req->buf_size = cmd_info->buf_size;
503 	req->ether_type = cmd_info->ether_type;
504 	for (i = 0; i < QDF_MAC_ADDR_SIZE; i++) {
505 		req->src_mac[i] = cmd_info->src_mac.bytes[i];
506 		req->dest_mac[i] = cmd_info->dest_mac.bytes[i];
507 	}
508 
509 	if (cmd_info->cmd == WFDS_START_WHC) {
510 		for (i = 0; i < QDF_IPV4_ADDR_SIZE; i++) {
511 			req->src_ip_addr[i] = cmd_info->src_ip.bytes[i];
512 			req->dest_ip_addr[i] = cmd_info->dest_ip.bytes[i];
513 		}
514 
515 		req->dest_port = cmd_info->dest_port;
516 	}
517 
518 	osif_debug("cmd: %u for duration: %u s, flush period: %u ms",
519 		  req->cmd, req->duration, req->flush_period);
520 
521 	status = os_if_qmi_txn_init(&qmi_wfds, &txn, wfds_gen_resp_msg_v01_ei,
522 				    resp);
523 	if (QDF_IS_STATUS_ERROR(status)) {
524 		osif_info("QMI txn for WFDS unit test cmd init failed %d",
525 			  status);
526 		goto out;
527 	}
528 
529 	status = os_if_qmi_send_request(&qmi_wfds, NULL, &txn,
530 					QMI_WFDS_UT_CMD_REQ_V01,
531 					WFDS_UT_CMD_REQ_MSG_V01_MAX_MSG_LEN,
532 					wfds_ut_cmd_req_msg_v01_ei, req);
533 	if (QDF_IS_STATUS_ERROR(status)) {
534 		osif_info("QMI WFDS UT command request send failed %d",
535 			  status);
536 		os_if_qmi_txn_cancel(&txn);
537 		goto out;
538 	}
539 
540 	status = os_if_qmi_txn_wait(&txn, QMI_WFDS_TIMEOUT_JF);
541 	if (QDF_IS_STATUS_ERROR(status)) {
542 		osif_info("Wait for unit test cmd response timed out %d",
543 			  status);
544 		goto out;
545 	}
546 
547 	qdf_assert(resp->resp.result == QMI_RESULT_SUCCESS_V01);
548 
549 out:
550 	qdf_mem_free(resp);
551 	qdf_mem_free(req);
552 
553 	return status;
554 }
555 
556 /**
557  * os_if_qmi_wfds_new_server() - New server callback triggered when service is
558  *  up.
559  * @qmi_hdl: QMI client handle
560  * @qmi_svc: QMI service handle
561  *
562  * Returns: 0 on success else OS failure code
563  */
564 static int
os_if_qmi_wfds_new_server(struct qmi_handle * qmi_hdl,struct qmi_service * qmi_svc)565 os_if_qmi_wfds_new_server(struct qmi_handle *qmi_hdl,
566 			  struct qmi_service *qmi_svc)
567 {
568 	QDF_STATUS status;
569 
570 	status = os_if_qmi_connect_to_svc(qmi_hdl, qmi_svc);
571 	if (QDF_IS_STATUS_ERROR(status)) {
572 		osif_err("Failed to connect to WFDS QMI service port");
573 		return qdf_status_to_os_return(status);
574 	}
575 
576 	status = ucfg_dp_wfds_new_server();
577 
578 	return qdf_status_to_os_return(status);
579 }
580 
581 /**
582  * os_if_qmi_wfds_del_server() - Del server callback triggered when service is
583  *  down.
584  * @qmi_hdl: QMI client handle
585  * @qmi_svc: QMI service handle
586  *
587  * Returns: None
588  */
589 static void
os_if_qmi_wfds_del_server(struct qmi_handle * qmi_hdl,struct qmi_service * qmi_svc)590 os_if_qmi_wfds_del_server(struct qmi_handle *qmi_hdl,
591 			  struct qmi_service *qmi_svc)
592 {
593 	ucfg_dp_wfds_del_server();
594 }
595 
596 static struct qmi_msg_handler qmi_wfds_msg_handler[] = {
597 	{
598 		.type = QMI_INDICATION,
599 		.msg_id = QMI_WFDS_MEM_IND_V01,
600 		.ei = wfds_mem_ind_msg_v01_ei,
601 		.decoded_size = sizeof(struct wfds_mem_ind_msg_v01),
602 		.fn = os_if_qmi_wfds_request_mem_ind_cb
603 	},
604 	{
605 		.type = QMI_INDICATION,
606 		.msg_id = QMI_WFDS_IPCC_MAP_N_CFG_IND_V01,
607 		.ei = wfds_ipcc_map_n_cfg_ind_msg_v01_ei,
608 		.decoded_size = sizeof(struct wfds_ipcc_map_n_cfg_ind_msg_v01),
609 		.fn = os_if_wfds_ipcc_map_n_cfg_ind_cb
610 	},
611 };
612 
613 static struct qmi_ops qmi_wfds_ops = {
614 	.new_server = os_if_qmi_wfds_new_server,
615 	.del_server = os_if_qmi_wfds_del_server,
616 };
617 
618 /**
619  * os_if_qmi_wfds_init() - Initialize WFDS QMI client
620  *
621  * Returns: QDF status
622  */
os_if_qmi_wfds_init(void)623 static QDF_STATUS os_if_qmi_wfds_init(void)
624 {
625 	QDF_STATUS status;
626 
627 	status = os_if_qmi_handle_init(&qmi_wfds, QMI_WFDS_MAX_RECV_BUF_SIZE,
628 				       &qmi_wfds_ops, qmi_wfds_msg_handler);
629 	if (QDF_IS_STATUS_ERROR(status)) {
630 		osif_err("WFDS QMI handle init failed");
631 		return status;
632 	}
633 
634 	status = os_if_qmi_add_lookup(&qmi_wfds, WFDS_SERVICE_ID_V01,
635 				      WFDS_SERVICE_VERS_V01,
636 				      QMI_WFDS_SERVICE_INS_ID_V01);
637 	if (QDF_IS_STATUS_ERROR(status)) {
638 		osif_err("WFDS QMI add lookup failed");
639 		os_if_qmi_handle_release(&qmi_wfds);
640 		return status;
641 	}
642 
643 	return status;
644 }
645 
646 /**
647  * os_if_qmi_wfds_deinit() - Deinitialize WFDS QMI client
648  *
649  * Returns: None
650  */
os_if_qmi_wfds_deinit(void)651 static void os_if_qmi_wfds_deinit(void)
652 {
653 	os_if_qmi_handle_release(&qmi_wfds);
654 }
655 
os_if_qmi_wfds_register_callbacks(struct wlan_qmi_psoc_callbacks * cb_obj)656 void os_if_qmi_wfds_register_callbacks(struct wlan_qmi_psoc_callbacks *cb_obj)
657 {
658 	cb_obj->qmi_wfds_init = os_if_qmi_wfds_init;
659 	cb_obj->qmi_wfds_deinit = os_if_qmi_wfds_deinit;
660 	cb_obj->qmi_wfds_send_config_msg = os_if_qmi_wfds_send_config_msg;
661 	cb_obj->qmi_wfds_send_req_mem_msg = os_if_qmi_wfds_send_req_mem_msg;
662 	cb_obj->qmi_wfds_send_ipcc_map_n_cfg_msg =
663 					os_if_qmi_wfds_ipcc_map_n_cfg_msg;
664 	cb_obj->qmi_wfds_send_misc_req_msg =
665 					os_if_qmi_wfds_send_misc_req_msg;
666 }
667