18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * remote processor messaging bus 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2011 Texas Instruments, Inc. 68c2ecf20Sopenharmony_ci * Copyright (C) 2011 Google, Inc. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Ohad Ben-Cohen <ohad@wizery.com> 98c2ecf20Sopenharmony_ci * Brian Swetland <swetland@google.com> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "%s: " fmt, __func__ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/rpmsg.h> 178c2ecf20Sopenharmony_ci#include <linux/of_device.h> 188c2ecf20Sopenharmony_ci#include <linux/pm_domain.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "rpmsg_internal.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/** 248c2ecf20Sopenharmony_ci * rpmsg_create_ept() - create a new rpmsg_endpoint 258c2ecf20Sopenharmony_ci * @rpdev: rpmsg channel device 268c2ecf20Sopenharmony_ci * @cb: rx callback handler 278c2ecf20Sopenharmony_ci * @priv: private data for the driver's use 288c2ecf20Sopenharmony_ci * @chinfo: channel_info with the local rpmsg address to bind with @cb 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * Every rpmsg address in the system is bound to an rx callback (so when 318c2ecf20Sopenharmony_ci * inbound messages arrive, they are dispatched by the rpmsg bus using the 328c2ecf20Sopenharmony_ci * appropriate callback handler) by means of an rpmsg_endpoint struct. 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * This function allows drivers to create such an endpoint, and by that, 358c2ecf20Sopenharmony_ci * bind a callback, and possibly some private data too, to an rpmsg address 368c2ecf20Sopenharmony_ci * (either one that is known in advance, or one that will be dynamically 378c2ecf20Sopenharmony_ci * assigned for them). 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * Simple rpmsg drivers need not call rpmsg_create_ept, because an endpoint 408c2ecf20Sopenharmony_ci * is already created for them when they are probed by the rpmsg bus 418c2ecf20Sopenharmony_ci * (using the rx callback provided when they registered to the rpmsg bus). 428c2ecf20Sopenharmony_ci * 438c2ecf20Sopenharmony_ci * So things should just work for simple drivers: they already have an 448c2ecf20Sopenharmony_ci * endpoint, their rx callback is bound to their rpmsg address, and when 458c2ecf20Sopenharmony_ci * relevant inbound messages arrive (i.e. messages which their dst address 468c2ecf20Sopenharmony_ci * equals to the src address of their rpmsg channel), the driver's handler 478c2ecf20Sopenharmony_ci * is invoked to process it. 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * That said, more complicated drivers might need to allocate 508c2ecf20Sopenharmony_ci * additional rpmsg addresses, and bind them to different rx callbacks. 518c2ecf20Sopenharmony_ci * To accomplish that, those drivers need to call this function. 528c2ecf20Sopenharmony_ci * 538c2ecf20Sopenharmony_ci * Drivers should provide their @rpdev channel (so the new endpoint would belong 548c2ecf20Sopenharmony_ci * to the same remote processor their channel belongs to), an rx callback 558c2ecf20Sopenharmony_ci * function, an optional private data (which is provided back when the 568c2ecf20Sopenharmony_ci * rx callback is invoked), and an address they want to bind with the 578c2ecf20Sopenharmony_ci * callback. If @addr is RPMSG_ADDR_ANY, then rpmsg_create_ept will 588c2ecf20Sopenharmony_ci * dynamically assign them an available rpmsg address (drivers should have 598c2ecf20Sopenharmony_ci * a very good reason why not to always use RPMSG_ADDR_ANY here). 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci * Returns a pointer to the endpoint on success, or NULL on error. 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_cistruct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev, 648c2ecf20Sopenharmony_ci rpmsg_rx_cb_t cb, void *priv, 658c2ecf20Sopenharmony_ci struct rpmsg_channel_info chinfo) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci if (WARN_ON(!rpdev)) 688c2ecf20Sopenharmony_ci return NULL; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci return rpdev->ops->create_ept(rpdev, cb, priv, chinfo); 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rpmsg_create_ept); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/** 758c2ecf20Sopenharmony_ci * rpmsg_destroy_ept() - destroy an existing rpmsg endpoint 768c2ecf20Sopenharmony_ci * @ept: endpoing to destroy 778c2ecf20Sopenharmony_ci * 788c2ecf20Sopenharmony_ci * Should be used by drivers to destroy an rpmsg endpoint previously 798c2ecf20Sopenharmony_ci * created with rpmsg_create_ept(). As with other types of "free" NULL 808c2ecf20Sopenharmony_ci * is a valid parameter. 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_civoid rpmsg_destroy_ept(struct rpmsg_endpoint *ept) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci if (ept && ept->ops) 858c2ecf20Sopenharmony_ci ept->ops->destroy_ept(ept); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rpmsg_destroy_ept); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/** 908c2ecf20Sopenharmony_ci * rpmsg_send() - send a message across to the remote processor 918c2ecf20Sopenharmony_ci * @ept: the rpmsg endpoint 928c2ecf20Sopenharmony_ci * @data: payload of message 938c2ecf20Sopenharmony_ci * @len: length of payload 948c2ecf20Sopenharmony_ci * 958c2ecf20Sopenharmony_ci * This function sends @data of length @len on the @ept endpoint. 968c2ecf20Sopenharmony_ci * The message will be sent to the remote processor which the @ept 978c2ecf20Sopenharmony_ci * endpoint belongs to, using @ept's address and its associated rpmsg 988c2ecf20Sopenharmony_ci * device destination addresses. 998c2ecf20Sopenharmony_ci * In case there are no TX buffers available, the function will block until 1008c2ecf20Sopenharmony_ci * one becomes available, or a timeout of 15 seconds elapses. When the latter 1018c2ecf20Sopenharmony_ci * happens, -ERESTARTSYS is returned. 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * Can only be called from process context (for now). 1048c2ecf20Sopenharmony_ci * 1058c2ecf20Sopenharmony_ci * Returns 0 on success and an appropriate error value on failure. 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ciint rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci if (WARN_ON(!ept)) 1108c2ecf20Sopenharmony_ci return -EINVAL; 1118c2ecf20Sopenharmony_ci if (!ept->ops->send) 1128c2ecf20Sopenharmony_ci return -ENXIO; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return ept->ops->send(ept, data, len); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rpmsg_send); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/** 1198c2ecf20Sopenharmony_ci * rpmsg_sendto() - send a message across to the remote processor, specify dst 1208c2ecf20Sopenharmony_ci * @ept: the rpmsg endpoint 1218c2ecf20Sopenharmony_ci * @data: payload of message 1228c2ecf20Sopenharmony_ci * @len: length of payload 1238c2ecf20Sopenharmony_ci * @dst: destination address 1248c2ecf20Sopenharmony_ci * 1258c2ecf20Sopenharmony_ci * This function sends @data of length @len to the remote @dst address. 1268c2ecf20Sopenharmony_ci * The message will be sent to the remote processor which the @ept 1278c2ecf20Sopenharmony_ci * endpoint belongs to, using @ept's address as source. 1288c2ecf20Sopenharmony_ci * In case there are no TX buffers available, the function will block until 1298c2ecf20Sopenharmony_ci * one becomes available, or a timeout of 15 seconds elapses. When the latter 1308c2ecf20Sopenharmony_ci * happens, -ERESTARTSYS is returned. 1318c2ecf20Sopenharmony_ci * 1328c2ecf20Sopenharmony_ci * Can only be called from process context (for now). 1338c2ecf20Sopenharmony_ci * 1348c2ecf20Sopenharmony_ci * Returns 0 on success and an appropriate error value on failure. 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_ciint rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci if (WARN_ON(!ept)) 1398c2ecf20Sopenharmony_ci return -EINVAL; 1408c2ecf20Sopenharmony_ci if (!ept->ops->sendto) 1418c2ecf20Sopenharmony_ci return -ENXIO; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return ept->ops->sendto(ept, data, len, dst); 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rpmsg_sendto); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci/** 1488c2ecf20Sopenharmony_ci * rpmsg_send_offchannel() - send a message using explicit src/dst addresses 1498c2ecf20Sopenharmony_ci * @ept: the rpmsg endpoint 1508c2ecf20Sopenharmony_ci * @src: source address 1518c2ecf20Sopenharmony_ci * @dst: destination address 1528c2ecf20Sopenharmony_ci * @data: payload of message 1538c2ecf20Sopenharmony_ci * @len: length of payload 1548c2ecf20Sopenharmony_ci * 1558c2ecf20Sopenharmony_ci * This function sends @data of length @len to the remote @dst address, 1568c2ecf20Sopenharmony_ci * and uses @src as the source address. 1578c2ecf20Sopenharmony_ci * The message will be sent to the remote processor which the @ept 1588c2ecf20Sopenharmony_ci * endpoint belongs to. 1598c2ecf20Sopenharmony_ci * In case there are no TX buffers available, the function will block until 1608c2ecf20Sopenharmony_ci * one becomes available, or a timeout of 15 seconds elapses. When the latter 1618c2ecf20Sopenharmony_ci * happens, -ERESTARTSYS is returned. 1628c2ecf20Sopenharmony_ci * 1638c2ecf20Sopenharmony_ci * Can only be called from process context (for now). 1648c2ecf20Sopenharmony_ci * 1658c2ecf20Sopenharmony_ci * Returns 0 on success and an appropriate error value on failure. 1668c2ecf20Sopenharmony_ci */ 1678c2ecf20Sopenharmony_ciint rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, 1688c2ecf20Sopenharmony_ci void *data, int len) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci if (WARN_ON(!ept)) 1718c2ecf20Sopenharmony_ci return -EINVAL; 1728c2ecf20Sopenharmony_ci if (!ept->ops->send_offchannel) 1738c2ecf20Sopenharmony_ci return -ENXIO; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci return ept->ops->send_offchannel(ept, src, dst, data, len); 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rpmsg_send_offchannel); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/** 1808c2ecf20Sopenharmony_ci * rpmsg_trysend() - send a message across to the remote processor 1818c2ecf20Sopenharmony_ci * @ept: the rpmsg endpoint 1828c2ecf20Sopenharmony_ci * @data: payload of message 1838c2ecf20Sopenharmony_ci * @len: length of payload 1848c2ecf20Sopenharmony_ci * 1858c2ecf20Sopenharmony_ci * This function sends @data of length @len on the @ept endpoint. 1868c2ecf20Sopenharmony_ci * The message will be sent to the remote processor which the @ept 1878c2ecf20Sopenharmony_ci * endpoint belongs to, using @ept's address as source and its associated 1888c2ecf20Sopenharmony_ci * rpdev's address as destination. 1898c2ecf20Sopenharmony_ci * In case there are no TX buffers available, the function will immediately 1908c2ecf20Sopenharmony_ci * return -ENOMEM without waiting until one becomes available. 1918c2ecf20Sopenharmony_ci * 1928c2ecf20Sopenharmony_ci * Can only be called from process context (for now). 1938c2ecf20Sopenharmony_ci * 1948c2ecf20Sopenharmony_ci * Returns 0 on success and an appropriate error value on failure. 1958c2ecf20Sopenharmony_ci */ 1968c2ecf20Sopenharmony_ciint rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci if (WARN_ON(!ept)) 1998c2ecf20Sopenharmony_ci return -EINVAL; 2008c2ecf20Sopenharmony_ci if (!ept->ops->trysend) 2018c2ecf20Sopenharmony_ci return -ENXIO; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return ept->ops->trysend(ept, data, len); 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rpmsg_trysend); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/** 2088c2ecf20Sopenharmony_ci * rpmsg_trysendto() - send a message across to the remote processor, specify dst 2098c2ecf20Sopenharmony_ci * @ept: the rpmsg endpoint 2108c2ecf20Sopenharmony_ci * @data: payload of message 2118c2ecf20Sopenharmony_ci * @len: length of payload 2128c2ecf20Sopenharmony_ci * @dst: destination address 2138c2ecf20Sopenharmony_ci * 2148c2ecf20Sopenharmony_ci * This function sends @data of length @len to the remote @dst address. 2158c2ecf20Sopenharmony_ci * The message will be sent to the remote processor which the @ept 2168c2ecf20Sopenharmony_ci * endpoint belongs to, using @ept's address as source. 2178c2ecf20Sopenharmony_ci * In case there are no TX buffers available, the function will immediately 2188c2ecf20Sopenharmony_ci * return -ENOMEM without waiting until one becomes available. 2198c2ecf20Sopenharmony_ci * 2208c2ecf20Sopenharmony_ci * Can only be called from process context (for now). 2218c2ecf20Sopenharmony_ci * 2228c2ecf20Sopenharmony_ci * Returns 0 on success and an appropriate error value on failure. 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_ciint rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci if (WARN_ON(!ept)) 2278c2ecf20Sopenharmony_ci return -EINVAL; 2288c2ecf20Sopenharmony_ci if (!ept->ops->trysendto) 2298c2ecf20Sopenharmony_ci return -ENXIO; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci return ept->ops->trysendto(ept, data, len, dst); 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rpmsg_trysendto); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci/** 2368c2ecf20Sopenharmony_ci * rpmsg_poll() - poll the endpoint's send buffers 2378c2ecf20Sopenharmony_ci * @ept: the rpmsg endpoint 2388c2ecf20Sopenharmony_ci * @filp: file for poll_wait() 2398c2ecf20Sopenharmony_ci * @wait: poll_table for poll_wait() 2408c2ecf20Sopenharmony_ci * 2418c2ecf20Sopenharmony_ci * Returns mask representing the current state of the endpoint's send buffers 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_ci__poll_t rpmsg_poll(struct rpmsg_endpoint *ept, struct file *filp, 2448c2ecf20Sopenharmony_ci poll_table *wait) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci if (WARN_ON(!ept)) 2478c2ecf20Sopenharmony_ci return 0; 2488c2ecf20Sopenharmony_ci if (!ept->ops->poll) 2498c2ecf20Sopenharmony_ci return 0; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return ept->ops->poll(ept, filp, wait); 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rpmsg_poll); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci/** 2568c2ecf20Sopenharmony_ci * rpmsg_trysend_offchannel() - send a message using explicit src/dst addresses 2578c2ecf20Sopenharmony_ci * @ept: the rpmsg endpoint 2588c2ecf20Sopenharmony_ci * @src: source address 2598c2ecf20Sopenharmony_ci * @dst: destination address 2608c2ecf20Sopenharmony_ci * @data: payload of message 2618c2ecf20Sopenharmony_ci * @len: length of payload 2628c2ecf20Sopenharmony_ci * 2638c2ecf20Sopenharmony_ci * This function sends @data of length @len to the remote @dst address, 2648c2ecf20Sopenharmony_ci * and uses @src as the source address. 2658c2ecf20Sopenharmony_ci * The message will be sent to the remote processor which the @ept 2668c2ecf20Sopenharmony_ci * endpoint belongs to. 2678c2ecf20Sopenharmony_ci * In case there are no TX buffers available, the function will immediately 2688c2ecf20Sopenharmony_ci * return -ENOMEM without waiting until one becomes available. 2698c2ecf20Sopenharmony_ci * 2708c2ecf20Sopenharmony_ci * Can only be called from process context (for now). 2718c2ecf20Sopenharmony_ci * 2728c2ecf20Sopenharmony_ci * Returns 0 on success and an appropriate error value on failure. 2738c2ecf20Sopenharmony_ci */ 2748c2ecf20Sopenharmony_ciint rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, 2758c2ecf20Sopenharmony_ci void *data, int len) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci if (WARN_ON(!ept)) 2788c2ecf20Sopenharmony_ci return -EINVAL; 2798c2ecf20Sopenharmony_ci if (!ept->ops->trysend_offchannel) 2808c2ecf20Sopenharmony_ci return -ENXIO; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return ept->ops->trysend_offchannel(ept, src, dst, data, len); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rpmsg_trysend_offchannel); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci/* 2878c2ecf20Sopenharmony_ci * match a rpmsg channel with a channel info struct. 2888c2ecf20Sopenharmony_ci * this is used to make sure we're not creating rpmsg devices for channels 2898c2ecf20Sopenharmony_ci * that already exist. 2908c2ecf20Sopenharmony_ci */ 2918c2ecf20Sopenharmony_cistatic int rpmsg_device_match(struct device *dev, void *data) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci struct rpmsg_channel_info *chinfo = data; 2948c2ecf20Sopenharmony_ci struct rpmsg_device *rpdev = to_rpmsg_device(dev); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (chinfo->src != RPMSG_ADDR_ANY && chinfo->src != rpdev->src) 2978c2ecf20Sopenharmony_ci return 0; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (chinfo->dst != RPMSG_ADDR_ANY && chinfo->dst != rpdev->dst) 3008c2ecf20Sopenharmony_ci return 0; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (strncmp(chinfo->name, rpdev->id.name, RPMSG_NAME_SIZE)) 3038c2ecf20Sopenharmony_ci return 0; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* found a match ! */ 3068c2ecf20Sopenharmony_ci return 1; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistruct device *rpmsg_find_device(struct device *parent, 3108c2ecf20Sopenharmony_ci struct rpmsg_channel_info *chinfo) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci return device_find_child(parent, chinfo, rpmsg_device_match); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rpmsg_find_device); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci/* sysfs show configuration fields */ 3188c2ecf20Sopenharmony_ci#define rpmsg_show_attr(field, path, format_string) \ 3198c2ecf20Sopenharmony_cistatic ssize_t \ 3208c2ecf20Sopenharmony_cifield##_show(struct device *dev, \ 3218c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) \ 3228c2ecf20Sopenharmony_ci{ \ 3238c2ecf20Sopenharmony_ci struct rpmsg_device *rpdev = to_rpmsg_device(dev); \ 3248c2ecf20Sopenharmony_ci \ 3258c2ecf20Sopenharmony_ci return sprintf(buf, format_string, rpdev->path); \ 3268c2ecf20Sopenharmony_ci} \ 3278c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(field); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci#define rpmsg_string_attr(field, member) \ 3308c2ecf20Sopenharmony_cistatic ssize_t \ 3318c2ecf20Sopenharmony_cifield##_store(struct device *dev, struct device_attribute *attr, \ 3328c2ecf20Sopenharmony_ci const char *buf, size_t sz) \ 3338c2ecf20Sopenharmony_ci{ \ 3348c2ecf20Sopenharmony_ci struct rpmsg_device *rpdev = to_rpmsg_device(dev); \ 3358c2ecf20Sopenharmony_ci const char *old; \ 3368c2ecf20Sopenharmony_ci char *new; \ 3378c2ecf20Sopenharmony_ci \ 3388c2ecf20Sopenharmony_ci new = kstrndup(buf, sz, GFP_KERNEL); \ 3398c2ecf20Sopenharmony_ci if (!new) \ 3408c2ecf20Sopenharmony_ci return -ENOMEM; \ 3418c2ecf20Sopenharmony_ci new[strcspn(new, "\n")] = '\0'; \ 3428c2ecf20Sopenharmony_ci \ 3438c2ecf20Sopenharmony_ci device_lock(dev); \ 3448c2ecf20Sopenharmony_ci old = rpdev->member; \ 3458c2ecf20Sopenharmony_ci if (strlen(new)) { \ 3468c2ecf20Sopenharmony_ci rpdev->member = new; \ 3478c2ecf20Sopenharmony_ci } else { \ 3488c2ecf20Sopenharmony_ci kfree(new); \ 3498c2ecf20Sopenharmony_ci rpdev->member = NULL; \ 3508c2ecf20Sopenharmony_ci } \ 3518c2ecf20Sopenharmony_ci device_unlock(dev); \ 3528c2ecf20Sopenharmony_ci \ 3538c2ecf20Sopenharmony_ci kfree(old); \ 3548c2ecf20Sopenharmony_ci \ 3558c2ecf20Sopenharmony_ci return sz; \ 3568c2ecf20Sopenharmony_ci} \ 3578c2ecf20Sopenharmony_cistatic ssize_t \ 3588c2ecf20Sopenharmony_cifield##_show(struct device *dev, \ 3598c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) \ 3608c2ecf20Sopenharmony_ci{ \ 3618c2ecf20Sopenharmony_ci struct rpmsg_device *rpdev = to_rpmsg_device(dev); \ 3628c2ecf20Sopenharmony_ci \ 3638c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", rpdev->member); \ 3648c2ecf20Sopenharmony_ci} \ 3658c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(field) 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci/* for more info, see Documentation/ABI/testing/sysfs-bus-rpmsg */ 3688c2ecf20Sopenharmony_cirpmsg_show_attr(name, id.name, "%s\n"); 3698c2ecf20Sopenharmony_cirpmsg_show_attr(src, src, "0x%x\n"); 3708c2ecf20Sopenharmony_cirpmsg_show_attr(dst, dst, "0x%x\n"); 3718c2ecf20Sopenharmony_cirpmsg_show_attr(announce, announce ? "true" : "false", "%s\n"); 3728c2ecf20Sopenharmony_cirpmsg_string_attr(driver_override, driver_override); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic ssize_t modalias_show(struct device *dev, 3758c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci struct rpmsg_device *rpdev = to_rpmsg_device(dev); 3788c2ecf20Sopenharmony_ci ssize_t len; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci len = of_device_modalias(dev, buf, PAGE_SIZE); 3818c2ecf20Sopenharmony_ci if (len != -ENODEV) 3828c2ecf20Sopenharmony_ci return len; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci return sprintf(buf, RPMSG_DEVICE_MODALIAS_FMT "\n", rpdev->id.name); 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(modalias); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic struct attribute *rpmsg_dev_attrs[] = { 3898c2ecf20Sopenharmony_ci &dev_attr_name.attr, 3908c2ecf20Sopenharmony_ci &dev_attr_modalias.attr, 3918c2ecf20Sopenharmony_ci &dev_attr_dst.attr, 3928c2ecf20Sopenharmony_ci &dev_attr_src.attr, 3938c2ecf20Sopenharmony_ci &dev_attr_announce.attr, 3948c2ecf20Sopenharmony_ci &dev_attr_driver_override.attr, 3958c2ecf20Sopenharmony_ci NULL, 3968c2ecf20Sopenharmony_ci}; 3978c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(rpmsg_dev); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci/* rpmsg devices and drivers are matched using the service name */ 4008c2ecf20Sopenharmony_cistatic inline int rpmsg_id_match(const struct rpmsg_device *rpdev, 4018c2ecf20Sopenharmony_ci const struct rpmsg_device_id *id) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci return strncmp(id->name, rpdev->id.name, RPMSG_NAME_SIZE) == 0; 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci/* match rpmsg channel and rpmsg driver */ 4078c2ecf20Sopenharmony_cistatic int rpmsg_dev_match(struct device *dev, struct device_driver *drv) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci struct rpmsg_device *rpdev = to_rpmsg_device(dev); 4108c2ecf20Sopenharmony_ci struct rpmsg_driver *rpdrv = to_rpmsg_driver(drv); 4118c2ecf20Sopenharmony_ci const struct rpmsg_device_id *ids = rpdrv->id_table; 4128c2ecf20Sopenharmony_ci unsigned int i; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (rpdev->driver_override) 4158c2ecf20Sopenharmony_ci return !strcmp(rpdev->driver_override, drv->name); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (ids) 4188c2ecf20Sopenharmony_ci for (i = 0; ids[i].name[0]; i++) 4198c2ecf20Sopenharmony_ci if (rpmsg_id_match(rpdev, &ids[i])) 4208c2ecf20Sopenharmony_ci return 1; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci return of_driver_match_device(dev, drv); 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci struct rpmsg_device *rpdev = to_rpmsg_device(dev); 4288c2ecf20Sopenharmony_ci int ret; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci ret = of_device_uevent_modalias(dev, env); 4318c2ecf20Sopenharmony_ci if (ret != -ENODEV) 4328c2ecf20Sopenharmony_ci return ret; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci return add_uevent_var(env, "MODALIAS=" RPMSG_DEVICE_MODALIAS_FMT, 4358c2ecf20Sopenharmony_ci rpdev->id.name); 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci/* 4398c2ecf20Sopenharmony_ci * when an rpmsg driver is probed with a channel, we seamlessly create 4408c2ecf20Sopenharmony_ci * it an endpoint, binding its rx callback to a unique local rpmsg 4418c2ecf20Sopenharmony_ci * address. 4428c2ecf20Sopenharmony_ci * 4438c2ecf20Sopenharmony_ci * if we need to, we also announce about this channel to the remote 4448c2ecf20Sopenharmony_ci * processor (needed in case the driver is exposing an rpmsg service). 4458c2ecf20Sopenharmony_ci */ 4468c2ecf20Sopenharmony_cistatic int rpmsg_dev_probe(struct device *dev) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct rpmsg_device *rpdev = to_rpmsg_device(dev); 4498c2ecf20Sopenharmony_ci struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver); 4508c2ecf20Sopenharmony_ci struct rpmsg_channel_info chinfo = {}; 4518c2ecf20Sopenharmony_ci struct rpmsg_endpoint *ept = NULL; 4528c2ecf20Sopenharmony_ci int err; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci err = dev_pm_domain_attach(dev, true); 4558c2ecf20Sopenharmony_ci if (err) 4568c2ecf20Sopenharmony_ci goto out; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (rpdrv->callback) { 4598c2ecf20Sopenharmony_ci strncpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE); 4608c2ecf20Sopenharmony_ci chinfo.src = rpdev->src; 4618c2ecf20Sopenharmony_ci chinfo.dst = RPMSG_ADDR_ANY; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, chinfo); 4648c2ecf20Sopenharmony_ci if (!ept) { 4658c2ecf20Sopenharmony_ci dev_err(dev, "failed to create endpoint\n"); 4668c2ecf20Sopenharmony_ci err = -ENOMEM; 4678c2ecf20Sopenharmony_ci goto out; 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci rpdev->ept = ept; 4718c2ecf20Sopenharmony_ci rpdev->src = ept->addr; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci err = rpdrv->probe(rpdev); 4758c2ecf20Sopenharmony_ci if (err) { 4768c2ecf20Sopenharmony_ci dev_err(dev, "%s: failed: %d\n", __func__, err); 4778c2ecf20Sopenharmony_ci goto destroy_ept; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (ept && rpdev->ops->announce_create) { 4818c2ecf20Sopenharmony_ci err = rpdev->ops->announce_create(rpdev); 4828c2ecf20Sopenharmony_ci if (err) { 4838c2ecf20Sopenharmony_ci dev_err(dev, "failed to announce creation\n"); 4848c2ecf20Sopenharmony_ci goto remove_rpdev; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci return 0; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ciremove_rpdev: 4918c2ecf20Sopenharmony_ci if (rpdrv->remove) 4928c2ecf20Sopenharmony_ci rpdrv->remove(rpdev); 4938c2ecf20Sopenharmony_cidestroy_ept: 4948c2ecf20Sopenharmony_ci if (ept) 4958c2ecf20Sopenharmony_ci rpmsg_destroy_ept(ept); 4968c2ecf20Sopenharmony_ciout: 4978c2ecf20Sopenharmony_ci return err; 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cistatic int rpmsg_dev_remove(struct device *dev) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci struct rpmsg_device *rpdev = to_rpmsg_device(dev); 5038c2ecf20Sopenharmony_ci struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver); 5048c2ecf20Sopenharmony_ci int err = 0; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci if (rpdev->ops->announce_destroy) 5078c2ecf20Sopenharmony_ci err = rpdev->ops->announce_destroy(rpdev); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (rpdrv->remove) 5108c2ecf20Sopenharmony_ci rpdrv->remove(rpdev); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci dev_pm_domain_detach(dev, true); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci if (rpdev->ept) 5158c2ecf20Sopenharmony_ci rpmsg_destroy_ept(rpdev->ept); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci return err; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic struct bus_type rpmsg_bus = { 5218c2ecf20Sopenharmony_ci .name = "rpmsg", 5228c2ecf20Sopenharmony_ci .match = rpmsg_dev_match, 5238c2ecf20Sopenharmony_ci .dev_groups = rpmsg_dev_groups, 5248c2ecf20Sopenharmony_ci .uevent = rpmsg_uevent, 5258c2ecf20Sopenharmony_ci .probe = rpmsg_dev_probe, 5268c2ecf20Sopenharmony_ci .remove = rpmsg_dev_remove, 5278c2ecf20Sopenharmony_ci}; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci/* 5308c2ecf20Sopenharmony_ci * A helper for registering rpmsg device with driver override and name. 5318c2ecf20Sopenharmony_ci * Drivers should not be using it, but instead rpmsg_register_device(). 5328c2ecf20Sopenharmony_ci */ 5338c2ecf20Sopenharmony_ciint rpmsg_register_device_override(struct rpmsg_device *rpdev, 5348c2ecf20Sopenharmony_ci const char *driver_override) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci struct device *dev = &rpdev->dev; 5378c2ecf20Sopenharmony_ci int ret; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (driver_override) 5408c2ecf20Sopenharmony_ci strcpy(rpdev->id.name, driver_override); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci dev_set_name(&rpdev->dev, "%s.%s.%d.%d", dev_name(dev->parent), 5438c2ecf20Sopenharmony_ci rpdev->id.name, rpdev->src, rpdev->dst); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci rpdev->dev.bus = &rpmsg_bus; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci device_initialize(dev); 5488c2ecf20Sopenharmony_ci if (driver_override) { 5498c2ecf20Sopenharmony_ci ret = driver_set_override(dev, &rpdev->driver_override, 5508c2ecf20Sopenharmony_ci driver_override, 5518c2ecf20Sopenharmony_ci strlen(driver_override)); 5528c2ecf20Sopenharmony_ci if (ret) { 5538c2ecf20Sopenharmony_ci dev_err(dev, "device_set_override failed: %d\n", ret); 5548c2ecf20Sopenharmony_ci put_device(dev); 5558c2ecf20Sopenharmony_ci return ret; 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci ret = device_add(dev); 5608c2ecf20Sopenharmony_ci if (ret) { 5618c2ecf20Sopenharmony_ci dev_err(dev, "device_add failed: %d\n", ret); 5628c2ecf20Sopenharmony_ci kfree(rpdev->driver_override); 5638c2ecf20Sopenharmony_ci rpdev->driver_override = NULL; 5648c2ecf20Sopenharmony_ci put_device(&rpdev->dev); 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci return ret; 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rpmsg_register_device_override); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ciint rpmsg_register_device(struct rpmsg_device *rpdev) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci return rpmsg_register_device_override(rpdev, NULL); 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rpmsg_register_device); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci/* 5788c2ecf20Sopenharmony_ci * find an existing channel using its name + address properties, 5798c2ecf20Sopenharmony_ci * and destroy it 5808c2ecf20Sopenharmony_ci */ 5818c2ecf20Sopenharmony_ciint rpmsg_unregister_device(struct device *parent, 5828c2ecf20Sopenharmony_ci struct rpmsg_channel_info *chinfo) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci struct device *dev; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci dev = rpmsg_find_device(parent, chinfo); 5878c2ecf20Sopenharmony_ci if (!dev) 5888c2ecf20Sopenharmony_ci return -EINVAL; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci device_unregister(dev); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci put_device(dev); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci return 0; 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rpmsg_unregister_device); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci/** 5998c2ecf20Sopenharmony_ci * __register_rpmsg_driver() - register an rpmsg driver with the rpmsg bus 6008c2ecf20Sopenharmony_ci * @rpdrv: pointer to a struct rpmsg_driver 6018c2ecf20Sopenharmony_ci * @owner: owning module/driver 6028c2ecf20Sopenharmony_ci * 6038c2ecf20Sopenharmony_ci * Returns 0 on success, and an appropriate error value on failure. 6048c2ecf20Sopenharmony_ci */ 6058c2ecf20Sopenharmony_ciint __register_rpmsg_driver(struct rpmsg_driver *rpdrv, struct module *owner) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci rpdrv->drv.bus = &rpmsg_bus; 6088c2ecf20Sopenharmony_ci rpdrv->drv.owner = owner; 6098c2ecf20Sopenharmony_ci return driver_register(&rpdrv->drv); 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__register_rpmsg_driver); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci/** 6148c2ecf20Sopenharmony_ci * unregister_rpmsg_driver() - unregister an rpmsg driver from the rpmsg bus 6158c2ecf20Sopenharmony_ci * @rpdrv: pointer to a struct rpmsg_driver 6168c2ecf20Sopenharmony_ci * 6178c2ecf20Sopenharmony_ci * Returns 0 on success, and an appropriate error value on failure. 6188c2ecf20Sopenharmony_ci */ 6198c2ecf20Sopenharmony_civoid unregister_rpmsg_driver(struct rpmsg_driver *rpdrv) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci driver_unregister(&rpdrv->drv); 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ciEXPORT_SYMBOL(unregister_rpmsg_driver); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic int __init rpmsg_init(void) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci int ret; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci ret = bus_register(&rpmsg_bus); 6318c2ecf20Sopenharmony_ci if (ret) 6328c2ecf20Sopenharmony_ci pr_err("failed to register rpmsg bus: %d\n", ret); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci return ret; 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_cipostcore_initcall(rpmsg_init); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic void __exit rpmsg_fini(void) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci bus_unregister(&rpmsg_bus); 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_cimodule_exit(rpmsg_fini); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("remote processor messaging bus"); 6458c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 646