Merge tag 'dmaengine-5.3-rc1' of git://git.infradead.org/users/vkoul/slave-dma
[platform/kernel/linux-starfive.git] / net / qrtr / smd.c
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  */
6
7 #include <linux/module.h>
8 #include <linux/skbuff.h>
9 #include <linux/rpmsg.h>
10
11 #include "qrtr.h"
12
13 struct qrtr_smd_dev {
14         struct qrtr_endpoint ep;
15         struct rpmsg_endpoint *channel;
16         struct device *dev;
17 };
18
19 /* from smd to qrtr */
20 static int qcom_smd_qrtr_callback(struct rpmsg_device *rpdev,
21                                   void *data, int len, void *priv, u32 addr)
22 {
23         struct qrtr_smd_dev *qdev = dev_get_drvdata(&rpdev->dev);
24         int rc;
25
26         if (!qdev)
27                 return -EAGAIN;
28
29         rc = qrtr_endpoint_post(&qdev->ep, data, len);
30         if (rc == -EINVAL) {
31                 dev_err(qdev->dev, "invalid ipcrouter packet\n");
32                 /* return 0 to let smd drop the packet */
33                 rc = 0;
34         }
35
36         return rc;
37 }
38
39 /* from qrtr to smd */
40 static int qcom_smd_qrtr_send(struct qrtr_endpoint *ep, struct sk_buff *skb)
41 {
42         struct qrtr_smd_dev *qdev = container_of(ep, struct qrtr_smd_dev, ep);
43         int rc;
44
45         rc = skb_linearize(skb);
46         if (rc)
47                 goto out;
48
49         rc = rpmsg_send(qdev->channel, skb->data, skb->len);
50
51 out:
52         if (rc)
53                 kfree_skb(skb);
54         else
55                 consume_skb(skb);
56         return rc;
57 }
58
59 static int qcom_smd_qrtr_probe(struct rpmsg_device *rpdev)
60 {
61         struct qrtr_smd_dev *qdev;
62         int rc;
63
64         qdev = devm_kzalloc(&rpdev->dev, sizeof(*qdev), GFP_KERNEL);
65         if (!qdev)
66                 return -ENOMEM;
67
68         qdev->channel = rpdev->ept;
69         qdev->dev = &rpdev->dev;
70         qdev->ep.xmit = qcom_smd_qrtr_send;
71
72         rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO);
73         if (rc)
74                 return rc;
75
76         dev_set_drvdata(&rpdev->dev, qdev);
77
78         dev_dbg(&rpdev->dev, "Qualcomm SMD QRTR driver probed\n");
79
80         return 0;
81 }
82
83 static void qcom_smd_qrtr_remove(struct rpmsg_device *rpdev)
84 {
85         struct qrtr_smd_dev *qdev = dev_get_drvdata(&rpdev->dev);
86
87         qrtr_endpoint_unregister(&qdev->ep);
88
89         dev_set_drvdata(&rpdev->dev, NULL);
90 }
91
92 static const struct rpmsg_device_id qcom_smd_qrtr_smd_match[] = {
93         { "IPCRTR" },
94         {}
95 };
96
97 static struct rpmsg_driver qcom_smd_qrtr_driver = {
98         .probe = qcom_smd_qrtr_probe,
99         .remove = qcom_smd_qrtr_remove,
100         .callback = qcom_smd_qrtr_callback,
101         .id_table = qcom_smd_qrtr_smd_match,
102         .drv = {
103                 .name = "qcom_smd_qrtr",
104         },
105 };
106
107 module_rpmsg_driver(qcom_smd_qrtr_driver);
108
109 MODULE_ALIAS("rpmsg:IPCRTR");
110 MODULE_DESCRIPTION("Qualcomm IPC-Router SMD interface driver");
111 MODULE_LICENSE("GPL v2");