dm writecache: add cond_resched to loop in persistent_memory_claim()
[linux/fpc-iii.git] / drivers / soc / qcom / pdr_interface.c
blob17ad3b8698e16c856e78264a4370ede6b7e60c23
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2020 The Linux Foundation. All rights reserved.
4 */
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"
13 struct pdr_service {
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;
20 unsigned int service;
21 u8 service_data_valid;
22 u32 service_data;
23 int state;
25 bool need_notifier_register;
26 bool need_notifier_remove;
27 bool need_locator_lookup;
28 bool service_connected;
30 struct list_head node;
33 struct pdr_handle {
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 */
49 struct mutex lock;
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);
61 void *priv;
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;
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,
75 locator_hdl);
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);
95 return 0;
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,
102 locator_hdl);
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,
119 bool enable)
121 struct servreg_register_listener_resp resp;
122 struct servreg_register_listener_req req;
123 struct qmi_txn txn;
124 int ret;
126 ret = qmi_txn_init(&pdr->notifier_hdl, &txn,
127 servreg_register_listener_resp_ei,
128 &resp);
129 if (ret < 0)
130 return ret;
132 req.enable = enable;
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,
139 &req);
140 if (ret < 0) {
141 qmi_txn_cancel(&txn);
142 return ret;
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;
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;
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;
164 return 0;
167 static void pdr_notifier_work(struct work_struct *work)
169 struct pdr_handle *pdr = container_of(work, struct pdr_handle,
170 notifier_work);
171 struct pdr_service *pds;
172 int ret;
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)
178 continue;
180 pds->need_notifier_register = false;
181 ret = pdr_register_listener(pdr, pds, true);
182 if (ret < 0)
183 pds->state = SERVREG_SERVICE_STATE_DOWN;
184 } else {
185 if (!pds->need_notifier_remove)
186 continue;
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,
203 notifier_hdl);
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);
220 return 0;
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,
227 notifier_hdl);
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,
250 u16 tid)
252 struct servreg_set_ack_resp resp;
253 struct servreg_set_ack_req req;
254 struct qmi_txn txn;
255 int ret;
257 ret = qmi_txn_init(&pdr->notifier_hdl, &txn, servreg_set_ack_resp_ei,
258 &resp);
259 if (ret < 0)
260 return ret;
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,
269 &req);
271 /* Skip waiting for response */
272 qmi_txn_cancel(&txn);
273 return ret;
276 static void pdr_indack_work(struct work_struct *work)
278 struct pdr_handle *pdr = container_of(work, struct pdr_handle,
279 indack_work);
280 struct pdr_list_node *ind, *tmp;
281 struct pdr_service *pds;
283 list_for_each_entry_safe(ind, tmp, &pdr->indack_list, node) {
284 pds = ind->pds;
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);
296 kfree(ind);
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,
305 notifier_hdl);
306 const struct servreg_state_updated_ind *ind_msg = data;
307 struct pdr_list_node *ind;
308 struct pdr_service *pds;
309 bool found = false;
311 if (!ind_msg || !ind_msg->service_path[0] ||
312 strlen(ind_msg->service_path) > SERVREG_NAME_LENGTH)
313 return;
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))
318 continue;
320 found = true;
321 break;
323 mutex_unlock(&pdr->list_lock);
325 if (!found)
326 return;
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);
333 if (!ind)
334 return;
336 ind->transaction_id = ind_msg->transaction_id;
337 ind->curr_state = ind_msg->curr_state;
338 ind->pds = pds;
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)
362 struct qmi_txn txn;
363 int ret;
365 ret = qmi_txn_init(&pdr->locator_hdl, &txn,
366 servreg_get_domain_list_resp_ei, resp);
367 if (ret < 0)
368 return ret;
370 ret = qmi_send_request(&pdr->locator_hdl,
371 &pdr->locator_addr,
372 &txn, SERVREG_GET_DOMAIN_LIST_REQ,
373 SERVREG_GET_DOMAIN_LIST_REQ_MAX_LEN,
374 servreg_get_domain_list_req_ei,
375 req);
376 if (ret < 0) {
377 qmi_txn_cancel(&txn);
378 return ret;
381 ret = qmi_txn_wait(&txn, 5 * HZ);
382 if (ret < 0) {
383 pr_err("PDR: %s get domain list txn wait failed: %d\n",
384 req->service_name, ret);
385 return 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);
391 return -EREMOTEIO;
394 return 0;
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;
403 int ret, i;
405 resp = kzalloc(sizeof(*resp), GFP_KERNEL);
406 if (!resp)
407 return -ENOMEM;
409 /* Prepare req message */
410 strcpy(req.service_name, pds->service_name);
411 req.domain_offset_valid = true;
412 req.domain_offset = 0;
414 do {
415 req.domain_offset = domains_read;
416 ret = pdr_get_domain_list(&req, resp, pdr);
417 if (ret < 0)
418 goto out;
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))
424 continue;
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;
430 goto out;
434 /* Update ret to indicate that the service is not yet found */
435 ret = -ENXIO;
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);
443 out:
444 kfree(resp);
445 return ret;
448 static void pdr_notify_lookup_failure(struct pdr_handle *pdr,
449 struct pdr_service *pds,
450 int err)
452 pr_err("PDR: service lookup for %s failed: %d\n",
453 pds->service_name, err);
455 if (err == -ENXIO)
456 return;
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);
463 kfree(pds);
466 static void pdr_locator_work(struct work_struct *work)
468 struct pdr_handle *pdr = container_of(work, struct pdr_handle,
469 locator_work);
470 struct pdr_service *pds, *tmp;
471 int ret = 0;
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");
478 return;
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)
485 continue;
487 ret = pdr_locate_service(pdr, pds);
488 if (ret < 0) {
489 pdr_notify_lookup_failure(pdr, pds, ret);
490 continue;
493 ret = qmi_add_lookup(&pdr->notifier_hdl, pds->service, 1,
494 pds->instance);
495 if (ret < 0) {
496 pdr_notify_lookup_failure(pdr, pds, ret);
497 continue;
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;
521 int ret;
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);
531 if (!pds)
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))
542 continue;
544 mutex_unlock(&pdr->list_lock);
545 ret = -EALREADY;
546 goto err;
549 list_add(&pds->node, &pdr->lookups);
550 mutex_unlock(&pdr->list_lock);
552 schedule_work(&pdr->locator_work);
554 return pds;
555 err:
556 kfree(pds);
557 return ERR_PTR(ret);
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;
576 struct qmi_txn txn;
577 int ret;
579 if (IS_ERR_OR_NULL(pdr) || IS_ERR_OR_NULL(pds))
580 return -EINVAL;
582 mutex_lock(&pdr->list_lock);
583 list_for_each_entry(tmp, &pdr->lookups, node) {
584 if (tmp != pds)
585 continue;
587 if (!pds->service_connected)
588 break;
590 /* Prepare req message */
591 strcpy(req.service_path, pds->service_path);
592 addr = pds->addr;
593 break;
595 mutex_unlock(&pdr->list_lock);
597 if (!req.service_path[0])
598 return -EINVAL;
600 ret = qmi_txn_init(&pdr->notifier_hdl, &txn,
601 servreg_restart_pd_resp_ei,
602 &resp);
603 if (ret < 0)
604 return ret;
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);
610 if (ret < 0) {
611 qmi_txn_cancel(&txn);
612 return ret;
615 ret = qmi_txn_wait(&txn, 5 * HZ);
616 if (ret < 0) {
617 pr_err("PDR: %s PD restart txn wait failed: %d\n",
618 req.service_path, ret);
619 return 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);
627 return -EOPNOTSUPP;
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);
634 return -EREMOTEIO;
637 return 0;
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,
651 char *service_path,
652 void *priv), void *priv)
654 struct pdr_handle *pdr;
655 int ret;
657 if (!status)
658 return ERR_PTR(-EINVAL);
660 pdr = kzalloc(sizeof(*pdr), GFP_KERNEL);
661 if (!pdr)
662 return ERR_PTR(-ENOMEM);
664 pdr->status = status;
665 pdr->priv = priv;
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) {
680 ret = -ENOMEM;
681 goto free_pdr_handle;
684 pdr->indack_wq = alloc_ordered_workqueue("pdr_indack_wq", WQ_HIGHPRI);
685 if (!pdr->indack_wq) {
686 ret = -ENOMEM;
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);
693 if (ret < 0)
694 goto destroy_indack;
696 ret = qmi_add_lookup(&pdr->locator_hdl, SERVREG_LOCATOR_SERVICE, 1, 1);
697 if (ret < 0)
698 goto release_qmi_handle;
700 ret = qmi_handle_init(&pdr->notifier_hdl,
701 SERVREG_STATE_UPDATED_IND_MAX_LEN,
702 &pdr_notifier_ops,
703 qmi_indication_handler);
704 if (ret < 0)
705 goto release_qmi_handle;
707 return pdr;
709 release_qmi_handle:
710 qmi_handle_release(&pdr->locator_hdl);
711 destroy_indack:
712 destroy_workqueue(pdr->indack_wq);
713 destroy_notifier:
714 destroy_workqueue(pdr->notifier_wq);
715 free_pdr_handle:
716 kfree(pdr);
718 return ERR_PTR(ret);
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))
733 return;
735 mutex_lock(&pdr->list_lock);
736 list_for_each_entry_safe(pds, tmp, &pdr->lookups, node) {
737 list_del(&pds->node);
738 kfree(pds);
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);
752 kfree(pdr);
754 EXPORT_SYMBOL(pdr_handle_release);
756 MODULE_LICENSE("GPL v2");
757 MODULE_DESCRIPTION("Qualcomm Protection Domain Restart helpers");