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 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 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 * 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 * 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 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 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 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 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 * 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) { 18670179969SPi-Hsun Shih ret = of_property_read_string(child, "mtk,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 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 221*231331b2SNicolas Boichat return rpmsg_register_device(rpdev); 22270179969SPi-Hsun Shih } 22370179969SPi-Hsun Shih 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 23770179969SPi-Hsun Shih ret = mtk_rpmsg_register_device(subdev, &info->info); 23870179969SPi-Hsun Shih if (ret) { 23970179969SPi-Hsun Shih dev_err(&pdev->dev, "Can't create rpmsg_device\n"); 24070179969SPi-Hsun Shih continue; 24170179969SPi-Hsun Shih } 24270179969SPi-Hsun Shih 24370179969SPi-Hsun Shih info->registered = true; 24470179969SPi-Hsun Shih } 24570179969SPi-Hsun Shih mutex_unlock(&subdev->channels_lock); 24670179969SPi-Hsun Shih } 24770179969SPi-Hsun Shih 24870179969SPi-Hsun Shih static int mtk_rpmsg_create_device(struct mtk_rpmsg_rproc_subdev *mtk_subdev, 24970179969SPi-Hsun Shih char *name, u32 addr) 25070179969SPi-Hsun Shih { 25170179969SPi-Hsun Shih struct mtk_rpmsg_channel_info *info; 25270179969SPi-Hsun Shih 25370179969SPi-Hsun Shih info = kzalloc(sizeof(*info), GFP_KERNEL); 25470179969SPi-Hsun Shih if (!info) 25570179969SPi-Hsun Shih return -ENOMEM; 25670179969SPi-Hsun Shih 25770179969SPi-Hsun Shih strscpy(info->info.name, name, RPMSG_NAME_SIZE); 25870179969SPi-Hsun Shih info->info.src = addr; 25970179969SPi-Hsun Shih info->info.dst = RPMSG_ADDR_ANY; 26070179969SPi-Hsun Shih mutex_lock(&mtk_subdev->channels_lock); 26170179969SPi-Hsun Shih list_add(&info->list, &mtk_subdev->channels); 26270179969SPi-Hsun Shih mutex_unlock(&mtk_subdev->channels_lock); 26370179969SPi-Hsun Shih 26470179969SPi-Hsun Shih schedule_work(&mtk_subdev->register_work); 26570179969SPi-Hsun Shih return 0; 26670179969SPi-Hsun Shih } 26770179969SPi-Hsun Shih 26870179969SPi-Hsun Shih static int mtk_rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len, 26970179969SPi-Hsun Shih void *priv, u32 src) 27070179969SPi-Hsun Shih { 27170179969SPi-Hsun Shih struct rpmsg_ns_msg *msg = data; 27270179969SPi-Hsun Shih struct mtk_rpmsg_rproc_subdev *mtk_subdev = priv; 27370179969SPi-Hsun Shih struct device *dev = &mtk_subdev->pdev->dev; 27470179969SPi-Hsun Shih 27570179969SPi-Hsun Shih int ret; 27670179969SPi-Hsun Shih 27770179969SPi-Hsun Shih if (len != sizeof(*msg)) { 27870179969SPi-Hsun Shih dev_err(dev, "malformed ns msg (%d)\n", len); 27970179969SPi-Hsun Shih return -EINVAL; 28070179969SPi-Hsun Shih } 28170179969SPi-Hsun Shih 28270179969SPi-Hsun Shih /* 28370179969SPi-Hsun Shih * the name service ept does _not_ belong to a real rpmsg channel, 28470179969SPi-Hsun Shih * and is handled by the rpmsg bus itself. 28570179969SPi-Hsun Shih * for sanity reasons, make sure a valid rpdev has _not_ sneaked 28670179969SPi-Hsun Shih * in somehow. 28770179969SPi-Hsun Shih */ 28870179969SPi-Hsun Shih if (rpdev) { 28970179969SPi-Hsun Shih dev_err(dev, "anomaly: ns ept has an rpdev handle\n"); 29070179969SPi-Hsun Shih return -EINVAL; 29170179969SPi-Hsun Shih } 29270179969SPi-Hsun Shih 29370179969SPi-Hsun Shih /* don't trust the remote processor for null terminating the name */ 29470179969SPi-Hsun Shih msg->name[RPMSG_NAME_SIZE - 1] = '\0'; 29570179969SPi-Hsun Shih 29670179969SPi-Hsun Shih dev_info(dev, "creating channel %s addr 0x%x\n", msg->name, msg->addr); 29770179969SPi-Hsun Shih 29870179969SPi-Hsun Shih ret = mtk_rpmsg_create_device(mtk_subdev, msg->name, msg->addr); 29970179969SPi-Hsun Shih if (ret) { 30070179969SPi-Hsun Shih dev_err(dev, "create rpmsg device failed\n"); 30170179969SPi-Hsun Shih return ret; 30270179969SPi-Hsun Shih } 30370179969SPi-Hsun Shih 30470179969SPi-Hsun Shih return 0; 30570179969SPi-Hsun Shih } 30670179969SPi-Hsun Shih 30770179969SPi-Hsun Shih static int mtk_rpmsg_prepare(struct rproc_subdev *subdev) 30870179969SPi-Hsun Shih { 30970179969SPi-Hsun Shih struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev); 31070179969SPi-Hsun Shih 31170179969SPi-Hsun Shih /* a dedicated endpoint handles the name service msgs */ 31270179969SPi-Hsun Shih if (mtk_subdev->info->ns_ipi_id >= 0) { 31370179969SPi-Hsun Shih mtk_subdev->ns_ept = 31470179969SPi-Hsun Shih __mtk_create_ept(mtk_subdev, NULL, mtk_rpmsg_ns_cb, 31570179969SPi-Hsun Shih mtk_subdev, 31670179969SPi-Hsun Shih mtk_subdev->info->ns_ipi_id); 31770179969SPi-Hsun Shih if (!mtk_subdev->ns_ept) { 31870179969SPi-Hsun Shih dev_err(&mtk_subdev->pdev->dev, 31970179969SPi-Hsun Shih "failed to create name service endpoint\n"); 32070179969SPi-Hsun Shih return -ENOMEM; 32170179969SPi-Hsun Shih } 32270179969SPi-Hsun Shih } 32370179969SPi-Hsun Shih 32470179969SPi-Hsun Shih return 0; 32570179969SPi-Hsun Shih } 32670179969SPi-Hsun Shih 32770179969SPi-Hsun Shih static void mtk_rpmsg_unprepare(struct rproc_subdev *subdev) 32870179969SPi-Hsun Shih { 32970179969SPi-Hsun Shih struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev); 33070179969SPi-Hsun Shih 33170179969SPi-Hsun Shih if (mtk_subdev->ns_ept) { 33270179969SPi-Hsun Shih mtk_rpmsg_destroy_ept(mtk_subdev->ns_ept); 33370179969SPi-Hsun Shih mtk_subdev->ns_ept = NULL; 33470179969SPi-Hsun Shih } 33570179969SPi-Hsun Shih } 33670179969SPi-Hsun Shih 33770179969SPi-Hsun Shih static void mtk_rpmsg_stop(struct rproc_subdev *subdev, bool crashed) 33870179969SPi-Hsun Shih { 33970179969SPi-Hsun Shih struct mtk_rpmsg_channel_info *info, *next; 34070179969SPi-Hsun Shih struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev); 34170179969SPi-Hsun Shih struct device *dev = &mtk_subdev->pdev->dev; 34270179969SPi-Hsun Shih 34370179969SPi-Hsun Shih /* 34470179969SPi-Hsun Shih * Destroy the name service endpoint here, to avoid new channel being 34570179969SPi-Hsun Shih * created after the rpmsg_unregister_device loop below. 34670179969SPi-Hsun Shih */ 34770179969SPi-Hsun Shih if (mtk_subdev->ns_ept) { 34870179969SPi-Hsun Shih mtk_rpmsg_destroy_ept(mtk_subdev->ns_ept); 34970179969SPi-Hsun Shih mtk_subdev->ns_ept = NULL; 35070179969SPi-Hsun Shih } 35170179969SPi-Hsun Shih 35270179969SPi-Hsun Shih cancel_work_sync(&mtk_subdev->register_work); 35370179969SPi-Hsun Shih 35470179969SPi-Hsun Shih mutex_lock(&mtk_subdev->channels_lock); 35570179969SPi-Hsun Shih list_for_each_entry(info, &mtk_subdev->channels, list) { 35670179969SPi-Hsun Shih if (!info->registered) 35770179969SPi-Hsun Shih continue; 35870179969SPi-Hsun Shih if (rpmsg_unregister_device(dev, &info->info)) { 35970179969SPi-Hsun Shih dev_warn( 36070179969SPi-Hsun Shih dev, 36170179969SPi-Hsun Shih "rpmsg_unregister_device failed for %s.%d.%d\n", 36270179969SPi-Hsun Shih info->info.name, info->info.src, 36370179969SPi-Hsun Shih info->info.dst); 36470179969SPi-Hsun Shih } 36570179969SPi-Hsun Shih } 36670179969SPi-Hsun Shih 36770179969SPi-Hsun Shih list_for_each_entry_safe(info, next, 36870179969SPi-Hsun Shih &mtk_subdev->channels, list) { 36970179969SPi-Hsun Shih list_del(&info->list); 37070179969SPi-Hsun Shih kfree(info); 37170179969SPi-Hsun Shih } 37270179969SPi-Hsun Shih mutex_unlock(&mtk_subdev->channels_lock); 37370179969SPi-Hsun Shih } 37470179969SPi-Hsun Shih 37570179969SPi-Hsun Shih struct rproc_subdev * 37670179969SPi-Hsun Shih mtk_rpmsg_create_rproc_subdev(struct platform_device *pdev, 37770179969SPi-Hsun Shih struct mtk_rpmsg_info *info) 37870179969SPi-Hsun Shih { 37970179969SPi-Hsun Shih struct mtk_rpmsg_rproc_subdev *mtk_subdev; 38070179969SPi-Hsun Shih 38170179969SPi-Hsun Shih mtk_subdev = kzalloc(sizeof(*mtk_subdev), GFP_KERNEL); 38270179969SPi-Hsun Shih if (!mtk_subdev) 38370179969SPi-Hsun Shih return NULL; 38470179969SPi-Hsun Shih 38570179969SPi-Hsun Shih mtk_subdev->pdev = pdev; 38670179969SPi-Hsun Shih mtk_subdev->subdev.prepare = mtk_rpmsg_prepare; 38770179969SPi-Hsun Shih mtk_subdev->subdev.stop = mtk_rpmsg_stop; 38870179969SPi-Hsun Shih mtk_subdev->subdev.unprepare = mtk_rpmsg_unprepare; 38970179969SPi-Hsun Shih mtk_subdev->info = info; 39070179969SPi-Hsun Shih INIT_LIST_HEAD(&mtk_subdev->channels); 39170179969SPi-Hsun Shih INIT_WORK(&mtk_subdev->register_work, 39270179969SPi-Hsun Shih mtk_register_device_work_function); 39370179969SPi-Hsun Shih mutex_init(&mtk_subdev->channels_lock); 39470179969SPi-Hsun Shih 39570179969SPi-Hsun Shih return &mtk_subdev->subdev; 39670179969SPi-Hsun Shih } 39770179969SPi-Hsun Shih EXPORT_SYMBOL_GPL(mtk_rpmsg_create_rproc_subdev); 39870179969SPi-Hsun Shih 39970179969SPi-Hsun Shih void mtk_rpmsg_destroy_rproc_subdev(struct rproc_subdev *subdev) 40070179969SPi-Hsun Shih { 40170179969SPi-Hsun Shih struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev); 40270179969SPi-Hsun Shih 40370179969SPi-Hsun Shih kfree(mtk_subdev); 40470179969SPi-Hsun Shih } 40570179969SPi-Hsun Shih EXPORT_SYMBOL_GPL(mtk_rpmsg_destroy_rproc_subdev); 40670179969SPi-Hsun Shih 40770179969SPi-Hsun Shih MODULE_LICENSE("GPL v2"); 40870179969SPi-Hsun Shih MODULE_DESCRIPTION("MediaTek scp rpmsg driver"); 409