blob: 19c3de4ad4abccb3952275fe15d89e8f7454fbc8 [file] [log] [blame]
Skylar Chang1be75e1b2017-01-23 13:53:56 -08001/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
Amir Levy9659e592016-10-27 18:08:27 +03002 *
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
14#include <linux/module.h>
15#include <linux/slab.h>
16#include <linux/errno.h>
17#include <linux/delay.h>
18#include <linux/debugfs.h>
19#include <linux/qmi_encdec.h>
20#include <linux/delay.h>
21#include <linux/uaccess.h>
22#include <soc/qcom/subsystem_restart.h>
23#include <linux/ipa.h>
24#include <linux/vmalloc.h>
25
26#include "ipa_qmi_service.h"
27
28#define IPA_Q6_SVC_VERS 1
29#define IPA_A5_SVC_VERS 1
30#define Q6_QMI_COMPLETION_TIMEOUT (60*HZ)
31
32#define IPA_A5_SERVICE_SVC_ID 0x31
33#define IPA_A5_SERVICE_INS_ID 1
34#define IPA_Q6_SERVICE_SVC_ID 0x31
35#define IPA_Q6_SERVICE_INS_ID 2
36
37#define QMI_SEND_STATS_REQ_TIMEOUT_MS 5000
38#define QMI_SEND_REQ_TIMEOUT_MS 60000
39
Skylar Chang1be75e1b2017-01-23 13:53:56 -080040#define QMI_IPA_FORCE_CLEAR_DATAPATH_TIMEOUT_MS 1000
41
Amir Levy9659e592016-10-27 18:08:27 +030042static struct qmi_handle *ipa3_svc_handle;
43static void ipa3_a5_svc_recv_msg(struct work_struct *work);
44static DECLARE_DELAYED_WORK(work_recv_msg, ipa3_a5_svc_recv_msg);
45static struct workqueue_struct *ipa_svc_workqueue;
46static struct workqueue_struct *ipa_clnt_req_workqueue;
47static struct workqueue_struct *ipa_clnt_resp_workqueue;
48static void *curr_conn;
49static bool ipa3_qmi_modem_init_fin, ipa3_qmi_indication_fin;
50static struct work_struct ipa3_qmi_service_init_work;
51static uint32_t ipa_wan_platform;
52struct ipa3_qmi_context *ipa3_qmi_ctx;
53static bool workqueues_stopped;
54static bool ipa3_modem_init_cmplt;
55static bool first_time_handshake;
56/* QMI A5 service */
57
58static struct msg_desc ipa3_indication_reg_req_desc = {
59 .max_msg_len = QMI_IPA_INDICATION_REGISTER_REQ_MAX_MSG_LEN_V01,
60 .msg_id = QMI_IPA_INDICATION_REGISTER_REQ_V01,
61 .ei_array = ipa3_indication_reg_req_msg_data_v01_ei,
62};
63static struct msg_desc ipa3_indication_reg_resp_desc = {
64 .max_msg_len = QMI_IPA_INDICATION_REGISTER_RESP_MAX_MSG_LEN_V01,
65 .msg_id = QMI_IPA_INDICATION_REGISTER_RESP_V01,
66 .ei_array = ipa3_indication_reg_resp_msg_data_v01_ei,
67};
68static struct msg_desc ipa3_master_driver_complete_indication_desc = {
69 .max_msg_len = QMI_IPA_MASTER_DRIVER_INIT_COMPLETE_IND_MAX_MSG_LEN_V01,
70 .msg_id = QMI_IPA_MASTER_DRIVER_INIT_COMPLETE_IND_V01,
71 .ei_array = ipa3_master_driver_init_complt_ind_msg_data_v01_ei,
72};
73static struct msg_desc ipa3_install_fltr_rule_req_desc = {
74 .max_msg_len = QMI_IPA_INSTALL_FILTER_RULE_REQ_MAX_MSG_LEN_V01,
75 .msg_id = QMI_IPA_INSTALL_FILTER_RULE_REQ_V01,
76 .ei_array = ipa3_install_fltr_rule_req_msg_data_v01_ei,
77};
78static struct msg_desc ipa3_install_fltr_rule_resp_desc = {
79 .max_msg_len = QMI_IPA_INSTALL_FILTER_RULE_RESP_MAX_MSG_LEN_V01,
80 .msg_id = QMI_IPA_INSTALL_FILTER_RULE_RESP_V01,
81 .ei_array = ipa3_install_fltr_rule_resp_msg_data_v01_ei,
82};
83static struct msg_desc ipa3_filter_installed_notif_req_desc = {
84 .max_msg_len = QMI_IPA_FILTER_INSTALLED_NOTIF_REQ_MAX_MSG_LEN_V01,
85 .msg_id = QMI_IPA_FILTER_INSTALLED_NOTIF_REQ_V01,
86 .ei_array = ipa3_fltr_installed_notif_req_msg_data_v01_ei,
87};
88static struct msg_desc ipa3_filter_installed_notif_resp_desc = {
89 .max_msg_len = QMI_IPA_FILTER_INSTALLED_NOTIF_RESP_MAX_MSG_LEN_V01,
90 .msg_id = QMI_IPA_FILTER_INSTALLED_NOTIF_RESP_V01,
91 .ei_array = ipa3_fltr_installed_notif_resp_msg_data_v01_ei,
92};
93static struct msg_desc ipa3_config_req_desc = {
94 .max_msg_len = QMI_IPA_CONFIG_REQ_MAX_MSG_LEN_V01,
95 .msg_id = QMI_IPA_CONFIG_REQ_V01,
96 .ei_array = ipa3_config_req_msg_data_v01_ei,
97};
98static struct msg_desc ipa3_config_resp_desc = {
99 .max_msg_len = QMI_IPA_CONFIG_RESP_MAX_MSG_LEN_V01,
100 .msg_id = QMI_IPA_CONFIG_RESP_V01,
101 .ei_array = ipa3_config_resp_msg_data_v01_ei,
102};
103
104static struct msg_desc ipa3_init_modem_driver_cmplt_req_desc = {
105 .max_msg_len = QMI_IPA_INIT_MODEM_DRIVER_CMPLT_REQ_MAX_MSG_LEN_V01,
106 .msg_id = QMI_IPA_INIT_MODEM_DRIVER_CMPLT_REQ_V01,
107 .ei_array = ipa3_init_modem_driver_cmplt_req_msg_data_v01_ei,
108};
109
110static struct msg_desc ipa3_init_modem_driver_cmplt_resp_desc = {
111 .max_msg_len = QMI_IPA_INIT_MODEM_DRIVER_CMPLT_RESP_MAX_MSG_LEN_V01,
112 .msg_id = QMI_IPA_INIT_MODEM_DRIVER_CMPLT_RESP_V01,
113 .ei_array = ipa3_init_modem_driver_cmplt_resp_msg_data_v01_ei,
114};
115
Amir Levy664bda32017-02-15 18:21:25 +0200116static struct msg_desc ipa3_install_fltr_rule_req_ex_desc = {
117 .max_msg_len = QMI_IPA_INSTALL_FILTER_RULE_EX_REQ_MAX_MSG_LEN_V01,
118 .msg_id = QMI_IPA_INSTALL_FILTER_RULE_EX_REQ_V01,
119 .ei_array = ipa3_install_fltr_rule_req_ex_msg_data_v01_ei,
120};
121
Amir Levy9659e592016-10-27 18:08:27 +0300122static int ipa3_handle_indication_req(void *req_h, void *req)
123{
124 struct ipa_indication_reg_req_msg_v01 *indication_req;
125 struct ipa_indication_reg_resp_msg_v01 resp;
126 struct ipa_master_driver_init_complt_ind_msg_v01 ind;
127 int rc;
128
129 indication_req = (struct ipa_indication_reg_req_msg_v01 *)req;
130 IPAWANDBG("Received INDICATION Request\n");
131
132 memset(&resp, 0, sizeof(struct ipa_indication_reg_resp_msg_v01));
133 resp.resp.result = IPA_QMI_RESULT_SUCCESS_V01;
134 rc = qmi_send_resp_from_cb(ipa3_svc_handle, curr_conn, req_h,
135 &ipa3_indication_reg_resp_desc, &resp, sizeof(resp));
136 ipa3_qmi_indication_fin = true;
137 /* check if need sending indication to modem */
138 if (ipa3_qmi_modem_init_fin) {
139 IPAWANDBG("send indication to modem (%d)\n",
140 ipa3_qmi_modem_init_fin);
141 memset(&ind, 0, sizeof(struct
142 ipa_master_driver_init_complt_ind_msg_v01));
143 ind.master_driver_init_status.result =
144 IPA_QMI_RESULT_SUCCESS_V01;
145 rc = qmi_send_ind_from_cb(ipa3_svc_handle, curr_conn,
146 &ipa3_master_driver_complete_indication_desc,
147 &ind,
148 sizeof(ind));
149 } else {
150 IPAWANERR("not send indication\n");
151 }
152 return rc;
153}
154
155
156static int ipa3_handle_install_filter_rule_req(void *req_h, void *req)
157{
158 struct ipa_install_fltr_rule_req_msg_v01 *rule_req;
159 struct ipa_install_fltr_rule_resp_msg_v01 resp;
160 uint32_t rule_hdl[MAX_NUM_Q6_RULE];
161 int rc = 0, i;
162
163 rule_req = (struct ipa_install_fltr_rule_req_msg_v01 *)req;
164 memset(rule_hdl, 0, sizeof(rule_hdl));
165 memset(&resp, 0, sizeof(struct ipa_install_fltr_rule_resp_msg_v01));
166 IPAWANDBG("Received install filter Request\n");
167
168 rc = ipa3_copy_ul_filter_rule_to_ipa((struct
169 ipa_install_fltr_rule_req_msg_v01*)req);
170 if (rc)
171 IPAWANERR("copy UL rules from modem is failed\n");
172
173 resp.resp.result = IPA_QMI_RESULT_SUCCESS_V01;
174 if (rule_req->filter_spec_ex_list_valid == true) {
175 resp.rule_id_valid = 1;
176 if (rule_req->filter_spec_ex_list_len > MAX_NUM_Q6_RULE) {
177 resp.rule_id_len = MAX_NUM_Q6_RULE;
178 IPAWANERR("installed (%d) max Q6-UL rules ",
179 MAX_NUM_Q6_RULE);
180 IPAWANERR("but modem gives total (%u)\n",
181 rule_req->filter_spec_ex_list_len);
182 } else {
183 resp.rule_id_len =
184 rule_req->filter_spec_ex_list_len;
185 }
186 } else {
187 resp.rule_id_valid = 0;
188 resp.rule_id_len = 0;
189 }
190
191 /* construct UL filter rules response to Modem*/
192 for (i = 0; i < resp.rule_id_len; i++) {
193 resp.rule_id[i] =
194 rule_req->filter_spec_ex_list[i].rule_id;
195 }
196
197 rc = qmi_send_resp_from_cb(ipa3_svc_handle, curr_conn, req_h,
198 &ipa3_install_fltr_rule_resp_desc, &resp, sizeof(resp));
199
200 IPAWANDBG("Replied to install filter request\n");
201 return rc;
202}
203
204static int ipa3_handle_filter_installed_notify_req(void *req_h, void *req)
205{
206 struct ipa_fltr_installed_notif_resp_msg_v01 resp;
207 int rc = 0;
208
209 memset(&resp, 0, sizeof(struct ipa_fltr_installed_notif_resp_msg_v01));
210 IPAWANDBG("Received filter_install_notify Request\n");
211 resp.resp.result = IPA_QMI_RESULT_SUCCESS_V01;
212
213 rc = qmi_send_resp_from_cb(ipa3_svc_handle, curr_conn, req_h,
214 &ipa3_filter_installed_notif_resp_desc,
215 &resp, sizeof(resp));
216
217 IPAWANDBG("Responsed filter_install_notify Request\n");
218 return rc;
219}
220
221static int handle_ipa_config_req(void *req_h, void *req)
222{
223 struct ipa_config_resp_msg_v01 resp;
224 int rc;
225
226 memset(&resp, 0, sizeof(struct ipa_config_resp_msg_v01));
227 resp.resp.result = IPA_QMI_RESULT_SUCCESS_V01;
228 IPAWANDBG("Received IPA CONFIG Request\n");
229 rc = ipa_mhi_handle_ipa_config_req(
230 (struct ipa_config_req_msg_v01 *)req);
231 if (rc) {
232 IPAERR("ipa3_mhi_handle_ipa_config_req failed %d\n", rc);
233 resp.resp.result = IPA_QMI_RESULT_FAILURE_V01;
234 }
235 rc = qmi_send_resp_from_cb(ipa3_svc_handle, curr_conn, req_h,
236 &ipa3_config_resp_desc,
237 &resp, sizeof(resp));
238 IPAWANDBG("Responsed IPA CONFIG Request\n");
239 return rc;
240}
241
242static int ipa3_handle_modem_init_cmplt_req(void *req_h, void *req)
243{
244 struct ipa_init_modem_driver_cmplt_req_msg_v01 *cmplt_req;
245 struct ipa_init_modem_driver_cmplt_resp_msg_v01 resp;
246 int rc;
247
248 IPAWANDBG("Received QMI_IPA_INIT_MODEM_DRIVER_CMPLT_REQ_V01\n");
249 cmplt_req = (struct ipa_init_modem_driver_cmplt_req_msg_v01 *)req;
250
251 if (ipa3_modem_init_cmplt == false) {
252 ipa3_modem_init_cmplt = true;
253 if (ipa3_qmi_modem_init_fin == true) {
254 IPAWANDBG("load uc related registers (%d)\n",
255 ipa3_qmi_modem_init_fin);
256 ipa3_uc_load_notify();
257 }
258 }
259
260 memset(&resp, 0, sizeof(resp));
261 resp.resp.result = IPA_QMI_RESULT_SUCCESS_V01;
262
263 rc = qmi_send_resp_from_cb(ipa3_svc_handle, curr_conn, req_h,
264 &ipa3_init_modem_driver_cmplt_resp_desc,
265 &resp, sizeof(resp));
266
267 IPAWANDBG("Sent QMI_IPA_INIT_MODEM_DRIVER_CMPLT_RESP_V01\n");
268 return rc;
269}
270
271static int ipa3_a5_svc_connect_cb(struct qmi_handle *handle,
272 void *conn_h)
273{
274 if (ipa3_svc_handle != handle || !conn_h)
275 return -EINVAL;
276
277 if (curr_conn) {
278 IPAWANERR("Service is busy\n");
279 return -ECONNREFUSED;
280 }
281 curr_conn = conn_h;
282 return 0;
283}
284
285static int ipa3_a5_svc_disconnect_cb(struct qmi_handle *handle,
286 void *conn_h)
287{
288 if (ipa3_svc_handle != handle || curr_conn != conn_h)
289 return -EINVAL;
290
291 curr_conn = NULL;
292 return 0;
293}
294
295static int ipa3_a5_svc_req_desc_cb(unsigned int msg_id,
296 struct msg_desc **req_desc)
297{
298 int rc;
299
300 switch (msg_id) {
301 case QMI_IPA_INDICATION_REGISTER_REQ_V01:
302 *req_desc = &ipa3_indication_reg_req_desc;
303 rc = sizeof(struct ipa_indication_reg_req_msg_v01);
304 break;
305
306 case QMI_IPA_INSTALL_FILTER_RULE_REQ_V01:
307 *req_desc = &ipa3_install_fltr_rule_req_desc;
308 rc = sizeof(struct ipa_install_fltr_rule_req_msg_v01);
309 break;
Amir Levy664bda32017-02-15 18:21:25 +0200310 case QMI_IPA_INSTALL_FILTER_RULE_EX_REQ_V01:
311 *req_desc = &ipa3_install_fltr_rule_req_ex_desc;
312 rc = sizeof(struct ipa_install_fltr_rule_req_ex_msg_v01);
313 break;
Amir Levy9659e592016-10-27 18:08:27 +0300314 case QMI_IPA_FILTER_INSTALLED_NOTIF_REQ_V01:
315 *req_desc = &ipa3_filter_installed_notif_req_desc;
316 rc = sizeof(struct ipa_fltr_installed_notif_req_msg_v01);
317 break;
318 case QMI_IPA_CONFIG_REQ_V01:
319 *req_desc = &ipa3_config_req_desc;
320 rc = sizeof(struct ipa_config_req_msg_v01);
321 break;
322 case QMI_IPA_INIT_MODEM_DRIVER_CMPLT_REQ_V01:
323 *req_desc = &ipa3_init_modem_driver_cmplt_req_desc;
324 rc = sizeof(struct ipa_init_modem_driver_cmplt_req_msg_v01);
325 break;
326 default:
327 rc = -ENOTSUPP;
328 break;
329 }
330 return rc;
331}
332
333static int ipa3_a5_svc_req_cb(struct qmi_handle *handle, void *conn_h,
334 void *req_h, unsigned int msg_id, void *req)
335{
336 int rc;
337
338 if (ipa3_svc_handle != handle || curr_conn != conn_h)
339 return -EINVAL;
340
341 switch (msg_id) {
342 case QMI_IPA_INDICATION_REGISTER_REQ_V01:
343 rc = ipa3_handle_indication_req(req_h, req);
344 break;
345 case QMI_IPA_INSTALL_FILTER_RULE_REQ_V01:
346 rc = ipa3_handle_install_filter_rule_req(req_h, req);
347 rc = ipa3_wwan_update_mux_channel_prop();
348 break;
349 case QMI_IPA_FILTER_INSTALLED_NOTIF_REQ_V01:
350 rc = ipa3_handle_filter_installed_notify_req(req_h, req);
351 break;
352 case QMI_IPA_CONFIG_REQ_V01:
353 rc = handle_ipa_config_req(req_h, req);
354 break;
355 case QMI_IPA_INIT_MODEM_DRIVER_CMPLT_REQ_V01:
356 rc = ipa3_handle_modem_init_cmplt_req(req_h, req);
357 break;
358 default:
359 rc = -ENOTSUPP;
360 break;
361 }
362 return rc;
363}
364
365static void ipa3_a5_svc_recv_msg(struct work_struct *work)
366{
367 int rc;
368
369 do {
370 IPAWANDBG_LOW("Notified about a Receive Event");
371 rc = qmi_recv_msg(ipa3_svc_handle);
372 } while (rc == 0);
373 if (rc != -ENOMSG)
374 IPAWANERR("Error receiving message\n");
375}
376
377static void qmi_ipa_a5_svc_ntfy(struct qmi_handle *handle,
378 enum qmi_event_type event, void *priv)
379{
380 switch (event) {
381 case QMI_RECV_MSG:
382 if (!workqueues_stopped)
383 queue_delayed_work(ipa_svc_workqueue,
384 &work_recv_msg, 0);
385 break;
386 default:
387 break;
388 }
389}
390
391static struct qmi_svc_ops_options ipa3_a5_svc_ops_options = {
392 .version = 1,
393 .service_id = IPA_A5_SERVICE_SVC_ID,
394 .service_vers = IPA_A5_SVC_VERS,
395 .service_ins = IPA_A5_SERVICE_INS_ID,
396 .connect_cb = ipa3_a5_svc_connect_cb,
397 .disconnect_cb = ipa3_a5_svc_disconnect_cb,
398 .req_desc_cb = ipa3_a5_svc_req_desc_cb,
399 .req_cb = ipa3_a5_svc_req_cb,
400};
401
402
403/****************************************************/
404/* QMI A5 client ->Q6 */
405/****************************************************/
406static void ipa3_q6_clnt_recv_msg(struct work_struct *work);
407static DECLARE_DELAYED_WORK(ipa3_work_recv_msg_client, ipa3_q6_clnt_recv_msg);
408static void ipa3_q6_clnt_svc_arrive(struct work_struct *work);
409static DECLARE_DELAYED_WORK(ipa3_work_svc_arrive, ipa3_q6_clnt_svc_arrive);
410static void ipa3_q6_clnt_svc_exit(struct work_struct *work);
411static DECLARE_DELAYED_WORK(ipa3_work_svc_exit, ipa3_q6_clnt_svc_exit);
412/* Test client port for IPC Router */
413static struct qmi_handle *ipa_q6_clnt;
414static int ipa_q6_clnt_reset;
415
416static int ipa3_check_qmi_response(int rc,
417 int req_id,
418 enum ipa_qmi_result_type_v01 result,
419 enum ipa_qmi_error_type_v01 error,
420 char *resp_type)
421{
422 if (rc < 0) {
423 if (rc == -ETIMEDOUT && ipa3_rmnet_ctx.ipa_rmnet_ssr) {
424 IPAWANERR(
425 "Timeout for qmi request id %d\n", req_id);
426 return rc;
427 }
428 if ((rc == -ENETRESET) || (rc == -ENODEV)) {
429 IPAWANERR(
430 "SSR while waiting for qmi request id %d\n", req_id);
431 return rc;
432 }
433 IPAWANERR("Error sending qmi request id %d, rc = %d\n",
434 req_id, rc);
435 return rc;
436 }
437 if (result != IPA_QMI_RESULT_SUCCESS_V01 &&
438 ipa3_rmnet_ctx.ipa_rmnet_ssr) {
439 IPAWANERR(
440 "Got bad response %d from request id %d (error %d)\n",
441 req_id, result, error);
442 return result;
443 }
444 IPAWANDBG_LOW("Received %s successfully\n", resp_type);
445 return 0;
446}
447
448static int ipa3_qmi_init_modem_send_sync_msg(void)
449{
450 struct ipa_init_modem_driver_req_msg_v01 req;
451 struct ipa_init_modem_driver_resp_msg_v01 resp;
452 struct msg_desc req_desc, resp_desc;
453 int rc;
454 u16 smem_restr_bytes = ipa3_get_smem_restr_bytes();
455
456 memset(&req, 0, sizeof(struct ipa_init_modem_driver_req_msg_v01));
457 memset(&resp, 0, sizeof(struct ipa_init_modem_driver_resp_msg_v01));
458
459 req.platform_type_valid = true;
460 req.platform_type = ipa_wan_platform;
461
462 req.hdr_tbl_info_valid = (IPA_MEM_PART(modem_hdr_size) != 0);
463 req.hdr_tbl_info.modem_offset_start =
464 IPA_MEM_PART(modem_hdr_ofst) + smem_restr_bytes;
465 req.hdr_tbl_info.modem_offset_end = IPA_MEM_PART(modem_hdr_ofst) +
466 smem_restr_bytes + IPA_MEM_PART(modem_hdr_size) - 1;
467
468 req.v4_route_tbl_info_valid = true;
469 req.v4_route_tbl_info.route_tbl_start_addr =
470 IPA_MEM_PART(v4_rt_nhash_ofst) + smem_restr_bytes;
471 req.v4_route_tbl_info.num_indices =
472 IPA_MEM_PART(v4_modem_rt_index_hi);
473 req.v6_route_tbl_info_valid = true;
474
475 req.v6_route_tbl_info.route_tbl_start_addr =
476 IPA_MEM_PART(v6_rt_nhash_ofst) + smem_restr_bytes;
477 req.v6_route_tbl_info.num_indices =
478 IPA_MEM_PART(v6_modem_rt_index_hi);
479
480 req.v4_filter_tbl_start_addr_valid = true;
481 req.v4_filter_tbl_start_addr =
482 IPA_MEM_PART(v4_flt_nhash_ofst) + smem_restr_bytes;
483
484 req.v6_filter_tbl_start_addr_valid = true;
485 req.v6_filter_tbl_start_addr =
486 IPA_MEM_PART(v6_flt_nhash_ofst) + smem_restr_bytes;
487
488 req.modem_mem_info_valid = (IPA_MEM_PART(modem_size) != 0);
489 req.modem_mem_info.block_start_addr =
490 IPA_MEM_PART(modem_ofst) + smem_restr_bytes;
491 req.modem_mem_info.size = IPA_MEM_PART(modem_size);
492
493 req.ctrl_comm_dest_end_pt_valid = true;
494 req.ctrl_comm_dest_end_pt =
495 ipa3_get_ep_mapping(IPA_CLIENT_APPS_WAN_CONS);
496
497 req.hdr_proc_ctx_tbl_info_valid =
498 (IPA_MEM_PART(modem_hdr_proc_ctx_size) != 0);
499 req.hdr_proc_ctx_tbl_info.modem_offset_start =
500 IPA_MEM_PART(modem_hdr_proc_ctx_ofst) + smem_restr_bytes;
501 req.hdr_proc_ctx_tbl_info.modem_offset_end =
502 IPA_MEM_PART(modem_hdr_proc_ctx_ofst) +
503 IPA_MEM_PART(modem_hdr_proc_ctx_size) + smem_restr_bytes - 1;
504
505 req.zip_tbl_info_valid = (IPA_MEM_PART(modem_comp_decomp_size) != 0);
506 req.zip_tbl_info.modem_offset_start =
507 IPA_MEM_PART(modem_comp_decomp_size) + smem_restr_bytes;
508 req.zip_tbl_info.modem_offset_end =
509 IPA_MEM_PART(modem_comp_decomp_ofst) +
510 IPA_MEM_PART(modem_comp_decomp_size) + smem_restr_bytes - 1;
511
512 req.v4_hash_route_tbl_info_valid = true;
513 req.v4_hash_route_tbl_info.route_tbl_start_addr =
514 IPA_MEM_PART(v4_rt_hash_ofst) + smem_restr_bytes;
515 req.v4_hash_route_tbl_info.num_indices =
516 IPA_MEM_PART(v4_modem_rt_index_hi);
517
518 req.v6_hash_route_tbl_info_valid = true;
519 req.v6_hash_route_tbl_info.route_tbl_start_addr =
520 IPA_MEM_PART(v6_rt_hash_ofst) + smem_restr_bytes;
521 req.v6_hash_route_tbl_info.num_indices =
522 IPA_MEM_PART(v6_modem_rt_index_hi);
523
524 req.v4_hash_filter_tbl_start_addr_valid = true;
525 req.v4_hash_filter_tbl_start_addr =
526 IPA_MEM_PART(v4_flt_hash_ofst) + smem_restr_bytes;
527
528 req.v6_hash_filter_tbl_start_addr_valid = true;
529 req.v6_hash_filter_tbl_start_addr =
530 IPA_MEM_PART(v6_flt_hash_ofst) + smem_restr_bytes;
531
532 if (!ipa3_uc_loaded_check()) { /* First time boot */
533 req.is_ssr_bootup_valid = false;
534 req.is_ssr_bootup = 0;
535 } else { /* After SSR boot */
536 req.is_ssr_bootup_valid = true;
537 req.is_ssr_bootup = 1;
538 }
539
540 IPAWANDBG("platform_type %d\n", req.platform_type);
541 IPAWANDBG("hdr_tbl_info.modem_offset_start %d\n",
542 req.hdr_tbl_info.modem_offset_start);
543 IPAWANDBG("hdr_tbl_info.modem_offset_end %d\n",
544 req.hdr_tbl_info.modem_offset_end);
545 IPAWANDBG("v4_route_tbl_info.route_tbl_start_addr %d\n",
546 req.v4_route_tbl_info.route_tbl_start_addr);
547 IPAWANDBG("v4_route_tbl_info.num_indices %d\n",
548 req.v4_route_tbl_info.num_indices);
549 IPAWANDBG("v6_route_tbl_info.route_tbl_start_addr %d\n",
550 req.v6_route_tbl_info.route_tbl_start_addr);
551 IPAWANDBG("v6_route_tbl_info.num_indices %d\n",
552 req.v6_route_tbl_info.num_indices);
553 IPAWANDBG("v4_filter_tbl_start_addr %d\n",
554 req.v4_filter_tbl_start_addr);
555 IPAWANDBG("v6_filter_tbl_start_addr %d\n",
556 req.v6_filter_tbl_start_addr);
557 IPAWANDBG("modem_mem_info.block_start_addr %d\n",
558 req.modem_mem_info.block_start_addr);
559 IPAWANDBG("modem_mem_info.size %d\n",
560 req.modem_mem_info.size);
561 IPAWANDBG("ctrl_comm_dest_end_pt %d\n",
562 req.ctrl_comm_dest_end_pt);
563 IPAWANDBG("is_ssr_bootup %d\n",
564 req.is_ssr_bootup);
565 IPAWANDBG("v4_hash_route_tbl_info.route_tbl_start_addr %d\n",
566 req.v4_hash_route_tbl_info.route_tbl_start_addr);
567 IPAWANDBG("v4_hash_route_tbl_info.num_indices %d\n",
568 req.v4_hash_route_tbl_info.num_indices);
569 IPAWANDBG("v6_hash_route_tbl_info.route_tbl_start_addr %d\n",
570 req.v6_hash_route_tbl_info.route_tbl_start_addr);
571 IPAWANDBG("v6_hash_route_tbl_info.num_indices %d\n",
572 req.v6_hash_route_tbl_info.num_indices);
573 IPAWANDBG("v4_hash_filter_tbl_start_addr %d\n",
574 req.v4_hash_filter_tbl_start_addr);
575 IPAWANDBG("v6_hash_filter_tbl_start_addr %d\n",
576 req.v6_hash_filter_tbl_start_addr);
577
578 req_desc.max_msg_len = QMI_IPA_INIT_MODEM_DRIVER_REQ_MAX_MSG_LEN_V01;
579 req_desc.msg_id = QMI_IPA_INIT_MODEM_DRIVER_REQ_V01;
580 req_desc.ei_array = ipa3_init_modem_driver_req_msg_data_v01_ei;
581
582 resp_desc.max_msg_len = QMI_IPA_INIT_MODEM_DRIVER_RESP_MAX_MSG_LEN_V01;
583 resp_desc.msg_id = QMI_IPA_INIT_MODEM_DRIVER_RESP_V01;
584 resp_desc.ei_array = ipa3_init_modem_driver_resp_msg_data_v01_ei;
585
586 pr_info("Sending QMI_IPA_INIT_MODEM_DRIVER_REQ_V01\n");
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200587 if (unlikely(!ipa_q6_clnt))
588 return -ETIMEDOUT;
Amir Levy9659e592016-10-27 18:08:27 +0300589 rc = qmi_send_req_wait(ipa_q6_clnt, &req_desc, &req, sizeof(req),
590 &resp_desc, &resp, sizeof(resp),
591 QMI_SEND_REQ_TIMEOUT_MS);
592 pr_info("QMI_IPA_INIT_MODEM_DRIVER_REQ_V01 response received\n");
593 return ipa3_check_qmi_response(rc,
594 QMI_IPA_INIT_MODEM_DRIVER_REQ_V01, resp.resp.result,
595 resp.resp.error, "ipa_init_modem_driver_resp_msg_v01");
596}
597
598/* sending filter-install-request to modem*/
599int ipa3_qmi_filter_request_send(struct ipa_install_fltr_rule_req_msg_v01 *req)
600{
601 struct ipa_install_fltr_rule_resp_msg_v01 resp;
602 struct msg_desc req_desc, resp_desc;
603 int rc;
604
605 /* check if the filter rules from IPACM is valid */
606 if (req->filter_spec_ex_list_len == 0) {
607 IPAWANDBG("IPACM pass zero rules to Q6\n");
608 } else {
609 IPAWANDBG("IPACM pass %u rules to Q6\n",
610 req->filter_spec_ex_list_len);
611 }
612
613 /* cache the qmi_filter_request */
614 memcpy(&(ipa3_qmi_ctx->ipa_install_fltr_rule_req_msg_cache[
615 ipa3_qmi_ctx->num_ipa_install_fltr_rule_req_msg]),
616 req, sizeof(struct ipa_install_fltr_rule_req_msg_v01));
617 ipa3_qmi_ctx->num_ipa_install_fltr_rule_req_msg++;
618 ipa3_qmi_ctx->num_ipa_install_fltr_rule_req_msg %= 10;
619
620 req_desc.max_msg_len = QMI_IPA_INSTALL_FILTER_RULE_REQ_MAX_MSG_LEN_V01;
621 req_desc.msg_id = QMI_IPA_INSTALL_FILTER_RULE_REQ_V01;
622 req_desc.ei_array = ipa3_install_fltr_rule_req_msg_data_v01_ei;
623
624 memset(&resp, 0, sizeof(struct ipa_install_fltr_rule_resp_msg_v01));
625 resp_desc.max_msg_len =
626 QMI_IPA_INSTALL_FILTER_RULE_RESP_MAX_MSG_LEN_V01;
627 resp_desc.msg_id = QMI_IPA_INSTALL_FILTER_RULE_RESP_V01;
628 resp_desc.ei_array = ipa3_install_fltr_rule_resp_msg_data_v01_ei;
629
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200630 if (unlikely(!ipa_q6_clnt))
631 return -ETIMEDOUT;
Amir Levy9659e592016-10-27 18:08:27 +0300632 rc = qmi_send_req_wait(ipa_q6_clnt, &req_desc,
633 req,
634 sizeof(struct ipa_install_fltr_rule_req_msg_v01),
635 &resp_desc, &resp, sizeof(resp),
636 QMI_SEND_REQ_TIMEOUT_MS);
637 return ipa3_check_qmi_response(rc,
638 QMI_IPA_INSTALL_FILTER_RULE_REQ_V01, resp.resp.result,
639 resp.resp.error, "ipa_install_filter");
640}
641
Amir Levy664bda32017-02-15 18:21:25 +0200642/* sending filter-install-request to modem*/
643int ipa3_qmi_filter_request_ex_send(
644 struct ipa_install_fltr_rule_req_ex_msg_v01 *req)
645{
646 struct ipa_install_fltr_rule_resp_ex_msg_v01 resp;
647 struct msg_desc req_desc, resp_desc;
648 int rc;
649
650 /* check if the filter rules from IPACM is valid */
651 if (req->filter_spec_ex_list_len == 0) {
652 IPAWANDBG("IPACM pass zero rules to Q6\n");
653 } else {
654 IPAWANDBG("IPACM pass %u rules to Q6\n",
655 req->filter_spec_ex_list_len);
656 }
657
658 /* cache the qmi_filter_request */
659 memcpy(&(ipa3_qmi_ctx->ipa_install_fltr_rule_req_ex_msg_cache[
660 ipa3_qmi_ctx->num_ipa_install_fltr_rule_req_ex_msg]),
661 req, sizeof(struct ipa_install_fltr_rule_req_ex_msg_v01));
662 ipa3_qmi_ctx->num_ipa_install_fltr_rule_req_ex_msg++;
663 ipa3_qmi_ctx->num_ipa_install_fltr_rule_req_ex_msg %= 10;
664
665 req_desc.max_msg_len =
666 QMI_IPA_INSTALL_FILTER_RULE_EX_REQ_MAX_MSG_LEN_V01;
667 req_desc.msg_id = QMI_IPA_INSTALL_FILTER_RULE_EX_REQ_V01;
668 req_desc.ei_array = ipa3_install_fltr_rule_req_ex_msg_data_v01_ei;
669
670 memset(&resp, 0, sizeof(struct ipa_install_fltr_rule_resp_ex_msg_v01));
671 resp_desc.max_msg_len =
672 QMI_IPA_INSTALL_FILTER_RULE_EX_RESP_MAX_MSG_LEN_V01;
673 resp_desc.msg_id = QMI_IPA_INSTALL_FILTER_RULE_EX_RESP_V01;
674 resp_desc.ei_array = ipa3_install_fltr_rule_resp_ex_msg_data_v01_ei;
675
676 rc = qmi_send_req_wait(ipa_q6_clnt, &req_desc,
677 req,
678 sizeof(struct ipa_install_fltr_rule_req_ex_msg_v01),
679 &resp_desc, &resp, sizeof(resp),
680 QMI_SEND_REQ_TIMEOUT_MS);
681 return ipa3_check_qmi_response(rc,
682 QMI_IPA_INSTALL_FILTER_RULE_EX_REQ_V01, resp.resp.result,
683 resp.resp.error, "ipa_install_filter");
684}
Amir Levy9659e592016-10-27 18:08:27 +0300685
686int ipa3_qmi_enable_force_clear_datapath_send(
687 struct ipa_enable_force_clear_datapath_req_msg_v01 *req)
688{
689 struct ipa_enable_force_clear_datapath_resp_msg_v01 resp;
690 struct msg_desc req_desc, resp_desc;
691 int rc = 0;
692
693
694 if (!req || !req->source_pipe_bitmask) {
695 IPAWANERR("invalid params\n");
696 return -EINVAL;
697 }
698
699 req_desc.max_msg_len =
700 QMI_IPA_ENABLE_FORCE_CLEAR_DATAPATH_REQ_MAX_MSG_LEN_V01;
701 req_desc.msg_id = QMI_IPA_ENABLE_FORCE_CLEAR_DATAPATH_REQ_V01;
702 req_desc.ei_array =
703 ipa3_enable_force_clear_datapath_req_msg_data_v01_ei;
704
705 memset(&resp, 0, sizeof(struct ipa_fltr_installed_notif_resp_msg_v01));
706 resp_desc.max_msg_len =
707 QMI_IPA_ENABLE_FORCE_CLEAR_DATAPATH_RESP_MAX_MSG_LEN_V01;
708 resp_desc.msg_id = QMI_IPA_ENABLE_FORCE_CLEAR_DATAPATH_RESP_V01;
709 resp_desc.ei_array =
710 ipa3_enable_force_clear_datapath_resp_msg_data_v01_ei;
711
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200712 if (unlikely(!ipa_q6_clnt))
713 return -ETIMEDOUT;
Amir Levy9659e592016-10-27 18:08:27 +0300714 rc = qmi_send_req_wait(ipa_q6_clnt,
715 &req_desc,
716 req,
717 sizeof(*req),
Skylar Chang1be75e1b2017-01-23 13:53:56 -0800718 &resp_desc, &resp, sizeof(resp),
719 QMI_IPA_FORCE_CLEAR_DATAPATH_TIMEOUT_MS);
Amir Levy9659e592016-10-27 18:08:27 +0300720 if (rc < 0) {
721 IPAWANERR("send req failed %d\n", rc);
722 return rc;
723 }
724 if (resp.resp.result != IPA_QMI_RESULT_SUCCESS_V01) {
725 IPAWANERR("filter_notify failed %d\n",
726 resp.resp.result);
727 return resp.resp.result;
728 }
729 IPAWANDBG("SUCCESS\n");
730 return rc;
731}
732
733int ipa3_qmi_disable_force_clear_datapath_send(
734 struct ipa_disable_force_clear_datapath_req_msg_v01 *req)
735{
736 struct ipa_disable_force_clear_datapath_resp_msg_v01 resp;
737 struct msg_desc req_desc, resp_desc;
738 int rc = 0;
739
740
741 if (!req) {
742 IPAWANERR("invalid params\n");
743 return -EINVAL;
744 }
745
746 req_desc.max_msg_len =
747 QMI_IPA_DISABLE_FORCE_CLEAR_DATAPATH_REQ_MAX_MSG_LEN_V01;
748 req_desc.msg_id = QMI_IPA_DISABLE_FORCE_CLEAR_DATAPATH_REQ_V01;
749 req_desc.ei_array =
750 ipa3_disable_force_clear_datapath_req_msg_data_v01_ei;
751
752 memset(&resp, 0, sizeof(struct ipa_fltr_installed_notif_resp_msg_v01));
753 resp_desc.max_msg_len =
754 QMI_IPA_DISABLE_FORCE_CLEAR_DATAPATH_RESP_MAX_MSG_LEN_V01;
755 resp_desc.msg_id = QMI_IPA_DISABLE_FORCE_CLEAR_DATAPATH_RESP_V01;
756 resp_desc.ei_array =
757 ipa3_disable_force_clear_datapath_resp_msg_data_v01_ei;
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200758 if (unlikely(!ipa_q6_clnt))
759 return -ETIMEDOUT;
Amir Levy9659e592016-10-27 18:08:27 +0300760 rc = qmi_send_req_wait(ipa_q6_clnt,
761 &req_desc,
762 req,
763 sizeof(*req),
Skylar Chang1be75e1b2017-01-23 13:53:56 -0800764 &resp_desc, &resp, sizeof(resp),
765 QMI_IPA_FORCE_CLEAR_DATAPATH_TIMEOUT_MS);
Amir Levy9659e592016-10-27 18:08:27 +0300766 if (rc < 0) {
767 IPAWANERR("send req failed %d\n", rc);
768 return rc;
769 }
770 if (resp.resp.result != IPA_QMI_RESULT_SUCCESS_V01) {
771 IPAWANERR("filter_notify failed %d\n",
772 resp.resp.result);
773 return resp.resp.result;
774 }
775 IPAWANDBG("SUCCESS\n");
776 return rc;
777}
778
779/* sending filter-installed-notify-request to modem*/
780int ipa3_qmi_filter_notify_send(
781 struct ipa_fltr_installed_notif_req_msg_v01 *req)
782{
783 struct ipa_fltr_installed_notif_resp_msg_v01 resp;
784 struct msg_desc req_desc, resp_desc;
785 int rc = 0;
786
787 /* check if the filter rules from IPACM is valid */
788 if (req->rule_id_len == 0) {
789 IPAWANERR(" delete UL filter rule for pipe %d\n",
790 req->source_pipe_index);
791 return -EINVAL;
792 } else if (req->rule_id_len > QMI_IPA_MAX_FILTERS_V01) {
793 IPAWANERR(" UL filter rule for pipe %d exceed max (%u)\n",
794 req->source_pipe_index,
795 req->rule_id_len);
796 return -EINVAL;
797 }
798
799 /* cache the qmi_filter_request */
800 memcpy(&(ipa3_qmi_ctx->ipa_fltr_installed_notif_req_msg_cache[
801 ipa3_qmi_ctx->num_ipa_fltr_installed_notif_req_msg]),
802 req, sizeof(struct ipa_fltr_installed_notif_req_msg_v01));
803 ipa3_qmi_ctx->num_ipa_fltr_installed_notif_req_msg++;
804 ipa3_qmi_ctx->num_ipa_fltr_installed_notif_req_msg %= 10;
805
806 req_desc.max_msg_len =
807 QMI_IPA_FILTER_INSTALLED_NOTIF_REQ_MAX_MSG_LEN_V01;
808 req_desc.msg_id = QMI_IPA_FILTER_INSTALLED_NOTIF_REQ_V01;
809 req_desc.ei_array = ipa3_fltr_installed_notif_req_msg_data_v01_ei;
810
811 memset(&resp, 0, sizeof(struct ipa_fltr_installed_notif_resp_msg_v01));
812 resp_desc.max_msg_len =
813 QMI_IPA_FILTER_INSTALLED_NOTIF_RESP_MAX_MSG_LEN_V01;
814 resp_desc.msg_id = QMI_IPA_FILTER_INSTALLED_NOTIF_RESP_V01;
815 resp_desc.ei_array = ipa3_fltr_installed_notif_resp_msg_data_v01_ei;
816
Gidon Studinski3021a6f2016-11-10 12:48:48 +0200817 if (unlikely(!ipa_q6_clnt))
818 return -ETIMEDOUT;
Amir Levy9659e592016-10-27 18:08:27 +0300819 rc = qmi_send_req_wait(ipa_q6_clnt,
820 &req_desc,
821 req,
822 sizeof(struct ipa_fltr_installed_notif_req_msg_v01),
823 &resp_desc, &resp, sizeof(resp),
824 QMI_SEND_REQ_TIMEOUT_MS);
825 return ipa3_check_qmi_response(rc,
826 QMI_IPA_FILTER_INSTALLED_NOTIF_REQ_V01, resp.resp.result,
827 resp.resp.error, "ipa_fltr_installed_notif_resp");
828}
829
830static void ipa3_q6_clnt_recv_msg(struct work_struct *work)
831{
832 int rc;
833
834 do {
835 IPAWANDBG_LOW("Notified about a Receive Event");
836 rc = qmi_recv_msg(ipa_q6_clnt);
837 } while (rc == 0);
838 if (rc != -ENOMSG)
839 IPAWANERR("Error receiving message\n");
840}
841
842static void ipa3_q6_clnt_notify(struct qmi_handle *handle,
843 enum qmi_event_type event, void *notify_priv)
844{
845 switch (event) {
846 case QMI_RECV_MSG:
847 IPAWANDBG_LOW("client qmi recv message called");
848 if (!workqueues_stopped)
849 queue_delayed_work(ipa_clnt_resp_workqueue,
850 &ipa3_work_recv_msg_client, 0);
851 break;
852 default:
853 break;
854 }
855}
856
857static void ipa3_q6_clnt_ind_cb(struct qmi_handle *handle, unsigned int msg_id,
858 void *msg, unsigned int msg_len,
859 void *ind_cb_priv)
860{
861 struct ipa_data_usage_quota_reached_ind_msg_v01 qmi_ind;
862 struct msg_desc qmi_ind_desc;
863 int rc = 0;
864
865 if (handle != ipa_q6_clnt) {
866 IPAWANERR("Wrong client\n");
867 return;
868 }
869
870 if (msg_id == QMI_IPA_DATA_USAGE_QUOTA_REACHED_IND_V01) {
871 memset(&qmi_ind, 0, sizeof(
872 struct ipa_data_usage_quota_reached_ind_msg_v01));
873 qmi_ind_desc.max_msg_len =
874 QMI_IPA_DATA_USAGE_QUOTA_REACHED_IND_MAX_MSG_LEN_V01;
875 qmi_ind_desc.msg_id = QMI_IPA_DATA_USAGE_QUOTA_REACHED_IND_V01;
876 qmi_ind_desc.ei_array =
877 ipa3_data_usage_quota_reached_ind_msg_data_v01_ei;
878
879 rc = qmi_kernel_decode(&qmi_ind_desc, &qmi_ind, msg, msg_len);
880 if (rc < 0) {
881 IPAWANERR("Error decoding msg_id %d\n", msg_id);
882 return;
883 }
884 IPAWANDBG("Quota reached indication on qmux(%d) Mbytes(%lu)\n",
885 qmi_ind.apn.mux_id,
886 (unsigned long int) qmi_ind.apn.num_Mbytes);
Skylar Chang6b41f8d2016-11-01 12:50:11 -0700887 ipa3_broadcast_quota_reach_ind(qmi_ind.apn.mux_id,
888 IPA_UPSTEAM_MODEM);
Amir Levy9659e592016-10-27 18:08:27 +0300889 }
890}
891
892static void ipa3_q6_clnt_svc_arrive(struct work_struct *work)
893{
894 int rc;
895 struct ipa_master_driver_init_complt_ind_msg_v01 ind;
896
897 /* Create a Local client port for QMI communication */
898 ipa_q6_clnt = qmi_handle_create(ipa3_q6_clnt_notify, NULL);
899 if (!ipa_q6_clnt) {
900 IPAWANERR("QMI client handle alloc failed\n");
901 return;
902 }
903
904 IPAWANDBG("Lookup server name, get client-hdl(%p)\n",
905 ipa_q6_clnt);
906 rc = qmi_connect_to_service(ipa_q6_clnt,
907 IPA_Q6_SERVICE_SVC_ID,
908 IPA_Q6_SVC_VERS,
909 IPA_Q6_SERVICE_INS_ID);
910 if (rc < 0) {
911 IPAWANERR("Server not found\n");
912 qmi_handle_destroy(ipa_q6_clnt);
913 ipa_q6_clnt = NULL;
914 return;
915 }
916
917 rc = qmi_register_ind_cb(ipa_q6_clnt, ipa3_q6_clnt_ind_cb, NULL);
918 if (rc < 0)
919 IPAWANERR("Unable to register for indications\n");
920
921 ipa_q6_clnt_reset = 0;
922 IPAWANDBG("Q6 QMI service available now\n");
923 /* Initialize modem IPA-driver */
924 IPAWANDBG("send ipa3_qmi_init_modem_send_sync_msg to modem\n");
925 rc = ipa3_qmi_init_modem_send_sync_msg();
926 if ((rc == -ENETRESET) || (rc == -ENODEV)) {
927 IPAWANERR(
928 "ipa3_qmi_init_modem_send_sync_msg failed due to SSR!\n");
929 /* Cleanup will take place when ipa3_wwan_remove is called */
930 return;
931 }
932 if (rc != 0) {
933 IPAWANERR("ipa3_qmi_init_modem_send_sync_msg failed\n");
934 /*
935 * This is a very unexpected scenario, which requires a kernel
936 * panic in order to force dumps for QMI/Q6 side analysis.
937 */
938 BUG();
939 return;
940 }
941 ipa3_qmi_modem_init_fin = true;
942
943 /* got modem_init_cmplt_req already, load uc-related register */
944 if (ipa3_modem_init_cmplt == true) {
945 IPAWANDBG("load uc related registers (%d)\n",
946 ipa3_modem_init_cmplt);
947 ipa3_uc_load_notify();
948 }
949
950 /* In cold-bootup, first_time_handshake = false */
951 ipa3_q6_handshake_complete(first_time_handshake);
952 first_time_handshake = true;
953 IPAWANDBG("complete, ipa3_qmi_modem_init_fin : %d\n",
954 ipa3_qmi_modem_init_fin);
955
956 if (ipa3_qmi_indication_fin) {
957 IPAWANDBG("send indication to modem (%d)\n",
958 ipa3_qmi_indication_fin);
959 memset(&ind, 0, sizeof(struct
960 ipa_master_driver_init_complt_ind_msg_v01));
961 ind.master_driver_init_status.result =
962 IPA_QMI_RESULT_SUCCESS_V01;
963 rc = qmi_send_ind(ipa3_svc_handle, curr_conn,
964 &ipa3_master_driver_complete_indication_desc,
965 &ind,
966 sizeof(ind));
967 IPAWANDBG("ipa_qmi_service_client good\n");
968 } else {
969 IPAWANERR("not send indication (%d)\n",
970 ipa3_qmi_indication_fin);
971 }
972}
973
974
975static void ipa3_q6_clnt_svc_exit(struct work_struct *work)
976{
977 qmi_handle_destroy(ipa_q6_clnt);
978 ipa_q6_clnt_reset = 1;
979 ipa_q6_clnt = NULL;
980}
981
982
983static int ipa3_q6_clnt_svc_event_notify(struct notifier_block *this,
984 unsigned long code,
985 void *_cmd)
986{
987 IPAWANDBG("event %ld\n", code);
988 switch (code) {
989 case QMI_SERVER_ARRIVE:
990 if (!workqueues_stopped)
991 queue_delayed_work(ipa_clnt_req_workqueue,
992 &ipa3_work_svc_arrive, 0);
993 break;
994 case QMI_SERVER_EXIT:
995 if (!workqueues_stopped)
996 queue_delayed_work(ipa_clnt_req_workqueue,
997 &ipa3_work_svc_exit, 0);
998 break;
999 default:
1000 break;
1001 }
1002 return 0;
1003}
1004
1005
1006static struct notifier_block ipa3_q6_clnt_nb = {
1007 .notifier_call = ipa3_q6_clnt_svc_event_notify,
1008};
1009
1010static void ipa3_qmi_service_init_worker(struct work_struct *work)
1011{
1012 int rc;
1013
1014 /* Initialize QMI-service*/
1015 IPAWANDBG("IPA A7 QMI init OK :>>>>\n");
1016
1017 /* start the QMI msg cache */
1018 ipa3_qmi_ctx = vzalloc(sizeof(*ipa3_qmi_ctx));
1019 if (!ipa3_qmi_ctx) {
1020 IPAWANERR(":kzalloc err.\n");
1021 return;
1022 }
1023 ipa3_qmi_ctx->modem_cfg_emb_pipe_flt =
1024 ipa3_get_modem_cfg_emb_pipe_flt();
1025
1026 ipa_svc_workqueue = create_singlethread_workqueue("ipa_A7_svc");
1027 if (!ipa_svc_workqueue) {
1028 IPAWANERR("Creating ipa_A7_svc workqueue failed\n");
1029 vfree(ipa3_qmi_ctx);
1030 ipa3_qmi_ctx = NULL;
1031 return;
1032 }
1033
1034 ipa3_svc_handle = qmi_handle_create(qmi_ipa_a5_svc_ntfy, NULL);
1035 if (!ipa3_svc_handle) {
1036 IPAWANERR("Creating ipa_A7_svc qmi handle failed\n");
1037 goto destroy_ipa_A7_svc_wq;
1038 }
1039
1040 /*
1041 * Setting the current connection to NULL, as due to a race between
1042 * server and client clean-up in SSR, the disconnect_cb might not
1043 * have necessarily been called
1044 */
1045 curr_conn = NULL;
1046
1047 rc = qmi_svc_register(ipa3_svc_handle, &ipa3_a5_svc_ops_options);
1048 if (rc < 0) {
1049 IPAWANERR("Registering ipa_a5 svc failed %d\n",
1050 rc);
1051 goto destroy_qmi_handle;
1052 }
1053
1054 /* Initialize QMI-client */
1055
1056 ipa_clnt_req_workqueue = create_singlethread_workqueue("clnt_req");
1057 if (!ipa_clnt_req_workqueue) {
1058 IPAWANERR("Creating clnt_req workqueue failed\n");
1059 goto deregister_qmi_srv;
1060 }
1061
1062 ipa_clnt_resp_workqueue = create_singlethread_workqueue("clnt_resp");
1063 if (!ipa_clnt_resp_workqueue) {
1064 IPAWANERR("Creating clnt_resp workqueue failed\n");
1065 goto destroy_clnt_req_wq;
1066 }
1067
1068 rc = qmi_svc_event_notifier_register(IPA_Q6_SERVICE_SVC_ID,
1069 IPA_Q6_SVC_VERS,
1070 IPA_Q6_SERVICE_INS_ID, &ipa3_q6_clnt_nb);
1071 if (rc < 0) {
1072 IPAWANERR("notifier register failed\n");
1073 goto destroy_clnt_resp_wq;
1074 }
1075
1076 /* get Q6 service and start send modem-initial to Q6 */
1077 IPAWANDBG("wait service available\n");
1078 return;
1079
1080destroy_clnt_resp_wq:
1081 destroy_workqueue(ipa_clnt_resp_workqueue);
1082 ipa_clnt_resp_workqueue = NULL;
1083destroy_clnt_req_wq:
1084 destroy_workqueue(ipa_clnt_req_workqueue);
1085 ipa_clnt_req_workqueue = NULL;
1086deregister_qmi_srv:
1087 qmi_svc_unregister(ipa3_svc_handle);
1088destroy_qmi_handle:
1089 qmi_handle_destroy(ipa3_svc_handle);
1090 ipa3_svc_handle = 0;
1091destroy_ipa_A7_svc_wq:
1092 destroy_workqueue(ipa_svc_workqueue);
1093 ipa_svc_workqueue = NULL;
1094 vfree(ipa3_qmi_ctx);
1095 ipa3_qmi_ctx = NULL;
1096}
1097
1098int ipa3_qmi_service_init(uint32_t wan_platform_type)
1099{
1100 ipa_wan_platform = wan_platform_type;
1101 ipa3_qmi_modem_init_fin = false;
1102 ipa3_qmi_indication_fin = false;
1103 ipa3_modem_init_cmplt = false;
1104 workqueues_stopped = false;
1105
1106 if (!ipa3_svc_handle) {
1107 INIT_WORK(&ipa3_qmi_service_init_work,
1108 ipa3_qmi_service_init_worker);
1109 schedule_work(&ipa3_qmi_service_init_work);
1110 }
1111 return 0;
1112}
1113
1114void ipa3_qmi_service_exit(void)
1115{
1116 int ret = 0;
1117
1118 workqueues_stopped = true;
1119
1120 /* qmi-service */
1121 if (ipa3_svc_handle) {
1122 ret = qmi_svc_unregister(ipa3_svc_handle);
1123 if (ret < 0)
1124 IPAWANERR("unregister qmi handle %p failed, ret=%d\n",
1125 ipa3_svc_handle, ret);
1126 }
1127 if (ipa_svc_workqueue) {
1128 flush_workqueue(ipa_svc_workqueue);
1129 destroy_workqueue(ipa_svc_workqueue);
1130 ipa_svc_workqueue = NULL;
1131 }
1132
1133 if (ipa3_svc_handle) {
1134 ret = qmi_handle_destroy(ipa3_svc_handle);
1135 if (ret < 0)
1136 IPAWANERR("Error destroying qmi handle %p, ret=%d\n",
1137 ipa3_svc_handle, ret);
1138 }
1139
1140 /* qmi-client */
1141
1142 /* Unregister from events */
1143 ret = qmi_svc_event_notifier_unregister(IPA_Q6_SERVICE_SVC_ID,
1144 IPA_Q6_SVC_VERS,
1145 IPA_Q6_SERVICE_INS_ID, &ipa3_q6_clnt_nb);
1146 if (ret < 0)
1147 IPAWANERR(
1148 "Error qmi_svc_event_notifier_unregister service %d, ret=%d\n",
1149 IPA_Q6_SERVICE_SVC_ID, ret);
1150
1151 /* Release client handle */
1152 ipa3_q6_clnt_svc_exit(0);
1153
1154 if (ipa_clnt_req_workqueue) {
1155 destroy_workqueue(ipa_clnt_req_workqueue);
1156 ipa_clnt_req_workqueue = NULL;
1157 }
1158 if (ipa_clnt_resp_workqueue) {
1159 destroy_workqueue(ipa_clnt_resp_workqueue);
1160 ipa_clnt_resp_workqueue = NULL;
1161 }
1162
1163 /* clean the QMI msg cache */
1164 if (ipa3_qmi_ctx != NULL) {
1165 vfree(ipa3_qmi_ctx);
1166 ipa3_qmi_ctx = NULL;
1167 }
1168 ipa3_svc_handle = 0;
1169 ipa3_qmi_modem_init_fin = false;
1170 ipa3_qmi_indication_fin = false;
1171 ipa3_modem_init_cmplt = false;
1172}
1173
1174void ipa3_qmi_stop_workqueues(void)
1175{
1176 IPAWANDBG("Stopping all QMI workqueues\n");
1177
1178 /* Stopping all workqueues so new work won't be scheduled */
1179 workqueues_stopped = true;
1180
1181 /* Making sure that the current scheduled work won't be executed */
1182 cancel_delayed_work(&work_recv_msg);
1183 cancel_delayed_work(&ipa3_work_recv_msg_client);
1184 cancel_delayed_work(&ipa3_work_svc_arrive);
1185 cancel_delayed_work(&ipa3_work_svc_exit);
1186}
1187
1188
1189/* voting for bus BW to ipa_rm*/
1190int ipa3_vote_for_bus_bw(uint32_t *bw_mbps)
1191{
1192 struct ipa_rm_perf_profile profile;
1193 int ret;
1194
1195 if (bw_mbps == NULL) {
1196 IPAWANERR("Bus BW is invalid\n");
1197 return -EINVAL;
1198 }
1199
1200 memset(&profile, 0, sizeof(profile));
1201 profile.max_supported_bandwidth_mbps = *bw_mbps;
1202 ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_Q6_PROD,
1203 &profile);
1204 if (ret)
1205 IPAWANERR("Failed to set perf profile to BW %u\n",
1206 profile.max_supported_bandwidth_mbps);
1207 else
1208 IPAWANDBG("Succeeded to set perf profile to BW %u\n",
1209 profile.max_supported_bandwidth_mbps);
1210
1211 return ret;
1212}
1213
1214int ipa3_qmi_get_data_stats(struct ipa_get_data_stats_req_msg_v01 *req,
1215 struct ipa_get_data_stats_resp_msg_v01 *resp)
1216{
1217 struct msg_desc req_desc, resp_desc;
1218 int rc;
1219
1220 req_desc.max_msg_len = QMI_IPA_GET_DATA_STATS_REQ_MAX_MSG_LEN_V01;
1221 req_desc.msg_id = QMI_IPA_GET_DATA_STATS_REQ_V01;
1222 req_desc.ei_array = ipa3_get_data_stats_req_msg_data_v01_ei;
1223
1224 resp_desc.max_msg_len = QMI_IPA_GET_DATA_STATS_RESP_MAX_MSG_LEN_V01;
1225 resp_desc.msg_id = QMI_IPA_GET_DATA_STATS_RESP_V01;
1226 resp_desc.ei_array = ipa3_get_data_stats_resp_msg_data_v01_ei;
1227
1228 IPAWANDBG_LOW("Sending QMI_IPA_GET_DATA_STATS_REQ_V01\n");
1229
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001230 if (unlikely(!ipa_q6_clnt))
1231 return -ETIMEDOUT;
Amir Levy9659e592016-10-27 18:08:27 +03001232 rc = qmi_send_req_wait(ipa_q6_clnt, &req_desc, req,
1233 sizeof(struct ipa_get_data_stats_req_msg_v01),
1234 &resp_desc, resp,
1235 sizeof(struct ipa_get_data_stats_resp_msg_v01),
1236 QMI_SEND_STATS_REQ_TIMEOUT_MS);
1237
1238 IPAWANDBG_LOW("QMI_IPA_GET_DATA_STATS_RESP_V01 received\n");
1239
1240 return ipa3_check_qmi_response(rc,
1241 QMI_IPA_GET_DATA_STATS_REQ_V01, resp->resp.result,
1242 resp->resp.error, "ipa_get_data_stats_resp_msg_v01");
1243}
1244
1245int ipa3_qmi_get_network_stats(struct ipa_get_apn_data_stats_req_msg_v01 *req,
1246 struct ipa_get_apn_data_stats_resp_msg_v01 *resp)
1247{
1248 struct msg_desc req_desc, resp_desc;
1249 int rc;
1250
1251 req_desc.max_msg_len = QMI_IPA_GET_APN_DATA_STATS_REQ_MAX_MSG_LEN_V01;
1252 req_desc.msg_id = QMI_IPA_GET_APN_DATA_STATS_REQ_V01;
1253 req_desc.ei_array = ipa3_get_apn_data_stats_req_msg_data_v01_ei;
1254
1255 resp_desc.max_msg_len = QMI_IPA_GET_APN_DATA_STATS_RESP_MAX_MSG_LEN_V01;
1256 resp_desc.msg_id = QMI_IPA_GET_APN_DATA_STATS_RESP_V01;
1257 resp_desc.ei_array = ipa3_get_apn_data_stats_resp_msg_data_v01_ei;
1258
1259 IPAWANDBG_LOW("Sending QMI_IPA_GET_APN_DATA_STATS_REQ_V01\n");
1260
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001261 if (unlikely(!ipa_q6_clnt))
1262 return -ETIMEDOUT;
Amir Levy9659e592016-10-27 18:08:27 +03001263 rc = qmi_send_req_wait(ipa_q6_clnt, &req_desc, req,
1264 sizeof(struct ipa_get_apn_data_stats_req_msg_v01),
1265 &resp_desc, resp,
1266 sizeof(struct ipa_get_apn_data_stats_resp_msg_v01),
1267 QMI_SEND_STATS_REQ_TIMEOUT_MS);
1268
1269 IPAWANDBG_LOW("QMI_IPA_GET_APN_DATA_STATS_RESP_V01 received\n");
1270
1271 return ipa3_check_qmi_response(rc,
1272 QMI_IPA_GET_APN_DATA_STATS_REQ_V01, resp->resp.result,
1273 resp->resp.error, "ipa_get_apn_data_stats_req_msg_v01");
1274}
1275
1276int ipa3_qmi_set_data_quota(struct ipa_set_data_usage_quota_req_msg_v01 *req)
1277{
1278 struct ipa_set_data_usage_quota_resp_msg_v01 resp;
1279 struct msg_desc req_desc, resp_desc;
1280 int rc;
1281
1282 memset(&resp, 0, sizeof(struct ipa_set_data_usage_quota_resp_msg_v01));
1283
1284 req_desc.max_msg_len = QMI_IPA_SET_DATA_USAGE_QUOTA_REQ_MAX_MSG_LEN_V01;
1285 req_desc.msg_id = QMI_IPA_SET_DATA_USAGE_QUOTA_REQ_V01;
1286 req_desc.ei_array = ipa3_set_data_usage_quota_req_msg_data_v01_ei;
1287
1288 resp_desc.max_msg_len =
1289 QMI_IPA_SET_DATA_USAGE_QUOTA_RESP_MAX_MSG_LEN_V01;
1290 resp_desc.msg_id = QMI_IPA_SET_DATA_USAGE_QUOTA_RESP_V01;
1291 resp_desc.ei_array = ipa3_set_data_usage_quota_resp_msg_data_v01_ei;
1292
1293 IPAWANDBG_LOW("Sending QMI_IPA_SET_DATA_USAGE_QUOTA_REQ_V01\n");
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001294 if (unlikely(!ipa_q6_clnt))
1295 return -ETIMEDOUT;
Amir Levy9659e592016-10-27 18:08:27 +03001296 rc = qmi_send_req_wait(ipa_q6_clnt, &req_desc, req,
1297 sizeof(struct ipa_set_data_usage_quota_req_msg_v01),
1298 &resp_desc, &resp, sizeof(resp),
1299 QMI_SEND_STATS_REQ_TIMEOUT_MS);
1300
1301 IPAWANDBG_LOW("QMI_IPA_SET_DATA_USAGE_QUOTA_RESP_V01 received\n");
1302
1303 return ipa3_check_qmi_response(rc,
1304 QMI_IPA_SET_DATA_USAGE_QUOTA_REQ_V01, resp.resp.result,
1305 resp.resp.error, "ipa_set_data_usage_quota_req_msg_v01");
1306}
1307
1308int ipa3_qmi_stop_data_qouta(void)
1309{
1310 struct ipa_stop_data_usage_quota_req_msg_v01 req;
1311 struct ipa_stop_data_usage_quota_resp_msg_v01 resp;
1312 struct msg_desc req_desc, resp_desc;
1313 int rc;
1314
1315 memset(&req, 0, sizeof(struct ipa_stop_data_usage_quota_req_msg_v01));
1316 memset(&resp, 0, sizeof(struct ipa_stop_data_usage_quota_resp_msg_v01));
1317
1318 req_desc.max_msg_len =
1319 QMI_IPA_STOP_DATA_USAGE_QUOTA_REQ_MAX_MSG_LEN_V01;
1320 req_desc.msg_id = QMI_IPA_STOP_DATA_USAGE_QUOTA_REQ_V01;
1321 req_desc.ei_array = ipa3_stop_data_usage_quota_req_msg_data_v01_ei;
1322
1323 resp_desc.max_msg_len =
1324 QMI_IPA_STOP_DATA_USAGE_QUOTA_RESP_MAX_MSG_LEN_V01;
1325 resp_desc.msg_id = QMI_IPA_STOP_DATA_USAGE_QUOTA_RESP_V01;
1326 resp_desc.ei_array = ipa3_stop_data_usage_quota_resp_msg_data_v01_ei;
1327
1328 IPAWANDBG_LOW("Sending QMI_IPA_STOP_DATA_USAGE_QUOTA_REQ_V01\n");
Gidon Studinski3021a6f2016-11-10 12:48:48 +02001329 if (unlikely(!ipa_q6_clnt))
1330 return -ETIMEDOUT;
Amir Levy9659e592016-10-27 18:08:27 +03001331 rc = qmi_send_req_wait(ipa_q6_clnt, &req_desc, &req, sizeof(req),
1332 &resp_desc, &resp, sizeof(resp),
1333 QMI_SEND_STATS_REQ_TIMEOUT_MS);
1334
1335 IPAWANDBG_LOW("QMI_IPA_STOP_DATA_USAGE_QUOTA_RESP_V01 received\n");
1336
1337 return ipa3_check_qmi_response(rc,
1338 QMI_IPA_STOP_DATA_USAGE_QUOTA_REQ_V01, resp.resp.result,
1339 resp.resp.error, "ipa_stop_data_usage_quota_req_msg_v01");
1340}
1341