xref: /linux/net/qrtr/smd.c (revision 24bce201d79807b668bf9d9e0aca801c5c0d5f78)
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");
112