From: grant.likely@secretlab.ca (Grant Likely)
To: linux-arm-kernel@lists.infradead.org
Subject: [RFC 7/8] drivers: introduce rpmsg, a remote-processor messaging bus
Date: Mon, 27 Jun 2011 16:21:21 -0600 [thread overview]
Message-ID: <20110627222121.GD20865@ponder.secretlab.ca> (raw)
In-Reply-To: <1308640714-17961-8-git-send-email-ohad@wizery.com>
On Tue, Jun 21, 2011 at 10:18:33AM +0300, Ohad Ben-Cohen wrote:
> Add a virtio-based IPC bus, which enables kernel users to communicate
> with remote processors over shared memory using a simple messaging
> protocol.
>
> Assign a local address for every local endpoint that is created,
> and bind it to the user's callback. Invoke that callback when the
> destination of an inbound message is the user's address.
>
> Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Hey Ohad,
Nice patch. I'm quite thrilled to see this implemented. Some
comments below, but otherwise I think it looks pretty good.
> ---
> Documentation/ABI/testing/sysfs-bus-rpmsg | 75 +++
> Documentation/rpmsg.txt | 308 +++++++++
> drivers/Kconfig | 1 +
> drivers/Makefile | 1 +
> drivers/rpmsg/Kconfig | 14 +
> drivers/rpmsg/Makefile | 1 +
> drivers/rpmsg/virtio_rpmsg_bus.c | 1036 +++++++++++++++++++++++++++++
> include/linux/mod_devicetable.h | 10 +
> include/linux/rpmsg.h | 421 ++++++++++++
> include/linux/virtio_ids.h | 1 +
> 10 files changed, 1868 insertions(+), 0 deletions(-)
> create mode 100644 Documentation/ABI/testing/sysfs-bus-rpmsg
> create mode 100644 Documentation/rpmsg.txt
> create mode 100644 drivers/rpmsg/Kconfig
> create mode 100644 drivers/rpmsg/Makefile
> create mode 100644 drivers/rpmsg/virtio_rpmsg_bus.c
> create mode 100644 include/linux/rpmsg.h
>
> diff --git a/Documentation/rpmsg.txt b/Documentation/rpmsg.txt
> new file mode 100644
> index 0000000..0a7c820
> --- /dev/null
> +++ b/Documentation/rpmsg.txt
[...]
Great documentation! Thanks!
> diff --git a/drivers/Kconfig b/drivers/Kconfig
> index 1f6d6d3..840f835 100644
> --- a/drivers/Kconfig
> +++ b/drivers/Kconfig
> @@ -128,4 +128,5 @@ source "drivers/clocksource/Kconfig"
>
> source "drivers/remoteproc/Kconfig"
>
> +source "drivers/rpmsg/Kconfig"
> endmenu
> diff --git a/drivers/Makefile b/drivers/Makefile
> index 4d53a18..2980a15 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -22,6 +22,7 @@ obj-$(CONFIG_ARM_AMBA) += amba/
> obj-$(CONFIG_DMA_ENGINE) += dma/
>
> obj-$(CONFIG_VIRTIO) += virtio/
> +obj-$(CONFIG_RPMSG) += rpmsg/
> obj-$(CONFIG_XEN) += xen/
>
> # regulators early, since some subsystems rely on them to initialize
> diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
> new file mode 100644
> index 0000000..41303f5
> --- /dev/null
> +++ b/drivers/rpmsg/Kconfig
> @@ -0,0 +1,14 @@
> +# RPMSG always gets selected by whoever wants it
> +config RPMSG
> + tristate
> + select VIRTIO
> + select VIRTIO_RING
> +
> +if RPMSG
> +
> +# OK, it's a little counter-intuitive to do this, but it puts it neatly under
> +# the rpmsg menu (and it's the approach preferred by the virtio folks).
> +
> +source "drivers/virtio/Kconfig"
What happens when kvm and rpmsg both get enabled on the same kernel.
ARM virtualization is currently being worked on, so it will happen.
Also, I can see this finding use in the x86 world to talk to
coprocessor boards (like the Xilinx FPGA plugin board which can have a
soft core on it).
> +
> +endif # RPMSG
> diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
> new file mode 100644
> index 0000000..7617fcb
> --- /dev/null
> +++ b/drivers/rpmsg/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_RPMSG) += virtio_rpmsg_bus.o
> diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
> new file mode 100644
> index 0000000..3e98b02
> --- /dev/null
> +++ b/drivers/rpmsg/virtio_rpmsg_bus.c
[...]
> +/* rpmsg devices and drivers are matched using the service name */
> +static inline int rpmsg_id_match(const struct rpmsg_channel *rpdev,
> + const struct rpmsg_device_id *id)
> +{
> + if (strncmp(id->name, rpdev->id.name, RPMSG_NAME_SIZE))
> + return 0;
> +
> + return 1;
> +}
or simply: 'return strncmp(id->name, rpdev->id.name, RPMSG_NAME_SIZE) == 0;'
:-)
> +/* for more info, see below documentation of rpmsg_create_ept() */
> +static struct rpmsg_endpoint *__rpmsg_create_ept(struct virtproc_info *vrp,
> + struct rpmsg_channel *rpdev,
> + void (*cb)(struct rpmsg_channel *, void *, int, void *, u32),
> + void *priv, u32 addr)
> +{
> + int err, tmpaddr, request;
> + struct rpmsg_endpoint *ept;
> + struct device *dev = rpdev ? &rpdev->dev : &vrp->vdev->dev;
> +
> + if (!idr_pre_get(&vrp->endpoints, GFP_KERNEL))
> + return NULL;
> +
> + ept = kzalloc(sizeof(*ept), GFP_KERNEL);
> + if (!ept) {
> + dev_err(dev, "failed to kzalloc a new ept\n");
> + return NULL;
> + }
> +
> + ept->rpdev = rpdev;
> + ept->cb = cb;
> + ept->priv = priv;
> +
> + /* do we need to allocate a local address ? */
> + request = addr == RPMSG_ADDR_ANY ? RPMSG_RESERVED_ADDRESSES : addr;
> +
> + spin_lock(&vrp->endpoints_lock);
Is a spin_lock the right choice for endpoints, or should it be a
mutex (do the endpoints operations need to be atomic)?
> +/*
> + * 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_channel_match);
> + if (!dev)
> + return -EINVAL;
> +
> + device_unregister(dev);
> +
> + put_device(dev);
> +
> + kfree(to_rpmsg_channel(dev));
At put_device time, it is conceivable that the dev pointer is no
longer valid. You'll need to get do the to_rpmsg_channel() before
putting the dev.
> +
> + return 0;
> +}
> +
> +/* super simple buffer "allocator" that is just enough for now */
> +static void *get_a_tx_buf(struct virtproc_info *vrp)
> +{
> + unsigned int len;
> + void *ret;
> +
> + /* support multiple concurrent senders */
> + spin_lock(&vrp->tx_lock);
> +
> + /*
> + * either pick the next unused tx buffer
> + * (half of our buffers are used for sending messages)
> + */
> + if (vrp->last_sbuf < vrp->num_bufs / 2)
> + ret = vrp->sbufs + vrp->buf_size * vrp->last_sbuf++;
> + /* or recycle a used one */
> + else
> + ret = virtqueue_get_buf(vrp->svq, &len);
> +
> + spin_unlock(&vrp->tx_lock);
> +
> + return ret;
> +}
> +
> +/**
> + * rpmsg_upref_sleepers() - enable "tx-complete" interrupts, if needed
> + * @vrp: virtual remote processor state
> + *
> + * This function is called before a sender is blocked, waiting for
> + * a tx buffer to become available.
> + *
> + * If we already have blocking senders, this function merely increases
> + * the "sleepers" reference count, and exits.
> + *
> + * Otherwise, if this is the first sender to block, we also enable
> + * virtio's tx callbacks, so we'd be immediately notified when a tx
> + * buffer is consumed (we rely on virtio's tx callback in order
> + * to wake up sleeping senders as soon as a tx buffer is used by the
> + * remote processor).
> + */
> +static void rpmsg_upref_sleepers(struct virtproc_info *vrp)
> +{
> + /* support multiple concurrent senders */
> + spin_lock(&vrp->tx_lock);
> +
> + /* are we the first sleeping context waiting for tx buffers ? */
> + if (!vrp->sleepers++)
Maybe use a kref? It might be useful to have a kref_get_first() that
takes a callback used for the first increment.
> +static int rpmsg_remove_device(struct device *dev, void *data)
> +{
> + struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
> +
> + device_unregister(dev);
> +
> + kfree(rpdev);
put_device() I think.
> +
> + return 0;
> +}
> +
> +static void __devexit rpmsg_remove(struct virtio_device *vdev)
> +{
> + struct virtproc_info *vrp = vdev->priv;
> + int ret;
> +
> + ret = device_for_each_child(&vdev->dev, NULL, rpmsg_remove_device);
> + if (ret)
> + dev_warn(&vdev->dev, "can't remove rpmsg device: %d\n", ret);
> +
> + idr_remove_all(&vrp->endpoints);
> + idr_destroy(&vrp->endpoints);
> +
> + vdev->config->del_vqs(vrp->vdev);
> +
> + kfree(vrp);
> +}
> +
> +static struct virtio_device_id id_table[] = {
> + { VIRTIO_ID_RPMSG, VIRTIO_DEV_ANY_ID },
> + { 0 },
> +};
> +
> +static unsigned int features[] = {
> + VIRTIO_RPMSG_F_NS,
> +};
> +
> +static struct virtio_driver virtio_ipc_driver = {
> + .feature_table = features,
> + .feature_table_size = ARRAY_SIZE(features),
> + .driver.name = KBUILD_MODNAME,
> + .driver.owner = THIS_MODULE,
> + .id_table = id_table,
> + .probe = rpmsg_probe,
> + .remove = __devexit_p(rpmsg_remove),
> +};
> +
> +static int __init init(void)
Even for static functions, it's a really good idea to prefix all
function names and file scoped symbol with a common prefix like
"rpmsg_". Doing so avoids even the outside chance of a namespace
conflict.
> +{
> + int ret;
> +
> + ret = bus_register(&rpmsg_bus);
> + if (ret) {
> + pr_err("failed to register rpmsg bus: %d\n", ret);
> + return ret;
> + }
> +
> + return register_virtio_driver(&virtio_ipc_driver);
And if register_virtio_driver fails?
> +}
> +module_init(init);
> +
> +static void __exit fini(void)
> +{
> + unregister_virtio_driver(&virtio_ipc_driver);
> + bus_unregister(&rpmsg_bus);
> +}
> +module_exit(fini);
> +
> +MODULE_DEVICE_TABLE(virtio, id_table);
> +MODULE_DESCRIPTION("Virtio-based remote processor messaging bus");
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
> index ae28e93..561567e 100644
> --- a/include/linux/mod_devicetable.h
> +++ b/include/linux/mod_devicetable.h
> @@ -533,4 +533,14 @@ struct isapnp_device_id {
> kernel_ulong_t driver_data; /* data private to the driver */
> };
>
> +/* rpmsg */
> +
> +#define RPMSG_NAME_SIZE 32
> +#define RPMSG_DEVICE_MODALIAS_FMT "rpmsg:%s"
> +
> +struct rpmsg_device_id {
> + char name[RPMSG_NAME_SIZE];
> + kernel_ulong_t driver_data /* Data private to the driver */
> + __attribute__((aligned(sizeof(kernel_ulong_t))));
> +};
Should this be co-located with vio_device_id?
It makes it easier to dereference in kernel code if you do:
#ifdef __KERNEL__
void *data;
#else
kernel_ulong_t data;
#endif
next prev parent reply other threads:[~2011-06-27 22:21 UTC|newest]
Thread overview: 63+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-06-21 7:18 [RFC 0/8] Introducing a generic AMP/IPC framework Ohad Ben-Cohen
[not found] ` <BANLkTimn-THKipuQVHLA9i3QSoO5RTqMtA@mail.gmail.com>
2011-06-21 9:30 ` Ohad Ben-Cohen
2011-06-21 14:20 ` Arnd Bergmann
2011-06-21 15:54 ` Grant Likely
2011-06-22 11:41 ` Ohad Ben-Cohen
2011-06-22 13:05 ` Arnd Bergmann
2011-06-22 13:09 ` Ohad Ben-Cohen
[not found] ` <1308640714-17961-3-git-send-email-ohad@wizery.com>
2011-06-22 10:05 ` [RFC 2/8] remoteproc: add omap implementation Will Newton
2011-06-22 10:50 ` Ohad Ben-Cohen
2011-06-27 21:00 ` Grant Likely
2011-06-29 15:04 ` Ohad Ben-Cohen
2011-06-29 15:31 ` Grant Likely
2011-06-23 12:23 ` [RFC 0/8] Introducing a generic AMP/IPC framework Michael Williamson
2011-06-23 16:27 ` Grosen, Mark
2011-06-23 18:46 ` Arnd Bergmann
2011-06-24 4:32 ` Grosen, Mark
[not found] ` <1308640714-17961-6-git-send-email-ohad@wizery.com>
2011-06-23 15:27 ` [RFC 5/8] remoteproc: add davinci implementation Sergei Shtylyov
2011-06-24 4:25 ` Grosen, Mark
2011-06-24 15:13 ` Sergei Shtylyov
2011-06-24 15:43 ` Nori, Sekhar
2011-06-27 18:31 ` Grosen, Mark
2011-07-05 5:29 ` Nori, Sekhar
2011-07-05 16:54 ` Grosen, Mark
2011-07-05 5:34 ` Nori, Sekhar
2011-07-05 16:54 ` Grosen, Mark
2011-07-06 4:36 ` Nori, Sekhar
2011-06-27 18:20 ` Grosen, Mark
2011-06-28 9:36 ` Nori, Sekhar
2011-06-24 20:16 ` [RFC 0/8] Introducing a generic AMP/IPC framework Stephen Boyd
2011-06-26 1:11 ` Ohad Ben-Cohen
2011-06-26 1:17 ` Brian Swetland
2011-06-27 21:22 ` Grosen, Mark
2011-06-28 11:26 ` Ohad Ben-Cohen
2011-06-28 11:36 ` Brian Swetland
[not found] ` <1308640714-17961-2-git-send-email-ohad@wizery.com>
2011-06-22 17:55 ` [RFC 1/8] drivers: add generic remoteproc framework Randy Dunlap
2011-06-22 19:11 ` Ohad Ben-Cohen
2011-06-27 20:49 ` Grant Likely
2011-06-27 21:52 ` Grosen, Mark
2011-06-27 22:24 ` Grant Likely
2011-06-27 23:54 ` Grosen, Mark
2011-06-27 23:29 ` Russell King - ARM Linux
2011-06-27 23:35 ` Grant Likely
2011-06-28 21:55 ` Ohad Ben-Cohen
2011-06-28 21:41 ` Ohad Ben-Cohen
[not found] ` <1308640714-17961-7-git-send-email-ohad@wizery.com>
2011-06-28 10:18 ` [RFC 6/8] davinci: da850: add remoteproc dsp device Sergei Shtylyov
[not found] ` <1308640714-17961-8-git-send-email-ohad@wizery.com>
2011-06-22 2:42 ` [RFC 7/8] drivers: introduce rpmsg, a remote-processor messaging bus Rusty Russell
2011-06-22 3:11 ` Sasha Levin
2011-06-22 10:46 ` Ohad Ben-Cohen
2011-09-14 18:38 ` Ohad Ben-Cohen
2011-09-15 0:12 ` Rusty Russell
2011-09-15 14:56 ` Ohad Ben-Cohen
2011-06-27 22:21 ` Grant Likely [this message]
2011-06-28 22:46 ` Ohad Ben-Cohen
2011-06-28 22:51 ` Grant Likely
2011-06-28 23:00 ` Ohad Ben-Cohen
2011-06-29 15:43 ` Grant Likely
2011-07-01 15:13 ` Ohad Ben-Cohen
2011-06-28 23:44 ` Randy Dunlap
2011-06-29 6:30 ` Ohad Ben-Cohen
2011-06-29 11:59 ` Arnd Bergmann
2011-06-29 12:29 ` Ohad Ben-Cohen
2011-07-18 22:07 ` Pavel Machek
2011-07-19 5:38 ` Ohad Ben-Cohen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20110627222121.GD20865@ponder.secretlab.ca \
--to=grant.likely@secretlab.ca \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).