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