1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
4 * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
5 */
6
7 #define pr_fmt(fmt) "icnss2_qmi: " fmt
8
9 #include <linux/export.h>
10 #include <linux/err.h>
11 #include <linux/of.h>
12 #include <linux/init.h>
13 #include <linux/io.h>
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/etherdevice.h>
17 #include <linux/seq_file.h>
18 #include <linux/slab.h>
19 #include <linux/delay.h>
20 #include <linux/ipc_logging.h>
21 #include <linux/thread_info.h>
22 #include <linux/firmware.h>
23 #include <linux/soc/qcom/qmi.h>
24 #include <linux/platform_device.h>
25 #ifdef CONFIG_CNSS_OUT_OF_TREE
26 #include "icnss2.h"
27 #else
28 #include <soc/qcom/icnss2.h>
29 #endif
30 #include <soc/qcom/of_common.h>
31 #include "wlan_firmware_service_v01.h"
32 #include "main.h"
33 #include "qmi.h"
34 #include "debug.h"
35 #include "genl.h"
36
37 #define WLFW_SERVICE_WCN_INS_ID_V01 3
38 #define WLFW_SERVICE_INS_ID_V01 0
39 #define WLFW_CLIENT_ID 0x4b4e454c
40 #define QMI_ERR_PLAT_CCPM_CLK_INIT_FAILED 0x77
41
42 #define BDF_FILE_NAME_PREFIX "bdwlan"
43 #define ELF_BDF_FILE_NAME "bdwlan.elf"
44 #define ELF_BDF_FILE_NAME_PREFIX "bdwlan.e"
45 #define BIN_BDF_FILE_NAME "bdwlan.bin"
46 #define BIN_BDF_FILE_NAME_PREFIX "bdwlan."
47 #define REGDB_FILE_NAME "regdb.bin"
48
49 #define QDSS_TRACE_CONFIG_FILE "qdss_trace_config.cfg"
50
51 #define WLAN_BOARD_ID_INDEX 0x100
52 #define DEVICE_BAR_SIZE 0x200000
53 #define M3_SEGMENT_ADDR_MASK 0xFFFFFFFF
54 #define DMS_QMI_MAX_MSG_LEN SZ_256
55 #define DMS_MAC_NOT_PROVISIONED 16
56 #define BDWLAN_SIZE 6
57 #define UMC_CHIP_ID 0x4320
58 #define MAX_SHADOW_REG_RESERVED 2
59 #define MAX_NUM_SHADOW_REG_V3 (QMI_WLFW_MAX_NUM_SHADOW_REG_V3_USAGE_V01 - \
60 MAX_SHADOW_REG_RESERVED)
61 #define IMSPRIVATE_SERVICE_MAX_MSG_LEN SZ_8K
62
63 #ifdef CONFIG_ICNSS2_DEBUG
64 bool ignore_fw_timeout;
65 #define ICNSS_QMI_ASSERT() ICNSS_ASSERT(ignore_fw_timeout)
66 #else
67 #define ICNSS_QMI_ASSERT() do { } while (0)
68 #endif
69
70 #ifdef CONFIG_ICNSS2_DEBUG
icnss_ignore_fw_timeout(bool ignore)71 void icnss_ignore_fw_timeout(bool ignore)
72 {
73 ignore_fw_timeout = ignore;
74 }
75 #else
icnss_ignore_fw_timeout(bool ignore)76 void icnss_ignore_fw_timeout(bool ignore) { }
77 #endif
78
79 #define icnss_qmi_fatal_err(_fmt, ...) do { \
80 icnss_pr_err("fatal: "_fmt, ##__VA_ARGS__); \
81 ICNSS_QMI_ASSERT(); \
82 } while (0)
83
wlfw_msa_mem_info_send_sync_msg(struct icnss_priv * priv)84 int wlfw_msa_mem_info_send_sync_msg(struct icnss_priv *priv)
85 {
86 int ret;
87 int i;
88 struct wlfw_msa_info_req_msg_v01 *req;
89 struct wlfw_msa_info_resp_msg_v01 *resp;
90 struct qmi_txn txn;
91 uint64_t max_mapped_addr;
92
93 if (!priv)
94 return -ENODEV;
95
96 icnss_pr_dbg("Sending MSA mem info, state: 0x%lx\n", priv->state);
97
98 req = kzalloc(sizeof(*req), GFP_KERNEL);
99 if (!req)
100 return -ENOMEM;
101
102 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
103 if (!resp) {
104 kfree(req);
105 return -ENOMEM;
106 }
107
108 req->msa_addr = priv->msa_pa;
109 req->size = priv->msa_mem_size;
110
111 priv->stats.msa_info_req++;
112
113 ret = qmi_txn_init(&priv->qmi, &txn,
114 wlfw_msa_info_resp_msg_v01_ei, resp);
115 if (ret < 0) {
116 icnss_qmi_fatal_err(
117 "Fail to init txn for MSA Mem info resp %d\n",
118 ret);
119 goto out;
120 }
121
122 ret = qmi_send_request(&priv->qmi, NULL, &txn,
123 QMI_WLFW_MSA_INFO_REQ_V01,
124 WLFW_MSA_INFO_REQ_MSG_V01_MAX_MSG_LEN,
125 wlfw_msa_info_req_msg_v01_ei, req);
126 if (ret < 0) {
127 qmi_txn_cancel(&txn);
128 icnss_qmi_fatal_err("Fail to send MSA Mem info req %d\n", ret);
129 goto out;
130 }
131
132 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
133 if (ret < 0) {
134 icnss_qmi_fatal_err("MSA Mem info resp wait failed ret %d\n",
135 ret);
136 goto out;
137 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
138 icnss_qmi_fatal_err(
139 "QMI MSA Mem info request rejected, result:%d error:%d\n",
140 resp->resp.result, resp->resp.error);
141 ret = -resp->resp.result;
142 goto out;
143 }
144
145 icnss_pr_dbg("Receive mem_region_info_len: %d\n",
146 resp->mem_region_info_len);
147
148 if (resp->mem_region_info_len > QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01) {
149 icnss_qmi_fatal_err(
150 "Invalid memory region length received: %d\n",
151 resp->mem_region_info_len);
152 ret = -EINVAL;
153 goto out;
154 }
155
156 max_mapped_addr = priv->msa_pa + priv->msa_mem_size;
157 priv->stats.msa_info_resp++;
158 priv->nr_mem_region = resp->mem_region_info_len;
159 for (i = 0; i < resp->mem_region_info_len; i++) {
160
161 if (resp->mem_region_info[i].size > priv->msa_mem_size ||
162 resp->mem_region_info[i].region_addr >= max_mapped_addr ||
163 resp->mem_region_info[i].region_addr < priv->msa_pa ||
164 resp->mem_region_info[i].size +
165 resp->mem_region_info[i].region_addr > max_mapped_addr) {
166 icnss_pr_dbg("Received out of range Addr: 0x%llx Size: 0x%x\n",
167 resp->mem_region_info[i].region_addr,
168 resp->mem_region_info[i].size);
169 ret = -EINVAL;
170 goto fail_unwind;
171 }
172
173 priv->mem_region[i].reg_addr =
174 resp->mem_region_info[i].region_addr;
175 priv->mem_region[i].size =
176 resp->mem_region_info[i].size;
177 priv->mem_region[i].secure_flag =
178 resp->mem_region_info[i].secure_flag;
179 icnss_pr_dbg("Memory Region: %d Addr: 0x%llx Size: 0x%x Flag: 0x%08x\n",
180 i, priv->mem_region[i].reg_addr,
181 priv->mem_region[i].size,
182 priv->mem_region[i].secure_flag);
183 }
184
185 kfree(resp);
186 kfree(req);
187 return 0;
188
189 fail_unwind:
190 memset(&priv->mem_region[0], 0, sizeof(priv->mem_region[0]) * i);
191 out:
192 kfree(resp);
193 kfree(req);
194 priv->stats.msa_info_err++;
195 return ret;
196 }
197
wlfw_msa_ready_send_sync_msg(struct icnss_priv * priv)198 int wlfw_msa_ready_send_sync_msg(struct icnss_priv *priv)
199 {
200 int ret;
201 struct wlfw_msa_ready_req_msg_v01 *req;
202 struct wlfw_msa_ready_resp_msg_v01 *resp;
203 struct qmi_txn txn;
204
205 if (!priv)
206 return -ENODEV;
207
208 icnss_pr_dbg("Sending MSA ready request message, state: 0x%lx\n",
209 priv->state);
210
211 req = kzalloc(sizeof(*req), GFP_KERNEL);
212 if (!req)
213 return -ENOMEM;
214
215 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
216 if (!resp) {
217 kfree(req);
218 return -ENOMEM;
219 }
220
221 priv->stats.msa_ready_req++;
222
223 ret = qmi_txn_init(&priv->qmi, &txn,
224 wlfw_msa_ready_resp_msg_v01_ei, resp);
225 if (ret < 0) {
226 icnss_qmi_fatal_err(
227 "Fail to init txn for MSA Mem Ready resp %d\n",
228 ret);
229 goto out;
230 }
231
232 ret = qmi_send_request(&priv->qmi, NULL, &txn,
233 QMI_WLFW_MSA_READY_REQ_V01,
234 WLFW_MSA_READY_REQ_MSG_V01_MAX_MSG_LEN,
235 wlfw_msa_ready_req_msg_v01_ei, req);
236 if (ret < 0) {
237 qmi_txn_cancel(&txn);
238 icnss_qmi_fatal_err("Fail to send MSA Mem Ready req %d\n", ret);
239 goto out;
240 }
241
242 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
243 if (ret < 0) {
244 icnss_qmi_fatal_err(
245 "MSA Mem Ready resp wait failed with ret %d\n",
246 ret);
247 goto out;
248 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
249 icnss_qmi_fatal_err(
250 "QMI MSA Mem Ready request rejected, result:%d error:%d\n",
251 resp->resp.result, resp->resp.error);
252 ret = -resp->resp.result;
253 goto out;
254 }
255
256 priv->stats.msa_ready_resp++;
257
258 kfree(resp);
259 kfree(req);
260 return 0;
261
262 out:
263 kfree(resp);
264 kfree(req);
265 priv->stats.msa_ready_err++;
266 return ret;
267 }
268
wlfw_device_info_send_msg(struct icnss_priv * priv)269 int wlfw_device_info_send_msg(struct icnss_priv *priv)
270 {
271 int ret;
272 struct wlfw_device_info_req_msg_v01 *req;
273 struct wlfw_device_info_resp_msg_v01 *resp;
274 struct qmi_txn txn;
275
276 if (!priv)
277 return -ENODEV;
278
279 icnss_pr_dbg("Sending Device Info request message, state: 0x%lx\n",
280 priv->state);
281
282 req = kzalloc(sizeof(*req), GFP_KERNEL);
283 if (!req)
284 return -ENOMEM;
285
286 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
287 if (!resp) {
288 kfree(req);
289 return -ENOMEM;
290 }
291
292 priv->stats.device_info_req++;
293
294 ret = qmi_txn_init(&priv->qmi, &txn,
295 wlfw_device_info_resp_msg_v01_ei, resp);
296 if (ret < 0) {
297 icnss_qmi_fatal_err(
298 "Fail to init txn for Device Info resp %d\n",
299 ret);
300 goto out;
301 }
302
303 ret = qmi_send_request(&priv->qmi, NULL, &txn,
304 QMI_WLFW_DEVICE_INFO_REQ_V01,
305 WLFW_DEVICE_INFO_REQ_MSG_V01_MAX_MSG_LEN,
306 wlfw_device_info_req_msg_v01_ei, req);
307 if (ret < 0) {
308 qmi_txn_cancel(&txn);
309 icnss_qmi_fatal_err("Fail to send device info req %d\n", ret);
310 goto out;
311 }
312
313 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
314 if (ret < 0) {
315 icnss_qmi_fatal_err(
316 "Device Info resp wait failed with ret %d\n",
317 ret);
318 goto out;
319 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
320 icnss_qmi_fatal_err(
321 "QMI Device info request rejected, result:%d error:%d\n",
322 resp->resp.result, resp->resp.error);
323 ret = -resp->resp.result;
324 goto out;
325 }
326
327 priv->stats.device_info_resp++;
328
329 if (resp->bar_addr_valid)
330 priv->mem_base_pa = resp->bar_addr;
331
332 if (resp->bar_size_valid)
333 priv->mem_base_size = resp->bar_size;
334
335 if (!priv->mem_base_pa) {
336 ret = -EINVAL;
337 icnss_qmi_fatal_err("Fail to get bar address\n");
338 goto out;
339 }
340
341 if (priv->mem_base_size < DEVICE_BAR_SIZE) {
342 ret = -EINVAL;
343 icnss_qmi_fatal_err("Bar size is not proper 0x%x\n",
344 priv->mem_base_size);
345 goto out;
346 }
347
348 if (resp->mhi_state_info_addr_valid)
349 priv->mhi_state_info_pa = resp->mhi_state_info_addr;
350
351 if (resp->mhi_state_info_size_valid)
352 priv->mhi_state_info_size = resp->mhi_state_info_size;
353
354 if (!priv->mhi_state_info_pa)
355 icnss_pr_err("Fail to get MHI info address\n");
356
357 kfree(resp);
358 kfree(req);
359 return 0;
360
361 out:
362 kfree(resp);
363 kfree(req);
364 priv->stats.device_info_err++;
365 return ret;
366 }
367
wlfw_power_save_send_msg(struct icnss_priv * priv,enum wlfw_power_save_mode_v01 mode)368 int wlfw_power_save_send_msg(struct icnss_priv *priv,
369 enum wlfw_power_save_mode_v01 mode)
370 {
371 int ret;
372 struct wlfw_power_save_req_msg_v01 *req;
373 struct qmi_txn txn;
374
375 if (!priv)
376 return -ENODEV;
377
378 if (test_bit(ICNSS_FW_DOWN, &priv->state))
379 return -EINVAL;
380
381 if (test_bit(ICNSS_PD_RESTART, &priv->state) ||
382 !test_bit(ICNSS_MODE_ON, &priv->state))
383 return 0;
384
385 icnss_pr_dbg("Sending power save mode: %d, state: 0x%lx\n",
386 mode, priv->state);
387
388 req = kzalloc(sizeof(*req), GFP_KERNEL);
389 if (!req)
390 return -ENOMEM;
391
392 req->power_save_mode_valid = 1;
393 req->power_save_mode = mode;
394
395 if (mode == WLFW_POWER_SAVE_EXIT_V01)
396 priv->stats.exit_power_save_req++;
397 else
398 priv->stats.enter_power_save_req++;
399
400 ret = qmi_txn_init(&priv->qmi, &txn,
401 NULL, NULL);
402 if (ret < 0) {
403 icnss_qmi_fatal_err("Fail to init txn for exit power save%d\n",
404 ret);
405 goto out;
406 }
407
408 ret = qmi_send_request(&priv->qmi, NULL, &txn,
409 QMI_WLFW_POWER_SAVE_REQ_V01,
410 WLFW_POWER_SAVE_REQ_MSG_V01_MAX_MSG_LEN,
411 wlfw_power_save_req_msg_v01_ei, req);
412 if (ret < 0) {
413 qmi_txn_cancel(&txn);
414 icnss_qmi_fatal_err("Fail to send exit power save req %d\n",
415 ret);
416 goto out;
417 }
418
419 qmi_txn_cancel(&txn);
420
421 if (mode == WLFW_POWER_SAVE_EXIT_V01)
422 priv->stats.exit_power_save_resp++;
423 else
424 priv->stats.enter_power_save_resp++;
425
426 kfree(req);
427 return 0;
428
429 out:
430 kfree(req);
431
432 if (mode == WLFW_POWER_SAVE_EXIT_V01)
433 priv->stats.exit_power_save_err++;
434 else
435 priv->stats.enter_power_save_err++;
436 return ret;
437 }
438
wlfw_send_soc_wake_msg(struct icnss_priv * priv,enum wlfw_soc_wake_enum_v01 type)439 int wlfw_send_soc_wake_msg(struct icnss_priv *priv,
440 enum wlfw_soc_wake_enum_v01 type)
441 {
442 int ret;
443 struct wlfw_soc_wake_req_msg_v01 *req;
444 struct wlfw_soc_wake_resp_msg_v01 *resp;
445 struct qmi_txn txn;
446
447 if (!priv)
448 return -ENODEV;
449
450 if (test_bit(ICNSS_FW_DOWN, &priv->state))
451 return -EINVAL;
452
453 icnss_pr_soc_wake("Sending soc wake msg, type: 0x%x\n",
454 type);
455
456 req = kzalloc(sizeof(*req), GFP_KERNEL);
457 if (!req)
458 return -ENOMEM;
459
460 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
461 if (!resp) {
462 kfree(req);
463 return -ENOMEM;
464 }
465 req->wake_valid = 1;
466 req->wake = type;
467
468 priv->stats.soc_wake_req++;
469
470 ret = qmi_txn_init(&priv->qmi, &txn,
471 wlfw_soc_wake_resp_msg_v01_ei, resp);
472
473 if (ret < 0) {
474 icnss_pr_err("Fail to init txn for wake msg resp %d\n",
475 ret);
476 goto out;
477 }
478
479 ret = qmi_send_request(&priv->qmi, NULL, &txn,
480 QMI_WLFW_SOC_WAKE_REQ_V01,
481 WLFW_SOC_WAKE_REQ_MSG_V01_MAX_MSG_LEN,
482 wlfw_soc_wake_req_msg_v01_ei, req);
483 if (ret < 0) {
484 qmi_txn_cancel(&txn);
485 icnss_pr_err("Fail to send soc wake msg %d\n", ret);
486 goto out;
487 }
488
489 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
490 if (ret < 0) {
491 icnss_qmi_fatal_err("SOC wake timed out with ret %d\n",
492 ret);
493 goto out;
494 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
495 icnss_qmi_fatal_err(
496 "SOC wake request rejected,result:%d error:%d\n",
497 resp->resp.result, resp->resp.error);
498 ret = -resp->resp.result;
499 goto out;
500 }
501
502 priv->stats.soc_wake_resp++;
503
504 kfree(resp);
505 kfree(req);
506 return 0;
507
508 out:
509 kfree(req);
510 kfree(resp);
511 priv->stats.soc_wake_err++;
512 return ret;
513 }
514
wlfw_ind_register_send_sync_msg(struct icnss_priv * priv)515 int wlfw_ind_register_send_sync_msg(struct icnss_priv *priv)
516 {
517 int ret;
518 struct wlfw_ind_register_req_msg_v01 *req;
519 struct wlfw_ind_register_resp_msg_v01 *resp;
520 struct qmi_txn txn;
521
522 if (!priv)
523 return -ENODEV;
524
525 icnss_pr_dbg("Sending indication register message, state: 0x%lx\n",
526 priv->state);
527
528 req = kzalloc(sizeof(*req), GFP_KERNEL);
529 if (!req)
530 return -ENOMEM;
531
532 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
533 if (!resp) {
534 kfree(req);
535 return -ENOMEM;
536 }
537
538 req->client_id_valid = 1;
539 req->client_id = WLFW_CLIENT_ID;
540 req->fw_ready_enable_valid = 1;
541 req->fw_ready_enable = 1;
542 req->pin_connect_result_enable_valid = 1;
543 req->pin_connect_result_enable = 1;
544
545 if (priv->device_id == ADRASTEA_DEVICE_ID) {
546 req->msa_ready_enable_valid = 1;
547 req->msa_ready_enable = 1;
548 if (test_bit(FW_REJUVENATE_ENABLE,
549 &priv->ctrl_params.quirks)) {
550 req->rejuvenate_enable_valid = 1;
551 req->rejuvenate_enable = 1;
552 }
553 } else if (priv->device_id == WCN6750_DEVICE_ID ||
554 priv->device_id == WCN6450_DEVICE_ID) {
555 req->fw_init_done_enable_valid = 1;
556 req->fw_init_done_enable = 1;
557 req->cal_done_enable_valid = 1;
558 req->cal_done_enable = 1;
559 req->qdss_trace_req_mem_enable_valid = 1;
560 req->qdss_trace_req_mem_enable = 1;
561 req->qdss_trace_save_enable_valid = 1;
562 req->qdss_trace_save_enable = 1;
563 req->qdss_trace_free_enable_valid = 1;
564 req->qdss_trace_free_enable = 1;
565 req->respond_get_info_enable_valid = 1;
566 req->respond_get_info_enable = 1;
567 req->m3_dump_upload_segments_req_enable_valid = 1;
568 req->m3_dump_upload_segments_req_enable = 1;
569 }
570
571 priv->stats.ind_register_req++;
572
573 ret = qmi_txn_init(&priv->qmi, &txn,
574 wlfw_ind_register_resp_msg_v01_ei, resp);
575 if (ret < 0) {
576 icnss_qmi_fatal_err(
577 "Fail to init txn for Ind Register resp %d\n",
578 ret);
579 goto out;
580 }
581
582 ret = qmi_send_request(&priv->qmi, NULL, &txn,
583 QMI_WLFW_IND_REGISTER_REQ_V01,
584 WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN,
585 wlfw_ind_register_req_msg_v01_ei, req);
586 if (ret < 0) {
587 qmi_txn_cancel(&txn);
588 icnss_qmi_fatal_err("Fail to send Ind Register req %d\n", ret);
589 goto out;
590 }
591
592 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
593 if (ret < 0) {
594 icnss_qmi_fatal_err(
595 "Ind Register resp wait failed with ret %d\n",
596 ret);
597 goto out;
598 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
599 icnss_qmi_fatal_err(
600 "QMI Ind Register request rejected, result:%d error:%d\n",
601 resp->resp.result, resp->resp.error);
602 ret = -resp->resp.result;
603 goto out;
604 }
605
606 priv->stats.ind_register_resp++;
607
608 if (resp->fw_status_valid &&
609 (resp->fw_status & QMI_WLFW_ALREADY_REGISTERED_V01)) {
610 ret = -EALREADY;
611 icnss_pr_dbg("WLFW already registered\n");
612 goto qmi_registered;
613 }
614
615 kfree(resp);
616 kfree(req);
617
618 return 0;
619
620 out:
621 priv->stats.ind_register_err++;
622 qmi_registered:
623 kfree(resp);
624 kfree(req);
625 return ret;
626 }
627
wlfw_cal_report_req(struct icnss_priv * priv)628 int wlfw_cal_report_req(struct icnss_priv *priv)
629 {
630 int ret;
631 struct wlfw_cal_report_req_msg_v01 *req;
632 struct wlfw_cal_report_resp_msg_v01 *resp;
633 struct qmi_txn txn;
634
635 if (!priv)
636 return -ENODEV;
637
638 if (test_bit(ICNSS_FW_DOWN, &priv->state))
639 return -EINVAL;
640
641 icnss_pr_info("Sending cal report request, state: 0x%lx\n",
642 priv->state);
643
644 req = kzalloc(sizeof(*req), GFP_KERNEL);
645 if (!req)
646 return -ENOMEM;
647
648 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
649 if (!resp) {
650 kfree(req);
651 return -ENOMEM;
652 }
653 req->meta_data_len = 0;
654
655 ret = qmi_txn_init(&priv->qmi, &txn,
656 wlfw_cal_report_resp_msg_v01_ei, resp);
657 if (ret < 0) {
658 icnss_qmi_fatal_err("Fail to init txn for cal report req %d\n",
659 ret);
660 goto out;
661 }
662
663 ret = qmi_send_request(&priv->qmi, NULL, &txn,
664 QMI_WLFW_CAL_REPORT_REQ_V01,
665 WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN,
666 wlfw_cal_report_req_msg_v01_ei, req);
667 if (ret < 0) {
668 qmi_txn_cancel(&txn);
669 icnss_qmi_fatal_err("Fail to send cal report req %d\n", ret);
670 goto out;
671 }
672
673 ret = qmi_txn_wait(&txn,
674 priv->ctrl_params.qmi_timeout);
675
676 if (ret < 0) {
677 icnss_qmi_fatal_err("Cal report wait failed with ret %d\n",
678 ret);
679 goto out;
680 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
681 icnss_qmi_fatal_err("QMI cal report request rejected, result:%d error:%d\n",
682 resp->resp.result, resp->resp.error);
683 ret = -resp->resp.result;
684 goto out;
685 }
686
687 kfree(resp);
688 kfree(req);
689
690 return 0;
691
692 out:
693 return ret;
694 }
695
wlfw_cap_send_sync_msg(struct icnss_priv * priv)696 int wlfw_cap_send_sync_msg(struct icnss_priv *priv)
697 {
698 int ret = 0, i = 0;
699 struct wlfw_cap_req_msg_v01 *req;
700 struct wlfw_cap_resp_msg_v01 *resp;
701 struct qmi_txn txn;
702
703 if (!priv)
704 return -ENODEV;
705
706 icnss_pr_dbg("Sending target capability message, state: 0x%lx\n",
707 priv->state);
708
709 req = kzalloc(sizeof(*req), GFP_KERNEL);
710 if (!req)
711 return -ENOMEM;
712
713 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
714 if (!resp) {
715 kfree(req);
716 return -ENOMEM;
717 }
718
719 priv->stats.cap_req++;
720
721 ret = qmi_txn_init(&priv->qmi, &txn, wlfw_cap_resp_msg_v01_ei, resp);
722 if (ret < 0) {
723 icnss_qmi_fatal_err("Fail to init txn for Capability resp %d\n",
724 ret);
725 goto out;
726 }
727
728 ret = qmi_send_request(&priv->qmi, NULL, &txn,
729 QMI_WLFW_CAP_REQ_V01,
730 WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN,
731 wlfw_cap_req_msg_v01_ei, req);
732 if (ret < 0) {
733 qmi_txn_cancel(&txn);
734 icnss_qmi_fatal_err("Fail to send Capability req %d\n", ret);
735 goto out;
736 }
737
738 ret = qmi_txn_wait(&txn,
739 priv->ctrl_params.qmi_timeout +
740 msecs_to_jiffies(priv->wlan_en_delay_ms));
741 if (ret < 0) {
742 icnss_qmi_fatal_err("Capability resp wait failed with ret %d\n",
743 ret);
744 goto out;
745 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
746 ret = -resp->resp.result;
747 if (resp->resp.error == QMI_ERR_PLAT_CCPM_CLK_INIT_FAILED) {
748 icnss_pr_err("RF card not present\n");
749 goto out;
750 }
751 icnss_qmi_fatal_err(
752 "QMI Capability request rejected, result:%d error:%d\n",
753 resp->resp.result, resp->resp.error);
754 goto out;
755 }
756
757 priv->stats.cap_resp++;
758
759 if (resp->chip_info_valid) {
760 priv->chip_info.chip_id = resp->chip_info.chip_id;
761 priv->chip_info.chip_family = resp->chip_info.chip_family;
762 }
763 if (resp->board_info_valid)
764 priv->board_id = resp->board_info.board_id;
765 else
766 priv->board_id = 0xFF;
767 if (resp->soc_info_valid)
768 priv->soc_id = resp->soc_info.soc_id;
769 if (resp->fw_version_info_valid) {
770 priv->fw_version_info.fw_version =
771 resp->fw_version_info.fw_version;
772 strlcpy(priv->fw_version_info.fw_build_timestamp,
773 resp->fw_version_info.fw_build_timestamp,
774 WLFW_MAX_TIMESTAMP_LEN + 1);
775 }
776
777 if (resp->dev_mem_info_valid) {
778 for (i = 0; i < QMI_WLFW_MAX_DEV_MEM_NUM_V01; i++) {
779 priv->dev_mem_info[i].start =
780 resp->dev_mem_info[i].start;
781 priv->dev_mem_info[i].size =
782 resp->dev_mem_info[i].size;
783 icnss_pr_info("Device memory info[%d]: start = 0x%llx, size = 0x%llx\n",
784 i, priv->dev_mem_info[i].start,
785 priv->dev_mem_info[i].size);
786 }
787 }
788
789 if (resp->voltage_mv_valid) {
790 priv->cpr_info.voltage = resp->voltage_mv;
791 icnss_pr_dbg("Voltage for CPR: %dmV\n",
792 priv->cpr_info.voltage);
793 icnss_update_cpr_info(priv);
794 }
795
796 if (resp->fw_build_id_valid)
797 strlcpy(priv->fw_build_id, resp->fw_build_id,
798 QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1);
799
800 if (resp->rd_card_chain_cap_valid) {
801 priv->rd_card_chain_cap = (enum icnss_rd_card_chain_cap)resp->rd_card_chain_cap;
802 if (resp->rd_card_chain_cap == WLFW_RD_CARD_CHAIN_CAP_1x1_V01)
803 priv->is_chain1_supported = false;
804 }
805
806 if (resp->foundry_name_valid)
807 priv->foundry_name = resp->foundry_name[0];
808 else if (resp->chip_info_valid && priv->chip_info.chip_id == UMC_CHIP_ID)
809 priv->foundry_name = 'u';
810
811 if (resp->he_channel_width_cap_valid)
812 priv->phy_he_channel_width_cap =
813 (enum icnss_phy_he_channel_width_cap)resp->he_channel_width_cap;
814
815 if (resp->phy_qam_cap_valid)
816 priv->phy_qam_cap = (enum icnss_phy_qam_cap)resp->phy_qam_cap;
817
818 if (resp->serial_id_valid) {
819 priv->serial_id = resp->serial_id;
820 icnss_pr_info("serial id 0x%x 0x%x\n",
821 resp->serial_id.serial_id_msb,
822 resp->serial_id.serial_id_lsb);
823 }
824
825 icnss_pr_dbg("Capability, chip_id: 0x%x, chip_family: 0x%x, board_id: 0x%x, soc_id: 0x%x",
826 priv->chip_info.chip_id, priv->chip_info.chip_family,
827 priv->board_id, priv->soc_id);
828
829 icnss_pr_dbg("fw_version: 0x%x, fw_build_timestamp: %s, fw_build_id: %s",
830 priv->fw_version_info.fw_version,
831 priv->fw_version_info.fw_build_timestamp,
832 priv->fw_build_id);
833
834 icnss_pr_dbg("RD card chain cap: %d, PHY HE channel width cap: %d, PHY QAM cap: %d",
835 priv->rd_card_chain_cap, priv->phy_he_channel_width_cap,
836 priv->phy_qam_cap);
837
838 kfree(resp);
839 kfree(req);
840 return 0;
841
842 out:
843 kfree(resp);
844 kfree(req);
845 priv->stats.cap_err++;
846 return ret;
847 }
848
icnss_qmi_get_dms_mac(struct icnss_priv * priv)849 int icnss_qmi_get_dms_mac(struct icnss_priv *priv)
850 {
851 struct dms_get_mac_address_req_msg_v01 req;
852 struct dms_get_mac_address_resp_msg_v01 resp;
853 struct qmi_txn txn;
854 int ret = 0;
855
856 if (!test_bit(ICNSS_QMI_DMS_CONNECTED, &priv->state)) {
857 icnss_pr_err("DMS QMI connection not established\n");
858 return -EAGAIN;
859 }
860 icnss_pr_dbg("Requesting DMS MAC address");
861
862 memset(&resp, 0, sizeof(resp));
863 ret = qmi_txn_init(&priv->qmi_dms, &txn,
864 dms_get_mac_address_resp_msg_v01_ei, &resp);
865 if (ret < 0) {
866 icnss_pr_err("Failed to initialize txn for dms, err: %d\n",
867 ret);
868 goto out;
869 }
870 req.device = DMS_DEVICE_MAC_WLAN_V01;
871 ret = qmi_send_request(&priv->qmi_dms, NULL, &txn,
872 QMI_DMS_GET_MAC_ADDRESS_REQ_V01,
873 DMS_GET_MAC_ADDRESS_REQ_MSG_V01_MAX_MSG_LEN,
874 dms_get_mac_address_req_msg_v01_ei, &req);
875 if (ret < 0) {
876 qmi_txn_cancel(&txn);
877 icnss_pr_err("Failed to send QMI_DMS_GET_MAC_ADDRESS_REQ_V01, err: %d\n",
878 ret);
879 goto out;
880 }
881 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
882 if (ret < 0) {
883 icnss_pr_err("Failed to wait for QMI_DMS_GET_MAC_ADDRESS_RESP_V01, err: %d\n",
884 ret);
885 goto out;
886 }
887
888 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
889 if (resp.resp.error == DMS_MAC_NOT_PROVISIONED) {
890 icnss_pr_err("NV MAC address is not provisioned");
891 priv->dms.nv_mac_not_prov = 1;
892 } else {
893 icnss_pr_err("QMI_DMS_GET_MAC_ADDRESS_REQ_V01 failed, result: %d, err: %d\n",
894 resp.resp.result, resp.resp.error);
895 }
896 ret = -resp.resp.result;
897 goto out;
898 }
899 if (!resp.mac_address_valid ||
900 resp.mac_address_len != QMI_WLFW_MAC_ADDR_SIZE_V01) {
901 icnss_pr_err("Invalid MAC address received from DMS\n");
902 priv->dms.mac_valid = false;
903 goto out;
904 }
905 priv->dms.mac_valid = true;
906 memcpy(priv->dms.mac, resp.mac_address, QMI_WLFW_MAC_ADDR_SIZE_V01);
907 icnss_pr_info("Received DMS MAC: [%pM]\n", priv->dms.mac);
908 out:
909 return ret;
910 }
911
icnss_wlfw_wlan_mac_req_send_sync(struct icnss_priv * priv,u8 * mac,u32 mac_len)912 int icnss_wlfw_wlan_mac_req_send_sync(struct icnss_priv *priv,
913 u8 *mac, u32 mac_len)
914 {
915 struct wlfw_mac_addr_req_msg_v01 req;
916 struct wlfw_mac_addr_resp_msg_v01 resp = {0};
917 struct qmi_txn txn;
918 int ret;
919
920 if (!priv || !mac || mac_len != QMI_WLFW_MAC_ADDR_SIZE_V01)
921 return -EINVAL;
922
923 ret = qmi_txn_init(&priv->qmi, &txn,
924 wlfw_mac_addr_resp_msg_v01_ei, &resp);
925 if (ret < 0) {
926 icnss_pr_err("Failed to initialize txn for mac req, err: %d\n",
927 ret);
928 ret = -EIO;
929 goto out;
930 }
931
932 icnss_pr_dbg("Sending WLAN mac req [%pM], state: 0x%lx\n",
933 mac, priv->state);
934 memcpy(req.mac_addr, mac, mac_len);
935 req.mac_addr_valid = 1;
936
937 ret = qmi_send_request(&priv->qmi, NULL, &txn,
938 QMI_WLFW_MAC_ADDR_REQ_V01,
939 WLFW_MAC_ADDR_REQ_MSG_V01_MAX_MSG_LEN,
940 wlfw_mac_addr_req_msg_v01_ei, &req);
941 if (ret < 0) {
942 qmi_txn_cancel(&txn);
943 icnss_pr_err("Failed to send mac req, err: %d\n", ret);
944 ret = -EIO;
945 goto out;
946 }
947
948 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
949 if (ret < 0) {
950 icnss_pr_err("Failed to wait for resp of mac req, err: %d\n",
951 ret);
952 ret = -EIO;
953 goto out;
954 }
955
956 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
957 icnss_pr_err("WLAN mac req failed, result: %d\n",
958 resp.resp.result);
959 ret = -resp.resp.result;
960 }
961 out:
962 return ret;
963 }
964
icnss_dms_connect_to_server(struct icnss_priv * priv,unsigned int node,unsigned int port)965 static int icnss_dms_connect_to_server(struct icnss_priv *priv,
966 unsigned int node, unsigned int port)
967 {
968 struct qmi_handle *qmi_dms = &priv->qmi_dms;
969 struct sockaddr_qrtr sq = {0};
970 int ret = 0;
971
972 sq.sq_family = AF_QIPCRTR;
973 sq.sq_node = node;
974 sq.sq_port = port;
975
976 ret = kernel_connect(qmi_dms->sock, (struct sockaddr *)&sq,
977 sizeof(sq), 0);
978 if (ret < 0) {
979 icnss_pr_err("Failed to connect to QMI DMS remote service Node: %d Port: %d\n",
980 node, port);
981 goto out;
982 }
983
984 set_bit(ICNSS_QMI_DMS_CONNECTED, &priv->state);
985 icnss_pr_info("QMI DMS service connected, state: 0x%lx\n",
986 priv->state);
987 out:
988 return ret;
989 }
990
dms_new_server(struct qmi_handle * qmi_dms,struct qmi_service * service)991 static int dms_new_server(struct qmi_handle *qmi_dms,
992 struct qmi_service *service)
993 {
994 struct icnss_priv *priv =
995 container_of(qmi_dms, struct icnss_priv, qmi_dms);
996
997 if (!service)
998 return -EINVAL;
999
1000 return icnss_dms_connect_to_server(priv, service->node,
1001 service->port);
1002 }
1003
dms_del_server(struct qmi_handle * qmi_dms,struct qmi_service * service)1004 static void dms_del_server(struct qmi_handle *qmi_dms,
1005 struct qmi_service *service)
1006 {
1007 struct icnss_priv *priv =
1008 container_of(qmi_dms, struct icnss_priv, qmi_dms);
1009
1010 clear_bit(ICNSS_QMI_DMS_CONNECTED, &priv->state);
1011 icnss_pr_info("QMI DMS service disconnected, state: 0x%lx\n",
1012 priv->state);
1013 }
1014
1015 static struct qmi_ops qmi_dms_ops = {
1016 .new_server = dms_new_server,
1017 .del_server = dms_del_server,
1018 };
1019
icnss_dms_init(struct icnss_priv * priv)1020 int icnss_dms_init(struct icnss_priv *priv)
1021 {
1022 int ret = 0;
1023
1024 ret = qmi_handle_init(&priv->qmi_dms, DMS_QMI_MAX_MSG_LEN,
1025 &qmi_dms_ops, NULL);
1026 if (ret < 0) {
1027 icnss_pr_err("Failed to initialize DMS handle, err: %d\n", ret);
1028 goto out;
1029 }
1030
1031 ret = qmi_add_lookup(&priv->qmi_dms, DMS_SERVICE_ID_V01,
1032 DMS_SERVICE_VERS_V01, 0);
1033 if (ret < 0)
1034 icnss_pr_err("Failed to add DMS lookup, err: %d\n", ret);
1035 out:
1036 return ret;
1037 }
1038
icnss_dms_deinit(struct icnss_priv * priv)1039 void icnss_dms_deinit(struct icnss_priv *priv)
1040 {
1041 qmi_handle_release(&priv->qmi_dms);
1042 }
1043
icnss_get_bdf_file_name(struct icnss_priv * priv,u32 bdf_type,char * filename,u32 filename_len)1044 static int icnss_get_bdf_file_name(struct icnss_priv *priv,
1045 u32 bdf_type, char *filename,
1046 u32 filename_len)
1047 {
1048 char filename_tmp[ICNSS_MAX_FILE_NAME];
1049 char foundry_specific_filename[ICNSS_MAX_FILE_NAME];
1050 int ret = 0;
1051
1052 switch (bdf_type) {
1053 case ICNSS_BDF_ELF:
1054 if (priv->board_id == 0xFF)
1055 snprintf(filename_tmp, filename_len, ELF_BDF_FILE_NAME);
1056 else if (priv->board_id < 0xFF)
1057 snprintf(filename_tmp, filename_len,
1058 ELF_BDF_FILE_NAME_PREFIX "%02x",
1059 priv->board_id);
1060 else
1061 snprintf(filename_tmp, filename_len,
1062 BDF_FILE_NAME_PREFIX "%02x.e%02x",
1063 priv->board_id >> 8 & 0xFF,
1064 priv->board_id & 0xFF);
1065 break;
1066 case ICNSS_BDF_BIN:
1067 if (priv->board_id == 0xFF)
1068 snprintf(filename_tmp, filename_len, BIN_BDF_FILE_NAME);
1069 else if (priv->board_id >= WLAN_BOARD_ID_INDEX)
1070 snprintf(filename_tmp, filename_len,
1071 BIN_BDF_FILE_NAME_PREFIX "%03x",
1072 priv->board_id);
1073 else
1074 snprintf(filename_tmp, filename_len,
1075 BIN_BDF_FILE_NAME_PREFIX "b%02x",
1076 priv->board_id);
1077 if (priv->foundry_name) {
1078 strlcpy(foundry_specific_filename, filename_tmp, ICNSS_MAX_FILE_NAME);
1079 memmove(foundry_specific_filename + BDWLAN_SIZE + 1,
1080 foundry_specific_filename + BDWLAN_SIZE,
1081 BDWLAN_SIZE - 1);
1082 foundry_specific_filename[BDWLAN_SIZE] = priv->foundry_name;
1083 foundry_specific_filename[ICNSS_MAX_FILE_NAME - 1] = '\0';
1084 strlcpy(filename_tmp, foundry_specific_filename, ICNSS_MAX_FILE_NAME);
1085 }
1086 break;
1087 case ICNSS_BDF_REGDB:
1088 snprintf(filename_tmp, filename_len, REGDB_FILE_NAME);
1089 break;
1090 default:
1091 icnss_pr_err("Invalid BDF type: %d\n",
1092 priv->ctrl_params.bdf_type);
1093 ret = -EINVAL;
1094 break;
1095 }
1096
1097 if (!ret)
1098 icnss_add_fw_prefix_name(priv, filename, filename_tmp);
1099
1100 return ret;
1101 }
1102
icnss_bdf_type_to_str(enum icnss_bdf_type bdf_type)1103 static char *icnss_bdf_type_to_str(enum icnss_bdf_type bdf_type)
1104 {
1105 switch (bdf_type) {
1106 case ICNSS_BDF_BIN:
1107 return "BDF";
1108 case ICNSS_BDF_ELF:
1109 return "BDF";
1110 case ICNSS_BDF_REGDB:
1111 return "REGDB";
1112 default:
1113 return "UNKNOWN";
1114 }
1115 };
1116
icnss_wlfw_bdf_dnld_send_sync(struct icnss_priv * priv,u32 bdf_type)1117 int icnss_wlfw_bdf_dnld_send_sync(struct icnss_priv *priv, u32 bdf_type)
1118 {
1119 struct wlfw_bdf_download_req_msg_v01 *req;
1120 struct wlfw_bdf_download_resp_msg_v01 *resp;
1121 struct qmi_txn txn;
1122 char filename[ICNSS_MAX_FILE_NAME];
1123 const struct firmware *fw_entry = NULL;
1124 const u8 *temp;
1125 unsigned int remaining;
1126 int ret = 0;
1127
1128 icnss_pr_dbg("Sending %s download message, state: 0x%lx, type: %d\n",
1129 icnss_bdf_type_to_str(bdf_type), priv->state, bdf_type);
1130
1131 req = kzalloc(sizeof(*req), GFP_KERNEL);
1132 if (!req)
1133 return -ENOMEM;
1134
1135 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
1136 if (!resp) {
1137 kfree(req);
1138 return -ENOMEM;
1139 }
1140
1141 ret = icnss_get_bdf_file_name(priv, bdf_type,
1142 filename, sizeof(filename));
1143 if (ret)
1144 goto err_req_fw;
1145
1146 ret = firmware_request_nowarn(&fw_entry, filename, &priv->pdev->dev);
1147 if (ret) {
1148 icnss_pr_err("Failed to load %s: %s ret:%d\n",
1149 icnss_bdf_type_to_str(bdf_type), filename, ret);
1150 goto err_req_fw;
1151 }
1152
1153 temp = fw_entry->data;
1154 remaining = fw_entry->size;
1155
1156 icnss_pr_dbg("Downloading %s: %s, size: %u\n",
1157 icnss_bdf_type_to_str(bdf_type), filename, remaining);
1158
1159 while (remaining) {
1160 req->valid = 1;
1161 req->file_id_valid = 1;
1162 req->file_id = priv->board_id;
1163 req->total_size_valid = 1;
1164 req->total_size = fw_entry->size;
1165 req->seg_id_valid = 1;
1166 req->data_valid = 1;
1167 req->end_valid = 1;
1168 req->bdf_type_valid = 1;
1169 req->bdf_type = bdf_type;
1170
1171 if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) {
1172 req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01;
1173 } else {
1174 req->data_len = remaining;
1175 req->end = 1;
1176 }
1177
1178 memcpy(req->data, temp, req->data_len);
1179
1180 ret = qmi_txn_init(&priv->qmi, &txn,
1181 wlfw_bdf_download_resp_msg_v01_ei, resp);
1182 if (ret < 0) {
1183 icnss_pr_err("Failed to initialize txn for %s download request, err: %d\n",
1184 icnss_bdf_type_to_str(bdf_type), ret);
1185 goto err_send;
1186 }
1187
1188 ret = qmi_send_request
1189 (&priv->qmi, NULL, &txn,
1190 QMI_WLFW_BDF_DOWNLOAD_REQ_V01,
1191 WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN,
1192 wlfw_bdf_download_req_msg_v01_ei, req);
1193 if (ret < 0) {
1194 qmi_txn_cancel(&txn);
1195 icnss_pr_err("Failed to send respond %s download request, err: %d\n",
1196 icnss_bdf_type_to_str(bdf_type), ret);
1197 goto err_send;
1198 }
1199
1200 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
1201 if (ret < 0) {
1202 icnss_pr_err("Failed to wait for response of %s download request, err: %d\n",
1203 icnss_bdf_type_to_str(bdf_type), ret);
1204 goto err_send;
1205 }
1206
1207 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
1208 icnss_pr_err("%s download request failed, result: %d, err: %d\n",
1209 icnss_bdf_type_to_str(bdf_type), resp->resp.result,
1210 resp->resp.error);
1211 ret = -resp->resp.result;
1212 goto err_send;
1213 }
1214
1215 remaining -= req->data_len;
1216 temp += req->data_len;
1217 req->seg_id++;
1218 }
1219
1220 release_firmware(fw_entry);
1221
1222 kfree(req);
1223 kfree(resp);
1224 return 0;
1225
1226 err_send:
1227 release_firmware(fw_entry);
1228 err_req_fw:
1229 if (bdf_type != ICNSS_BDF_REGDB)
1230 ICNSS_QMI_ASSERT();
1231 kfree(req);
1232 kfree(resp);
1233 return ret;
1234 }
1235
icnss_wlfw_qdss_data_send_sync(struct icnss_priv * priv,char * file_name,u32 total_size)1236 int icnss_wlfw_qdss_data_send_sync(struct icnss_priv *priv, char *file_name,
1237 u32 total_size)
1238 {
1239 int ret = 0;
1240 struct wlfw_qdss_trace_data_req_msg_v01 *req;
1241 struct wlfw_qdss_trace_data_resp_msg_v01 *resp;
1242 unsigned char *p_qdss_trace_data_temp, *p_qdss_trace_data = NULL;
1243 unsigned int remaining;
1244 struct qmi_txn txn;
1245
1246 icnss_pr_dbg("%s", __func__);
1247
1248 req = kzalloc(sizeof(*req), GFP_KERNEL);
1249 if (!req)
1250 return -ENOMEM;
1251
1252 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
1253 if (!resp) {
1254 kfree(req);
1255 return -ENOMEM;
1256 }
1257
1258 p_qdss_trace_data = kzalloc(total_size, GFP_KERNEL);
1259 if (!p_qdss_trace_data) {
1260 ret = ENOMEM;
1261 goto end;
1262 }
1263
1264 remaining = total_size;
1265 p_qdss_trace_data_temp = p_qdss_trace_data;
1266 while (remaining && resp->end == 0) {
1267 ret = qmi_txn_init(&priv->qmi, &txn,
1268 wlfw_qdss_trace_data_resp_msg_v01_ei, resp);
1269
1270 if (ret < 0) {
1271 icnss_pr_err("Fail to init txn for QDSS trace resp %d\n",
1272 ret);
1273 goto fail;
1274 }
1275
1276 ret = qmi_send_request
1277 (&priv->qmi, NULL, &txn,
1278 QMI_WLFW_QDSS_TRACE_DATA_REQ_V01,
1279 WLFW_QDSS_TRACE_DATA_REQ_MSG_V01_MAX_MSG_LEN,
1280 wlfw_qdss_trace_data_req_msg_v01_ei, req);
1281
1282 if (ret < 0) {
1283 qmi_txn_cancel(&txn);
1284 icnss_pr_err("Fail to send QDSS trace data req %d\n",
1285 ret);
1286 goto fail;
1287 }
1288
1289 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
1290
1291 if (ret < 0) {
1292 icnss_pr_err("QDSS trace resp wait failed with rc %d\n",
1293 ret);
1294 goto fail;
1295 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
1296 icnss_pr_err("QMI QDSS trace request rejected, result:%d error:%d\n",
1297 resp->resp.result, resp->resp.error);
1298 ret = -resp->resp.result;
1299 goto fail;
1300 } else {
1301 ret = 0;
1302 }
1303
1304 icnss_pr_dbg("%s: response total size %d data len %d",
1305 __func__, resp->total_size, resp->data_len);
1306
1307 if ((resp->total_size_valid == 1 &&
1308 resp->total_size == total_size) &&
1309 (resp->seg_id_valid == 1 && resp->seg_id == req->seg_id) &&
1310 (resp->data_valid == 1 &&
1311 resp->data_len <= QMI_WLFW_MAX_DATA_SIZE_V01) &&
1312 resp->data_len <= remaining) {
1313 memcpy(p_qdss_trace_data_temp,
1314 resp->data, resp->data_len);
1315 } else {
1316 icnss_pr_err("%s: Unmatched qdss trace data, Expect total_size %u, seg_id %u, Recv total_size_valid %u, total_size %u, seg_id_valid %u, seg_id %u, data_len_valid %u, data_len %u",
1317 __func__,
1318 total_size, req->seg_id,
1319 resp->total_size_valid,
1320 resp->total_size,
1321 resp->seg_id_valid,
1322 resp->seg_id,
1323 resp->data_valid,
1324 resp->data_len);
1325 ret = -EINVAL;
1326 goto fail;
1327 }
1328
1329 remaining -= resp->data_len;
1330 p_qdss_trace_data_temp += resp->data_len;
1331 req->seg_id++;
1332 }
1333
1334 if (remaining == 0 && (resp->end_valid && resp->end)) {
1335 ret = icnss_genl_send_msg(p_qdss_trace_data,
1336 ICNSS_GENL_MSG_TYPE_QDSS, file_name,
1337 total_size);
1338 if (ret < 0) {
1339 icnss_pr_err("Fail to save QDSS trace data: %d\n",
1340 ret);
1341 ret = -EINVAL;
1342 }
1343 } else {
1344 icnss_pr_err("%s: QDSS trace file corrupted: remaining %u, end_valid %u, end %u",
1345 __func__,
1346 remaining, resp->end_valid, resp->end);
1347 ret = -EINVAL;
1348 }
1349
1350 fail:
1351 kfree(p_qdss_trace_data);
1352
1353 end:
1354 kfree(req);
1355 kfree(resp);
1356 return ret;
1357 }
1358
icnss_wlfw_qdss_dnld_send_sync(struct icnss_priv * priv)1359 int icnss_wlfw_qdss_dnld_send_sync(struct icnss_priv *priv)
1360 {
1361 struct wlfw_qdss_trace_config_download_req_msg_v01 *req;
1362 struct wlfw_qdss_trace_config_download_resp_msg_v01 *resp;
1363 struct qmi_txn txn;
1364 char filename[ICNSS_MAX_FILE_NAME];
1365 const struct firmware *fw_entry = NULL;
1366 const u8 *temp;
1367 unsigned int remaining;
1368 int ret = 0;
1369
1370 icnss_pr_dbg("Sending QDSS config download message, state: 0x%lx\n",
1371 priv->state);
1372
1373 req = kzalloc(sizeof(*req), GFP_KERNEL);
1374 if (!req)
1375 return -ENOMEM;
1376
1377 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
1378 if (!resp) {
1379 kfree(req);
1380 return -ENOMEM;
1381 }
1382
1383 icnss_add_fw_prefix_name(priv, filename, QDSS_TRACE_CONFIG_FILE);
1384 ret = firmware_request_nowarn(&fw_entry, filename,
1385 &priv->pdev->dev);
1386 if (ret) {
1387 icnss_pr_err("Failed to load QDSS: %s ret:%d\n",
1388 filename, ret);
1389 goto err_req_fw;
1390 }
1391
1392 temp = fw_entry->data;
1393 remaining = fw_entry->size;
1394
1395 icnss_pr_dbg("Downloading QDSS: %s, size: %u\n",
1396 filename, remaining);
1397
1398 while (remaining) {
1399 req->total_size_valid = 1;
1400 req->total_size = remaining;
1401 req->seg_id_valid = 1;
1402 req->data_valid = 1;
1403 req->end_valid = 1;
1404
1405 if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) {
1406 req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01;
1407 } else {
1408 req->data_len = remaining;
1409 req->end = 1;
1410 }
1411
1412 memcpy(req->data, temp, req->data_len);
1413
1414 ret = qmi_txn_init
1415 (&priv->qmi, &txn,
1416 wlfw_qdss_trace_config_download_resp_msg_v01_ei,
1417 resp);
1418 if (ret < 0) {
1419 icnss_pr_err("Failed to initialize txn for QDSS download request, err: %d\n",
1420 ret);
1421 goto err_send;
1422 }
1423
1424 ret = qmi_send_request
1425 (&priv->qmi, NULL, &txn,
1426 QMI_WLFW_QDSS_TRACE_CONFIG_DOWNLOAD_REQ_V01,
1427 WLFW_QDSS_TRACE_CONFIG_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN,
1428 wlfw_qdss_trace_config_download_req_msg_v01_ei, req);
1429 if (ret < 0) {
1430 qmi_txn_cancel(&txn);
1431 icnss_pr_err("Failed to send respond QDSS download request, err: %d\n",
1432 ret);
1433 goto err_send;
1434 }
1435
1436 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
1437 if (ret < 0) {
1438 icnss_pr_err("Failed to wait for response of QDSS download request, err: %d\n",
1439 ret);
1440 goto err_send;
1441 }
1442
1443 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
1444 icnss_pr_err("QDSS download request failed, result: %d, err: %d\n",
1445 resp->resp.result, resp->resp.error);
1446 ret = -resp->resp.result;
1447 goto err_send;
1448 }
1449
1450 remaining -= req->data_len;
1451 temp += req->data_len;
1452 req->seg_id++;
1453 }
1454
1455 release_firmware(fw_entry);
1456 kfree(req);
1457 kfree(resp);
1458 return 0;
1459
1460 err_send:
1461 release_firmware(fw_entry);
1462 err_req_fw:
1463
1464 kfree(req);
1465 kfree(resp);
1466 return ret;
1467 }
1468
wlfw_wlan_mode_send_sync_msg(struct icnss_priv * priv,enum wlfw_driver_mode_enum_v01 mode)1469 int wlfw_wlan_mode_send_sync_msg(struct icnss_priv *priv,
1470 enum wlfw_driver_mode_enum_v01 mode)
1471 {
1472 int ret;
1473 struct wlfw_wlan_mode_req_msg_v01 *req;
1474 struct wlfw_wlan_mode_resp_msg_v01 *resp;
1475 struct qmi_txn txn;
1476
1477 if (!priv)
1478 return -ENODEV;
1479
1480 /* During recovery do not send mode request for WLAN OFF as
1481 * FW not able to process it.
1482 */
1483 if (test_bit(ICNSS_PD_RESTART, &priv->state) &&
1484 mode == QMI_WLFW_OFF_V01)
1485 return 0;
1486
1487 if (!test_bit(ICNSS_MODE_ON, &priv->state) &&
1488 mode == QMI_WLFW_OFF_V01)
1489 return 0;
1490
1491 icnss_pr_dbg("Sending Mode request, state: 0x%lx, mode: %d\n",
1492 priv->state, mode);
1493
1494 req = kzalloc(sizeof(*req), GFP_KERNEL);
1495 if (!req)
1496 return -ENOMEM;
1497
1498 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
1499 if (!resp) {
1500 kfree(req);
1501 return -ENOMEM;
1502 }
1503
1504 req->mode = mode;
1505 req->hw_debug_valid = 1;
1506 req->hw_debug = !!test_bit(HW_DEBUG_ENABLE, &priv->ctrl_params.quirks);
1507
1508 if (priv->wlan_en_delay_ms >= 100) {
1509 icnss_pr_dbg("Setting WLAN_EN delay: %d ms\n",
1510 priv->wlan_en_delay_ms);
1511 req->wlan_en_delay_valid = 1;
1512 req->wlan_en_delay = priv->wlan_en_delay_ms;
1513 }
1514
1515 priv->stats.mode_req++;
1516
1517 ret = qmi_txn_init(&priv->qmi, &txn,
1518 wlfw_wlan_mode_resp_msg_v01_ei, resp);
1519 if (ret < 0) {
1520 icnss_qmi_fatal_err("Fail to init txn for Mode resp %d\n", ret);
1521 goto out;
1522 }
1523
1524 ret = qmi_send_request(&priv->qmi, NULL, &txn,
1525 QMI_WLFW_WLAN_MODE_REQ_V01,
1526 WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN,
1527 wlfw_wlan_mode_req_msg_v01_ei, req);
1528 if (ret < 0) {
1529 qmi_txn_cancel(&txn);
1530 icnss_qmi_fatal_err("Fail to send Mode req %d\n", ret);
1531 goto out;
1532 }
1533
1534 ret = qmi_txn_wait(&txn,
1535 priv->ctrl_params.qmi_timeout +
1536 msecs_to_jiffies(priv->wlan_en_delay_ms));
1537 if (ret < 0) {
1538 icnss_qmi_fatal_err("Mode resp wait failed with ret %d\n", ret);
1539 goto out;
1540 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
1541 icnss_qmi_fatal_err(
1542 "QMI Mode request rejected, result:%d error:%d\n",
1543 resp->resp.result, resp->resp.error);
1544 ret = -resp->resp.result;
1545 goto out;
1546 }
1547
1548 priv->stats.mode_resp++;
1549
1550 if (mode == QMI_WLFW_OFF_V01) {
1551 icnss_pr_dbg("Clear mode on 0x%lx, mode: %d\n",
1552 priv->state, mode);
1553 clear_bit(ICNSS_MODE_ON, &priv->state);
1554 } else {
1555 icnss_pr_dbg("Set mode on 0x%lx, mode: %d\n",
1556 priv->state, mode);
1557 set_bit(ICNSS_MODE_ON, &priv->state);
1558 }
1559
1560 kfree(resp);
1561 kfree(req);
1562 return 0;
1563
1564 out:
1565 kfree(resp);
1566 kfree(req);
1567 priv->stats.mode_req_err++;
1568 return ret;
1569 }
1570
wlfw_send_qdss_trace_mode_req(struct icnss_priv * priv,enum wlfw_qdss_trace_mode_enum_v01 mode,unsigned long long option)1571 static int wlfw_send_qdss_trace_mode_req
1572 (struct icnss_priv *priv,
1573 enum wlfw_qdss_trace_mode_enum_v01 mode,
1574 unsigned long long option)
1575 {
1576 int rc = 0;
1577 int tmp = 0;
1578 struct wlfw_qdss_trace_mode_req_msg_v01 *req;
1579 struct wlfw_qdss_trace_mode_resp_msg_v01 *resp;
1580 struct qmi_txn txn;
1581
1582 if (!priv)
1583 return -ENODEV;
1584
1585 req = kzalloc(sizeof(*req), GFP_KERNEL);
1586 if (!req)
1587 return -ENOMEM;
1588
1589 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
1590 if (!resp) {
1591 kfree(req);
1592 return -ENOMEM;
1593 }
1594
1595 req->mode_valid = 1;
1596 req->mode = mode;
1597 req->option_valid = 1;
1598 req->option = option;
1599
1600 tmp = priv->hw_trc_override;
1601
1602 req->hw_trc_disable_override_valid = 1;
1603 req->hw_trc_disable_override =
1604 (tmp > QMI_PARAM_DISABLE_V01 ? QMI_PARAM_DISABLE_V01 :
1605 (tmp < 0 ? QMI_PARAM_INVALID_V01 : tmp));
1606
1607 icnss_pr_dbg("%s: mode %u, option %llu, hw_trc_disable_override: %u",
1608 __func__, mode, option, req->hw_trc_disable_override);
1609
1610 rc = qmi_txn_init(&priv->qmi, &txn,
1611 wlfw_qdss_trace_mode_resp_msg_v01_ei, resp);
1612 if (rc < 0) {
1613 icnss_qmi_fatal_err("Fail to init txn for QDSS Mode resp %d\n",
1614 rc);
1615 goto out;
1616 }
1617
1618 rc = qmi_send_request(&priv->qmi, NULL, &txn,
1619 QMI_WLFW_QDSS_TRACE_MODE_REQ_V01,
1620 WLFW_QDSS_TRACE_MODE_REQ_MSG_V01_MAX_MSG_LEN,
1621 wlfw_qdss_trace_mode_req_msg_v01_ei, req);
1622 if (rc < 0) {
1623 qmi_txn_cancel(&txn);
1624 icnss_qmi_fatal_err("Fail to send QDSS Mode req %d\n", rc);
1625 goto out;
1626 }
1627
1628 rc = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
1629 if (rc < 0) {
1630 icnss_qmi_fatal_err("QDSS Mode resp wait failed with rc %d\n",
1631 rc);
1632 goto out;
1633 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
1634 icnss_qmi_fatal_err(
1635 "QMI QDSS Mode request rejected, result:%d error:%d\n",
1636 resp->resp.result, resp->resp.error);
1637 rc = -resp->resp.result;
1638 goto out;
1639 }
1640
1641 out:
1642 kfree(resp);
1643 kfree(req);
1644 return rc;
1645 }
1646
wlfw_qdss_trace_start(struct icnss_priv * priv)1647 int wlfw_qdss_trace_start(struct icnss_priv *priv)
1648 {
1649 return wlfw_send_qdss_trace_mode_req(priv,
1650 QMI_WLFW_QDSS_TRACE_ON_V01, 0);
1651 }
1652
wlfw_qdss_trace_stop(struct icnss_priv * priv,unsigned long long option)1653 int wlfw_qdss_trace_stop(struct icnss_priv *priv, unsigned long long option)
1654 {
1655 return wlfw_send_qdss_trace_mode_req(priv, QMI_WLFW_QDSS_TRACE_OFF_V01,
1656 option);
1657 }
1658
wlfw_wlan_cfg_send_sync_msg(struct icnss_priv * priv,struct wlfw_wlan_cfg_req_msg_v01 * data)1659 int wlfw_wlan_cfg_send_sync_msg(struct icnss_priv *priv,
1660 struct wlfw_wlan_cfg_req_msg_v01 *data)
1661 {
1662 int ret;
1663 struct wlfw_wlan_cfg_req_msg_v01 *req;
1664 struct wlfw_wlan_cfg_resp_msg_v01 *resp;
1665 struct qmi_txn txn;
1666
1667 if (!priv)
1668 return -ENODEV;
1669
1670 icnss_pr_dbg("Sending config request, state: 0x%lx\n", priv->state);
1671
1672 req = kzalloc(sizeof(*req), GFP_KERNEL);
1673 if (!req)
1674 return -ENOMEM;
1675
1676 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
1677 if (!resp) {
1678 kfree(req);
1679 return -ENOMEM;
1680 }
1681
1682 memcpy(req, data, sizeof(*req));
1683
1684 priv->stats.cfg_req++;
1685
1686 ret = qmi_txn_init(&priv->qmi, &txn,
1687 wlfw_wlan_cfg_resp_msg_v01_ei, resp);
1688 if (ret < 0) {
1689 icnss_qmi_fatal_err("Fail to init txn for Config resp %d\n",
1690 ret);
1691 goto out;
1692 }
1693
1694 ret = qmi_send_request(&priv->qmi, NULL, &txn,
1695 QMI_WLFW_WLAN_CFG_REQ_V01,
1696 WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN,
1697 wlfw_wlan_cfg_req_msg_v01_ei, req);
1698 if (ret < 0) {
1699 qmi_txn_cancel(&txn);
1700 icnss_qmi_fatal_err("Fail to send Config req %d\n", ret);
1701 goto out;
1702 }
1703
1704 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
1705 if (ret < 0) {
1706 icnss_qmi_fatal_err("Config resp wait failed with ret %d\n",
1707 ret);
1708 goto out;
1709 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
1710 icnss_qmi_fatal_err(
1711 "QMI Config request rejected, result:%d error:%d\n",
1712 resp->resp.result, resp->resp.error);
1713 ret = -resp->resp.result;
1714 goto out;
1715 }
1716
1717 priv->stats.cfg_resp++;
1718
1719 kfree(resp);
1720 kfree(req);
1721 return 0;
1722
1723 out:
1724 kfree(resp);
1725 kfree(req);
1726 priv->stats.cfg_req_err++;
1727 return ret;
1728 }
1729
wlfw_send_modem_shutdown_msg(struct icnss_priv * priv)1730 int wlfw_send_modem_shutdown_msg(struct icnss_priv *priv)
1731 {
1732 int ret;
1733 struct wlfw_shutdown_req_msg_v01 *req;
1734 struct wlfw_shutdown_resp_msg_v01 *resp;
1735 struct qmi_txn txn;
1736
1737 if (!priv)
1738 return -ENODEV;
1739
1740 if (test_bit(ICNSS_FW_DOWN, &priv->state))
1741 return -EINVAL;
1742
1743 icnss_pr_dbg("Sending modem shutdown request, state: 0x%lx\n",
1744 priv->state);
1745
1746 req = kzalloc(sizeof(*req), GFP_KERNEL);
1747 if (!req)
1748 return -ENOMEM;
1749
1750 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
1751 if (!resp) {
1752 kfree(req);
1753 return -ENOMEM;
1754 }
1755
1756 req->shutdown_valid = 1;
1757 req->shutdown = 1;
1758
1759 ret = qmi_txn_init(&priv->qmi, &txn,
1760 wlfw_shutdown_resp_msg_v01_ei, resp);
1761
1762 if (ret < 0) {
1763 icnss_pr_err("Fail to init txn for shutdown resp %d\n",
1764 ret);
1765 goto out;
1766 }
1767
1768 ret = qmi_send_request(&priv->qmi, NULL, &txn,
1769 QMI_WLFW_SHUTDOWN_REQ_V01,
1770 WLFW_SHUTDOWN_REQ_MSG_V01_MAX_MSG_LEN,
1771 wlfw_shutdown_req_msg_v01_ei, req);
1772 if (ret < 0) {
1773 qmi_txn_cancel(&txn);
1774 icnss_pr_err("Fail to send Shutdown req %d\n", ret);
1775 goto out;
1776 }
1777
1778 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
1779 if (ret < 0) {
1780 icnss_pr_err("Shutdown resp wait failed with ret %d\n",
1781 ret);
1782 goto out;
1783 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
1784 icnss_pr_err("QMI modem shutdown request rejected result:%d error:%d\n",
1785 resp->resp.result, resp->resp.error);
1786 ret = -resp->resp.result;
1787 goto out;
1788 }
1789
1790 out:
1791 kfree(resp);
1792 kfree(req);
1793 return ret;
1794 }
1795
wlfw_ini_send_sync_msg(struct icnss_priv * priv,uint8_t fw_log_mode)1796 int wlfw_ini_send_sync_msg(struct icnss_priv *priv, uint8_t fw_log_mode)
1797 {
1798 int ret;
1799 struct wlfw_ini_req_msg_v01 *req;
1800 struct wlfw_ini_resp_msg_v01 *resp;
1801 struct qmi_txn txn;
1802
1803 if (!priv)
1804 return -ENODEV;
1805
1806 icnss_pr_dbg("Sending ini sync request, state: 0x%lx, fw_log_mode: %d\n",
1807 priv->state, fw_log_mode);
1808
1809 req = kzalloc(sizeof(*req), GFP_KERNEL);
1810 if (!req)
1811 return -ENOMEM;
1812
1813 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
1814 if (!resp) {
1815 kfree(req);
1816 return -ENOMEM;
1817 }
1818
1819 req->enablefwlog_valid = 1;
1820 req->enablefwlog = fw_log_mode;
1821
1822 priv->stats.ini_req++;
1823
1824 ret = qmi_txn_init(&priv->qmi, &txn, wlfw_ini_resp_msg_v01_ei, resp);
1825 if (ret < 0) {
1826 icnss_qmi_fatal_err("Fail to init txn for INI resp %d\n", ret);
1827 goto out;
1828 }
1829
1830 ret = qmi_send_request(&priv->qmi, NULL, &txn,
1831 QMI_WLFW_INI_REQ_V01,
1832 WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN,
1833 wlfw_ini_req_msg_v01_ei, req);
1834 if (ret < 0) {
1835 qmi_txn_cancel(&txn);
1836 icnss_qmi_fatal_err("Fail to send INI req %d\n", ret);
1837 goto out;
1838 }
1839
1840 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
1841 if (ret < 0) {
1842 icnss_qmi_fatal_err("INI resp wait failed with ret %d\n", ret);
1843 goto out;
1844 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
1845 icnss_qmi_fatal_err(
1846 "QMI INI request rejected, result:%d error:%d\n",
1847 resp->resp.result, resp->resp.error);
1848 ret = -resp->resp.result;
1849 goto out;
1850 }
1851
1852 priv->stats.ini_resp++;
1853
1854 kfree(resp);
1855 kfree(req);
1856 return 0;
1857
1858 out:
1859 kfree(resp);
1860 kfree(req);
1861 priv->stats.ini_req_err++;
1862 return ret;
1863 }
1864
wlfw_athdiag_read_send_sync_msg(struct icnss_priv * priv,uint32_t offset,uint32_t mem_type,uint32_t data_len,uint8_t * data)1865 int wlfw_athdiag_read_send_sync_msg(struct icnss_priv *priv,
1866 uint32_t offset, uint32_t mem_type,
1867 uint32_t data_len, uint8_t *data)
1868 {
1869 int ret;
1870 struct wlfw_athdiag_read_req_msg_v01 *req;
1871 struct wlfw_athdiag_read_resp_msg_v01 *resp;
1872 struct qmi_txn txn;
1873
1874 if (!priv)
1875 return -ENODEV;
1876
1877 icnss_pr_dbg("Diag read: state 0x%lx, offset %x, mem_type %x, data_len %u\n",
1878 priv->state, offset, mem_type, data_len);
1879
1880 req = kzalloc(sizeof(*req), GFP_KERNEL);
1881 if (!req)
1882 return -ENOMEM;
1883
1884 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
1885 if (!resp) {
1886 kfree(req);
1887 return -ENOMEM;
1888 }
1889
1890 req->offset = offset;
1891 req->mem_type = mem_type;
1892 req->data_len = data_len;
1893
1894 ret = qmi_txn_init(&priv->qmi, &txn,
1895 wlfw_athdiag_read_resp_msg_v01_ei, resp);
1896 if (ret < 0) {
1897 icnss_pr_err("Fail to init txn for Athdiag Read resp %d\n",
1898 ret);
1899 goto out;
1900 }
1901
1902 ret = qmi_send_request(&priv->qmi, NULL, &txn,
1903 QMI_WLFW_ATHDIAG_READ_REQ_V01,
1904 WLFW_ATHDIAG_READ_REQ_MSG_V01_MAX_MSG_LEN,
1905 wlfw_athdiag_read_req_msg_v01_ei, req);
1906 if (ret < 0) {
1907 qmi_txn_cancel(&txn);
1908 icnss_pr_err("Fail to send Athdiag Read req %d\n", ret);
1909 goto out;
1910 }
1911
1912 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
1913 if (ret < 0) {
1914 icnss_pr_err("Athdaig Read resp wait failed with ret %d\n",
1915 ret);
1916 goto out;
1917 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
1918 icnss_pr_err("QMI Athdiag Read request rejected, result:%d error:%d\n",
1919 resp->resp.result, resp->resp.error);
1920 ret = -resp->resp.result;
1921 goto out;
1922 } else {
1923 ret = 0;
1924 }
1925
1926 if (!resp->data_valid || resp->data_len < data_len) {
1927 icnss_pr_err("Athdiag read data is invalid, data_valid = %u, data_len = %u\n",
1928 resp->data_valid, resp->data_len);
1929 ret = -EINVAL;
1930 goto out;
1931 }
1932
1933 memcpy(data, resp->data, resp->data_len);
1934
1935 out:
1936 kfree(resp);
1937 kfree(req);
1938 return ret;
1939 }
1940
wlfw_athdiag_write_send_sync_msg(struct icnss_priv * priv,uint32_t offset,uint32_t mem_type,uint32_t data_len,uint8_t * data)1941 int wlfw_athdiag_write_send_sync_msg(struct icnss_priv *priv,
1942 uint32_t offset, uint32_t mem_type,
1943 uint32_t data_len, uint8_t *data)
1944 {
1945 int ret;
1946 struct wlfw_athdiag_write_req_msg_v01 *req;
1947 struct wlfw_athdiag_write_resp_msg_v01 *resp;
1948 struct qmi_txn txn;
1949
1950 if (!priv)
1951 return -ENODEV;
1952
1953 icnss_pr_dbg("Diag write: state 0x%lx, offset %x, mem_type %x, data_len %u, data %pK\n",
1954 priv->state, offset, mem_type, data_len, data);
1955
1956 req = kzalloc(sizeof(*req), GFP_KERNEL);
1957 if (!req)
1958 return -ENOMEM;
1959
1960 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
1961 if (!resp) {
1962 kfree(req);
1963 return -ENOMEM;
1964 }
1965
1966 req->offset = offset;
1967 req->mem_type = mem_type;
1968 req->data_len = data_len;
1969 memcpy(req->data, data, data_len);
1970
1971 ret = qmi_txn_init(&priv->qmi, &txn,
1972 wlfw_athdiag_write_resp_msg_v01_ei, resp);
1973 if (ret < 0) {
1974 icnss_pr_err("Fail to init txn for Athdiag Write resp %d\n",
1975 ret);
1976 goto out;
1977 }
1978
1979 ret = qmi_send_request(&priv->qmi, NULL, &txn,
1980 QMI_WLFW_ATHDIAG_WRITE_REQ_V01,
1981 WLFW_ATHDIAG_WRITE_REQ_MSG_V01_MAX_MSG_LEN,
1982 wlfw_athdiag_write_req_msg_v01_ei, req);
1983 if (ret < 0) {
1984 qmi_txn_cancel(&txn);
1985 icnss_pr_err("Fail to send Athdiag Write req %d\n", ret);
1986 goto out;
1987 }
1988
1989 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
1990 if (ret < 0) {
1991 icnss_pr_err("Athdiag Write resp wait failed with ret %d\n",
1992 ret);
1993 goto out;
1994 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
1995 icnss_pr_err("QMI Athdiag Write request rejected, result:%d error:%d\n",
1996 resp->resp.result, resp->resp.error);
1997 ret = -resp->resp.result;
1998 goto out;
1999 } else {
2000 ret = 0;
2001 }
2002
2003 out:
2004 kfree(resp);
2005 kfree(req);
2006 return ret;
2007 }
2008
wlfw_rejuvenate_ack_send_sync_msg(struct icnss_priv * priv)2009 int wlfw_rejuvenate_ack_send_sync_msg(struct icnss_priv *priv)
2010 {
2011 int ret;
2012 struct wlfw_rejuvenate_ack_req_msg_v01 *req;
2013 struct wlfw_rejuvenate_ack_resp_msg_v01 *resp;
2014 struct qmi_txn txn;
2015
2016 if (!priv)
2017 return -ENODEV;
2018
2019 icnss_pr_dbg("Sending rejuvenate ack request, state: 0x%lx\n",
2020 priv->state);
2021
2022 req = kzalloc(sizeof(*req), GFP_KERNEL);
2023 if (!req)
2024 return -ENOMEM;
2025
2026 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
2027 if (!resp) {
2028 kfree(req);
2029 return -ENOMEM;
2030 }
2031
2032 priv->stats.rejuvenate_ack_req++;
2033
2034 ret = qmi_txn_init(&priv->qmi, &txn,
2035 wlfw_rejuvenate_ack_resp_msg_v01_ei, resp);
2036 if (ret < 0) {
2037 icnss_qmi_fatal_err(
2038 "Fail to init txn for Rejuvenate Ack resp %d\n",
2039 ret);
2040 goto out;
2041 }
2042
2043 ret = qmi_send_request(&priv->qmi, NULL, &txn,
2044 QMI_WLFW_REJUVENATE_ACK_REQ_V01,
2045 WLFW_REJUVENATE_ACK_REQ_MSG_V01_MAX_MSG_LEN,
2046 wlfw_rejuvenate_ack_req_msg_v01_ei, req);
2047 if (ret < 0) {
2048 qmi_txn_cancel(&txn);
2049 icnss_qmi_fatal_err("Fail to send Rejuvenate Ack req %d\n",
2050 ret);
2051 goto out;
2052 }
2053
2054 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
2055 if (ret < 0) {
2056 icnss_qmi_fatal_err(
2057 "Rejuvenate Ack resp wait failed with ret %d\n",
2058 ret);
2059 goto out;
2060 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
2061 icnss_qmi_fatal_err(
2062 "QMI Rejuvenate Ack request rejected, result:%d error:%d\n",
2063 resp->resp.result, resp->resp.error);
2064 ret = -resp->resp.result;
2065 goto out;
2066 }
2067
2068 priv->stats.rejuvenate_ack_resp++;
2069
2070 kfree(resp);
2071 kfree(req);
2072 return 0;
2073
2074 out:
2075 kfree(resp);
2076 kfree(req);
2077 priv->stats.rejuvenate_ack_err++;
2078 return ret;
2079 }
2080
wlfw_dynamic_feature_mask_send_sync_msg(struct icnss_priv * priv,uint64_t dynamic_feature_mask)2081 int wlfw_dynamic_feature_mask_send_sync_msg(struct icnss_priv *priv,
2082 uint64_t dynamic_feature_mask)
2083 {
2084 int ret;
2085 struct wlfw_dynamic_feature_mask_req_msg_v01 *req;
2086 struct wlfw_dynamic_feature_mask_resp_msg_v01 *resp;
2087 struct qmi_txn txn;
2088
2089 if (!priv)
2090 return -ENODEV;
2091
2092 if (!test_bit(ICNSS_WLFW_CONNECTED, &priv->state)) {
2093 icnss_pr_err("Invalid state for dynamic feature: 0x%lx\n",
2094 priv->state);
2095 return -EINVAL;
2096 }
2097
2098 if (!test_bit(FW_REJUVENATE_ENABLE, &priv->ctrl_params.quirks)) {
2099 icnss_pr_dbg("FW rejuvenate is disabled from quirks\n");
2100 return 0;
2101 }
2102
2103 icnss_pr_dbg("Sending dynamic feature mask request, val 0x%llx, state: 0x%lx\n",
2104 dynamic_feature_mask, priv->state);
2105
2106 req = kzalloc(sizeof(*req), GFP_KERNEL);
2107 if (!req)
2108 return -ENOMEM;
2109
2110 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
2111 if (!resp) {
2112 kfree(req);
2113 return -ENOMEM;
2114 }
2115
2116 req->mask_valid = 1;
2117 req->mask = dynamic_feature_mask;
2118
2119 ret = qmi_txn_init(&priv->qmi, &txn,
2120 wlfw_dynamic_feature_mask_resp_msg_v01_ei, resp);
2121 if (ret < 0) {
2122 icnss_pr_err("Fail to init txn for Dynamic Feature Mask resp %d\n",
2123 ret);
2124 goto out;
2125 }
2126
2127 ret = qmi_send_request(&priv->qmi, NULL, &txn,
2128 QMI_WLFW_DYNAMIC_FEATURE_MASK_REQ_V01,
2129 WLFW_DYNAMIC_FEATURE_MASK_REQ_MSG_V01_MAX_MSG_LEN,
2130 wlfw_dynamic_feature_mask_req_msg_v01_ei, req);
2131 if (ret < 0) {
2132 qmi_txn_cancel(&txn);
2133 icnss_pr_err("Fail to send Dynamic Feature Mask req %d\n", ret);
2134 goto out;
2135 }
2136
2137 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
2138 if (ret < 0) {
2139 icnss_pr_err("Dynamic Feature Mask resp wait failed with ret %d\n",
2140 ret);
2141 goto out;
2142 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
2143 icnss_pr_err("QMI Dynamic Feature Mask request rejected, result:%d error:%d\n",
2144 resp->resp.result, resp->resp.error);
2145 ret = -resp->resp.result;
2146 goto out;
2147 }
2148
2149 icnss_pr_dbg("prev_mask_valid %u, prev_mask 0x%llx, curr_maks_valid %u, curr_mask 0x%llx\n",
2150 resp->prev_mask_valid, resp->prev_mask,
2151 resp->curr_mask_valid, resp->curr_mask);
2152
2153 out:
2154 kfree(resp);
2155 kfree(req);
2156 return ret;
2157 }
2158
icnss_handle_rejuvenate(struct icnss_priv * priv)2159 void icnss_handle_rejuvenate(struct icnss_priv *priv)
2160 {
2161 struct icnss_event_pd_service_down_data *event_data;
2162 struct icnss_uevent_fw_down_data fw_down_data = {0};
2163
2164 event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
2165 if (event_data == NULL)
2166 return;
2167
2168 event_data->crashed = true;
2169 event_data->fw_rejuvenate = true;
2170 fw_down_data.crashed = true;
2171 set_bit(ICNSS_REJUVENATE, &priv->state);
2172
2173 icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN,
2174 &fw_down_data);
2175 icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
2176 0, event_data);
2177 }
2178
wlfw_qdss_trace_mem_info_send_sync(struct icnss_priv * priv)2179 int wlfw_qdss_trace_mem_info_send_sync(struct icnss_priv *priv)
2180 {
2181 struct wlfw_qdss_trace_mem_info_req_msg_v01 *req;
2182 struct wlfw_qdss_trace_mem_info_resp_msg_v01 *resp;
2183 struct qmi_txn txn;
2184 struct icnss_fw_mem *qdss_mem = priv->qdss_mem;
2185 int ret = 0;
2186 int i;
2187
2188 if (test_bit(ICNSS_FW_DOWN, &priv->state))
2189 return -EINVAL;
2190
2191 icnss_pr_dbg("Sending QDSS trace mem info, state: 0x%lx\n",
2192 priv->state);
2193
2194 req = kzalloc(sizeof(*req), GFP_KERNEL);
2195 if (!req)
2196 return -ENOMEM;
2197
2198 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
2199 if (!resp) {
2200 kfree(req);
2201 return -ENOMEM;
2202 }
2203
2204 req->mem_seg_len = priv->qdss_mem_seg_len;
2205
2206 if (priv->qdss_mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG_V01) {
2207 icnss_pr_err("Invalid seg len %u\n",
2208 priv->qdss_mem_seg_len);
2209 ret = -EINVAL;
2210 goto out;
2211 }
2212
2213 for (i = 0; i < req->mem_seg_len; i++) {
2214 icnss_pr_dbg("Memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx, type: %u\n",
2215 qdss_mem[i].va, &qdss_mem[i].pa,
2216 qdss_mem[i].size, qdss_mem[i].type);
2217
2218 req->mem_seg[i].addr = qdss_mem[i].pa;
2219 req->mem_seg[i].size = qdss_mem[i].size;
2220 req->mem_seg[i].type = qdss_mem[i].type;
2221 }
2222
2223 ret = qmi_txn_init(&priv->qmi, &txn,
2224 wlfw_qdss_trace_mem_info_resp_msg_v01_ei, resp);
2225 if (ret < 0) {
2226 icnss_pr_err("Fail to initialize txn for QDSS trace mem request: err %d\n",
2227 ret);
2228 goto out;
2229 }
2230
2231 ret = qmi_send_request(&priv->qmi, NULL, &txn,
2232 QMI_WLFW_QDSS_TRACE_MEM_INFO_REQ_V01,
2233 WLFW_QDSS_TRACE_MEM_INFO_REQ_MSG_V01_MAX_MSG_LEN,
2234 wlfw_qdss_trace_mem_info_req_msg_v01_ei, req);
2235 if (ret < 0) {
2236 qmi_txn_cancel(&txn);
2237 icnss_pr_err("Fail to send QDSS trace mem info request: err %d\n",
2238 ret);
2239 goto out;
2240 }
2241
2242 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
2243 if (ret < 0) {
2244 icnss_pr_err("Fail to wait for response of QDSS trace mem info request, err %d\n",
2245 ret);
2246 goto out;
2247 }
2248
2249 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
2250 icnss_pr_err("QDSS trace mem info request failed, result: %d, err: %d\n",
2251 resp->resp.result, resp->resp.error);
2252 ret = -resp->resp.result;
2253 goto out;
2254 }
2255
2256 kfree(req);
2257 kfree(resp);
2258 return 0;
2259
2260 out:
2261 kfree(req);
2262 kfree(resp);
2263 return ret;
2264 }
2265
icnss_wlfw_m3_dump_upload_done_send_sync(struct icnss_priv * priv,u32 pdev_id,int status)2266 int icnss_wlfw_m3_dump_upload_done_send_sync(struct icnss_priv *priv,
2267 u32 pdev_id, int status)
2268 {
2269 struct wlfw_m3_dump_upload_done_req_msg_v01 *req;
2270 struct wlfw_m3_dump_upload_done_resp_msg_v01 *resp;
2271 struct qmi_txn txn;
2272 int ret = 0;
2273
2274 req = kzalloc(sizeof(*req), GFP_KERNEL);
2275 if (!req)
2276 return -ENOMEM;
2277
2278 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
2279 if (!resp) {
2280 kfree(req);
2281 return -ENOMEM;
2282 }
2283
2284 icnss_pr_dbg("Sending M3 Upload done req, pdev %d, status %d\n",
2285 pdev_id, status);
2286
2287 req->pdev_id = pdev_id;
2288 req->status = status;
2289
2290 ret = qmi_txn_init(&priv->qmi, &txn,
2291 wlfw_m3_dump_upload_done_resp_msg_v01_ei, resp);
2292 if (ret < 0) {
2293 icnss_pr_err("Fail to initialize txn for M3 dump upload done req: err %d\n",
2294 ret);
2295 goto out;
2296 }
2297
2298 ret = qmi_send_request(&priv->qmi, NULL, &txn,
2299 QMI_WLFW_M3_DUMP_UPLOAD_DONE_REQ_V01,
2300 WLFW_M3_DUMP_UPLOAD_DONE_REQ_MSG_V01_MAX_MSG_LEN,
2301 wlfw_m3_dump_upload_done_req_msg_v01_ei, req);
2302 if (ret < 0) {
2303 qmi_txn_cancel(&txn);
2304 icnss_pr_err("Fail to send M3 dump upload done request: err %d\n",
2305 ret);
2306 goto out;
2307 }
2308
2309 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
2310 if (ret < 0) {
2311 icnss_pr_err("Fail to wait for response of M3 dump upload done request, err %d\n",
2312 ret);
2313 goto out;
2314 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
2315 icnss_pr_err("M3 Dump Upload Done Req failed, result: %d, err: 0x%X\n",
2316 resp->resp.result, resp->resp.error);
2317 ret = -resp->resp.result;
2318 goto out;
2319 }
2320
2321 out:
2322 kfree(req);
2323 kfree(resp);
2324 return ret;
2325 }
2326
fw_ready_ind_cb(struct qmi_handle * qmi,struct sockaddr_qrtr * sq,struct qmi_txn * txn,const void * data)2327 static void fw_ready_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
2328 struct qmi_txn *txn, const void *data)
2329 {
2330 struct icnss_priv *priv =
2331 container_of(qmi, struct icnss_priv, qmi);
2332
2333 icnss_pr_dbg("Received FW Ready Indication\n");
2334
2335 if (!txn) {
2336 pr_err("spurious indication\n");
2337 return;
2338 }
2339
2340 icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_FW_READY_IND,
2341 0, NULL);
2342 }
2343
msa_ready_ind_cb(struct qmi_handle * qmi,struct sockaddr_qrtr * sq,struct qmi_txn * txn,const void * data)2344 static void msa_ready_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
2345 struct qmi_txn *txn, const void *data)
2346 {
2347 struct icnss_priv *priv = container_of(qmi, struct icnss_priv, qmi);
2348 struct device *dev = &priv->pdev->dev;
2349 const struct wlfw_msa_ready_ind_msg_v01 *ind_msg = data;
2350 uint64_t msa_base_addr = priv->msa_pa;
2351 phys_addr_t hang_data_phy_addr;
2352
2353 icnss_pr_dbg("Received MSA Ready Indication\n");
2354
2355 if (!txn) {
2356 pr_err("spurious indication\n");
2357 return;
2358 }
2359
2360 priv->stats.msa_ready_ind++;
2361
2362 /* Check if the length is valid &
2363 * the length should not be 0 and
2364 * should be <= WLFW_MAX_HANG_EVENT_DATA_SIZE(400)
2365 */
2366
2367 if (ind_msg->hang_data_length_valid &&
2368 ind_msg->hang_data_length &&
2369 ind_msg->hang_data_length <= WLFW_MAX_HANG_EVENT_DATA_SIZE)
2370 priv->hang_event_data_len = ind_msg->hang_data_length;
2371 else
2372 goto out;
2373
2374 /* Check if the offset is valid &
2375 * the offset should be in range of 0 to msa_mem_size-hang_data_length
2376 */
2377
2378 if (ind_msg->hang_data_addr_offset_valid &&
2379 (ind_msg->hang_data_addr_offset <= (priv->msa_mem_size -
2380 ind_msg->hang_data_length)))
2381 hang_data_phy_addr = msa_base_addr +
2382 ind_msg->hang_data_addr_offset;
2383 else
2384 goto out;
2385
2386 if (priv->hang_event_data_pa == hang_data_phy_addr)
2387 goto exit;
2388
2389 priv->hang_event_data_pa = hang_data_phy_addr;
2390 priv->hang_event_data_va = devm_ioremap(dev, priv->hang_event_data_pa,
2391 ind_msg->hang_data_length);
2392
2393 if (!priv->hang_event_data_va) {
2394 icnss_pr_err("Hang Data ioremap failed: phy addr: %pa\n",
2395 &priv->hang_event_data_pa);
2396 goto fail;
2397 }
2398 exit:
2399 icnss_pr_dbg("Hang Event Data details,Offset:0x%x, Length:0x%x,va_addr: 0x%pK\n",
2400 ind_msg->hang_data_addr_offset,
2401 ind_msg->hang_data_length,
2402 priv->hang_event_data_va);
2403
2404 return;
2405
2406 out:
2407 icnss_pr_err("Invalid Hang Data details, Offset:0x%x, Length:0x%x",
2408 ind_msg->hang_data_addr_offset,
2409 ind_msg->hang_data_length);
2410 fail:
2411 priv->hang_event_data_va = NULL;
2412 priv->hang_event_data_pa = 0;
2413 priv->hang_event_data_len = 0;
2414 }
2415
pin_connect_result_ind_cb(struct qmi_handle * qmi,struct sockaddr_qrtr * sq,struct qmi_txn * txn,const void * data)2416 static void pin_connect_result_ind_cb(struct qmi_handle *qmi,
2417 struct sockaddr_qrtr *sq,
2418 struct qmi_txn *txn, const void *data)
2419 {
2420 struct icnss_priv *priv = container_of(qmi, struct icnss_priv, qmi);
2421 const struct wlfw_pin_connect_result_ind_msg_v01 *ind_msg = data;
2422
2423 icnss_pr_dbg("Received Pin Connect Result Indication\n");
2424
2425 if (!txn) {
2426 pr_err("spurious indication\n");
2427 return;
2428 }
2429
2430 if (ind_msg->pwr_pin_result_valid)
2431 priv->pwr_pin_result = ind_msg->pwr_pin_result;
2432 if (ind_msg->phy_io_pin_result_valid)
2433 priv->phy_io_pin_result = ind_msg->phy_io_pin_result;
2434 if (ind_msg->rf_pin_result_valid)
2435 priv->rf_pin_result = ind_msg->rf_pin_result;
2436
2437 icnss_pr_dbg("Pin connect Result: pwr_pin: 0x%x phy_io_pin: 0x%x rf_io_pin: 0x%x\n",
2438 ind_msg->pwr_pin_result, ind_msg->phy_io_pin_result,
2439 ind_msg->rf_pin_result);
2440 priv->stats.pin_connect_result++;
2441 }
2442
rejuvenate_ind_cb(struct qmi_handle * qmi,struct sockaddr_qrtr * sq,struct qmi_txn * txn,const void * data)2443 static void rejuvenate_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
2444 struct qmi_txn *txn, const void *data)
2445 {
2446 struct icnss_priv *priv = container_of(qmi, struct icnss_priv, qmi);
2447 const struct wlfw_rejuvenate_ind_msg_v01 *ind_msg = data;
2448
2449 icnss_pr_dbg("Received Rejuvenate Indication\n");
2450
2451 if (!txn) {
2452 pr_err("spurious indication\n");
2453 return;
2454 }
2455
2456 icnss_ignore_fw_timeout(true);
2457
2458 if (ind_msg->cause_for_rejuvenation_valid)
2459 priv->cause_for_rejuvenation = ind_msg->cause_for_rejuvenation;
2460 else
2461 priv->cause_for_rejuvenation = 0;
2462 if (ind_msg->requesting_sub_system_valid)
2463 priv->requesting_sub_system = ind_msg->requesting_sub_system;
2464 else
2465 priv->requesting_sub_system = 0;
2466 if (ind_msg->line_number_valid)
2467 priv->line_number = ind_msg->line_number;
2468 else
2469 priv->line_number = 0;
2470 if (ind_msg->function_name_valid)
2471 memcpy(priv->function_name, ind_msg->function_name,
2472 QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1);
2473 else
2474 memset(priv->function_name, 0,
2475 QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1);
2476
2477 icnss_pr_info("Cause for rejuvenation: 0x%x, requesting sub-system: 0x%x, line number: %u, function name: %s\n",
2478 priv->cause_for_rejuvenation,
2479 priv->requesting_sub_system,
2480 priv->line_number,
2481 priv->function_name);
2482
2483 priv->stats.rejuvenate_ind++;
2484
2485 icnss_handle_rejuvenate(priv);
2486 }
2487
cal_done_ind_cb(struct qmi_handle * qmi,struct sockaddr_qrtr * sq,struct qmi_txn * txn,const void * data)2488 static void cal_done_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
2489 struct qmi_txn *txn, const void *data)
2490 {
2491 struct icnss_priv *priv = container_of(qmi, struct icnss_priv, qmi);
2492
2493 icnss_pr_dbg("Received QMI WLFW calibration done indication\n");
2494
2495 if (!txn) {
2496 icnss_pr_err("Spurious indication\n");
2497 return;
2498 }
2499
2500 priv->cal_done = true;
2501 clear_bit(ICNSS_COLD_BOOT_CAL, &priv->state);
2502 }
2503
fw_init_done_ind_cb(struct qmi_handle * qmi,struct sockaddr_qrtr * sq,struct qmi_txn * txn,const void * data)2504 static void fw_init_done_ind_cb(struct qmi_handle *qmi,
2505 struct sockaddr_qrtr *sq,
2506 struct qmi_txn *txn, const void *data)
2507 {
2508 struct icnss_priv *priv = container_of(qmi, struct icnss_priv, qmi);
2509 struct device *dev = &priv->pdev->dev;
2510 const struct wlfw_fw_init_done_ind_msg_v01 *ind_msg = data;
2511 uint64_t msa_base_addr = priv->msa_pa;
2512 phys_addr_t hang_data_phy_addr;
2513
2514 icnss_pr_dbg("Received QMI WLFW FW initialization done indication\n");
2515
2516 if (!txn) {
2517 icnss_pr_err("Spurious indication\n");
2518 return;
2519 }
2520
2521 /* Check if the length is valid &
2522 * the length should not be 0 and
2523 * should be <= WLFW_MAX_HANG_EVENT_DATA_SIZE(400)
2524 */
2525
2526 if (ind_msg->hang_data_length_valid &&
2527 ind_msg->hang_data_length &&
2528 ind_msg->hang_data_length <= WLFW_MAX_HANG_EVENT_DATA_SIZE)
2529 priv->hang_event_data_len = ind_msg->hang_data_length;
2530 else
2531 goto out;
2532
2533 /* Check if the offset is valid &
2534 * the offset should be in range of 0 to msa_mem_size-hang_data_length
2535 */
2536
2537 if (ind_msg->hang_data_addr_offset_valid &&
2538 (ind_msg->hang_data_addr_offset <= (priv->msa_mem_size -
2539 ind_msg->hang_data_length)))
2540 hang_data_phy_addr = msa_base_addr +
2541 ind_msg->hang_data_addr_offset;
2542 else
2543 goto out;
2544
2545 if (priv->hang_event_data_pa == hang_data_phy_addr)
2546 goto exit;
2547
2548 priv->hang_event_data_pa = hang_data_phy_addr;
2549 priv->hang_event_data_va = devm_ioremap(dev, priv->hang_event_data_pa,
2550 ind_msg->hang_data_length);
2551
2552 if (!priv->hang_event_data_va) {
2553 icnss_pr_err("Hang Data ioremap failed: phy addr: %pa\n",
2554 &priv->hang_event_data_pa);
2555 goto fail;
2556 }
2557
2558 exit:
2559 icnss_pr_dbg("Hang Event Data details,Offset:0x%x, Length:0x%x,va_addr: 0x%pK\n",
2560 ind_msg->hang_data_addr_offset,
2561 ind_msg->hang_data_length,
2562 priv->hang_event_data_va);
2563
2564 goto post;
2565
2566 out:
2567 icnss_pr_err("Invalid Hang Data details, Offset:0x%x, Length:0x%x",
2568 ind_msg->hang_data_addr_offset,
2569 ind_msg->hang_data_length);
2570 fail:
2571 priv->hang_event_data_va = NULL;
2572 priv->hang_event_data_pa = 0;
2573 priv->hang_event_data_len = 0;
2574 post:
2575 icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_FW_INIT_DONE_IND,
2576 0, NULL);
2577
2578 }
2579
wlfw_qdss_trace_req_mem_ind_cb(struct qmi_handle * qmi,struct sockaddr_qrtr * sq,struct qmi_txn * txn,const void * data)2580 static void wlfw_qdss_trace_req_mem_ind_cb(struct qmi_handle *qmi,
2581 struct sockaddr_qrtr *sq,
2582 struct qmi_txn *txn,
2583 const void *data)
2584 {
2585 struct icnss_priv *priv =
2586 container_of(qmi, struct icnss_priv, qmi);
2587 const struct wlfw_qdss_trace_req_mem_ind_msg_v01 *ind_msg = data;
2588 int i;
2589
2590 icnss_pr_dbg("Received QMI WLFW QDSS trace request mem indication\n");
2591
2592 if (!txn) {
2593 icnss_pr_err("Spurious indication\n");
2594 return;
2595 }
2596
2597 if (priv->qdss_mem_seg_len) {
2598 icnss_pr_err("Ignore double allocation for QDSS trace, current len %u\n",
2599 priv->qdss_mem_seg_len);
2600 return;
2601 }
2602
2603 priv->qdss_mem_seg_len = ind_msg->mem_seg_len;
2604
2605 if (priv->qdss_mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG_V01) {
2606 icnss_pr_err("Invalid seg len %u\n",
2607 priv->qdss_mem_seg_len);
2608 return;
2609 }
2610
2611 for (i = 0; i < priv->qdss_mem_seg_len; i++) {
2612 icnss_pr_dbg("QDSS requests for memory, size: 0x%x, type: %u\n",
2613 ind_msg->mem_seg[i].size,
2614 ind_msg->mem_seg[i].type);
2615 priv->qdss_mem[i].type = ind_msg->mem_seg[i].type;
2616 priv->qdss_mem[i].size = ind_msg->mem_seg[i].size;
2617 }
2618
2619 icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_QDSS_TRACE_REQ_MEM,
2620 0, NULL);
2621 }
2622
wlfw_qdss_trace_save_ind_cb(struct qmi_handle * qmi,struct sockaddr_qrtr * sq,struct qmi_txn * txn,const void * data)2623 static void wlfw_qdss_trace_save_ind_cb(struct qmi_handle *qmi,
2624 struct sockaddr_qrtr *sq,
2625 struct qmi_txn *txn,
2626 const void *data)
2627 {
2628 struct icnss_priv *priv =
2629 container_of(qmi, struct icnss_priv, qmi);
2630 const struct wlfw_qdss_trace_save_ind_msg_v01 *ind_msg = data;
2631 struct icnss_qmi_event_qdss_trace_save_data *event_data;
2632 int i = 0;
2633
2634 icnss_pr_dbg("Received QMI WLFW QDSS trace save indication\n");
2635
2636 if (!txn) {
2637 icnss_pr_err("Spurious indication\n");
2638 return;
2639 }
2640
2641 icnss_pr_dbg("QDSS_trace_save info: source %u, total_size %u, file_name_valid %u, file_name %s\n",
2642 ind_msg->source, ind_msg->total_size,
2643 ind_msg->file_name_valid, ind_msg->file_name);
2644
2645 event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
2646 if (!event_data)
2647 return;
2648
2649 if (ind_msg->mem_seg_valid) {
2650 if (ind_msg->mem_seg_len > QDSS_TRACE_SEG_LEN_MAX) {
2651 icnss_pr_err("Invalid seg len %u\n",
2652 ind_msg->mem_seg_len);
2653 goto free_event_data;
2654 }
2655 icnss_pr_dbg("QDSS_trace_save seg len %u\n",
2656 ind_msg->mem_seg_len);
2657 event_data->mem_seg_len = ind_msg->mem_seg_len;
2658 for (i = 0; i < ind_msg->mem_seg_len; i++) {
2659 event_data->mem_seg[i].addr = ind_msg->mem_seg[i].addr;
2660 event_data->mem_seg[i].size = ind_msg->mem_seg[i].size;
2661 icnss_pr_dbg("seg-%d: addr 0x%llx size 0x%x\n",
2662 i, ind_msg->mem_seg[i].addr,
2663 ind_msg->mem_seg[i].size);
2664 }
2665 }
2666
2667 event_data->total_size = ind_msg->total_size;
2668
2669 if (ind_msg->file_name_valid)
2670 strlcpy(event_data->file_name, ind_msg->file_name,
2671 QDSS_TRACE_FILE_NAME_MAX + 1);
2672
2673 if (ind_msg->source == 1) {
2674 if (!ind_msg->file_name_valid)
2675 strlcpy(event_data->file_name, "qdss_trace_wcss_etb",
2676 QDSS_TRACE_FILE_NAME_MAX + 1);
2677 icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_QDSS_TRACE_REQ_DATA,
2678 0, event_data);
2679 } else {
2680 if (!ind_msg->file_name_valid)
2681 strlcpy(event_data->file_name, "qdss_trace_ddr",
2682 QDSS_TRACE_FILE_NAME_MAX + 1);
2683 icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_QDSS_TRACE_SAVE,
2684 0, event_data);
2685 }
2686
2687 return;
2688
2689 free_event_data:
2690 kfree(event_data);
2691 }
2692
wlfw_qdss_trace_free_ind_cb(struct qmi_handle * qmi,struct sockaddr_qrtr * sq,struct qmi_txn * txn,const void * data)2693 static void wlfw_qdss_trace_free_ind_cb(struct qmi_handle *qmi,
2694 struct sockaddr_qrtr *sq,
2695 struct qmi_txn *txn,
2696 const void *data)
2697 {
2698 struct icnss_priv *priv =
2699 container_of(qmi, struct icnss_priv, qmi);
2700
2701 icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_QDSS_TRACE_FREE,
2702 0, NULL);
2703 }
2704
icnss_wlfw_respond_get_info_ind_cb(struct qmi_handle * qmi,struct sockaddr_qrtr * sq,struct qmi_txn * txn,const void * data)2705 static void icnss_wlfw_respond_get_info_ind_cb(struct qmi_handle *qmi,
2706 struct sockaddr_qrtr *sq,
2707 struct qmi_txn *txn,
2708 const void *data)
2709 {
2710 struct icnss_priv *priv = container_of(qmi, struct icnss_priv, qmi);
2711 const struct wlfw_respond_get_info_ind_msg_v01 *ind_msg = data;
2712
2713 if (!txn) {
2714 icnss_pr_err("Spurious indication\n");
2715 return;
2716 }
2717
2718 icnss_pr_vdbg("Extract message with event length: %d, type: %d, is last: %d, seq no: %d\n",
2719 ind_msg->data_len, ind_msg->type,
2720 ind_msg->is_last, ind_msg->seq_no);
2721
2722 if (priv->get_info_cb_ctx && priv->get_info_cb)
2723 priv->get_info_cb(priv->get_info_cb_ctx,
2724 (void *)ind_msg->data,
2725 ind_msg->data_len);
2726 }
2727
icnss_wlfw_m3_dump_upload_segs_req_ind_cb(struct qmi_handle * qmi,struct sockaddr_qrtr * sq,struct qmi_txn * txn,const void * d)2728 static void icnss_wlfw_m3_dump_upload_segs_req_ind_cb(struct qmi_handle *qmi,
2729 struct sockaddr_qrtr *sq,
2730 struct qmi_txn *txn,
2731 const void *d)
2732 {
2733 struct icnss_priv *priv = container_of(qmi, struct icnss_priv, qmi);
2734 const struct wlfw_m3_dump_upload_segments_req_ind_msg_v01 *ind_msg = d;
2735 struct icnss_m3_upload_segments_req_data *event_data = NULL;
2736 u64 max_mapped_addr = 0;
2737 u64 segment_addr = 0;
2738 int i = 0;
2739
2740 icnss_pr_dbg("Received QMI WLFW M3 dump upload sigments indication\n");
2741
2742 if (!txn) {
2743 icnss_pr_err("Spurious indication\n");
2744 return;
2745 }
2746
2747 icnss_pr_dbg("M3 Dump upload info: pdev_id: %d no_of_segments: %d\n",
2748 ind_msg->pdev_id, ind_msg->no_of_valid_segments);
2749
2750 if (ind_msg->no_of_valid_segments > QMI_WLFW_MAX_M3_SEGMENTS_SIZE_V01)
2751 return;
2752
2753 event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
2754 if (!event_data)
2755 return;
2756
2757 event_data->pdev_id = ind_msg->pdev_id;
2758 event_data->no_of_valid_segments = ind_msg->no_of_valid_segments;
2759 max_mapped_addr = priv->msa_pa + priv->msa_mem_size;
2760
2761 for (i = 0; i < ind_msg->no_of_valid_segments; i++) {
2762 segment_addr = ind_msg->m3_segment[i].addr &
2763 M3_SEGMENT_ADDR_MASK;
2764
2765 if (ind_msg->m3_segment[i].size > priv->msa_mem_size ||
2766 segment_addr >= max_mapped_addr ||
2767 segment_addr < priv->msa_pa ||
2768 ind_msg->m3_segment[i].size +
2769 segment_addr > max_mapped_addr) {
2770 icnss_pr_dbg("Received out of range Segment %d Addr: 0x%llx Size: 0x%x, Name: %s, type: %d\n",
2771 (i + 1), segment_addr,
2772 ind_msg->m3_segment[i].size,
2773 ind_msg->m3_segment[i].name,
2774 ind_msg->m3_segment[i].type);
2775 goto out;
2776 }
2777
2778 event_data->m3_segment[i].addr = segment_addr;
2779 event_data->m3_segment[i].size = ind_msg->m3_segment[i].size;
2780 event_data->m3_segment[i].type = ind_msg->m3_segment[i].type;
2781 strlcpy(event_data->m3_segment[i].name,
2782 ind_msg->m3_segment[i].name,
2783 WLFW_MAX_STR_LEN + 1);
2784
2785 icnss_pr_dbg("Received Segment %d Addr: 0x%llx Size: 0x%x, Name: %s, type: %d\n",
2786 (i + 1), segment_addr,
2787 ind_msg->m3_segment[i].size,
2788 ind_msg->m3_segment[i].name,
2789 ind_msg->m3_segment[i].type);
2790 }
2791
2792 icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_M3_DUMP_UPLOAD_REQ,
2793 0, event_data);
2794
2795 return;
2796 out:
2797 kfree(event_data);
2798 }
2799
icnss_wlfw_wfc_call_status_send_sync(struct icnss_priv * priv,const struct ims_private_service_wfc_call_status_ind_msg_v01 * ind_msg)2800 static int icnss_wlfw_wfc_call_status_send_sync
2801 (struct icnss_priv *priv,
2802 const struct ims_private_service_wfc_call_status_ind_msg_v01 *ind_msg)
2803 {
2804 struct wlfw_wfc_call_status_req_msg_v01 *req;
2805 struct wlfw_wfc_call_status_resp_msg_v01 *resp;
2806 struct qmi_txn txn;
2807 int ret = 0;
2808
2809 if (!test_bit(ICNSS_FW_READY, &priv->state) ||
2810 !test_bit(ICNSS_MODE_ON, &priv->state)) {
2811 icnss_pr_err("Drop IMS WFC indication as FW not initialized\n");
2812 return -EINVAL;
2813 }
2814 req = kzalloc(sizeof(*req), GFP_KERNEL);
2815 if (!req)
2816 return -ENOMEM;
2817
2818 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
2819 if (!resp) {
2820 kfree(req);
2821 return -ENOMEM;
2822 }
2823
2824 /**
2825 * WFC Call r1 design has CNSS as pass thru using opaque hex buffer.
2826 * But in r2 update QMI structure is expanded and as an effect qmi
2827 * decoded structures have padding. Thus we cannot use buffer design.
2828 * For backward compatibility for r1 design copy only wfc_call_active
2829 * value in hex buffer.
2830 */
2831 req->wfc_call_status_len = sizeof(ind_msg->wfc_call_active);
2832 req->wfc_call_status[0] = ind_msg->wfc_call_active;
2833
2834 /* wfc_call_active is mandatory in IMS indication */
2835 req->wfc_call_active_valid = 1;
2836 req->wfc_call_active = ind_msg->wfc_call_active;
2837 req->all_wfc_calls_held_valid = ind_msg->all_wfc_calls_held_valid;
2838 req->all_wfc_calls_held = ind_msg->all_wfc_calls_held;
2839 req->is_wfc_emergency_valid = ind_msg->is_wfc_emergency_valid;
2840 req->is_wfc_emergency = ind_msg->is_wfc_emergency;
2841 req->twt_ims_start_valid = ind_msg->twt_ims_start_valid;
2842 req->twt_ims_start = ind_msg->twt_ims_start;
2843 req->twt_ims_int_valid = ind_msg->twt_ims_int_valid;
2844 req->twt_ims_int = ind_msg->twt_ims_int;
2845 req->media_quality_valid = ind_msg->media_quality_valid;
2846 req->media_quality =
2847 (enum wlfw_wfc_media_quality_v01)ind_msg->media_quality;
2848
2849 icnss_pr_dbg("CNSS->FW: WFC_CALL_REQ: state: 0x%lx\n",
2850 priv->state);
2851
2852 ret = qmi_txn_init(&priv->qmi, &txn,
2853 wlfw_wfc_call_status_resp_msg_v01_ei, resp);
2854 if (ret < 0) {
2855 icnss_pr_err("CNSS->FW: WFC_CALL_REQ: QMI Txn Init: Err %d\n",
2856 ret);
2857 goto out;
2858 }
2859
2860 ret = qmi_send_request(&priv->qmi, NULL, &txn,
2861 QMI_WLFW_WFC_CALL_STATUS_REQ_V01,
2862 WLFW_WFC_CALL_STATUS_REQ_MSG_V01_MAX_MSG_LEN,
2863 wlfw_wfc_call_status_req_msg_v01_ei, req);
2864 if (ret < 0) {
2865 qmi_txn_cancel(&txn);
2866 icnss_pr_err("CNSS->FW: WFC_CALL_REQ: QMI Send Err: %d\n",
2867 ret);
2868 goto out;
2869 }
2870
2871 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
2872 if (ret < 0) {
2873 icnss_pr_err("FW->CNSS: WFC_CALL_RSP: QMI Wait Err: %d\n",
2874 ret);
2875 goto out;
2876 }
2877
2878 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
2879 icnss_pr_err("FW->CNSS: WFC_CALL_RSP: Result: %d Err: %d\n",
2880 resp->resp.result, resp->resp.error);
2881 ret = -resp->resp.result;
2882 goto out;
2883 }
2884 ret = 0;
2885 out:
2886 kfree(req);
2887 kfree(resp);
2888 return ret;
2889 }
2890
icnss_ims_wfc_call_twt_cfg_send_sync(struct icnss_priv * priv,const struct wlfw_wfc_call_twt_config_ind_msg_v01 * ind_msg)2891 static int icnss_ims_wfc_call_twt_cfg_send_sync
2892 (struct icnss_priv *priv,
2893 const struct wlfw_wfc_call_twt_config_ind_msg_v01 *ind_msg)
2894 {
2895 struct ims_private_service_wfc_call_twt_config_req_msg_v01 *req;
2896 struct ims_private_service_wfc_call_twt_config_rsp_msg_v01 *resp;
2897 struct qmi_txn txn;
2898 int ret = 0;
2899
2900 if (!test_bit(ICNSS_IMS_CONNECTED, &priv->state)) {
2901 icnss_pr_err("Drop FW WFC indication as IMS QMI not connected\n");
2902 return -EINVAL;
2903 }
2904
2905 req = kzalloc(sizeof(*req), GFP_KERNEL);
2906 if (!req)
2907 return -ENOMEM;
2908
2909 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
2910 if (!resp) {
2911 kfree(req);
2912 return -ENOMEM;
2913 }
2914
2915 req->twt_sta_start_valid = ind_msg->twt_sta_start_valid;
2916 req->twt_sta_start = ind_msg->twt_sta_start;
2917 req->twt_sta_int_valid = ind_msg->twt_sta_int_valid;
2918 req->twt_sta_int = ind_msg->twt_sta_int;
2919 req->twt_sta_upo_valid = ind_msg->twt_sta_upo_valid;
2920 req->twt_sta_upo = ind_msg->twt_sta_upo;
2921 req->twt_sta_sp_valid = ind_msg->twt_sta_sp_valid;
2922 req->twt_sta_sp = ind_msg->twt_sta_sp;
2923 req->twt_sta_dl_valid = req->twt_sta_dl_valid;
2924 req->twt_sta_dl = req->twt_sta_dl;
2925 req->twt_sta_config_changed_valid =
2926 ind_msg->twt_sta_config_changed_valid;
2927 req->twt_sta_config_changed = ind_msg->twt_sta_config_changed;
2928
2929 icnss_pr_dbg("CNSS->IMS: TWT_CFG_REQ: state: 0x%lx\n",
2930 priv->state);
2931
2932 ret =
2933 qmi_txn_init(&priv->ims_qmi, &txn,
2934 ims_private_service_wfc_call_twt_config_rsp_msg_v01_ei,
2935 resp);
2936 if (ret < 0) {
2937 icnss_pr_err("CNSS->IMS: TWT_CFG_REQ: QMI Txn Init Err: %d\n",
2938 ret);
2939 goto out;
2940 }
2941
2942 ret =
2943 qmi_send_request(&priv->ims_qmi, NULL, &txn,
2944 QMI_IMS_PRIVATE_SERVICE_WFC_CALL_TWT_CONFIG_REQ_V01,
2945 IMS_PRIVATE_SERVICE_WFC_CALL_TWT_CONFIG_REQ_MSG_V01_MAX_MSG_LEN,
2946 ims_private_service_wfc_call_twt_config_req_msg_v01_ei, req);
2947 if (ret < 0) {
2948 qmi_txn_cancel(&txn);
2949 icnss_pr_err("CNSS->IMS: TWT_CFG_REQ: QMI Send Err: %d\n", ret);
2950 goto out;
2951 }
2952
2953 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
2954 if (ret < 0) {
2955 icnss_pr_err("IMS->CNSS: TWT_CFG_RSP: QMI Wait Err: %d\n", ret);
2956 goto out;
2957 }
2958
2959 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
2960 icnss_pr_err("IMS->CNSS: TWT_CFG_RSP: Result: %d Err: %d\n",
2961 resp->resp.result, resp->resp.error);
2962 ret = -resp->resp.result;
2963 goto out;
2964 }
2965 ret = 0;
2966 out:
2967 kfree(req);
2968 kfree(resp);
2969 return ret;
2970 }
2971
icnss_process_twt_cfg_ind_event(struct icnss_priv * priv,void * data)2972 int icnss_process_twt_cfg_ind_event(struct icnss_priv *priv,
2973 void *data)
2974 {
2975 int ret;
2976 struct wlfw_wfc_call_twt_config_ind_msg_v01 *ind_msg = data;
2977
2978 ret = icnss_ims_wfc_call_twt_cfg_send_sync(priv, ind_msg);
2979 kfree(data);
2980 return ret;
2981 }
2982
icnss_wlfw_process_twt_cfg_ind(struct qmi_handle * qmi,struct sockaddr_qrtr * sq,struct qmi_txn * txn,const void * data)2983 static void icnss_wlfw_process_twt_cfg_ind(struct qmi_handle *qmi,
2984 struct sockaddr_qrtr *sq,
2985 struct qmi_txn *txn,
2986 const void *data)
2987 {
2988 struct icnss_priv *priv =
2989 container_of(qmi, struct icnss_priv, qmi);
2990 const struct wlfw_wfc_call_twt_config_ind_msg_v01 *ind_msg = data;
2991 struct wlfw_wfc_call_twt_config_ind_msg_v01 *event_data;
2992
2993 if (!txn) {
2994 icnss_pr_err("FW->CNSS: TWT_CFG_IND: Spurious indication\n");
2995 return;
2996 }
2997
2998 if (!ind_msg) {
2999 icnss_pr_err("FW->CNSS: TWT_CFG_IND: Invalid indication\n");
3000 return;
3001 }
3002 icnss_pr_dbg("FW->CNSS: TWT_CFG_IND: %x %llx, %x %x, %x %x, %x %x, %x %x, %x %x\n",
3003 ind_msg->twt_sta_start_valid, ind_msg->twt_sta_start,
3004 ind_msg->twt_sta_int_valid, ind_msg->twt_sta_int,
3005 ind_msg->twt_sta_upo_valid, ind_msg->twt_sta_upo,
3006 ind_msg->twt_sta_sp_valid, ind_msg->twt_sta_sp,
3007 ind_msg->twt_sta_dl_valid, ind_msg->twt_sta_dl,
3008 ind_msg->twt_sta_config_changed_valid,
3009 ind_msg->twt_sta_config_changed);
3010
3011 event_data = kmemdup(ind_msg, sizeof(*event_data), GFP_KERNEL);
3012 if (!event_data)
3013 return;
3014 icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_WLFW_TWT_CFG_IND, 0,
3015 event_data);
3016 }
3017
3018 static struct qmi_msg_handler wlfw_msg_handlers[] = {
3019 {
3020 .type = QMI_INDICATION,
3021 .msg_id = QMI_WLFW_FW_READY_IND_V01,
3022 .ei = wlfw_fw_ready_ind_msg_v01_ei,
3023 .decoded_size = sizeof(struct wlfw_fw_ready_ind_msg_v01),
3024 .fn = fw_ready_ind_cb
3025 },
3026 {
3027 .type = QMI_INDICATION,
3028 .msg_id = QMI_WLFW_MSA_READY_IND_V01,
3029 .ei = wlfw_msa_ready_ind_msg_v01_ei,
3030 .decoded_size = sizeof(struct wlfw_msa_ready_ind_msg_v01),
3031 .fn = msa_ready_ind_cb
3032 },
3033 {
3034 .type = QMI_INDICATION,
3035 .msg_id = QMI_WLFW_PIN_CONNECT_RESULT_IND_V01,
3036 .ei = wlfw_pin_connect_result_ind_msg_v01_ei,
3037 .decoded_size =
3038 sizeof(struct wlfw_pin_connect_result_ind_msg_v01),
3039 .fn = pin_connect_result_ind_cb
3040 },
3041 {
3042 .type = QMI_INDICATION,
3043 .msg_id = QMI_WLFW_REJUVENATE_IND_V01,
3044 .ei = wlfw_rejuvenate_ind_msg_v01_ei,
3045 .decoded_size = sizeof(struct wlfw_rejuvenate_ind_msg_v01),
3046 .fn = rejuvenate_ind_cb
3047 },
3048 {
3049 .type = QMI_INDICATION,
3050 .msg_id = QMI_WLFW_CAL_DONE_IND_V01,
3051 .ei = wlfw_cal_done_ind_msg_v01_ei,
3052 .decoded_size = sizeof(struct wlfw_cal_done_ind_msg_v01),
3053 .fn = cal_done_ind_cb
3054 },
3055 {
3056 .type = QMI_INDICATION,
3057 .msg_id = QMI_WLFW_FW_INIT_DONE_IND_V01,
3058 .ei = wlfw_fw_init_done_ind_msg_v01_ei,
3059 .decoded_size = sizeof(struct wlfw_fw_init_done_ind_msg_v01),
3060 .fn = fw_init_done_ind_cb
3061 },
3062 {
3063 .type = QMI_INDICATION,
3064 .msg_id = QMI_WLFW_QDSS_TRACE_REQ_MEM_IND_V01,
3065 .ei = wlfw_qdss_trace_req_mem_ind_msg_v01_ei,
3066 .decoded_size =
3067 sizeof(struct wlfw_qdss_trace_req_mem_ind_msg_v01),
3068 .fn = wlfw_qdss_trace_req_mem_ind_cb
3069 },
3070 {
3071 .type = QMI_INDICATION,
3072 .msg_id = QMI_WLFW_QDSS_TRACE_SAVE_IND_V01,
3073 .ei = wlfw_qdss_trace_save_ind_msg_v01_ei,
3074 .decoded_size =
3075 sizeof(struct wlfw_qdss_trace_save_ind_msg_v01),
3076 .fn = wlfw_qdss_trace_save_ind_cb
3077 },
3078 {
3079 .type = QMI_INDICATION,
3080 .msg_id = QMI_WLFW_QDSS_TRACE_FREE_IND_V01,
3081 .ei = wlfw_qdss_trace_free_ind_msg_v01_ei,
3082 .decoded_size =
3083 sizeof(struct wlfw_qdss_trace_free_ind_msg_v01),
3084 .fn = wlfw_qdss_trace_free_ind_cb
3085 },
3086 {
3087 .type = QMI_INDICATION,
3088 .msg_id = QMI_WLFW_RESPOND_GET_INFO_IND_V01,
3089 .ei = wlfw_respond_get_info_ind_msg_v01_ei,
3090 .decoded_size =
3091 sizeof(struct wlfw_respond_get_info_ind_msg_v01),
3092 .fn = icnss_wlfw_respond_get_info_ind_cb
3093 },
3094 {
3095 .type = QMI_INDICATION,
3096 .msg_id = QMI_WLFW_M3_DUMP_UPLOAD_SEGMENTS_REQ_IND_V01,
3097 .ei = wlfw_m3_dump_upload_segments_req_ind_msg_v01_ei,
3098 .decoded_size =
3099 sizeof(struct wlfw_m3_dump_upload_segments_req_ind_msg_v01),
3100 .fn = icnss_wlfw_m3_dump_upload_segs_req_ind_cb
3101 },
3102 {
3103 .type = QMI_INDICATION,
3104 .msg_id = QMI_WLFW_WFC_CALL_TWT_CONFIG_IND_V01,
3105 .ei = wlfw_wfc_call_twt_config_ind_msg_v01_ei,
3106 .decoded_size =
3107 sizeof(struct wlfw_wfc_call_twt_config_ind_msg_v01),
3108 .fn = icnss_wlfw_process_twt_cfg_ind
3109 },
3110 {}
3111 };
3112
icnss_connect_to_fw_server(struct icnss_priv * priv,void * data)3113 int icnss_connect_to_fw_server(struct icnss_priv *priv, void *data)
3114 {
3115 struct icnss_event_server_arrive_data *event_data = data;
3116 struct qmi_handle *qmi = &priv->qmi;
3117 struct sockaddr_qrtr sq = { 0 };
3118 int ret = 0;
3119
3120 if (!priv) {
3121 ret = -ENODEV;
3122 goto out;
3123 }
3124
3125 sq.sq_family = AF_QIPCRTR;
3126 sq.sq_node = event_data->node;
3127 sq.sq_port = event_data->port;
3128 ret = kernel_connect(qmi->sock, (struct sockaddr *)&sq, sizeof(sq), 0);
3129 if (ret < 0) {
3130 icnss_pr_err("Fail to connect to remote service port\n");
3131 goto out;
3132 }
3133
3134 icnss_pr_info("QMI Server Connected: state: 0x%lx\n", priv->state);
3135
3136 kfree(data);
3137 return 0;
3138
3139 out:
3140 kfree(data);
3141 ICNSS_ASSERT(0);
3142 return ret;
3143 }
3144
icnss_clear_server(struct icnss_priv * priv)3145 int icnss_clear_server(struct icnss_priv *priv)
3146 {
3147 int ret;
3148
3149 if (!priv)
3150 return -ENODEV;
3151
3152 icnss_pr_info("QMI Service Disconnected: 0x%lx\n", priv->state);
3153 clear_bit(ICNSS_WLFW_CONNECTED, &priv->state);
3154
3155 icnss_unregister_fw_service(priv);
3156
3157 clear_bit(ICNSS_DEL_SERVER, &priv->state);
3158
3159 ret = icnss_register_fw_service(priv);
3160 if (ret < 0) {
3161 icnss_pr_err("WLFW server registration failed\n");
3162 ICNSS_ASSERT(0);
3163 }
3164
3165 return 0;
3166 }
3167
wlfw_new_server(struct qmi_handle * qmi,struct qmi_service * service)3168 static int wlfw_new_server(struct qmi_handle *qmi,
3169 struct qmi_service *service)
3170 {
3171 struct icnss_priv *priv =
3172 container_of(qmi, struct icnss_priv, qmi);
3173 struct icnss_event_server_arrive_data *event_data;
3174
3175 if (priv && test_bit(ICNSS_DEL_SERVER, &priv->state)) {
3176 icnss_pr_info("WLFW server delete in progress, Ignore server arrive: 0x%lx\n",
3177 priv->state);
3178 return 0;
3179 }
3180
3181 icnss_pr_dbg("WLFW server arrive: node %u port %u\n",
3182 service->node, service->port);
3183
3184 event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
3185 if (event_data == NULL)
3186 return -ENOMEM;
3187
3188 event_data->node = service->node;
3189 event_data->port = service->port;
3190
3191 icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_SERVER_ARRIVE,
3192 0, event_data);
3193
3194 return 0;
3195 }
3196
wlfw_del_server(struct qmi_handle * qmi,struct qmi_service * service)3197 static void wlfw_del_server(struct qmi_handle *qmi,
3198 struct qmi_service *service)
3199 {
3200 struct icnss_priv *priv = container_of(qmi, struct icnss_priv, qmi);
3201
3202 if (priv && test_bit(ICNSS_DEL_SERVER, &priv->state)) {
3203 icnss_pr_info("WLFW server delete / icnss remove in progress, Ignore server delete: 0x%lx\n",
3204 priv->state);
3205 return;
3206 }
3207
3208 icnss_pr_dbg("WLFW server delete\n");
3209
3210 if (priv) {
3211 set_bit(ICNSS_DEL_SERVER, &priv->state);
3212 set_bit(ICNSS_FW_DOWN, &priv->state);
3213 icnss_ignore_fw_timeout(true);
3214 }
3215
3216 icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_SERVER_EXIT,
3217 0, NULL);
3218 }
3219
3220 static struct qmi_ops wlfw_qmi_ops = {
3221 .new_server = wlfw_new_server,
3222 .del_server = wlfw_del_server,
3223 };
3224
icnss_register_fw_service(struct icnss_priv * priv)3225 int icnss_register_fw_service(struct icnss_priv *priv)
3226 {
3227 int ret;
3228
3229 ret = qmi_handle_init(&priv->qmi,
3230 WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN,
3231 &wlfw_qmi_ops, wlfw_msg_handlers);
3232 if (ret < 0)
3233 return ret;
3234
3235 if (priv->device_id == WCN6750_DEVICE_ID ||
3236 priv->device_id == WCN6450_DEVICE_ID)
3237 ret = qmi_add_lookup(&priv->qmi, WLFW_SERVICE_ID_V01,
3238 WLFW_SERVICE_VERS_V01,
3239 WLFW_SERVICE_WCN_INS_ID_V01);
3240 else
3241 ret = qmi_add_lookup(&priv->qmi, WLFW_SERVICE_ID_V01,
3242 WLFW_SERVICE_VERS_V01,
3243 WLFW_SERVICE_INS_ID_V01);
3244 return ret;
3245 }
3246
icnss_unregister_fw_service(struct icnss_priv * priv)3247 void icnss_unregister_fw_service(struct icnss_priv *priv)
3248 {
3249 set_bit(ICNSS_DEL_SERVER, &priv->state);
3250 qmi_handle_release(&priv->qmi);
3251 }
3252
icnss_send_wlan_enable_to_fw(struct icnss_priv * priv,struct icnss_wlan_enable_cfg * config,enum icnss_driver_mode mode,const char * host_version)3253 int icnss_send_wlan_enable_to_fw(struct icnss_priv *priv,
3254 struct icnss_wlan_enable_cfg *config,
3255 enum icnss_driver_mode mode,
3256 const char *host_version)
3257 {
3258 struct wlfw_wlan_cfg_req_msg_v01 req;
3259 u32 i;
3260 int ret;
3261
3262 icnss_pr_dbg("Mode: %d, config: %pK, host_version: %s\n",
3263 mode, config, host_version);
3264
3265 memset(&req, 0, sizeof(req));
3266
3267 if (mode == ICNSS_WALTEST || mode == ICNSS_CCPM)
3268 goto skip;
3269
3270 if (!config || !host_version) {
3271 icnss_pr_err("Invalid cfg pointer, config: %pK, host_version: %pK\n",
3272 config, host_version);
3273 ret = -EINVAL;
3274 goto out;
3275 }
3276
3277 req.host_version_valid = 1;
3278 strlcpy(req.host_version, host_version,
3279 WLFW_MAX_STR_LEN + 1);
3280
3281 req.tgt_cfg_valid = 1;
3282 if (config->num_ce_tgt_cfg > WLFW_MAX_NUM_CE)
3283 req.tgt_cfg_len = WLFW_MAX_NUM_CE;
3284 else
3285 req.tgt_cfg_len = config->num_ce_tgt_cfg;
3286 for (i = 0; i < req.tgt_cfg_len; i++) {
3287 req.tgt_cfg[i].pipe_num = config->ce_tgt_cfg[i].pipe_num;
3288 req.tgt_cfg[i].pipe_dir = config->ce_tgt_cfg[i].pipe_dir;
3289 req.tgt_cfg[i].nentries = config->ce_tgt_cfg[i].nentries;
3290 req.tgt_cfg[i].nbytes_max = config->ce_tgt_cfg[i].nbytes_max;
3291 req.tgt_cfg[i].flags = config->ce_tgt_cfg[i].flags;
3292 }
3293
3294 req.svc_cfg_valid = 1;
3295 if (config->num_ce_svc_pipe_cfg > WLFW_MAX_NUM_SVC)
3296 req.svc_cfg_len = WLFW_MAX_NUM_SVC;
3297 else
3298 req.svc_cfg_len = config->num_ce_svc_pipe_cfg;
3299 for (i = 0; i < req.svc_cfg_len; i++) {
3300 req.svc_cfg[i].service_id = config->ce_svc_cfg[i].service_id;
3301 req.svc_cfg[i].pipe_dir = config->ce_svc_cfg[i].pipe_dir;
3302 req.svc_cfg[i].pipe_num = config->ce_svc_cfg[i].pipe_num;
3303 }
3304
3305 if (priv->device_id == WCN6750_DEVICE_ID) {
3306 req.shadow_reg_v2_valid = 1;
3307 if (config->num_shadow_reg_v2_cfg >
3308 QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01)
3309 req.shadow_reg_v2_len =
3310 QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01;
3311 else
3312 req.shadow_reg_v2_len = config->num_shadow_reg_v2_cfg;
3313
3314 memcpy(req.shadow_reg_v2, config->shadow_reg_v2_cfg,
3315 sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01) *
3316 req.shadow_reg_v2_len);
3317 } else if (priv->device_id == ADRASTEA_DEVICE_ID) {
3318 req.shadow_reg_valid = 1;
3319 if (config->num_shadow_reg_cfg >
3320 QMI_WLFW_MAX_NUM_SHADOW_REG_V01)
3321 req.shadow_reg_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V01;
3322 else
3323 req.shadow_reg_len = config->num_shadow_reg_cfg;
3324
3325 memcpy(req.shadow_reg, config->shadow_reg_cfg,
3326 sizeof(struct wlfw_msi_cfg_s_v01) * req.shadow_reg_len);
3327 } else if (priv->device_id == WCN6450_DEVICE_ID) {
3328 req.shadow_reg_v3_valid = 1;
3329 if (config->num_shadow_reg_v3_cfg >
3330 MAX_NUM_SHADOW_REG_V3)
3331 req.shadow_reg_v3_len = MAX_NUM_SHADOW_REG_V3;
3332 else
3333 req.shadow_reg_v3_len = config->num_shadow_reg_v3_cfg;
3334
3335 memcpy(req.shadow_reg_v3, config->shadow_reg_v3_cfg,
3336 sizeof(struct wlfw_shadow_reg_v3_cfg_s_v01)
3337 * req.shadow_reg_v3_len);
3338 }
3339
3340 ret = wlfw_wlan_cfg_send_sync_msg(priv, &req);
3341 if (ret)
3342 goto out;
3343 skip:
3344 ret = wlfw_wlan_mode_send_sync_msg(priv,
3345 (enum wlfw_driver_mode_enum_v01)mode);
3346 out:
3347 if (test_bit(SKIP_QMI, &priv->ctrl_params.quirks))
3348 ret = 0;
3349
3350 return ret;
3351 }
3352
icnss_send_wlan_disable_to_fw(struct icnss_priv * priv)3353 int icnss_send_wlan_disable_to_fw(struct icnss_priv *priv)
3354 {
3355 enum wlfw_driver_mode_enum_v01 mode = QMI_WLFW_OFF_V01;
3356
3357 return wlfw_wlan_mode_send_sync_msg(priv, mode);
3358 }
3359
3360 #ifdef CONFIG_ICNSS2_DEBUG
icnss_get_host_build_type(void)3361 static inline u32 icnss_get_host_build_type(void)
3362 {
3363 return QMI_HOST_BUILD_TYPE_PRIMARY_V01;
3364 }
3365 #else
icnss_get_host_build_type(void)3366 static inline u32 icnss_get_host_build_type(void)
3367 {
3368 return QMI_HOST_BUILD_TYPE_SECONDARY_V01;
3369 }
3370 #endif
3371
wlfw_host_cap_send_sync(struct icnss_priv * priv)3372 int wlfw_host_cap_send_sync(struct icnss_priv *priv)
3373 {
3374 struct wlfw_host_cap_req_msg_v01 *req;
3375 struct wlfw_host_cap_resp_msg_v01 *resp;
3376 struct qmi_txn txn;
3377 int ddr_type;
3378 u32 gpio;
3379 int ret = 0;
3380 u64 iova_start = 0, iova_size = 0,
3381 iova_ipa_start = 0, iova_ipa_size = 0;
3382
3383 icnss_pr_dbg("Sending host capability message, state: 0x%lx\n",
3384 priv->state);
3385
3386 req = kzalloc(sizeof(*req), GFP_KERNEL);
3387 if (!req)
3388 return -ENOMEM;
3389
3390 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
3391 if (!resp) {
3392 kfree(req);
3393 return -ENOMEM;
3394 }
3395
3396 req->num_clients_valid = 1;
3397 req->num_clients = 1;
3398
3399 req->bdf_support_valid = 1;
3400 req->bdf_support = 1;
3401
3402 req->cal_done_valid = 1;
3403 req->cal_done = priv->cal_done;
3404 icnss_pr_dbg("Calibration done is %d\n", priv->cal_done);
3405
3406 if (priv->smmu_s1_enable &&
3407 !icnss_get_iova(priv, &iova_start, &iova_size) &&
3408 !icnss_get_iova_ipa(priv, &iova_ipa_start,
3409 &iova_ipa_size)) {
3410 req->ddr_range_valid = 1;
3411 req->ddr_range[0].start = iova_start;
3412 req->ddr_range[0].size = iova_size + iova_ipa_size;
3413 req->ddr_range[1].start = priv->msa_pa;
3414 req->ddr_range[1].size = priv->msa_mem_size;
3415 icnss_pr_dbg("Sending iova starting 0x%llx with size 0x%llx\n",
3416 req->ddr_range[0].start, req->ddr_range[0].size);
3417 icnss_pr_dbg("Sending msa starting 0x%llx with size 0x%llx\n",
3418 req->ddr_range[1].start, req->ddr_range[1].size);
3419 }
3420
3421 req->host_build_type_valid = 1;
3422 req->host_build_type = icnss_get_host_build_type();
3423
3424 if (priv->wlan_en_delay_ms >= 100) {
3425 icnss_pr_dbg("Setting WLAN_EN delay: %d ms\n",
3426 priv->wlan_en_delay_ms);
3427 req->wlan_enable_delay_valid = 1;
3428 req->wlan_enable_delay = priv->wlan_en_delay_ms;
3429 }
3430
3431 /* ddr_type = 7(LPDDR4) and 8(LPDDR5) */
3432 ddr_type = of_fdt_get_ddrtype();
3433 if (ddr_type > 0) {
3434 icnss_pr_dbg("DDR Type: %d\n", ddr_type);
3435 req->ddr_type_valid = 1;
3436 req->ddr_type = ddr_type;
3437 }
3438
3439 ret = of_property_read_u32(priv->pdev->dev.of_node, "wlan-en-gpio",
3440 &gpio);
3441 if (!ret) {
3442 icnss_pr_dbg("WLAN_EN_GPIO modified through DT: %d\n", gpio);
3443 req->gpio_info_valid = 1;
3444 req->gpio_info[WLAN_EN_GPIO_V01] = gpio;
3445 } else {
3446 req->gpio_info[WLAN_EN_GPIO_V01] = 0xFFFF;
3447 }
3448
3449 ret = of_property_read_u32(priv->pdev->dev.of_node, "bt-en-gpio",
3450 &gpio);
3451 if (!ret) {
3452 icnss_pr_dbg("BT_EN_GPIO modified through DT: %d\n", gpio);
3453 req->gpio_info_valid = 1;
3454 req->gpio_info[BT_EN_GPIO_V01] = gpio;
3455 } else {
3456 req->gpio_info[BT_EN_GPIO_V01] = 0xFFFF;
3457 }
3458
3459 ret = of_property_read_u32(priv->pdev->dev.of_node, "host-sol-gpio",
3460 &gpio);
3461 if (!ret) {
3462 icnss_pr_dbg("HOST_SOL_GPIO modified through DT: %d\n", gpio);
3463 req->gpio_info_valid = 1;
3464 req->gpio_info[HOST_SOL_GPIO_V01] = gpio;
3465 } else {
3466 req->gpio_info[HOST_SOL_GPIO_V01] = 0xFFFF;
3467 }
3468
3469 ret = of_property_read_u32(priv->pdev->dev.of_node, "target-sol-gpio",
3470 &gpio);
3471 if (!ret) {
3472 icnss_pr_dbg("TARGET_SOL_GPIO modified through DT: %d\n", gpio);
3473 req->gpio_info_valid = 1;
3474 req->gpio_info[TARGET_SOL_GPIO_V01] = gpio;
3475 } else {
3476 req->gpio_info[TARGET_SOL_GPIO_V01] = 0xFFFF;
3477 }
3478
3479 req->gpio_info_len = GPIO_TYPE_MAX_V01;
3480
3481 ret = qmi_txn_init(&priv->qmi, &txn,
3482 wlfw_host_cap_resp_msg_v01_ei, resp);
3483 if (ret < 0) {
3484 icnss_pr_err("Failed to initialize txn for host capability request, err: %d\n",
3485 ret);
3486 goto out;
3487 }
3488
3489 ret = qmi_send_request(&priv->qmi, NULL, &txn,
3490 QMI_WLFW_HOST_CAP_REQ_V01,
3491 WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN,
3492 wlfw_host_cap_req_msg_v01_ei, req);
3493 if (ret < 0) {
3494 qmi_txn_cancel(&txn);
3495 icnss_pr_err("Failed to send host capability request, err: %d\n",
3496 ret);
3497 goto out;
3498 }
3499
3500 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
3501 if (ret < 0) {
3502 icnss_pr_err("Failed to wait for response of host capability request, err: %d\n",
3503 ret);
3504 goto out;
3505 }
3506
3507 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
3508 icnss_pr_err("Host capability request failed, result: %d, err: %d\n",
3509 resp->resp.result, resp->resp.error);
3510 ret = -resp->resp.result;
3511 goto out;
3512 }
3513
3514 kfree(req);
3515 kfree(resp);
3516 return 0;
3517
3518 out:
3519 ICNSS_QMI_ASSERT();
3520 kfree(req);
3521 kfree(resp);
3522 return ret;
3523 }
3524
icnss_wlfw_get_info_send_sync(struct icnss_priv * plat_priv,int type,void * cmd,int cmd_len)3525 int icnss_wlfw_get_info_send_sync(struct icnss_priv *plat_priv, int type,
3526 void *cmd, int cmd_len)
3527 {
3528 struct wlfw_get_info_req_msg_v01 *req;
3529 struct wlfw_get_info_resp_msg_v01 *resp;
3530 struct qmi_txn txn;
3531 int ret = 0;
3532 int flags = GFP_KERNEL & ~__GFP_DIRECT_RECLAIM;
3533
3534 if (cmd_len > QMI_WLFW_MAX_DATA_SIZE_V01)
3535 return -EINVAL;
3536
3537 if (test_bit(ICNSS_FW_DOWN, &plat_priv->state))
3538 return -EINVAL;
3539
3540 req = kzalloc(sizeof(*req), flags);
3541 if (!req)
3542 return -ENOMEM;
3543
3544 resp = kzalloc(sizeof(*resp), flags);
3545 if (!resp) {
3546 kfree(req);
3547 return -ENOMEM;
3548 }
3549
3550 req->type = type;
3551 req->data_len = cmd_len;
3552 memcpy(req->data, cmd, req->data_len);
3553
3554 ret = qmi_txn_init(&plat_priv->qmi, &txn,
3555 wlfw_get_info_resp_msg_v01_ei, resp);
3556 if (ret < 0) {
3557 icnss_pr_err("Failed to initialize txn for get info request, err: %d\n",
3558 ret);
3559 goto out;
3560 }
3561
3562 ret = qmi_send_request(&plat_priv->qmi, NULL, &txn,
3563 QMI_WLFW_GET_INFO_REQ_V01,
3564 WLFW_GET_INFO_REQ_MSG_V01_MAX_MSG_LEN,
3565 wlfw_get_info_req_msg_v01_ei, req);
3566 if (ret < 0) {
3567 qmi_txn_cancel(&txn);
3568 icnss_pr_err("Failed to send get info request, err: %d\n",
3569 ret);
3570 goto out;
3571 }
3572
3573 ret = qmi_txn_wait(&txn, plat_priv->ctrl_params.qmi_timeout);
3574 if (ret < 0) {
3575 icnss_pr_err("Failed to wait for response of get info request, err: %d\n",
3576 ret);
3577 goto out;
3578 }
3579
3580 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
3581 icnss_pr_err("Get info request failed, result: %d, err: %d\n",
3582 resp->resp.result, resp->resp.error);
3583 ret = -resp->resp.result;
3584 goto out;
3585 }
3586
3587 kfree(req);
3588 kfree(resp);
3589 return 0;
3590
3591 out:
3592 kfree(req);
3593 kfree(resp);
3594 return ret;
3595 }
3596
wlfw_subsys_restart_level_msg(struct icnss_priv * penv,uint8_t restart_level)3597 int wlfw_subsys_restart_level_msg(struct icnss_priv *penv, uint8_t restart_level)
3598 {
3599 int ret;
3600 struct wlfw_subsys_restart_level_req_msg_v01 *req;
3601 struct wlfw_subsys_restart_level_resp_msg_v01 *resp;
3602 struct qmi_txn txn;
3603
3604 if (!penv)
3605 return -ENODEV;
3606
3607 if (test_bit(ICNSS_FW_DOWN, &penv->state))
3608 return -EINVAL;
3609
3610 icnss_pr_dbg("Sending subsystem restart level: 0x%x\n", restart_level);
3611
3612 req = kzalloc(sizeof(*req), GFP_KERNEL);
3613 if (!req)
3614 return -ENOMEM;
3615
3616 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
3617 if (!resp) {
3618 kfree(req);
3619 return -ENOMEM;
3620 }
3621
3622 req->restart_level_type_valid = 1;
3623 req->restart_level_type = restart_level;
3624
3625 penv->stats.restart_level_req++;
3626
3627 ret = qmi_txn_init(&penv->qmi, &txn,
3628 wlfw_subsys_restart_level_resp_msg_v01_ei, resp);
3629 if (ret < 0) {
3630 icnss_pr_err("Fail to init txn for subsystem restart level, resp %d\n",
3631 ret);
3632 goto out;
3633 }
3634
3635 ret = qmi_send_request(&penv->qmi, NULL, &txn,
3636 QMI_WLFW_SUBSYS_RESTART_LEVEL_REQ_V01,
3637 WLFW_SUBSYS_RESTART_LEVEL_REQ_MSG_V01_MAX_MSG_LEN,
3638 wlfw_subsys_restart_level_req_msg_v01_ei, req);
3639 if (ret < 0) {
3640 qmi_txn_cancel(&txn);
3641 icnss_pr_err("Fail to send subsystem restart level %d\n",
3642 ret);
3643 goto out;
3644 }
3645
3646 ret = qmi_txn_wait(&txn, penv->ctrl_params.qmi_timeout);
3647 if (ret < 0) {
3648 icnss_pr_err("Subsystem restart level timed out with ret %d\n",
3649 ret);
3650 goto out;
3651 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
3652 icnss_pr_err("Subsystem restart level request rejected,result:%d error:%d\n",
3653 resp->resp.result, resp->resp.error);
3654 ret = -resp->resp.result;
3655 goto out;
3656 }
3657
3658 penv->stats.restart_level_resp++;
3659
3660 kfree(resp);
3661 kfree(req);
3662 return 0;
3663
3664 out:
3665 kfree(req);
3666 kfree(resp);
3667 penv->stats.restart_level_err++;
3668 return ret;
3669 }
3670
icnss_send_vbatt_update(struct icnss_priv * priv,uint64_t voltage_uv)3671 int icnss_send_vbatt_update(struct icnss_priv *priv, uint64_t voltage_uv)
3672 {
3673 int ret;
3674 struct wlfw_vbatt_req_msg_v01 *req;
3675 struct wlfw_vbatt_resp_msg_v01 *resp;
3676 struct qmi_txn txn;
3677
3678 if (!priv)
3679 return -ENODEV;
3680
3681 if (test_bit(ICNSS_FW_DOWN, &priv->state))
3682 return -EINVAL;
3683
3684 icnss_pr_dbg("Sending Vbatt message, state: 0x%lx\n", priv->state);
3685
3686 req = kzalloc(sizeof(*req), GFP_KERNEL);
3687 if (!req)
3688 return -ENOMEM;
3689
3690 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
3691 if (!resp) {
3692 kfree(req);
3693 return -ENOMEM;
3694 }
3695
3696 req->voltage_uv = voltage_uv;
3697
3698 ret = qmi_txn_init(&priv->qmi, &txn, wlfw_vbatt_resp_msg_v01_ei, resp);
3699 if (ret < 0) {
3700 icnss_pr_err("Fail to init txn for Vbatt message resp %d\n",
3701 ret);
3702 goto out;
3703 }
3704
3705 ret = qmi_send_request(&priv->qmi, NULL, &txn,
3706 QMI_WLFW_VBATT_REQ_V01,
3707 WLFW_VBATT_REQ_MSG_V01_MAX_MSG_LEN,
3708 wlfw_vbatt_req_msg_v01_ei, req);
3709 if (ret < 0) {
3710 qmi_txn_cancel(&txn);
3711 icnss_pr_err("Fail to send Vbatt message req %d\n", ret);
3712 goto out;
3713 }
3714
3715 ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
3716 if (ret < 0) {
3717 icnss_pr_err("VBATT message resp wait failed with ret %d\n",
3718 ret);
3719 goto out;
3720 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
3721 icnss_pr_err("QMI Vbatt message request rejected, result:%d error:%d\n",
3722 resp->resp.result, resp->resp.error);
3723 ret = -resp->resp.result;
3724 goto out;
3725 }
3726
3727 kfree(resp);
3728 kfree(req);
3729 return 0;
3730
3731 out:
3732 kfree(resp);
3733 kfree(req);
3734 return ret;
3735 }
3736
wlfw_wlan_hw_init_cfg_msg(struct icnss_priv * penv,enum wlfw_wlan_rf_subtype_v01 type)3737 int wlfw_wlan_hw_init_cfg_msg(struct icnss_priv *penv,
3738 enum wlfw_wlan_rf_subtype_v01 type)
3739 {
3740 int ret;
3741 struct wlfw_wlan_hw_init_cfg_req_msg_v01 *req;
3742 struct wlfw_wlan_hw_init_cfg_resp_msg_v01 *resp;
3743 struct qmi_txn txn;
3744
3745 if (!penv)
3746 return -ENODEV;
3747
3748 icnss_pr_dbg("Sending hw init cfg, rf_subtype: 0x%x\n", type);
3749
3750 req = kzalloc(sizeof(*req), GFP_KERNEL);
3751 if (!req)
3752 return -ENOMEM;
3753
3754 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
3755 if (!resp) {
3756 kfree(req);
3757 return -ENOMEM;
3758 }
3759
3760 req->rf_subtype_valid = 1;
3761 req->rf_subtype = type;
3762
3763 ret = qmi_txn_init(&penv->qmi, &txn,
3764 wlfw_wlan_hw_init_cfg_resp_msg_v01_ei, resp);
3765 if (ret < 0) {
3766 icnss_pr_err("Fail to init txn for hw init cfg, resp %d\n",
3767 ret);
3768 goto out;
3769 }
3770
3771 ret = qmi_send_request(&penv->qmi, NULL, &txn,
3772 QMI_WLFW_WLAN_HW_INIT_CFG_REQ_V01,
3773 WLFW_WLAN_HW_INIT_CFG_REQ_MSG_V01_MAX_MSG_LEN,
3774 wlfw_wlan_hw_init_cfg_req_msg_v01_ei, req);
3775 if (ret < 0) {
3776 qmi_txn_cancel(&txn);
3777 icnss_pr_err("Fail to send hw init cfg %d\n", ret);
3778 goto out;
3779 }
3780
3781 ret = qmi_txn_wait(&txn, penv->ctrl_params.qmi_timeout);
3782 if (ret < 0) {
3783 icnss_pr_err("HW init cfg timed out with ret %d\n",
3784 ret);
3785 goto out;
3786
3787 } else if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
3788 icnss_pr_err("HW init cfg request rejected,result:%d error:%d\n",
3789 resp->resp.result, resp->resp.error);
3790 ret = -resp->resp.result;
3791 goto out;
3792 }
3793
3794 kfree(resp);
3795 kfree(req);
3796 return 0;
3797
3798 out:
3799 kfree(req);
3800 kfree(resp);
3801 return ret;
3802 }
3803
3804 /* IMS Service */
ims_subscribe_for_indication_send_async(struct icnss_priv * priv)3805 int ims_subscribe_for_indication_send_async(struct icnss_priv *priv)
3806 {
3807 int ret;
3808 struct ims_private_service_subscribe_for_indications_req_msg_v01 *req;
3809 struct qmi_txn *txn;
3810
3811 if (!priv)
3812 return -ENODEV;
3813
3814 icnss_pr_dbg("Sending ASYNC ims subscribe for indication\n");
3815
3816 req = kzalloc(sizeof(*req), GFP_KERNEL);
3817 if (!req)
3818 return -ENOMEM;
3819
3820 req->wfc_call_status_valid = 1;
3821 req->wfc_call_status = 1;
3822
3823 txn = &priv->ims_async_txn;
3824 ret = qmi_txn_init(&priv->ims_qmi, txn, NULL, NULL);
3825 if (ret < 0) {
3826 icnss_pr_err("Fail to init txn for ims subscribe for indication resp %d\n",
3827 ret);
3828 goto out;
3829 }
3830
3831 ret = qmi_send_request
3832 (&priv->ims_qmi, NULL, txn,
3833 QMI_IMS_PRIVATE_SERVICE_SUBSCRIBE_FOR_INDICATIONS_REQ_V01,
3834 IMS_PRIVATE_SERVICE_SUBSCRIBE_FOR_INDICATIONS_REQ_MSG_V01_MAX_MSG_LEN,
3835 ims_private_service_subscribe_ind_req_msg_v01_ei, req);
3836 if (ret < 0) {
3837 qmi_txn_cancel(txn);
3838 icnss_pr_err("Fail to send ims subscribe for indication req %d\n",
3839 ret);
3840 goto out;
3841 }
3842
3843 kfree(req);
3844 return 0;
3845
3846 out:
3847 kfree(req);
3848 return ret;
3849 }
3850
ims_subscribe_for_indication_resp_cb(struct qmi_handle * qmi,struct sockaddr_qrtr * sq,struct qmi_txn * txn,const void * data)3851 static void ims_subscribe_for_indication_resp_cb(struct qmi_handle *qmi,
3852 struct sockaddr_qrtr *sq,
3853 struct qmi_txn *txn,
3854 const void *data)
3855 {
3856 const
3857 struct ims_private_service_subscribe_for_indications_rsp_msg_v01 *resp =
3858 data;
3859
3860 icnss_pr_dbg("Received IMS subscribe indication response\n");
3861
3862 if (!txn) {
3863 icnss_pr_err("spurious response\n");
3864 return;
3865 }
3866
3867 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
3868 icnss_pr_err("IMS subscribe for indication request rejected, result:%d error:%d\n",
3869 resp->resp.result, resp->resp.error);
3870 txn->result = -resp->resp.result;
3871 }
3872 }
3873
icnss_process_wfc_call_ind_event(struct icnss_priv * priv,void * data)3874 int icnss_process_wfc_call_ind_event(struct icnss_priv *priv,
3875 void *data)
3876 {
3877 int ret;
3878 struct ims_private_service_wfc_call_status_ind_msg_v01 *ind_msg = data;
3879
3880 ret = icnss_wlfw_wfc_call_status_send_sync(priv, ind_msg);
3881 kfree(data);
3882 return ret;
3883 }
3884
3885 static void
icnss_ims_process_wfc_call_ind_cb(struct qmi_handle * ims_qmi,struct sockaddr_qrtr * sq,struct qmi_txn * txn,const void * data)3886 icnss_ims_process_wfc_call_ind_cb(struct qmi_handle *ims_qmi,
3887 struct sockaddr_qrtr *sq,
3888 struct qmi_txn *txn, const void *data)
3889 {
3890 struct icnss_priv *priv =
3891 container_of(ims_qmi, struct icnss_priv, ims_qmi);
3892 const
3893 struct ims_private_service_wfc_call_status_ind_msg_v01 *ind_msg = data;
3894 struct ims_private_service_wfc_call_status_ind_msg_v01 *event_data;
3895
3896 if (!txn) {
3897 icnss_pr_err("IMS->CNSS: WFC_CALL_IND: Spurious indication\n");
3898 return;
3899 }
3900
3901 if (!ind_msg) {
3902 icnss_pr_err("IMS->CNSS: WFC_CALL_IND: Invalid indication\n");
3903 return;
3904 }
3905 icnss_pr_dbg("IMS->CNSS: WFC_CALL_IND: %x, %x %x, %x %x, %x %llx, %x %x, %x %x\n",
3906 ind_msg->wfc_call_active, ind_msg->all_wfc_calls_held_valid,
3907 ind_msg->all_wfc_calls_held,
3908 ind_msg->is_wfc_emergency_valid, ind_msg->is_wfc_emergency,
3909 ind_msg->twt_ims_start_valid, ind_msg->twt_ims_start,
3910 ind_msg->twt_ims_int_valid, ind_msg->twt_ims_int,
3911 ind_msg->media_quality_valid, ind_msg->media_quality);
3912
3913 event_data = kmemdup(ind_msg, sizeof(*event_data), GFP_KERNEL);
3914 if (!event_data)
3915 return;
3916 icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_IMS_WFC_CALL_IND,
3917 0, event_data);
3918 }
3919
3920 static struct qmi_msg_handler qmi_ims_msg_handlers[] = {
3921 {
3922 .type = QMI_RESPONSE,
3923 .msg_id =
3924 QMI_IMS_PRIVATE_SERVICE_SUBSCRIBE_FOR_INDICATIONS_REQ_V01,
3925 .ei =
3926 ims_private_service_subscribe_ind_rsp_msg_v01_ei,
3927 .decoded_size = sizeof(struct
3928 ims_private_service_subscribe_for_indications_rsp_msg_v01),
3929 .fn = ims_subscribe_for_indication_resp_cb
3930 },
3931 {
3932 .type = QMI_INDICATION,
3933 .msg_id = QMI_IMS_PRIVATE_SERVICE_WFC_CALL_STATUS_IND_V01,
3934 .ei = ims_private_service_wfc_call_status_ind_msg_v01_ei,
3935 .decoded_size =
3936 sizeof(struct ims_private_service_wfc_call_status_ind_msg_v01),
3937 .fn = icnss_ims_process_wfc_call_ind_cb
3938 },
3939 {}
3940 };
3941
ims_new_server(struct qmi_handle * qmi,struct qmi_service * service)3942 static int ims_new_server(struct qmi_handle *qmi,
3943 struct qmi_service *service)
3944 {
3945 struct icnss_priv *priv =
3946 container_of(qmi, struct icnss_priv, ims_qmi);
3947 struct sockaddr_qrtr sq = { 0 };
3948 int ret = 0;
3949
3950 icnss_pr_dbg("IMS server arrive: node %u port %u\n",
3951 service->node, service->port);
3952
3953 sq.sq_family = AF_QIPCRTR;
3954 sq.sq_node = service->node;
3955 sq.sq_port = service->port;
3956 ret = kernel_connect(qmi->sock, (struct sockaddr *)&sq, sizeof(sq), 0);
3957 if (ret < 0) {
3958 icnss_pr_err("Fail to connect to remote service port\n");
3959 return ret;
3960 }
3961
3962 set_bit(ICNSS_IMS_CONNECTED, &priv->state);
3963 icnss_pr_dbg("IMS Server Connected: 0x%lx\n",
3964 priv->state);
3965
3966 ret = ims_subscribe_for_indication_send_async(priv);
3967 return ret;
3968 }
3969
ims_del_server(struct qmi_handle * qmi,struct qmi_service * service)3970 static void ims_del_server(struct qmi_handle *qmi,
3971 struct qmi_service *service)
3972 {
3973 struct icnss_priv *priv =
3974 container_of(qmi, struct icnss_priv, ims_qmi);
3975
3976 icnss_pr_dbg("IMS server exit\n");
3977
3978 clear_bit(ICNSS_IMS_CONNECTED, &priv->state);
3979 }
3980
3981 static struct qmi_ops ims_qmi_ops = {
3982 .new_server = ims_new_server,
3983 .del_server = ims_del_server,
3984 };
3985
icnss_register_ims_service(struct icnss_priv * priv)3986 int icnss_register_ims_service(struct icnss_priv *priv)
3987 {
3988 int ret;
3989
3990 ret = qmi_handle_init(&priv->ims_qmi,
3991 IMSPRIVATE_SERVICE_MAX_MSG_LEN,
3992 &ims_qmi_ops, qmi_ims_msg_handlers);
3993 if (ret < 0)
3994 return ret;
3995
3996 ret = qmi_add_lookup(&priv->ims_qmi, IMSPRIVATE_SERVICE_ID_V01,
3997 IMSPRIVATE_SERVICE_VERS_V01, 0);
3998 return ret;
3999 }
4000
icnss_unregister_ims_service(struct icnss_priv * priv)4001 void icnss_unregister_ims_service(struct icnss_priv *priv)
4002 {
4003 qmi_handle_release(&priv->ims_qmi);
4004 }
4005