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/slab.h>
9 #include <linux/string.h>
10 #include <linux/workqueue.h>
12 #include "pdr_internal.h"
15 char service_name
[SERVREG_NAME_LENGTH
+ 1];
16 char service_path
[SERVREG_NAME_LENGTH
+ 1];
18 struct sockaddr_qrtr addr
;
20 unsigned int instance
;
22 u8 service_data_valid
;
26 bool need_notifier_register
;
27 bool need_notifier_remove
;
28 bool need_locator_lookup
;
29 bool service_connected
;
31 struct list_head node
;
35 struct qmi_handle locator_hdl
;
36 struct qmi_handle notifier_hdl
;
38 struct sockaddr_qrtr locator_addr
;
40 struct list_head lookups
;
41 struct list_head indack_list
;
43 /* control access to pdr lookup/indack lists */
44 struct mutex list_lock
;
46 /* serialize pd status invocation */
47 struct mutex status_lock
;
49 /* control access to the locator state */
52 bool locator_init_complete
;
54 struct work_struct locator_work
;
55 struct work_struct notifier_work
;
56 struct work_struct indack_work
;
58 struct workqueue_struct
*notifier_wq
;
59 struct workqueue_struct
*indack_wq
;
61 void (*status
)(int state
, char *service_path
, void *priv
);
65 struct pdr_list_node
{
66 enum servreg_service_state curr_state
;
68 struct pdr_service
*pds
;
69 struct list_head node
;
72 static int pdr_locator_new_server(struct qmi_handle
*qmi
,
73 struct qmi_service
*svc
)
75 struct pdr_handle
*pdr
= container_of(qmi
, struct pdr_handle
,
77 struct pdr_service
*pds
;
79 /* Create a local client port for QMI communication */
80 pdr
->locator_addr
.sq_family
= AF_QIPCRTR
;
81 pdr
->locator_addr
.sq_node
= svc
->node
;
82 pdr
->locator_addr
.sq_port
= svc
->port
;
84 mutex_lock(&pdr
->lock
);
85 pdr
->locator_init_complete
= true;
86 mutex_unlock(&pdr
->lock
);
88 /* Service pending lookup requests */
89 mutex_lock(&pdr
->list_lock
);
90 list_for_each_entry(pds
, &pdr
->lookups
, node
) {
91 if (pds
->need_locator_lookup
)
92 schedule_work(&pdr
->locator_work
);
94 mutex_unlock(&pdr
->list_lock
);
99 static void pdr_locator_del_server(struct qmi_handle
*qmi
,
100 struct qmi_service
*svc
)
102 struct pdr_handle
*pdr
= container_of(qmi
, struct pdr_handle
,
105 mutex_lock(&pdr
->lock
);
106 pdr
->locator_init_complete
= false;
107 mutex_unlock(&pdr
->lock
);
109 pdr
->locator_addr
.sq_node
= 0;
110 pdr
->locator_addr
.sq_port
= 0;
113 static const struct qmi_ops pdr_locator_ops
= {
114 .new_server
= pdr_locator_new_server
,
115 .del_server
= pdr_locator_del_server
,
118 static int pdr_register_listener(struct pdr_handle
*pdr
,
119 struct pdr_service
*pds
,
122 struct servreg_register_listener_resp resp
;
123 struct servreg_register_listener_req req
;
127 ret
= qmi_txn_init(&pdr
->notifier_hdl
, &txn
,
128 servreg_register_listener_resp_ei
,
134 strcpy(req
.service_path
, pds
->service_path
);
136 ret
= qmi_send_request(&pdr
->notifier_hdl
, &pds
->addr
,
137 &txn
, SERVREG_REGISTER_LISTENER_REQ
,
138 SERVREG_REGISTER_LISTENER_REQ_LEN
,
139 servreg_register_listener_req_ei
,
142 qmi_txn_cancel(&txn
);
146 ret
= qmi_txn_wait(&txn
, 5 * HZ
);
148 pr_err("PDR: %s register listener txn wait failed: %d\n",
149 pds
->service_path
, ret
);
153 if (resp
.resp
.result
!= QMI_RESULT_SUCCESS_V01
) {
154 pr_err("PDR: %s register listener failed: 0x%x\n",
155 pds
->service_path
, resp
.resp
.error
);
159 pds
->state
= resp
.curr_state
;
164 static void pdr_notifier_work(struct work_struct
*work
)
166 struct pdr_handle
*pdr
= container_of(work
, struct pdr_handle
,
168 struct pdr_service
*pds
;
171 mutex_lock(&pdr
->list_lock
);
172 list_for_each_entry(pds
, &pdr
->lookups
, node
) {
173 if (pds
->service_connected
) {
174 if (!pds
->need_notifier_register
)
177 pds
->need_notifier_register
= false;
178 ret
= pdr_register_listener(pdr
, pds
, true);
180 pds
->state
= SERVREG_SERVICE_STATE_DOWN
;
182 if (!pds
->need_notifier_remove
)
185 pds
->need_notifier_remove
= false;
186 pds
->state
= SERVREG_SERVICE_STATE_DOWN
;
189 mutex_lock(&pdr
->status_lock
);
190 pdr
->status(pds
->state
, pds
->service_path
, pdr
->priv
);
191 mutex_unlock(&pdr
->status_lock
);
193 mutex_unlock(&pdr
->list_lock
);
196 static int pdr_notifier_new_server(struct qmi_handle
*qmi
,
197 struct qmi_service
*svc
)
199 struct pdr_handle
*pdr
= container_of(qmi
, struct pdr_handle
,
201 struct pdr_service
*pds
;
203 mutex_lock(&pdr
->list_lock
);
204 list_for_each_entry(pds
, &pdr
->lookups
, node
) {
205 if (pds
->service
== svc
->service
&&
206 pds
->instance
== svc
->instance
) {
207 pds
->service_connected
= true;
208 pds
->need_notifier_register
= true;
209 pds
->addr
.sq_family
= AF_QIPCRTR
;
210 pds
->addr
.sq_node
= svc
->node
;
211 pds
->addr
.sq_port
= svc
->port
;
212 queue_work(pdr
->notifier_wq
, &pdr
->notifier_work
);
215 mutex_unlock(&pdr
->list_lock
);
220 static void pdr_notifier_del_server(struct qmi_handle
*qmi
,
221 struct qmi_service
*svc
)
223 struct pdr_handle
*pdr
= container_of(qmi
, struct pdr_handle
,
225 struct pdr_service
*pds
;
227 mutex_lock(&pdr
->list_lock
);
228 list_for_each_entry(pds
, &pdr
->lookups
, node
) {
229 if (pds
->service
== svc
->service
&&
230 pds
->instance
== svc
->instance
) {
231 pds
->service_connected
= false;
232 pds
->need_notifier_remove
= true;
233 pds
->addr
.sq_node
= 0;
234 pds
->addr
.sq_port
= 0;
235 queue_work(pdr
->notifier_wq
, &pdr
->notifier_work
);
238 mutex_unlock(&pdr
->list_lock
);
241 static const struct qmi_ops pdr_notifier_ops
= {
242 .new_server
= pdr_notifier_new_server
,
243 .del_server
= pdr_notifier_del_server
,
246 static int pdr_send_indack_msg(struct pdr_handle
*pdr
, struct pdr_service
*pds
,
249 struct servreg_set_ack_resp resp
;
250 struct servreg_set_ack_req req
;
254 ret
= qmi_txn_init(&pdr
->notifier_hdl
, &txn
, servreg_set_ack_resp_ei
,
259 req
.transaction_id
= tid
;
260 strcpy(req
.service_path
, pds
->service_path
);
262 ret
= qmi_send_request(&pdr
->notifier_hdl
, &pds
->addr
,
263 &txn
, SERVREG_SET_ACK_REQ
,
264 SERVREG_SET_ACK_REQ_LEN
,
265 servreg_set_ack_req_ei
,
268 /* Skip waiting for response */
269 qmi_txn_cancel(&txn
);
273 static void pdr_indack_work(struct work_struct
*work
)
275 struct pdr_handle
*pdr
= container_of(work
, struct pdr_handle
,
277 struct pdr_list_node
*ind
, *tmp
;
278 struct pdr_service
*pds
;
280 list_for_each_entry_safe(ind
, tmp
, &pdr
->indack_list
, node
) {
283 mutex_lock(&pdr
->status_lock
);
284 pds
->state
= ind
->curr_state
;
285 pdr
->status(pds
->state
, pds
->service_path
, pdr
->priv
);
286 mutex_unlock(&pdr
->status_lock
);
288 /* Ack the indication after clients release the PD resources */
289 pdr_send_indack_msg(pdr
, pds
, ind
->transaction_id
);
291 mutex_lock(&pdr
->list_lock
);
292 list_del(&ind
->node
);
293 mutex_unlock(&pdr
->list_lock
);
299 static void pdr_indication_cb(struct qmi_handle
*qmi
,
300 struct sockaddr_qrtr
*sq
,
301 struct qmi_txn
*txn
, const void *data
)
303 struct pdr_handle
*pdr
= container_of(qmi
, struct pdr_handle
,
305 const struct servreg_state_updated_ind
*ind_msg
= data
;
306 struct pdr_list_node
*ind
;
307 struct pdr_service
*pds
;
310 if (!ind_msg
|| !ind_msg
->service_path
[0] ||
311 strlen(ind_msg
->service_path
) > SERVREG_NAME_LENGTH
)
314 mutex_lock(&pdr
->list_lock
);
315 list_for_each_entry(pds
, &pdr
->lookups
, node
) {
316 if (strcmp(pds
->service_path
, ind_msg
->service_path
))
322 mutex_unlock(&pdr
->list_lock
);
327 pr_info("PDR: Indication received from %s, state: 0x%x, trans-id: %d\n",
328 ind_msg
->service_path
, ind_msg
->curr_state
,
329 ind_msg
->transaction_id
);
331 ind
= kzalloc(sizeof(*ind
), GFP_KERNEL
);
335 ind
->transaction_id
= ind_msg
->transaction_id
;
336 ind
->curr_state
= ind_msg
->curr_state
;
339 mutex_lock(&pdr
->list_lock
);
340 list_add_tail(&ind
->node
, &pdr
->indack_list
);
341 mutex_unlock(&pdr
->list_lock
);
343 queue_work(pdr
->indack_wq
, &pdr
->indack_work
);
346 static const struct qmi_msg_handler qmi_indication_handler
[] = {
348 .type
= QMI_INDICATION
,
349 .msg_id
= SERVREG_STATE_UPDATED_IND_ID
,
350 .ei
= servreg_state_updated_ind_ei
,
351 .decoded_size
= sizeof(struct servreg_state_updated_ind
),
352 .fn
= pdr_indication_cb
,
357 static int pdr_get_domain_list(struct servreg_get_domain_list_req
*req
,
358 struct servreg_get_domain_list_resp
*resp
,
359 struct pdr_handle
*pdr
)
364 ret
= qmi_txn_init(&pdr
->locator_hdl
, &txn
,
365 servreg_get_domain_list_resp_ei
, resp
);
369 ret
= qmi_send_request(&pdr
->locator_hdl
,
371 &txn
, SERVREG_GET_DOMAIN_LIST_REQ
,
372 SERVREG_GET_DOMAIN_LIST_REQ_MAX_LEN
,
373 servreg_get_domain_list_req_ei
,
376 qmi_txn_cancel(&txn
);
380 ret
= qmi_txn_wait(&txn
, 5 * HZ
);
382 pr_err("PDR: %s get domain list txn wait failed: %d\n",
383 req
->service_name
, ret
);
387 if (resp
->resp
.result
!= QMI_RESULT_SUCCESS_V01
) {
388 pr_err("PDR: %s get domain list failed: 0x%x\n",
389 req
->service_name
, resp
->resp
.error
);
396 static int pdr_locate_service(struct pdr_handle
*pdr
, struct pdr_service
*pds
)
398 struct servreg_get_domain_list_resp
*resp
;
399 struct servreg_get_domain_list_req req
;
400 struct servreg_location_entry
*entry
;
401 int domains_read
= 0;
404 resp
= kzalloc(sizeof(*resp
), GFP_KERNEL
);
408 /* Prepare req message */
409 strcpy(req
.service_name
, pds
->service_name
);
410 req
.domain_offset_valid
= true;
411 req
.domain_offset
= 0;
414 req
.domain_offset
= domains_read
;
415 ret
= pdr_get_domain_list(&req
, resp
, pdr
);
419 for (i
= domains_read
; i
< resp
->domain_list_len
; i
++) {
420 entry
= &resp
->domain_list
[i
];
422 if (strnlen(entry
->name
, sizeof(entry
->name
)) == sizeof(entry
->name
))
425 if (!strcmp(entry
->name
, pds
->service_path
)) {
426 pds
->service_data_valid
= entry
->service_data_valid
;
427 pds
->service_data
= entry
->service_data
;
428 pds
->instance
= entry
->instance
;
433 /* Update ret to indicate that the service is not yet found */
436 /* Always read total_domains from the response msg */
437 if (resp
->domain_list_len
> resp
->total_domains
)
438 resp
->domain_list_len
= resp
->total_domains
;
440 domains_read
+= resp
->domain_list_len
;
441 } while (domains_read
< resp
->total_domains
);
447 static void pdr_notify_lookup_failure(struct pdr_handle
*pdr
,
448 struct pdr_service
*pds
,
451 pr_err("PDR: service lookup for %s failed: %d\n",
452 pds
->service_name
, err
);
457 list_del(&pds
->node
);
458 pds
->state
= SERVREG_LOCATOR_ERR
;
459 mutex_lock(&pdr
->status_lock
);
460 pdr
->status(pds
->state
, pds
->service_path
, pdr
->priv
);
461 mutex_unlock(&pdr
->status_lock
);
465 static void pdr_locator_work(struct work_struct
*work
)
467 struct pdr_handle
*pdr
= container_of(work
, struct pdr_handle
,
469 struct pdr_service
*pds
, *tmp
;
472 /* Bail out early if the SERVREG LOCATOR QMI service is not up */
473 mutex_lock(&pdr
->lock
);
474 if (!pdr
->locator_init_complete
) {
475 mutex_unlock(&pdr
->lock
);
476 pr_debug("PDR: SERVICE LOCATOR service not available\n");
479 mutex_unlock(&pdr
->lock
);
481 mutex_lock(&pdr
->list_lock
);
482 list_for_each_entry_safe(pds
, tmp
, &pdr
->lookups
, node
) {
483 if (!pds
->need_locator_lookup
)
486 ret
= pdr_locate_service(pdr
, pds
);
488 pdr_notify_lookup_failure(pdr
, pds
, ret
);
492 ret
= qmi_add_lookup(&pdr
->notifier_hdl
, pds
->service
, 1,
495 pdr_notify_lookup_failure(pdr
, pds
, ret
);
499 pds
->need_locator_lookup
= false;
501 mutex_unlock(&pdr
->list_lock
);
505 * pdr_add_lookup() - register a tracking request for a PD
506 * @pdr: PDR client handle
507 * @service_name: service name of the tracking request
508 * @service_path: service path of the tracking request
510 * Registering a pdr lookup allows for tracking the life cycle of the PD.
512 * Return: pdr_service object on success, ERR_PTR on failure. -EALREADY is
513 * returned if a lookup is already in progress for the given service path.
515 struct pdr_service
*pdr_add_lookup(struct pdr_handle
*pdr
,
516 const char *service_name
,
517 const char *service_path
)
519 struct pdr_service
*pds
, *tmp
;
522 if (IS_ERR_OR_NULL(pdr
))
523 return ERR_PTR(-EINVAL
);
525 if (!service_name
|| strlen(service_name
) > SERVREG_NAME_LENGTH
||
526 !service_path
|| strlen(service_path
) > SERVREG_NAME_LENGTH
)
527 return ERR_PTR(-EINVAL
);
529 pds
= kzalloc(sizeof(*pds
), GFP_KERNEL
);
531 return ERR_PTR(-ENOMEM
);
533 pds
->service
= SERVREG_NOTIFIER_SERVICE
;
534 strcpy(pds
->service_name
, service_name
);
535 strcpy(pds
->service_path
, service_path
);
536 pds
->need_locator_lookup
= true;
538 mutex_lock(&pdr
->list_lock
);
539 list_for_each_entry(tmp
, &pdr
->lookups
, node
) {
540 if (strcmp(tmp
->service_path
, service_path
))
543 mutex_unlock(&pdr
->list_lock
);
548 list_add(&pds
->node
, &pdr
->lookups
);
549 mutex_unlock(&pdr
->list_lock
);
551 schedule_work(&pdr
->locator_work
);
558 EXPORT_SYMBOL(pdr_add_lookup
);
561 * pdr_restart_pd() - restart PD
562 * @pdr: PDR client handle
563 * @pds: PD service handle
565 * Restarts the PD tracked by the PDR client handle for a given service path.
567 * Return: 0 on success, negative errno on failure.
569 int pdr_restart_pd(struct pdr_handle
*pdr
, struct pdr_service
*pds
)
571 struct servreg_restart_pd_resp resp
;
572 struct servreg_restart_pd_req req
= { 0 };
573 struct sockaddr_qrtr addr
;
574 struct pdr_service
*tmp
;
578 if (IS_ERR_OR_NULL(pdr
) || IS_ERR_OR_NULL(pds
))
581 mutex_lock(&pdr
->list_lock
);
582 list_for_each_entry(tmp
, &pdr
->lookups
, node
) {
586 if (!pds
->service_connected
)
589 /* Prepare req message */
590 strcpy(req
.service_path
, pds
->service_path
);
594 mutex_unlock(&pdr
->list_lock
);
596 if (!req
.service_path
[0])
599 ret
= qmi_txn_init(&pdr
->notifier_hdl
, &txn
,
600 servreg_restart_pd_resp_ei
,
605 ret
= qmi_send_request(&pdr
->notifier_hdl
, &addr
,
606 &txn
, SERVREG_RESTART_PD_REQ
,
607 SERVREG_RESTART_PD_REQ_MAX_LEN
,
608 servreg_restart_pd_req_ei
, &req
);
610 qmi_txn_cancel(&txn
);
614 ret
= qmi_txn_wait(&txn
, 5 * HZ
);
616 pr_err("PDR: %s PD restart txn wait failed: %d\n",
617 req
.service_path
, ret
);
621 /* Check response if PDR is disabled */
622 if (resp
.resp
.result
== QMI_RESULT_FAILURE_V01
&&
623 resp
.resp
.error
== QMI_ERR_DISABLED_V01
) {
624 pr_err("PDR: %s PD restart is disabled: 0x%x\n",
625 req
.service_path
, resp
.resp
.error
);
629 /* Check the response for other error case*/
630 if (resp
.resp
.result
!= QMI_RESULT_SUCCESS_V01
) {
631 pr_err("PDR: %s request for PD restart failed: 0x%x\n",
632 req
.service_path
, resp
.resp
.error
);
638 EXPORT_SYMBOL(pdr_restart_pd
);
641 * pdr_handle_alloc() - initialize the PDR client handle
642 * @status: function to be called on PD state change
643 * @priv: handle for client's use
645 * Initializes the PDR client handle to allow for tracking/restart of PDs.
647 * Return: pdr_handle object on success, ERR_PTR on failure.
649 struct pdr_handle
*pdr_handle_alloc(void (*status
)(int state
,
651 void *priv
), void *priv
)
653 struct pdr_handle
*pdr
;
657 return ERR_PTR(-EINVAL
);
659 pdr
= kzalloc(sizeof(*pdr
), GFP_KERNEL
);
661 return ERR_PTR(-ENOMEM
);
663 pdr
->status
= status
;
666 mutex_init(&pdr
->status_lock
);
667 mutex_init(&pdr
->list_lock
);
668 mutex_init(&pdr
->lock
);
670 INIT_LIST_HEAD(&pdr
->lookups
);
671 INIT_LIST_HEAD(&pdr
->indack_list
);
673 INIT_WORK(&pdr
->locator_work
, pdr_locator_work
);
674 INIT_WORK(&pdr
->notifier_work
, pdr_notifier_work
);
675 INIT_WORK(&pdr
->indack_work
, pdr_indack_work
);
677 pdr
->notifier_wq
= create_singlethread_workqueue("pdr_notifier_wq");
678 if (!pdr
->notifier_wq
) {
680 goto free_pdr_handle
;
683 pdr
->indack_wq
= alloc_ordered_workqueue("pdr_indack_wq", WQ_HIGHPRI
);
684 if (!pdr
->indack_wq
) {
686 goto destroy_notifier
;
689 ret
= qmi_handle_init(&pdr
->locator_hdl
,
690 SERVREG_GET_DOMAIN_LIST_RESP_MAX_LEN
,
691 &pdr_locator_ops
, NULL
);
695 ret
= qmi_add_lookup(&pdr
->locator_hdl
, SERVREG_LOCATOR_SERVICE
, 1, 1);
697 goto release_qmi_handle
;
699 ret
= qmi_handle_init(&pdr
->notifier_hdl
,
700 SERVREG_STATE_UPDATED_IND_MAX_LEN
,
702 qmi_indication_handler
);
704 goto release_qmi_handle
;
709 qmi_handle_release(&pdr
->locator_hdl
);
711 destroy_workqueue(pdr
->indack_wq
);
713 destroy_workqueue(pdr
->notifier_wq
);
719 EXPORT_SYMBOL(pdr_handle_alloc
);
722 * pdr_handle_release() - release the PDR client handle
723 * @pdr: PDR client handle
725 * Cleans up pending tracking requests and releases the underlying qmi handles.
727 void pdr_handle_release(struct pdr_handle
*pdr
)
729 struct pdr_service
*pds
, *tmp
;
731 if (IS_ERR_OR_NULL(pdr
))
734 mutex_lock(&pdr
->list_lock
);
735 list_for_each_entry_safe(pds
, tmp
, &pdr
->lookups
, node
) {
736 list_del(&pds
->node
);
739 mutex_unlock(&pdr
->list_lock
);
741 cancel_work_sync(&pdr
->locator_work
);
742 cancel_work_sync(&pdr
->notifier_work
);
743 cancel_work_sync(&pdr
->indack_work
);
745 destroy_workqueue(pdr
->notifier_wq
);
746 destroy_workqueue(pdr
->indack_wq
);
748 qmi_handle_release(&pdr
->locator_hdl
);
749 qmi_handle_release(&pdr
->notifier_hdl
);
753 EXPORT_SYMBOL(pdr_handle_release
);
755 MODULE_LICENSE("GPL v2");
756 MODULE_DESCRIPTION("Qualcomm Protection Domain Restart helpers");