xref: /openbmc/linux/drivers/soc/qcom/pdr_interface.c (revision 55fd7e02)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2020 The Linux Foundation. All rights reserved.
4  */
5 
6 #include <linux/kernel.h>
7 #include <linux/module.h>
8 #include <linux/string.h>
9 #include <linux/workqueue.h>
10 
11 #include "pdr_internal.h"
12 
13 struct pdr_service {
14 	char service_name[SERVREG_NAME_LENGTH + 1];
15 	char service_path[SERVREG_NAME_LENGTH + 1];
16 
17 	struct sockaddr_qrtr addr;
18 
19 	unsigned int instance;
20 	unsigned int service;
21 	u8 service_data_valid;
22 	u32 service_data;
23 	int state;
24 
25 	bool need_notifier_register;
26 	bool need_notifier_remove;
27 	bool need_locator_lookup;
28 	bool service_connected;
29 
30 	struct list_head node;
31 };
32 
33 struct pdr_handle {
34 	struct qmi_handle locator_hdl;
35 	struct qmi_handle notifier_hdl;
36 
37 	struct sockaddr_qrtr locator_addr;
38 
39 	struct list_head lookups;
40 	struct list_head indack_list;
41 
42 	/* control access to pdr lookup/indack lists */
43 	struct mutex list_lock;
44 
45 	/* serialize pd status invocation */
46 	struct mutex status_lock;
47 
48 	/* control access to the locator state */
49 	struct mutex lock;
50 
51 	bool locator_init_complete;
52 
53 	struct work_struct locator_work;
54 	struct work_struct notifier_work;
55 	struct work_struct indack_work;
56 
57 	struct workqueue_struct *notifier_wq;
58 	struct workqueue_struct *indack_wq;
59 
60 	void (*status)(int state, char *service_path, void *priv);
61 	void *priv;
62 };
63 
64 struct pdr_list_node {
65 	enum servreg_service_state curr_state;
66 	u16 transaction_id;
67 	struct pdr_service *pds;
68 	struct list_head node;
69 };
70 
71 static int pdr_locator_new_server(struct qmi_handle *qmi,
72 				  struct qmi_service *svc)
73 {
74 	struct pdr_handle *pdr = container_of(qmi, struct pdr_handle,
75 					      locator_hdl);
76 	struct pdr_service *pds;
77 
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;
82 
83 	mutex_lock(&pdr->lock);
84 	pdr->locator_init_complete = true;
85 	mutex_unlock(&pdr->lock);
86 
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);
92 	}
93 	mutex_unlock(&pdr->list_lock);
94 
95 	return 0;
96 }
97 
98 static void pdr_locator_del_server(struct qmi_handle *qmi,
99 				   struct qmi_service *svc)
100 {
101 	struct pdr_handle *pdr = container_of(qmi, struct pdr_handle,
102 					      locator_hdl);
103 
104 	mutex_lock(&pdr->lock);
105 	pdr->locator_init_complete = false;
106 	mutex_unlock(&pdr->lock);
107 
108 	pdr->locator_addr.sq_node = 0;
109 	pdr->locator_addr.sq_port = 0;
110 }
111 
112 static struct qmi_ops pdr_locator_ops = {
113 	.new_server = pdr_locator_new_server,
114 	.del_server = pdr_locator_del_server,
115 };
116 
117 static int pdr_register_listener(struct pdr_handle *pdr,
118 				 struct pdr_service *pds,
119 				 bool enable)
120 {
121 	struct servreg_register_listener_resp resp;
122 	struct servreg_register_listener_req req;
123 	struct qmi_txn txn;
124 	int ret;
125 
126 	ret = qmi_txn_init(&pdr->notifier_hdl, &txn,
127 			   servreg_register_listener_resp_ei,
128 			   &resp);
129 	if (ret < 0)
130 		return ret;
131 
132 	req.enable = enable;
133 	strcpy(req.service_path, pds->service_path);
134 
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,
139 			       &req);
140 	if (ret < 0) {
141 		qmi_txn_cancel(&txn);
142 		return ret;
143 	}
144 
145 	ret = qmi_txn_wait(&txn, 5 * HZ);
146 	if (ret < 0) {
147 		pr_err("PDR: %s register listener txn wait failed: %d\n",
148 		       pds->service_path, ret);
149 		return ret;
150 	}
151 
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);
155 		return ret;
156 	}
157 
158 	pds->state = resp.curr_state;
159 
160 	return 0;
161 }
162 
163 static void pdr_notifier_work(struct work_struct *work)
164 {
165 	struct pdr_handle *pdr = container_of(work, struct pdr_handle,
166 					      notifier_work);
167 	struct pdr_service *pds;
168 	int ret;
169 
170 	mutex_lock(&pdr->list_lock);
171 	list_for_each_entry(pds, &pdr->lookups, node) {
172 		if (pds->service_connected) {
173 			if (!pds->need_notifier_register)
174 				continue;
175 
176 			pds->need_notifier_register = false;
177 			ret = pdr_register_listener(pdr, pds, true);
178 			if (ret < 0)
179 				pds->state = SERVREG_SERVICE_STATE_DOWN;
180 		} else {
181 			if (!pds->need_notifier_remove)
182 				continue;
183 
184 			pds->need_notifier_remove = false;
185 			pds->state = SERVREG_SERVICE_STATE_DOWN;
186 		}
187 
188 		mutex_lock(&pdr->status_lock);
189 		pdr->status(pds->state, pds->service_path, pdr->priv);
190 		mutex_unlock(&pdr->status_lock);
191 	}
192 	mutex_unlock(&pdr->list_lock);
193 }
194 
195 static int pdr_notifier_new_server(struct qmi_handle *qmi,
196 				   struct qmi_service *svc)
197 {
198 	struct pdr_handle *pdr = container_of(qmi, struct pdr_handle,
199 					      notifier_hdl);
200 	struct pdr_service *pds;
201 
202 	mutex_lock(&pdr->list_lock);
203 	list_for_each_entry(pds, &pdr->lookups, node) {
204 		if (pds->service == svc->service &&
205 		    pds->instance == svc->instance) {
206 			pds->service_connected = true;
207 			pds->need_notifier_register = true;
208 			pds->addr.sq_family = AF_QIPCRTR;
209 			pds->addr.sq_node = svc->node;
210 			pds->addr.sq_port = svc->port;
211 			queue_work(pdr->notifier_wq, &pdr->notifier_work);
212 		}
213 	}
214 	mutex_unlock(&pdr->list_lock);
215 
216 	return 0;
217 }
218 
219 static void pdr_notifier_del_server(struct qmi_handle *qmi,
220 				    struct qmi_service *svc)
221 {
222 	struct pdr_handle *pdr = container_of(qmi, struct pdr_handle,
223 					      notifier_hdl);
224 	struct pdr_service *pds;
225 
226 	mutex_lock(&pdr->list_lock);
227 	list_for_each_entry(pds, &pdr->lookups, node) {
228 		if (pds->service == svc->service &&
229 		    pds->instance == svc->instance) {
230 			pds->service_connected = false;
231 			pds->need_notifier_remove = true;
232 			pds->addr.sq_node = 0;
233 			pds->addr.sq_port = 0;
234 			queue_work(pdr->notifier_wq, &pdr->notifier_work);
235 		}
236 	}
237 	mutex_unlock(&pdr->list_lock);
238 }
239 
240 static struct qmi_ops pdr_notifier_ops = {
241 	.new_server = pdr_notifier_new_server,
242 	.del_server = pdr_notifier_del_server,
243 };
244 
245 static int pdr_send_indack_msg(struct pdr_handle *pdr, struct pdr_service *pds,
246 			       u16 tid)
247 {
248 	struct servreg_set_ack_resp resp;
249 	struct servreg_set_ack_req req;
250 	struct qmi_txn txn;
251 	int ret;
252 
253 	ret = qmi_txn_init(&pdr->notifier_hdl, &txn, servreg_set_ack_resp_ei,
254 			   &resp);
255 	if (ret < 0)
256 		return ret;
257 
258 	req.transaction_id = tid;
259 	strcpy(req.service_path, pds->service_path);
260 
261 	ret = qmi_send_request(&pdr->notifier_hdl, &pds->addr,
262 			       &txn, SERVREG_SET_ACK_REQ,
263 			       SERVREG_SET_ACK_REQ_LEN,
264 			       servreg_set_ack_req_ei,
265 			       &req);
266 
267 	/* Skip waiting for response */
268 	qmi_txn_cancel(&txn);
269 	return ret;
270 }
271 
272 static void pdr_indack_work(struct work_struct *work)
273 {
274 	struct pdr_handle *pdr = container_of(work, struct pdr_handle,
275 					      indack_work);
276 	struct pdr_list_node *ind, *tmp;
277 	struct pdr_service *pds;
278 
279 	list_for_each_entry_safe(ind, tmp, &pdr->indack_list, node) {
280 		pds = ind->pds;
281 		pdr_send_indack_msg(pdr, pds, ind->transaction_id);
282 
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);
287 
288 		mutex_lock(&pdr->list_lock);
289 		list_del(&ind->node);
290 		mutex_unlock(&pdr->list_lock);
291 
292 		kfree(ind);
293 	}
294 }
295 
296 static void pdr_indication_cb(struct qmi_handle *qmi,
297 			      struct sockaddr_qrtr *sq,
298 			      struct qmi_txn *txn, const void *data)
299 {
300 	struct pdr_handle *pdr = container_of(qmi, struct pdr_handle,
301 					      notifier_hdl);
302 	const struct servreg_state_updated_ind *ind_msg = data;
303 	struct pdr_list_node *ind;
304 	struct pdr_service *pds;
305 	bool found = false;
306 
307 	if (!ind_msg || !ind_msg->service_path[0] ||
308 	    strlen(ind_msg->service_path) > SERVREG_NAME_LENGTH)
309 		return;
310 
311 	mutex_lock(&pdr->list_lock);
312 	list_for_each_entry(pds, &pdr->lookups, node) {
313 		if (strcmp(pds->service_path, ind_msg->service_path))
314 			continue;
315 
316 		found = true;
317 		break;
318 	}
319 	mutex_unlock(&pdr->list_lock);
320 
321 	if (!found)
322 		return;
323 
324 	pr_info("PDR: Indication received from %s, state: 0x%x, trans-id: %d\n",
325 		ind_msg->service_path, ind_msg->curr_state,
326 		ind_msg->transaction_id);
327 
328 	ind = kzalloc(sizeof(*ind), GFP_KERNEL);
329 	if (!ind)
330 		return;
331 
332 	ind->transaction_id = ind_msg->transaction_id;
333 	ind->curr_state = ind_msg->curr_state;
334 	ind->pds = pds;
335 
336 	mutex_lock(&pdr->list_lock);
337 	list_add_tail(&ind->node, &pdr->indack_list);
338 	mutex_unlock(&pdr->list_lock);
339 
340 	queue_work(pdr->indack_wq, &pdr->indack_work);
341 }
342 
343 static struct qmi_msg_handler qmi_indication_handler[] = {
344 	{
345 		.type = QMI_INDICATION,
346 		.msg_id = SERVREG_STATE_UPDATED_IND_ID,
347 		.ei = servreg_state_updated_ind_ei,
348 		.decoded_size = sizeof(struct servreg_state_updated_ind),
349 		.fn = pdr_indication_cb,
350 	},
351 	{}
352 };
353 
354 static int pdr_get_domain_list(struct servreg_get_domain_list_req *req,
355 			       struct servreg_get_domain_list_resp *resp,
356 			       struct pdr_handle *pdr)
357 {
358 	struct qmi_txn txn;
359 	int ret;
360 
361 	ret = qmi_txn_init(&pdr->locator_hdl, &txn,
362 			   servreg_get_domain_list_resp_ei, resp);
363 	if (ret < 0)
364 		return ret;
365 
366 	ret = qmi_send_request(&pdr->locator_hdl,
367 			       &pdr->locator_addr,
368 			       &txn, SERVREG_GET_DOMAIN_LIST_REQ,
369 			       SERVREG_GET_DOMAIN_LIST_REQ_MAX_LEN,
370 			       servreg_get_domain_list_req_ei,
371 			       req);
372 	if (ret < 0) {
373 		qmi_txn_cancel(&txn);
374 		return ret;
375 	}
376 
377 	ret = qmi_txn_wait(&txn, 5 * HZ);
378 	if (ret < 0) {
379 		pr_err("PDR: %s get domain list txn wait failed: %d\n",
380 		       req->service_name, ret);
381 		return ret;
382 	}
383 
384 	if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
385 		pr_err("PDR: %s get domain list failed: 0x%x\n",
386 		       req->service_name, resp->resp.error);
387 		return -EREMOTEIO;
388 	}
389 
390 	return 0;
391 }
392 
393 static int pdr_locate_service(struct pdr_handle *pdr, struct pdr_service *pds)
394 {
395 	struct servreg_get_domain_list_resp *resp;
396 	struct servreg_get_domain_list_req req;
397 	struct servreg_location_entry *entry;
398 	int domains_read = 0;
399 	int ret, i;
400 
401 	resp = kzalloc(sizeof(*resp), GFP_KERNEL);
402 	if (!resp)
403 		return -ENOMEM;
404 
405 	/* Prepare req message */
406 	strcpy(req.service_name, pds->service_name);
407 	req.domain_offset_valid = true;
408 	req.domain_offset = 0;
409 
410 	do {
411 		req.domain_offset = domains_read;
412 		ret = pdr_get_domain_list(&req, resp, pdr);
413 		if (ret < 0)
414 			goto out;
415 
416 		for (i = domains_read; i < resp->domain_list_len; i++) {
417 			entry = &resp->domain_list[i];
418 
419 			if (strnlen(entry->name, sizeof(entry->name)) == sizeof(entry->name))
420 				continue;
421 
422 			if (!strcmp(entry->name, pds->service_path)) {
423 				pds->service_data_valid = entry->service_data_valid;
424 				pds->service_data = entry->service_data;
425 				pds->instance = entry->instance;
426 				goto out;
427 			}
428 		}
429 
430 		/* Update ret to indicate that the service is not yet found */
431 		ret = -ENXIO;
432 
433 		/* Always read total_domains from the response msg */
434 		if (resp->domain_list_len > resp->total_domains)
435 			resp->domain_list_len = resp->total_domains;
436 
437 		domains_read += resp->domain_list_len;
438 	} while (domains_read < resp->total_domains);
439 out:
440 	kfree(resp);
441 	return ret;
442 }
443 
444 static void pdr_notify_lookup_failure(struct pdr_handle *pdr,
445 				      struct pdr_service *pds,
446 				      int err)
447 {
448 	pr_err("PDR: service lookup for %s failed: %d\n",
449 	       pds->service_name, err);
450 
451 	if (err == -ENXIO)
452 		return;
453 
454 	list_del(&pds->node);
455 	pds->state = SERVREG_LOCATOR_ERR;
456 	mutex_lock(&pdr->status_lock);
457 	pdr->status(pds->state, pds->service_path, pdr->priv);
458 	mutex_unlock(&pdr->status_lock);
459 	kfree(pds);
460 }
461 
462 static void pdr_locator_work(struct work_struct *work)
463 {
464 	struct pdr_handle *pdr = container_of(work, struct pdr_handle,
465 					      locator_work);
466 	struct pdr_service *pds, *tmp;
467 	int ret = 0;
468 
469 	/* Bail out early if the SERVREG LOCATOR QMI service is not up */
470 	mutex_lock(&pdr->lock);
471 	if (!pdr->locator_init_complete) {
472 		mutex_unlock(&pdr->lock);
473 		pr_debug("PDR: SERVICE LOCATOR service not available\n");
474 		return;
475 	}
476 	mutex_unlock(&pdr->lock);
477 
478 	mutex_lock(&pdr->list_lock);
479 	list_for_each_entry_safe(pds, tmp, &pdr->lookups, node) {
480 		if (!pds->need_locator_lookup)
481 			continue;
482 
483 		ret = pdr_locate_service(pdr, pds);
484 		if (ret < 0) {
485 			pdr_notify_lookup_failure(pdr, pds, ret);
486 			continue;
487 		}
488 
489 		ret = qmi_add_lookup(&pdr->notifier_hdl, pds->service, 1,
490 				     pds->instance);
491 		if (ret < 0) {
492 			pdr_notify_lookup_failure(pdr, pds, ret);
493 			continue;
494 		}
495 
496 		pds->need_locator_lookup = false;
497 	}
498 	mutex_unlock(&pdr->list_lock);
499 }
500 
501 /**
502  * pdr_add_lookup() - register a tracking request for a PD
503  * @pdr:		PDR client handle
504  * @service_name:	service name of the tracking request
505  * @service_path:	service path of the tracking request
506  *
507  * Registering a pdr lookup allows for tracking the life cycle of the PD.
508  *
509  * Return: pdr_service object on success, ERR_PTR on failure. -EALREADY is
510  * returned if a lookup is already in progress for the given service path.
511  */
512 struct pdr_service *pdr_add_lookup(struct pdr_handle *pdr,
513 				   const char *service_name,
514 				   const char *service_path)
515 {
516 	struct pdr_service *pds, *tmp;
517 	int ret;
518 
519 	if (IS_ERR_OR_NULL(pdr))
520 		return ERR_PTR(-EINVAL);
521 
522 	if (!service_name || strlen(service_name) > SERVREG_NAME_LENGTH ||
523 	    !service_path || strlen(service_path) > SERVREG_NAME_LENGTH)
524 		return ERR_PTR(-EINVAL);
525 
526 	pds = kzalloc(sizeof(*pds), GFP_KERNEL);
527 	if (!pds)
528 		return ERR_PTR(-ENOMEM);
529 
530 	pds->service = SERVREG_NOTIFIER_SERVICE;
531 	strcpy(pds->service_name, service_name);
532 	strcpy(pds->service_path, service_path);
533 	pds->need_locator_lookup = true;
534 
535 	mutex_lock(&pdr->list_lock);
536 	list_for_each_entry(tmp, &pdr->lookups, node) {
537 		if (strcmp(tmp->service_path, service_path))
538 			continue;
539 
540 		mutex_unlock(&pdr->list_lock);
541 		ret = -EALREADY;
542 		goto err;
543 	}
544 
545 	list_add(&pds->node, &pdr->lookups);
546 	mutex_unlock(&pdr->list_lock);
547 
548 	schedule_work(&pdr->locator_work);
549 
550 	return pds;
551 err:
552 	kfree(pds);
553 	return ERR_PTR(ret);
554 }
555 EXPORT_SYMBOL(pdr_add_lookup);
556 
557 /**
558  * pdr_restart_pd() - restart PD
559  * @pdr:	PDR client handle
560  * @pds:	PD service handle
561  *
562  * Restarts the PD tracked by the PDR client handle for a given service path.
563  *
564  * Return: 0 on success, negative errno on failure.
565  */
566 int pdr_restart_pd(struct pdr_handle *pdr, struct pdr_service *pds)
567 {
568 	struct servreg_restart_pd_resp resp;
569 	struct servreg_restart_pd_req req;
570 	struct sockaddr_qrtr addr;
571 	struct pdr_service *tmp;
572 	struct qmi_txn txn;
573 	int ret;
574 
575 	if (IS_ERR_OR_NULL(pdr) || IS_ERR_OR_NULL(pds))
576 		return -EINVAL;
577 
578 	mutex_lock(&pdr->list_lock);
579 	list_for_each_entry(tmp, &pdr->lookups, node) {
580 		if (tmp != pds)
581 			continue;
582 
583 		if (!pds->service_connected)
584 			break;
585 
586 		/* Prepare req message */
587 		strcpy(req.service_path, pds->service_path);
588 		addr = pds->addr;
589 		break;
590 	}
591 	mutex_unlock(&pdr->list_lock);
592 
593 	if (!req.service_path[0])
594 		return -EINVAL;
595 
596 	ret = qmi_txn_init(&pdr->notifier_hdl, &txn,
597 			   servreg_restart_pd_resp_ei,
598 			   &resp);
599 	if (ret < 0)
600 		return ret;
601 
602 	ret = qmi_send_request(&pdr->notifier_hdl, &addr,
603 			       &txn, SERVREG_RESTART_PD_REQ,
604 			       SERVREG_RESTART_PD_REQ_MAX_LEN,
605 			       servreg_restart_pd_req_ei, &req);
606 	if (ret < 0) {
607 		qmi_txn_cancel(&txn);
608 		return ret;
609 	}
610 
611 	ret = qmi_txn_wait(&txn, 5 * HZ);
612 	if (ret < 0) {
613 		pr_err("PDR: %s PD restart txn wait failed: %d\n",
614 		       req.service_path, ret);
615 		return ret;
616 	}
617 
618 	/* Check response if PDR is disabled */
619 	if (resp.resp.result == QMI_RESULT_FAILURE_V01 &&
620 	    resp.resp.error == QMI_ERR_DISABLED_V01) {
621 		pr_err("PDR: %s PD restart is disabled: 0x%x\n",
622 		       req.service_path, resp.resp.error);
623 		return -EOPNOTSUPP;
624 	}
625 
626 	/* Check the response for other error case*/
627 	if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
628 		pr_err("PDR: %s request for PD restart failed: 0x%x\n",
629 		       req.service_path, resp.resp.error);
630 		return -EREMOTEIO;
631 	}
632 
633 	return 0;
634 }
635 EXPORT_SYMBOL(pdr_restart_pd);
636 
637 /**
638  * pdr_handle_alloc() - initialize the PDR client handle
639  * @status:	function to be called on PD state change
640  * @priv:	handle for client's use
641  *
642  * Initializes the PDR client handle to allow for tracking/restart of PDs.
643  *
644  * Return: pdr_handle object on success, ERR_PTR on failure.
645  */
646 struct pdr_handle *pdr_handle_alloc(void (*status)(int state,
647 						   char *service_path,
648 						   void *priv), void *priv)
649 {
650 	struct pdr_handle *pdr;
651 	int ret;
652 
653 	if (!status)
654 		return ERR_PTR(-EINVAL);
655 
656 	pdr = kzalloc(sizeof(*pdr), GFP_KERNEL);
657 	if (!pdr)
658 		return ERR_PTR(-ENOMEM);
659 
660 	pdr->status = status;
661 	pdr->priv = priv;
662 
663 	mutex_init(&pdr->status_lock);
664 	mutex_init(&pdr->list_lock);
665 	mutex_init(&pdr->lock);
666 
667 	INIT_LIST_HEAD(&pdr->lookups);
668 	INIT_LIST_HEAD(&pdr->indack_list);
669 
670 	INIT_WORK(&pdr->locator_work, pdr_locator_work);
671 	INIT_WORK(&pdr->notifier_work, pdr_notifier_work);
672 	INIT_WORK(&pdr->indack_work, pdr_indack_work);
673 
674 	pdr->notifier_wq = create_singlethread_workqueue("pdr_notifier_wq");
675 	if (!pdr->notifier_wq) {
676 		ret = -ENOMEM;
677 		goto free_pdr_handle;
678 	}
679 
680 	pdr->indack_wq = alloc_ordered_workqueue("pdr_indack_wq", WQ_HIGHPRI);
681 	if (!pdr->indack_wq) {
682 		ret = -ENOMEM;
683 		goto destroy_notifier;
684 	}
685 
686 	ret = qmi_handle_init(&pdr->locator_hdl,
687 			      SERVREG_GET_DOMAIN_LIST_RESP_MAX_LEN,
688 			      &pdr_locator_ops, NULL);
689 	if (ret < 0)
690 		goto destroy_indack;
691 
692 	ret = qmi_add_lookup(&pdr->locator_hdl, SERVREG_LOCATOR_SERVICE, 1, 1);
693 	if (ret < 0)
694 		goto release_qmi_handle;
695 
696 	ret = qmi_handle_init(&pdr->notifier_hdl,
697 			      SERVREG_STATE_UPDATED_IND_MAX_LEN,
698 			      &pdr_notifier_ops,
699 			      qmi_indication_handler);
700 	if (ret < 0)
701 		goto release_qmi_handle;
702 
703 	return pdr;
704 
705 release_qmi_handle:
706 	qmi_handle_release(&pdr->locator_hdl);
707 destroy_indack:
708 	destroy_workqueue(pdr->indack_wq);
709 destroy_notifier:
710 	destroy_workqueue(pdr->notifier_wq);
711 free_pdr_handle:
712 	kfree(pdr);
713 
714 	return ERR_PTR(ret);
715 }
716 EXPORT_SYMBOL(pdr_handle_alloc);
717 
718 /**
719  * pdr_handle_release() - release the PDR client handle
720  * @pdr:	PDR client handle
721  *
722  * Cleans up pending tracking requests and releases the underlying qmi handles.
723  */
724 void pdr_handle_release(struct pdr_handle *pdr)
725 {
726 	struct pdr_service *pds, *tmp;
727 
728 	if (IS_ERR_OR_NULL(pdr))
729 		return;
730 
731 	mutex_lock(&pdr->list_lock);
732 	list_for_each_entry_safe(pds, tmp, &pdr->lookups, node) {
733 		list_del(&pds->node);
734 		kfree(pds);
735 	}
736 	mutex_unlock(&pdr->list_lock);
737 
738 	cancel_work_sync(&pdr->locator_work);
739 	cancel_work_sync(&pdr->notifier_work);
740 	cancel_work_sync(&pdr->indack_work);
741 
742 	destroy_workqueue(pdr->notifier_wq);
743 	destroy_workqueue(pdr->indack_wq);
744 
745 	qmi_handle_release(&pdr->locator_hdl);
746 	qmi_handle_release(&pdr->notifier_hdl);
747 
748 	kfree(pdr);
749 }
750 EXPORT_SYMBOL(pdr_handle_release);
751 
752 MODULE_LICENSE("GPL v2");
753 MODULE_DESCRIPTION("Qualcomm Protection Domain Restart helpers");
754