pdr_interface.c 21 KB

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