18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Copyright 2019 Google LLC. 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <linux/kernel.h> 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci#include <linux/of.h> 88c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 98c2ecf20Sopenharmony_ci#include <linux/remoteproc.h> 108c2ecf20Sopenharmony_ci#include <linux/rpmsg/mtk_rpmsg.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "rpmsg_internal.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistruct mtk_rpmsg_rproc_subdev { 178c2ecf20Sopenharmony_ci struct platform_device *pdev; 188c2ecf20Sopenharmony_ci struct mtk_rpmsg_info *info; 198c2ecf20Sopenharmony_ci struct rpmsg_endpoint *ns_ept; 208c2ecf20Sopenharmony_ci struct rproc_subdev subdev; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci struct work_struct register_work; 238c2ecf20Sopenharmony_ci struct list_head channels; 248c2ecf20Sopenharmony_ci struct mutex channels_lock; 258c2ecf20Sopenharmony_ci}; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define to_mtk_subdev(d) container_of(d, struct mtk_rpmsg_rproc_subdev, subdev) 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistruct mtk_rpmsg_channel_info { 308c2ecf20Sopenharmony_ci struct rpmsg_channel_info info; 318c2ecf20Sopenharmony_ci bool registered; 328c2ecf20Sopenharmony_ci struct list_head list; 338c2ecf20Sopenharmony_ci}; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/** 368c2ecf20Sopenharmony_ci * struct rpmsg_ns_msg - dynamic name service announcement message 378c2ecf20Sopenharmony_ci * @name: name of remote service that is published 388c2ecf20Sopenharmony_ci * @addr: address of remote service that is published 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * This message is sent across to publish a new service. When we receive these 418c2ecf20Sopenharmony_ci * messages, an appropriate rpmsg channel (i.e device) is created. In turn, the 428c2ecf20Sopenharmony_ci * ->probe() handler of the appropriate rpmsg driver will be invoked 438c2ecf20Sopenharmony_ci * (if/as-soon-as one is registered). 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_cistruct rpmsg_ns_msg { 468c2ecf20Sopenharmony_ci char name[RPMSG_NAME_SIZE]; 478c2ecf20Sopenharmony_ci u32 addr; 488c2ecf20Sopenharmony_ci} __packed; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistruct mtk_rpmsg_device { 518c2ecf20Sopenharmony_ci struct rpmsg_device rpdev; 528c2ecf20Sopenharmony_ci struct mtk_rpmsg_rproc_subdev *mtk_subdev; 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistruct mtk_rpmsg_endpoint { 568c2ecf20Sopenharmony_ci struct rpmsg_endpoint ept; 578c2ecf20Sopenharmony_ci struct mtk_rpmsg_rproc_subdev *mtk_subdev; 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define to_mtk_rpmsg_device(r) container_of(r, struct mtk_rpmsg_device, rpdev) 618c2ecf20Sopenharmony_ci#define to_mtk_rpmsg_endpoint(r) container_of(r, struct mtk_rpmsg_endpoint, ept) 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic const struct rpmsg_endpoint_ops mtk_rpmsg_endpoint_ops; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic void __mtk_ept_release(struct kref *kref) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct rpmsg_endpoint *ept = container_of(kref, struct rpmsg_endpoint, 688c2ecf20Sopenharmony_ci refcount); 698c2ecf20Sopenharmony_ci kfree(to_mtk_rpmsg_endpoint(ept)); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic void mtk_rpmsg_ipi_handler(void *data, unsigned int len, void *priv) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci struct mtk_rpmsg_endpoint *mept = priv; 758c2ecf20Sopenharmony_ci struct rpmsg_endpoint *ept = &mept->ept; 768c2ecf20Sopenharmony_ci int ret; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci ret = (*ept->cb)(ept->rpdev, data, len, ept->priv, ept->addr); 798c2ecf20Sopenharmony_ci if (ret) 808c2ecf20Sopenharmony_ci dev_warn(&ept->rpdev->dev, "rpmsg handler return error = %d", 818c2ecf20Sopenharmony_ci ret); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic struct rpmsg_endpoint * 858c2ecf20Sopenharmony_ci__mtk_create_ept(struct mtk_rpmsg_rproc_subdev *mtk_subdev, 868c2ecf20Sopenharmony_ci struct rpmsg_device *rpdev, rpmsg_rx_cb_t cb, void *priv, 878c2ecf20Sopenharmony_ci u32 id) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct mtk_rpmsg_endpoint *mept; 908c2ecf20Sopenharmony_ci struct rpmsg_endpoint *ept; 918c2ecf20Sopenharmony_ci struct platform_device *pdev = mtk_subdev->pdev; 928c2ecf20Sopenharmony_ci int ret; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci mept = kzalloc(sizeof(*mept), GFP_KERNEL); 958c2ecf20Sopenharmony_ci if (!mept) 968c2ecf20Sopenharmony_ci return NULL; 978c2ecf20Sopenharmony_ci mept->mtk_subdev = mtk_subdev; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci ept = &mept->ept; 1008c2ecf20Sopenharmony_ci kref_init(&ept->refcount); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci ept->rpdev = rpdev; 1038c2ecf20Sopenharmony_ci ept->cb = cb; 1048c2ecf20Sopenharmony_ci ept->priv = priv; 1058c2ecf20Sopenharmony_ci ept->ops = &mtk_rpmsg_endpoint_ops; 1068c2ecf20Sopenharmony_ci ept->addr = id; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci ret = mtk_subdev->info->register_ipi(pdev, id, mtk_rpmsg_ipi_handler, 1098c2ecf20Sopenharmony_ci mept); 1108c2ecf20Sopenharmony_ci if (ret) { 1118c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "IPI register failed, id = %d", id); 1128c2ecf20Sopenharmony_ci kref_put(&ept->refcount, __mtk_ept_release); 1138c2ecf20Sopenharmony_ci return NULL; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci return ept; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic struct rpmsg_endpoint * 1208c2ecf20Sopenharmony_cimtk_rpmsg_create_ept(struct rpmsg_device *rpdev, rpmsg_rx_cb_t cb, void *priv, 1218c2ecf20Sopenharmony_ci struct rpmsg_channel_info chinfo) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci struct mtk_rpmsg_rproc_subdev *mtk_subdev = 1248c2ecf20Sopenharmony_ci to_mtk_rpmsg_device(rpdev)->mtk_subdev; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci return __mtk_create_ept(mtk_subdev, rpdev, cb, priv, chinfo.src); 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic void mtk_rpmsg_destroy_ept(struct rpmsg_endpoint *ept) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci struct mtk_rpmsg_rproc_subdev *mtk_subdev = 1328c2ecf20Sopenharmony_ci to_mtk_rpmsg_endpoint(ept)->mtk_subdev; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci mtk_subdev->info->unregister_ipi(mtk_subdev->pdev, ept->addr); 1358c2ecf20Sopenharmony_ci kref_put(&ept->refcount, __mtk_ept_release); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic int mtk_rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct mtk_rpmsg_rproc_subdev *mtk_subdev = 1418c2ecf20Sopenharmony_ci to_mtk_rpmsg_endpoint(ept)->mtk_subdev; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return mtk_subdev->info->send_ipi(mtk_subdev->pdev, ept->addr, data, 1448c2ecf20Sopenharmony_ci len, 0); 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic int mtk_rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct mtk_rpmsg_rproc_subdev *mtk_subdev = 1508c2ecf20Sopenharmony_ci to_mtk_rpmsg_endpoint(ept)->mtk_subdev; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* 1538c2ecf20Sopenharmony_ci * TODO: This currently is same as mtk_rpmsg_send, and wait until SCP 1548c2ecf20Sopenharmony_ci * received the last command. 1558c2ecf20Sopenharmony_ci */ 1568c2ecf20Sopenharmony_ci return mtk_subdev->info->send_ipi(mtk_subdev->pdev, ept->addr, data, 1578c2ecf20Sopenharmony_ci len, 0); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic const struct rpmsg_endpoint_ops mtk_rpmsg_endpoint_ops = { 1618c2ecf20Sopenharmony_ci .destroy_ept = mtk_rpmsg_destroy_ept, 1628c2ecf20Sopenharmony_ci .send = mtk_rpmsg_send, 1638c2ecf20Sopenharmony_ci .trysend = mtk_rpmsg_trysend, 1648c2ecf20Sopenharmony_ci}; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic void mtk_rpmsg_release_device(struct device *dev) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct rpmsg_device *rpdev = to_rpmsg_device(dev); 1698c2ecf20Sopenharmony_ci struct mtk_rpmsg_device *mdev = to_mtk_rpmsg_device(rpdev); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci kfree(mdev); 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic const struct rpmsg_device_ops mtk_rpmsg_device_ops = { 1758c2ecf20Sopenharmony_ci .create_ept = mtk_rpmsg_create_ept, 1768c2ecf20Sopenharmony_ci}; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic struct device_node * 1798c2ecf20Sopenharmony_cimtk_rpmsg_match_device_subnode(struct device_node *node, const char *channel) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci struct device_node *child; 1828c2ecf20Sopenharmony_ci const char *name; 1838c2ecf20Sopenharmony_ci int ret; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci for_each_available_child_of_node(node, child) { 1868c2ecf20Sopenharmony_ci ret = of_property_read_string(child, "mtk,rpmsg-name", &name); 1878c2ecf20Sopenharmony_ci if (ret) 1888c2ecf20Sopenharmony_ci continue; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if (strcmp(name, channel) == 0) 1918c2ecf20Sopenharmony_ci return child; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci return NULL; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic int mtk_rpmsg_register_device(struct mtk_rpmsg_rproc_subdev *mtk_subdev, 1988c2ecf20Sopenharmony_ci struct rpmsg_channel_info *info) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci struct rpmsg_device *rpdev; 2018c2ecf20Sopenharmony_ci struct mtk_rpmsg_device *mdev; 2028c2ecf20Sopenharmony_ci struct platform_device *pdev = mtk_subdev->pdev; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); 2058c2ecf20Sopenharmony_ci if (!mdev) 2068c2ecf20Sopenharmony_ci return -ENOMEM; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci mdev->mtk_subdev = mtk_subdev; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci rpdev = &mdev->rpdev; 2118c2ecf20Sopenharmony_ci rpdev->ops = &mtk_rpmsg_device_ops; 2128c2ecf20Sopenharmony_ci rpdev->src = info->src; 2138c2ecf20Sopenharmony_ci rpdev->dst = info->dst; 2148c2ecf20Sopenharmony_ci strscpy(rpdev->id.name, info->name, RPMSG_NAME_SIZE); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci rpdev->dev.of_node = 2178c2ecf20Sopenharmony_ci mtk_rpmsg_match_device_subnode(pdev->dev.of_node, info->name); 2188c2ecf20Sopenharmony_ci rpdev->dev.parent = &pdev->dev; 2198c2ecf20Sopenharmony_ci rpdev->dev.release = mtk_rpmsg_release_device; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci return rpmsg_register_device(rpdev); 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic void mtk_register_device_work_function(struct work_struct *register_work) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci struct mtk_rpmsg_rproc_subdev *subdev = container_of( 2278c2ecf20Sopenharmony_ci register_work, struct mtk_rpmsg_rproc_subdev, register_work); 2288c2ecf20Sopenharmony_ci struct platform_device *pdev = subdev->pdev; 2298c2ecf20Sopenharmony_ci struct mtk_rpmsg_channel_info *info; 2308c2ecf20Sopenharmony_ci int ret; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci mutex_lock(&subdev->channels_lock); 2338c2ecf20Sopenharmony_ci list_for_each_entry(info, &subdev->channels, list) { 2348c2ecf20Sopenharmony_ci if (info->registered) 2358c2ecf20Sopenharmony_ci continue; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci mutex_unlock(&subdev->channels_lock); 2388c2ecf20Sopenharmony_ci ret = mtk_rpmsg_register_device(subdev, &info->info); 2398c2ecf20Sopenharmony_ci mutex_lock(&subdev->channels_lock); 2408c2ecf20Sopenharmony_ci if (ret) { 2418c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Can't create rpmsg_device\n"); 2428c2ecf20Sopenharmony_ci continue; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci info->registered = true; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci mutex_unlock(&subdev->channels_lock); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int mtk_rpmsg_create_device(struct mtk_rpmsg_rproc_subdev *mtk_subdev, 2518c2ecf20Sopenharmony_ci char *name, u32 addr) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci struct mtk_rpmsg_channel_info *info; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci info = kzalloc(sizeof(*info), GFP_KERNEL); 2568c2ecf20Sopenharmony_ci if (!info) 2578c2ecf20Sopenharmony_ci return -ENOMEM; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci strscpy(info->info.name, name, RPMSG_NAME_SIZE); 2608c2ecf20Sopenharmony_ci info->info.src = addr; 2618c2ecf20Sopenharmony_ci info->info.dst = RPMSG_ADDR_ANY; 2628c2ecf20Sopenharmony_ci mutex_lock(&mtk_subdev->channels_lock); 2638c2ecf20Sopenharmony_ci list_add(&info->list, &mtk_subdev->channels); 2648c2ecf20Sopenharmony_ci mutex_unlock(&mtk_subdev->channels_lock); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci schedule_work(&mtk_subdev->register_work); 2678c2ecf20Sopenharmony_ci return 0; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic int mtk_rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len, 2718c2ecf20Sopenharmony_ci void *priv, u32 src) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct rpmsg_ns_msg *msg = data; 2748c2ecf20Sopenharmony_ci struct mtk_rpmsg_rproc_subdev *mtk_subdev = priv; 2758c2ecf20Sopenharmony_ci struct device *dev = &mtk_subdev->pdev->dev; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci int ret; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci if (len != sizeof(*msg)) { 2808c2ecf20Sopenharmony_ci dev_err(dev, "malformed ns msg (%d)\n", len); 2818c2ecf20Sopenharmony_ci return -EINVAL; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* 2858c2ecf20Sopenharmony_ci * the name service ept does _not_ belong to a real rpmsg channel, 2868c2ecf20Sopenharmony_ci * and is handled by the rpmsg bus itself. 2878c2ecf20Sopenharmony_ci * for sanity reasons, make sure a valid rpdev has _not_ sneaked 2888c2ecf20Sopenharmony_ci * in somehow. 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_ci if (rpdev) { 2918c2ecf20Sopenharmony_ci dev_err(dev, "anomaly: ns ept has an rpdev handle\n"); 2928c2ecf20Sopenharmony_ci return -EINVAL; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* don't trust the remote processor for null terminating the name */ 2968c2ecf20Sopenharmony_ci msg->name[RPMSG_NAME_SIZE - 1] = '\0'; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci dev_info(dev, "creating channel %s addr 0x%x\n", msg->name, msg->addr); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci ret = mtk_rpmsg_create_device(mtk_subdev, msg->name, msg->addr); 3018c2ecf20Sopenharmony_ci if (ret) { 3028c2ecf20Sopenharmony_ci dev_err(dev, "create rpmsg device failed\n"); 3038c2ecf20Sopenharmony_ci return ret; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci return 0; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic int mtk_rpmsg_prepare(struct rproc_subdev *subdev) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* a dedicated endpoint handles the name service msgs */ 3148c2ecf20Sopenharmony_ci if (mtk_subdev->info->ns_ipi_id >= 0) { 3158c2ecf20Sopenharmony_ci mtk_subdev->ns_ept = 3168c2ecf20Sopenharmony_ci __mtk_create_ept(mtk_subdev, NULL, mtk_rpmsg_ns_cb, 3178c2ecf20Sopenharmony_ci mtk_subdev, 3188c2ecf20Sopenharmony_ci mtk_subdev->info->ns_ipi_id); 3198c2ecf20Sopenharmony_ci if (!mtk_subdev->ns_ept) { 3208c2ecf20Sopenharmony_ci dev_err(&mtk_subdev->pdev->dev, 3218c2ecf20Sopenharmony_ci "failed to create name service endpoint\n"); 3228c2ecf20Sopenharmony_ci return -ENOMEM; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci return 0; 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic void mtk_rpmsg_unprepare(struct rproc_subdev *subdev) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (mtk_subdev->ns_ept) { 3348c2ecf20Sopenharmony_ci mtk_rpmsg_destroy_ept(mtk_subdev->ns_ept); 3358c2ecf20Sopenharmony_ci mtk_subdev->ns_ept = NULL; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic void mtk_rpmsg_stop(struct rproc_subdev *subdev, bool crashed) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci struct mtk_rpmsg_channel_info *info, *next; 3428c2ecf20Sopenharmony_ci struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev); 3438c2ecf20Sopenharmony_ci struct device *dev = &mtk_subdev->pdev->dev; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci /* 3468c2ecf20Sopenharmony_ci * Destroy the name service endpoint here, to avoid new channel being 3478c2ecf20Sopenharmony_ci * created after the rpmsg_unregister_device loop below. 3488c2ecf20Sopenharmony_ci */ 3498c2ecf20Sopenharmony_ci if (mtk_subdev->ns_ept) { 3508c2ecf20Sopenharmony_ci mtk_rpmsg_destroy_ept(mtk_subdev->ns_ept); 3518c2ecf20Sopenharmony_ci mtk_subdev->ns_ept = NULL; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci cancel_work_sync(&mtk_subdev->register_work); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci mutex_lock(&mtk_subdev->channels_lock); 3578c2ecf20Sopenharmony_ci list_for_each_entry(info, &mtk_subdev->channels, list) { 3588c2ecf20Sopenharmony_ci if (!info->registered) 3598c2ecf20Sopenharmony_ci continue; 3608c2ecf20Sopenharmony_ci if (rpmsg_unregister_device(dev, &info->info)) { 3618c2ecf20Sopenharmony_ci dev_warn( 3628c2ecf20Sopenharmony_ci dev, 3638c2ecf20Sopenharmony_ci "rpmsg_unregister_device failed for %s.%d.%d\n", 3648c2ecf20Sopenharmony_ci info->info.name, info->info.src, 3658c2ecf20Sopenharmony_ci info->info.dst); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci list_for_each_entry_safe(info, next, 3708c2ecf20Sopenharmony_ci &mtk_subdev->channels, list) { 3718c2ecf20Sopenharmony_ci list_del(&info->list); 3728c2ecf20Sopenharmony_ci kfree(info); 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci mutex_unlock(&mtk_subdev->channels_lock); 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistruct rproc_subdev * 3788c2ecf20Sopenharmony_cimtk_rpmsg_create_rproc_subdev(struct platform_device *pdev, 3798c2ecf20Sopenharmony_ci struct mtk_rpmsg_info *info) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci struct mtk_rpmsg_rproc_subdev *mtk_subdev; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci mtk_subdev = kzalloc(sizeof(*mtk_subdev), GFP_KERNEL); 3848c2ecf20Sopenharmony_ci if (!mtk_subdev) 3858c2ecf20Sopenharmony_ci return NULL; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci mtk_subdev->pdev = pdev; 3888c2ecf20Sopenharmony_ci mtk_subdev->subdev.prepare = mtk_rpmsg_prepare; 3898c2ecf20Sopenharmony_ci mtk_subdev->subdev.stop = mtk_rpmsg_stop; 3908c2ecf20Sopenharmony_ci mtk_subdev->subdev.unprepare = mtk_rpmsg_unprepare; 3918c2ecf20Sopenharmony_ci mtk_subdev->info = info; 3928c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&mtk_subdev->channels); 3938c2ecf20Sopenharmony_ci INIT_WORK(&mtk_subdev->register_work, 3948c2ecf20Sopenharmony_ci mtk_register_device_work_function); 3958c2ecf20Sopenharmony_ci mutex_init(&mtk_subdev->channels_lock); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci return &mtk_subdev->subdev; 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_rpmsg_create_rproc_subdev); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_civoid mtk_rpmsg_destroy_rproc_subdev(struct rproc_subdev *subdev) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci struct mtk_rpmsg_rproc_subdev *mtk_subdev = to_mtk_subdev(subdev); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci kfree(mtk_subdev); 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mtk_rpmsg_destroy_rproc_subdev); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 4108c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MediaTek scp rpmsg driver"); 411