genpool.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */
  3. #include <linux/genalloc.h>
  4. #include <linux/mailbox_client.h>
  5. #include <linux/module.h>
  6. #include <linux/of_device.h>
  7. #include <linux/of_irq.h>
  8. #include <linux/platform_device.h>
  9. #include <linux/sizes.h>
  10. #include <linux/skbuff.h>
  11. #include <linux/types.h>
  12. #include "qrtr.h"
  13. #define MAX_PKT_SZ SZ_64K
  14. #define LABEL_SIZE 32
  15. #define FIFO_FULL_RESERVE 8
  16. #define FIFO_SIZE 0x4000
  17. #define HDR_KEY_VALUE 0xdead
  18. #define MAGIC_KEY_VALUE 0x24495043 /* "$IPC" */
  19. #define MAGIC_KEY 0x0
  20. #define BUFFER_SIZE 0x4
  21. #define FIFO_0_START_OFFSET 0x1000
  22. #define FIFO_0_BASE 0x8
  23. #define FIFO_0_SIZE 0xc
  24. #define FIFO_0_TAIL 0x10
  25. #define FIFO_0_HEAD 0x14
  26. #define FIFO_0_NOTIFY 0x18
  27. #define FIFO_1_START_OFFSET (FIFO_0_START_OFFSET + FIFO_SIZE)
  28. #define FIFO_1_BASE 0x1c
  29. #define FIFO_1_SIZE 0x20
  30. #define FIFO_1_TAIL 0x24
  31. #define FIFO_1_HEAD 0x28
  32. #define FIFO_1_NOTIFY 0x2c
  33. #define IRQ_SETUP_IDX 0
  34. #define IRQ_XFER_IDX 1
  35. struct qrtr_genpool_hdr {
  36. __le16 len;
  37. __le16 magic;
  38. };
  39. struct qrtr_genpool_ring {
  40. void *buf;
  41. size_t len;
  42. u32 offset;
  43. };
  44. struct qrtr_genpool_pipe {
  45. __le32 *tail;
  46. __le32 *head;
  47. __le32 *read_notify;
  48. void *fifo;
  49. size_t length;
  50. };
  51. /**
  52. * qrtr_genpool_dev - qrtr genpool fifo transport structure
  53. * @ep: qrtr endpoint specific info.
  54. * @ep_registered: tracks the registration state of the qrtr endpoint.
  55. * @dev: device from platform_device.
  56. * @label: label of the edge on the other side.
  57. * @ring: buf for reading from fifo.
  58. * @rx_pipe: RX genpool fifo specific info.
  59. * @tx_pipe: TX genpool fifo specific info.
  60. * @tx_avail_notify: wait queue for available tx.
  61. * @base: base of the shared fifo.
  62. * @size: fifo size.
  63. * @mbox_client: mailbox client signaling.
  64. * @mbox_setup_chan: mailbox channel for setup.
  65. * @mbox_xfer_chan: mailbox channel for transfers.
  66. * @irq_setup: IRQ for signaling completion of fifo setup.
  67. * @setup_work: worker to maintain shared memory between edges.
  68. * @irq_xfer: IRQ for incoming transfers.
  69. */
  70. struct qrtr_genpool_dev {
  71. struct qrtr_endpoint ep;
  72. bool ep_registered;
  73. struct device *dev;
  74. const char *label;
  75. struct qrtr_genpool_ring ring;
  76. struct qrtr_genpool_pipe rx_pipe;
  77. struct qrtr_genpool_pipe tx_pipe;
  78. wait_queue_head_t tx_avail_notify;
  79. struct gen_pool *pool;
  80. dma_addr_t dma_addr;
  81. void *base;
  82. size_t size;
  83. struct mbox_client mbox_client;
  84. struct mbox_chan *mbox_setup_chan;
  85. struct mbox_chan *mbox_xfer_chan;
  86. int irq_setup;
  87. char irq_setup_label[LABEL_SIZE];
  88. struct work_struct setup_work;
  89. int irq_xfer;
  90. char irq_xfer_label[LABEL_SIZE];
  91. };
  92. static void qrtr_genpool_signal(struct qrtr_genpool_dev *qdev,
  93. struct mbox_chan *mbox_chan)
  94. {
  95. mbox_send_message(mbox_chan, NULL);
  96. mbox_client_txdone(mbox_chan, 0);
  97. }
  98. static void qrtr_genpool_signal_setup(struct qrtr_genpool_dev *qdev)
  99. {
  100. qrtr_genpool_signal(qdev, qdev->mbox_setup_chan);
  101. }
  102. static void qrtr_genpool_signal_xfer(struct qrtr_genpool_dev *qdev)
  103. {
  104. qrtr_genpool_signal(qdev, qdev->mbox_xfer_chan);
  105. }
  106. static void qrtr_genpool_tx_write(struct qrtr_genpool_pipe *pipe, const void *data,
  107. size_t count)
  108. {
  109. size_t len;
  110. u32 head;
  111. head = le32_to_cpu(*pipe->head);
  112. len = min_t(size_t, count, pipe->length - head);
  113. if (len)
  114. memcpy_toio(pipe->fifo + head, data, len);
  115. if (len != count)
  116. memcpy_toio(pipe->fifo, data + len, count - len);
  117. head += count;
  118. if (head >= pipe->length)
  119. head %= pipe->length;
  120. /* Ensure ordering of fifo and head update */
  121. smp_wmb();
  122. *pipe->head = cpu_to_le32(head);
  123. }
  124. static void qrtr_genpool_clr_tx_notify(struct qrtr_genpool_dev *qdev)
  125. {
  126. *qdev->tx_pipe.read_notify = 0;
  127. }
  128. static void qrtr_genpool_set_tx_notify(struct qrtr_genpool_dev *qdev)
  129. {
  130. *qdev->tx_pipe.read_notify = cpu_to_le32(1);
  131. }
  132. static size_t qrtr_genpool_tx_avail(struct qrtr_genpool_pipe *pipe)
  133. {
  134. u32 avail;
  135. u32 head;
  136. u32 tail;
  137. head = le32_to_cpu(*pipe->head);
  138. tail = le32_to_cpu(*pipe->tail);
  139. if (tail <= head)
  140. avail = pipe->length - head + tail;
  141. else
  142. avail = tail - head;
  143. if (avail < FIFO_FULL_RESERVE)
  144. avail = 0;
  145. else
  146. avail -= FIFO_FULL_RESERVE;
  147. return avail;
  148. }
  149. static void qrtr_genpool_wait_for_tx_avail(struct qrtr_genpool_dev *qdev)
  150. {
  151. qrtr_genpool_set_tx_notify(qdev);
  152. wait_event_timeout(qdev->tx_avail_notify,
  153. qrtr_genpool_tx_avail(&qdev->tx_pipe), 10 * HZ);
  154. }
  155. static void qrtr_genpool_generate_hdr(struct qrtr_genpool_dev *qdev,
  156. struct qrtr_genpool_hdr *hdr)
  157. {
  158. size_t hdr_len = sizeof(*hdr);
  159. while (qrtr_genpool_tx_avail(&qdev->tx_pipe) < hdr_len)
  160. qrtr_genpool_wait_for_tx_avail(qdev);
  161. qrtr_genpool_tx_write(&qdev->tx_pipe, hdr, hdr_len);
  162. };
  163. /* from qrtr to genpool fifo */
  164. static int qrtr_genpool_send(struct qrtr_endpoint *ep, struct sk_buff *skb)
  165. {
  166. struct qrtr_genpool_dev *qdev;
  167. struct qrtr_genpool_hdr hdr;
  168. size_t tx_avail;
  169. int chunk_size;
  170. int left_size;
  171. int offset;
  172. int rc;
  173. qdev = container_of(ep, struct qrtr_genpool_dev, ep);
  174. rc = skb_linearize(skb);
  175. if (rc) {
  176. kfree_skb(skb);
  177. return rc;
  178. }
  179. hdr.len = cpu_to_le16(skb->len);
  180. hdr.magic = cpu_to_le16(HDR_KEY_VALUE);
  181. qrtr_genpool_generate_hdr(qdev, &hdr);
  182. left_size = skb->len;
  183. offset = 0;
  184. while (left_size > 0) {
  185. tx_avail = qrtr_genpool_tx_avail(&qdev->tx_pipe);
  186. if (!tx_avail) {
  187. qrtr_genpool_wait_for_tx_avail(qdev);
  188. continue;
  189. }
  190. if (tx_avail < left_size)
  191. chunk_size = tx_avail;
  192. else
  193. chunk_size = left_size;
  194. qrtr_genpool_tx_write(&qdev->tx_pipe, skb->data + offset,
  195. chunk_size);
  196. offset += chunk_size;
  197. left_size -= chunk_size;
  198. qrtr_genpool_signal_xfer(qdev);
  199. }
  200. qrtr_genpool_clr_tx_notify(qdev);
  201. kfree_skb(skb);
  202. return 0;
  203. }
  204. static size_t qrtr_genpool_rx_avail(struct qrtr_genpool_pipe *pipe)
  205. {
  206. size_t len;
  207. u32 head;
  208. u32 tail;
  209. head = le32_to_cpu(*pipe->head);
  210. tail = le32_to_cpu(*pipe->tail);
  211. if (head < tail)
  212. len = pipe->length - tail + head;
  213. else
  214. len = head - tail;
  215. if (WARN_ON_ONCE(len > pipe->length))
  216. len = 0;
  217. return len;
  218. }
  219. static void qrtr_genpool_rx_advance(struct qrtr_genpool_pipe *pipe, size_t count)
  220. {
  221. u32 tail;
  222. tail = le32_to_cpu(*pipe->tail);
  223. tail += count;
  224. if (tail >= pipe->length)
  225. tail %= pipe->length;
  226. *pipe->tail = cpu_to_le32(tail);
  227. }
  228. static void qrtr_genpool_rx_peak(struct qrtr_genpool_pipe *pipe, void *data,
  229. unsigned int offset, size_t count)
  230. {
  231. size_t len;
  232. u32 tail;
  233. tail = le32_to_cpu(*pipe->tail);
  234. tail += offset;
  235. if (tail >= pipe->length)
  236. tail %= pipe->length;
  237. len = min_t(size_t, count, pipe->length - tail);
  238. if (len)
  239. memcpy_fromio(data, pipe->fifo + tail, len);
  240. if (len != count)
  241. memcpy_fromio(data + len, pipe->fifo, count - len);
  242. }
  243. static bool qrtr_genpool_get_read_notify(struct qrtr_genpool_dev *qdev)
  244. {
  245. return le32_to_cpu(*qdev->rx_pipe.read_notify);
  246. }
  247. static void qrtr_genpool_read_new(struct qrtr_genpool_dev *qdev)
  248. {
  249. struct qrtr_genpool_ring *ring = &qdev->ring;
  250. struct qrtr_genpool_hdr hdr = {0, 0};
  251. size_t rx_avail;
  252. size_t pkt_len;
  253. size_t hdr_len;
  254. int rc;
  255. /* copy hdr from rx_pipe and check hdr for pkt size */
  256. hdr_len = sizeof(hdr);
  257. qrtr_genpool_rx_peak(&qdev->rx_pipe, &hdr, 0, hdr_len);
  258. pkt_len = le16_to_cpu(hdr.len);
  259. if (pkt_len > MAX_PKT_SZ) {
  260. dev_err(qdev->dev, "invalid pkt_len %zu\n", pkt_len);
  261. return;
  262. }
  263. qrtr_genpool_rx_advance(&qdev->rx_pipe, hdr_len);
  264. rx_avail = qrtr_genpool_rx_avail(&qdev->rx_pipe);
  265. if (rx_avail > pkt_len)
  266. rx_avail = pkt_len;
  267. qrtr_genpool_rx_peak(&qdev->rx_pipe, ring->buf, 0, rx_avail);
  268. qrtr_genpool_rx_advance(&qdev->rx_pipe, rx_avail);
  269. if (rx_avail == pkt_len) {
  270. rc = qrtr_endpoint_post(&qdev->ep, ring->buf, pkt_len);
  271. if (rc == -EINVAL)
  272. dev_err(qdev->dev, "invalid ipcrouter packet\n");
  273. } else {
  274. ring->len = pkt_len;
  275. ring->offset = rx_avail;
  276. }
  277. }
  278. static void qrtr_genpool_read_frag(struct qrtr_genpool_dev *qdev)
  279. {
  280. struct qrtr_genpool_ring *ring = &qdev->ring;
  281. size_t rx_avail;
  282. int rc;
  283. rx_avail = qrtr_genpool_rx_avail(&qdev->rx_pipe);
  284. if (rx_avail + ring->offset > ring->len)
  285. rx_avail = ring->len - ring->offset;
  286. qrtr_genpool_rx_peak(&qdev->rx_pipe, ring->buf + ring->offset, 0, rx_avail);
  287. qrtr_genpool_rx_advance(&qdev->rx_pipe, rx_avail);
  288. if (rx_avail + ring->offset == ring->len) {
  289. rc = qrtr_endpoint_post(&qdev->ep, ring->buf, ring->len);
  290. if (rc == -EINVAL)
  291. dev_err(qdev->dev, "invalid ipcrouter packet\n");
  292. ring->offset = 0;
  293. ring->len = 0;
  294. } else {
  295. ring->offset += rx_avail;
  296. }
  297. }
  298. static void qrtr_genpool_read(struct qrtr_genpool_dev *qdev)
  299. {
  300. wake_up_all(&qdev->tx_avail_notify);
  301. while (qrtr_genpool_rx_avail(&qdev->rx_pipe)) {
  302. if (qdev->ring.offset)
  303. qrtr_genpool_read_frag(qdev);
  304. else
  305. qrtr_genpool_read_new(qdev);
  306. if (qrtr_genpool_get_read_notify(qdev))
  307. qrtr_genpool_signal_xfer(qdev);
  308. }
  309. }
  310. static void qrtr_genpool_memory_free(struct qrtr_genpool_dev *qdev)
  311. {
  312. if (!qdev->base)
  313. return;
  314. gen_pool_free(qdev->pool, (unsigned long)qdev->base, qdev->size);
  315. qdev->base = NULL;
  316. qdev->dma_addr = 0;
  317. qdev->size = 0;
  318. }
  319. static int qrtr_genpool_memory_alloc(struct qrtr_genpool_dev *qdev)
  320. {
  321. qdev->size = gen_pool_size(qdev->pool);
  322. qdev->base = gen_pool_dma_alloc(qdev->pool, qdev->size, &qdev->dma_addr);
  323. if (!qdev->base) {
  324. dev_err(qdev->dev, "failed to dma alloc\n");
  325. return -ENOMEM;
  326. }
  327. return 0;
  328. }
  329. static irqreturn_t qrtr_genpool_setup_intr(int irq, void *data)
  330. {
  331. struct qrtr_genpool_dev *qdev = data;
  332. schedule_work(&qdev->setup_work);
  333. return IRQ_HANDLED;
  334. }
  335. static irqreturn_t qrtr_genpool_xfer_intr(int irq, void *data)
  336. {
  337. struct qrtr_genpool_dev *qdev = data;
  338. if (!qdev->base)
  339. return IRQ_HANDLED;
  340. qrtr_genpool_read(qdev);
  341. return IRQ_HANDLED;
  342. }
  343. static int qrtr_genpool_irq_init(struct qrtr_genpool_dev *qdev)
  344. {
  345. struct device *dev = qdev->dev;
  346. int irq, rc;
  347. irq = of_irq_get(dev->of_node, IRQ_XFER_IDX);
  348. if (irq < 0)
  349. return irq;
  350. qdev->irq_xfer = irq;
  351. snprintf(qdev->irq_xfer_label, LABEL_SIZE, "%s-xfer", qdev->label);
  352. rc = devm_request_irq(dev, qdev->irq_xfer, qrtr_genpool_xfer_intr, 0,
  353. qdev->irq_xfer_label, qdev);
  354. if (rc) {
  355. dev_err(dev, "failed to request xfer IRQ: %d\n", rc);
  356. return rc;
  357. }
  358. enable_irq_wake(qdev->irq_xfer);
  359. irq = of_irq_get(dev->of_node, IRQ_SETUP_IDX);
  360. if (irq < 0)
  361. return irq;
  362. qdev->irq_setup = irq;
  363. snprintf(qdev->irq_setup_label, LABEL_SIZE, "%s-setup", qdev->label);
  364. rc = devm_request_irq(dev, qdev->irq_setup, qrtr_genpool_setup_intr, 0,
  365. qdev->irq_setup_label, qdev);
  366. if (rc) {
  367. dev_err(dev, "failed to request setup IRQ: %d\n", rc);
  368. return rc;
  369. }
  370. enable_irq_wake(qdev->irq_setup);
  371. return 0;
  372. }
  373. static int qrtr_genpool_mbox_init(struct qrtr_genpool_dev *qdev)
  374. {
  375. struct device *dev = qdev->dev;
  376. int rc;
  377. qdev->mbox_client.dev = dev;
  378. qdev->mbox_client.knows_txdone = true;
  379. qdev->mbox_setup_chan = mbox_request_channel(&qdev->mbox_client, IRQ_SETUP_IDX);
  380. if (IS_ERR(qdev->mbox_setup_chan)) {
  381. rc = PTR_ERR(qdev->mbox_setup_chan);
  382. if (rc != -EPROBE_DEFER)
  383. dev_err(dev, "failed to acquire IPC setup channel %d\n", rc);
  384. return rc;
  385. }
  386. qdev->mbox_xfer_chan = mbox_request_channel(&qdev->mbox_client, IRQ_XFER_IDX);
  387. if (IS_ERR(qdev->mbox_xfer_chan)) {
  388. rc = PTR_ERR(qdev->mbox_xfer_chan);
  389. if (rc != -EPROBE_DEFER)
  390. dev_err(dev, "failed to acquire IPC xfer channel %d\n", rc);
  391. return rc;
  392. }
  393. return 0;
  394. }
  395. /**
  396. * qrtr_genpool_fifo_init() - init genpool fifo configs
  397. *
  398. * @return: 0 on success, standard Linux error codes on error.
  399. *
  400. * This function is called to initialize the genpool fifo pointer with
  401. * the genpool fifo configurations.
  402. */
  403. static void qrtr_genpool_fifo_init(struct qrtr_genpool_dev *qdev)
  404. {
  405. u8 *descs;
  406. memset(qdev->base, 0, FIFO_0_START_OFFSET);
  407. descs = qdev->base;
  408. *(u32 *)(descs + MAGIC_KEY) = MAGIC_KEY_VALUE;
  409. *(u32 *)(descs + BUFFER_SIZE) = qdev->size;
  410. *(u32 *)(descs + FIFO_0_BASE) = FIFO_0_START_OFFSET;
  411. *(u32 *)(descs + FIFO_0_SIZE) = FIFO_SIZE;
  412. qdev->tx_pipe.fifo = (u32 *)(descs + FIFO_0_START_OFFSET);
  413. qdev->tx_pipe.tail = (u32 *)(descs + FIFO_0_TAIL);
  414. qdev->tx_pipe.head = (u32 *)(descs + FIFO_0_HEAD);
  415. qdev->tx_pipe.read_notify = (u32 *)(descs + FIFO_0_NOTIFY);
  416. qdev->tx_pipe.length = FIFO_SIZE;
  417. *(u32 *)(descs + FIFO_1_BASE) = FIFO_1_START_OFFSET;
  418. *(u32 *)(descs + FIFO_1_SIZE) = FIFO_SIZE;
  419. qdev->rx_pipe.fifo = (u32 *)(descs + FIFO_1_START_OFFSET);
  420. qdev->rx_pipe.tail = (u32 *)(descs + FIFO_1_TAIL);
  421. qdev->rx_pipe.head = (u32 *)(descs + FIFO_1_HEAD);
  422. qdev->rx_pipe.read_notify = (u32 *)(descs + FIFO_1_NOTIFY);
  423. qdev->rx_pipe.length = FIFO_SIZE;
  424. /* Reset respective index */
  425. *qdev->tx_pipe.head = 0;
  426. *qdev->rx_pipe.tail = 0;
  427. }
  428. static int qrtr_genpool_memory_init(struct qrtr_genpool_dev *qdev)
  429. {
  430. struct device_node *np;
  431. np = of_parse_phandle(qdev->dev->of_node, "gen-pool", 0);
  432. if (!np) {
  433. dev_err(qdev->dev, "failed to parse gen-pool\n");
  434. return -ENODEV;
  435. }
  436. qdev->pool = of_gen_pool_get(np, "qrtr-gen-pool", 0);
  437. of_node_put(np);
  438. if (!qdev->pool)
  439. return -EPROBE_DEFER;
  440. /* check if pool has any entries */
  441. if (!gen_pool_avail(qdev->pool))
  442. return -EPROBE_DEFER;
  443. return 0;
  444. }
  445. static void qrtr_genpool_setup_work(struct work_struct *work)
  446. {
  447. struct qrtr_genpool_dev *qdev = container_of(work, struct qrtr_genpool_dev, setup_work);
  448. int rc;
  449. disable_irq(qdev->irq_xfer);
  450. if (qdev->ep_registered) {
  451. qrtr_endpoint_unregister(&qdev->ep);
  452. qdev->ep_registered = false;
  453. }
  454. qrtr_genpool_memory_free(qdev);
  455. rc = qrtr_genpool_memory_alloc(qdev);
  456. if (rc)
  457. return;
  458. qrtr_genpool_fifo_init(qdev);
  459. qdev->ep.xmit = qrtr_genpool_send;
  460. rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NET_ID_AUTO, false, NULL);
  461. if (rc) {
  462. dev_err(qdev->dev, "failed to register qrtr endpoint rc%d\n", rc);
  463. return;
  464. }
  465. qdev->ep_registered = true;
  466. enable_irq(qdev->irq_xfer);
  467. qrtr_genpool_signal_setup(qdev);
  468. }
  469. /**
  470. * qrtr_genpool_probe() - Probe a genpool fifo transport
  471. *
  472. * @pdev: Platform device corresponding to genpool fifo transport.
  473. *
  474. * @return: 0 on success, standard Linux error codes on error.
  475. *
  476. * This function is called when the underlying device tree driver registers
  477. * a platform device, mapped to a genpool fifo transport.
  478. */
  479. static int qrtr_genpool_probe(struct platform_device *pdev)
  480. {
  481. struct device *dev = &pdev->dev;
  482. struct qrtr_genpool_dev *qdev;
  483. int rc;
  484. qdev = devm_kzalloc(dev, sizeof(*qdev), GFP_KERNEL);
  485. if (!qdev)
  486. return -ENOMEM;
  487. qdev->dev = dev;
  488. dev_set_drvdata(dev, qdev);
  489. rc = of_property_read_string(dev->of_node, "label", &qdev->label);
  490. if (rc < 0)
  491. qdev->label = dev->of_node->name;
  492. qdev->ring.buf = vzalloc(MAX_PKT_SZ);
  493. if (!qdev->ring.buf)
  494. return -ENOMEM;
  495. rc = qrtr_genpool_memory_init(qdev);
  496. if (rc)
  497. goto err;
  498. init_waitqueue_head(&qdev->tx_avail_notify);
  499. INIT_WORK(&qdev->setup_work, qrtr_genpool_setup_work);
  500. rc = qrtr_genpool_mbox_init(qdev);
  501. if (rc)
  502. goto err;
  503. rc = qrtr_genpool_irq_init(qdev);
  504. if (rc)
  505. goto err;
  506. return 0;
  507. err:
  508. vfree(qdev->ring.buf);
  509. return rc;
  510. }
  511. static int qrtr_genpool_remove(struct platform_device *pdev)
  512. {
  513. struct qrtr_genpool_dev *qdev = platform_get_drvdata(pdev);
  514. cancel_work_sync(&qdev->setup_work);
  515. if (qdev->ep_registered)
  516. qrtr_endpoint_unregister(&qdev->ep);
  517. vfree(qdev->ring.buf);
  518. return 0;
  519. }
  520. static const struct of_device_id qrtr_genpool_match_table[] = {
  521. { .compatible = "qcom,qrtr-genpool" },
  522. {},
  523. };
  524. static struct platform_driver qrtr_genpool_driver = {
  525. .probe = qrtr_genpool_probe,
  526. .remove = qrtr_genpool_remove,
  527. .driver = {
  528. .name = "qcom_genpool_qrtr",
  529. .of_match_table = qrtr_genpool_match_table,
  530. },
  531. };
  532. module_platform_driver(qrtr_genpool_driver);
  533. MODULE_DESCRIPTION("QTI IPC-Router FIFO interface driver");
  534. MODULE_LICENSE("GPL");