xref: /openbmc/linux/drivers/rpmsg/rpmsg_ns.c (revision 950a7388)
1*950a7388SArnaud Pouliquen // SPDX-License-Identifier: GPL-2.0
2*950a7388SArnaud Pouliquen /*
3*950a7388SArnaud Pouliquen  * Copyright (C) STMicroelectronics 2020 - All Rights Reserved
4*950a7388SArnaud Pouliquen  */
5*950a7388SArnaud Pouliquen #include <linux/device.h>
6*950a7388SArnaud Pouliquen #include <linux/kernel.h>
7*950a7388SArnaud Pouliquen #include <linux/module.h>
8*950a7388SArnaud Pouliquen #include <linux/rpmsg.h>
9*950a7388SArnaud Pouliquen #include <linux/rpmsg/ns.h>
10*950a7388SArnaud Pouliquen #include <linux/slab.h>
11*950a7388SArnaud Pouliquen 
12*950a7388SArnaud Pouliquen #include "rpmsg_internal.h"
13*950a7388SArnaud Pouliquen 
14*950a7388SArnaud Pouliquen /**
15*950a7388SArnaud Pouliquen  * rpmsg_ns_register_device() - register name service device based on rpdev
16*950a7388SArnaud Pouliquen  * @rpdev: prepared rpdev to be used for creating endpoints
17*950a7388SArnaud Pouliquen  *
18*950a7388SArnaud Pouliquen  * This function wraps rpmsg_register_device() preparing the rpdev for use as
19*950a7388SArnaud Pouliquen  * basis for the rpmsg name service device.
20*950a7388SArnaud Pouliquen  */
21*950a7388SArnaud Pouliquen int rpmsg_ns_register_device(struct rpmsg_device *rpdev)
22*950a7388SArnaud Pouliquen {
23*950a7388SArnaud Pouliquen 	strcpy(rpdev->id.name, "rpmsg_ns");
24*950a7388SArnaud Pouliquen 	rpdev->driver_override = "rpmsg_ns";
25*950a7388SArnaud Pouliquen 	rpdev->src = RPMSG_NS_ADDR;
26*950a7388SArnaud Pouliquen 	rpdev->dst = RPMSG_NS_ADDR;
27*950a7388SArnaud Pouliquen 
28*950a7388SArnaud Pouliquen 	return rpmsg_register_device(rpdev);
29*950a7388SArnaud Pouliquen }
30*950a7388SArnaud Pouliquen EXPORT_SYMBOL(rpmsg_ns_register_device);
31*950a7388SArnaud Pouliquen 
32*950a7388SArnaud Pouliquen /* invoked when a name service announcement arrives */
33*950a7388SArnaud Pouliquen static int rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
34*950a7388SArnaud Pouliquen 		       void *priv, u32 src)
35*950a7388SArnaud Pouliquen {
36*950a7388SArnaud Pouliquen 	struct rpmsg_ns_msg *msg = data;
37*950a7388SArnaud Pouliquen 	struct rpmsg_device *newch;
38*950a7388SArnaud Pouliquen 	struct rpmsg_channel_info chinfo;
39*950a7388SArnaud Pouliquen 	struct device *dev = rpdev->dev.parent;
40*950a7388SArnaud Pouliquen 	int ret;
41*950a7388SArnaud Pouliquen 
42*950a7388SArnaud Pouliquen #if defined(CONFIG_DYNAMIC_DEBUG)
43*950a7388SArnaud Pouliquen 	dynamic_hex_dump("NS announcement: ", DUMP_PREFIX_NONE, 16, 1,
44*950a7388SArnaud Pouliquen 			 data, len, true);
45*950a7388SArnaud Pouliquen #endif
46*950a7388SArnaud Pouliquen 
47*950a7388SArnaud Pouliquen 	if (len != sizeof(*msg)) {
48*950a7388SArnaud Pouliquen 		dev_err(dev, "malformed ns msg (%d)\n", len);
49*950a7388SArnaud Pouliquen 		return -EINVAL;
50*950a7388SArnaud Pouliquen 	}
51*950a7388SArnaud Pouliquen 
52*950a7388SArnaud Pouliquen 	/* don't trust the remote processor for null terminating the name */
53*950a7388SArnaud Pouliquen 	msg->name[RPMSG_NAME_SIZE - 1] = '\0';
54*950a7388SArnaud Pouliquen 
55*950a7388SArnaud Pouliquen 	strncpy(chinfo.name, msg->name, sizeof(chinfo.name));
56*950a7388SArnaud Pouliquen 	chinfo.src = RPMSG_ADDR_ANY;
57*950a7388SArnaud Pouliquen 	chinfo.dst = rpmsg32_to_cpu(rpdev, msg->addr);
58*950a7388SArnaud Pouliquen 
59*950a7388SArnaud Pouliquen 	dev_info(dev, "%sing channel %s addr 0x%x\n",
60*950a7388SArnaud Pouliquen 		 rpmsg32_to_cpu(rpdev, msg->flags) & RPMSG_NS_DESTROY ?
61*950a7388SArnaud Pouliquen 		 "destroy" : "creat", msg->name, chinfo.dst);
62*950a7388SArnaud Pouliquen 
63*950a7388SArnaud Pouliquen 	if (rpmsg32_to_cpu(rpdev, msg->flags) & RPMSG_NS_DESTROY) {
64*950a7388SArnaud Pouliquen 		ret = rpmsg_release_channel(rpdev, &chinfo);
65*950a7388SArnaud Pouliquen 		if (ret)
66*950a7388SArnaud Pouliquen 			dev_err(dev, "rpmsg_destroy_channel failed: %d\n", ret);
67*950a7388SArnaud Pouliquen 	} else {
68*950a7388SArnaud Pouliquen 		newch = rpmsg_create_channel(rpdev, &chinfo);
69*950a7388SArnaud Pouliquen 		if (!newch)
70*950a7388SArnaud Pouliquen 			dev_err(dev, "rpmsg_create_channel failed\n");
71*950a7388SArnaud Pouliquen 	}
72*950a7388SArnaud Pouliquen 
73*950a7388SArnaud Pouliquen 	return 0;
74*950a7388SArnaud Pouliquen }
75*950a7388SArnaud Pouliquen 
76*950a7388SArnaud Pouliquen static int rpmsg_ns_probe(struct rpmsg_device *rpdev)
77*950a7388SArnaud Pouliquen {
78*950a7388SArnaud Pouliquen 	struct rpmsg_endpoint *ns_ept;
79*950a7388SArnaud Pouliquen 	struct rpmsg_channel_info ns_chinfo = {
80*950a7388SArnaud Pouliquen 		.src = RPMSG_NS_ADDR,
81*950a7388SArnaud Pouliquen 		.dst = RPMSG_NS_ADDR,
82*950a7388SArnaud Pouliquen 		.name = "name_service",
83*950a7388SArnaud Pouliquen 	};
84*950a7388SArnaud Pouliquen 
85*950a7388SArnaud Pouliquen 	/*
86*950a7388SArnaud Pouliquen 	 * Create the NS announcement service endpoint associated to the RPMsg
87*950a7388SArnaud Pouliquen 	 * device. The endpoint will be automatically destroyed when the RPMsg
88*950a7388SArnaud Pouliquen 	 * device will be deleted.
89*950a7388SArnaud Pouliquen 	 */
90*950a7388SArnaud Pouliquen 	ns_ept = rpmsg_create_ept(rpdev, rpmsg_ns_cb, NULL, ns_chinfo);
91*950a7388SArnaud Pouliquen 	if (!ns_ept) {
92*950a7388SArnaud Pouliquen 		dev_err(&rpdev->dev, "failed to create the ns ept\n");
93*950a7388SArnaud Pouliquen 		return -ENOMEM;
94*950a7388SArnaud Pouliquen 	}
95*950a7388SArnaud Pouliquen 	rpdev->ept = ns_ept;
96*950a7388SArnaud Pouliquen 
97*950a7388SArnaud Pouliquen 	return 0;
98*950a7388SArnaud Pouliquen }
99*950a7388SArnaud Pouliquen 
100*950a7388SArnaud Pouliquen static struct rpmsg_driver rpmsg_ns_driver = {
101*950a7388SArnaud Pouliquen 	.drv.name = KBUILD_MODNAME,
102*950a7388SArnaud Pouliquen 	.probe = rpmsg_ns_probe,
103*950a7388SArnaud Pouliquen };
104*950a7388SArnaud Pouliquen 
105*950a7388SArnaud Pouliquen static int rpmsg_ns_init(void)
106*950a7388SArnaud Pouliquen {
107*950a7388SArnaud Pouliquen 	int ret;
108*950a7388SArnaud Pouliquen 
109*950a7388SArnaud Pouliquen 	ret = register_rpmsg_driver(&rpmsg_ns_driver);
110*950a7388SArnaud Pouliquen 	if (ret < 0)
111*950a7388SArnaud Pouliquen 		pr_err("%s: Failed to register rpmsg driver\n", __func__);
112*950a7388SArnaud Pouliquen 
113*950a7388SArnaud Pouliquen 	return ret;
114*950a7388SArnaud Pouliquen }
115*950a7388SArnaud Pouliquen postcore_initcall(rpmsg_ns_init);
116*950a7388SArnaud Pouliquen 
117*950a7388SArnaud Pouliquen static void rpmsg_ns_exit(void)
118*950a7388SArnaud Pouliquen {
119*950a7388SArnaud Pouliquen 	unregister_rpmsg_driver(&rpmsg_ns_driver);
120*950a7388SArnaud Pouliquen }
121*950a7388SArnaud Pouliquen module_exit(rpmsg_ns_exit);
122*950a7388SArnaud Pouliquen 
123*950a7388SArnaud Pouliquen MODULE_DESCRIPTION("Name service announcement rpmsg driver");
124*950a7388SArnaud Pouliquen MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>");
125*950a7388SArnaud Pouliquen MODULE_ALIAS("rpmsg:" KBUILD_MODNAME);
126*950a7388SArnaud Pouliquen MODULE_LICENSE("GPL v2");
127