^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/mhi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/mod_devicetable.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/skbuff.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <net/sock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include "qrtr.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) struct qrtr_mhi_dev {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) struct qrtr_endpoint ep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) struct mhi_device *mhi_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /* From MHI to QRTR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) static void qcom_mhi_qrtr_dl_callback(struct mhi_device *mhi_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct mhi_result *mhi_res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) if (!qdev || mhi_res->transaction_status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) rc = qrtr_endpoint_post(&qdev->ep, mhi_res->buf_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) mhi_res->bytes_xferd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) if (rc == -EINVAL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) dev_err(qdev->dev, "invalid ipcrouter packet\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) /* From QRTR to MHI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static void qcom_mhi_qrtr_ul_callback(struct mhi_device *mhi_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct mhi_result *mhi_res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct sk_buff *skb = mhi_res->buf_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (skb->sk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) sock_put(skb->sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) consume_skb(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) /* Send data over MHI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static int qcom_mhi_qrtr_send(struct qrtr_endpoint *ep, struct sk_buff *skb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct qrtr_mhi_dev *qdev = container_of(ep, struct qrtr_mhi_dev, ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (skb->sk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) sock_hold(skb->sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) rc = skb_linearize(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) goto free_skb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) rc = mhi_queue_skb(qdev->mhi_dev, DMA_TO_DEVICE, skb, skb->len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) MHI_EOT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) goto free_skb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) free_skb:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) if (skb->sk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) sock_put(skb->sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) kfree_skb(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) const struct mhi_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) struct qrtr_mhi_dev *qdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) qdev = devm_kzalloc(&mhi_dev->dev, sizeof(*qdev), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (!qdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) qdev->mhi_dev = mhi_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) qdev->dev = &mhi_dev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) qdev->ep.xmit = qcom_mhi_qrtr_send;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) dev_set_drvdata(&mhi_dev->dev, qdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) dev_dbg(qdev->dev, "Qualcomm MHI QRTR driver probed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static void qcom_mhi_qrtr_remove(struct mhi_device *mhi_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) struct qrtr_mhi_dev *qdev = dev_get_drvdata(&mhi_dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) qrtr_endpoint_unregister(&qdev->ep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) dev_set_drvdata(&mhi_dev->dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) static const struct mhi_device_id qcom_mhi_qrtr_id_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) { .chan = "IPCR" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) MODULE_DEVICE_TABLE(mhi, qcom_mhi_qrtr_id_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) static struct mhi_driver qcom_mhi_qrtr_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) .probe = qcom_mhi_qrtr_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) .remove = qcom_mhi_qrtr_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) .dl_xfer_cb = qcom_mhi_qrtr_dl_callback,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) .ul_xfer_cb = qcom_mhi_qrtr_ul_callback,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) .id_table = qcom_mhi_qrtr_id_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) .name = "qcom_mhi_qrtr",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) module_mhi_driver(qcom_mhi_qrtr_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) MODULE_AUTHOR("Chris Lew <clew@codeaurora.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) MODULE_DESCRIPTION("Qualcomm IPC-Router MHI interface driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) MODULE_LICENSE("GPL v2");