smd.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2015, Sony Mobile Communications Inc.
  4. * Copyright (c) 2013, The Linux Foundation. All rights reserved.
  5. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  6. */
  7. #include <linux/module.h>
  8. #include <linux/skbuff.h>
  9. #include <linux/rpmsg.h>
  10. #include <linux/rpmsg/qcom_glink.h>
  11. #include <linux/of.h>
  12. #include "qrtr.h"
  13. struct qrtr_smd_dev {
  14. struct qrtr_endpoint ep;
  15. struct rpmsg_endpoint *channel;
  16. struct device *dev;
  17. };
  18. /* from smd to qrtr */
  19. static int qcom_smd_qrtr_callback(struct rpmsg_device *rpdev,
  20. void *data, int len, void *priv, u32 addr)
  21. {
  22. struct qrtr_smd_dev *qdev = dev_get_drvdata(&rpdev->dev);
  23. int rc;
  24. if (!qdev) {
  25. pr_err_ratelimited("%s: Not ready\n", __func__);
  26. return -EAGAIN;
  27. }
  28. rc = qrtr_endpoint_post(&qdev->ep, data, len);
  29. if (rc == -EINVAL) {
  30. dev_err(qdev->dev, "invalid ipcrouter packet\n");
  31. /* return 0 to let smd drop the packet */
  32. rc = 0;
  33. }
  34. if (qcom_glink_is_wakeup(true))
  35. qrtr_print_wakeup_reason(data);
  36. return rc;
  37. }
  38. /* from qrtr to smd */
  39. static int qcom_smd_qrtr_send(struct qrtr_endpoint *ep, struct sk_buff *skb)
  40. {
  41. struct qrtr_smd_dev *qdev = container_of(ep, struct qrtr_smd_dev, ep);
  42. int rc;
  43. rc = skb_linearize(skb);
  44. if (rc)
  45. goto out;
  46. rc = rpmsg_send(qdev->channel, skb->data, skb->len);
  47. out:
  48. if (rc)
  49. kfree_skb(skb);
  50. else
  51. consume_skb(skb);
  52. return rc;
  53. }
  54. static int qcom_smd_qrtr_probe(struct rpmsg_device *rpdev)
  55. {
  56. struct qrtr_array svc_arr = {NULL, 0};
  57. struct qrtr_smd_dev *qdev;
  58. u32 net_id;
  59. int size;
  60. bool rt;
  61. int rc;
  62. qdev = devm_kzalloc(&rpdev->dev, sizeof(*qdev), GFP_KERNEL);
  63. if (!qdev)
  64. return -ENOMEM;
  65. qdev->channel = rpdev->ept;
  66. qdev->dev = &rpdev->dev;
  67. qdev->ep.xmit = qcom_smd_qrtr_send;
  68. rc = of_property_read_u32(rpdev->dev.of_node, "qcom,net-id", &net_id);
  69. if (rc < 0)
  70. net_id = QRTR_EP_NET_ID_AUTO;
  71. rt = of_property_read_bool(rpdev->dev.of_node, "qcom,low-latency");
  72. size = of_property_count_u32_elems(rpdev->dev.of_node, "qcom,no-wake-svc");
  73. if (size > 0) {
  74. svc_arr.size = size;
  75. svc_arr.arr = kmalloc_array(size, sizeof(u32), GFP_KERNEL);
  76. if (!svc_arr.arr)
  77. return -ENOMEM;
  78. of_property_read_u32_array(rpdev->dev.of_node, "qcom,no-wake-svc",
  79. svc_arr.arr, size);
  80. }
  81. rc = qrtr_endpoint_register(&qdev->ep, net_id, rt, &svc_arr);
  82. kfree(svc_arr.arr);
  83. if (rc) {
  84. dev_err(qdev->dev, "endpoint register failed: %d, low-latency: %d\n", rc, rt);
  85. return rc;
  86. }
  87. dev_set_drvdata(&rpdev->dev, qdev);
  88. pr_info("%s: SMD QRTR driver probed\n", __func__);
  89. return 0;
  90. }
  91. static void qcom_smd_qrtr_remove(struct rpmsg_device *rpdev)
  92. {
  93. struct qrtr_smd_dev *qdev = dev_get_drvdata(&rpdev->dev);
  94. qrtr_endpoint_unregister(&qdev->ep);
  95. dev_set_drvdata(&rpdev->dev, NULL);
  96. }
  97. static const struct rpmsg_device_id qcom_smd_qrtr_smd_match[] = {
  98. { "IPCRTR" },
  99. {}
  100. };
  101. static struct rpmsg_driver qcom_smd_qrtr_driver = {
  102. .probe = qcom_smd_qrtr_probe,
  103. .remove = qcom_smd_qrtr_remove,
  104. .callback = qcom_smd_qrtr_callback,
  105. .id_table = qcom_smd_qrtr_smd_match,
  106. .drv = {
  107. .name = "qcom_smd_qrtr",
  108. },
  109. };
  110. module_rpmsg_driver(qcom_smd_qrtr_driver);
  111. MODULE_ALIAS("rpmsg:IPCRTR");
  112. MODULE_DESCRIPTION("Qualcomm IPC-Router SMD interface driver");
  113. MODULE_LICENSE("GPL v2");