blob: d857b9f98f6f2459e46b98c0030dd0da129662ce [file] [log] [blame]
Yue Maa3e15032018-02-15 15:56:12 -08001/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
Yue Ma0317e4a2018-01-10 11:48:32 -08002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/firmware.h>
14#include <linux/module.h>
15#include <linux/qmi_encdec.h>
16#include <soc/qcom/msm_qmi_interface.h>
17
Yue Mafcf60422018-05-01 16:59:56 -070018#include "bus.h"
Yue Ma0317e4a2018-01-10 11:48:32 -080019#include "debug.h"
Yue Mafcf60422018-05-01 16:59:56 -070020#include "main.h"
Yue Ma0317e4a2018-01-10 11:48:32 -080021#include "qmi.h"
22
23#define WLFW_SERVICE_INS_ID_V01 1
24#define WLFW_CLIENT_ID 0x4b4e454c
25#define MAX_BDF_FILE_NAME 11
Yue Mac2cb4672018-08-02 16:35:20 -070026#define ELF_BDF_FILE_NAME "bdwlan.elf"
27#define ELF_BDF_FILE_NAME_PREFIX "bdwlan.e"
28#define BIN_BDF_FILE_NAME "bdwlan.bin"
29#define BIN_BDF_FILE_NAME_PREFIX "bdwlan.b"
30#define DUMMY_BDF_FILE_NAME "bdwlan.dmy"
31
32enum cnss_bdf_type {
33 CNSS_BDF_BIN,
34 CNSS_BDF_ELF,
35 CNSS_BDF_DUMMY = 255,
36};
Yue Ma0317e4a2018-01-10 11:48:32 -080037
38#ifdef CONFIG_CNSS2_DEBUG
39static unsigned int qmi_timeout = 10000;
40module_param(qmi_timeout, uint, 0600);
41MODULE_PARM_DESC(qmi_timeout, "Timeout for QMI message in milliseconds");
42
43#define QMI_WLFW_TIMEOUT_MS qmi_timeout
44#else
45#define QMI_WLFW_TIMEOUT_MS 10000
46#endif
47
48static bool daemon_support;
49module_param(daemon_support, bool, 0600);
50MODULE_PARM_DESC(daemon_support, "User space has cnss-daemon support or not");
51
Yue Mac2cb4672018-08-02 16:35:20 -070052static unsigned int bdf_type = CNSS_BDF_ELF;
Yue Ma0317e4a2018-01-10 11:48:32 -080053#ifdef CONFIG_CNSS2_DEBUG
Yue Mac2cb4672018-08-02 16:35:20 -070054module_param(bdf_type, uint, 0600);
55MODULE_PARM_DESC(bdf_type, "Type of board data file to be downloaded");
Yue Ma0317e4a2018-01-10 11:48:32 -080056#endif
57
Yue Mab79d4862018-07-11 12:32:12 -070058static char *cnss_qmi_mode_to_str(enum cnss_driver_mode mode)
Yue Ma0317e4a2018-01-10 11:48:32 -080059{
60 switch (mode) {
Yue Mab79d4862018-07-11 12:32:12 -070061 case CNSS_MISSION:
Yue Ma0317e4a2018-01-10 11:48:32 -080062 return "MISSION";
Yue Mab79d4862018-07-11 12:32:12 -070063 case CNSS_FTM:
Yue Ma0317e4a2018-01-10 11:48:32 -080064 return "FTM";
Yue Mab79d4862018-07-11 12:32:12 -070065 case CNSS_EPPING:
Yue Ma0317e4a2018-01-10 11:48:32 -080066 return "EPPING";
Yue Mab79d4862018-07-11 12:32:12 -070067 case CNSS_WALTEST:
Yue Ma0317e4a2018-01-10 11:48:32 -080068 return "WALTEST";
Yue Mab79d4862018-07-11 12:32:12 -070069 case CNSS_OFF:
Yue Ma0317e4a2018-01-10 11:48:32 -080070 return "OFF";
Yue Mab79d4862018-07-11 12:32:12 -070071 case CNSS_CCPM:
Yue Ma0317e4a2018-01-10 11:48:32 -080072 return "CCPM";
Yue Mab79d4862018-07-11 12:32:12 -070073 case CNSS_QVIT:
Yue Ma0317e4a2018-01-10 11:48:32 -080074 return "QVIT";
Yue Mab79d4862018-07-11 12:32:12 -070075 case CNSS_CALIBRATION:
Yue Ma0317e4a2018-01-10 11:48:32 -080076 return "CALIBRATION";
77 default:
78 return "UNKNOWN";
79 }
80};
81
82static void cnss_wlfw_clnt_notifier_work(struct work_struct *work)
83{
84 struct cnss_plat_data *plat_priv =
85 container_of(work, struct cnss_plat_data, qmi_recv_msg_work);
86 int ret = 0;
87
88 cnss_pr_dbg("Receiving QMI WLFW event in work queue context\n");
89
90 do {
91 ret = qmi_recv_msg(plat_priv->qmi_wlfw_clnt);
92 } while (ret == 0);
93
94 if (ret != -ENOMSG)
95 cnss_pr_err("Error receiving message: %d\n", ret);
96
97 cnss_pr_dbg("Receiving QMI event completed\n");
98}
99
100static void cnss_wlfw_clnt_notifier(struct qmi_handle *handle,
101 enum qmi_event_type event,
102 void *notify_priv)
103{
104 struct cnss_plat_data *plat_priv = notify_priv;
105
106 cnss_pr_dbg("Received QMI WLFW event: %d\n", event);
107
108 if (!plat_priv) {
109 cnss_pr_err("plat_priv is NULL!\n");
110 return;
111 }
112
113 switch (event) {
114 case QMI_RECV_MSG:
115 schedule_work(&plat_priv->qmi_recv_msg_work);
116 break;
117 case QMI_SERVER_EXIT:
118 break;
119 default:
120 cnss_pr_dbg("Unhandled QMI event: %d\n", event);
121 break;
122 }
123}
124
125static int cnss_wlfw_clnt_svc_event_notifier(struct notifier_block *nb,
126 unsigned long code, void *_cmd)
127{
128 struct cnss_plat_data *plat_priv =
129 container_of(nb, struct cnss_plat_data, qmi_wlfw_clnt_nb);
130 int ret = 0;
131
132 cnss_pr_dbg("Received QMI WLFW service event: %ld\n", code);
133
134 switch (code) {
135 case QMI_SERVER_ARRIVE:
136 ret = cnss_driver_event_post(plat_priv,
137 CNSS_DRIVER_EVENT_SERVER_ARRIVE,
138 0, NULL);
139 break;
140
141 case QMI_SERVER_EXIT:
142 ret = cnss_driver_event_post(plat_priv,
143 CNSS_DRIVER_EVENT_SERVER_EXIT,
144 0, NULL);
145 break;
146 default:
147 cnss_pr_dbg("Invalid QMI service event: %ld\n", code);
148 break;
149 }
150
151 return ret;
152}
153
154static int cnss_wlfw_host_cap_send_sync(struct cnss_plat_data *plat_priv)
155{
156 struct wlfw_host_cap_req_msg_v01 req;
157 struct wlfw_host_cap_resp_msg_v01 resp;
158 struct msg_desc req_desc, resp_desc;
159 int ret = 0;
160
161 cnss_pr_dbg("Sending host capability message, state: 0x%lx\n",
162 plat_priv->driver_state);
163
164 memset(&req, 0, sizeof(req));
165 memset(&resp, 0, sizeof(resp));
166
Yue Maa3e15032018-02-15 15:56:12 -0800167 req.num_clients_valid = 1;
168 req.num_clients = daemon_support ? 2 : 1;
169 cnss_pr_dbg("Number of clients is %d\n", req.num_clients);
Yue Ma0317e4a2018-01-10 11:48:32 -0800170
Yue Mafcf60422018-05-01 16:59:56 -0700171 req.wake_msi = cnss_bus_get_wake_irq(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -0800172 if (req.wake_msi) {
173 cnss_pr_dbg("WAKE MSI base data is %d\n", req.wake_msi);
174 req.wake_msi_valid = 1;
175 }
176
Yue Maa3e15032018-02-15 15:56:12 -0800177 req.bdf_support_valid = 1;
178 req.bdf_support = 1;
179
180 req.m3_support_valid = 1;
181 req.m3_support = 1;
182
183 req.m3_cache_support_valid = 1;
184 req.m3_cache_support = 1;
185
186 req.cal_done_valid = 1;
187 req.cal_done = plat_priv->cal_done;
188 cnss_pr_dbg("Calibration done is %d\n", plat_priv->cal_done);
189
Yue Ma0317e4a2018-01-10 11:48:32 -0800190 req_desc.max_msg_len = WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN;
191 req_desc.msg_id = QMI_WLFW_HOST_CAP_REQ_V01;
192 req_desc.ei_array = wlfw_host_cap_req_msg_v01_ei;
193
194 resp_desc.max_msg_len = WLFW_HOST_CAP_RESP_MSG_V01_MAX_MSG_LEN;
195 resp_desc.msg_id = QMI_WLFW_HOST_CAP_RESP_V01;
196 resp_desc.ei_array = wlfw_host_cap_resp_msg_v01_ei;
197
198 ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
199 sizeof(req), &resp_desc, &resp, sizeof(resp),
200 QMI_WLFW_TIMEOUT_MS);
201 if (ret < 0) {
202 cnss_pr_err("Failed to send host capability request, err = %d\n",
203 ret);
204 goto out;
205 }
206
207 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
208 cnss_pr_err("Host capability request failed, result: %d, err: %d\n",
209 resp.resp.result, resp.resp.error);
210 ret = resp.resp.result;
211 goto out;
212 }
213
214 return 0;
215out:
216 CNSS_ASSERT(0);
217 return ret;
218}
219
220static int cnss_wlfw_ind_register_send_sync(struct cnss_plat_data *plat_priv)
221{
222 struct wlfw_ind_register_req_msg_v01 req;
223 struct wlfw_ind_register_resp_msg_v01 resp;
224 struct msg_desc req_desc, resp_desc;
225 int ret = 0;
226
227 cnss_pr_dbg("Sending indication register message, state: 0x%lx\n",
228 plat_priv->driver_state);
229
230 memset(&req, 0, sizeof(req));
231 memset(&resp, 0, sizeof(resp));
232
233 req.client_id_valid = 1;
234 req.client_id = WLFW_CLIENT_ID;
235 req.fw_ready_enable_valid = 1;
236 req.fw_ready_enable = 1;
237 req.request_mem_enable_valid = 1;
238 req.request_mem_enable = 1;
239 req.fw_mem_ready_enable_valid = 1;
240 req.fw_mem_ready_enable = 1;
Yue Maa3e15032018-02-15 15:56:12 -0800241 req.fw_init_done_enable_valid = 1;
242 req.fw_init_done_enable = 1;
Yue Ma0317e4a2018-01-10 11:48:32 -0800243 req.pin_connect_result_enable_valid = 1;
244 req.pin_connect_result_enable = 1;
Yue Ma0bb61162018-10-17 16:14:41 -0700245 req.cal_done_enable_valid = 1;
246 req.cal_done_enable = 1;
Yue Ma0317e4a2018-01-10 11:48:32 -0800247
248 req_desc.max_msg_len = WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN;
249 req_desc.msg_id = QMI_WLFW_IND_REGISTER_REQ_V01;
250 req_desc.ei_array = wlfw_ind_register_req_msg_v01_ei;
251
252 resp_desc.max_msg_len = WLFW_IND_REGISTER_RESP_MSG_V01_MAX_MSG_LEN;
253 resp_desc.msg_id = QMI_WLFW_IND_REGISTER_RESP_V01;
254 resp_desc.ei_array = wlfw_ind_register_resp_msg_v01_ei;
255
256 ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
257 sizeof(req), &resp_desc, &resp, sizeof(resp),
258 QMI_WLFW_TIMEOUT_MS);
259 if (ret < 0) {
260 cnss_pr_err("Failed to send indication register request, err = %d\n",
261 ret);
262 goto out;
263 }
264
265 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
266 cnss_pr_err("Indication register request failed, result: %d, err: %d\n",
267 resp.resp.result, resp.resp.error);
268 ret = resp.resp.result;
269 goto out;
270 }
271
272 return 0;
273out:
274 CNSS_ASSERT(0);
275 return ret;
276}
277
278static int cnss_wlfw_request_mem_ind_hdlr(struct cnss_plat_data *plat_priv,
279 void *msg, unsigned int msg_len)
280{
281 struct msg_desc ind_desc;
Yue Maa3e15032018-02-15 15:56:12 -0800282 struct wlfw_request_mem_ind_msg_v01 *ind_msg;
283 int ret = 0, i;
284
285 ind_msg = kzalloc(sizeof(*ind_msg), GFP_KERNEL);
286 if (!ind_msg)
287 return -ENOMEM;
Yue Ma0317e4a2018-01-10 11:48:32 -0800288
289 ind_desc.msg_id = QMI_WLFW_REQUEST_MEM_IND_V01;
290 ind_desc.max_msg_len = WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN;
291 ind_desc.ei_array = wlfw_request_mem_ind_msg_v01_ei;
292
Yue Maa3e15032018-02-15 15:56:12 -0800293 ret = qmi_kernel_decode(&ind_desc, ind_msg, msg, msg_len);
Yue Ma0317e4a2018-01-10 11:48:32 -0800294 if (ret < 0) {
295 cnss_pr_err("Failed to decode request memory indication, msg_len: %u, err = %d\n",
296 ret, msg_len);
Yue Maa3e15032018-02-15 15:56:12 -0800297 goto out;
Yue Ma0317e4a2018-01-10 11:48:32 -0800298 }
299
Yue Maa3e15032018-02-15 15:56:12 -0800300 if (ind_msg->mem_seg_len == 0 ||
301 ind_msg->mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG_V01) {
302 cnss_pr_err("Invalid memory segment length: %u\n",
303 ind_msg->mem_seg_len);
304 ret = -EINVAL;
305 goto out;
306 }
307
308 cnss_pr_dbg("FW memory segment count is %u\n", ind_msg->mem_seg_len);
309 plat_priv->fw_mem_seg_len = ind_msg->mem_seg_len;
310 for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
311 plat_priv->fw_mem[i].type = ind_msg->mem_seg[i].type;
312 plat_priv->fw_mem[i].size = ind_msg->mem_seg[i].size;
313 }
Yue Ma0317e4a2018-01-10 11:48:32 -0800314
315 cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_REQUEST_MEM,
316 0, NULL);
317
Yue Maa3e15032018-02-15 15:56:12 -0800318 kfree(ind_msg);
Yue Ma0317e4a2018-01-10 11:48:32 -0800319 return 0;
Yue Maa3e15032018-02-15 15:56:12 -0800320
321out:
322 kfree(ind_msg);
323 return ret;
Yue Ma0317e4a2018-01-10 11:48:32 -0800324}
325
326static int cnss_qmi_pin_result_ind_hdlr(struct cnss_plat_data *plat_priv,
327 void *msg, unsigned int msg_len)
328{
329 struct msg_desc ind_desc;
330 struct wlfw_pin_connect_result_ind_msg_v01 ind_msg;
331 int ret = 0;
332
333 ind_desc.msg_id = QMI_WLFW_PIN_CONNECT_RESULT_IND_V01;
334 ind_desc.max_msg_len = WLFW_PIN_CONNECT_RESULT_IND_MSG_V01_MAX_MSG_LEN;
335 ind_desc.ei_array = wlfw_pin_connect_result_ind_msg_v01_ei;
336
337 ret = qmi_kernel_decode(&ind_desc, &ind_msg, msg, msg_len);
338 if (ret < 0) {
339 cnss_pr_err("Failed to decode pin connect result indication, msg_len: %u, err = %d\n",
340 msg_len, ret);
341 return ret;
342 }
343 if (ind_msg.pwr_pin_result_valid)
344 plat_priv->pin_result.fw_pwr_pin_result =
345 ind_msg.pwr_pin_result;
346 if (ind_msg.phy_io_pin_result_valid)
347 plat_priv->pin_result.fw_phy_io_pin_result =
348 ind_msg.phy_io_pin_result;
349 if (ind_msg.rf_pin_result_valid)
350 plat_priv->pin_result.fw_rf_pin_result = ind_msg.rf_pin_result;
351
352 cnss_pr_dbg("Pin connect Result: pwr_pin: 0x%x phy_io_pin: 0x%x rf_io_pin: 0x%x\n",
353 ind_msg.pwr_pin_result, ind_msg.phy_io_pin_result,
354 ind_msg.rf_pin_result);
355 return ret;
356}
357
358int cnss_wlfw_respond_mem_send_sync(struct cnss_plat_data *plat_priv)
359{
Yue Maa3e15032018-02-15 15:56:12 -0800360 struct wlfw_respond_mem_req_msg_v01 *req;
361 struct wlfw_respond_mem_resp_msg_v01 *resp;
Yue Ma0317e4a2018-01-10 11:48:32 -0800362 struct msg_desc req_desc, resp_desc;
Yue Maa3e15032018-02-15 15:56:12 -0800363 struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
364 int ret = 0, i;
Yue Ma0317e4a2018-01-10 11:48:32 -0800365
366 cnss_pr_dbg("Sending respond memory message, state: 0x%lx\n",
367 plat_priv->driver_state);
368
Yue Maa3e15032018-02-15 15:56:12 -0800369 req = kzalloc(sizeof(*req), GFP_KERNEL);
370 if (!req)
371 return -ENOMEM;
372
373 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
374 if (!resp)
375 return -ENOMEM;
376
377 req->mem_seg_len = plat_priv->fw_mem_seg_len;
378 for (i = 0; i < req->mem_seg_len; i++) {
379 if (!fw_mem[i].pa || !fw_mem[i].size) {
380 if (fw_mem[i].type == 0) {
381 cnss_pr_err("Invalid memory for FW type, segment = %d\n",
382 i);
383 ret = -EINVAL;
384 goto out;
385 }
386 cnss_pr_err("Memory for FW is not available for type: %u\n",
387 fw_mem[i].type);
388 ret = -ENOMEM;
389 goto out;
390 }
391
392 cnss_pr_dbg("Memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx, type: %u\n",
393 fw_mem[i].va, &fw_mem[i].pa,
394 fw_mem[i].size, fw_mem[i].type);
395
396 req->mem_seg[i].addr = fw_mem[i].pa;
397 req->mem_seg[i].size = fw_mem[i].size;
398 req->mem_seg[i].type = fw_mem[i].type;
Yue Ma0317e4a2018-01-10 11:48:32 -0800399 }
400
Yue Ma0317e4a2018-01-10 11:48:32 -0800401 req_desc.max_msg_len = WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN;
402 req_desc.msg_id = QMI_WLFW_RESPOND_MEM_REQ_V01;
403 req_desc.ei_array = wlfw_respond_mem_req_msg_v01_ei;
404
405 resp_desc.max_msg_len = WLFW_RESPOND_MEM_RESP_MSG_V01_MAX_MSG_LEN;
406 resp_desc.msg_id = QMI_WLFW_RESPOND_MEM_RESP_V01;
407 resp_desc.ei_array = wlfw_respond_mem_resp_msg_v01_ei;
408
Yue Maa3e15032018-02-15 15:56:12 -0800409 ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, req,
410 sizeof(*req), &resp_desc, resp, sizeof(*resp),
Yue Ma0317e4a2018-01-10 11:48:32 -0800411 QMI_WLFW_TIMEOUT_MS);
412 if (ret < 0) {
413 cnss_pr_err("Failed to send respond memory request, err = %d\n",
414 ret);
415 goto out;
416 }
417
Yue Maa3e15032018-02-15 15:56:12 -0800418 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
Yue Ma0317e4a2018-01-10 11:48:32 -0800419 cnss_pr_err("Respond memory request failed, result: %d, err: %d\n",
Yue Maa3e15032018-02-15 15:56:12 -0800420 resp->resp.result, resp->resp.error);
421 ret = resp->resp.result;
Yue Ma0317e4a2018-01-10 11:48:32 -0800422 goto out;
423 }
424
Yue Maa3e15032018-02-15 15:56:12 -0800425 kfree(req);
426 kfree(resp);
Yue Ma0317e4a2018-01-10 11:48:32 -0800427 return 0;
Yue Maa3e15032018-02-15 15:56:12 -0800428
Yue Ma0317e4a2018-01-10 11:48:32 -0800429out:
430 CNSS_ASSERT(0);
Yue Maa3e15032018-02-15 15:56:12 -0800431 kfree(req);
432 kfree(resp);
Yue Ma0317e4a2018-01-10 11:48:32 -0800433 return ret;
434}
435
436int cnss_wlfw_tgt_cap_send_sync(struct cnss_plat_data *plat_priv)
437{
438 struct wlfw_cap_req_msg_v01 req;
439 struct wlfw_cap_resp_msg_v01 resp;
440 struct msg_desc req_desc, resp_desc;
441 int ret = 0;
442
443 cnss_pr_dbg("Sending target capability message, state: 0x%lx\n",
444 plat_priv->driver_state);
445
446 memset(&req, 0, sizeof(req));
447 memset(&resp, 0, sizeof(resp));
448
449 req_desc.max_msg_len = WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN;
450 req_desc.msg_id = QMI_WLFW_CAP_REQ_V01;
451 req_desc.ei_array = wlfw_cap_req_msg_v01_ei;
452
453 resp_desc.max_msg_len = WLFW_CAP_RESP_MSG_V01_MAX_MSG_LEN;
454 resp_desc.msg_id = QMI_WLFW_CAP_RESP_V01;
455 resp_desc.ei_array = wlfw_cap_resp_msg_v01_ei;
456
457 ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
458 sizeof(req), &resp_desc, &resp, sizeof(resp),
459 QMI_WLFW_TIMEOUT_MS);
460 if (ret < 0) {
461 cnss_pr_err("Failed to send target capability request, err = %d\n",
462 ret);
463 goto out;
464 }
465
466 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
467 cnss_pr_err("Target capability request failed, result: %d, err: %d\n",
468 resp.resp.result, resp.resp.error);
469 ret = resp.resp.result;
470 goto out;
471 }
472
Yue Mab79d4862018-07-11 12:32:12 -0700473 if (resp.chip_info_valid) {
474 plat_priv->chip_info.chip_id = resp.chip_info.chip_id;
475 plat_priv->chip_info.chip_family = resp.chip_info.chip_family;
476 }
Yue Ma0317e4a2018-01-10 11:48:32 -0800477 if (resp.board_info_valid)
Yue Mab79d4862018-07-11 12:32:12 -0700478 plat_priv->board_info.board_id = resp.board_info.board_id;
Yue Ma0317e4a2018-01-10 11:48:32 -0800479 else
480 plat_priv->board_info.board_id = 0xFF;
481 if (resp.soc_info_valid)
Yue Mab79d4862018-07-11 12:32:12 -0700482 plat_priv->soc_info.soc_id = resp.soc_info.soc_id;
483 if (resp.fw_version_info_valid) {
484 plat_priv->fw_version_info.fw_version =
485 resp.fw_version_info.fw_version;
486 strlcpy(plat_priv->fw_version_info.fw_build_timestamp,
487 resp.fw_version_info.fw_build_timestamp,
488 QMI_WLFW_MAX_TIMESTAMP_LEN + 1);
489 }
Yue Ma0317e4a2018-01-10 11:48:32 -0800490
491 cnss_pr_dbg("Target capability: chip_id: 0x%x, chip_family: 0x%x, board_id: 0x%x, soc_id: 0x%x, fw_version: 0x%x, fw_build_timestamp: %s",
492 plat_priv->chip_info.chip_id,
493 plat_priv->chip_info.chip_family,
494 plat_priv->board_info.board_id, plat_priv->soc_info.soc_id,
495 plat_priv->fw_version_info.fw_version,
496 plat_priv->fw_version_info.fw_build_timestamp);
497
498 return 0;
499out:
500 CNSS_ASSERT(0);
501 return ret;
502}
503
504int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv)
505{
506 struct wlfw_bdf_download_req_msg_v01 *req;
507 struct wlfw_bdf_download_resp_msg_v01 resp;
508 struct msg_desc req_desc, resp_desc;
509 char filename[MAX_BDF_FILE_NAME];
510 const struct firmware *fw_entry;
511 const u8 *temp;
512 unsigned int remaining;
513 int ret = 0;
514
515 cnss_pr_dbg("Sending BDF download message, state: 0x%lx\n",
516 plat_priv->driver_state);
517
518 req = kzalloc(sizeof(*req), GFP_KERNEL);
519 if (!req) {
520 ret = -ENOMEM;
521 goto out;
522 }
523
Yue Mac2cb4672018-08-02 16:35:20 -0700524 switch (bdf_type) {
525 case CNSS_BDF_ELF:
526 if (plat_priv->board_info.board_id == 0xFF)
527 snprintf(filename, sizeof(filename), ELF_BDF_FILE_NAME);
528 else
529 snprintf(filename, sizeof(filename),
530 ELF_BDF_FILE_NAME_PREFIX "%02x",
531 plat_priv->board_info.board_id);
532 break;
533 case CNSS_BDF_BIN:
534 if (plat_priv->board_info.board_id == 0xFF)
535 snprintf(filename, sizeof(filename), BIN_BDF_FILE_NAME);
536 else
537 snprintf(filename, sizeof(filename),
538 BIN_BDF_FILE_NAME_PREFIX "%02x",
539 plat_priv->board_info.board_id);
540 break;
541 case CNSS_BDF_DUMMY:
542 cnss_pr_dbg("CNSS_BDF_DUMMY is set, sending dummy BDF\n");
543 snprintf(filename, sizeof(filename), DUMMY_BDF_FILE_NAME);
544 temp = DUMMY_BDF_FILE_NAME;
Yue Mafdb6aa82018-06-07 17:55:04 -0700545 remaining = MAX_BDF_FILE_NAME;
546 goto bypass_bdf;
Yue Mac2cb4672018-08-02 16:35:20 -0700547 default:
548 cnss_pr_err("Invalid BDF type: %d\n", bdf_type);
549 ret = -EINVAL;
550 goto err_req_fw;
Yue Mafdb6aa82018-06-07 17:55:04 -0700551 }
552
Yue Ma0317e4a2018-01-10 11:48:32 -0800553 ret = request_firmware(&fw_entry, filename, &plat_priv->plat_dev->dev);
554 if (ret) {
555 cnss_pr_err("Failed to load BDF: %s\n", filename);
Yue Mafdb6aa82018-06-07 17:55:04 -0700556 goto err_req_fw;
Yue Ma0317e4a2018-01-10 11:48:32 -0800557 }
558
559 temp = fw_entry->data;
560 remaining = fw_entry->size;
561
562bypass_bdf:
563 cnss_pr_dbg("Downloading BDF: %s, size: %u\n", filename, remaining);
564
565 memset(&resp, 0, sizeof(resp));
566
567 req_desc.max_msg_len = WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN;
568 req_desc.msg_id = QMI_WLFW_BDF_DOWNLOAD_REQ_V01;
569 req_desc.ei_array = wlfw_bdf_download_req_msg_v01_ei;
570
571 resp_desc.max_msg_len = WLFW_BDF_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN;
572 resp_desc.msg_id = QMI_WLFW_BDF_DOWNLOAD_RESP_V01;
573 resp_desc.ei_array = wlfw_bdf_download_resp_msg_v01_ei;
574
575 while (remaining) {
576 req->valid = 1;
577 req->file_id_valid = 1;
578 req->file_id = plat_priv->board_info.board_id;
579 req->total_size_valid = 1;
580 req->total_size = remaining;
581 req->seg_id_valid = 1;
582 req->data_valid = 1;
583 req->end_valid = 1;
584 req->bdf_type_valid = 1;
Yue Mac2cb4672018-08-02 16:35:20 -0700585 req->bdf_type = bdf_type;
Yue Ma0317e4a2018-01-10 11:48:32 -0800586
587 if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) {
588 req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01;
589 } else {
590 req->data_len = remaining;
591 req->end = 1;
592 }
593
594 memcpy(req->data, temp, req->data_len);
595
596 ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc,
597 req, sizeof(*req), &resp_desc, &resp,
598 sizeof(resp), QMI_WLFW_TIMEOUT_MS);
599 if (ret < 0) {
600 cnss_pr_err("Failed to send BDF download request, err = %d\n",
601 ret);
602 goto err_send;
603 }
604
605 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
606 cnss_pr_err("BDF download request failed, result: %d, err: %d\n",
607 resp.resp.result, resp.resp.error);
608 ret = resp.resp.result;
609 goto err_send;
610 }
611
612 remaining -= req->data_len;
613 temp += req->data_len;
614 req->seg_id++;
615 }
616
617err_send:
Yue Mac2cb4672018-08-02 16:35:20 -0700618 if (bdf_type != CNSS_BDF_DUMMY)
Yue Ma0317e4a2018-01-10 11:48:32 -0800619 release_firmware(fw_entry);
620err_req_fw:
621 kfree(req);
622out:
623 if (ret)
624 CNSS_ASSERT(0);
625 return ret;
626}
627
628int cnss_wlfw_m3_dnld_send_sync(struct cnss_plat_data *plat_priv)
629{
630 struct wlfw_m3_info_req_msg_v01 req;
631 struct wlfw_m3_info_resp_msg_v01 resp;
632 struct msg_desc req_desc, resp_desc;
633 struct cnss_fw_mem *m3_mem = &plat_priv->m3_mem;
634 int ret = 0;
635
636 cnss_pr_dbg("Sending M3 information message, state: 0x%lx\n",
637 plat_priv->driver_state);
638
639 if (!m3_mem->pa || !m3_mem->size) {
640 cnss_pr_err("Memory for M3 is not available!\n");
641 ret = -ENOMEM;
642 goto out;
643 }
644
645 cnss_pr_dbg("M3 memory, va: 0x%pK, pa: %pa, size: 0x%zx\n",
646 m3_mem->va, &m3_mem->pa, m3_mem->size);
647
648 memset(&req, 0, sizeof(req));
649 memset(&resp, 0, sizeof(resp));
650
651 req.addr = plat_priv->m3_mem.pa;
652 req.size = plat_priv->m3_mem.size;
653
654 req_desc.max_msg_len = WLFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN;
655 req_desc.msg_id = QMI_WLFW_M3_INFO_REQ_V01;
656 req_desc.ei_array = wlfw_m3_info_req_msg_v01_ei;
657
658 resp_desc.max_msg_len = WLFW_M3_INFO_RESP_MSG_V01_MAX_MSG_LEN;
659 resp_desc.msg_id = QMI_WLFW_M3_INFO_RESP_V01;
660 resp_desc.ei_array = wlfw_m3_info_resp_msg_v01_ei;
661
662 ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
663 sizeof(req), &resp_desc, &resp, sizeof(resp),
664 QMI_WLFW_TIMEOUT_MS);
665 if (ret < 0) {
666 cnss_pr_err("Failed to send M3 information request, err = %d\n",
667 ret);
668 goto out;
669 }
670
671 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
672 cnss_pr_err("M3 information request failed, result: %d, err: %d\n",
673 resp.resp.result, resp.resp.error);
674 ret = resp.resp.result;
675 goto out;
676 }
677
678 return 0;
679
680out:
681 CNSS_ASSERT(0);
682 return ret;
683}
684
685int cnss_wlfw_wlan_mode_send_sync(struct cnss_plat_data *plat_priv,
Yue Mab79d4862018-07-11 12:32:12 -0700686 enum cnss_driver_mode mode)
Yue Ma0317e4a2018-01-10 11:48:32 -0800687{
688 struct wlfw_wlan_mode_req_msg_v01 req;
689 struct wlfw_wlan_mode_resp_msg_v01 resp;
690 struct msg_desc req_desc, resp_desc;
691 int ret = 0;
692
693 if (!plat_priv)
694 return -ENODEV;
695
696 cnss_pr_dbg("Sending mode message, mode: %s(%d), state: 0x%lx\n",
697 cnss_qmi_mode_to_str(mode), mode, plat_priv->driver_state);
698
Yue Mab79d4862018-07-11 12:32:12 -0700699 if (mode == CNSS_OFF &&
Yue Ma0317e4a2018-01-10 11:48:32 -0800700 test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) {
701 cnss_pr_dbg("Recovery is in progress, ignore mode off request.\n");
702 return 0;
703 }
704
705 memset(&req, 0, sizeof(req));
706 memset(&resp, 0, sizeof(resp));
707
708 req.mode = mode;
709 req.hw_debug_valid = 1;
710 req.hw_debug = 0;
711
712 req_desc.max_msg_len = WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN;
713 req_desc.msg_id = QMI_WLFW_WLAN_MODE_REQ_V01;
714 req_desc.ei_array = wlfw_wlan_mode_req_msg_v01_ei;
715
716 resp_desc.max_msg_len = WLFW_WLAN_MODE_RESP_MSG_V01_MAX_MSG_LEN;
717 resp_desc.msg_id = QMI_WLFW_WLAN_MODE_RESP_V01;
718 resp_desc.ei_array = wlfw_wlan_mode_resp_msg_v01_ei;
719
720 ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
721 sizeof(req), &resp_desc, &resp, sizeof(resp),
722 QMI_WLFW_TIMEOUT_MS);
723 if (ret < 0) {
Yue Mab79d4862018-07-11 12:32:12 -0700724 if (mode == CNSS_OFF && ret == -ENETRESET) {
Yue Ma0317e4a2018-01-10 11:48:32 -0800725 cnss_pr_dbg("WLFW service is disconnected while sending mode off request.\n");
726 return 0;
727 }
728 cnss_pr_err("Failed to send mode request, mode: %s(%d), err: %d\n",
729 cnss_qmi_mode_to_str(mode), mode, ret);
730 goto out;
731 }
732
733 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
734 cnss_pr_err("Mode request failed, mode: %s(%d), result: %d, err: %d\n",
735 cnss_qmi_mode_to_str(mode), mode, resp.resp.result,
736 resp.resp.error);
737 ret = resp.resp.result;
738 goto out;
739 }
740
741 return 0;
742out:
Yue Mab79d4862018-07-11 12:32:12 -0700743 if (mode != CNSS_OFF)
Yue Ma0317e4a2018-01-10 11:48:32 -0800744 CNSS_ASSERT(0);
745 return ret;
746}
747
748int cnss_wlfw_wlan_cfg_send_sync(struct cnss_plat_data *plat_priv,
Yue Mab79d4862018-07-11 12:32:12 -0700749 struct cnss_wlan_enable_cfg *config,
750 const char *host_version)
Yue Ma0317e4a2018-01-10 11:48:32 -0800751{
752 struct wlfw_wlan_cfg_req_msg_v01 req;
753 struct wlfw_wlan_cfg_resp_msg_v01 resp;
754 struct msg_desc req_desc, resp_desc;
Yue Mab79d4862018-07-11 12:32:12 -0700755 u32 i;
Yue Ma0317e4a2018-01-10 11:48:32 -0800756 int ret = 0;
757
758 cnss_pr_dbg("Sending WLAN config message, state: 0x%lx\n",
759 plat_priv->driver_state);
760
761 if (!plat_priv)
762 return -ENODEV;
763
764 memset(&req, 0, sizeof(req));
765 memset(&resp, 0, sizeof(resp));
766
Yue Mab79d4862018-07-11 12:32:12 -0700767 req.host_version_valid = 1;
768 strlcpy(req.host_version, host_version,
769 QMI_WLFW_MAX_STR_LEN_V01 + 1);
770
771 req.tgt_cfg_valid = 1;
772 if (config->num_ce_tgt_cfg > QMI_WLFW_MAX_NUM_CE_V01)
773 req.tgt_cfg_len = QMI_WLFW_MAX_NUM_CE_V01;
774 else
775 req.tgt_cfg_len = config->num_ce_tgt_cfg;
776 for (i = 0; i < req.tgt_cfg_len; i++) {
777 req.tgt_cfg[i].pipe_num = config->ce_tgt_cfg[i].pipe_num;
778 req.tgt_cfg[i].pipe_dir = config->ce_tgt_cfg[i].pipe_dir;
779 req.tgt_cfg[i].nentries = config->ce_tgt_cfg[i].nentries;
780 req.tgt_cfg[i].nbytes_max = config->ce_tgt_cfg[i].nbytes_max;
781 req.tgt_cfg[i].flags = config->ce_tgt_cfg[i].flags;
782 }
783
784 req.svc_cfg_valid = 1;
785 if (config->num_ce_svc_pipe_cfg > QMI_WLFW_MAX_NUM_SVC_V01)
786 req.svc_cfg_len = QMI_WLFW_MAX_NUM_SVC_V01;
787 else
788 req.svc_cfg_len = config->num_ce_svc_pipe_cfg;
789 for (i = 0; i < req.svc_cfg_len; i++) {
790 req.svc_cfg[i].service_id = config->ce_svc_cfg[i].service_id;
791 req.svc_cfg[i].pipe_dir = config->ce_svc_cfg[i].pipe_dir;
792 req.svc_cfg[i].pipe_num = config->ce_svc_cfg[i].pipe_num;
793 }
794
795 req.shadow_reg_v2_valid = 1;
796 if (config->num_shadow_reg_v2_cfg >
797 QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01)
798 req.shadow_reg_v2_len = QMI_WLFW_MAX_NUM_SHADOW_REG_V2_V01;
799 else
800 req.shadow_reg_v2_len = config->num_shadow_reg_v2_cfg;
801
802 memcpy(req.shadow_reg_v2, config->shadow_reg_v2_cfg,
803 sizeof(struct wlfw_shadow_reg_v2_cfg_s_v01)
804 * req.shadow_reg_v2_len);
Yue Ma0317e4a2018-01-10 11:48:32 -0800805
806 req_desc.max_msg_len = WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN;
807 req_desc.msg_id = QMI_WLFW_WLAN_CFG_REQ_V01;
808 req_desc.ei_array = wlfw_wlan_cfg_req_msg_v01_ei;
809
810 resp_desc.max_msg_len = WLFW_WLAN_CFG_RESP_MSG_V01_MAX_MSG_LEN;
811 resp_desc.msg_id = QMI_WLFW_WLAN_CFG_RESP_V01;
812 resp_desc.ei_array = wlfw_wlan_cfg_resp_msg_v01_ei;
813
814 ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
815 sizeof(req), &resp_desc, &resp, sizeof(resp),
816 QMI_WLFW_TIMEOUT_MS);
817 if (ret < 0) {
818 cnss_pr_err("Failed to send WLAN config request, err = %d\n",
819 ret);
820 goto out;
821 }
822
823 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
824 cnss_pr_err("WLAN config request failed, result: %d, err: %d\n",
825 resp.resp.result, resp.resp.error);
826 ret = resp.resp.result;
827 goto out;
828 }
829
830 return 0;
831out:
832 CNSS_ASSERT(0);
833 return ret;
834}
835
836int cnss_wlfw_athdiag_read_send_sync(struct cnss_plat_data *plat_priv,
837 u32 offset, u32 mem_type,
838 u32 data_len, u8 *data)
839{
840 struct wlfw_athdiag_read_req_msg_v01 req;
841 struct wlfw_athdiag_read_resp_msg_v01 *resp;
842 struct msg_desc req_desc, resp_desc;
843 int ret = 0;
844
845 if (!plat_priv)
846 return -ENODEV;
847
848 if (!plat_priv->qmi_wlfw_clnt)
849 return -EINVAL;
850
Yue Mab79d4862018-07-11 12:32:12 -0700851 if (!data || data_len == 0 || data_len > QMI_WLFW_MAX_DATA_SIZE_V01) {
852 cnss_pr_err("Invalid parameters for athdiag read: data %p, data_len %u\n",
853 data, data_len);
854 return -EINVAL;
855 }
856
Yue Ma0317e4a2018-01-10 11:48:32 -0800857 cnss_pr_dbg("athdiag read: state 0x%lx, offset %x, mem_type %x, data_len %u\n",
858 plat_priv->driver_state, offset, mem_type, data_len);
859
860 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
861 if (!resp)
862 return -ENOMEM;
863
864 memset(&req, 0, sizeof(req));
865
866 req.offset = offset;
867 req.mem_type = mem_type;
868 req.data_len = data_len;
869
870 req_desc.max_msg_len = WLFW_ATHDIAG_READ_REQ_MSG_V01_MAX_MSG_LEN;
871 req_desc.msg_id = QMI_WLFW_ATHDIAG_READ_REQ_V01;
872 req_desc.ei_array = wlfw_athdiag_read_req_msg_v01_ei;
873
874 resp_desc.max_msg_len = WLFW_ATHDIAG_READ_RESP_MSG_V01_MAX_MSG_LEN;
875 resp_desc.msg_id = QMI_WLFW_ATHDIAG_READ_RESP_V01;
876 resp_desc.ei_array = wlfw_athdiag_read_resp_msg_v01_ei;
877
878 ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
879 sizeof(req), &resp_desc, resp, sizeof(*resp),
880 QMI_WLFW_TIMEOUT_MS);
881 if (ret < 0) {
882 cnss_pr_err("Failed to send athdiag read request, err = %d\n",
883 ret);
884 goto out;
885 }
886
887 if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
888 cnss_pr_err("athdiag read request failed, result: %d, err: %d\n",
889 resp->resp.result, resp->resp.error);
890 ret = resp->resp.result;
891 goto out;
892 }
893
894 if (!resp->data_valid || resp->data_len != data_len) {
895 cnss_pr_err("athdiag read data is invalid, data_valid = %u, data_len = %u\n",
896 resp->data_valid, resp->data_len);
897 ret = -EINVAL;
898 goto out;
899 }
900
901 memcpy(data, resp->data, resp->data_len);
902
903out:
904 kfree(resp);
905 return ret;
906}
907
908int cnss_wlfw_athdiag_write_send_sync(struct cnss_plat_data *plat_priv,
909 u32 offset, u32 mem_type,
910 u32 data_len, u8 *data)
911{
912 struct wlfw_athdiag_write_req_msg_v01 *req;
913 struct wlfw_athdiag_write_resp_msg_v01 resp;
914 struct msg_desc req_desc, resp_desc;
915 int ret = 0;
916
917 if (!plat_priv)
918 return -ENODEV;
919
920 if (!plat_priv->qmi_wlfw_clnt)
921 return -EINVAL;
922
Yue Mab79d4862018-07-11 12:32:12 -0700923 if (!data || data_len == 0 || data_len > QMI_WLFW_MAX_DATA_SIZE_V01) {
924 cnss_pr_err("Invalid parameters for athdiag write: data %p, data_len %u\n",
925 data, data_len);
926 return -EINVAL;
927 }
928
Yue Ma0317e4a2018-01-10 11:48:32 -0800929 cnss_pr_dbg("athdiag write: state 0x%lx, offset %x, mem_type %x, data_len %u, data %p\n",
930 plat_priv->driver_state, offset, mem_type, data_len, data);
931
932 req = kzalloc(sizeof(*req), GFP_KERNEL);
933 if (!req)
934 return -ENOMEM;
935
936 memset(&resp, 0, sizeof(resp));
937
938 req->offset = offset;
939 req->mem_type = mem_type;
940 req->data_len = data_len;
941 memcpy(req->data, data, data_len);
942
943 req_desc.max_msg_len = WLFW_ATHDIAG_WRITE_REQ_MSG_V01_MAX_MSG_LEN;
944 req_desc.msg_id = QMI_WLFW_ATHDIAG_WRITE_REQ_V01;
945 req_desc.ei_array = wlfw_athdiag_write_req_msg_v01_ei;
946
947 resp_desc.max_msg_len = WLFW_ATHDIAG_WRITE_RESP_MSG_V01_MAX_MSG_LEN;
948 resp_desc.msg_id = QMI_WLFW_ATHDIAG_WRITE_RESP_V01;
949 resp_desc.ei_array = wlfw_athdiag_write_resp_msg_v01_ei;
950
951 ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, req,
952 sizeof(*req), &resp_desc, &resp, sizeof(resp),
953 QMI_WLFW_TIMEOUT_MS);
954 if (ret < 0) {
955 cnss_pr_err("Failed to send athdiag write request, err = %d\n",
956 ret);
957 goto out;
958 }
959
960 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
961 cnss_pr_err("athdiag write request failed, result: %d, err: %d\n",
962 resp.resp.result, resp.resp.error);
963 ret = resp.resp.result;
964 goto out;
965 }
966
967out:
968 kfree(req);
969 return ret;
970}
971
972int cnss_wlfw_ini_send_sync(struct cnss_plat_data *plat_priv,
973 u8 fw_log_mode)
974{
975 int ret;
976 struct wlfw_ini_req_msg_v01 req;
977 struct wlfw_ini_resp_msg_v01 resp;
978 struct msg_desc req_desc, resp_desc;
979
980 if (!plat_priv)
981 return -ENODEV;
982
983 cnss_pr_dbg("Sending ini sync request, state: 0x%lx, fw_log_mode: %d\n",
984 plat_priv->driver_state, fw_log_mode);
985
986 memset(&req, 0, sizeof(req));
987 memset(&resp, 0, sizeof(resp));
988
989 req.enablefwlog_valid = 1;
990 req.enablefwlog = fw_log_mode;
991
992 req_desc.max_msg_len = WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN;
993 req_desc.msg_id = QMI_WLFW_INI_REQ_V01;
994 req_desc.ei_array = wlfw_ini_req_msg_v01_ei;
995
996 resp_desc.max_msg_len = WLFW_INI_RESP_MSG_V01_MAX_MSG_LEN;
997 resp_desc.msg_id = QMI_WLFW_INI_RESP_V01;
998 resp_desc.ei_array = wlfw_ini_resp_msg_v01_ei;
999
1000 ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt,
1001 &req_desc, &req, sizeof(req),
1002 &resp_desc, &resp, sizeof(resp),
1003 QMI_WLFW_TIMEOUT_MS);
1004 if (ret < 0) {
1005 cnss_pr_err("Send INI req failed fw_log_mode: %d, ret: %d\n",
1006 fw_log_mode, ret);
1007 goto out;
1008 }
1009
1010 if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
1011 cnss_pr_err("QMI INI request rejected, fw_log_mode:%d result:%d error:%d\n",
1012 fw_log_mode, resp.resp.result, resp.resp.error);
1013 ret = resp.resp.result;
1014 goto out;
1015 }
1016
1017 return 0;
1018
1019out:
1020 return ret;
1021}
1022
1023static void cnss_wlfw_clnt_ind(struct qmi_handle *handle,
1024 unsigned int msg_id, void *msg,
1025 unsigned int msg_len, void *ind_cb_priv)
1026{
1027 struct cnss_plat_data *plat_priv = ind_cb_priv;
1028
1029 cnss_pr_dbg("Received QMI WLFW indication, msg_id: 0x%x, msg_len: %d\n",
1030 msg_id, msg_len);
1031
1032 if (!plat_priv) {
1033 cnss_pr_err("plat_priv is NULL!\n");
1034 return;
1035 }
1036
1037 switch (msg_id) {
1038 case QMI_WLFW_REQUEST_MEM_IND_V01:
1039 cnss_wlfw_request_mem_ind_hdlr(plat_priv, msg, msg_len);
1040 break;
1041 case QMI_WLFW_FW_MEM_READY_IND_V01:
1042 cnss_driver_event_post(plat_priv,
1043 CNSS_DRIVER_EVENT_FW_MEM_READY,
1044 0, NULL);
1045 break;
Yue Maa3e15032018-02-15 15:56:12 -08001046 case QMI_WLFW_FW_READY_IND_V01:
Yue Ma0317e4a2018-01-10 11:48:32 -08001047 cnss_driver_event_post(plat_priv,
1048 CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE,
1049 0, NULL);
1050 break;
Yue Maa3e15032018-02-15 15:56:12 -08001051 case QMI_WLFW_FW_INIT_DONE_IND_V01:
Yue Ma0317e4a2018-01-10 11:48:32 -08001052 cnss_driver_event_post(plat_priv,
1053 CNSS_DRIVER_EVENT_FW_READY,
1054 0, NULL);
1055 break;
1056 case QMI_WLFW_PIN_CONNECT_RESULT_IND_V01:
1057 cnss_qmi_pin_result_ind_hdlr(plat_priv, msg, msg_len);
1058 break;
Yue Ma0bb61162018-10-17 16:14:41 -07001059 case QMI_WLFW_CAL_DONE_IND_V01:
1060 cnss_driver_event_post(plat_priv,
1061 CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE,
1062 0, NULL);
1063 break;
Yue Ma0317e4a2018-01-10 11:48:32 -08001064 default:
1065 cnss_pr_err("Invalid QMI WLFW indication, msg_id: 0x%x\n",
1066 msg_id);
1067 break;
1068 }
1069}
1070
1071unsigned int cnss_get_qmi_timeout(void)
1072{
1073 cnss_pr_dbg("QMI timeout is %u ms\n", QMI_WLFW_TIMEOUT_MS);
1074
1075 return QMI_WLFW_TIMEOUT_MS;
1076}
Yue Ma0317e4a2018-01-10 11:48:32 -08001077
1078int cnss_wlfw_server_arrive(struct cnss_plat_data *plat_priv)
1079{
1080 int ret = 0;
1081
1082 if (!plat_priv)
1083 return -ENODEV;
1084
1085 plat_priv->qmi_wlfw_clnt =
1086 qmi_handle_create(cnss_wlfw_clnt_notifier, plat_priv);
1087 if (!plat_priv->qmi_wlfw_clnt) {
1088 cnss_pr_err("Failed to create QMI client handle!\n");
1089 ret = -ENOMEM;
1090 goto err_create_handle;
1091 }
1092
1093 ret = qmi_connect_to_service(plat_priv->qmi_wlfw_clnt,
1094 WLFW_SERVICE_ID_V01,
1095 WLFW_SERVICE_VERS_V01,
1096 WLFW_SERVICE_INS_ID_V01);
1097 if (ret < 0) {
1098 cnss_pr_err("Failed to connect to QMI WLFW service, err = %d\n",
1099 ret);
1100 goto out;
1101 }
1102
1103 ret = qmi_register_ind_cb(plat_priv->qmi_wlfw_clnt,
1104 cnss_wlfw_clnt_ind, plat_priv);
1105 if (ret < 0) {
1106 cnss_pr_err("Failed to register QMI WLFW service indication callback, err = %d\n",
1107 ret);
1108 goto out;
1109 }
1110
1111 set_bit(CNSS_QMI_WLFW_CONNECTED, &plat_priv->driver_state);
1112
1113 cnss_pr_info("QMI WLFW service connected, state: 0x%lx\n",
1114 plat_priv->driver_state);
1115
Yue Maa3e15032018-02-15 15:56:12 -08001116 ret = cnss_wlfw_ind_register_send_sync(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001117 if (ret < 0)
1118 goto out;
1119
Yue Maa3e15032018-02-15 15:56:12 -08001120 ret = cnss_wlfw_host_cap_send_sync(plat_priv);
Yue Ma0317e4a2018-01-10 11:48:32 -08001121 if (ret < 0)
1122 goto out;
1123
1124 return 0;
1125out:
1126 qmi_handle_destroy(plat_priv->qmi_wlfw_clnt);
1127 plat_priv->qmi_wlfw_clnt = NULL;
1128err_create_handle:
1129 CNSS_ASSERT(0);
1130 return ret;
1131}
1132
1133int cnss_wlfw_server_exit(struct cnss_plat_data *plat_priv)
1134{
1135 if (!plat_priv)
1136 return -ENODEV;
1137
1138 qmi_handle_destroy(plat_priv->qmi_wlfw_clnt);
1139 plat_priv->qmi_wlfw_clnt = NULL;
1140
1141 clear_bit(CNSS_QMI_WLFW_CONNECTED, &plat_priv->driver_state);
1142
1143 cnss_pr_info("QMI WLFW service disconnected, state: 0x%lx\n",
1144 plat_priv->driver_state);
1145
1146 return 0;
1147}
1148
1149int cnss_qmi_init(struct cnss_plat_data *plat_priv)
1150{
1151 int ret = 0;
1152
1153 INIT_WORK(&plat_priv->qmi_recv_msg_work,
1154 cnss_wlfw_clnt_notifier_work);
1155
1156 plat_priv->qmi_wlfw_clnt_nb.notifier_call =
1157 cnss_wlfw_clnt_svc_event_notifier;
1158
1159 ret = qmi_svc_event_notifier_register(WLFW_SERVICE_ID_V01,
1160 WLFW_SERVICE_VERS_V01,
1161 WLFW_SERVICE_INS_ID_V01,
1162 &plat_priv->qmi_wlfw_clnt_nb);
1163 if (ret < 0)
1164 cnss_pr_err("Failed to register QMI event notifier, err = %d\n",
1165 ret);
1166
1167 return ret;
1168}
1169
1170void cnss_qmi_deinit(struct cnss_plat_data *plat_priv)
1171{
1172 qmi_svc_event_notifier_unregister(WLFW_SERVICE_ID_V01,
1173 WLFW_SERVICE_VERS_V01,
1174 WLFW_SERVICE_INS_ID_V01,
1175 &plat_priv->qmi_wlfw_clnt_nb);
1176}