0001
0002
0003
0004
0005
0006
0007 #include <linux/types.h>
0008 #include <linux/string.h>
0009 #include <linux/slab.h>
0010 #include <linux/qrtr.h>
0011 #include <linux/soc/qcom/qmi.h>
0012
0013 #include "ipa.h"
0014 #include "ipa_endpoint.h"
0015 #include "ipa_mem.h"
0016 #include "ipa_table.h"
0017 #include "ipa_modem.h"
0018 #include "ipa_qmi_msg.h"
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073 #define IPA_HOST_SERVICE_SVC_ID 0x31
0074 #define IPA_HOST_SVC_VERS 1
0075 #define IPA_HOST_SERVICE_INS_ID 1
0076
0077 #define IPA_MODEM_SERVICE_SVC_ID 0x31
0078 #define IPA_MODEM_SERVICE_INS_ID 2
0079 #define IPA_MODEM_SVC_VERS 1
0080
0081 #define QMI_INIT_DRIVER_TIMEOUT 60000
0082
0083
0084 static void ipa_server_init_complete(struct ipa_qmi *ipa_qmi)
0085 {
0086 struct ipa *ipa = container_of(ipa_qmi, struct ipa, qmi);
0087 struct qmi_handle *qmi = &ipa_qmi->server_handle;
0088 struct sockaddr_qrtr *sq = &ipa_qmi->modem_sq;
0089 struct ipa_init_complete_ind ind = { };
0090 int ret;
0091
0092 ind.status.result = QMI_RESULT_SUCCESS_V01;
0093 ind.status.error = QMI_ERR_NONE_V01;
0094
0095 ret = qmi_send_indication(qmi, sq, IPA_QMI_INIT_COMPLETE,
0096 IPA_QMI_INIT_COMPLETE_IND_SZ,
0097 ipa_init_complete_ind_ei, &ind);
0098 if (ret)
0099 dev_err(&ipa->pdev->dev,
0100 "error %d sending init complete indication\n", ret);
0101 else
0102 ipa_qmi->indication_sent = true;
0103 }
0104
0105
0106 static void ipa_qmi_indication(struct ipa_qmi *ipa_qmi)
0107 {
0108 if (!ipa_qmi->indication_requested)
0109 return;
0110
0111 if (ipa_qmi->indication_sent)
0112 return;
0113
0114 ipa_server_init_complete(ipa_qmi);
0115 }
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126 static void ipa_qmi_ready(struct ipa_qmi *ipa_qmi)
0127 {
0128 struct ipa *ipa;
0129 int ret;
0130
0131
0132 if (!ipa_qmi->modem_ready || !ipa_qmi->uc_ready)
0133 return;
0134
0135
0136 ipa_qmi_indication(ipa_qmi);
0137
0138
0139 if (ipa_qmi->initial_boot) {
0140 if (!ipa_qmi->indication_sent)
0141 return;
0142
0143
0144 ipa_qmi->initial_boot = false;
0145 }
0146
0147
0148 ipa = container_of(ipa_qmi, struct ipa, qmi);
0149 ret = ipa_modem_start(ipa);
0150 if (ret)
0151 dev_err(&ipa->pdev->dev, "error %d starting modem\n", ret);
0152 }
0153
0154
0155 static void ipa_server_bye(struct qmi_handle *qmi, unsigned int node)
0156 {
0157 struct ipa_qmi *ipa_qmi;
0158
0159 ipa_qmi = container_of(qmi, struct ipa_qmi, server_handle);
0160
0161
0162 memset(&ipa_qmi->modem_sq, 0, sizeof(ipa_qmi->modem_sq));
0163
0164
0165
0166 ipa_qmi->modem_ready = false;
0167 ipa_qmi->indication_requested = false;
0168 ipa_qmi->indication_sent = false;
0169 }
0170
0171 static const struct qmi_ops ipa_server_ops = {
0172 .bye = ipa_server_bye,
0173 };
0174
0175
0176
0177
0178
0179 static void ipa_server_indication_register(struct qmi_handle *qmi,
0180 struct sockaddr_qrtr *sq,
0181 struct qmi_txn *txn,
0182 const void *decoded)
0183 {
0184 struct ipa_indication_register_rsp rsp = { };
0185 struct ipa_qmi *ipa_qmi;
0186 struct ipa *ipa;
0187 int ret;
0188
0189 ipa_qmi = container_of(qmi, struct ipa_qmi, server_handle);
0190 ipa = container_of(ipa_qmi, struct ipa, qmi);
0191
0192 rsp.rsp.result = QMI_RESULT_SUCCESS_V01;
0193 rsp.rsp.error = QMI_ERR_NONE_V01;
0194
0195 ret = qmi_send_response(qmi, sq, txn, IPA_QMI_INDICATION_REGISTER,
0196 IPA_QMI_INDICATION_REGISTER_RSP_SZ,
0197 ipa_indication_register_rsp_ei, &rsp);
0198 if (!ret) {
0199 ipa_qmi->indication_requested = true;
0200 ipa_qmi_ready(ipa_qmi);
0201 } else {
0202 dev_err(&ipa->pdev->dev,
0203 "error %d sending register indication response\n", ret);
0204 }
0205 }
0206
0207
0208 static void ipa_server_driver_init_complete(struct qmi_handle *qmi,
0209 struct sockaddr_qrtr *sq,
0210 struct qmi_txn *txn,
0211 const void *decoded)
0212 {
0213 struct ipa_driver_init_complete_rsp rsp = { };
0214 struct ipa_qmi *ipa_qmi;
0215 struct ipa *ipa;
0216 int ret;
0217
0218 ipa_qmi = container_of(qmi, struct ipa_qmi, server_handle);
0219 ipa = container_of(ipa_qmi, struct ipa, qmi);
0220
0221 rsp.rsp.result = QMI_RESULT_SUCCESS_V01;
0222 rsp.rsp.error = QMI_ERR_NONE_V01;
0223
0224 ret = qmi_send_response(qmi, sq, txn, IPA_QMI_DRIVER_INIT_COMPLETE,
0225 IPA_QMI_DRIVER_INIT_COMPLETE_RSP_SZ,
0226 ipa_driver_init_complete_rsp_ei, &rsp);
0227 if (!ret) {
0228 ipa_qmi->uc_ready = true;
0229 ipa_qmi_ready(ipa_qmi);
0230 } else {
0231 dev_err(&ipa->pdev->dev,
0232 "error %d sending init complete response\n", ret);
0233 }
0234 }
0235
0236
0237 static const struct qmi_msg_handler ipa_server_msg_handlers[] = {
0238 {
0239 .type = QMI_REQUEST,
0240 .msg_id = IPA_QMI_INDICATION_REGISTER,
0241 .ei = ipa_indication_register_req_ei,
0242 .decoded_size = IPA_QMI_INDICATION_REGISTER_REQ_SZ,
0243 .fn = ipa_server_indication_register,
0244 },
0245 {
0246 .type = QMI_REQUEST,
0247 .msg_id = IPA_QMI_DRIVER_INIT_COMPLETE,
0248 .ei = ipa_driver_init_complete_req_ei,
0249 .decoded_size = IPA_QMI_DRIVER_INIT_COMPLETE_REQ_SZ,
0250 .fn = ipa_server_driver_init_complete,
0251 },
0252 { },
0253 };
0254
0255
0256 static void ipa_client_init_driver(struct qmi_handle *qmi,
0257 struct sockaddr_qrtr *sq,
0258 struct qmi_txn *txn, const void *decoded)
0259 {
0260 txn->result = 0;
0261 complete(&txn->completion);
0262 }
0263
0264
0265 static const struct qmi_msg_handler ipa_client_msg_handlers[] = {
0266 {
0267 .type = QMI_RESPONSE,
0268 .msg_id = IPA_QMI_INIT_DRIVER,
0269 .ei = ipa_init_modem_driver_rsp_ei,
0270 .decoded_size = IPA_QMI_INIT_DRIVER_RSP_SZ,
0271 .fn = ipa_client_init_driver,
0272 },
0273 { },
0274 };
0275
0276
0277
0278
0279
0280
0281
0282
0283 static const struct ipa_init_modem_driver_req *
0284 init_modem_driver_req(struct ipa_qmi *ipa_qmi)
0285 {
0286 struct ipa *ipa = container_of(ipa_qmi, struct ipa, qmi);
0287 static struct ipa_init_modem_driver_req req;
0288 const struct ipa_mem *mem;
0289
0290
0291 req.skip_uc_load_valid = 1;
0292 req.skip_uc_load = ipa->uc_loaded ? 1 : 0;
0293
0294
0295 if (req.platform_type_valid)
0296 return &req;
0297
0298 req.platform_type_valid = 1;
0299 req.platform_type = IPA_QMI_PLATFORM_TYPE_MSM_ANDROID;
0300
0301 mem = ipa_mem_find(ipa, IPA_MEM_MODEM_HEADER);
0302 if (mem->size) {
0303 req.hdr_tbl_info_valid = 1;
0304 req.hdr_tbl_info.start = ipa->mem_offset + mem->offset;
0305 req.hdr_tbl_info.end = req.hdr_tbl_info.start + mem->size - 1;
0306 }
0307
0308 mem = ipa_mem_find(ipa, IPA_MEM_V4_ROUTE);
0309 req.v4_route_tbl_info_valid = 1;
0310 req.v4_route_tbl_info.start = ipa->mem_offset + mem->offset;
0311 req.v4_route_tbl_info.end = IPA_ROUTE_MODEM_COUNT - 1;
0312
0313 mem = ipa_mem_find(ipa, IPA_MEM_V6_ROUTE);
0314 req.v6_route_tbl_info_valid = 1;
0315 req.v6_route_tbl_info.start = ipa->mem_offset + mem->offset;
0316 req.v6_route_tbl_info.end = IPA_ROUTE_MODEM_COUNT - 1;
0317
0318 mem = ipa_mem_find(ipa, IPA_MEM_V4_FILTER);
0319 req.v4_filter_tbl_start_valid = 1;
0320 req.v4_filter_tbl_start = ipa->mem_offset + mem->offset;
0321
0322 mem = ipa_mem_find(ipa, IPA_MEM_V6_FILTER);
0323 req.v6_filter_tbl_start_valid = 1;
0324 req.v6_filter_tbl_start = ipa->mem_offset + mem->offset;
0325
0326 mem = ipa_mem_find(ipa, IPA_MEM_MODEM);
0327 if (mem->size) {
0328 req.modem_mem_info_valid = 1;
0329 req.modem_mem_info.start = ipa->mem_offset + mem->offset;
0330 req.modem_mem_info.size = mem->size;
0331 }
0332
0333 req.ctrl_comm_dest_end_pt_valid = 1;
0334 req.ctrl_comm_dest_end_pt =
0335 ipa->name_map[IPA_ENDPOINT_AP_MODEM_RX]->endpoint_id;
0336
0337
0338
0339 mem = ipa_mem_find(ipa, IPA_MEM_MODEM_PROC_CTX);
0340 if (mem->size) {
0341 req.hdr_proc_ctx_tbl_info_valid = 1;
0342 req.hdr_proc_ctx_tbl_info.start =
0343 ipa->mem_offset + mem->offset;
0344 req.hdr_proc_ctx_tbl_info.end =
0345 req.hdr_proc_ctx_tbl_info.start + mem->size - 1;
0346 }
0347
0348
0349
0350 mem = ipa_mem_find(ipa, IPA_MEM_V4_ROUTE_HASHED);
0351 if (mem->size) {
0352 req.v4_hash_route_tbl_info_valid = 1;
0353 req.v4_hash_route_tbl_info.start =
0354 ipa->mem_offset + mem->offset;
0355 req.v4_hash_route_tbl_info.end = IPA_ROUTE_MODEM_COUNT - 1;
0356 }
0357
0358 mem = ipa_mem_find(ipa, IPA_MEM_V6_ROUTE_HASHED);
0359 if (mem->size) {
0360 req.v6_hash_route_tbl_info_valid = 1;
0361 req.v6_hash_route_tbl_info.start =
0362 ipa->mem_offset + mem->offset;
0363 req.v6_hash_route_tbl_info.end = IPA_ROUTE_MODEM_COUNT - 1;
0364 }
0365
0366 mem = ipa_mem_find(ipa, IPA_MEM_V4_FILTER_HASHED);
0367 if (mem->size) {
0368 req.v4_hash_filter_tbl_start_valid = 1;
0369 req.v4_hash_filter_tbl_start = ipa->mem_offset + mem->offset;
0370 }
0371
0372 mem = ipa_mem_find(ipa, IPA_MEM_V6_FILTER_HASHED);
0373 if (mem->size) {
0374 req.v6_hash_filter_tbl_start_valid = 1;
0375 req.v6_hash_filter_tbl_start = ipa->mem_offset + mem->offset;
0376 }
0377
0378
0379 if (ipa->version >= IPA_VERSION_4_0) {
0380 mem = ipa_mem_find(ipa, IPA_MEM_STATS_QUOTA_MODEM);
0381 if (mem->size) {
0382 req.hw_stats_quota_base_addr_valid = 1;
0383 req.hw_stats_quota_base_addr =
0384 ipa->mem_offset + mem->offset;
0385 req.hw_stats_quota_size_valid = 1;
0386 req.hw_stats_quota_size = ipa->mem_offset + mem->size;
0387 }
0388
0389
0390 mem = ipa_mem_find(ipa, IPA_MEM_STATS_DROP);
0391 if (mem && mem->size) {
0392 req.hw_stats_drop_base_addr_valid = 1;
0393 req.hw_stats_drop_base_addr =
0394 ipa->mem_offset + mem->offset;
0395 req.hw_stats_drop_size_valid = 1;
0396 req.hw_stats_drop_size = ipa->mem_offset + mem->size;
0397 }
0398 }
0399
0400 return &req;
0401 }
0402
0403
0404 static void ipa_client_init_driver_work(struct work_struct *work)
0405 {
0406 unsigned long timeout = msecs_to_jiffies(QMI_INIT_DRIVER_TIMEOUT);
0407 const struct ipa_init_modem_driver_req *req;
0408 struct ipa_qmi *ipa_qmi;
0409 struct qmi_handle *qmi;
0410 struct qmi_txn txn;
0411 struct device *dev;
0412 struct ipa *ipa;
0413 int ret;
0414
0415 ipa_qmi = container_of(work, struct ipa_qmi, init_driver_work);
0416 qmi = &ipa_qmi->client_handle;
0417
0418 ipa = container_of(ipa_qmi, struct ipa, qmi);
0419 dev = &ipa->pdev->dev;
0420
0421 ret = qmi_txn_init(qmi, &txn, NULL, NULL);
0422 if (ret < 0) {
0423 dev_err(dev, "error %d preparing init driver request\n", ret);
0424 return;
0425 }
0426
0427
0428 req = init_modem_driver_req(ipa_qmi);
0429 ret = qmi_send_request(qmi, &ipa_qmi->modem_sq, &txn,
0430 IPA_QMI_INIT_DRIVER, IPA_QMI_INIT_DRIVER_REQ_SZ,
0431 ipa_init_modem_driver_req_ei, req);
0432 if (ret)
0433 dev_err(dev, "error %d sending init driver request\n", ret);
0434 else if ((ret = qmi_txn_wait(&txn, timeout)))
0435 dev_err(dev, "error %d awaiting init driver response\n", ret);
0436
0437 if (!ret) {
0438 ipa_qmi->modem_ready = true;
0439 ipa_qmi_ready(ipa_qmi);
0440 } else {
0441
0442 qmi_txn_cancel(&txn);
0443 }
0444 }
0445
0446
0447
0448
0449
0450 static int
0451 ipa_client_new_server(struct qmi_handle *qmi, struct qmi_service *svc)
0452 {
0453 struct ipa_qmi *ipa_qmi;
0454
0455 ipa_qmi = container_of(qmi, struct ipa_qmi, client_handle);
0456
0457 ipa_qmi->modem_sq.sq_family = AF_QIPCRTR;
0458 ipa_qmi->modem_sq.sq_node = svc->node;
0459 ipa_qmi->modem_sq.sq_port = svc->port;
0460
0461 schedule_work(&ipa_qmi->init_driver_work);
0462
0463 return 0;
0464 }
0465
0466 static const struct qmi_ops ipa_client_ops = {
0467 .new_server = ipa_client_new_server,
0468 };
0469
0470
0471 int ipa_qmi_setup(struct ipa *ipa)
0472 {
0473 struct ipa_qmi *ipa_qmi = &ipa->qmi;
0474 int ret;
0475
0476 ipa_qmi->initial_boot = true;
0477
0478
0479
0480
0481
0482
0483
0484 ret = qmi_handle_init(&ipa_qmi->server_handle,
0485 IPA_QMI_SERVER_MAX_RCV_SZ, &ipa_server_ops,
0486 ipa_server_msg_handlers);
0487 if (ret)
0488 return ret;
0489
0490 ret = qmi_add_server(&ipa_qmi->server_handle, IPA_HOST_SERVICE_SVC_ID,
0491 IPA_HOST_SVC_VERS, IPA_HOST_SERVICE_INS_ID);
0492 if (ret)
0493 goto err_server_handle_release;
0494
0495
0496
0497
0498 ret = qmi_handle_init(&ipa_qmi->client_handle,
0499 IPA_QMI_CLIENT_MAX_RCV_SZ, &ipa_client_ops,
0500 ipa_client_msg_handlers);
0501 if (ret)
0502 goto err_server_handle_release;
0503
0504
0505 INIT_WORK(&ipa_qmi->init_driver_work, ipa_client_init_driver_work);
0506
0507 ret = qmi_add_lookup(&ipa_qmi->client_handle, IPA_MODEM_SERVICE_SVC_ID,
0508 IPA_MODEM_SVC_VERS, IPA_MODEM_SERVICE_INS_ID);
0509 if (ret)
0510 goto err_client_handle_release;
0511
0512 return 0;
0513
0514 err_client_handle_release:
0515
0516 qmi_handle_release(&ipa_qmi->client_handle);
0517 memset(&ipa_qmi->client_handle, 0, sizeof(ipa_qmi->client_handle));
0518 err_server_handle_release:
0519
0520 qmi_handle_release(&ipa_qmi->server_handle);
0521 memset(&ipa_qmi->server_handle, 0, sizeof(ipa_qmi->server_handle));
0522
0523 return ret;
0524 }
0525
0526
0527 void ipa_qmi_teardown(struct ipa *ipa)
0528 {
0529 cancel_work_sync(&ipa->qmi.init_driver_work);
0530
0531 qmi_handle_release(&ipa->qmi.client_handle);
0532 memset(&ipa->qmi.client_handle, 0, sizeof(ipa->qmi.client_handle));
0533
0534 qmi_handle_release(&ipa->qmi.server_handle);
0535 memset(&ipa->qmi.server_handle, 0, sizeof(ipa->qmi.server_handle));
0536 }