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