1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // Copyright 2019 Google LLC.
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun #include <linux/kernel.h>
6*4882a593Smuzhiyun #include <linux/module.h>
7*4882a593Smuzhiyun #include <linux/of.h>
8*4882a593Smuzhiyun #include <linux/platform_device.h>
9*4882a593Smuzhiyun #include <linux/remoteproc.h>
10*4882a593Smuzhiyun #include <linux/rpmsg/mtk_rpmsg.h>
11*4882a593Smuzhiyun #include <linux/slab.h>
12*4882a593Smuzhiyun #include <linux/workqueue.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #include "rpmsg_internal.h"
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun struct mtk_rpmsg_rproc_subdev {
17*4882a593Smuzhiyun struct platform_device *pdev;
18*4882a593Smuzhiyun struct mtk_rpmsg_info *info;
19*4882a593Smuzhiyun struct rpmsg_endpoint *ns_ept;
20*4882a593Smuzhiyun struct rproc_subdev subdev;
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun struct work_struct register_work;
23*4882a593Smuzhiyun struct list_head channels;
24*4882a593Smuzhiyun struct mutex channels_lock;
25*4882a593Smuzhiyun };
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #define to_mtk_subdev(d) container_of(d, struct mtk_rpmsg_rproc_subdev, subdev)
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun struct mtk_rpmsg_channel_info {
30*4882a593Smuzhiyun struct rpmsg_channel_info info;
31*4882a593Smuzhiyun bool registered;
32*4882a593Smuzhiyun struct list_head list;
33*4882a593Smuzhiyun };
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun /**
36*4882a593Smuzhiyun * struct rpmsg_ns_msg - dynamic name service announcement message
37*4882a593Smuzhiyun * @name: name of remote service that is published
38*4882a593Smuzhiyun * @addr: address of remote service that is published
39*4882a593Smuzhiyun *
40*4882a593Smuzhiyun * This message is sent across to publish a new service. When we receive these
41*4882a593Smuzhiyun * messages, an appropriate rpmsg channel (i.e device) is created. In turn, the
42*4882a593Smuzhiyun * ->probe() handler of the appropriate rpmsg driver will be invoked
43*4882a593Smuzhiyun * (if/as-soon-as one is registered).
44*4882a593Smuzhiyun */
45*4882a593Smuzhiyun struct rpmsg_ns_msg {
46*4882a593Smuzhiyun char name[RPMSG_NAME_SIZE];
47*4882a593Smuzhiyun u32 addr;
48*4882a593Smuzhiyun } __packed;
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun struct mtk_rpmsg_device {
51*4882a593Smuzhiyun struct rpmsg_device rpdev;
52*4882a593Smuzhiyun struct mtk_rpmsg_rproc_subdev *mtk_subdev;
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun struct mtk_rpmsg_endpoint {
56*4882a593Smuzhiyun struct rpmsg_endpoint ept;
57*4882a593Smuzhiyun struct mtk_rpmsg_rproc_subdev *mtk_subdev;
58*4882a593Smuzhiyun };
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun #define to_mtk_rpmsg_device(r) container_of(r, struct mtk_rpmsg_device, rpdev)
61*4882a593Smuzhiyun #define to_mtk_rpmsg_endpoint(r) container_of(r, struct mtk_rpmsg_endpoint, ept)
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun static const struct rpmsg_endpoint_ops mtk_rpmsg_endpoint_ops;
64*4882a593Smuzhiyun
__mtk_ept_release(struct kref * kref)65*4882a593Smuzhiyun static void __mtk_ept_release(struct kref *kref)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun struct rpmsg_endpoint *ept = container_of(kref, struct rpmsg_endpoint,
68*4882a593Smuzhiyun refcount);
69*4882a593Smuzhiyun kfree(to_mtk_rpmsg_endpoint(ept));
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
mtk_rpmsg_ipi_handler(void * data,unsigned int len,void * priv)72*4882a593Smuzhiyun static void mtk_rpmsg_ipi_handler(void *data, unsigned int len, void *priv)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun struct mtk_rpmsg_endpoint *mept = priv;
75*4882a593Smuzhiyun struct rpmsg_endpoint *ept = &mept->ept;
76*4882a593Smuzhiyun int ret;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun ret = (*ept->cb)(ept->rpdev, data, len, ept->priv, ept->addr);
79*4882a593Smuzhiyun if (ret)
80*4882a593Smuzhiyun dev_warn(&ept->rpdev->dev, "rpmsg handler return error = %d",
81*4882a593Smuzhiyun ret);
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun static struct rpmsg_endpoint *
__mtk_create_ept(struct mtk_rpmsg_rproc_subdev * mtk_subdev,struct rpmsg_device * rpdev,rpmsg_rx_cb_t cb,void * priv,u32 id)85*4882a593Smuzhiyun __mtk_create_ept(struct mtk_rpmsg_rproc_subdev *mtk_subdev,
86*4882a593Smuzhiyun struct rpmsg_device *rpdev, rpmsg_rx_cb_t cb, void *priv,
87*4882a593Smuzhiyun u32 id)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun struct mtk_rpmsg_endpoint *mept;
90*4882a593Smuzhiyun struct rpmsg_endpoint *ept;
91*4882a593Smuzhiyun struct platform_device *pdev = mtk_subdev->pdev;
92*4882a593Smuzhiyun int ret;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun mept = kzalloc(sizeof(*mept), GFP_KERNEL);
95*4882a593Smuzhiyun if (!mept)
96*4882a593Smuzhiyun return NULL;
97*4882a593Smuzhiyun mept->mtk_subdev = mtk_subdev;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun ept = &mept->ept;
100*4882a593Smuzhiyun kref_init(&ept->refcount);
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun ept->rpdev = rpdev;
103*4882a593Smuzhiyun ept->cb = cb;
104*4882a593Smuzhiyun ept->priv = priv;
105*4882a593Smuzhiyun ept->ops = &mtk_rpmsg_endpoint_ops;
106*4882a593Smuzhiyun ept->addr = id;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun ret = mtk_subdev->info->register_ipi(pdev, id, mtk_rpmsg_ipi_handler,
109*4882a593Smuzhiyun mept);
110*4882a593Smuzhiyun if (ret) {
111*4882a593Smuzhiyun dev_err(&pdev->dev, "IPI register failed, id = %d", id);
112*4882a593Smuzhiyun kref_put(&ept->refcount, __mtk_ept_release);
113*4882a593Smuzhiyun return NULL;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun return ept;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun static struct rpmsg_endpoint *
mtk_rpmsg_create_ept(struct rpmsg_device * rpdev,rpmsg_rx_cb_t cb,void * priv,struct rpmsg_channel_info chinfo)120*4882a593Smuzhiyun mtk_rpmsg_create_ept(struct rpmsg_device *rpdev, rpmsg_rx_cb_t cb, void *priv,
121*4882a593Smuzhiyun struct rpmsg_channel_info chinfo)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun struct mtk_rpmsg_rproc_subdev *mtk_subdev =
124*4882a593Smuzhiyun to_mtk_rpmsg_device(rpdev)->mtk_subdev;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun return __mtk_create_ept(mtk_subdev, rpdev, cb, priv, chinfo.src);
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
mtk_rpmsg_destroy_ept(struct rpmsg_endpoint * ept)129*4882a593Smuzhiyun static void mtk_rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun struct mtk_rpmsg_rproc_subdev *mtk_subdev =
132*4882a593Smuzhiyun to_mtk_rpmsg_endpoint(ept)->mtk_subdev;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun mtk_subdev->info->unregister_ipi(mtk_subdev->pdev, ept->addr);
135*4882a593Smuzhiyun kref_put(&ept->refcount, __mtk_ept_release);
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
mtk_rpmsg_send(struct rpmsg_endpoint * ept,void * data,int len)138*4882a593Smuzhiyun static int mtk_rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun struct mtk_rpmsg_rproc_subdev *mtk_subdev =
141*4882a593Smuzhiyun to_mtk_rpmsg_endpoint(ept)->mtk_subdev;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun return mtk_subdev->info->send_ipi(mtk_subdev->pdev, ept->addr, data,
144*4882a593Smuzhiyun len, 0);
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun
mtk_rpmsg_trysend(struct rpmsg_endpoint * ept,void * data,int len)147*4882a593Smuzhiyun static int mtk_rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun struct mtk_rpmsg_rproc_subdev *mtk_subdev =
150*4882a593Smuzhiyun to_mtk_rpmsg_endpoint(ept)->mtk_subdev;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun /*
153*4882a593Smuzhiyun * TODO: This currently is same as mtk_rpmsg_send, and wait until SCP
154*4882a593Smuzhiyun * received the last command.
155*4882a593Smuzhiyun */
156*4882a593Smuzhiyun return mtk_subdev->info->send_ipi(mtk_subdev->pdev, ept->addr, data,
157*4882a593Smuzhiyun len, 0);
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun static const struct rpmsg_endpoint_ops mtk_rpmsg_endpoint_ops = {
161*4882a593Smuzhiyun .destroy_ept = mtk_rpmsg_destroy_ept,
162*4882a593Smuzhiyun .send = mtk_rpmsg_send,
163*4882a593Smuzhiyun .trysend = mtk_rpmsg_trysend,
164*4882a593Smuzhiyun };
165*4882a593Smuzhiyun
mtk_rpmsg_release_device(struct device * dev)166*4882a593Smuzhiyun static void mtk_rpmsg_release_device(struct device *dev)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun struct rpmsg_device *rpdev = to_rpmsg_device(dev);
169*4882a593Smuzhiyun struct mtk_rpmsg_device *mdev = to_mtk_rpmsg_device(rpdev);
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun kfree(mdev);
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun static const struct rpmsg_device_ops mtk_rpmsg_device_ops = {
175*4882a593Smuzhiyun .create_ept = mtk_rpmsg_create_ept,
176*4882a593Smuzhiyun };
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun static struct device_node *
mtk_rpmsg_match_device_subnode(struct device_node * node,const char * channel)179*4882a593Smuzhiyun mtk_rpmsg_match_device_subnode(struct device_node *node, const char *channel)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun struct device_node *child;
182*4882a593Smuzhiyun const char *name;
183*4882a593Smuzhiyun int ret;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun for_each_available_child_of_node(node, child) {
186*4882a593Smuzhiyun ret = of_property_read_string(child, "mtk,rpmsg-name", &name);
187*4882a593Smuzhiyun if (ret)
188*4882a593Smuzhiyun continue;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun if (strcmp(name, channel) == 0)
191*4882a593Smuzhiyun return child;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun return NULL;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun
mtk_rpmsg_register_device(struct mtk_rpmsg_rproc_subdev * mtk_subdev,struct rpmsg_channel_info * info)197*4882a593Smuzhiyun static int mtk_rpmsg_register_device(struct mtk_rpmsg_rproc_subdev *mtk_subdev,
198*4882a593Smuzhiyun struct rpmsg_channel_info *info)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun struct rpmsg_device *rpdev;
201*4882a593Smuzhiyun struct mtk_rpmsg_device *mdev;
202*4882a593Smuzhiyun struct platform_device *pdev = mtk_subdev->pdev;
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
205*4882a593Smuzhiyun if (!mdev)
206*4882a593Smuzhiyun return -ENOMEM;
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun mdev->mtk_subdev = mtk_subdev;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun rpdev = &mdev->rpdev;
211*4882a593Smuzhiyun rpdev->ops = &mtk_rpmsg_device_ops;
212*4882a593Smuzhiyun rpdev->src = info->src;
213*4882a593Smuzhiyun rpdev->dst = info->dst;
214*4882a593Smuzhiyun strscpy(rpdev->id.name, info->name, RPMSG_NAME_SIZE);
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun rpdev->dev.of_node =
217*4882a593Smuzhiyun mtk_rpmsg_match_device_subnode(pdev->dev.of_node, info->name);
218*4882a593Smuzhiyun rpdev->dev.parent = &pdev->dev;
219*4882a593Smuzhiyun rpdev->dev.release = mtk_rpmsg_release_device;
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun return rpmsg_register_device(rpdev);
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
mtk_register_device_work_function(struct work_struct * register_work)224*4882a593Smuzhiyun static void mtk_register_device_work_function(struct work_struct *register_work)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun struct mtk_rpmsg_rproc_subdev *subdev = container_of(
227*4882a593Smuzhiyun register_work, struct mtk_rpmsg_rproc_subdev, register_work);
228*4882a593Smuzhiyun struct platform_device *pdev = subdev->pdev;
229*4882a593Smuzhiyun struct mtk_rpmsg_channel_info *info;
230*4882a593Smuzhiyun int ret;
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun mutex_lock(&subdev->channels_lock);
233*4882a593Smuzhiyun list_for_each_entry(info, &subdev->channels, list) {
234*4882a593Smuzhiyun if (info->registered)
235*4882a593Smuzhiyun continue;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun mutex_unlock(&subdev->channels_lock);
238*4882a593Smuzhiyun ret = mtk_rpmsg_register_device(subdev, &info->info);
239*4882a593Smuzhiyun mutex_lock(&subdev->channels_lock);
240*4882a593Smuzhiyun if (ret) {
241*4882a593Smuzhiyun dev_err(&pdev->dev, "Can't create rpmsg_device\n");
242*4882a593Smuzhiyun continue;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun info->registered = true;
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun mutex_unlock(&subdev->channels_lock);
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun
mtk_rpmsg_create_device(struct mtk_rpmsg_rproc_subdev * mtk_subdev,char * name,u32 addr)250*4882a593Smuzhiyun static int mtk_rpmsg_create_device(struct mtk_rpmsg_rproc_subdev *mtk_subdev,
251*4882a593Smuzhiyun char *name, u32 addr)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun struct mtk_rpmsg_channel_info *info;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun info = kzalloc(sizeof(*info), GFP_KERNEL);
256*4882a593Smuzhiyun if (!info)
257*4882a593Smuzhiyun return -ENOMEM;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun strscpy(info->info.name, name, RPMSG_NAME_SIZE);
260*4882a593Smuzhiyun info->info.src = addr;
261*4882a593Smuzhiyun info->info.dst = RPMSG_ADDR_ANY;
262*4882a593Smuzhiyun mutex_lock(&mtk_subdev->channels_lock);
263*4882a593Smuzhiyun list_add(&info->list, &mtk_subdev->channels);
264*4882a593Smuzhiyun mutex_unlock(&mtk_subdev->channels_lock);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun schedule_work(&mtk_subdev->register_work);
267*4882a593Smuzhiyun return 0;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
mtk_rpmsg_ns_cb(struct rpmsg_device * rpdev,void * data,int len,void * priv,u32 src)270*4882a593Smuzhiyun static int mtk_rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
271*4882a593Smuzhiyun void *priv, u32 src)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun struct rpmsg_ns_msg *msg = data;
274*4882a593Smuzhiyun struct mtk_rpmsg_rproc_subdev *mtk_subdev = priv;
275*4882a593Smuzhiyun struct device *dev = &mtk_subdev->pdev->dev;
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun int ret;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun if (len != sizeof(*msg)) {
280*4882a593Smuzhiyun dev_err(dev, "malformed ns msg (%d)\n", len);
281*4882a593Smuzhiyun return -EINVAL;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun /*
285*4882a593Smuzhiyun * the name service ept does _not_ belong to a real rpmsg channel,
286*4882a593Smuzhiyun * and is handled by the rpmsg bus itself.
287*4882a593Smuzhiyun * for sanity reasons, make sure a valid rpdev has _not_ sneaked
288*4882a593Smuzhiyun * in somehow.
289*4882a593Smuzhiyun */
290*4882a593Smuzhiyun if (rpdev) {
291*4882a593Smuzhiyun dev_err(dev, "anomaly: ns ept has an rpdev handle\n");
292*4882a593Smuzhiyun return -EINVAL;
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun /* don't trust the remote processor for null terminating the name */
296*4882a593Smuzhiyun msg->name[RPMSG_NAME_SIZE - 1] = '\0';
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun dev_info(dev, "creating channel %s addr 0x%x\n", msg->name, msg->addr);
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun ret = mtk_rpmsg_create_device(mtk_subdev, msg->name, msg->addr);
301*4882a593Smuzhiyun if (ret) {
302*4882a593Smuzhiyun dev_err(dev, "create rpmsg device failed\n");
303*4882a593Smuzhiyun return ret;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun return 0;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun
mtk_rpmsg_prepare(struct rproc_subdev * subdev)309*4882a593Smuzhiyun static int mtk_rpmsg_prepare(struct rproc_subdev *subdev)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev);
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun /* a dedicated endpoint handles the name service msgs */
314*4882a593Smuzhiyun if (mtk_subdev->info->ns_ipi_id >= 0) {
315*4882a593Smuzhiyun mtk_subdev->ns_ept =
316*4882a593Smuzhiyun __mtk_create_ept(mtk_subdev, NULL, mtk_rpmsg_ns_cb,
317*4882a593Smuzhiyun mtk_subdev,
318*4882a593Smuzhiyun mtk_subdev->info->ns_ipi_id);
319*4882a593Smuzhiyun if (!mtk_subdev->ns_ept) {
320*4882a593Smuzhiyun dev_err(&mtk_subdev->pdev->dev,
321*4882a593Smuzhiyun "failed to create name service endpoint\n");
322*4882a593Smuzhiyun return -ENOMEM;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun return 0;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun
mtk_rpmsg_unprepare(struct rproc_subdev * subdev)329*4882a593Smuzhiyun static void mtk_rpmsg_unprepare(struct rproc_subdev *subdev)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev);
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun if (mtk_subdev->ns_ept) {
334*4882a593Smuzhiyun mtk_rpmsg_destroy_ept(mtk_subdev->ns_ept);
335*4882a593Smuzhiyun mtk_subdev->ns_ept = NULL;
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun
mtk_rpmsg_stop(struct rproc_subdev * subdev,bool crashed)339*4882a593Smuzhiyun static void mtk_rpmsg_stop(struct rproc_subdev *subdev, bool crashed)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun struct mtk_rpmsg_channel_info *info, *next;
342*4882a593Smuzhiyun struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev);
343*4882a593Smuzhiyun struct device *dev = &mtk_subdev->pdev->dev;
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun /*
346*4882a593Smuzhiyun * Destroy the name service endpoint here, to avoid new channel being
347*4882a593Smuzhiyun * created after the rpmsg_unregister_device loop below.
348*4882a593Smuzhiyun */
349*4882a593Smuzhiyun if (mtk_subdev->ns_ept) {
350*4882a593Smuzhiyun mtk_rpmsg_destroy_ept(mtk_subdev->ns_ept);
351*4882a593Smuzhiyun mtk_subdev->ns_ept = NULL;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun cancel_work_sync(&mtk_subdev->register_work);
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun mutex_lock(&mtk_subdev->channels_lock);
357*4882a593Smuzhiyun list_for_each_entry(info, &mtk_subdev->channels, list) {
358*4882a593Smuzhiyun if (!info->registered)
359*4882a593Smuzhiyun continue;
360*4882a593Smuzhiyun if (rpmsg_unregister_device(dev, &info->info)) {
361*4882a593Smuzhiyun dev_warn(
362*4882a593Smuzhiyun dev,
363*4882a593Smuzhiyun "rpmsg_unregister_device failed for %s.%d.%d\n",
364*4882a593Smuzhiyun info->info.name, info->info.src,
365*4882a593Smuzhiyun info->info.dst);
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun list_for_each_entry_safe(info, next,
370*4882a593Smuzhiyun &mtk_subdev->channels, list) {
371*4882a593Smuzhiyun list_del(&info->list);
372*4882a593Smuzhiyun kfree(info);
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun mutex_unlock(&mtk_subdev->channels_lock);
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun struct rproc_subdev *
mtk_rpmsg_create_rproc_subdev(struct platform_device * pdev,struct mtk_rpmsg_info * info)378*4882a593Smuzhiyun mtk_rpmsg_create_rproc_subdev(struct platform_device *pdev,
379*4882a593Smuzhiyun struct mtk_rpmsg_info *info)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun struct mtk_rpmsg_rproc_subdev *mtk_subdev;
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun mtk_subdev = kzalloc(sizeof(*mtk_subdev), GFP_KERNEL);
384*4882a593Smuzhiyun if (!mtk_subdev)
385*4882a593Smuzhiyun return NULL;
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun mtk_subdev->pdev = pdev;
388*4882a593Smuzhiyun mtk_subdev->subdev.prepare = mtk_rpmsg_prepare;
389*4882a593Smuzhiyun mtk_subdev->subdev.stop = mtk_rpmsg_stop;
390*4882a593Smuzhiyun mtk_subdev->subdev.unprepare = mtk_rpmsg_unprepare;
391*4882a593Smuzhiyun mtk_subdev->info = info;
392*4882a593Smuzhiyun INIT_LIST_HEAD(&mtk_subdev->channels);
393*4882a593Smuzhiyun INIT_WORK(&mtk_subdev->register_work,
394*4882a593Smuzhiyun mtk_register_device_work_function);
395*4882a593Smuzhiyun mutex_init(&mtk_subdev->channels_lock);
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun return &mtk_subdev->subdev;
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(mtk_rpmsg_create_rproc_subdev);
400*4882a593Smuzhiyun
mtk_rpmsg_destroy_rproc_subdev(struct rproc_subdev * subdev)401*4882a593Smuzhiyun void mtk_rpmsg_destroy_rproc_subdev(struct rproc_subdev *subdev)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev);
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun kfree(mtk_subdev);
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(mtk_rpmsg_destroy_rproc_subdev);
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
410*4882a593Smuzhiyun MODULE_DESCRIPTION("MediaTek scp rpmsg driver");
411