From patchwork Tue Aug 16 00:17:14 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bjorn Andersson X-Patchwork-Id: 73947 Delivered-To: patch@linaro.org Received: by 10.140.29.52 with SMTP id a49csp1712245qga; Mon, 15 Aug 2016 17:19:20 -0700 (PDT) X-Received: by 10.66.157.40 with SMTP id wj8mr58383371pab.53.1471306760203; Mon, 15 Aug 2016 17:19:20 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id c9si28954132pas.141.2016.08.15.17.19.19; Mon, 15 Aug 2016 17:19:20 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753246AbcHPATR (ORCPT + 27 others); Mon, 15 Aug 2016 20:19:17 -0400 Received: from mail-pa0-f43.google.com ([209.85.220.43]:35828 "EHLO mail-pa0-f43.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932353AbcHPARe (ORCPT ); Mon, 15 Aug 2016 20:17:34 -0400 Received: by mail-pa0-f43.google.com with SMTP id i5so20429336pat.2 for ; Mon, 15 Aug 2016 17:17:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=SHava1udtIKo1e3AYyOlZUJbymjbmoTPF2IqV4svZm0=; b=bvVvYuKFgK2/bBOeRBuWs2hFScPf3GSEIgulJfP2bT9gu9Jf5TJaZCZW8NWSqc1gff yt9r12ikq82yVTB4qe89IzwZldx2fvcpQrjPjTK2NELGwgVGXAUmz6NWhSGWK7K0afwn gj8xv6ZvxYlgmlVLd5zBVIJZgiCsaJvQHY78Y= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=SHava1udtIKo1e3AYyOlZUJbymjbmoTPF2IqV4svZm0=; b=jv/Dk2nvUkev2mg2pdMYPqu7cNWbIBwHpZz9Q8lmHMsS6NQqzGgexS5J2jGj4yu9YC Z0dqT0raQTy+famwyhwfbkpuNAFz4fIv5uYjP8iKLcStkBjgAoRUgkj+t4Zfw60ONKVL yuA9btO9NKjAm9EY7BM48/l6Ay3qaadm8cFm1hJWLGcXsmWJDC+AjgchnTzpxOMj+GgT R93BlJVj29xPqpAyXULYu12IdkkW9H1AILtbLqOoBK7Qc9tVSibSHGKyebc+bnVFCbac nHz9JUojy4yGbRe3Hz74/+r6St+iDDHKky4ZnIvYgmPWmADEshayl3+p3H8R4BBUPetQ 07ZA== X-Gm-Message-State: AEkoout0bwmkpurgUNkrEMV7J9MfONc06RfRtCF5ftvAmTs7nbRKrvKLjF5AAuQxwmEWlz8Y X-Received: by 10.66.138.108 with SMTP id qp12mr58535354pab.65.1471306652573; Mon, 15 Aug 2016 17:17:32 -0700 (PDT) Received: from localhost.localdomain (ip68-111-223-48.sd.sd.cox.net. [68.111.223.48]) by smtp.gmail.com with ESMTPSA id p187sm34047931pfb.5.2016.08.15.17.17.31 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 15 Aug 2016 17:17:31 -0700 (PDT) From: Bjorn Andersson To: Ohad Ben-Cohen , Bjorn Andersson 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 Subject: [PATCH 08/14] rpmsg: Split rpmsg core and virtio backend Date: Mon, 15 Aug 2016 17:17:14 -0700 Message-Id: <1471306640-29917-9-git-send-email-bjorn.andersson@linaro.org> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1471306640-29917-1-git-send-email-bjorn.andersson@linaro.org> References: <1471306640-29917-1-git-send-email-bjorn.andersson@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 Cc: Sricharan R Signed-off-by: Bjorn Andersson --- 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 -- 2.5.0 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 + * Brian Swetland + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + * Brian Swetland + * + * 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 #include +#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);