1*950a7388SArnaud Pouliquen // SPDX-License-Identifier: GPL-2.0 2*950a7388SArnaud Pouliquen /* 3*950a7388SArnaud Pouliquen * Copyright (C) STMicroelectronics 2020 - All Rights Reserved 4*950a7388SArnaud Pouliquen */ 5*950a7388SArnaud Pouliquen #include <linux/device.h> 6*950a7388SArnaud Pouliquen #include <linux/kernel.h> 7*950a7388SArnaud Pouliquen #include <linux/module.h> 8*950a7388SArnaud Pouliquen #include <linux/rpmsg.h> 9*950a7388SArnaud Pouliquen #include <linux/rpmsg/ns.h> 10*950a7388SArnaud Pouliquen #include <linux/slab.h> 11*950a7388SArnaud Pouliquen 12*950a7388SArnaud Pouliquen #include "rpmsg_internal.h" 13*950a7388SArnaud Pouliquen 14*950a7388SArnaud Pouliquen /** 15*950a7388SArnaud Pouliquen * rpmsg_ns_register_device() - register name service device based on rpdev 16*950a7388SArnaud Pouliquen * @rpdev: prepared rpdev to be used for creating endpoints 17*950a7388SArnaud Pouliquen * 18*950a7388SArnaud Pouliquen * This function wraps rpmsg_register_device() preparing the rpdev for use as 19*950a7388SArnaud Pouliquen * basis for the rpmsg name service device. 20*950a7388SArnaud Pouliquen */ 21*950a7388SArnaud Pouliquen int rpmsg_ns_register_device(struct rpmsg_device *rpdev) 22*950a7388SArnaud Pouliquen { 23*950a7388SArnaud Pouliquen strcpy(rpdev->id.name, "rpmsg_ns"); 24*950a7388SArnaud Pouliquen rpdev->driver_override = "rpmsg_ns"; 25*950a7388SArnaud Pouliquen rpdev->src = RPMSG_NS_ADDR; 26*950a7388SArnaud Pouliquen rpdev->dst = RPMSG_NS_ADDR; 27*950a7388SArnaud Pouliquen 28*950a7388SArnaud Pouliquen return rpmsg_register_device(rpdev); 29*950a7388SArnaud Pouliquen } 30*950a7388SArnaud Pouliquen EXPORT_SYMBOL(rpmsg_ns_register_device); 31*950a7388SArnaud Pouliquen 32*950a7388SArnaud Pouliquen /* invoked when a name service announcement arrives */ 33*950a7388SArnaud Pouliquen static int rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len, 34*950a7388SArnaud Pouliquen void *priv, u32 src) 35*950a7388SArnaud Pouliquen { 36*950a7388SArnaud Pouliquen struct rpmsg_ns_msg *msg = data; 37*950a7388SArnaud Pouliquen struct rpmsg_device *newch; 38*950a7388SArnaud Pouliquen struct rpmsg_channel_info chinfo; 39*950a7388SArnaud Pouliquen struct device *dev = rpdev->dev.parent; 40*950a7388SArnaud Pouliquen int ret; 41*950a7388SArnaud Pouliquen 42*950a7388SArnaud Pouliquen #if defined(CONFIG_DYNAMIC_DEBUG) 43*950a7388SArnaud Pouliquen dynamic_hex_dump("NS announcement: ", DUMP_PREFIX_NONE, 16, 1, 44*950a7388SArnaud Pouliquen data, len, true); 45*950a7388SArnaud Pouliquen #endif 46*950a7388SArnaud Pouliquen 47*950a7388SArnaud Pouliquen if (len != sizeof(*msg)) { 48*950a7388SArnaud Pouliquen dev_err(dev, "malformed ns msg (%d)\n", len); 49*950a7388SArnaud Pouliquen return -EINVAL; 50*950a7388SArnaud Pouliquen } 51*950a7388SArnaud Pouliquen 52*950a7388SArnaud Pouliquen /* don't trust the remote processor for null terminating the name */ 53*950a7388SArnaud Pouliquen msg->name[RPMSG_NAME_SIZE - 1] = '\0'; 54*950a7388SArnaud Pouliquen 55*950a7388SArnaud Pouliquen strncpy(chinfo.name, msg->name, sizeof(chinfo.name)); 56*950a7388SArnaud Pouliquen chinfo.src = RPMSG_ADDR_ANY; 57*950a7388SArnaud Pouliquen chinfo.dst = rpmsg32_to_cpu(rpdev, msg->addr); 58*950a7388SArnaud Pouliquen 59*950a7388SArnaud Pouliquen dev_info(dev, "%sing channel %s addr 0x%x\n", 60*950a7388SArnaud Pouliquen rpmsg32_to_cpu(rpdev, msg->flags) & RPMSG_NS_DESTROY ? 61*950a7388SArnaud Pouliquen "destroy" : "creat", msg->name, chinfo.dst); 62*950a7388SArnaud Pouliquen 63*950a7388SArnaud Pouliquen if (rpmsg32_to_cpu(rpdev, msg->flags) & RPMSG_NS_DESTROY) { 64*950a7388SArnaud Pouliquen ret = rpmsg_release_channel(rpdev, &chinfo); 65*950a7388SArnaud Pouliquen if (ret) 66*950a7388SArnaud Pouliquen dev_err(dev, "rpmsg_destroy_channel failed: %d\n", ret); 67*950a7388SArnaud Pouliquen } else { 68*950a7388SArnaud Pouliquen newch = rpmsg_create_channel(rpdev, &chinfo); 69*950a7388SArnaud Pouliquen if (!newch) 70*950a7388SArnaud Pouliquen dev_err(dev, "rpmsg_create_channel failed\n"); 71*950a7388SArnaud Pouliquen } 72*950a7388SArnaud Pouliquen 73*950a7388SArnaud Pouliquen return 0; 74*950a7388SArnaud Pouliquen } 75*950a7388SArnaud Pouliquen 76*950a7388SArnaud Pouliquen static int rpmsg_ns_probe(struct rpmsg_device *rpdev) 77*950a7388SArnaud Pouliquen { 78*950a7388SArnaud Pouliquen struct rpmsg_endpoint *ns_ept; 79*950a7388SArnaud Pouliquen struct rpmsg_channel_info ns_chinfo = { 80*950a7388SArnaud Pouliquen .src = RPMSG_NS_ADDR, 81*950a7388SArnaud Pouliquen .dst = RPMSG_NS_ADDR, 82*950a7388SArnaud Pouliquen .name = "name_service", 83*950a7388SArnaud Pouliquen }; 84*950a7388SArnaud Pouliquen 85*950a7388SArnaud Pouliquen /* 86*950a7388SArnaud Pouliquen * Create the NS announcement service endpoint associated to the RPMsg 87*950a7388SArnaud Pouliquen * device. The endpoint will be automatically destroyed when the RPMsg 88*950a7388SArnaud Pouliquen * device will be deleted. 89*950a7388SArnaud Pouliquen */ 90*950a7388SArnaud Pouliquen ns_ept = rpmsg_create_ept(rpdev, rpmsg_ns_cb, NULL, ns_chinfo); 91*950a7388SArnaud Pouliquen if (!ns_ept) { 92*950a7388SArnaud Pouliquen dev_err(&rpdev->dev, "failed to create the ns ept\n"); 93*950a7388SArnaud Pouliquen return -ENOMEM; 94*950a7388SArnaud Pouliquen } 95*950a7388SArnaud Pouliquen rpdev->ept = ns_ept; 96*950a7388SArnaud Pouliquen 97*950a7388SArnaud Pouliquen return 0; 98*950a7388SArnaud Pouliquen } 99*950a7388SArnaud Pouliquen 100*950a7388SArnaud Pouliquen static struct rpmsg_driver rpmsg_ns_driver = { 101*950a7388SArnaud Pouliquen .drv.name = KBUILD_MODNAME, 102*950a7388SArnaud Pouliquen .probe = rpmsg_ns_probe, 103*950a7388SArnaud Pouliquen }; 104*950a7388SArnaud Pouliquen 105*950a7388SArnaud Pouliquen static int rpmsg_ns_init(void) 106*950a7388SArnaud Pouliquen { 107*950a7388SArnaud Pouliquen int ret; 108*950a7388SArnaud Pouliquen 109*950a7388SArnaud Pouliquen ret = register_rpmsg_driver(&rpmsg_ns_driver); 110*950a7388SArnaud Pouliquen if (ret < 0) 111*950a7388SArnaud Pouliquen pr_err("%s: Failed to register rpmsg driver\n", __func__); 112*950a7388SArnaud Pouliquen 113*950a7388SArnaud Pouliquen return ret; 114*950a7388SArnaud Pouliquen } 115*950a7388SArnaud Pouliquen postcore_initcall(rpmsg_ns_init); 116*950a7388SArnaud Pouliquen 117*950a7388SArnaud Pouliquen static void rpmsg_ns_exit(void) 118*950a7388SArnaud Pouliquen { 119*950a7388SArnaud Pouliquen unregister_rpmsg_driver(&rpmsg_ns_driver); 120*950a7388SArnaud Pouliquen } 121*950a7388SArnaud Pouliquen module_exit(rpmsg_ns_exit); 122*950a7388SArnaud Pouliquen 123*950a7388SArnaud Pouliquen MODULE_DESCRIPTION("Name service announcement rpmsg driver"); 124*950a7388SArnaud Pouliquen MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>"); 125*950a7388SArnaud Pouliquen MODULE_ALIAS("rpmsg:" KBUILD_MODNAME); 126*950a7388SArnaud Pouliquen MODULE_LICENSE("GPL v2"); 127