1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2020 The Linux Foundation. All rights reserved.
6 #include <linux/kernel.h>
7 #include <linux/module.h>
8 #include <linux/string.h>
9 #include <linux/workqueue.h>
11 #include "pdr_internal.h"
14 char service_name
[SERVREG_NAME_LENGTH
+ 1];
15 char service_path
[SERVREG_NAME_LENGTH
+ 1];
17 struct sockaddr_qrtr addr
;
19 unsigned int instance
;
21 u8 service_data_valid
;
25 bool need_notifier_register
;
26 bool need_notifier_remove
;
27 bool need_locator_lookup
;
28 bool service_connected
;
30 struct list_head node
;
34 struct qmi_handle locator_hdl
;
35 struct qmi_handle notifier_hdl
;
37 struct sockaddr_qrtr locator_addr
;
39 struct list_head lookups
;
40 struct list_head indack_list
;
42 /* control access to pdr lookup/indack lists */
43 struct mutex list_lock
;
45 /* serialize pd status invocation */
46 struct mutex status_lock
;
48 /* control access to the locator state */
51 bool locator_init_complete
;
53 struct work_struct locator_work
;
54 struct work_struct notifier_work
;
55 struct work_struct indack_work
;
57 struct workqueue_struct
*notifier_wq
;
58 struct workqueue_struct
*indack_wq
;
60 void (*status
)(int state
, char *service_path
, void *priv
);
64 struct pdr_list_node
{
65 enum servreg_service_state curr_state
;
67 struct pdr_service
*pds
;
68 struct list_head node
;
71 static int pdr_locator_new_server(struct qmi_handle
*qmi
,
72 struct qmi_service
*svc
)
74 struct pdr_handle
*pdr
= container_of(qmi
, struct pdr_handle
,
76 struct pdr_service
*pds
;
78 /* Create a local client port for QMI communication */
79 pdr
->locator_addr
.sq_family
= AF_QIPCRTR
;
80 pdr
->locator_addr
.sq_node
= svc
->node
;
81 pdr
->locator_addr
.sq_port
= svc
->port
;
83 mutex_lock(&pdr
->lock
);
84 pdr
->locator_init_complete
= true;
85 mutex_unlock(&pdr
->lock
);
87 /* Service pending lookup requests */
88 mutex_lock(&pdr
->list_lock
);
89 list_for_each_entry(pds
, &pdr
->lookups
, node
) {
90 if (pds
->need_locator_lookup
)
91 schedule_work(&pdr
->locator_work
);
93 mutex_unlock(&pdr
->list_lock
);
98 static void pdr_locator_del_server(struct qmi_handle
*qmi
,
99 struct qmi_service
*svc
)
101 struct pdr_handle
*pdr
= container_of(qmi
, struct pdr_handle
,
104 mutex_lock(&pdr
->lock
);
105 pdr
->locator_init_complete
= false;
106 mutex_unlock(&pdr
->lock
);
108 pdr
->locator_addr
.sq_node
= 0;
109 pdr
->locator_addr
.sq_port
= 0;
112 static struct qmi_ops pdr_locator_ops
= {
113 .new_server
= pdr_locator_new_server
,
114 .del_server
= pdr_locator_del_server
,
117 static int pdr_register_listener(struct pdr_handle
*pdr
,
118 struct pdr_service
*pds
,
121 struct servreg_register_listener_resp resp
;
122 struct servreg_register_listener_req req
;
126 ret
= qmi_txn_init(&pdr
->notifier_hdl
, &txn
,
127 servreg_register_listener_resp_ei
,
133 strcpy(req
.service_path
, pds
->service_path
);
135 ret
= qmi_send_request(&pdr
->notifier_hdl
, &pds
->addr
,
136 &txn
, SERVREG_REGISTER_LISTENER_REQ
,
137 SERVREG_REGISTER_LISTENER_REQ_LEN
,
138 servreg_register_listener_req_ei
,
141 qmi_txn_cancel(&txn
);
145 ret
= qmi_txn_wait(&txn
, 5 * HZ
);
147 pr_err("PDR: %s register listener txn wait failed: %d\n",
148 pds
->service_path
, ret
);
152 if (resp
.resp
.result
!= QMI_RESULT_SUCCESS_V01
) {
153 pr_err("PDR: %s register listener failed: 0x%x\n",
154 pds
->service_path
, resp
.resp
.error
);
158 if ((int)resp
.curr_state
< INT_MIN
|| (int)resp
.curr_state
> INT_MAX
)
159 pr_err("PDR: %s notification state invalid: 0x%x\n",
160 pds
->service_path
, resp
.curr_state
);
162 pds
->state
= resp
.curr_state
;
167 static void pdr_notifier_work(struct work_struct
*work
)
169 struct pdr_handle
*pdr
= container_of(work
, struct pdr_handle
,
171 struct pdr_service
*pds
;
174 mutex_lock(&pdr
->list_lock
);
175 list_for_each_entry(pds
, &pdr
->lookups
, node
) {
176 if (pds
->service_connected
) {
177 if (!pds
->need_notifier_register
)
180 pds
->need_notifier_register
= false;
181 ret
= pdr_register_listener(pdr
, pds
, true);
183 pds
->state
= SERVREG_SERVICE_STATE_DOWN
;
185 if (!pds
->need_notifier_remove
)
188 pds
->need_notifier_remove
= false;
189 pds
->state
= SERVREG_SERVICE_STATE_DOWN
;
192 mutex_lock(&pdr
->status_lock
);
193 pdr
->status(pds
->state
, pds
->service_path
, pdr
->priv
);
194 mutex_unlock(&pdr
->status_lock
);
196 mutex_unlock(&pdr
->list_lock
);
199 static int pdr_notifier_new_server(struct qmi_handle
*qmi
,
200 struct qmi_service
*svc
)
202 struct pdr_handle
*pdr
= container_of(qmi
, struct pdr_handle
,
204 struct pdr_service
*pds
;
206 mutex_lock(&pdr
->list_lock
);
207 list_for_each_entry(pds
, &pdr
->lookups
, node
) {
208 if (pds
->service
== svc
->service
&&
209 pds
->instance
== svc
->instance
) {
210 pds
->service_connected
= true;
211 pds
->need_notifier_register
= true;
212 pds
->addr
.sq_family
= AF_QIPCRTR
;
213 pds
->addr
.sq_node
= svc
->node
;
214 pds
->addr
.sq_port
= svc
->port
;
215 queue_work(pdr
->notifier_wq
, &pdr
->notifier_work
);
218 mutex_unlock(&pdr
->list_lock
);
223 static void pdr_notifier_del_server(struct qmi_handle
*qmi
,
224 struct qmi_service
*svc
)
226 struct pdr_handle
*pdr
= container_of(qmi
, struct pdr_handle
,
228 struct pdr_service
*pds
;
230 mutex_lock(&pdr
->list_lock
);
231 list_for_each_entry(pds
, &pdr
->lookups
, node
) {
232 if (pds
->service
== svc
->service
&&
233 pds
->instance
== svc
->instance
) {
234 pds
->service_connected
= false;
235 pds
->need_notifier_remove
= true;
236 pds
->addr
.sq_node
= 0;
237 pds
->addr
.sq_port
= 0;
238 queue_work(pdr
->notifier_wq
, &pdr
->notifier_work
);
241 mutex_unlock(&pdr
->list_lock
);
244 static struct qmi_ops pdr_notifier_ops
= {
245 .new_server
= pdr_notifier_new_server
,
246 .del_server
= pdr_notifier_del_server
,
249 static int pdr_send_indack_msg(struct pdr_handle
*pdr
, struct pdr_service
*pds
,
252 struct servreg_set_ack_resp resp
;
253 struct servreg_set_ack_req req
;
257 ret
= qmi_txn_init(&pdr
->notifier_hdl
, &txn
, servreg_set_ack_resp_ei
,
262 req
.transaction_id
= tid
;
263 strcpy(req
.service_path
, pds
->service_path
);
265 ret
= qmi_send_request(&pdr
->notifier_hdl
, &pds
->addr
,
266 &txn
, SERVREG_SET_ACK_REQ
,
267 SERVREG_SET_ACK_REQ_LEN
,
268 servreg_set_ack_req_ei
,
271 /* Skip waiting for response */
272 qmi_txn_cancel(&txn
);
276 static void pdr_indack_work(struct work_struct
*work
)
278 struct pdr_handle
*pdr
= container_of(work
, struct pdr_handle
,
280 struct pdr_list_node
*ind
, *tmp
;
281 struct pdr_service
*pds
;
283 list_for_each_entry_safe(ind
, tmp
, &pdr
->indack_list
, node
) {
285 pdr_send_indack_msg(pdr
, pds
, ind
->transaction_id
);
287 mutex_lock(&pdr
->status_lock
);
288 pds
->state
= ind
->curr_state
;
289 pdr
->status(pds
->state
, pds
->service_path
, pdr
->priv
);
290 mutex_unlock(&pdr
->status_lock
);
292 mutex_lock(&pdr
->list_lock
);
293 list_del(&ind
->node
);
294 mutex_unlock(&pdr
->list_lock
);
300 static void pdr_indication_cb(struct qmi_handle
*qmi
,
301 struct sockaddr_qrtr
*sq
,
302 struct qmi_txn
*txn
, const void *data
)
304 struct pdr_handle
*pdr
= container_of(qmi
, struct pdr_handle
,
306 const struct servreg_state_updated_ind
*ind_msg
= data
;
307 struct pdr_list_node
*ind
;
308 struct pdr_service
*pds
;
311 if (!ind_msg
|| !ind_msg
->service_path
[0] ||
312 strlen(ind_msg
->service_path
) > SERVREG_NAME_LENGTH
)
315 mutex_lock(&pdr
->list_lock
);
316 list_for_each_entry(pds
, &pdr
->lookups
, node
) {
317 if (strcmp(pds
->service_path
, ind_msg
->service_path
))
323 mutex_unlock(&pdr
->list_lock
);
328 pr_info("PDR: Indication received from %s, state: 0x%x, trans-id: %d\n",
329 ind_msg
->service_path
, ind_msg
->curr_state
,
330 ind_msg
->transaction_id
);
332 ind
= kzalloc(sizeof(*ind
), GFP_KERNEL
);
336 ind
->transaction_id
= ind_msg
->transaction_id
;
337 ind
->curr_state
= ind_msg
->curr_state
;
340 mutex_lock(&pdr
->list_lock
);
341 list_add_tail(&ind
->node
, &pdr
->indack_list
);
342 mutex_unlock(&pdr
->list_lock
);
344 queue_work(pdr
->indack_wq
, &pdr
->indack_work
);
347 static struct qmi_msg_handler qmi_indication_handler
[] = {
349 .type
= QMI_INDICATION
,
350 .msg_id
= SERVREG_STATE_UPDATED_IND_ID
,
351 .ei
= servreg_state_updated_ind_ei
,
352 .decoded_size
= sizeof(struct servreg_state_updated_ind
),
353 .fn
= pdr_indication_cb
,
358 static int pdr_get_domain_list(struct servreg_get_domain_list_req
*req
,
359 struct servreg_get_domain_list_resp
*resp
,
360 struct pdr_handle
*pdr
)
365 ret
= qmi_txn_init(&pdr
->locator_hdl
, &txn
,
366 servreg_get_domain_list_resp_ei
, resp
);
370 ret
= qmi_send_request(&pdr
->locator_hdl
,
372 &txn
, SERVREG_GET_DOMAIN_LIST_REQ
,
373 SERVREG_GET_DOMAIN_LIST_REQ_MAX_LEN
,
374 servreg_get_domain_list_req_ei
,
377 qmi_txn_cancel(&txn
);
381 ret
= qmi_txn_wait(&txn
, 5 * HZ
);
383 pr_err("PDR: %s get domain list txn wait failed: %d\n",
384 req
->service_name
, ret
);
388 if (resp
->resp
.result
!= QMI_RESULT_SUCCESS_V01
) {
389 pr_err("PDR: %s get domain list failed: 0x%x\n",
390 req
->service_name
, resp
->resp
.error
);
397 static int pdr_locate_service(struct pdr_handle
*pdr
, struct pdr_service
*pds
)
399 struct servreg_get_domain_list_resp
*resp
;
400 struct servreg_get_domain_list_req req
;
401 struct servreg_location_entry
*entry
;
402 int domains_read
= 0;
405 resp
= kzalloc(sizeof(*resp
), GFP_KERNEL
);
409 /* Prepare req message */
410 strcpy(req
.service_name
, pds
->service_name
);
411 req
.domain_offset_valid
= true;
412 req
.domain_offset
= 0;
415 req
.domain_offset
= domains_read
;
416 ret
= pdr_get_domain_list(&req
, resp
, pdr
);
420 for (i
= domains_read
; i
< resp
->domain_list_len
; i
++) {
421 entry
= &resp
->domain_list
[i
];
423 if (strnlen(entry
->name
, sizeof(entry
->name
)) == sizeof(entry
->name
))
426 if (!strcmp(entry
->name
, pds
->service_path
)) {
427 pds
->service_data_valid
= entry
->service_data_valid
;
428 pds
->service_data
= entry
->service_data
;
429 pds
->instance
= entry
->instance
;
434 /* Update ret to indicate that the service is not yet found */
437 /* Always read total_domains from the response msg */
438 if (resp
->domain_list_len
> resp
->total_domains
)
439 resp
->domain_list_len
= resp
->total_domains
;
441 domains_read
+= resp
->domain_list_len
;
442 } while (domains_read
< resp
->total_domains
);
448 static void pdr_notify_lookup_failure(struct pdr_handle
*pdr
,
449 struct pdr_service
*pds
,
452 pr_err("PDR: service lookup for %s failed: %d\n",
453 pds
->service_name
, err
);
458 list_del(&pds
->node
);
459 pds
->state
= SERVREG_LOCATOR_ERR
;
460 mutex_lock(&pdr
->status_lock
);
461 pdr
->status(pds
->state
, pds
->service_path
, pdr
->priv
);
462 mutex_unlock(&pdr
->status_lock
);
466 static void pdr_locator_work(struct work_struct
*work
)
468 struct pdr_handle
*pdr
= container_of(work
, struct pdr_handle
,
470 struct pdr_service
*pds
, *tmp
;
473 /* Bail out early if the SERVREG LOCATOR QMI service is not up */
474 mutex_lock(&pdr
->lock
);
475 if (!pdr
->locator_init_complete
) {
476 mutex_unlock(&pdr
->lock
);
477 pr_debug("PDR: SERVICE LOCATOR service not available\n");
480 mutex_unlock(&pdr
->lock
);
482 mutex_lock(&pdr
->list_lock
);
483 list_for_each_entry_safe(pds
, tmp
, &pdr
->lookups
, node
) {
484 if (!pds
->need_locator_lookup
)
487 ret
= pdr_locate_service(pdr
, pds
);
489 pdr_notify_lookup_failure(pdr
, pds
, ret
);
493 ret
= qmi_add_lookup(&pdr
->notifier_hdl
, pds
->service
, 1,
496 pdr_notify_lookup_failure(pdr
, pds
, ret
);
500 pds
->need_locator_lookup
= false;
502 mutex_unlock(&pdr
->list_lock
);
506 * pdr_add_lookup() - register a tracking request for a PD
507 * @pdr: PDR client handle
508 * @service_name: service name of the tracking request
509 * @service_path: service path of the tracking request
511 * Registering a pdr lookup allows for tracking the life cycle of the PD.
513 * Return: pdr_service object on success, ERR_PTR on failure. -EALREADY is
514 * returned if a lookup is already in progress for the given service path.
516 struct pdr_service
*pdr_add_lookup(struct pdr_handle
*pdr
,
517 const char *service_name
,
518 const char *service_path
)
520 struct pdr_service
*pds
, *tmp
;
523 if (IS_ERR_OR_NULL(pdr
))
524 return ERR_PTR(-EINVAL
);
526 if (!service_name
|| strlen(service_name
) > SERVREG_NAME_LENGTH
||
527 !service_path
|| strlen(service_path
) > SERVREG_NAME_LENGTH
)
528 return ERR_PTR(-EINVAL
);
530 pds
= kzalloc(sizeof(*pds
), GFP_KERNEL
);
532 return ERR_PTR(-ENOMEM
);
534 pds
->service
= SERVREG_NOTIFIER_SERVICE
;
535 strcpy(pds
->service_name
, service_name
);
536 strcpy(pds
->service_path
, service_path
);
537 pds
->need_locator_lookup
= true;
539 mutex_lock(&pdr
->list_lock
);
540 list_for_each_entry(tmp
, &pdr
->lookups
, node
) {
541 if (strcmp(tmp
->service_path
, service_path
))
544 mutex_unlock(&pdr
->list_lock
);
549 list_add(&pds
->node
, &pdr
->lookups
);
550 mutex_unlock(&pdr
->list_lock
);
552 schedule_work(&pdr
->locator_work
);
559 EXPORT_SYMBOL(pdr_add_lookup
);
562 * pdr_restart_pd() - restart PD
563 * @pdr: PDR client handle
564 * @pds: PD service handle
566 * Restarts the PD tracked by the PDR client handle for a given service path.
568 * Return: 0 on success, negative errno on failure.
570 int pdr_restart_pd(struct pdr_handle
*pdr
, struct pdr_service
*pds
)
572 struct servreg_restart_pd_resp resp
;
573 struct servreg_restart_pd_req req
;
574 struct sockaddr_qrtr addr
;
575 struct pdr_service
*tmp
;
579 if (IS_ERR_OR_NULL(pdr
) || IS_ERR_OR_NULL(pds
))
582 mutex_lock(&pdr
->list_lock
);
583 list_for_each_entry(tmp
, &pdr
->lookups
, node
) {
587 if (!pds
->service_connected
)
590 /* Prepare req message */
591 strcpy(req
.service_path
, pds
->service_path
);
595 mutex_unlock(&pdr
->list_lock
);
597 if (!req
.service_path
[0])
600 ret
= qmi_txn_init(&pdr
->notifier_hdl
, &txn
,
601 servreg_restart_pd_resp_ei
,
606 ret
= qmi_send_request(&pdr
->notifier_hdl
, &addr
,
607 &txn
, SERVREG_RESTART_PD_REQ
,
608 SERVREG_RESTART_PD_REQ_MAX_LEN
,
609 servreg_restart_pd_req_ei
, &req
);
611 qmi_txn_cancel(&txn
);
615 ret
= qmi_txn_wait(&txn
, 5 * HZ
);
617 pr_err("PDR: %s PD restart txn wait failed: %d\n",
618 req
.service_path
, ret
);
622 /* Check response if PDR is disabled */
623 if (resp
.resp
.result
== QMI_RESULT_FAILURE_V01
&&
624 resp
.resp
.error
== QMI_ERR_DISABLED_V01
) {
625 pr_err("PDR: %s PD restart is disabled: 0x%x\n",
626 req
.service_path
, resp
.resp
.error
);
630 /* Check the response for other error case*/
631 if (resp
.resp
.result
!= QMI_RESULT_SUCCESS_V01
) {
632 pr_err("PDR: %s request for PD restart failed: 0x%x\n",
633 req
.service_path
, resp
.resp
.error
);
639 EXPORT_SYMBOL(pdr_restart_pd
);
642 * pdr_handle_alloc() - initialize the PDR client handle
643 * @status: function to be called on PD state change
644 * @priv: handle for client's use
646 * Initializes the PDR client handle to allow for tracking/restart of PDs.
648 * Return: pdr_handle object on success, ERR_PTR on failure.
650 struct pdr_handle
*pdr_handle_alloc(void (*status
)(int state
,
652 void *priv
), void *priv
)
654 struct pdr_handle
*pdr
;
658 return ERR_PTR(-EINVAL
);
660 pdr
= kzalloc(sizeof(*pdr
), GFP_KERNEL
);
662 return ERR_PTR(-ENOMEM
);
664 pdr
->status
= status
;
667 mutex_init(&pdr
->status_lock
);
668 mutex_init(&pdr
->list_lock
);
669 mutex_init(&pdr
->lock
);
671 INIT_LIST_HEAD(&pdr
->lookups
);
672 INIT_LIST_HEAD(&pdr
->indack_list
);
674 INIT_WORK(&pdr
->locator_work
, pdr_locator_work
);
675 INIT_WORK(&pdr
->notifier_work
, pdr_notifier_work
);
676 INIT_WORK(&pdr
->indack_work
, pdr_indack_work
);
678 pdr
->notifier_wq
= create_singlethread_workqueue("pdr_notifier_wq");
679 if (!pdr
->notifier_wq
) {
681 goto free_pdr_handle
;
684 pdr
->indack_wq
= alloc_ordered_workqueue("pdr_indack_wq", WQ_HIGHPRI
);
685 if (!pdr
->indack_wq
) {
687 goto destroy_notifier
;
690 ret
= qmi_handle_init(&pdr
->locator_hdl
,
691 SERVREG_GET_DOMAIN_LIST_RESP_MAX_LEN
,
692 &pdr_locator_ops
, NULL
);
696 ret
= qmi_add_lookup(&pdr
->locator_hdl
, SERVREG_LOCATOR_SERVICE
, 1, 1);
698 goto release_qmi_handle
;
700 ret
= qmi_handle_init(&pdr
->notifier_hdl
,
701 SERVREG_STATE_UPDATED_IND_MAX_LEN
,
703 qmi_indication_handler
);
705 goto release_qmi_handle
;
710 qmi_handle_release(&pdr
->locator_hdl
);
712 destroy_workqueue(pdr
->indack_wq
);
714 destroy_workqueue(pdr
->notifier_wq
);
720 EXPORT_SYMBOL(pdr_handle_alloc
);
723 * pdr_handle_release() - release the PDR client handle
724 * @pdr: PDR client handle
726 * Cleans up pending tracking requests and releases the underlying qmi handles.
728 void pdr_handle_release(struct pdr_handle
*pdr
)
730 struct pdr_service
*pds
, *tmp
;
732 if (IS_ERR_OR_NULL(pdr
))
735 mutex_lock(&pdr
->list_lock
);
736 list_for_each_entry_safe(pds
, tmp
, &pdr
->lookups
, node
) {
737 list_del(&pds
->node
);
740 mutex_unlock(&pdr
->list_lock
);
742 cancel_work_sync(&pdr
->locator_work
);
743 cancel_work_sync(&pdr
->notifier_work
);
744 cancel_work_sync(&pdr
->indack_work
);
746 destroy_workqueue(pdr
->notifier_wq
);
747 destroy_workqueue(pdr
->indack_wq
);
749 qmi_handle_release(&pdr
->locator_hdl
);
750 qmi_handle_release(&pdr
->notifier_hdl
);
754 EXPORT_SYMBOL(pdr_handle_release
);
756 MODULE_LICENSE("GPL v2");
757 MODULE_DESCRIPTION("Qualcomm Protection Domain Restart helpers");