mhi.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
  4. */
  5. #include <linux/mhi.h>
  6. #include <linux/mod_devicetable.h>
  7. #include <linux/module.h>
  8. #include <linux/skbuff.h>
  9. #include <net/sock.h>
  10. #include "qrtr.h"
  11. struct qrtr_mhi_dev {
  12. struct qrtr_endpoint ep;
  13. struct mhi_device *mhi_dev;
  14. struct device *dev;
  15. };
  16. /* From MHI to QRTR */
  17. static void qcom_mhi_qrtr_dl_callback(struct mhi_device *mhi_dev,
  18. struct mhi_result *mhi_res)
  19. {
  20. struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev);
  21. int rc;
  22. if (!qdev || (mhi_res->transaction_status && mhi_res->transaction_status != -ENOTCONN))
  23. return;
  24. /* Channel got reset. So just free the buffer */
  25. if (mhi_res->transaction_status == -ENOTCONN) {
  26. devm_kfree(&mhi_dev->dev, mhi_res->buf_addr);
  27. return;
  28. }
  29. rc = qrtr_endpoint_post(&qdev->ep, mhi_res->buf_addr,
  30. mhi_res->bytes_xferd);
  31. if (rc == -EINVAL)
  32. dev_err(qdev->dev, "invalid ipcrouter packet\n");
  33. /* Done with the buffer, now recycle it for future use */
  34. rc = mhi_queue_buf(mhi_dev, DMA_FROM_DEVICE, mhi_res->buf_addr,
  35. mhi_dev->mhi_cntrl->buffer_len, MHI_EOT);
  36. if (rc)
  37. dev_err(&mhi_dev->dev, "Failed to recycle the buffer: %d\n", rc);
  38. }
  39. /* From QRTR to MHI */
  40. static void qcom_mhi_qrtr_ul_callback(struct mhi_device *mhi_dev,
  41. struct mhi_result *mhi_res)
  42. {
  43. struct sk_buff *skb = mhi_res->buf_addr;
  44. if (skb->sk)
  45. sock_put(skb->sk);
  46. consume_skb(skb);
  47. }
  48. /* Send data over MHI */
  49. static int qcom_mhi_qrtr_send(struct qrtr_endpoint *ep, struct sk_buff *skb)
  50. {
  51. struct qrtr_mhi_dev *qdev = container_of(ep, struct qrtr_mhi_dev, ep);
  52. int rc;
  53. if (skb->sk)
  54. sock_hold(skb->sk);
  55. rc = skb_linearize(skb);
  56. if (rc)
  57. goto free_skb;
  58. rc = mhi_queue_skb(qdev->mhi_dev, DMA_TO_DEVICE, skb, skb->len,
  59. MHI_EOT);
  60. if (rc)
  61. goto free_skb;
  62. return rc;
  63. free_skb:
  64. if (skb->sk)
  65. sock_put(skb->sk);
  66. kfree_skb(skb);
  67. return rc;
  68. }
  69. static int qcom_mhi_qrtr_queue_dl_buffers(struct mhi_device *mhi_dev)
  70. {
  71. u32 free_desc;
  72. void *buf;
  73. int ret;
  74. free_desc = mhi_get_free_desc_count(mhi_dev, DMA_FROM_DEVICE);
  75. while (free_desc--) {
  76. buf = devm_kmalloc(&mhi_dev->dev, mhi_dev->mhi_cntrl->buffer_len, GFP_KERNEL);
  77. if (!buf)
  78. return -ENOMEM;
  79. ret = mhi_queue_buf(mhi_dev, DMA_FROM_DEVICE, buf, mhi_dev->mhi_cntrl->buffer_len,
  80. MHI_EOT);
  81. if (ret) {
  82. dev_err(&mhi_dev->dev, "Failed to queue buffer: %d\n", ret);
  83. return ret;
  84. }
  85. }
  86. return 0;
  87. }
  88. static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev,
  89. const struct mhi_device_id *id)
  90. {
  91. struct qrtr_mhi_dev *qdev;
  92. int rc;
  93. qdev = devm_kzalloc(&mhi_dev->dev, sizeof(*qdev), GFP_KERNEL);
  94. if (!qdev)
  95. return -ENOMEM;
  96. qdev->mhi_dev = mhi_dev;
  97. qdev->dev = &mhi_dev->dev;
  98. qdev->ep.xmit = qcom_mhi_qrtr_send;
  99. dev_set_drvdata(&mhi_dev->dev, qdev);
  100. /* start channels */
  101. rc = mhi_prepare_for_transfer(mhi_dev);
  102. if (rc)
  103. return rc;
  104. rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO);
  105. if (rc)
  106. goto err_unprepare;
  107. rc = qcom_mhi_qrtr_queue_dl_buffers(mhi_dev);
  108. if (rc)
  109. goto err_unregister;
  110. dev_dbg(qdev->dev, "Qualcomm MHI QRTR driver probed\n");
  111. return 0;
  112. err_unregister:
  113. qrtr_endpoint_unregister(&qdev->ep);
  114. err_unprepare:
  115. mhi_unprepare_from_transfer(mhi_dev);
  116. return rc;
  117. }
  118. static void qcom_mhi_qrtr_remove(struct mhi_device *mhi_dev)
  119. {
  120. struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev);
  121. qrtr_endpoint_unregister(&qdev->ep);
  122. mhi_unprepare_from_transfer(mhi_dev);
  123. dev_set_drvdata(&mhi_dev->dev, NULL);
  124. }
  125. static const struct mhi_device_id qcom_mhi_qrtr_id_table[] = {
  126. { .chan = "IPCR" },
  127. {}
  128. };
  129. MODULE_DEVICE_TABLE(mhi, qcom_mhi_qrtr_id_table);
  130. static int __maybe_unused qcom_mhi_qrtr_pm_suspend_late(struct device *dev)
  131. {
  132. struct mhi_device *mhi_dev = container_of(dev, struct mhi_device, dev);
  133. enum mhi_state state;
  134. state = mhi_get_mhi_state(mhi_dev->mhi_cntrl);
  135. /*
  136. * If the device is in suspend state, then no need for the
  137. * client driver to unprepare the channels.
  138. */
  139. if (state == MHI_STATE_M3)
  140. return 0;
  141. mhi_unprepare_from_transfer(mhi_dev);
  142. return 0;
  143. }
  144. static int __maybe_unused qcom_mhi_qrtr_pm_resume_early(struct device *dev)
  145. {
  146. struct mhi_device *mhi_dev = container_of(dev, struct mhi_device, dev);
  147. enum mhi_state state;
  148. int rc;
  149. state = mhi_get_mhi_state(mhi_dev->mhi_cntrl);
  150. /*
  151. * If the device is in suspend state, we won't unprepare channels
  152. * in suspend callback, therefore no need to prepare channels when
  153. * resume.
  154. */
  155. if (state == MHI_STATE_M3)
  156. return 0;
  157. rc = mhi_prepare_for_transfer(mhi_dev);
  158. if (rc) {
  159. dev_err(dev, "failed to prepare for autoqueue transfer %d\n", rc);
  160. return rc;
  161. }
  162. return qcom_mhi_qrtr_queue_dl_buffers(mhi_dev);
  163. }
  164. static const struct dev_pm_ops qcom_mhi_qrtr_pm_ops = {
  165. SET_LATE_SYSTEM_SLEEP_PM_OPS(qcom_mhi_qrtr_pm_suspend_late,
  166. qcom_mhi_qrtr_pm_resume_early)
  167. };
  168. static struct mhi_driver qcom_mhi_qrtr_driver = {
  169. .probe = qcom_mhi_qrtr_probe,
  170. .remove = qcom_mhi_qrtr_remove,
  171. .dl_xfer_cb = qcom_mhi_qrtr_dl_callback,
  172. .ul_xfer_cb = qcom_mhi_qrtr_ul_callback,
  173. .id_table = qcom_mhi_qrtr_id_table,
  174. .driver = {
  175. .name = "qcom_mhi_qrtr",
  176. .pm = &qcom_mhi_qrtr_pm_ops,
  177. },
  178. };
  179. module_mhi_driver(qcom_mhi_qrtr_driver);
  180. MODULE_AUTHOR("Chris Lew <clew@codeaurora.org>");
  181. MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
  182. MODULE_DESCRIPTION("Qualcomm IPC-Router MHI interface driver");
  183. MODULE_LICENSE("GPL v2");