Lines Matching +full:ipa +full:- +full:ap +full:- +full:to +full:- +full:modem

1 // SPDX-License-Identifier: GPL-2.0
3 /* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
4 * Copyright (C) 2018-2024 Linaro Ltd.
11 #include "ipa.h"
17 * DOC: AP/Modem QMI Handshake
19 * The AP and modem perform a "handshake" at initialization time to ensure
20 * both sides know when everything is ready to begin operating. The AP
22 * using a service on the modem, and server to service modem requests (and
23 * to supply an indication message from the AP). Once the handshake is
24 * complete, the AP and modem may begin IPA operation. This occurs
25 * only when the AP IPA driver, modem IPA driver, and IPA microcontroller
28 * The QMI service on the modem expects to receive an INIT_DRIVER request from
29 * the AP, which contains parameters used by the modem during initialization.
30 * The AP sends this request as soon as it is knows the modem side service
31 * is available. The modem responds to this request, and if this response
32 * contains a success result, the AP knows the modem IPA driver is ready.
34 * The modem is responsible for loading firmware on the IPA microcontroller.
35 * This occurs only during the initial modem boot. The modem sends a
36 * separate DRIVER_INIT_COMPLETE request to the AP to report that the
37 * microcontroller is ready. The AP may assume the microcontroller is
38 * ready and remain so (even if the modem reboots) once it has received
39 * and responded to this request.
42 * on the initial modem boot, but optional (but in practice does occur) on
43 * subsequent boots. The modem expects to receive a final INIT_COMPLETE
44 * indication message from the AP when it is about to begin its normal
45 * operation. The AP will only send this message after it has received
46 * and responded to an INDICATION_REGISTER request from the modem.
49 * - Whenever the AP learns the modem has booted and its IPA QMI service
50 * is available, it sends an INIT_DRIVER request to the modem. The
51 * modem supplies a success response when it is ready to operate.
52 * - On the initial boot, the modem sets up the IPA microcontroller, and
53 * sends a DRIVER_INIT_COMPLETE request to the AP when this is done.
54 * - When the modem is ready to receive an INIT_COMPLETE indication from
55 * the AP, it sends an INDICATION_REGISTER request to the AP.
56 * - On the initial modem boot, everything is ready when:
57 * - AP has received a success response from its INIT_DRIVER request
58 * - AP has responded to a DRIVER_INIT_COMPLETE request
59 * - AP has responded to an INDICATION_REGISTER request from the modem
60 * - AP has sent an INIT_COMPLETE indication to the modem
61 * - On subsequent modem boots, everything is ready when:
62 * - AP has received a success response from its INIT_DRIVER request
63 * - AP has responded to a DRIVER_INIT_COMPLETE request
64 * - The INDICATION_REGISTER request and INIT_COMPLETE indication are
65 * optional for non-initial modem boots, and have no bearing on the
79 /* Send an INIT_COMPLETE indication message to the modem */
82 struct ipa *ipa = container_of(ipa_qmi, struct ipa, qmi); in ipa_server_init_complete() local
83 struct qmi_handle *qmi = &ipa_qmi->server_handle; in ipa_server_init_complete()
84 struct sockaddr_qrtr *sq = &ipa_qmi->modem_sq; in ipa_server_init_complete()
95 dev_err(ipa->dev, in ipa_server_init_complete()
98 ipa_qmi->indication_sent = true; in ipa_server_init_complete()
104 if (!ipa_qmi->indication_requested) in ipa_qmi_indication()
107 if (ipa_qmi->indication_sent) in ipa_qmi_indication()
113 /* Determine whether everything is ready to start normal operation.
114 * We know everything (else) is ready when we know the IPA driver on
115 * the modem is ready, and the microcontroller is ready.
117 * When the modem boots (or reboots), the handshake sequence starts
118 * with the AP sending the modem an INIT_DRIVER request. Within
120 * initial boot, non-zero (true) for a subsequent (SSR) boot.
124 struct ipa *ipa; in ipa_qmi_ready() local
127 /* We aren't ready until the modem and microcontroller are */ in ipa_qmi_ready()
128 if (!ipa_qmi->modem_ready || !ipa_qmi->uc_ready) in ipa_qmi_ready()
134 /* The initial boot requires us to send the indication. */ in ipa_qmi_ready()
135 if (ipa_qmi->initial_boot) { in ipa_qmi_ready()
136 if (!ipa_qmi->indication_sent) in ipa_qmi_ready()
139 /* The initial modem boot completed successfully */ in ipa_qmi_ready()
140 ipa_qmi->initial_boot = false; in ipa_qmi_ready()
144 ipa = container_of(ipa_qmi, struct ipa, qmi); in ipa_qmi_ready()
145 ret = ipa_modem_start(ipa); in ipa_qmi_ready()
147 dev_err(ipa->dev, "error %d starting modem\n", ret); in ipa_qmi_ready()
150 /* All QMI clients from the modem node are gone (modem shut down or crashed). */
157 /* The modem client and server go away at the same time */ in ipa_server_bye()
158 memset(&ipa_qmi->modem_sq, 0, sizeof(ipa_qmi->modem_sq)); in ipa_server_bye()
160 /* initial_boot doesn't change when modem reboots */ in ipa_server_bye()
161 /* uc_ready doesn't change when modem reboots */ in ipa_server_bye()
162 ipa_qmi->modem_ready = false; in ipa_server_bye()
163 ipa_qmi->indication_requested = false; in ipa_server_bye()
164 ipa_qmi->indication_sent = false; in ipa_server_bye()
171 /* Callback function to handle an INDICATION_REGISTER request message from the
172 * modem. This informs the AP that the modem is now ready to receive the
182 struct ipa *ipa; in ipa_server_indication_register() local
186 ipa = container_of(ipa_qmi, struct ipa, qmi); in ipa_server_indication_register()
195 ipa_qmi->indication_requested = true; in ipa_server_indication_register()
198 dev_err(ipa->dev, in ipa_server_indication_register()
203 /* Respond to a DRIVER_INIT_COMPLETE request message from the modem. */
211 struct ipa *ipa; in ipa_server_driver_init_complete() local
215 ipa = container_of(ipa_qmi, struct ipa, qmi); in ipa_server_driver_init_complete()
224 ipa_qmi->uc_ready = true; in ipa_server_driver_init_complete()
227 dev_err(ipa->dev, in ipa_server_driver_init_complete()
232 /* The server handles two request message types sent by the modem. */
251 /* Handle an INIT_DRIVER response message from the modem. */
256 txn->result = 0; /* IPA_QMI_INIT_DRIVER request was successful */ in ipa_client_init_driver()
257 complete(&txn->completion); in ipa_client_init_driver()
260 /* The client handles one response message type sent by the modem. */
272 /* Return a pointer to an init modem driver request structure, which contains
273 * configuration parameters for the modem. The modem may be started multiple
282 struct ipa *ipa = container_of(ipa_qmi, struct ipa, qmi); in init_modem_driver_req() local
283 u32 modem_route_count = ipa->modem_route_count; in init_modem_driver_req()
289 req.skip_uc_load = ipa->uc_loaded ? 1 : 0; in init_modem_driver_req()
291 /* We only have to initialize most of it once */ in init_modem_driver_req()
298 mem = ipa_mem_find(ipa, IPA_MEM_MODEM_HEADER); in init_modem_driver_req()
299 if (mem->size) { in init_modem_driver_req()
301 req.hdr_tbl_info.start = ipa->mem_offset + mem->offset; in init_modem_driver_req()
302 req.hdr_tbl_info.end = req.hdr_tbl_info.start + mem->size - 1; in init_modem_driver_req()
305 mem = ipa_mem_find(ipa, IPA_MEM_V4_ROUTE); in init_modem_driver_req()
307 req.v4_route_tbl_info.start = ipa->mem_offset + mem->offset; in init_modem_driver_req()
308 req.v4_route_tbl_info.end = modem_route_count - 1; in init_modem_driver_req()
310 mem = ipa_mem_find(ipa, IPA_MEM_V6_ROUTE); in init_modem_driver_req()
312 req.v6_route_tbl_info.start = ipa->mem_offset + mem->offset; in init_modem_driver_req()
313 req.v6_route_tbl_info.end = modem_route_count - 1; in init_modem_driver_req()
315 mem = ipa_mem_find(ipa, IPA_MEM_V4_FILTER); in init_modem_driver_req()
317 req.v4_filter_tbl_start = ipa->mem_offset + mem->offset; in init_modem_driver_req()
319 mem = ipa_mem_find(ipa, IPA_MEM_V6_FILTER); in init_modem_driver_req()
321 req.v6_filter_tbl_start = ipa->mem_offset + mem->offset; in init_modem_driver_req()
323 mem = ipa_mem_find(ipa, IPA_MEM_MODEM); in init_modem_driver_req()
324 if (mem->size) { in init_modem_driver_req()
326 req.modem_mem_info.start = ipa->mem_offset + mem->offset; in init_modem_driver_req()
327 req.modem_mem_info.size = mem->size; in init_modem_driver_req()
332 ipa->name_map[IPA_ENDPOINT_AP_MODEM_RX]->endpoint_id; in init_modem_driver_req()
336 mem = ipa_mem_find(ipa, IPA_MEM_MODEM_PROC_CTX); in init_modem_driver_req()
337 if (mem->size) { in init_modem_driver_req()
340 ipa->mem_offset + mem->offset; in init_modem_driver_req()
342 req.hdr_proc_ctx_tbl_info.start + mem->size - 1; in init_modem_driver_req()
345 /* Nothing to report for the compression table (zip_tbl_info) */ in init_modem_driver_req()
347 mem = ipa_mem_find(ipa, IPA_MEM_V4_ROUTE_HASHED); in init_modem_driver_req()
348 if (mem->size) { in init_modem_driver_req()
351 ipa->mem_offset + mem->offset; in init_modem_driver_req()
352 req.v4_hash_route_tbl_info.end = modem_route_count - 1; in init_modem_driver_req()
355 mem = ipa_mem_find(ipa, IPA_MEM_V6_ROUTE_HASHED); in init_modem_driver_req()
356 if (mem->size) { in init_modem_driver_req()
359 ipa->mem_offset + mem->offset; in init_modem_driver_req()
360 req.v6_hash_route_tbl_info.end = modem_route_count - 1; in init_modem_driver_req()
363 mem = ipa_mem_find(ipa, IPA_MEM_V4_FILTER_HASHED); in init_modem_driver_req()
364 if (mem->size) { in init_modem_driver_req()
366 req.v4_hash_filter_tbl_start = ipa->mem_offset + mem->offset; in init_modem_driver_req()
369 mem = ipa_mem_find(ipa, IPA_MEM_V6_FILTER_HASHED); in init_modem_driver_req()
370 if (mem->size) { in init_modem_driver_req()
372 req.v6_hash_filter_tbl_start = ipa->mem_offset + mem->offset; in init_modem_driver_req()
375 /* The stats fields are only valid for IPA v4.0+ */ in init_modem_driver_req()
376 if (ipa->version >= IPA_VERSION_4_0) { in init_modem_driver_req()
377 mem = ipa_mem_find(ipa, IPA_MEM_STATS_QUOTA_MODEM); in init_modem_driver_req()
378 if (mem->size) { in init_modem_driver_req()
381 ipa->mem_offset + mem->offset; in init_modem_driver_req()
383 req.hw_stats_quota_size = ipa->mem_offset + mem->size; in init_modem_driver_req()
387 mem = ipa_mem_find(ipa, IPA_MEM_STATS_DROP); in init_modem_driver_req()
388 if (mem && mem->size) { in init_modem_driver_req()
391 ipa->mem_offset + mem->offset; in init_modem_driver_req()
393 req.hw_stats_drop_size = ipa->mem_offset + mem->size; in init_modem_driver_req()
400 /* Send an INIT_DRIVER request to the modem, and wait for it to complete. */
409 struct ipa *ipa; in ipa_client_init_driver_work() local
413 qmi = &ipa_qmi->client_handle; in ipa_client_init_driver_work()
415 ipa = container_of(ipa_qmi, struct ipa, qmi); in ipa_client_init_driver_work()
416 dev = ipa->dev; in ipa_client_init_driver_work()
426 ret = qmi_send_request(qmi, &ipa_qmi->modem_sq, &txn, in ipa_client_init_driver_work()
435 ipa_qmi->modem_ready = true; in ipa_client_init_driver_work()
438 /* If any error occurs we need to cancel the transaction */ in ipa_client_init_driver_work()
443 /* The modem server is now available. We will send an INIT_DRIVER request
444 * to the modem, but can't wait for it to complete in this callback thread.
445 * Schedule a worker on the global workqueue to do that for us.
454 ipa_qmi->modem_sq.sq_family = AF_QIPCRTR; in ipa_client_new_server()
455 ipa_qmi->modem_sq.sq_node = svc->node; in ipa_client_new_server()
456 ipa_qmi->modem_sq.sq_port = svc->port; in ipa_client_new_server()
458 schedule_work(&ipa_qmi->init_driver_work); in ipa_client_new_server()
468 int ipa_qmi_setup(struct ipa *ipa) in ipa_qmi_setup() argument
470 struct ipa_qmi *ipa_qmi = &ipa->qmi; in ipa_qmi_setup()
473 ipa_qmi->initial_boot = true; in ipa_qmi_setup()
475 /* The server handle is used to handle the DRIVER_INIT_COMPLETE in ipa_qmi_setup()
476 * request on the first modem boot. It also receives the in ipa_qmi_setup()
481 ret = qmi_handle_init(&ipa_qmi->server_handle, in ipa_qmi_setup()
487 ret = qmi_add_server(&ipa_qmi->server_handle, IPA_HOST_SERVICE_SVC_ID, in ipa_qmi_setup()
493 * to the modem, and receiving its response message. in ipa_qmi_setup()
495 ret = qmi_handle_init(&ipa_qmi->client_handle, in ipa_qmi_setup()
502 INIT_WORK(&ipa_qmi->init_driver_work, ipa_client_init_driver_work); in ipa_qmi_setup()
504 ret = qmi_add_lookup(&ipa_qmi->client_handle, IPA_MODEM_SERVICE_SVC_ID, in ipa_qmi_setup()
513 qmi_handle_release(&ipa_qmi->client_handle); in ipa_qmi_setup()
514 memset(&ipa_qmi->client_handle, 0, sizeof(ipa_qmi->client_handle)); in ipa_qmi_setup()
517 qmi_handle_release(&ipa_qmi->server_handle); in ipa_qmi_setup()
518 memset(&ipa_qmi->server_handle, 0, sizeof(ipa_qmi->server_handle)); in ipa_qmi_setup()
523 /* Tear down IPA QMI handles */
524 void ipa_qmi_teardown(struct ipa *ipa) in ipa_qmi_teardown() argument
526 cancel_work_sync(&ipa->qmi.init_driver_work); in ipa_qmi_teardown()
528 qmi_handle_release(&ipa->qmi.client_handle); in ipa_qmi_teardown()
529 memset(&ipa->qmi.client_handle, 0, sizeof(ipa->qmi.client_handle)); in ipa_qmi_teardown()
531 qmi_handle_release(&ipa->qmi.server_handle); in ipa_qmi_teardown()
532 memset(&ipa->qmi.server_handle, 0, sizeof(ipa->qmi.server_handle)); in ipa_qmi_teardown()