Lines Matching +full:modem +full:- +full:init
1 // SPDX-License-Identifier: GPL-2.0
3 /* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
4 * Copyright (C) 2018-2020 Linaro Ltd.
21 * DOC: AP/Modem QMI Handshake
23 * The AP and modem perform a "handshake" at initialization time to ensure
26 * using a service on the modem, and server to service modem requests (and
28 * complete, the AP and modem may begin IPA operation. This occurs
29 * only when the AP IPA driver, modem IPA driver, and IPA microcontroller
32 * The QMI service on the modem expects to receive an INIT_DRIVER request from
33 * the AP, which contains parameters used by the modem during initialization.
34 * The AP sends this request as soon as it is knows the modem side service
35 * is available. The modem responds to this request, and if this response
36 * contains a success result, the AP knows the modem IPA driver is ready.
38 * The modem is responsible for loading firmware on the IPA microcontroller.
39 * This occurs only during the initial modem boot. The modem sends a
42 * ready and remain so (even if the modem reboots) once it has received
46 * on the initial modem boot, but optional (but in practice does occur) on
47 * subsequent boots. The modem expects to receive a final INIT_COMPLETE
50 * and responded to an INDICATION_REGISTER request from the modem.
53 * - Whenever the AP learns the modem has booted and its IPA QMI service
54 * is available, it sends an INIT_DRIVER request to the modem. The
55 * modem supplies a success response when it is ready to operate.
56 * - On the initial boot, the modem sets up the IPA microcontroller, and
58 * - When the modem is ready to receive an INIT_COMPLETE indication from
60 * - On the initial modem boot, everything is ready when:
61 * - AP has received a success response from its INIT_DRIVER request
62 * - AP has responded to a DRIVER_INIT_COMPLETE request
63 * - AP has responded to an INDICATION_REGISTER request from the modem
64 * - AP has sent an INIT_COMPLETE indication to the modem
65 * - On subsequent modem boots, everything is ready when:
66 * - AP has received a success response from its INIT_DRIVER request
67 * - AP has responded to a DRIVER_INIT_COMPLETE request
68 * - The INDICATION_REGISTER request and INIT_COMPLETE indication are
69 * optional for non-initial modem boots, and have no bearing on the
83 /* Send an INIT_COMPLETE indication message to the modem */
87 struct qmi_handle *qmi = &ipa_qmi->server_handle; in ipa_server_init_complete()
88 struct sockaddr_qrtr *sq = &ipa_qmi->modem_sq; in ipa_server_init_complete()
99 dev_err(&ipa->pdev->dev, in ipa_server_init_complete()
100 "error %d sending init complete indication\n", ret); in ipa_server_init_complete()
102 ipa_qmi->indication_sent = true; in ipa_server_init_complete()
108 if (!ipa_qmi->indication_requested) in ipa_qmi_indication()
111 if (ipa_qmi->indication_sent) in ipa_qmi_indication()
119 * the modem is ready, and the microcontroller is ready.
121 * When the modem boots (or reboots), the handshake sequence starts
122 * with the AP sending the modem an INIT_DRIVER request. Within
124 * initial boot, non-zero (true) for a subsequent (SSR) boot.
131 /* We aren't ready until the modem and microcontroller are */ in ipa_qmi_ready()
132 if (!ipa_qmi->modem_ready || !ipa_qmi->uc_ready) in ipa_qmi_ready()
139 if (ipa_qmi->initial_boot) { in ipa_qmi_ready()
140 if (!ipa_qmi->indication_sent) in ipa_qmi_ready()
143 /* The initial modem boot completed successfully */ in ipa_qmi_ready()
144 ipa_qmi->initial_boot = false; in ipa_qmi_ready()
151 dev_err(&ipa->pdev->dev, "error %d starting modem\n", ret); in ipa_qmi_ready()
154 /* All QMI clients from the modem node are gone (modem shut down or crashed). */
161 /* The modem client and server go away at the same time */ in ipa_server_bye()
162 memset(&ipa_qmi->modem_sq, 0, sizeof(ipa_qmi->modem_sq)); in ipa_server_bye()
164 /* initial_boot doesn't change when modem reboots */ in ipa_server_bye()
165 /* uc_ready doesn't change when modem reboots */ in ipa_server_bye()
166 ipa_qmi->modem_ready = false; in ipa_server_bye()
167 ipa_qmi->indication_requested = false; in ipa_server_bye()
168 ipa_qmi->indication_sent = false; in ipa_server_bye()
176 * modem. This informs the AP that the modem is now ready to receive the
199 ipa_qmi->indication_requested = true; in ipa_server_indication_register()
202 dev_err(&ipa->pdev->dev, in ipa_server_indication_register()
207 /* Respond to a DRIVER_INIT_COMPLETE request message from the modem. */
228 ipa_qmi->uc_ready = true; in ipa_server_driver_init_complete()
231 dev_err(&ipa->pdev->dev, in ipa_server_driver_init_complete()
232 "error %d sending init complete response\n", ret); in ipa_server_driver_init_complete()
236 /* The server handles two request message types sent by the modem. */
255 /* Handle an INIT_DRIVER response message from the modem. */
260 txn->result = 0; /* IPA_QMI_INIT_DRIVER request was successful */ in ipa_client_init_driver()
261 complete(&txn->completion); in ipa_client_init_driver()
264 /* The client handles one response message type sent by the modem. */
276 /* Return a pointer to an init modem driver request structure, which contains
277 * configuration parameters for the modem. The modem may be started multiple
292 req.skip_uc_load = ipa->uc_loaded ? 1 : 0; in init_modem_driver_req()
301 mem = &ipa->mem[IPA_MEM_MODEM_HEADER]; in init_modem_driver_req()
302 if (mem->size) { in init_modem_driver_req()
304 req.hdr_tbl_info.start = ipa->mem_offset + mem->offset; in init_modem_driver_req()
305 req.hdr_tbl_info.end = req.hdr_tbl_info.start + mem->size - 1; in init_modem_driver_req()
308 mem = &ipa->mem[IPA_MEM_V4_ROUTE]; in init_modem_driver_req()
310 req.v4_route_tbl_info.start = ipa->mem_offset + mem->offset; in init_modem_driver_req()
311 req.v4_route_tbl_info.count = mem->size / IPA_TABLE_ENTRY_SIZE; in init_modem_driver_req()
313 mem = &ipa->mem[IPA_MEM_V6_ROUTE]; in init_modem_driver_req()
315 req.v6_route_tbl_info.start = ipa->mem_offset + mem->offset; in init_modem_driver_req()
316 req.v6_route_tbl_info.count = mem->size / IPA_TABLE_ENTRY_SIZE; in init_modem_driver_req()
318 mem = &ipa->mem[IPA_MEM_V4_FILTER]; in init_modem_driver_req()
320 req.v4_filter_tbl_start = ipa->mem_offset + mem->offset; in init_modem_driver_req()
322 mem = &ipa->mem[IPA_MEM_V6_FILTER]; in init_modem_driver_req()
324 req.v6_filter_tbl_start = ipa->mem_offset + mem->offset; in init_modem_driver_req()
326 mem = &ipa->mem[IPA_MEM_MODEM]; in init_modem_driver_req()
327 if (mem->size) { in init_modem_driver_req()
329 req.modem_mem_info.start = ipa->mem_offset + mem->offset; in init_modem_driver_req()
330 req.modem_mem_info.size = mem->size; in init_modem_driver_req()
335 ipa->name_map[IPA_ENDPOINT_AP_MODEM_RX]->endpoint_id; in init_modem_driver_req()
339 mem = &ipa->mem[IPA_MEM_MODEM_PROC_CTX]; in init_modem_driver_req()
340 if (mem->size) { in init_modem_driver_req()
343 ipa->mem_offset + mem->offset; in init_modem_driver_req()
345 req.hdr_proc_ctx_tbl_info.start + mem->size - 1; in init_modem_driver_req()
350 mem = &ipa->mem[IPA_MEM_V4_ROUTE_HASHED]; in init_modem_driver_req()
351 if (mem->size) { in init_modem_driver_req()
354 ipa->mem_offset + mem->offset; in init_modem_driver_req()
356 mem->size / IPA_TABLE_ENTRY_SIZE; in init_modem_driver_req()
359 mem = &ipa->mem[IPA_MEM_V6_ROUTE_HASHED]; in init_modem_driver_req()
360 if (mem->size) { in init_modem_driver_req()
363 ipa->mem_offset + mem->offset; in init_modem_driver_req()
365 mem->size / IPA_TABLE_ENTRY_SIZE; in init_modem_driver_req()
368 mem = &ipa->mem[IPA_MEM_V4_FILTER_HASHED]; in init_modem_driver_req()
369 if (mem->size) { in init_modem_driver_req()
371 req.v4_hash_filter_tbl_start = ipa->mem_offset + mem->offset; in init_modem_driver_req()
374 mem = &ipa->mem[IPA_MEM_V6_FILTER_HASHED]; in init_modem_driver_req()
375 if (mem->size) { in init_modem_driver_req()
377 req.v6_hash_filter_tbl_start = ipa->mem_offset + mem->offset; in init_modem_driver_req()
382 if (ipa->version != IPA_VERSION_3_5_1) { in init_modem_driver_req()
383 mem = &ipa->mem[IPA_MEM_STATS_QUOTA]; in init_modem_driver_req()
384 if (mem->size) { in init_modem_driver_req()
387 ipa->mem_offset + mem->offset; in init_modem_driver_req()
389 req.hw_stats_quota_size = ipa->mem_offset + mem->size; in init_modem_driver_req()
392 mem = &ipa->mem[IPA_MEM_STATS_DROP]; in init_modem_driver_req()
393 if (mem->size) { in init_modem_driver_req()
396 ipa->mem_offset + mem->offset; in init_modem_driver_req()
398 req.hw_stats_drop_size = ipa->mem_offset + mem->size; in init_modem_driver_req()
405 /* Send an INIT_DRIVER request to the modem, and wait for it to complete. */
418 qmi = &ipa_qmi->client_handle, in ipa_client_init_driver_work()
421 dev = &ipa->pdev->dev; in ipa_client_init_driver_work()
425 dev_err(dev, "error %d preparing init driver request\n", ret); in ipa_client_init_driver_work()
431 ret = qmi_send_request(qmi, &ipa_qmi->modem_sq, &txn, in ipa_client_init_driver_work()
435 dev_err(dev, "error %d sending init driver request\n", ret); in ipa_client_init_driver_work()
437 dev_err(dev, "error %d awaiting init driver response\n", ret); in ipa_client_init_driver_work()
440 ipa_qmi->modem_ready = true; in ipa_client_init_driver_work()
448 /* The modem server is now available. We will send an INIT_DRIVER request
449 * to the modem, but can't wait for it to complete in this callback thread.
459 ipa_qmi->modem_sq.sq_family = AF_QIPCRTR; in ipa_client_new_server()
460 ipa_qmi->modem_sq.sq_node = svc->node; in ipa_client_new_server()
461 ipa_qmi->modem_sq.sq_port = svc->port; in ipa_client_new_server()
463 schedule_work(&ipa_qmi->init_driver_work); in ipa_client_new_server()
473 * the modem has shut down, in which case this function will be called
478 struct ipa_qmi *ipa_qmi = &ipa->qmi; in ipa_qmi_setup()
481 ipa_qmi->initial_boot = true; in ipa_qmi_setup()
484 * request on the first modem boot. It also receives the in ipa_qmi_setup()
489 ret = qmi_handle_init(&ipa_qmi->server_handle, in ipa_qmi_setup()
495 ret = qmi_add_server(&ipa_qmi->server_handle, IPA_HOST_SERVICE_SVC_ID, in ipa_qmi_setup()
501 * to the modem, and receiving its response message. in ipa_qmi_setup()
503 ret = qmi_handle_init(&ipa_qmi->client_handle, in ipa_qmi_setup()
510 INIT_WORK(&ipa_qmi->init_driver_work, ipa_client_init_driver_work); in ipa_qmi_setup()
512 ret = qmi_add_lookup(&ipa_qmi->client_handle, IPA_MODEM_SERVICE_SVC_ID, in ipa_qmi_setup()
521 qmi_handle_release(&ipa_qmi->client_handle); in ipa_qmi_setup()
522 memset(&ipa_qmi->client_handle, 0, sizeof(ipa_qmi->client_handle)); in ipa_qmi_setup()
525 qmi_handle_release(&ipa_qmi->server_handle); in ipa_qmi_setup()
526 memset(&ipa_qmi->server_handle, 0, sizeof(ipa_qmi->server_handle)); in ipa_qmi_setup()
533 cancel_work_sync(&ipa->qmi.init_driver_work); in ipa_qmi_teardown()
535 qmi_handle_release(&ipa->qmi.client_handle); in ipa_qmi_teardown()
536 memset(&ipa->qmi.client_handle, 0, sizeof(ipa->qmi.client_handle)); in ipa_qmi_teardown()
538 qmi_handle_release(&ipa->qmi.server_handle); in ipa_qmi_teardown()
539 memset(&ipa->qmi.server_handle, 0, sizeof(ipa->qmi.server_handle)); in ipa_qmi_teardown()