xref: /openbmc/linux/drivers/rpmsg/mtk_rpmsg.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
170179969SPi-Hsun Shih // SPDX-License-Identifier: GPL-2.0
270179969SPi-Hsun Shih //
370179969SPi-Hsun Shih // Copyright 2019 Google LLC.
470179969SPi-Hsun Shih 
570179969SPi-Hsun Shih #include <linux/kernel.h>
670179969SPi-Hsun Shih #include <linux/module.h>
770179969SPi-Hsun Shih #include <linux/of.h>
870179969SPi-Hsun Shih #include <linux/platform_device.h>
970179969SPi-Hsun Shih #include <linux/remoteproc.h>
1070179969SPi-Hsun Shih #include <linux/rpmsg/mtk_rpmsg.h>
113d820cd4SMichael S. Tsirkin #include <linux/slab.h>
1270179969SPi-Hsun Shih #include <linux/workqueue.h>
1370179969SPi-Hsun Shih 
1470179969SPi-Hsun Shih #include "rpmsg_internal.h"
1570179969SPi-Hsun Shih 
1670179969SPi-Hsun Shih struct mtk_rpmsg_rproc_subdev {
1770179969SPi-Hsun Shih 	struct platform_device *pdev;
1870179969SPi-Hsun Shih 	struct mtk_rpmsg_info *info;
1970179969SPi-Hsun Shih 	struct rpmsg_endpoint *ns_ept;
2070179969SPi-Hsun Shih 	struct rproc_subdev subdev;
2170179969SPi-Hsun Shih 
2270179969SPi-Hsun Shih 	struct work_struct register_work;
2370179969SPi-Hsun Shih 	struct list_head channels;
2470179969SPi-Hsun Shih 	struct mutex channels_lock;
2570179969SPi-Hsun Shih };
2670179969SPi-Hsun Shih 
2770179969SPi-Hsun Shih #define to_mtk_subdev(d) container_of(d, struct mtk_rpmsg_rproc_subdev, subdev)
2870179969SPi-Hsun Shih 
2970179969SPi-Hsun Shih struct mtk_rpmsg_channel_info {
3070179969SPi-Hsun Shih 	struct rpmsg_channel_info info;
3170179969SPi-Hsun Shih 	bool registered;
3270179969SPi-Hsun Shih 	struct list_head list;
3370179969SPi-Hsun Shih };
3470179969SPi-Hsun Shih 
3570179969SPi-Hsun Shih /**
3670179969SPi-Hsun Shih  * struct rpmsg_ns_msg - dynamic name service announcement message
3770179969SPi-Hsun Shih  * @name: name of remote service that is published
3870179969SPi-Hsun Shih  * @addr: address of remote service that is published
3970179969SPi-Hsun Shih  *
4070179969SPi-Hsun Shih  * This message is sent across to publish a new service. When we receive these
4170179969SPi-Hsun Shih  * messages, an appropriate rpmsg channel (i.e device) is created. In turn, the
4270179969SPi-Hsun Shih  * ->probe() handler of the appropriate rpmsg driver will be invoked
4370179969SPi-Hsun Shih  *  (if/as-soon-as one is registered).
4470179969SPi-Hsun Shih  */
4570179969SPi-Hsun Shih struct rpmsg_ns_msg {
4670179969SPi-Hsun Shih 	char name[RPMSG_NAME_SIZE];
4770179969SPi-Hsun Shih 	u32 addr;
4870179969SPi-Hsun Shih } __packed;
4970179969SPi-Hsun Shih 
5070179969SPi-Hsun Shih struct mtk_rpmsg_device {
5170179969SPi-Hsun Shih 	struct rpmsg_device rpdev;
5270179969SPi-Hsun Shih 	struct mtk_rpmsg_rproc_subdev *mtk_subdev;
5370179969SPi-Hsun Shih };
5470179969SPi-Hsun Shih 
5570179969SPi-Hsun Shih struct mtk_rpmsg_endpoint {
5670179969SPi-Hsun Shih 	struct rpmsg_endpoint ept;
5770179969SPi-Hsun Shih 	struct mtk_rpmsg_rproc_subdev *mtk_subdev;
5870179969SPi-Hsun Shih };
5970179969SPi-Hsun Shih 
6070179969SPi-Hsun Shih #define to_mtk_rpmsg_device(r) container_of(r, struct mtk_rpmsg_device, rpdev)
6170179969SPi-Hsun Shih #define to_mtk_rpmsg_endpoint(r) container_of(r, struct mtk_rpmsg_endpoint, ept)
6270179969SPi-Hsun Shih 
6370179969SPi-Hsun Shih static const struct rpmsg_endpoint_ops mtk_rpmsg_endpoint_ops;
6470179969SPi-Hsun Shih 
__mtk_ept_release(struct kref * kref)6570179969SPi-Hsun Shih static void __mtk_ept_release(struct kref *kref)
6670179969SPi-Hsun Shih {
6770179969SPi-Hsun Shih 	struct rpmsg_endpoint *ept = container_of(kref, struct rpmsg_endpoint,
6870179969SPi-Hsun Shih 						  refcount);
6970179969SPi-Hsun Shih 	kfree(to_mtk_rpmsg_endpoint(ept));
7070179969SPi-Hsun Shih }
7170179969SPi-Hsun Shih 
mtk_rpmsg_ipi_handler(void * data,unsigned int len,void * priv)7270179969SPi-Hsun Shih static void mtk_rpmsg_ipi_handler(void *data, unsigned int len, void *priv)
7370179969SPi-Hsun Shih {
7470179969SPi-Hsun Shih 	struct mtk_rpmsg_endpoint *mept = priv;
7570179969SPi-Hsun Shih 	struct rpmsg_endpoint *ept = &mept->ept;
7670179969SPi-Hsun Shih 	int ret;
7770179969SPi-Hsun Shih 
7870179969SPi-Hsun Shih 	ret = (*ept->cb)(ept->rpdev, data, len, ept->priv, ept->addr);
7970179969SPi-Hsun Shih 	if (ret)
8070179969SPi-Hsun Shih 		dev_warn(&ept->rpdev->dev, "rpmsg handler return error = %d",
8170179969SPi-Hsun Shih 			 ret);
8270179969SPi-Hsun Shih }
8370179969SPi-Hsun Shih 
8470179969SPi-Hsun Shih 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)8570179969SPi-Hsun Shih __mtk_create_ept(struct mtk_rpmsg_rproc_subdev *mtk_subdev,
8670179969SPi-Hsun Shih 		 struct rpmsg_device *rpdev, rpmsg_rx_cb_t cb, void *priv,
8770179969SPi-Hsun Shih 		 u32 id)
8870179969SPi-Hsun Shih {
8970179969SPi-Hsun Shih 	struct mtk_rpmsg_endpoint *mept;
9070179969SPi-Hsun Shih 	struct rpmsg_endpoint *ept;
9170179969SPi-Hsun Shih 	struct platform_device *pdev = mtk_subdev->pdev;
9270179969SPi-Hsun Shih 	int ret;
9370179969SPi-Hsun Shih 
9470179969SPi-Hsun Shih 	mept = kzalloc(sizeof(*mept), GFP_KERNEL);
9570179969SPi-Hsun Shih 	if (!mept)
9670179969SPi-Hsun Shih 		return NULL;
9770179969SPi-Hsun Shih 	mept->mtk_subdev = mtk_subdev;
9870179969SPi-Hsun Shih 
9970179969SPi-Hsun Shih 	ept = &mept->ept;
10070179969SPi-Hsun Shih 	kref_init(&ept->refcount);
10170179969SPi-Hsun Shih 
10270179969SPi-Hsun Shih 	ept->rpdev = rpdev;
10370179969SPi-Hsun Shih 	ept->cb = cb;
10470179969SPi-Hsun Shih 	ept->priv = priv;
10570179969SPi-Hsun Shih 	ept->ops = &mtk_rpmsg_endpoint_ops;
10670179969SPi-Hsun Shih 	ept->addr = id;
10770179969SPi-Hsun Shih 
10870179969SPi-Hsun Shih 	ret = mtk_subdev->info->register_ipi(pdev, id, mtk_rpmsg_ipi_handler,
10970179969SPi-Hsun Shih 					     mept);
11070179969SPi-Hsun Shih 	if (ret) {
11170179969SPi-Hsun Shih 		dev_err(&pdev->dev, "IPI register failed, id = %d", id);
11270179969SPi-Hsun Shih 		kref_put(&ept->refcount, __mtk_ept_release);
11370179969SPi-Hsun Shih 		return NULL;
11470179969SPi-Hsun Shih 	}
11570179969SPi-Hsun Shih 
11670179969SPi-Hsun Shih 	return ept;
11770179969SPi-Hsun Shih }
11870179969SPi-Hsun Shih 
11970179969SPi-Hsun Shih static struct rpmsg_endpoint *
mtk_rpmsg_create_ept(struct rpmsg_device * rpdev,rpmsg_rx_cb_t cb,void * priv,struct rpmsg_channel_info chinfo)12070179969SPi-Hsun Shih mtk_rpmsg_create_ept(struct rpmsg_device *rpdev, rpmsg_rx_cb_t cb, void *priv,
12170179969SPi-Hsun Shih 		     struct rpmsg_channel_info chinfo)
12270179969SPi-Hsun Shih {
12370179969SPi-Hsun Shih 	struct mtk_rpmsg_rproc_subdev *mtk_subdev =
12470179969SPi-Hsun Shih 		to_mtk_rpmsg_device(rpdev)->mtk_subdev;
12570179969SPi-Hsun Shih 
12670179969SPi-Hsun Shih 	return __mtk_create_ept(mtk_subdev, rpdev, cb, priv, chinfo.src);
12770179969SPi-Hsun Shih }
12870179969SPi-Hsun Shih 
mtk_rpmsg_destroy_ept(struct rpmsg_endpoint * ept)12970179969SPi-Hsun Shih static void mtk_rpmsg_destroy_ept(struct rpmsg_endpoint *ept)
13070179969SPi-Hsun Shih {
13170179969SPi-Hsun Shih 	struct mtk_rpmsg_rproc_subdev *mtk_subdev =
13270179969SPi-Hsun Shih 		to_mtk_rpmsg_endpoint(ept)->mtk_subdev;
13370179969SPi-Hsun Shih 
13470179969SPi-Hsun Shih 	mtk_subdev->info->unregister_ipi(mtk_subdev->pdev, ept->addr);
13570179969SPi-Hsun Shih 	kref_put(&ept->refcount, __mtk_ept_release);
13670179969SPi-Hsun Shih }
13770179969SPi-Hsun Shih 
mtk_rpmsg_send(struct rpmsg_endpoint * ept,void * data,int len)13870179969SPi-Hsun Shih static int mtk_rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len)
13970179969SPi-Hsun Shih {
14070179969SPi-Hsun Shih 	struct mtk_rpmsg_rproc_subdev *mtk_subdev =
14170179969SPi-Hsun Shih 		to_mtk_rpmsg_endpoint(ept)->mtk_subdev;
14270179969SPi-Hsun Shih 
14370179969SPi-Hsun Shih 	return mtk_subdev->info->send_ipi(mtk_subdev->pdev, ept->addr, data,
14470179969SPi-Hsun Shih 					  len, 0);
14570179969SPi-Hsun Shih }
14670179969SPi-Hsun Shih 
mtk_rpmsg_trysend(struct rpmsg_endpoint * ept,void * data,int len)14770179969SPi-Hsun Shih static int mtk_rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len)
14870179969SPi-Hsun Shih {
14970179969SPi-Hsun Shih 	struct mtk_rpmsg_rproc_subdev *mtk_subdev =
15070179969SPi-Hsun Shih 		to_mtk_rpmsg_endpoint(ept)->mtk_subdev;
15170179969SPi-Hsun Shih 
15270179969SPi-Hsun Shih 	/*
15370179969SPi-Hsun Shih 	 * TODO: This currently is same as mtk_rpmsg_send, and wait until SCP
15470179969SPi-Hsun Shih 	 * received the last command.
15570179969SPi-Hsun Shih 	 */
15670179969SPi-Hsun Shih 	return mtk_subdev->info->send_ipi(mtk_subdev->pdev, ept->addr, data,
15770179969SPi-Hsun Shih 					  len, 0);
15870179969SPi-Hsun Shih }
15970179969SPi-Hsun Shih 
16070179969SPi-Hsun Shih static const struct rpmsg_endpoint_ops mtk_rpmsg_endpoint_ops = {
16170179969SPi-Hsun Shih 	.destroy_ept = mtk_rpmsg_destroy_ept,
16270179969SPi-Hsun Shih 	.send = mtk_rpmsg_send,
16370179969SPi-Hsun Shih 	.trysend = mtk_rpmsg_trysend,
16470179969SPi-Hsun Shih };
16570179969SPi-Hsun Shih 
mtk_rpmsg_release_device(struct device * dev)16670179969SPi-Hsun Shih static void mtk_rpmsg_release_device(struct device *dev)
16770179969SPi-Hsun Shih {
16870179969SPi-Hsun Shih 	struct rpmsg_device *rpdev = to_rpmsg_device(dev);
16970179969SPi-Hsun Shih 	struct mtk_rpmsg_device *mdev = to_mtk_rpmsg_device(rpdev);
17070179969SPi-Hsun Shih 
17170179969SPi-Hsun Shih 	kfree(mdev);
17270179969SPi-Hsun Shih }
17370179969SPi-Hsun Shih 
17470179969SPi-Hsun Shih static const struct rpmsg_device_ops mtk_rpmsg_device_ops = {
17570179969SPi-Hsun Shih 	.create_ept = mtk_rpmsg_create_ept,
17670179969SPi-Hsun Shih };
17770179969SPi-Hsun Shih 
17870179969SPi-Hsun Shih static struct device_node *
mtk_rpmsg_match_device_subnode(struct device_node * node,const char * channel)17970179969SPi-Hsun Shih mtk_rpmsg_match_device_subnode(struct device_node *node, const char *channel)
18070179969SPi-Hsun Shih {
18170179969SPi-Hsun Shih 	struct device_node *child;
18270179969SPi-Hsun Shih 	const char *name;
18370179969SPi-Hsun Shih 	int ret;
18470179969SPi-Hsun Shih 
18570179969SPi-Hsun Shih 	for_each_available_child_of_node(node, child) {
18654c9237aSTinghan Shen 		ret = of_property_read_string(child, "mediatek,rpmsg-name", &name);
18770179969SPi-Hsun Shih 		if (ret)
18870179969SPi-Hsun Shih 			continue;
18970179969SPi-Hsun Shih 
19070179969SPi-Hsun Shih 		if (strcmp(name, channel) == 0)
19170179969SPi-Hsun Shih 			return child;
19270179969SPi-Hsun Shih 	}
19370179969SPi-Hsun Shih 
19470179969SPi-Hsun Shih 	return NULL;
19570179969SPi-Hsun Shih }
19670179969SPi-Hsun Shih 
mtk_rpmsg_register_device(struct mtk_rpmsg_rproc_subdev * mtk_subdev,struct rpmsg_channel_info * info)19770179969SPi-Hsun Shih static int mtk_rpmsg_register_device(struct mtk_rpmsg_rproc_subdev *mtk_subdev,
19870179969SPi-Hsun Shih 				     struct rpmsg_channel_info *info)
19970179969SPi-Hsun Shih {
20070179969SPi-Hsun Shih 	struct rpmsg_device *rpdev;
20170179969SPi-Hsun Shih 	struct mtk_rpmsg_device *mdev;
20270179969SPi-Hsun Shih 	struct platform_device *pdev = mtk_subdev->pdev;
20370179969SPi-Hsun Shih 
20470179969SPi-Hsun Shih 	mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
20570179969SPi-Hsun Shih 	if (!mdev)
20670179969SPi-Hsun Shih 		return -ENOMEM;
20770179969SPi-Hsun Shih 
20870179969SPi-Hsun Shih 	mdev->mtk_subdev = mtk_subdev;
20970179969SPi-Hsun Shih 
21070179969SPi-Hsun Shih 	rpdev = &mdev->rpdev;
21170179969SPi-Hsun Shih 	rpdev->ops = &mtk_rpmsg_device_ops;
21270179969SPi-Hsun Shih 	rpdev->src = info->src;
21370179969SPi-Hsun Shih 	rpdev->dst = info->dst;
21470179969SPi-Hsun Shih 	strscpy(rpdev->id.name, info->name, RPMSG_NAME_SIZE);
21570179969SPi-Hsun Shih 
21670179969SPi-Hsun Shih 	rpdev->dev.of_node =
21770179969SPi-Hsun Shih 		mtk_rpmsg_match_device_subnode(pdev->dev.of_node, info->name);
21870179969SPi-Hsun Shih 	rpdev->dev.parent = &pdev->dev;
21970179969SPi-Hsun Shih 	rpdev->dev.release = mtk_rpmsg_release_device;
22070179969SPi-Hsun Shih 
221231331b2SNicolas Boichat 	return rpmsg_register_device(rpdev);
22270179969SPi-Hsun Shih }
22370179969SPi-Hsun Shih 
mtk_register_device_work_function(struct work_struct * register_work)22470179969SPi-Hsun Shih static void mtk_register_device_work_function(struct work_struct *register_work)
22570179969SPi-Hsun Shih {
22670179969SPi-Hsun Shih 	struct mtk_rpmsg_rproc_subdev *subdev = container_of(
22770179969SPi-Hsun Shih 		register_work, struct mtk_rpmsg_rproc_subdev, register_work);
22870179969SPi-Hsun Shih 	struct platform_device *pdev = subdev->pdev;
22970179969SPi-Hsun Shih 	struct mtk_rpmsg_channel_info *info;
23070179969SPi-Hsun Shih 	int ret;
23170179969SPi-Hsun Shih 
23270179969SPi-Hsun Shih 	mutex_lock(&subdev->channels_lock);
23370179969SPi-Hsun Shih 	list_for_each_entry(info, &subdev->channels, list) {
23470179969SPi-Hsun Shih 		if (info->registered)
23570179969SPi-Hsun Shih 			continue;
23670179969SPi-Hsun Shih 
237*353d9214SAngeloGioacchino Del Regno 		mutex_unlock(&subdev->channels_lock);
23870179969SPi-Hsun Shih 		ret = mtk_rpmsg_register_device(subdev, &info->info);
239*353d9214SAngeloGioacchino Del Regno 		mutex_lock(&subdev->channels_lock);
24070179969SPi-Hsun Shih 		if (ret) {
24170179969SPi-Hsun Shih 			dev_err(&pdev->dev, "Can't create rpmsg_device\n");
24270179969SPi-Hsun Shih 			continue;
24370179969SPi-Hsun Shih 		}
24470179969SPi-Hsun Shih 
24570179969SPi-Hsun Shih 		info->registered = true;
24670179969SPi-Hsun Shih 	}
24770179969SPi-Hsun Shih 	mutex_unlock(&subdev->channels_lock);
24870179969SPi-Hsun Shih }
24970179969SPi-Hsun Shih 
mtk_rpmsg_create_device(struct mtk_rpmsg_rproc_subdev * mtk_subdev,char * name,u32 addr)25070179969SPi-Hsun Shih static int mtk_rpmsg_create_device(struct mtk_rpmsg_rproc_subdev *mtk_subdev,
25170179969SPi-Hsun Shih 				   char *name, u32 addr)
25270179969SPi-Hsun Shih {
25370179969SPi-Hsun Shih 	struct mtk_rpmsg_channel_info *info;
25470179969SPi-Hsun Shih 
25570179969SPi-Hsun Shih 	info = kzalloc(sizeof(*info), GFP_KERNEL);
25670179969SPi-Hsun Shih 	if (!info)
25770179969SPi-Hsun Shih 		return -ENOMEM;
25870179969SPi-Hsun Shih 
25970179969SPi-Hsun Shih 	strscpy(info->info.name, name, RPMSG_NAME_SIZE);
26070179969SPi-Hsun Shih 	info->info.src = addr;
26170179969SPi-Hsun Shih 	info->info.dst = RPMSG_ADDR_ANY;
26270179969SPi-Hsun Shih 	mutex_lock(&mtk_subdev->channels_lock);
26370179969SPi-Hsun Shih 	list_add(&info->list, &mtk_subdev->channels);
26470179969SPi-Hsun Shih 	mutex_unlock(&mtk_subdev->channels_lock);
26570179969SPi-Hsun Shih 
26670179969SPi-Hsun Shih 	schedule_work(&mtk_subdev->register_work);
26770179969SPi-Hsun Shih 	return 0;
26870179969SPi-Hsun Shih }
26970179969SPi-Hsun Shih 
mtk_rpmsg_ns_cb(struct rpmsg_device * rpdev,void * data,int len,void * priv,u32 src)27070179969SPi-Hsun Shih static int mtk_rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
27170179969SPi-Hsun Shih 			   void *priv, u32 src)
27270179969SPi-Hsun Shih {
27370179969SPi-Hsun Shih 	struct rpmsg_ns_msg *msg = data;
27470179969SPi-Hsun Shih 	struct mtk_rpmsg_rproc_subdev *mtk_subdev = priv;
27570179969SPi-Hsun Shih 	struct device *dev = &mtk_subdev->pdev->dev;
27670179969SPi-Hsun Shih 
27770179969SPi-Hsun Shih 	int ret;
27870179969SPi-Hsun Shih 
27970179969SPi-Hsun Shih 	if (len != sizeof(*msg)) {
28070179969SPi-Hsun Shih 		dev_err(dev, "malformed ns msg (%d)\n", len);
28170179969SPi-Hsun Shih 		return -EINVAL;
28270179969SPi-Hsun Shih 	}
28370179969SPi-Hsun Shih 
28470179969SPi-Hsun Shih 	/*
28570179969SPi-Hsun Shih 	 * the name service ept does _not_ belong to a real rpmsg channel,
28670179969SPi-Hsun Shih 	 * and is handled by the rpmsg bus itself.
28770179969SPi-Hsun Shih 	 * for sanity reasons, make sure a valid rpdev has _not_ sneaked
28870179969SPi-Hsun Shih 	 * in somehow.
28970179969SPi-Hsun Shih 	 */
29070179969SPi-Hsun Shih 	if (rpdev) {
29170179969SPi-Hsun Shih 		dev_err(dev, "anomaly: ns ept has an rpdev handle\n");
29270179969SPi-Hsun Shih 		return -EINVAL;
29370179969SPi-Hsun Shih 	}
29470179969SPi-Hsun Shih 
29570179969SPi-Hsun Shih 	/* don't trust the remote processor for null terminating the name */
29670179969SPi-Hsun Shih 	msg->name[RPMSG_NAME_SIZE - 1] = '\0';
29770179969SPi-Hsun Shih 
29870179969SPi-Hsun Shih 	dev_info(dev, "creating channel %s addr 0x%x\n", msg->name, msg->addr);
29970179969SPi-Hsun Shih 
30070179969SPi-Hsun Shih 	ret = mtk_rpmsg_create_device(mtk_subdev, msg->name, msg->addr);
30170179969SPi-Hsun Shih 	if (ret) {
30270179969SPi-Hsun Shih 		dev_err(dev, "create rpmsg device failed\n");
30370179969SPi-Hsun Shih 		return ret;
30470179969SPi-Hsun Shih 	}
30570179969SPi-Hsun Shih 
30670179969SPi-Hsun Shih 	return 0;
30770179969SPi-Hsun Shih }
30870179969SPi-Hsun Shih 
mtk_rpmsg_prepare(struct rproc_subdev * subdev)30970179969SPi-Hsun Shih static int mtk_rpmsg_prepare(struct rproc_subdev *subdev)
31070179969SPi-Hsun Shih {
31170179969SPi-Hsun Shih 	struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev);
31270179969SPi-Hsun Shih 
31370179969SPi-Hsun Shih 	/* a dedicated endpoint handles the name service msgs */
31470179969SPi-Hsun Shih 	if (mtk_subdev->info->ns_ipi_id >= 0) {
31570179969SPi-Hsun Shih 		mtk_subdev->ns_ept =
31670179969SPi-Hsun Shih 			__mtk_create_ept(mtk_subdev, NULL, mtk_rpmsg_ns_cb,
31770179969SPi-Hsun Shih 					 mtk_subdev,
31870179969SPi-Hsun Shih 					 mtk_subdev->info->ns_ipi_id);
31970179969SPi-Hsun Shih 		if (!mtk_subdev->ns_ept) {
32070179969SPi-Hsun Shih 			dev_err(&mtk_subdev->pdev->dev,
32170179969SPi-Hsun Shih 				"failed to create name service endpoint\n");
32270179969SPi-Hsun Shih 			return -ENOMEM;
32370179969SPi-Hsun Shih 		}
32470179969SPi-Hsun Shih 	}
32570179969SPi-Hsun Shih 
32670179969SPi-Hsun Shih 	return 0;
32770179969SPi-Hsun Shih }
32870179969SPi-Hsun Shih 
mtk_rpmsg_unprepare(struct rproc_subdev * subdev)32970179969SPi-Hsun Shih static void mtk_rpmsg_unprepare(struct rproc_subdev *subdev)
33070179969SPi-Hsun Shih {
33170179969SPi-Hsun Shih 	struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev);
33270179969SPi-Hsun Shih 
33370179969SPi-Hsun Shih 	if (mtk_subdev->ns_ept) {
33470179969SPi-Hsun Shih 		mtk_rpmsg_destroy_ept(mtk_subdev->ns_ept);
33570179969SPi-Hsun Shih 		mtk_subdev->ns_ept = NULL;
33670179969SPi-Hsun Shih 	}
33770179969SPi-Hsun Shih }
33870179969SPi-Hsun Shih 
mtk_rpmsg_stop(struct rproc_subdev * subdev,bool crashed)33970179969SPi-Hsun Shih static void mtk_rpmsg_stop(struct rproc_subdev *subdev, bool crashed)
34070179969SPi-Hsun Shih {
34170179969SPi-Hsun Shih 	struct mtk_rpmsg_channel_info *info, *next;
34270179969SPi-Hsun Shih 	struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev);
34370179969SPi-Hsun Shih 	struct device *dev = &mtk_subdev->pdev->dev;
34470179969SPi-Hsun Shih 
34570179969SPi-Hsun Shih 	/*
34670179969SPi-Hsun Shih 	 * Destroy the name service endpoint here, to avoid new channel being
34770179969SPi-Hsun Shih 	 * created after the rpmsg_unregister_device loop below.
34870179969SPi-Hsun Shih 	 */
34970179969SPi-Hsun Shih 	if (mtk_subdev->ns_ept) {
35070179969SPi-Hsun Shih 		mtk_rpmsg_destroy_ept(mtk_subdev->ns_ept);
35170179969SPi-Hsun Shih 		mtk_subdev->ns_ept = NULL;
35270179969SPi-Hsun Shih 	}
35370179969SPi-Hsun Shih 
35470179969SPi-Hsun Shih 	cancel_work_sync(&mtk_subdev->register_work);
35570179969SPi-Hsun Shih 
35670179969SPi-Hsun Shih 	mutex_lock(&mtk_subdev->channels_lock);
35770179969SPi-Hsun Shih 	list_for_each_entry(info, &mtk_subdev->channels, list) {
35870179969SPi-Hsun Shih 		if (!info->registered)
35970179969SPi-Hsun Shih 			continue;
36070179969SPi-Hsun Shih 		if (rpmsg_unregister_device(dev, &info->info)) {
36170179969SPi-Hsun Shih 			dev_warn(
36270179969SPi-Hsun Shih 				dev,
36370179969SPi-Hsun Shih 				"rpmsg_unregister_device failed for %s.%d.%d\n",
36470179969SPi-Hsun Shih 				info->info.name, info->info.src,
36570179969SPi-Hsun Shih 				info->info.dst);
36670179969SPi-Hsun Shih 		}
36770179969SPi-Hsun Shih 	}
36870179969SPi-Hsun Shih 
36970179969SPi-Hsun Shih 	list_for_each_entry_safe(info, next,
37070179969SPi-Hsun Shih 				 &mtk_subdev->channels, list) {
37170179969SPi-Hsun Shih 		list_del(&info->list);
37270179969SPi-Hsun Shih 		kfree(info);
37370179969SPi-Hsun Shih 	}
37470179969SPi-Hsun Shih 	mutex_unlock(&mtk_subdev->channels_lock);
37570179969SPi-Hsun Shih }
37670179969SPi-Hsun Shih 
37770179969SPi-Hsun Shih struct rproc_subdev *
mtk_rpmsg_create_rproc_subdev(struct platform_device * pdev,struct mtk_rpmsg_info * info)37870179969SPi-Hsun Shih mtk_rpmsg_create_rproc_subdev(struct platform_device *pdev,
37970179969SPi-Hsun Shih 			      struct mtk_rpmsg_info *info)
38070179969SPi-Hsun Shih {
38170179969SPi-Hsun Shih 	struct mtk_rpmsg_rproc_subdev *mtk_subdev;
38270179969SPi-Hsun Shih 
38370179969SPi-Hsun Shih 	mtk_subdev = kzalloc(sizeof(*mtk_subdev), GFP_KERNEL);
38470179969SPi-Hsun Shih 	if (!mtk_subdev)
38570179969SPi-Hsun Shih 		return NULL;
38670179969SPi-Hsun Shih 
38770179969SPi-Hsun Shih 	mtk_subdev->pdev = pdev;
38870179969SPi-Hsun Shih 	mtk_subdev->subdev.prepare = mtk_rpmsg_prepare;
38970179969SPi-Hsun Shih 	mtk_subdev->subdev.stop = mtk_rpmsg_stop;
39070179969SPi-Hsun Shih 	mtk_subdev->subdev.unprepare = mtk_rpmsg_unprepare;
39170179969SPi-Hsun Shih 	mtk_subdev->info = info;
39270179969SPi-Hsun Shih 	INIT_LIST_HEAD(&mtk_subdev->channels);
39370179969SPi-Hsun Shih 	INIT_WORK(&mtk_subdev->register_work,
39470179969SPi-Hsun Shih 		  mtk_register_device_work_function);
39570179969SPi-Hsun Shih 	mutex_init(&mtk_subdev->channels_lock);
39670179969SPi-Hsun Shih 
39770179969SPi-Hsun Shih 	return &mtk_subdev->subdev;
39870179969SPi-Hsun Shih }
39970179969SPi-Hsun Shih EXPORT_SYMBOL_GPL(mtk_rpmsg_create_rproc_subdev);
40070179969SPi-Hsun Shih 
mtk_rpmsg_destroy_rproc_subdev(struct rproc_subdev * subdev)40170179969SPi-Hsun Shih void mtk_rpmsg_destroy_rproc_subdev(struct rproc_subdev *subdev)
40270179969SPi-Hsun Shih {
40370179969SPi-Hsun Shih 	struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev);
40470179969SPi-Hsun Shih 
40570179969SPi-Hsun Shih 	kfree(mtk_subdev);
40670179969SPi-Hsun Shih }
40770179969SPi-Hsun Shih EXPORT_SYMBOL_GPL(mtk_rpmsg_destroy_rproc_subdev);
40870179969SPi-Hsun Shih 
40970179969SPi-Hsun Shih MODULE_LICENSE("GPL v2");
41070179969SPi-Hsun Shih MODULE_DESCRIPTION("MediaTek scp rpmsg driver");
411