Message ID | 1471306640-29917-9-git-send-email-bjorn.andersson@linaro.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
> -----Original Message----- > From: linux-remoteproc-owner@vger.kernel.org [mailto:linux-remoteproc- > owner@vger.kernel.org] On Behalf Of Bjorn Andersson > Sent: Tuesday, August 16, 2016 2:17 AM > To: Ohad Ben-Cohen <ohad@wizery.com>; Bjorn Andersson > <bjorn.andersson@linaro.org> > Cc: linux-remoteproc@vger.kernel.org; linux-arm-msm@vger.kernel.org; > linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org; > Sricharan R <sricharan@codeaurora.org> > Subject: [PATCH 08/14] rpmsg: Split rpmsg core and virtio backend > > Extract the generic rpmsg core functionality from the virtio rpmsg > implementation, splitting the implementation in a rpmsg core and a > virtio backend. > > Based on initial work by Sricharan R <sricharan@codeaurora.org> > > Cc: Sricharan R <sricharan@codeaurora.org> > Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org> > --- > drivers/rpmsg/Kconfig | 4 + > drivers/rpmsg/Makefile | 3 +- > drivers/rpmsg/rpmsg_core.c | 513 > +++++++++++++++++++++++++++++++++++++++ > drivers/rpmsg/rpmsg_internal.h | 45 ++++ > drivers/rpmsg/virtio_rpmsg_bus.c | 477 +----------------------------------- Hi Bjorn, Could you please regenerate the patch with option -M (of git formatpatch) to detect file renames. It will provide better visibility of differences between virtio_rpmsg_bus.c and rpmsg_core.c. > 5 files changed, 569 insertions(+), 473 deletions(-) > create mode 100644 drivers/rpmsg/rpmsg_core.c > create mode 100644 drivers/rpmsg/rpmsg_internal.h > > diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig > index 69a219387582..40614be88c97 100644 > --- a/drivers/rpmsg/Kconfig > +++ b/drivers/rpmsg/Kconfig > @@ -3,6 +3,10 @@ menu "Rpmsg drivers" > # RPMSG always gets selected by whoever wants it > config RPMSG > tristate > + > +config RPMSG_VIRTIO > + tristate > + select RPMSG > select VIRTIO > select VIRTUALIZATION > Remoteproc Kconfig should be changed too to select RPMSG_VIRTIO instead of RPMSG. Regards, Loic > diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile > index 7617fcb8259f..383213417a00 100644 > --- a/drivers/rpmsg/Makefile > +++ b/drivers/rpmsg/Makefile > @@ -1 +1,2 @@ > -obj-$(CONFIG_RPMSG) += virtio_rpmsg_bus.o > +obj-$(CONFIG_RPMSG) += rpmsg_core.o > +obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o > diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c > new file mode 100644 > index 000000000000..73bbc5ea5778 > --- /dev/null > +++ b/drivers/rpmsg/rpmsg_core.c > @@ -0,0 +1,513 @@ > +/* > + * Virtio-based remote processor messaging bus > + * > + * Copyright (C) 2011 Texas Instruments, Inc. > + * Copyright (C) 2011 Google, Inc. > + * > + * Ohad Ben-Cohen <ohad@wizery.com> > + * Brian Swetland <swetland@google.com> > + * > + * This software is licensed under the terms of the GNU General Public > + * License version 2, as published by the Free Software Foundation, and > + * may be copied, distributed, and modified under those terms. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + */ > + > +#define pr_fmt(fmt) "%s: " fmt, __func__ > + > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/virtio.h> > +#include <linux/virtio_ids.h> > +#include <linux/virtio_config.h> > +#include <linux/scatterlist.h> > +#include <linux/dma-mapping.h> > +#include <linux/slab.h> > +#include <linux/idr.h> > +#include <linux/jiffies.h> > +#include <linux/sched.h> > +#include <linux/wait.h> > +#include <linux/rpmsg.h> > +#include <linux/mutex.h> > +#include <linux/of_device.h> > + > +#include "rpmsg_internal.h" > + > +/** > + * rpmsg_create_ept() - create a new rpmsg_endpoint > + * @rpdev: rpmsg channel device > + * @cb: rx callback handler > + * @priv: private data for the driver's use > + * @addr: local rpmsg address to bind with @cb > + * > + * Every rpmsg address in the system is bound to an rx callback (so when > + * inbound messages arrive, they are dispatched by the rpmsg bus using the > + * appropriate callback handler) by means of an rpmsg_endpoint struct. > + * > + * This function allows drivers to create such an endpoint, and by that, > + * bind a callback, and possibly some private data too, to an rpmsg address > + * (either one that is known in advance, or one that will be dynamically > + * assigned for them). > + * > + * Simple rpmsg drivers need not call rpmsg_create_ept, because an > endpoint > + * is already created for them when they are probed by the rpmsg bus > + * (using the rx callback provided when they registered to the rpmsg bus). > + * > + * So things should just work for simple drivers: they already have an > + * endpoint, their rx callback is bound to their rpmsg address, and when > + * relevant inbound messages arrive (i.e. messages which their dst address > + * equals to the src address of their rpmsg channel), the driver's handler > + * is invoked to process it. > + * > + * That said, more complicated drivers might do need to allocate > + * additional rpmsg addresses, and bind them to different rx callbacks. > + * To accomplish that, those drivers need to call this function. > + * > + * Drivers should provide their @rpdev channel (so the new endpoint would > belong > + * to the same remote processor their channel belongs to), an rx callback > + * function, an optional private data (which is provided back when the > + * rx callback is invoked), and an address they want to bind with the > + * callback. If @addr is RPMSG_ADDR_ANY, then rpmsg_create_ept will > + * dynamically assign them an available rpmsg address (drivers should have > + * a very good reason why not to always use RPMSG_ADDR_ANY here). > + * > + * Returns a pointer to the endpoint on success, or NULL on error. > + */ > +struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev, > + rpmsg_rx_cb_t cb, void *priv, u32 addr) > +{ > + return rpdev->create_ept(rpdev, cb, priv, addr); > +} > +EXPORT_SYMBOL(rpmsg_create_ept); > + > +/** > + * rpmsg_destroy_ept() - destroy an existing rpmsg endpoint > + * @ept: endpoing to destroy > + * > + * Should be used by drivers to destroy an rpmsg endpoint previously > + * created with rpmsg_create_ept(). > + */ > +void rpmsg_destroy_ept(struct rpmsg_endpoint *ept) > +{ > + ept->rpdev->destroy_ept(ept); > +} > +EXPORT_SYMBOL(rpmsg_destroy_ept); > + > +/** > + * rpmsg_send() - send a message across to the remote processor > + * @ept: the rpmsg endpoint > + * @data: payload of message > + * @len: length of payload > + * > + * This function sends @data of length @len on the @ept endpoint. > + * The message will be sent to the remote processor which the @ept > + * endpoint belongs to, using @ept's address and its associated rpmsg > + * device destination addresses. > + * In case there are no TX buffers available, the function will block until > + * one becomes available, or a timeout of 15 seconds elapses. When the > latter > + * happens, -ERESTARTSYS is returned. > + * > + * Can only be called from process context (for now). > + * > + * Returns 0 on success and an appropriate error value on failure. > + */ > +int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len) > +{ > + struct rpmsg_device *rpdev = ept->rpdev; > + > + return rpdev->send(ept, data, len); > +} > + > +/** > + * rpmsg_sendto() - send a message across to the remote processor, > specify dst > + * @ept: the rpmsg endpoint > + * @data: payload of message > + * @len: length of payload > + * @dst: destination address > + * > + * This function sends @data of length @len to the remote @dst address. > + * The message will be sent to the remote processor which the @ept > + * endpoint belongs to, using @ept's address as source. > + * In case there are no TX buffers available, the function will block until > + * one becomes available, or a timeout of 15 seconds elapses. When the > latter > + * happens, -ERESTARTSYS is returned. > + * > + * Can only be called from process context (for now). > + * > + * Returns 0 on success and an appropriate error value on failure. > + */ > +int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst) > +{ > + struct rpmsg_device *rpdev = ept->rpdev; > + > + return rpdev->sendto(ept, data, len, dst); > +} > +EXPORT_SYMBOL(rpmsg_sendto); > + > +/** > + * rpmsg_send_offchannel() - send a message using explicit src/dst > addresses > + * @ept: the rpmsg endpoint > + * @src: source address > + * @dst: destination address > + * @data: payload of message > + * @len: length of payload > + * > + * This function sends @data of length @len to the remote @dst address, > + * and uses @src as the source address. > + * The message will be sent to the remote processor which the @ept > + * endpoint belongs to. > + * In case there are no TX buffers available, the function will block until > + * one becomes available, or a timeout of 15 seconds elapses. When the > latter > + * happens, -ERESTARTSYS is returned. > + * > + * Can only be called from process context (for now). > + * > + * Returns 0 on success and an appropriate error value on failure. > + */ > +int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, > + void *data, int len) > +{ > + struct rpmsg_device *rpdev = ept->rpdev; > + > + return rpdev->send_offchannel(ept, src, dst, data, len); > +} > +EXPORT_SYMBOL(rpmsg_send_offchannel); > + > +/** > + * rpmsg_send() - send a message across to the remote processor > + * @ept: the rpmsg endpoint > + * @data: payload of message > + * @len: length of payload > + * > + * This function sends @data of length @len on the @ept endpoint. > + * The message will be sent to the remote processor which the @ept > + * endpoint belongs to, using @ept's address as source and its associated > + * rpdev's address as destination. > + * In case there are no TX buffers available, the function will immediately > + * return -ENOMEM without waiting until one becomes available. > + * > + * Can only be called from process context (for now). > + * > + * Returns 0 on success and an appropriate error value on failure. > + */ > +int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len) > +{ > + struct rpmsg_device *rpdev = ept->rpdev; > + > + return rpdev->trysend(ept, data, len); > +} > +EXPORT_SYMBOL(rpmsg_trysend); > + > +/** > + * rpmsg_sendto() - send a message across to the remote processor, > specify dst > + * @ept: the rpmsg endpoint > + * @data: payload of message > + * @len: length of payload > + * @dst: destination address > + * > + * This function sends @data of length @len to the remote @dst address. > + * The message will be sent to the remote processor which the @ept > + * endpoint belongs to, using @ept's address as source. > + * In case there are no TX buffers available, the function will immediately > + * return -ENOMEM without waiting until one becomes available. > + * > + * Can only be called from process context (for now). > + * > + * Returns 0 on success and an appropriate error value on failure. > + */ > +int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 > dst) > +{ > + struct rpmsg_device *rpdev = ept->rpdev; > + > + return rpdev->trysendto(ept, data, len, dst); > +} > +EXPORT_SYMBOL(rpmsg_trysendto); > + > +/** > + * rpmsg_send_offchannel() - send a message using explicit src/dst > addresses > + * @ept: the rpmsg endpoint > + * @src: source address > + * @dst: destination address > + * @data: payload of message > + * @len: length of payload > + * > + * This function sends @data of length @len to the remote @dst address, > + * and uses @src as the source address. > + * The message will be sent to the remote processor which the @ept > + * endpoint belongs to. > + * In case there are no TX buffers available, the function will immediately > + * return -ENOMEM without waiting until one becomes available. > + * > + * Can only be called from process context (for now). > + * > + * Returns 0 on success and an appropriate error value on failure. > + */ > +int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 > dst, > + void *data, int len) > +{ > + struct rpmsg_device *rpdev = ept->rpdev; > + > + return rpdev->trysend_offchannel(ept, src, dst, data, len); > +} > +EXPORT_SYMBOL(rpmsg_trysend_offchannel); > + > +/* sysfs show configuration fields */ > +#define rpmsg_show_attr(field, path, format_string) \ > +static ssize_t \ > +field##_show(struct device *dev, \ > + struct device_attribute *attr, char *buf) \ > +{ \ > + struct rpmsg_device *rpdev = to_rpmsg_device(dev); \ > + \ > + return sprintf(buf, format_string, rpdev->path); \ > +} > + > +/* for more info, see Documentation/ABI/testing/sysfs-bus-rpmsg */ > +rpmsg_show_attr(name, id.name, "%s\n"); > +rpmsg_show_attr(src, src, "0x%x\n"); > +rpmsg_show_attr(dst, dst, "0x%x\n"); > +rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n"); > + > +static ssize_t modalias_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct rpmsg_device *rpdev = to_rpmsg_device(dev); > + > + return sprintf(buf, RPMSG_DEVICE_MODALIAS_FMT "\n", rpdev- > >id.name); > +} > + > +static struct device_attribute rpmsg_dev_attrs[] = { > + __ATTR_RO(name), > + __ATTR_RO(modalias), > + __ATTR_RO(dst), > + __ATTR_RO(src), > + __ATTR_RO(announce), > + __ATTR_NULL > +}; > + > +/* rpmsg devices and drivers are matched using the service name */ > +static inline int rpmsg_id_match(const struct rpmsg_device *rpdev, > + const struct rpmsg_device_id *id) > +{ > + return strncmp(id->name, rpdev->id.name, RPMSG_NAME_SIZE) == > 0; > +} > + > +/* match rpmsg channel and rpmsg driver */ > +static int rpmsg_dev_match(struct device *dev, struct device_driver *drv) > +{ > + struct rpmsg_device *rpdev = to_rpmsg_device(dev); > + struct rpmsg_driver *rpdrv = to_rpmsg_driver(drv); > + const struct rpmsg_device_id *ids = rpdrv->id_table; > + unsigned int i; > + > + if (ids) > + for (i = 0; ids[i].name[0]; i++) > + if (rpmsg_id_match(rpdev, &ids[i])) > + return 1; > + > + return of_driver_match_device(dev, drv); > +} > + > +static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env) > +{ > + struct rpmsg_device *rpdev = to_rpmsg_device(dev); > + > + return add_uevent_var(env, "MODALIAS=" > RPMSG_DEVICE_MODALIAS_FMT, > + rpdev->id.name); > +} > + > +/* > + * when an rpmsg driver is probed with a channel, we seamlessly create > + * it an endpoint, binding its rx callback to a unique local rpmsg > + * address. > + * > + * if we need to, we also announce about this channel to the remote > + * processor (needed in case the driver is exposing an rpmsg service). > + */ > +static int rpmsg_dev_probe(struct device *dev) > +{ > + struct rpmsg_device *rpdev = to_rpmsg_device(dev); > + struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver); > + struct rpmsg_endpoint *ept; > + int err; > + > + ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, rpdev->src); > + if (!ept) { > + dev_err(dev, "failed to create endpoint\n"); > + err = -ENOMEM; > + goto out; > + } > + > + rpdev->ept = ept; > + rpdev->src = ept->addr; > + > + err = rpdrv->probe(rpdev); > + if (err) { > + dev_err(dev, "%s: failed: %d\n", __func__, err); > + rpmsg_destroy_ept(ept); > + goto out; > + } > + > + if (rpdev->announce_create) > + err = rpdev->announce_create(rpdev); > +out: > + return err; > +} > + > +static int rpmsg_dev_remove(struct device *dev) > +{ > + struct rpmsg_device *rpdev = to_rpmsg_device(dev); > + struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver); > + int err = 0; > + > + if (rpdev->announce_destroy) > + err = rpdev->announce_destroy(rpdev); > + > + rpdrv->remove(rpdev); > + > + rpmsg_destroy_ept(rpdev->ept); > + > + return err; > +} > + > +static struct bus_type rpmsg_bus = { > + .name = "rpmsg", > + .match = rpmsg_dev_match, > + .dev_attrs = rpmsg_dev_attrs, > + .uevent = rpmsg_uevent, > + .probe = rpmsg_dev_probe, > + .remove = rpmsg_dev_remove, > +}; > + > +static void rpmsg_release_device(struct device *dev) > +{ > + struct rpmsg_device *rpdev = to_rpmsg_device(dev); > + > + kfree(rpdev); > +} > + > +int rpmsg_register_device(struct rpmsg_device *rpdev) > +{ > + struct device *dev = &rpdev->dev; > + int ret; > + > + dev_set_name(&rpdev->dev, "%s:%s", > + dev_name(dev->parent), rpdev->id.name); > + > + rpdev->dev.bus = &rpmsg_bus; > + rpdev->dev.release = rpmsg_release_device; > + > + ret = device_register(&rpdev->dev); > + if (ret) { > + dev_err(dev, "device_register failed: %d\n", ret); > + put_device(&rpdev->dev); > + } > + > + return ret; > +} > +EXPORT_SYMBOL(rpmsg_register_device); > + > +/* > + * match an rpmsg channel with a channel info struct. > + * this is used to make sure we're not creating rpmsg devices for channels > + * that already exist. > + */ > +static int rpmsg_channel_match(struct device *dev, void *data) > +{ > + struct rpmsg_channel_info *chinfo = data; > + struct rpmsg_device *rpdev = to_rpmsg_device(dev); > + > + if (chinfo->src != RPMSG_ADDR_ANY && chinfo->src != rpdev->src) > + return 0; > + > + if (chinfo->dst != RPMSG_ADDR_ANY && chinfo->dst != rpdev->dst) > + return 0; > + > + if (strncmp(chinfo->name, rpdev->id.name, RPMSG_NAME_SIZE)) > + return 0; > + > + /* found a match ! */ > + return 1; > +} > + > +struct device *rpmsg_find_device(struct device *parent, > + struct rpmsg_channel_info *chinfo) > +{ > + return device_find_child(parent, chinfo, rpmsg_channel_match); > + > +} > +EXPORT_SYMBOL(rpmsg_find_device); > + > +/* > + * find an existing channel using its name + address properties, > + * and destroy it > + */ > +int rpmsg_unregister_device(struct device *parent, > + struct rpmsg_channel_info *chinfo) > +{ > + struct device *dev; > + > + dev = rpmsg_find_device(parent, chinfo); > + if (!dev) > + return -EINVAL; > + > + device_unregister(dev); > + > + put_device(dev); > + > + return 0; > +} > +EXPORT_SYMBOL(rpmsg_unregister_device); > + > +/** > + * __register_rpmsg_driver() - register an rpmsg driver with the rpmsg bus > + * @rpdrv: pointer to a struct rpmsg_driver > + * @owner: owning module/driver > + * > + * Returns 0 on success, and an appropriate error value on failure. > + */ > +int __register_rpmsg_driver(struct rpmsg_driver *rpdrv, struct module > *owner) > +{ > + rpdrv->drv.bus = &rpmsg_bus; > + rpdrv->drv.owner = owner; > + return driver_register(&rpdrv->drv); > +} > +EXPORT_SYMBOL(__register_rpmsg_driver); > + > +/** > + * unregister_rpmsg_driver() - unregister an rpmsg driver from the rpmsg > bus > + * @rpdrv: pointer to a struct rpmsg_driver > + * > + * Returns 0 on success, and an appropriate error value on failure. > + */ > +void unregister_rpmsg_driver(struct rpmsg_driver *rpdrv) > +{ > + driver_unregister(&rpdrv->drv); > +} > +EXPORT_SYMBOL(unregister_rpmsg_driver); > + > + > +static int __init rpmsg_init(void) > +{ > + int ret; > + > + ret = bus_register(&rpmsg_bus); > + if (ret) > + pr_err("failed to register rpmsg bus: %d\n", ret); > + > + return ret; > +} > +postcore_initcall(rpmsg_init); > + > +static void __exit rpmsg_fini(void) > +{ > + bus_unregister(&rpmsg_bus); > +} > +module_exit(rpmsg_fini); > + > +MODULE_DESCRIPTION("remote processor messaging bus"); > +MODULE_LICENSE("GPL v2"); > diff --git a/drivers/rpmsg/rpmsg_internal.h > b/drivers/rpmsg/rpmsg_internal.h > new file mode 100644 > index 000000000000..fa91075c7956 > --- /dev/null > +++ b/drivers/rpmsg/rpmsg_internal.h > @@ -0,0 +1,45 @@ > +/* > + * Virtio-based remote processor messaging bus > + * > + * Copyright (C) 2011 Texas Instruments, Inc. > + * Copyright (C) 2011 Google, Inc. > + * > + * Ohad Ben-Cohen <ohad@wizery.com> > + * Brian Swetland <swetland@google.com> > + * > + * This software is licensed under the terms of the GNU General Public > + * License version 2, as published by the Free Software Foundation, and > + * may be copied, distributed, and modified under those terms. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + */ > + > +#ifndef __RPMSG_INTERNAL_H__ > +#define __RPMSG_INTERNAL_H__ > + > +#define to_rpmsg_device(d) container_of(d, struct rpmsg_device, dev) > +#define to_rpmsg_driver(d) container_of(d, struct rpmsg_driver, drv) > + > +/** > + * struct rpmsg_channel_info - internal channel info representation > + * @name: name of service > + * @src: local address > + * @dst: destination address > + */ > +struct rpmsg_channel_info { > + char name[RPMSG_NAME_SIZE]; > + u32 src; > + u32 dst; > +}; > + > +int rpmsg_register_device(struct rpmsg_device *rpdev); > +int rpmsg_unregister_device(struct device *parent, > + struct rpmsg_channel_info *chinfo); > + > +struct device *rpmsg_find_device(struct device *parent, > + struct rpmsg_channel_info *chinfo); > + > +#endif > diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c > b/drivers/rpmsg/virtio_rpmsg_bus.c > index 5cadb75a225d..779c54304774 100644 > --- a/drivers/rpmsg/virtio_rpmsg_bus.c > +++ b/drivers/rpmsg/virtio_rpmsg_bus.c > @@ -35,6 +35,8 @@ > #include <linux/mutex.h> > #include <linux/of_device.h> > > +#include "rpmsg_internal.h" > + > /** > * struct virtproc_info - virtual remote processor state > * @vdev: the virtio device > @@ -73,21 +75,6 @@ struct virtproc_info { > struct rpmsg_endpoint *ns_ept; > }; > > -/** > - * struct rpmsg_channel_info - internal channel info representation > - * @name: name of service > - * @src: local address > - * @dst: destination address > - */ > -struct rpmsg_channel_info { > - char name[RPMSG_NAME_SIZE]; > - u32 src; > - u32 dst; > -}; > - > -#define to_rpmsg_device(d) container_of(d, struct rpmsg_device, dev) > -#define to_rpmsg_driver(d) container_of(d, struct rpmsg_driver, drv) > - > /* > * We're allocating buffers of 512 bytes each for communications. The > * number of buffers will be computed from the number of buffers > supported > @@ -129,72 +116,6 @@ static int virtio_rpmsg_trysendto(struct > rpmsg_endpoint *ept, void *data, > int len, u32 dst); > static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 > src, > u32 dst, void *data, int len); > -static int rpmsg_register_device(struct rpmsg_device *rpdev); > - > -/* sysfs show configuration fields */ > -#define rpmsg_show_attr(field, path, format_string) \ > -static ssize_t \ > -field##_show(struct device *dev, \ > - struct device_attribute *attr, char *buf) \ > -{ \ > - struct rpmsg_device *rpdev = to_rpmsg_device(dev); \ > - \ > - return sprintf(buf, format_string, rpdev->path); \ > -} > - > -/* for more info, see Documentation/ABI/testing/sysfs-bus-rpmsg */ > -rpmsg_show_attr(name, id.name, "%s\n"); > -rpmsg_show_attr(src, src, "0x%x\n"); > -rpmsg_show_attr(dst, dst, "0x%x\n"); > -rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n"); > - > -static ssize_t modalias_show(struct device *dev, > - struct device_attribute *attr, char *buf) > -{ > - struct rpmsg_device *rpdev = to_rpmsg_device(dev); > - > - return sprintf(buf, RPMSG_DEVICE_MODALIAS_FMT "\n", rpdev- > >id.name); > -} > - > -static struct device_attribute rpmsg_dev_attrs[] = { > - __ATTR_RO(name), > - __ATTR_RO(modalias), > - __ATTR_RO(dst), > - __ATTR_RO(src), > - __ATTR_RO(announce), > - __ATTR_NULL > -}; > - > -/* rpmsg devices and drivers are matched using the service name */ > -static inline int rpmsg_id_match(const struct rpmsg_device *rpdev, > - const struct rpmsg_device_id *id) > -{ > - return strncmp(id->name, rpdev->id.name, RPMSG_NAME_SIZE) == > 0; > -} > - > -/* match rpmsg channel and rpmsg driver */ > -static int rpmsg_dev_match(struct device *dev, struct device_driver *drv) > -{ > - struct rpmsg_device *rpdev = to_rpmsg_device(dev); > - struct rpmsg_driver *rpdrv = to_rpmsg_driver(drv); > - const struct rpmsg_device_id *ids = rpdrv->id_table; > - unsigned int i; > - > - if (ids) > - for (i = 0; ids[i].name[0]; i++) > - if (rpmsg_id_match(rpdev, &ids[i])) > - return 1; > - > - return of_driver_match_device(dev, drv); > -} > - > -static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env) > -{ > - struct rpmsg_device *rpdev = to_rpmsg_device(dev); > - > - return add_uevent_var(env, "MODALIAS=" > RPMSG_DEVICE_MODALIAS_FMT, > - rpdev->id.name); > -} > > /** > * __ept_release() - deallocate an rpmsg endpoint > @@ -266,53 +187,6 @@ free_ept: > return NULL; > } > > -/** > - * rpmsg_create_ept() - create a new rpmsg_endpoint > - * @rpdev: rpmsg channel device > - * @cb: rx callback handler > - * @priv: private data for the driver's use > - * @addr: local rpmsg address to bind with @cb > - * > - * Every rpmsg address in the system is bound to an rx callback (so when > - * inbound messages arrive, they are dispatched by the rpmsg bus using the > - * appropriate callback handler) by means of an rpmsg_endpoint struct. > - * > - * This function allows drivers to create such an endpoint, and by that, > - * bind a callback, and possibly some private data too, to an rpmsg address > - * (either one that is known in advance, or one that will be dynamically > - * assigned for them). > - * > - * Simple rpmsg drivers need not call rpmsg_create_ept, because an > endpoint > - * is already created for them when they are probed by the rpmsg bus > - * (using the rx callback provided when they registered to the rpmsg bus). > - * > - * So things should just work for simple drivers: they already have an > - * endpoint, their rx callback is bound to their rpmsg address, and when > - * relevant inbound messages arrive (i.e. messages which their dst address > - * equals to the src address of their rpmsg channel), the driver's handler > - * is invoked to process it. > - * > - * That said, more complicated drivers might do need to allocate > - * additional rpmsg addresses, and bind them to different rx callbacks. > - * To accomplish that, those drivers need to call this function. > - * > - * Drivers should provide their @rpdev channel (so the new endpoint would > belong > - * to the same remote processor their channel belongs to), an rx callback > - * function, an optional private data (which is provided back when the > - * rx callback is invoked), and an address they want to bind with the > - * callback. If @addr is RPMSG_ADDR_ANY, then rpmsg_create_ept will > - * dynamically assign them an available rpmsg address (drivers should have > - * a very good reason why not to always use RPMSG_ADDR_ANY here). > - * > - * Returns a pointer to the endpoint on success, or NULL on error. > - */ > -struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev, > - rpmsg_rx_cb_t cb, void *priv, u32 > addr) > -{ > - return rpdev->create_ept(rpdev, cb, priv, addr); > -} > -EXPORT_SYMBOL(rpmsg_create_ept); > - > static struct rpmsg_endpoint *virtio_rpmsg_create_ept(struct > rpmsg_device *rpdev, > rpmsg_rx_cb_t cb, > void *priv, u32 addr) > @@ -346,62 +220,11 @@ __rpmsg_destroy_ept(struct virtproc_info *vrp, > struct rpmsg_endpoint *ept) > kref_put(&ept->refcount, __ept_release); > } > > -/** > - * rpmsg_destroy_ept() - destroy an existing rpmsg endpoint > - * @ept: endpoing to destroy > - * > - * Should be used by drivers to destroy an rpmsg endpoint previously > - * created with rpmsg_create_ept(). > - */ > -void rpmsg_destroy_ept(struct rpmsg_endpoint *ept) > -{ > - ept->rpdev->destroy_ept(ept); > -} > -EXPORT_SYMBOL(rpmsg_destroy_ept); > - > static void virtio_rpmsg_destroy_ept(struct rpmsg_endpoint *ept) > { > __rpmsg_destroy_ept(ept->rpdev->vrp, ept); > } > > -/* > - * when an rpmsg driver is probed with a channel, we seamlessly create > - * it an endpoint, binding its rx callback to a unique local rpmsg > - * address. > - * > - * if we need to, we also announce about this channel to the remote > - * processor (needed in case the driver is exposing an rpmsg service). > - */ > -static int rpmsg_dev_probe(struct device *dev) > -{ > - struct rpmsg_device *rpdev = to_rpmsg_device(dev); > - struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver); > - struct rpmsg_endpoint *ept; > - int err; > - > - ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, rpdev->src); > - if (!ept) { > - dev_err(dev, "failed to create endpoint\n"); > - err = -ENOMEM; > - goto out; > - } > - > - rpdev->ept = ept; > - rpdev->src = ept->addr; > - > - err = rpdrv->probe(rpdev); > - if (err) { > - dev_err(dev, "%s: failed: %d\n", __func__, err); > - rpmsg_destroy_ept(ept); > - goto out; > - } > - > - if (rpdev->announce_create) > - err = rpdev->announce_create(rpdev); > -out: > - return err; > -} > - > static int virtio_rpmsg_announce_create(struct rpmsg_device *rpdev) > { > struct virtproc_info *vrp = rpdev->vrp; > @@ -448,88 +271,6 @@ static int virtio_rpmsg_announce_destroy(struct > rpmsg_device *rpdev) > return err; > } > > -static int rpmsg_dev_remove(struct device *dev) > -{ > - struct rpmsg_device *rpdev = to_rpmsg_device(dev); > - struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver); > - int err = 0; > - > - if (rpdev->announce_destroy) > - err = rpdev->announce_destroy(rpdev); > - > - rpdrv->remove(rpdev); > - > - rpmsg_destroy_ept(rpdev->ept); > - > - return err; > -} > - > -static struct bus_type rpmsg_bus = { > - .name = "rpmsg", > - .match = rpmsg_dev_match, > - .dev_attrs = rpmsg_dev_attrs, > - .uevent = rpmsg_uevent, > - .probe = rpmsg_dev_probe, > - .remove = rpmsg_dev_remove, > -}; > - > -/** > - * __register_rpmsg_driver() - register an rpmsg driver with the rpmsg bus > - * @rpdrv: pointer to a struct rpmsg_driver > - * @owner: owning module/driver > - * > - * Returns 0 on success, and an appropriate error value on failure. > - */ > -int __register_rpmsg_driver(struct rpmsg_driver *rpdrv, struct module > *owner) > -{ > - rpdrv->drv.bus = &rpmsg_bus; > - rpdrv->drv.owner = owner; > - return driver_register(&rpdrv->drv); > -} > -EXPORT_SYMBOL(__register_rpmsg_driver); > - > -/** > - * unregister_rpmsg_driver() - unregister an rpmsg driver from the rpmsg > bus > - * @rpdrv: pointer to a struct rpmsg_driver > - * > - * Returns 0 on success, and an appropriate error value on failure. > - */ > -void unregister_rpmsg_driver(struct rpmsg_driver *rpdrv) > -{ > - driver_unregister(&rpdrv->drv); > -} > -EXPORT_SYMBOL(unregister_rpmsg_driver); > - > -static void rpmsg_release_device(struct device *dev) > -{ > - struct rpmsg_device *rpdev = to_rpmsg_device(dev); > - > - kfree(rpdev); > -} > - > -/* > - * match an rpmsg channel with a channel info struct. > - * this is used to make sure we're not creating rpmsg devices for channels > - * that already exist. > - */ > -static int rpmsg_device_match(struct device *dev, void *data) > -{ > - struct rpmsg_channel_info *chinfo = data; > - struct rpmsg_device *rpdev = to_rpmsg_device(dev); > - > - if (chinfo->src != RPMSG_ADDR_ANY && chinfo->src != rpdev->src) > - return 0; > - > - if (chinfo->dst != RPMSG_ADDR_ANY && chinfo->dst != rpdev->dst) > - return 0; > - > - if (strncmp(chinfo->name, rpdev->id.name, RPMSG_NAME_SIZE)) > - return 0; > - > - /* found a match ! */ > - return 1; > -} > - > static const struct rpmsg_device virtio_rpmsg_ops = { > .create_ept = virtio_rpmsg_create_ept, > .destroy_ept = virtio_rpmsg_destroy_ept, > @@ -556,7 +297,7 @@ static struct rpmsg_device > *rpmsg_create_channel(struct virtproc_info *vrp, > int ret; > > /* make sure a similar channel doesn't already exist */ > - tmp = device_find_child(dev, chinfo, rpmsg_device_match); > + tmp = rpmsg_find_device(dev, chinfo); > if (tmp) { > /* decrement the matched device's refcount back */ > put_device(tmp); > @@ -592,47 +333,6 @@ static struct rpmsg_device > *rpmsg_create_channel(struct virtproc_info *vrp, > return rpdev; > } > > -static int rpmsg_register_device(struct rpmsg_device *rpdev) > -{ > - struct device *dev = &rpdev->dev; > - int ret; > - > - dev_set_name(&rpdev->dev, "%s:%s", > - dev_name(dev->parent), rpdev->id.name); > - > - rpdev->dev.bus = &rpmsg_bus; > - rpdev->dev.release = rpmsg_release_device; > - > - ret = device_register(&rpdev->dev); > - if (ret) { > - dev_err(dev, "device_register failed: %d\n", ret); > - put_device(&rpdev->dev); > - } > - > - return ret; > -} > - > -/* > - * find an existing channel using its name + address properties, > - * and destroy it > - */ > -static int rpmsg_destroy_channel(struct virtproc_info *vrp, > - struct rpmsg_channel_info *chinfo) > -{ > - struct virtio_device *vdev = vrp->vdev; > - struct device *dev; > - > - dev = device_find_child(&vdev->dev, chinfo, rpmsg_device_match); > - if (!dev) > - return -EINVAL; > - > - device_unregister(dev); > - > - put_device(dev); > - > - return 0; > -} > - > /* super simple buffer "allocator" that is just enough for now */ > static void *get_a_tx_buf(struct virtproc_info *vrp) > { > @@ -844,31 +544,6 @@ out: > return err; > } > > -/** > - * rpmsg_send() - send a message across to the remote processor > - * @ept: the rpmsg endpoint > - * @data: payload of message > - * @len: length of payload > - * > - * This function sends @data of length @len on the @ept endpoint. > - * The message will be sent to the remote processor which the @ept > - * endpoint belongs to, using @ept's address and its associated rpmsg > - * device destination addresses. > - * In case there are no TX buffers available, the function will block until > - * one becomes available, or a timeout of 15 seconds elapses. When the > latter > - * happens, -ERESTARTSYS is returned. > - * > - * Can only be called from process context (for now). > - * > - * Returns 0 on success and an appropriate error value on failure. > - */ > -int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len) > -{ > - struct rpmsg_device *rpdev = ept->rpdev; > - > - return rpdev->send(ept, data, len); > -} > - > static int virtio_rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len) > { > struct rpmsg_device *rpdev = ept->rpdev; > @@ -877,32 +552,6 @@ static int virtio_rpmsg_send(struct rpmsg_endpoint > *ept, void *data, int len) > return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true); > } > > -/** > - * rpmsg_sendto() - send a message across to the remote processor, specify > dst > - * @ept: the rpmsg endpoint > - * @data: payload of message > - * @len: length of payload > - * @dst: destination address > - * > - * This function sends @data of length @len to the remote @dst address. > - * The message will be sent to the remote processor which the @ept > - * endpoint belongs to, using @ept's address as source. > - * In case there are no TX buffers available, the function will block until > - * one becomes available, or a timeout of 15 seconds elapses. When the > latter > - * happens, -ERESTARTSYS is returned. > - * > - * Can only be called from process context (for now). > - * > - * Returns 0 on success and an appropriate error value on failure. > - */ > -int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst) > -{ > - struct rpmsg_device *rpdev = ept->rpdev; > - > - return rpdev->sendto(ept, data, len, dst); > -} > -EXPORT_SYMBOL(rpmsg_sendto); > - > static int virtio_rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int > len, > u32 dst) > { > @@ -912,35 +561,6 @@ static int virtio_rpmsg_sendto(struct > rpmsg_endpoint *ept, void *data, int len, > return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true); > } > > -/** > - * rpmsg_send_offchannel() - send a message using explicit src/dst > addresses > - * @ept: the rpmsg endpoint > - * @src: source address > - * @dst: destination address > - * @data: payload of message > - * @len: length of payload > - * > - * This function sends @data of length @len to the remote @dst address, > - * and uses @src as the source address. > - * The message will be sent to the remote processor which the @ept > - * endpoint belongs to. > - * In case there are no TX buffers available, the function will block until > - * one becomes available, or a timeout of 15 seconds elapses. When the > latter > - * happens, -ERESTARTSYS is returned. > - * > - * Can only be called from process context (for now). > - * > - * Returns 0 on success and an appropriate error value on failure. > - */ > -int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, > - void *data, int len) > -{ > - struct rpmsg_device *rpdev = ept->rpdev; > - > - return rpdev->send_offchannel(ept, src, dst, data, len); > -} > -EXPORT_SYMBOL(rpmsg_send_offchannel); > - > static int virtio_rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 > src, > u32 dst, void *data, int len) > { > @@ -949,31 +569,6 @@ static int virtio_rpmsg_send_offchannel(struct > rpmsg_endpoint *ept, u32 src, > return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true); > } > > -/** > - * rpmsg_send() - send a message across to the remote processor > - * @ept: the rpmsg endpoint > - * @data: payload of message > - * @len: length of payload > - * > - * This function sends @data of length @len on the @ept endpoint. > - * The message will be sent to the remote processor which the @ept > - * endpoint belongs to, using @ept's addres as source and its associated > - * rpdev's address as destination. > - * In case there are no TX buffers available, the function will immediately > - * return -ENOMEM without waiting until one becomes available. > - * > - * Can only be called from process context (for now). > - * > - * Returns 0 on success and an appropriate error value on failure. > - */ > -int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len) > -{ > - struct rpmsg_device *rpdev = ept->rpdev; > - > - return rpdev->trysend(ept, data, len); > -} > -EXPORT_SYMBOL(rpmsg_trysend); > - > static int virtio_rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int > len) > { > struct rpmsg_device *rpdev = ept->rpdev; > @@ -982,31 +577,6 @@ static int virtio_rpmsg_trysend(struct > rpmsg_endpoint *ept, void *data, int len) > return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false); > } > > -/** > - * rpmsg_sendto() - send a message across to the remote processor, specify > dst > - * @ept: the rpmsg endpoint > - * @data: payload of message > - * @len: length of payload > - * @dst: destination address > - * > - * This function sends @data of length @len to the remote @dst address. > - * The message will be sent to the remote processor which the @ept > - * endpoint belongs to, using @ept's address as source. > - * In case there are no TX buffers available, the function will immediately > - * return -ENOMEM without waiting until one becomes available. > - * > - * Can only be called from process context (for now). > - * > - * Returns 0 on success and an appropriate error value on failure. > - */ > -int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 > dst) > -{ > - struct rpmsg_device *rpdev = ept->rpdev; > - > - return rpdev->trysendto(ept, data, len, dst); > -} > -EXPORT_SYMBOL(rpmsg_trysendto); > - > static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, > int len, u32 dst) > { > @@ -1016,34 +586,6 @@ static int virtio_rpmsg_trysendto(struct > rpmsg_endpoint *ept, void *data, > return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false); > } > > -/** > - * rpmsg_send_offchannel() - send a message using explicit src/dst > addresses > - * @ept: the rpmsg endpoint > - * @src: source address > - * @dst: destination address > - * @data: payload of message > - * @len: length of payload > - * > - * This function sends @data of length @len to the remote @dst address, > - * and uses @src as the source address. > - * The message will be sent to the remote processor which the @ept > - * endpoint belongs to. > - * In case there are no TX buffers available, the function will immediately > - * return -ENOMEM without waiting until one becomes available. > - * > - * Can only be called from process context (for now). > - * > - * Returns 0 on success and an appropriate error value on failure. > - */ > -int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 > dst, > - void *data, int len) > -{ > - struct rpmsg_device *rpdev = ept->rpdev; > - > - return rpdev->trysend_offchannel(ept, src, dst, data, len); > -} > -EXPORT_SYMBOL(rpmsg_trysend_offchannel); > - > static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 > src, > u32 dst, void *data, int len) > { > @@ -1208,7 +750,7 @@ static void rpmsg_ns_cb(struct rpmsg_device > *rpdev, void *data, int len, > chinfo.dst = msg->addr; > > if (msg->flags & RPMSG_NS_DESTROY) { > - ret = rpmsg_destroy_channel(vrp, &chinfo); > + ret = rpmsg_unregister_device(&vrp->vdev->dev, &chinfo); > if (ret) > dev_err(dev, "rpmsg_destroy_channel failed: %d\n", > ret); > } else { > @@ -1393,17 +935,9 @@ static int __init rpmsg_init(void) > { > int ret; > > - ret = bus_register(&rpmsg_bus); > - if (ret) { > - pr_err("failed to register rpmsg bus: %d\n", ret); > - return ret; > - } > - > ret = register_virtio_driver(&virtio_ipc_driver); > - if (ret) { > + if (ret) > pr_err("failed to register virtio driver: %d\n", ret); > - bus_unregister(&rpmsg_bus); > - } > > return ret; > } > @@ -1412,7 +946,6 @@ subsys_initcall(rpmsg_init); > static void __exit rpmsg_fini(void) > { > unregister_virtio_driver(&virtio_ipc_driver); > - bus_unregister(&rpmsg_bus); > } > module_exit(rpmsg_fini); > > -- > 2.5.0 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-remoteproc" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html
On Thu 18 Aug 04:59 PDT 2016, Loic PALLARDY wrote: > > > > -----Original Message----- > > From: linux-remoteproc-owner@vger.kernel.org [mailto:linux-remoteproc- > > owner@vger.kernel.org] On Behalf Of Bjorn Andersson > > Sent: Tuesday, August 16, 2016 2:17 AM > > To: Ohad Ben-Cohen <ohad@wizery.com>; Bjorn Andersson > > <bjorn.andersson@linaro.org> > > Cc: linux-remoteproc@vger.kernel.org; linux-arm-msm@vger.kernel.org; > > linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org; > > Sricharan R <sricharan@codeaurora.org> > > Subject: [PATCH 08/14] rpmsg: Split rpmsg core and virtio backend > > > > Extract the generic rpmsg core functionality from the virtio rpmsg > > implementation, splitting the implementation in a rpmsg core and a > > virtio backend. > > > > Based on initial work by Sricharan R <sricharan@codeaurora.org> > > > > Cc: Sricharan R <sricharan@codeaurora.org> > > Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org> > > --- > > drivers/rpmsg/Kconfig | 4 + > > drivers/rpmsg/Makefile | 3 +- > > drivers/rpmsg/rpmsg_core.c | 513 > > +++++++++++++++++++++++++++++++++++++++ > > drivers/rpmsg/rpmsg_internal.h | 45 ++++ > > drivers/rpmsg/virtio_rpmsg_bus.c | 477 +----------------------------------- > Hi Bjorn, > > Could you please regenerate the patch with option -M (of git > formatpatch) to detect file renames. It will provide better > visibility of differences between virtio_rpmsg_bus.c and rpmsg_core.c. I believe this is with -M, but as I only extracted part of the file it did not detect it as a rename. I will see if I can figure something out for v2. Perhaps if I split the move in more than one commit it will be easier to follow; like take the device management in one chunk and the rpmsg_send() functions in one would reduce the size of the two patches quite a bit. > > > 5 files changed, 569 insertions(+), 473 deletions(-) > > create mode 100644 drivers/rpmsg/rpmsg_core.c > > create mode 100644 drivers/rpmsg/rpmsg_internal.h > > > > diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig > > index 69a219387582..40614be88c97 100644 > > --- a/drivers/rpmsg/Kconfig > > +++ b/drivers/rpmsg/Kconfig > > @@ -3,6 +3,10 @@ menu "Rpmsg drivers" > > # RPMSG always gets selected by whoever wants it > > config RPMSG > > tristate > > + > > +config RPMSG_VIRTIO > > + tristate > > + select RPMSG > > select VIRTIO > > select VIRTUALIZATION > > > Remoteproc Kconfig should be changed too to select RPMSG_VIRTIO instead of RPMSG. > You're right, forgot to include that. I still think this should be a user selectable option, rather than being tied to particular remoteproc drivers - but let's take that discussion separately. Thanks, Bjorn
diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig index 69a219387582..40614be88c97 100644 --- a/drivers/rpmsg/Kconfig +++ b/drivers/rpmsg/Kconfig @@ -3,6 +3,10 @@ menu "Rpmsg drivers" # RPMSG always gets selected by whoever wants it config RPMSG tristate + +config RPMSG_VIRTIO + tristate + select RPMSG select VIRTIO select VIRTUALIZATION diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile index 7617fcb8259f..383213417a00 100644 --- a/drivers/rpmsg/Makefile +++ b/drivers/rpmsg/Makefile @@ -1 +1,2 @@ -obj-$(CONFIG_RPMSG) += virtio_rpmsg_bus.o +obj-$(CONFIG_RPMSG) += rpmsg_core.o +obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c new file mode 100644 index 000000000000..73bbc5ea5778 --- /dev/null +++ b/drivers/rpmsg/rpmsg_core.c @@ -0,0 +1,513 @@ +/* + * Virtio-based remote processor messaging bus + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Copyright (C) 2011 Google, Inc. + * + * Ohad Ben-Cohen <ohad@wizery.com> + * Brian Swetland <swetland@google.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/virtio.h> +#include <linux/virtio_ids.h> +#include <linux/virtio_config.h> +#include <linux/scatterlist.h> +#include <linux/dma-mapping.h> +#include <linux/slab.h> +#include <linux/idr.h> +#include <linux/jiffies.h> +#include <linux/sched.h> +#include <linux/wait.h> +#include <linux/rpmsg.h> +#include <linux/mutex.h> +#include <linux/of_device.h> + +#include "rpmsg_internal.h" + +/** + * rpmsg_create_ept() - create a new rpmsg_endpoint + * @rpdev: rpmsg channel device + * @cb: rx callback handler + * @priv: private data for the driver's use + * @addr: local rpmsg address to bind with @cb + * + * Every rpmsg address in the system is bound to an rx callback (so when + * inbound messages arrive, they are dispatched by the rpmsg bus using the + * appropriate callback handler) by means of an rpmsg_endpoint struct. + * + * This function allows drivers to create such an endpoint, and by that, + * bind a callback, and possibly some private data too, to an rpmsg address + * (either one that is known in advance, or one that will be dynamically + * assigned for them). + * + * Simple rpmsg drivers need not call rpmsg_create_ept, because an endpoint + * is already created for them when they are probed by the rpmsg bus + * (using the rx callback provided when they registered to the rpmsg bus). + * + * So things should just work for simple drivers: they already have an + * endpoint, their rx callback is bound to their rpmsg address, and when + * relevant inbound messages arrive (i.e. messages which their dst address + * equals to the src address of their rpmsg channel), the driver's handler + * is invoked to process it. + * + * That said, more complicated drivers might do need to allocate + * additional rpmsg addresses, and bind them to different rx callbacks. + * To accomplish that, those drivers need to call this function. + * + * Drivers should provide their @rpdev channel (so the new endpoint would belong + * to the same remote processor their channel belongs to), an rx callback + * function, an optional private data (which is provided back when the + * rx callback is invoked), and an address they want to bind with the + * callback. If @addr is RPMSG_ADDR_ANY, then rpmsg_create_ept will + * dynamically assign them an available rpmsg address (drivers should have + * a very good reason why not to always use RPMSG_ADDR_ANY here). + * + * Returns a pointer to the endpoint on success, or NULL on error. + */ +struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev, + rpmsg_rx_cb_t cb, void *priv, u32 addr) +{ + return rpdev->create_ept(rpdev, cb, priv, addr); +} +EXPORT_SYMBOL(rpmsg_create_ept); + +/** + * rpmsg_destroy_ept() - destroy an existing rpmsg endpoint + * @ept: endpoing to destroy + * + * Should be used by drivers to destroy an rpmsg endpoint previously + * created with rpmsg_create_ept(). + */ +void rpmsg_destroy_ept(struct rpmsg_endpoint *ept) +{ + ept->rpdev->destroy_ept(ept); +} +EXPORT_SYMBOL(rpmsg_destroy_ept); + +/** + * rpmsg_send() - send a message across to the remote processor + * @ept: the rpmsg endpoint + * @data: payload of message + * @len: length of payload + * + * This function sends @data of length @len on the @ept endpoint. + * The message will be sent to the remote processor which the @ept + * endpoint belongs to, using @ept's address and its associated rpmsg + * device destination addresses. + * In case there are no TX buffers available, the function will block until + * one becomes available, or a timeout of 15 seconds elapses. When the latter + * happens, -ERESTARTSYS is returned. + * + * Can only be called from process context (for now). + * + * Returns 0 on success and an appropriate error value on failure. + */ +int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len) +{ + struct rpmsg_device *rpdev = ept->rpdev; + + return rpdev->send(ept, data, len); +} + +/** + * rpmsg_sendto() - send a message across to the remote processor, specify dst + * @ept: the rpmsg endpoint + * @data: payload of message + * @len: length of payload + * @dst: destination address + * + * This function sends @data of length @len to the remote @dst address. + * The message will be sent to the remote processor which the @ept + * endpoint belongs to, using @ept's address as source. + * In case there are no TX buffers available, the function will block until + * one becomes available, or a timeout of 15 seconds elapses. When the latter + * happens, -ERESTARTSYS is returned. + * + * Can only be called from process context (for now). + * + * Returns 0 on success and an appropriate error value on failure. + */ +int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst) +{ + struct rpmsg_device *rpdev = ept->rpdev; + + return rpdev->sendto(ept, data, len, dst); +} +EXPORT_SYMBOL(rpmsg_sendto); + +/** + * rpmsg_send_offchannel() - send a message using explicit src/dst addresses + * @ept: the rpmsg endpoint + * @src: source address + * @dst: destination address + * @data: payload of message + * @len: length of payload + * + * This function sends @data of length @len to the remote @dst address, + * and uses @src as the source address. + * The message will be sent to the remote processor which the @ept + * endpoint belongs to. + * In case there are no TX buffers available, the function will block until + * one becomes available, or a timeout of 15 seconds elapses. When the latter + * happens, -ERESTARTSYS is returned. + * + * Can only be called from process context (for now). + * + * Returns 0 on success and an appropriate error value on failure. + */ +int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, + void *data, int len) +{ + struct rpmsg_device *rpdev = ept->rpdev; + + return rpdev->send_offchannel(ept, src, dst, data, len); +} +EXPORT_SYMBOL(rpmsg_send_offchannel); + +/** + * rpmsg_send() - send a message across to the remote processor + * @ept: the rpmsg endpoint + * @data: payload of message + * @len: length of payload + * + * This function sends @data of length @len on the @ept endpoint. + * The message will be sent to the remote processor which the @ept + * endpoint belongs to, using @ept's address as source and its associated + * rpdev's address as destination. + * In case there are no TX buffers available, the function will immediately + * return -ENOMEM without waiting until one becomes available. + * + * Can only be called from process context (for now). + * + * Returns 0 on success and an appropriate error value on failure. + */ +int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len) +{ + struct rpmsg_device *rpdev = ept->rpdev; + + return rpdev->trysend(ept, data, len); +} +EXPORT_SYMBOL(rpmsg_trysend); + +/** + * rpmsg_sendto() - send a message across to the remote processor, specify dst + * @ept: the rpmsg endpoint + * @data: payload of message + * @len: length of payload + * @dst: destination address + * + * This function sends @data of length @len to the remote @dst address. + * The message will be sent to the remote processor which the @ept + * endpoint belongs to, using @ept's address as source. + * In case there are no TX buffers available, the function will immediately + * return -ENOMEM without waiting until one becomes available. + * + * Can only be called from process context (for now). + * + * Returns 0 on success and an appropriate error value on failure. + */ +int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst) +{ + struct rpmsg_device *rpdev = ept->rpdev; + + return rpdev->trysendto(ept, data, len, dst); +} +EXPORT_SYMBOL(rpmsg_trysendto); + +/** + * rpmsg_send_offchannel() - send a message using explicit src/dst addresses + * @ept: the rpmsg endpoint + * @src: source address + * @dst: destination address + * @data: payload of message + * @len: length of payload + * + * This function sends @data of length @len to the remote @dst address, + * and uses @src as the source address. + * The message will be sent to the remote processor which the @ept + * endpoint belongs to. + * In case there are no TX buffers available, the function will immediately + * return -ENOMEM without waiting until one becomes available. + * + * Can only be called from process context (for now). + * + * Returns 0 on success and an appropriate error value on failure. + */ +int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, + void *data, int len) +{ + struct rpmsg_device *rpdev = ept->rpdev; + + return rpdev->trysend_offchannel(ept, src, dst, data, len); +} +EXPORT_SYMBOL(rpmsg_trysend_offchannel); + +/* sysfs show configuration fields */ +#define rpmsg_show_attr(field, path, format_string) \ +static ssize_t \ +field##_show(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct rpmsg_device *rpdev = to_rpmsg_device(dev); \ + \ + return sprintf(buf, format_string, rpdev->path); \ +} + +/* for more info, see Documentation/ABI/testing/sysfs-bus-rpmsg */ +rpmsg_show_attr(name, id.name, "%s\n"); +rpmsg_show_attr(src, src, "0x%x\n"); +rpmsg_show_attr(dst, dst, "0x%x\n"); +rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n"); + +static ssize_t modalias_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct rpmsg_device *rpdev = to_rpmsg_device(dev); + + return sprintf(buf, RPMSG_DEVICE_MODALIAS_FMT "\n", rpdev->id.name); +} + +static struct device_attribute rpmsg_dev_attrs[] = { + __ATTR_RO(name), + __ATTR_RO(modalias), + __ATTR_RO(dst), + __ATTR_RO(src), + __ATTR_RO(announce), + __ATTR_NULL +}; + +/* rpmsg devices and drivers are matched using the service name */ +static inline int rpmsg_id_match(const struct rpmsg_device *rpdev, + const struct rpmsg_device_id *id) +{ + return strncmp(id->name, rpdev->id.name, RPMSG_NAME_SIZE) == 0; +} + +/* match rpmsg channel and rpmsg driver */ +static int rpmsg_dev_match(struct device *dev, struct device_driver *drv) +{ + struct rpmsg_device *rpdev = to_rpmsg_device(dev); + struct rpmsg_driver *rpdrv = to_rpmsg_driver(drv); + const struct rpmsg_device_id *ids = rpdrv->id_table; + unsigned int i; + + if (ids) + for (i = 0; ids[i].name[0]; i++) + if (rpmsg_id_match(rpdev, &ids[i])) + return 1; + + return of_driver_match_device(dev, drv); +} + +static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct rpmsg_device *rpdev = to_rpmsg_device(dev); + + return add_uevent_var(env, "MODALIAS=" RPMSG_DEVICE_MODALIAS_FMT, + rpdev->id.name); +} + +/* + * when an rpmsg driver is probed with a channel, we seamlessly create + * it an endpoint, binding its rx callback to a unique local rpmsg + * address. + * + * if we need to, we also announce about this channel to the remote + * processor (needed in case the driver is exposing an rpmsg service). + */ +static int rpmsg_dev_probe(struct device *dev) +{ + struct rpmsg_device *rpdev = to_rpmsg_device(dev); + struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver); + struct rpmsg_endpoint *ept; + int err; + + ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, rpdev->src); + if (!ept) { + dev_err(dev, "failed to create endpoint\n"); + err = -ENOMEM; + goto out; + } + + rpdev->ept = ept; + rpdev->src = ept->addr; + + err = rpdrv->probe(rpdev); + if (err) { + dev_err(dev, "%s: failed: %d\n", __func__, err); + rpmsg_destroy_ept(ept); + goto out; + } + + if (rpdev->announce_create) + err = rpdev->announce_create(rpdev); +out: + return err; +} + +static int rpmsg_dev_remove(struct device *dev) +{ + struct rpmsg_device *rpdev = to_rpmsg_device(dev); + struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver); + int err = 0; + + if (rpdev->announce_destroy) + err = rpdev->announce_destroy(rpdev); + + rpdrv->remove(rpdev); + + rpmsg_destroy_ept(rpdev->ept); + + return err; +} + +static struct bus_type rpmsg_bus = { + .name = "rpmsg", + .match = rpmsg_dev_match, + .dev_attrs = rpmsg_dev_attrs, + .uevent = rpmsg_uevent, + .probe = rpmsg_dev_probe, + .remove = rpmsg_dev_remove, +}; + +static void rpmsg_release_device(struct device *dev) +{ + struct rpmsg_device *rpdev = to_rpmsg_device(dev); + + kfree(rpdev); +} + +int rpmsg_register_device(struct rpmsg_device *rpdev) +{ + struct device *dev = &rpdev->dev; + int ret; + + dev_set_name(&rpdev->dev, "%s:%s", + dev_name(dev->parent), rpdev->id.name); + + rpdev->dev.bus = &rpmsg_bus; + rpdev->dev.release = rpmsg_release_device; + + ret = device_register(&rpdev->dev); + if (ret) { + dev_err(dev, "device_register failed: %d\n", ret); + put_device(&rpdev->dev); + } + + return ret; +} +EXPORT_SYMBOL(rpmsg_register_device); + +/* + * match an rpmsg channel with a channel info struct. + * this is used to make sure we're not creating rpmsg devices for channels + * that already exist. + */ +static int rpmsg_channel_match(struct device *dev, void *data) +{ + struct rpmsg_channel_info *chinfo = data; + struct rpmsg_device *rpdev = to_rpmsg_device(dev); + + if (chinfo->src != RPMSG_ADDR_ANY && chinfo->src != rpdev->src) + return 0; + + if (chinfo->dst != RPMSG_ADDR_ANY && chinfo->dst != rpdev->dst) + return 0; + + if (strncmp(chinfo->name, rpdev->id.name, RPMSG_NAME_SIZE)) + return 0; + + /* found a match ! */ + return 1; +} + +struct device *rpmsg_find_device(struct device *parent, + struct rpmsg_channel_info *chinfo) +{ + return device_find_child(parent, chinfo, rpmsg_channel_match); + +} +EXPORT_SYMBOL(rpmsg_find_device); + +/* + * find an existing channel using its name + address properties, + * and destroy it + */ +int rpmsg_unregister_device(struct device *parent, + struct rpmsg_channel_info *chinfo) +{ + struct device *dev; + + dev = rpmsg_find_device(parent, chinfo); + if (!dev) + return -EINVAL; + + device_unregister(dev); + + put_device(dev); + + return 0; +} +EXPORT_SYMBOL(rpmsg_unregister_device); + +/** + * __register_rpmsg_driver() - register an rpmsg driver with the rpmsg bus + * @rpdrv: pointer to a struct rpmsg_driver + * @owner: owning module/driver + * + * Returns 0 on success, and an appropriate error value on failure. + */ +int __register_rpmsg_driver(struct rpmsg_driver *rpdrv, struct module *owner) +{ + rpdrv->drv.bus = &rpmsg_bus; + rpdrv->drv.owner = owner; + return driver_register(&rpdrv->drv); +} +EXPORT_SYMBOL(__register_rpmsg_driver); + +/** + * unregister_rpmsg_driver() - unregister an rpmsg driver from the rpmsg bus + * @rpdrv: pointer to a struct rpmsg_driver + * + * Returns 0 on success, and an appropriate error value on failure. + */ +void unregister_rpmsg_driver(struct rpmsg_driver *rpdrv) +{ + driver_unregister(&rpdrv->drv); +} +EXPORT_SYMBOL(unregister_rpmsg_driver); + + +static int __init rpmsg_init(void) +{ + int ret; + + ret = bus_register(&rpmsg_bus); + if (ret) + pr_err("failed to register rpmsg bus: %d\n", ret); + + return ret; +} +postcore_initcall(rpmsg_init); + +static void __exit rpmsg_fini(void) +{ + bus_unregister(&rpmsg_bus); +} +module_exit(rpmsg_fini); + +MODULE_DESCRIPTION("remote processor messaging bus"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h new file mode 100644 index 000000000000..fa91075c7956 --- /dev/null +++ b/drivers/rpmsg/rpmsg_internal.h @@ -0,0 +1,45 @@ +/* + * Virtio-based remote processor messaging bus + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Copyright (C) 2011 Google, Inc. + * + * Ohad Ben-Cohen <ohad@wizery.com> + * Brian Swetland <swetland@google.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __RPMSG_INTERNAL_H__ +#define __RPMSG_INTERNAL_H__ + +#define to_rpmsg_device(d) container_of(d, struct rpmsg_device, dev) +#define to_rpmsg_driver(d) container_of(d, struct rpmsg_driver, drv) + +/** + * struct rpmsg_channel_info - internal channel info representation + * @name: name of service + * @src: local address + * @dst: destination address + */ +struct rpmsg_channel_info { + char name[RPMSG_NAME_SIZE]; + u32 src; + u32 dst; +}; + +int rpmsg_register_device(struct rpmsg_device *rpdev); +int rpmsg_unregister_device(struct device *parent, + struct rpmsg_channel_info *chinfo); + +struct device *rpmsg_find_device(struct device *parent, + struct rpmsg_channel_info *chinfo); + +#endif diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c index 5cadb75a225d..779c54304774 100644 --- a/drivers/rpmsg/virtio_rpmsg_bus.c +++ b/drivers/rpmsg/virtio_rpmsg_bus.c @@ -35,6 +35,8 @@ #include <linux/mutex.h> #include <linux/of_device.h> +#include "rpmsg_internal.h" + /** * struct virtproc_info - virtual remote processor state * @vdev: the virtio device @@ -73,21 +75,6 @@ struct virtproc_info { struct rpmsg_endpoint *ns_ept; }; -/** - * struct rpmsg_channel_info - internal channel info representation - * @name: name of service - * @src: local address - * @dst: destination address - */ -struct rpmsg_channel_info { - char name[RPMSG_NAME_SIZE]; - u32 src; - u32 dst; -}; - -#define to_rpmsg_device(d) container_of(d, struct rpmsg_device, dev) -#define to_rpmsg_driver(d) container_of(d, struct rpmsg_driver, drv) - /* * We're allocating buffers of 512 bytes each for communications. The * number of buffers will be computed from the number of buffers supported @@ -129,72 +116,6 @@ static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst); static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, void *data, int len); -static int rpmsg_register_device(struct rpmsg_device *rpdev); - -/* sysfs show configuration fields */ -#define rpmsg_show_attr(field, path, format_string) \ -static ssize_t \ -field##_show(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct rpmsg_device *rpdev = to_rpmsg_device(dev); \ - \ - return sprintf(buf, format_string, rpdev->path); \ -} - -/* for more info, see Documentation/ABI/testing/sysfs-bus-rpmsg */ -rpmsg_show_attr(name, id.name, "%s\n"); -rpmsg_show_attr(src, src, "0x%x\n"); -rpmsg_show_attr(dst, dst, "0x%x\n"); -rpmsg_show_attr(announce, announce ? "true" : "false", "%s\n"); - -static ssize_t modalias_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct rpmsg_device *rpdev = to_rpmsg_device(dev); - - return sprintf(buf, RPMSG_DEVICE_MODALIAS_FMT "\n", rpdev->id.name); -} - -static struct device_attribute rpmsg_dev_attrs[] = { - __ATTR_RO(name), - __ATTR_RO(modalias), - __ATTR_RO(dst), - __ATTR_RO(src), - __ATTR_RO(announce), - __ATTR_NULL -}; - -/* rpmsg devices and drivers are matched using the service name */ -static inline int rpmsg_id_match(const struct rpmsg_device *rpdev, - const struct rpmsg_device_id *id) -{ - return strncmp(id->name, rpdev->id.name, RPMSG_NAME_SIZE) == 0; -} - -/* match rpmsg channel and rpmsg driver */ -static int rpmsg_dev_match(struct device *dev, struct device_driver *drv) -{ - struct rpmsg_device *rpdev = to_rpmsg_device(dev); - struct rpmsg_driver *rpdrv = to_rpmsg_driver(drv); - const struct rpmsg_device_id *ids = rpdrv->id_table; - unsigned int i; - - if (ids) - for (i = 0; ids[i].name[0]; i++) - if (rpmsg_id_match(rpdev, &ids[i])) - return 1; - - return of_driver_match_device(dev, drv); -} - -static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct rpmsg_device *rpdev = to_rpmsg_device(dev); - - return add_uevent_var(env, "MODALIAS=" RPMSG_DEVICE_MODALIAS_FMT, - rpdev->id.name); -} /** * __ept_release() - deallocate an rpmsg endpoint @@ -266,53 +187,6 @@ free_ept: return NULL; } -/** - * rpmsg_create_ept() - create a new rpmsg_endpoint - * @rpdev: rpmsg channel device - * @cb: rx callback handler - * @priv: private data for the driver's use - * @addr: local rpmsg address to bind with @cb - * - * Every rpmsg address in the system is bound to an rx callback (so when - * inbound messages arrive, they are dispatched by the rpmsg bus using the - * appropriate callback handler) by means of an rpmsg_endpoint struct. - * - * This function allows drivers to create such an endpoint, and by that, - * bind a callback, and possibly some private data too, to an rpmsg address - * (either one that is known in advance, or one that will be dynamically - * assigned for them). - * - * Simple rpmsg drivers need not call rpmsg_create_ept, because an endpoint - * is already created for them when they are probed by the rpmsg bus - * (using the rx callback provided when they registered to the rpmsg bus). - * - * So things should just work for simple drivers: they already have an - * endpoint, their rx callback is bound to their rpmsg address, and when - * relevant inbound messages arrive (i.e. messages which their dst address - * equals to the src address of their rpmsg channel), the driver's handler - * is invoked to process it. - * - * That said, more complicated drivers might do need to allocate - * additional rpmsg addresses, and bind them to different rx callbacks. - * To accomplish that, those drivers need to call this function. - * - * Drivers should provide their @rpdev channel (so the new endpoint would belong - * to the same remote processor their channel belongs to), an rx callback - * function, an optional private data (which is provided back when the - * rx callback is invoked), and an address they want to bind with the - * callback. If @addr is RPMSG_ADDR_ANY, then rpmsg_create_ept will - * dynamically assign them an available rpmsg address (drivers should have - * a very good reason why not to always use RPMSG_ADDR_ANY here). - * - * Returns a pointer to the endpoint on success, or NULL on error. - */ -struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev, - rpmsg_rx_cb_t cb, void *priv, u32 addr) -{ - return rpdev->create_ept(rpdev, cb, priv, addr); -} -EXPORT_SYMBOL(rpmsg_create_ept); - static struct rpmsg_endpoint *virtio_rpmsg_create_ept(struct rpmsg_device *rpdev, rpmsg_rx_cb_t cb, void *priv, u32 addr) @@ -346,62 +220,11 @@ __rpmsg_destroy_ept(struct virtproc_info *vrp, struct rpmsg_endpoint *ept) kref_put(&ept->refcount, __ept_release); } -/** - * rpmsg_destroy_ept() - destroy an existing rpmsg endpoint - * @ept: endpoing to destroy - * - * Should be used by drivers to destroy an rpmsg endpoint previously - * created with rpmsg_create_ept(). - */ -void rpmsg_destroy_ept(struct rpmsg_endpoint *ept) -{ - ept->rpdev->destroy_ept(ept); -} -EXPORT_SYMBOL(rpmsg_destroy_ept); - static void virtio_rpmsg_destroy_ept(struct rpmsg_endpoint *ept) { __rpmsg_destroy_ept(ept->rpdev->vrp, ept); } -/* - * when an rpmsg driver is probed with a channel, we seamlessly create - * it an endpoint, binding its rx callback to a unique local rpmsg - * address. - * - * if we need to, we also announce about this channel to the remote - * processor (needed in case the driver is exposing an rpmsg service). - */ -static int rpmsg_dev_probe(struct device *dev) -{ - struct rpmsg_device *rpdev = to_rpmsg_device(dev); - struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver); - struct rpmsg_endpoint *ept; - int err; - - ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, rpdev->src); - if (!ept) { - dev_err(dev, "failed to create endpoint\n"); - err = -ENOMEM; - goto out; - } - - rpdev->ept = ept; - rpdev->src = ept->addr; - - err = rpdrv->probe(rpdev); - if (err) { - dev_err(dev, "%s: failed: %d\n", __func__, err); - rpmsg_destroy_ept(ept); - goto out; - } - - if (rpdev->announce_create) - err = rpdev->announce_create(rpdev); -out: - return err; -} - static int virtio_rpmsg_announce_create(struct rpmsg_device *rpdev) { struct virtproc_info *vrp = rpdev->vrp; @@ -448,88 +271,6 @@ static int virtio_rpmsg_announce_destroy(struct rpmsg_device *rpdev) return err; } -static int rpmsg_dev_remove(struct device *dev) -{ - struct rpmsg_device *rpdev = to_rpmsg_device(dev); - struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver); - int err = 0; - - if (rpdev->announce_destroy) - err = rpdev->announce_destroy(rpdev); - - rpdrv->remove(rpdev); - - rpmsg_destroy_ept(rpdev->ept); - - return err; -} - -static struct bus_type rpmsg_bus = { - .name = "rpmsg", - .match = rpmsg_dev_match, - .dev_attrs = rpmsg_dev_attrs, - .uevent = rpmsg_uevent, - .probe = rpmsg_dev_probe, - .remove = rpmsg_dev_remove, -}; - -/** - * __register_rpmsg_driver() - register an rpmsg driver with the rpmsg bus - * @rpdrv: pointer to a struct rpmsg_driver - * @owner: owning module/driver - * - * Returns 0 on success, and an appropriate error value on failure. - */ -int __register_rpmsg_driver(struct rpmsg_driver *rpdrv, struct module *owner) -{ - rpdrv->drv.bus = &rpmsg_bus; - rpdrv->drv.owner = owner; - return driver_register(&rpdrv->drv); -} -EXPORT_SYMBOL(__register_rpmsg_driver); - -/** - * unregister_rpmsg_driver() - unregister an rpmsg driver from the rpmsg bus - * @rpdrv: pointer to a struct rpmsg_driver - * - * Returns 0 on success, and an appropriate error value on failure. - */ -void unregister_rpmsg_driver(struct rpmsg_driver *rpdrv) -{ - driver_unregister(&rpdrv->drv); -} -EXPORT_SYMBOL(unregister_rpmsg_driver); - -static void rpmsg_release_device(struct device *dev) -{ - struct rpmsg_device *rpdev = to_rpmsg_device(dev); - - kfree(rpdev); -} - -/* - * match an rpmsg channel with a channel info struct. - * this is used to make sure we're not creating rpmsg devices for channels - * that already exist. - */ -static int rpmsg_device_match(struct device *dev, void *data) -{ - struct rpmsg_channel_info *chinfo = data; - struct rpmsg_device *rpdev = to_rpmsg_device(dev); - - if (chinfo->src != RPMSG_ADDR_ANY && chinfo->src != rpdev->src) - return 0; - - if (chinfo->dst != RPMSG_ADDR_ANY && chinfo->dst != rpdev->dst) - return 0; - - if (strncmp(chinfo->name, rpdev->id.name, RPMSG_NAME_SIZE)) - return 0; - - /* found a match ! */ - return 1; -} - static const struct rpmsg_device virtio_rpmsg_ops = { .create_ept = virtio_rpmsg_create_ept, .destroy_ept = virtio_rpmsg_destroy_ept, @@ -556,7 +297,7 @@ static struct rpmsg_device *rpmsg_create_channel(struct virtproc_info *vrp, int ret; /* make sure a similar channel doesn't already exist */ - tmp = device_find_child(dev, chinfo, rpmsg_device_match); + tmp = rpmsg_find_device(dev, chinfo); if (tmp) { /* decrement the matched device's refcount back */ put_device(tmp); @@ -592,47 +333,6 @@ static struct rpmsg_device *rpmsg_create_channel(struct virtproc_info *vrp, return rpdev; } -static int rpmsg_register_device(struct rpmsg_device *rpdev) -{ - struct device *dev = &rpdev->dev; - int ret; - - dev_set_name(&rpdev->dev, "%s:%s", - dev_name(dev->parent), rpdev->id.name); - - rpdev->dev.bus = &rpmsg_bus; - rpdev->dev.release = rpmsg_release_device; - - ret = device_register(&rpdev->dev); - if (ret) { - dev_err(dev, "device_register failed: %d\n", ret); - put_device(&rpdev->dev); - } - - return ret; -} - -/* - * find an existing channel using its name + address properties, - * and destroy it - */ -static int rpmsg_destroy_channel(struct virtproc_info *vrp, - struct rpmsg_channel_info *chinfo) -{ - struct virtio_device *vdev = vrp->vdev; - struct device *dev; - - dev = device_find_child(&vdev->dev, chinfo, rpmsg_device_match); - if (!dev) - return -EINVAL; - - device_unregister(dev); - - put_device(dev); - - return 0; -} - /* super simple buffer "allocator" that is just enough for now */ static void *get_a_tx_buf(struct virtproc_info *vrp) { @@ -844,31 +544,6 @@ out: return err; } -/** - * rpmsg_send() - send a message across to the remote processor - * @ept: the rpmsg endpoint - * @data: payload of message - * @len: length of payload - * - * This function sends @data of length @len on the @ept endpoint. - * The message will be sent to the remote processor which the @ept - * endpoint belongs to, using @ept's address and its associated rpmsg - * device destination addresses. - * In case there are no TX buffers available, the function will block until - * one becomes available, or a timeout of 15 seconds elapses. When the latter - * happens, -ERESTARTSYS is returned. - * - * Can only be called from process context (for now). - * - * Returns 0 on success and an appropriate error value on failure. - */ -int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len) -{ - struct rpmsg_device *rpdev = ept->rpdev; - - return rpdev->send(ept, data, len); -} - static int virtio_rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len) { struct rpmsg_device *rpdev = ept->rpdev; @@ -877,32 +552,6 @@ static int virtio_rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len) return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true); } -/** - * rpmsg_sendto() - send a message across to the remote processor, specify dst - * @ept: the rpmsg endpoint - * @data: payload of message - * @len: length of payload - * @dst: destination address - * - * This function sends @data of length @len to the remote @dst address. - * The message will be sent to the remote processor which the @ept - * endpoint belongs to, using @ept's address as source. - * In case there are no TX buffers available, the function will block until - * one becomes available, or a timeout of 15 seconds elapses. When the latter - * happens, -ERESTARTSYS is returned. - * - * Can only be called from process context (for now). - * - * Returns 0 on success and an appropriate error value on failure. - */ -int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst) -{ - struct rpmsg_device *rpdev = ept->rpdev; - - return rpdev->sendto(ept, data, len, dst); -} -EXPORT_SYMBOL(rpmsg_sendto); - static int virtio_rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst) { @@ -912,35 +561,6 @@ static int virtio_rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true); } -/** - * rpmsg_send_offchannel() - send a message using explicit src/dst addresses - * @ept: the rpmsg endpoint - * @src: source address - * @dst: destination address - * @data: payload of message - * @len: length of payload - * - * This function sends @data of length @len to the remote @dst address, - * and uses @src as the source address. - * The message will be sent to the remote processor which the @ept - * endpoint belongs to. - * In case there are no TX buffers available, the function will block until - * one becomes available, or a timeout of 15 seconds elapses. When the latter - * happens, -ERESTARTSYS is returned. - * - * Can only be called from process context (for now). - * - * Returns 0 on success and an appropriate error value on failure. - */ -int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, - void *data, int len) -{ - struct rpmsg_device *rpdev = ept->rpdev; - - return rpdev->send_offchannel(ept, src, dst, data, len); -} -EXPORT_SYMBOL(rpmsg_send_offchannel); - static int virtio_rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, void *data, int len) { @@ -949,31 +569,6 @@ static int virtio_rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true); } -/** - * rpmsg_send() - send a message across to the remote processor - * @ept: the rpmsg endpoint - * @data: payload of message - * @len: length of payload - * - * This function sends @data of length @len on the @ept endpoint. - * The message will be sent to the remote processor which the @ept - * endpoint belongs to, using @ept's addres as source and its associated - * rpdev's address as destination. - * In case there are no TX buffers available, the function will immediately - * return -ENOMEM without waiting until one becomes available. - * - * Can only be called from process context (for now). - * - * Returns 0 on success and an appropriate error value on failure. - */ -int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len) -{ - struct rpmsg_device *rpdev = ept->rpdev; - - return rpdev->trysend(ept, data, len); -} -EXPORT_SYMBOL(rpmsg_trysend); - static int virtio_rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len) { struct rpmsg_device *rpdev = ept->rpdev; @@ -982,31 +577,6 @@ static int virtio_rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len) return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false); } -/** - * rpmsg_sendto() - send a message across to the remote processor, specify dst - * @ept: the rpmsg endpoint - * @data: payload of message - * @len: length of payload - * @dst: destination address - * - * This function sends @data of length @len to the remote @dst address. - * The message will be sent to the remote processor which the @ept - * endpoint belongs to, using @ept's address as source. - * In case there are no TX buffers available, the function will immediately - * return -ENOMEM without waiting until one becomes available. - * - * Can only be called from process context (for now). - * - * Returns 0 on success and an appropriate error value on failure. - */ -int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst) -{ - struct rpmsg_device *rpdev = ept->rpdev; - - return rpdev->trysendto(ept, data, len, dst); -} -EXPORT_SYMBOL(rpmsg_trysendto); - static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst) { @@ -1016,34 +586,6 @@ static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false); } -/** - * rpmsg_send_offchannel() - send a message using explicit src/dst addresses - * @ept: the rpmsg endpoint - * @src: source address - * @dst: destination address - * @data: payload of message - * @len: length of payload - * - * This function sends @data of length @len to the remote @dst address, - * and uses @src as the source address. - * The message will be sent to the remote processor which the @ept - * endpoint belongs to. - * In case there are no TX buffers available, the function will immediately - * return -ENOMEM without waiting until one becomes available. - * - * Can only be called from process context (for now). - * - * Returns 0 on success and an appropriate error value on failure. - */ -int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, - void *data, int len) -{ - struct rpmsg_device *rpdev = ept->rpdev; - - return rpdev->trysend_offchannel(ept, src, dst, data, len); -} -EXPORT_SYMBOL(rpmsg_trysend_offchannel); - static int virtio_rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, void *data, int len) { @@ -1208,7 +750,7 @@ static void rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len, chinfo.dst = msg->addr; if (msg->flags & RPMSG_NS_DESTROY) { - ret = rpmsg_destroy_channel(vrp, &chinfo); + ret = rpmsg_unregister_device(&vrp->vdev->dev, &chinfo); if (ret) dev_err(dev, "rpmsg_destroy_channel failed: %d\n", ret); } else { @@ -1393,17 +935,9 @@ static int __init rpmsg_init(void) { int ret; - ret = bus_register(&rpmsg_bus); - if (ret) { - pr_err("failed to register rpmsg bus: %d\n", ret); - return ret; - } - ret = register_virtio_driver(&virtio_ipc_driver); - if (ret) { + if (ret) pr_err("failed to register virtio driver: %d\n", ret); - bus_unregister(&rpmsg_bus); - } return ret; } @@ -1412,7 +946,6 @@ subsys_initcall(rpmsg_init); static void __exit rpmsg_fini(void) { unregister_virtio_driver(&virtio_ipc_driver); - bus_unregister(&rpmsg_bus); } module_exit(rpmsg_fini);
Extract the generic rpmsg core functionality from the virtio rpmsg implementation, splitting the implementation in a rpmsg core and a virtio backend. Based on initial work by Sricharan R <sricharan@codeaurora.org> Cc: Sricharan R <sricharan@codeaurora.org> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org> --- drivers/rpmsg/Kconfig | 4 + drivers/rpmsg/Makefile | 3 +- drivers/rpmsg/rpmsg_core.c | 513 +++++++++++++++++++++++++++++++++++++++ drivers/rpmsg/rpmsg_internal.h | 45 ++++ drivers/rpmsg/virtio_rpmsg_bus.c | 477 +----------------------------------- 5 files changed, 569 insertions(+), 473 deletions(-) create mode 100644 drivers/rpmsg/rpmsg_core.c create mode 100644 drivers/rpmsg/rpmsg_internal.h