From 400e64df6b237eb36b127efd72000a2794f9eec1 Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Thu, 20 Oct 2011 16:52:46 +0200 Subject: remoteproc: add framework for controlling remote processors Modern SoCs typically employ a central symmetric multiprocessing (SMP) application processor running Linux, with several other asymmetric multiprocessing (AMP) heterogeneous processors running different instances of operating system, whether Linux or any other flavor of real-time OS. Booting a remote processor in an AMP configuration typically involves: - Loading a firmware which contains the OS image - Allocating and providing it required system resources (e.g. memory) - Programming an IOMMU (when relevant) - Powering on the device This patch introduces a generic framework that allows drivers to do that. In the future, this framework will also include runtime power management and error recovery. Based on (but now quite far from) work done by Fernando Guzman Lugo . ELF loader was written by Mark Grosen , based on msm's Peripheral Image Loader (PIL) by Stephen Boyd . Designed with Brian Swetland . Signed-off-by: Ohad Ben-Cohen Acked-by: Grant Likely Cc: Brian Swetland Cc: Arnd Bergmann Cc: Tony Lindgren Cc: Russell King Cc: Rusty Russell Cc: Andrew Morton Cc: Greg KH Cc: Stephen Boyd --- include/linux/remoteproc.h | 265 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 include/linux/remoteproc.h (limited to 'include') diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h new file mode 100644 index 00000000000..1edbfde4593 --- /dev/null +++ b/include/linux/remoteproc.h @@ -0,0 +1,265 @@ +/* + * Remote Processor Framework + * + * Copyright(c) 2011 Texas Instruments, Inc. + * Copyright(c) 2011 Google, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Texas Instruments nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef REMOTEPROC_H +#define REMOTEPROC_H + +#include +#include +#include +#include +#include +#include + +/* + * The alignment between the consumer and producer parts of the vring. + * Note: this is part of the "wire" protocol. If you change this, you need + * to update your peers too. + */ +#define AMP_VRING_ALIGN (4096) + +/** + * struct fw_resource - describes an entry from the resource section + * @type: resource type + * @id: index number of the resource + * @da: device address of the resource + * @pa: physical address of the resource + * @len: size, in bytes, of the resource + * @flags: properties of the resource, e.g. iommu protection required + * @reserved: must be 0 atm + * @name: name of resource + * + * The remote processor firmware should contain a "resource table": + * array of 'struct fw_resource' entries. + * + * Some resources entries are mere announcements, where the host is informed + * of specific remoteproc configuration. Other entries require the host to + * do something (e.g. reserve a requested resource) and possibly also reply + * by overwriting a member inside 'struct fw_resource' with info about the + * allocated resource. + * + * Different resource entries use different members of this struct, + * with different meanings. This is pretty limiting and error-prone, + * so the plan is to move to variable-length TLV-based resource entries, + * where each resource type will have its own structure. + */ +struct fw_resource { + u32 type; + u32 id; + u64 da; + u64 pa; + u32 len; + u32 flags; + u8 reserved[16]; + u8 name[48]; +} __packed; + +/** + * enum fw_resource_type - types of resource entries + * + * @RSC_CARVEOUT: request for allocation of a physically contiguous + * memory region. + * @RSC_DEVMEM: request to iommu_map a memory-based peripheral. + * @RSC_TRACE: announces the availability of a trace buffer into which + * the remote processor will be writing logs. In this case, + * 'da' indicates the device address where logs are written to, + * and 'len' is the size of the trace buffer. + * @RSC_VRING: request for allocation of a virtio vring (address should + * be indicated in 'da', and 'len' should contain the number + * of buffers supported by the vring). + * @RSC_VIRTIO_DEV: this entry declares about support for a virtio device, + * and serves as the virtio header. 'da' holds the + * the virtio device features, 'pa' holds the virtio guest + * features, 'len' holds the virtio status, and 'flags' holds + * the virtio id (currently only VIRTIO_ID_RPMSG is supported). + * + * Most of the resource entries share the basic idea of address/length + * negotiation with the host: the firmware usually asks (on behalf of the + * remote processor that will soon be booted with it) for memory + * of size 'len' bytes, and the host needs to allocate it and provide + * the device/physical address (when relevant) in 'da'/'pa' respectively. + * + * If the firmware is compiled with hard coded device addresses, and + * can't handle dynamically allocated 'da' values, then the 'da' field + * will contain the expected device addresses (today we actually only support + * this scheme, as there aren't yet any use cases for dynamically allocated + * device addresses). + */ +enum fw_resource_type { + RSC_CARVEOUT = 0, + RSC_DEVMEM = 1, + RSC_TRACE = 2, + RSC_VRING = 3, + RSC_VIRTIO_DEV = 4, + RSC_VIRTIO_CFG = 5, +}; + +/** + * struct rproc_mem_entry - memory entry descriptor + * @va: virtual address + * @dma: dma address + * @len: length, in bytes + * @da: device address + * @priv: associated data + * @node: list node + */ +struct rproc_mem_entry { + void *va; + dma_addr_t dma; + int len; + u64 da; + void *priv; + struct list_head node; +}; + +struct rproc; + +/** + * struct rproc_ops - platform-specific device handlers + * @start: power on the device and boot it + * @stop: power off the device + * @kick: kick a virtqueue (virtqueue id given as a parameter) + */ +struct rproc_ops { + int (*start)(struct rproc *rproc); + int (*stop)(struct rproc *rproc); + void (*kick)(struct rproc *rproc, int vqid); +}; + +/** + * enum rproc_state - remote processor states + * @RPROC_OFFLINE: device is powered off + * @RPROC_SUSPENDED: device is suspended; needs to be woken up to receive + * a message. + * @RPROC_RUNNING: device is up and running + * @RPROC_CRASHED: device has crashed; need to start recovery + * @RPROC_LAST: just keep this one at the end + * + * Please note that the values of these states are used as indices + * to rproc_state_string, a state-to-name lookup table, + * so please keep the two synchronized. @RPROC_LAST is used to check + * the validity of an index before the lookup table is accessed, so + * please update it as needed too. + */ +enum rproc_state { + RPROC_OFFLINE = 0, + RPROC_SUSPENDED = 1, + RPROC_RUNNING = 2, + RPROC_CRASHED = 3, + RPROC_LAST = 4, +}; + +/** + * struct rproc - represents a physical remote processor device + * @node: klist node of this rproc object + * @domain: iommu domain + * @name: human readable name of the rproc + * @firmware: name of firmware file to be loaded + * @priv: private data which belongs to the platform-specific rproc module + * @ops: platform-specific start/stop rproc handlers + * @dev: underlying device + * @refcount: refcount of users that have a valid pointer to this rproc + * @power: refcount of users who need this rproc powered up + * @state: state of the device + * @lock: lock which protects concurrent manipulations of the rproc + * @dbg_dir: debugfs directory of this rproc device + * @traces: list of trace buffers + * @num_traces: number of trace buffers + * @carveouts: list of physically contiguous memory allocations + * @mappings: list of iommu mappings we initiated, needed on shutdown + * @firmware_loading_complete: marks e/o asynchronous firmware loading + * @bootaddr: address of first instruction to boot rproc with (optional) + * @rvdev: virtio device (we only support a single rpmsg virtio device for now) + */ +struct rproc { + struct klist_node node; + struct iommu_domain *domain; + const char *name; + const char *firmware; + void *priv; + const struct rproc_ops *ops; + struct device *dev; + struct kref refcount; + atomic_t power; + unsigned int state; + struct mutex lock; + struct dentry *dbg_dir; + struct list_head traces; + int num_traces; + struct list_head carveouts; + struct list_head mappings; + struct completion firmware_loading_complete; + u64 bootaddr; + struct rproc_vdev *rvdev; +}; + +/** + * struct rproc_vdev - remoteproc state for a supported virtio device + * @rproc: the rproc handle + * @vdev: the virio device + * @vq: the virtqueues for this vdev + * @vring: the vrings for this vdev + * @dfeatures: virtio device features + * @gfeatures: virtio guest features + */ +struct rproc_vdev { + struct rproc *rproc; + struct virtio_device vdev; + struct virtqueue *vq[2]; + struct rproc_mem_entry vring[2]; + unsigned long dfeatures; + unsigned long gfeatures; +}; + +struct rproc *rproc_get_by_name(const char *name); +void rproc_put(struct rproc *rproc); + +struct rproc *rproc_alloc(struct device *dev, const char *name, + const struct rproc_ops *ops, + const char *firmware, int len); +void rproc_free(struct rproc *rproc); +int rproc_register(struct rproc *rproc); +int rproc_unregister(struct rproc *rproc); + +int rproc_boot(struct rproc *rproc); +void rproc_shutdown(struct rproc *rproc); + +static inline struct rproc *vdev_to_rproc(struct virtio_device *vdev) +{ + struct rproc_vdev *rvdev = container_of(vdev, struct rproc_vdev, vdev); + + return rvdev->rproc; +} + +#endif /* REMOTEPROC_H */ -- cgit v1.2.3-18-g5258 From bcabbccabffe7326f046f25737ba1084f463c65c Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Thu, 20 Oct 2011 21:10:55 +0200 Subject: rpmsg: add virtio-based remote processor messaging bus Add a virtio-based inter-processor communication bus, which enables kernel drivers to communicate with entities, running on remote processors, over shared memory using a simple messaging protocol. Every pair of AMP processors share two vrings, which are used to send and receive the messages over shared memory. The header of every message sent on the rpmsg bus contains src and dst addresses, which make it possible to multiplex several rpmsg channels on the same vring. Every rpmsg channel is a device on this bus. When a channel is added, and an appropriate rpmsg driver is found and probed, it is also assigned a local rpmsg address, which is then bound to the driver's callback. When inbound messages carry the local address of a bound driver, its callback is invoked by the bus. This patch provides a kernel interface only; user space interfaces will be later exposed by kernel users of this rpmsg bus. Designed with Brian Swetland . Signed-off-by: Ohad Ben-Cohen Acked-by: Rusty Russell (virtio_ids.h) Cc: Brian Swetland Cc: Arnd Bergmann Cc: Grant Likely Cc: Tony Lindgren Cc: Russell King Cc: Andrew Morton Cc: Greg KH Cc: Stephen Boyd --- include/linux/mod_devicetable.h | 9 ++ include/linux/rpmsg.h | 326 ++++++++++++++++++++++++++++++++++++++++ include/linux/virtio_ids.h | 1 + 3 files changed, 336 insertions(+) create mode 100644 include/linux/rpmsg.h (limited to 'include') diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index b29e7f6f8fa..92aef8aaef1 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -414,6 +414,15 @@ struct hv_vmbus_device_id { __attribute__((aligned(sizeof(kernel_ulong_t)))); }; +/* rpmsg */ + +#define RPMSG_NAME_SIZE 32 +#define RPMSG_DEVICE_MODALIAS_FMT "rpmsg:%s" + +struct rpmsg_device_id { + char name[RPMSG_NAME_SIZE]; +}; + /* i2c */ #define I2C_NAME_SIZE 20 diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h new file mode 100644 index 00000000000..a8e50e44203 --- /dev/null +++ b/include/linux/rpmsg.h @@ -0,0 +1,326 @@ +/* + * Remote processor messaging + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Copyright (C) 2011 Google, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Texas Instruments nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_RPMSG_H +#define _LINUX_RPMSG_H + +#include +#include +#include + +/* The feature bitmap for virtio rpmsg */ +#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */ + +/** + * struct rpmsg_hdr - common header for all rpmsg messages + * @src: source address + * @dst: destination address + * @reserved: reserved for future use + * @len: length of payload (in bytes) + * @flags: message flags + * @data: @len bytes of message payload data + * + * Every message sent(/received) on the rpmsg bus begins with this header. + */ +struct rpmsg_hdr { + u32 src; + u32 dst; + u32 reserved; + u16 len; + u16 flags; + u8 data[0]; +} __packed; + +/** + * struct rpmsg_ns_msg - dynamic name service announcement message + * @name: name of remote service that is published + * @addr: address of remote service that is published + * @flags: indicates whether service is created or destroyed + * + * This message is sent across to publish a new service, or announce + * about its removal. When we receive these messages, an appropriate + * rpmsg channel (i.e device) is created/destroyed. In turn, the ->probe() + * or ->remove() handler of the appropriate rpmsg driver will be invoked + * (if/as-soon-as one is registered). + */ +struct rpmsg_ns_msg { + char name[RPMSG_NAME_SIZE]; + u32 addr; + u32 flags; +} __packed; + +/** + * enum rpmsg_ns_flags - dynamic name service announcement flags + * + * @RPMSG_NS_CREATE: a new remote service was just created + * @RPMSG_NS_DESTROY: a known remote service was just destroyed + */ +enum rpmsg_ns_flags { + RPMSG_NS_CREATE = 0, + RPMSG_NS_DESTROY = 1, +}; + +#define RPMSG_ADDR_ANY 0xFFFFFFFF + +struct virtproc_info; + +/** + * rpmsg_channel - devices that belong to the rpmsg bus are called channels + * @vrp: the remote processor this channel belongs to + * @dev: the device struct + * @id: device id (used to match between rpmsg drivers and devices) + * @src: local address + * @dst: destination address + * @ept: the rpmsg endpoint of this channel + * @announce: if set, rpmsg will announce the creation/removal of this channel + */ +struct rpmsg_channel { + struct virtproc_info *vrp; + struct device dev; + struct rpmsg_device_id id; + u32 src; + u32 dst; + struct rpmsg_endpoint *ept; + bool announce; +}; + +typedef void (*rpmsg_rx_cb_t)(struct rpmsg_channel *, void *, int, void *, u32); + +/** + * struct rpmsg_endpoint - binds a local rpmsg address to its user + * @rpdev: rpmsg channel device + * @cb: rx callback handler + * @addr: local rpmsg address + * @priv: private data for the driver's use + * + * In essence, an rpmsg endpoint represents a listener on the rpmsg bus, as + * it binds an rpmsg address with an rx callback handler. + * + * Simple rpmsg drivers shouldn't use this struct directly, because + * things just work: every rpmsg driver provides an rx callback upon + * registering to the bus, and that callback is then bound to its rpmsg + * address when the driver is probed. When relevant inbound messages arrive + * (i.e. messages which their dst address equals to the src address of + * the rpmsg channel), the driver's handler is invoked to process it. + * + * More complicated drivers though, that do need to allocate additional rpmsg + * addresses, and bind them to different rx callbacks, must explicitly + * create additional endpoints by themselves (see rpmsg_create_ept()). + */ +struct rpmsg_endpoint { + struct rpmsg_channel *rpdev; + rpmsg_rx_cb_t cb; + u32 addr; + void *priv; +}; + +/** + * struct rpmsg_driver - rpmsg driver struct + * @drv: underlying device driver + * @id_table: rpmsg ids serviced by this driver + * @probe: invoked when a matching rpmsg channel (i.e. device) is found + * @remove: invoked when the rpmsg channel is removed + * @callback: invoked when an inbound message is received on the channel + */ +struct rpmsg_driver { + struct device_driver drv; + const struct rpmsg_device_id *id_table; + int (*probe)(struct rpmsg_channel *dev); + void (*remove)(struct rpmsg_channel *dev); + void (*callback)(struct rpmsg_channel *, void *, int, void *, u32); +}; + +int register_rpmsg_device(struct rpmsg_channel *dev); +void unregister_rpmsg_device(struct rpmsg_channel *dev); +int register_rpmsg_driver(struct rpmsg_driver *drv); +void unregister_rpmsg_driver(struct rpmsg_driver *drv); +void rpmsg_destroy_ept(struct rpmsg_endpoint *); +struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *, + rpmsg_rx_cb_t cb, void *priv, u32 addr); +int +rpmsg_send_offchannel_raw(struct rpmsg_channel *, u32, u32, void *, int, bool); + +/** + * rpmsg_send() - send a message across to the remote processor + * @rpdev: the rpmsg channel + * @data: payload of message + * @len: length of payload + * + * This function sends @data of length @len on the @rpdev channel. + * The message will be sent to the remote processor which the @rpdev + * channel belongs to, using @rpdev's source and 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. + */ +static inline int rpmsg_send(struct rpmsg_channel *rpdev, void *data, int len) +{ + u32 src = rpdev->src, dst = rpdev->dst; + + return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true); +} + +/** + * rpmsg_sendto() - send a message across to the remote processor, specify dst + * @rpdev: the rpmsg channel + * @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 @rpdev + * channel belongs to, using @rpdev's source address. + * 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. + */ +static inline +int rpmsg_sendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst) +{ + u32 src = rpdev->src; + + return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true); +} + +/** + * rpmsg_send_offchannel() - send a message using explicit src/dst addresses + * @rpdev: the rpmsg channel + * @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 @rpdev + * channel 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. + */ +static inline +int rpmsg_send_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst, + void *data, int len) +{ + return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, true); +} + +/** + * rpmsg_send() - send a message across to the remote processor + * @rpdev: the rpmsg channel + * @data: payload of message + * @len: length of payload + * + * This function sends @data of length @len on the @rpdev channel. + * The message will be sent to the remote processor which the @rpdev + * channel belongs to, using @rpdev's source and destination addresses. + * 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. + */ +static inline +int rpmsg_trysend(struct rpmsg_channel *rpdev, void *data, int len) +{ + u32 src = rpdev->src, dst = rpdev->dst; + + return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false); +} + +/** + * rpmsg_sendto() - send a message across to the remote processor, specify dst + * @rpdev: the rpmsg channel + * @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 @rpdev + * channel belongs to, using @rpdev's source address. + * 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. + */ +static inline +int rpmsg_trysendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst) +{ + u32 src = rpdev->src; + + return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false); +} + +/** + * rpmsg_send_offchannel() - send a message using explicit src/dst addresses + * @rpdev: the rpmsg channel + * @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 @rpdev + * channel 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. + */ +static inline +int rpmsg_trysend_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst, + void *data, int len) +{ + return rpmsg_send_offchannel_raw(rpdev, src, dst, data, len, false); +} + +#endif /* _LINUX_RPMSG_H */ diff --git a/include/linux/virtio_ids.h b/include/linux/virtio_ids.h index 85bb0bb66ff..b37c5212265 100644 --- a/include/linux/virtio_ids.h +++ b/include/linux/virtio_ids.h @@ -34,6 +34,7 @@ #define VIRTIO_ID_CONSOLE 3 /* virtio console */ #define VIRTIO_ID_RNG 4 /* virtio ring */ #define VIRTIO_ID_BALLOON 5 /* virtio balloon */ +#define VIRTIO_ID_RPMSG 7 /* virtio remote processor messaging */ #define VIRTIO_ID_9P 9 /* 9p virtio console */ #endif /* _LINUX_VIRTIO_IDS_H */ -- cgit v1.2.3-18-g5258 From 2fd51811b8b87408fd680b442364e3474a1a0f21 Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Tue, 13 Dec 2011 12:17:59 +0200 Subject: remoteproc: remove unused resource type RSC_VIRTIO_CFG isn't being used, so remove it. Originally it was introduced to overcome a resource table limitation that prevented describing a virtio device in a single resource table entry. The plan though is to describe resource table entries in a TLV fashion, where each entry will consume the amount of space it requires, so the original limitation is anyway temporary. Reported-by: Stephen Boyd Signed-off-by: Ohad Ben-Cohen --- include/linux/remoteproc.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include') diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index 1edbfde4593..b52f78413c5 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -122,7 +122,6 @@ enum fw_resource_type { RSC_TRACE = 2, RSC_VRING = 3, RSC_VIRTIO_DEV = 4, - RSC_VIRTIO_CFG = 5, }; /** -- cgit v1.2.3-18-g5258 From e12bc14b88d44e5c1456dccb59ff58103f6c6edc Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Tue, 31 Jan 2012 16:07:27 +0200 Subject: remoteproc: s/big switch/lookup table/ A lookup table would be easier to extend, and the resulting code is a bit cleaner. Reported-by: Grant Likely Signed-off-by: Ohad Ben-Cohen --- include/linux/remoteproc.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include') diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index b52f78413c5..ada4cb063df 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -103,6 +103,7 @@ struct fw_resource { * the virtio device features, 'pa' holds the virtio guest * features, 'len' holds the virtio status, and 'flags' holds * the virtio id (currently only VIRTIO_ID_RPMSG is supported). + * @RSC_LAST: just keep this one at the end * * Most of the resource entries share the basic idea of address/length * negotiation with the host: the firmware usually asks (on behalf of the @@ -115,6 +116,11 @@ struct fw_resource { * will contain the expected device addresses (today we actually only support * this scheme, as there aren't yet any use cases for dynamically allocated * device addresses). + * + * Please note that these values are used as indices to the rproc_handle_rsc + * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to + * check the validity of an index before the lookup table is accessed, so + * please update it as needed. */ enum fw_resource_type { RSC_CARVEOUT = 0, @@ -122,6 +128,7 @@ enum fw_resource_type { RSC_TRACE = 2, RSC_VRING = 3, RSC_VIRTIO_DEV = 4, + RSC_LAST = 5, }; /** -- cgit v1.2.3-18-g5258 From fd2c15ec1dd3c2fdfc6ff03bb9644da9d530e3b9 Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Wed, 1 Feb 2012 21:56:16 +0200 Subject: remoteproc: resource table overhaul The resource table is an array of 'struct fw_resource' members, where each resource entry is expressed as a single member of that array. This approach got us this far, but it has a few drawbacks: 1. Different resource entries end up overloading the same members of 'struct fw_resource' with different meanings. The resulting code is error prone and hard to read and maintain. 2. It's impossible to extend 'struct fw_resource' without breaking the existing firmware images (and we already want to: we can't introduce the new virito device resource entry with the current scheme). 3. It doesn't scale: 'struct fw_resource' must be as big as the largest resource entry type. As a result, smaller resource entries end up utilizing only small part of it. This is fixed by defining a dedicated structure for every resource type, and then converting the resource table to a list of type-value members. Instead of a rigid array of homogeneous structs, the resource table is turned into a collection of heterogeneous structures. This way: 1. Resource entries consume exactly the amount of bytes they need. 2. It's easy to extend: just create a new resource entry structure, and assign it a new type. 3. The code is easier to read and maintain: the structures' members names are meaningful. While we're at it, this patch has several other resource table changes: 1. The resource table gains a simple header which contains the number of entries in the table and their offsets within the table. This makes the parsing code simpler and easier to read. 2. A version member is added to the resource table. Should we change the format again, we'll bump up this version to prevent breakage with existing firmware images. 3. The VRING and VIRTIO_DEV resource entries are combined to a single VDEV entry. This paves the way to supporting multiple VDEV entries. 4. Since we don't really support 64-bit rprocs yet, convert two stray u64 members to u32. Signed-off-by: Ohad Ben-Cohen Cc: Brian Swetland Cc: Iliyan Malchev Cc: Arnd Bergmann Cc: Grant Likely Cc: Rusty Russell Cc: Mark Grosen Cc: John Williams Cc: Michal Simek Cc: Loic PALLARDY Cc: Ludovic BARRE Cc: Omar Ramirez Luna Cc: Guzman Lugo Fernando Cc: Anna Suman Cc: Clark Rob Cc: Stephen Boyd Cc: Saravana Kannan Cc: David Brown Cc: Kieran Bingham Cc: Tony Lindgren --- include/linux/remoteproc.h | 289 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 235 insertions(+), 54 deletions(-) (limited to 'include') diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index ada4cb063df..6040f831f62 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -50,39 +50,51 @@ #define AMP_VRING_ALIGN (4096) /** - * struct fw_resource - describes an entry from the resource section - * @type: resource type - * @id: index number of the resource - * @da: device address of the resource - * @pa: physical address of the resource - * @len: size, in bytes, of the resource - * @flags: properties of the resource, e.g. iommu protection required - * @reserved: must be 0 atm - * @name: name of resource + * struct resource_table - firmware resource table header + * @ver: version number + * @num: number of resource entries + * @reserved: reserved (must be zero) + * @offset: array of offsets pointing at the various resource entries * - * The remote processor firmware should contain a "resource table": - * array of 'struct fw_resource' entries. + * A resource table is essentially a list of system resources required + * by the remote processor. It may also include configuration entries. + * If needed, the remote processor firmware should contain this table + * as a dedicated ".resource_table" ELF section. * * Some resources entries are mere announcements, where the host is informed * of specific remoteproc configuration. Other entries require the host to - * do something (e.g. reserve a requested resource) and possibly also reply - * by overwriting a member inside 'struct fw_resource' with info about the - * allocated resource. - * - * Different resource entries use different members of this struct, - * with different meanings. This is pretty limiting and error-prone, - * so the plan is to move to variable-length TLV-based resource entries, - * where each resource type will have its own structure. + * do something (e.g. allocate a system resource). Sometimes a negotiation + * is expected, where the firmware requests a resource, and once allocated, + * the host should provide back its details (e.g. address of an allocated + * memory region). + * + * The header of the resource table, as expressed by this structure, + * contains a version number (should we need to change this format in the + * future), the number of available resource entries, and their offsets + * in the table. + * + * Immediately following this header are the resource entries themselves, + * each of which begins with a resource entry header (as described below). + */ +struct resource_table { + u32 ver; + u32 num; + u32 reserved[2]; + u32 offset[0]; +} __packed; + +/** + * struct fw_rsc_hdr - firmware resource entry header + * @type: resource type + * @data: resource data + * + * Every resource entry begins with a 'struct fw_rsc_hdr' header providing + * its @type. The content of the entry itself will immediately follow + * this header, and it should be parsed according to the resource type. */ -struct fw_resource { +struct fw_rsc_hdr { u32 type; - u32 id; - u64 da; - u64 pa; - u32 len; - u32 flags; - u8 reserved[16]; - u8 name[48]; + u8 data[0]; } __packed; /** @@ -92,30 +104,13 @@ struct fw_resource { * memory region. * @RSC_DEVMEM: request to iommu_map a memory-based peripheral. * @RSC_TRACE: announces the availability of a trace buffer into which - * the remote processor will be writing logs. In this case, - * 'da' indicates the device address where logs are written to, - * and 'len' is the size of the trace buffer. - * @RSC_VRING: request for allocation of a virtio vring (address should - * be indicated in 'da', and 'len' should contain the number - * of buffers supported by the vring). - * @RSC_VIRTIO_DEV: this entry declares about support for a virtio device, - * and serves as the virtio header. 'da' holds the - * the virtio device features, 'pa' holds the virtio guest - * features, 'len' holds the virtio status, and 'flags' holds - * the virtio id (currently only VIRTIO_ID_RPMSG is supported). + * the remote processor will be writing logs. + * @RSC_VDEV: declare support for a virtio device, and serve as its + * virtio header. * @RSC_LAST: just keep this one at the end * - * Most of the resource entries share the basic idea of address/length - * negotiation with the host: the firmware usually asks (on behalf of the - * remote processor that will soon be booted with it) for memory - * of size 'len' bytes, and the host needs to allocate it and provide - * the device/physical address (when relevant) in 'da'/'pa' respectively. - * - * If the firmware is compiled with hard coded device addresses, and - * can't handle dynamically allocated 'da' values, then the 'da' field - * will contain the expected device addresses (today we actually only support - * this scheme, as there aren't yet any use cases for dynamically allocated - * device addresses). + * For more details regarding a specific resource type, please see its + * dedicated structure below. * * Please note that these values are used as indices to the rproc_handle_rsc * lookup table, so please keep them sane. Moreover, @RSC_LAST is used to @@ -126,11 +121,197 @@ enum fw_resource_type { RSC_CARVEOUT = 0, RSC_DEVMEM = 1, RSC_TRACE = 2, - RSC_VRING = 3, - RSC_VIRTIO_DEV = 4, - RSC_LAST = 5, + RSC_VDEV = 3, + RSC_LAST = 4, }; +#define FW_RSC_ADDR_ANY (0xFFFFFFFFFFFFFFFF) + +/** + * struct fw_rsc_carveout - physically contiguous memory request + * @da: device address + * @pa: physical address + * @len: length (in bytes) + * @flags: iommu protection flags + * @reserved: reserved (must be zero) + * @name: human-readable name of the requested memory region + * + * This resource entry requests the host to allocate a physically contiguous + * memory region. + * + * These request entries should precede other firmware resource entries, + * as other entries might request placing other data objects inside + * these memory regions (e.g. data/code segments, trace resource entries, ...). + * + * Allocating memory this way helps utilizing the reserved physical memory + * (e.g. CMA) more efficiently, and also minimizes the number of TLB entries + * needed to map it (in case @rproc is using an IOMMU). Reducing the TLB + * pressure is important; it may have a substantial impact on performance. + * + * If the firmware is compiled with static addresses, then @da should specify + * the expected device address of this memory region. If @da is set to + * FW_RSC_ADDR_ANY, then the host will dynamically allocate it, and then + * overwrite @da with the dynamically allocated address. + * + * We will always use @da to negotiate the device addresses, even if it + * isn't using an iommu. In that case, though, it will obviously contain + * physical addresses. + * + * Some remote processors needs to know the allocated physical address + * even if they do use an iommu. This is needed, e.g., if they control + * hardware accelerators which access the physical memory directly (this + * is the case with OMAP4 for instance). In that case, the host will + * overwrite @pa with the dynamically allocated physical address. + * Generally we don't want to expose physical addresses if we don't have to + * (remote processors are generally _not_ trusted), so we might want to + * change this to happen _only_ when explicitly required by the hardware. + * + * @flags is used to provide IOMMU protection flags, and @name should + * (optionally) contain a human readable name of this carveout region + * (mainly for debugging purposes). + */ +struct fw_rsc_carveout { + u32 da; + u32 pa; + u32 len; + u32 flags; + u32 reserved; + u8 name[32]; +} __packed; + +/** + * struct fw_rsc_devmem - iommu mapping request + * @da: device address + * @pa: physical address + * @len: length (in bytes) + * @flags: iommu protection flags + * @reserved: reserved (must be zero) + * @name: human-readable name of the requested region to be mapped + * + * This resource entry requests the host to iommu map a physically contiguous + * memory region. This is needed in case the remote processor requires + * access to certain memory-based peripherals; _never_ use it to access + * regular memory. + * + * This is obviously only needed if the remote processor is accessing memory + * via an iommu. + * + * @da should specify the required device address, @pa should specify + * the physical address we want to map, @len should specify the size of + * the mapping and @flags is the IOMMU protection flags. As always, @name may + * (optionally) contain a human readable name of this mapping (mainly for + * debugging purposes). + * + * Note: at this point we just "trust" those devmem entries to contain valid + * physical addresses, but this isn't safe and will be changed: eventually we + * want remoteproc implementations to provide us ranges of physical addresses + * the firmware is allowed to request, and not allow firmwares to request + * access to physical addresses that are outside those ranges. + */ +struct fw_rsc_devmem { + u32 da; + u32 pa; + u32 len; + u32 flags; + u32 reserved; + u8 name[32]; +} __packed; + +/** + * struct fw_rsc_trace - trace buffer declaration + * @da: device address + * @len: length (in bytes) + * @reserved: reserved (must be zero) + * @name: human-readable name of the trace buffer + * + * This resource entry provides the host information about a trace buffer + * into which the remote processor will write log messages. + * + * @da specifies the device address of the buffer, @len specifies + * its size, and @name may contain a human readable name of the trace buffer. + * + * After booting the remote processor, the trace buffers are exposed to the + * user via debugfs entries (called trace0, trace1, etc..). + */ +struct fw_rsc_trace { + u32 da; + u32 len; + u32 reserved; + u8 name[32]; +} __packed; + +/** + * struct fw_rsc_vdev_vring - vring descriptor entry + * @da: device address + * @align: the alignment between the consumer and producer parts of the vring + * @num: num of buffers supported by this vring (must be power of two) + * @notifyid is a unique rproc-wide notify index for this vring. This notify + * index is used when kicking a remote processor, to let it know that this + * vring is triggered. + * @reserved: reserved (must be zero) + * + * This descriptor is not a resource entry by itself; it is part of the + * vdev resource type (see below). + * + * Note that @da should either contain the device address where + * the remote processor is expecting the vring, or indicate that + * dynamically allocation of the vring's device address is supported. + */ +struct fw_rsc_vdev_vring { + u32 da; + u32 align; + u32 num; + u32 notifyid; + u32 reserved; +} __packed; + +/** + * struct fw_rsc_vdev - virtio device header + * @id: virtio device id (as in virtio_ids.h) + * @notifyid is a unique rproc-wide notify index for this vdev. This notify + * index is used when kicking a remote processor, to let it know that the + * status/features of this vdev have changes. + * @dfeatures specifies the virtio device features supported by the firmware + * @gfeatures is a place holder used by the host to write back the + * negotiated features that are supported by both sides. + * @config_len is the size of the virtio config space of this vdev. The config + * space lies in the resource table immediate after this vdev header. + * @status is a place holder where the host will indicate its virtio progress. + * @num_of_vrings indicates how many vrings are described in this vdev header + * @reserved: reserved (must be zero) + * @vring is an array of @num_of_vrings entries of 'struct fw_rsc_vdev_vring'. + * + * This resource is a virtio device header: it provides information about + * the vdev, and is then used by the host and its peer remote processors + * to negotiate and share certain virtio properties. + * + * By providing this resource entry, the firmware essentially asks remoteproc + * to statically allocate a vdev upon registration of the rproc (dynamic vdev + * allocation is not yet supported). + * + * Note: unlike virtualization systems, the term 'host' here means + * the Linux side which is running remoteproc to control the remote + * processors. We use the name 'gfeatures' to comply with virtio's terms, + * though there isn't really any virtualized guest OS here: it's the host + * which is responsible for negotiating the final features. + * Yeah, it's a bit confusing. + * + * Note: immediately following this structure is the virtio config space for + * this vdev (which is specific to the vdev; for more info, read the virtio + * spec). the size of the config space is specified by @config_len. + */ +struct fw_rsc_vdev { + u32 id; + u32 notifyid; + u32 dfeatures; + u32 gfeatures; + u32 config_len; + u8 status; + u8 num_of_vrings; + u8 reserved[2]; + struct fw_rsc_vdev_vring vring[0]; +} __packed; + /** * struct rproc_mem_entry - memory entry descriptor * @va: virtual address @@ -144,7 +325,7 @@ struct rproc_mem_entry { void *va; dma_addr_t dma; int len; - u64 da; + u32 da; void *priv; struct list_head node; }; @@ -226,7 +407,7 @@ struct rproc { struct list_head carveouts; struct list_head mappings; struct completion firmware_loading_complete; - u64 bootaddr; + u32 bootaddr; struct rproc_vdev *rvdev; }; -- cgit v1.2.3-18-g5258 From 7a186941626d19f668b08108db158379b32e6e02 Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Mon, 13 Feb 2012 22:30:39 +0100 Subject: remoteproc: remove the single rpmsg vdev limitation Now that the resource table supports publishing a virtio device in a single resource entry, firmware images can start supporting more than a single vdev. This patch removes the single vdev limitation of the remoteproc framework so multi-vdev firmwares can be leveraged: VDEV resource entries are parsed when the rproc is registered, and as a result their vrings are set up and the virtio devices are registered (and they go away when the rproc goes away). Moreover, we no longer only support VIRTIO_ID_RPMSG vdevs; any virtio device type goes now. As a result, there's no more any rpmsg-specific APIs or code in remoteproc: it all becomes generic virtio handling. Signed-off-by: Ohad Ben-Cohen Cc: Brian Swetland Cc: Iliyan Malchev Cc: Arnd Bergmann Cc: Grant Likely Cc: Rusty Russell Cc: Mark Grosen Cc: John Williams Cc: Michal Simek Cc: Loic PALLARDY Cc: Ludovic BARRE Cc: Omar Ramirez Luna Cc: Guzman Lugo Fernando Cc: Anna Suman Cc: Clark Rob Cc: Stephen Boyd Cc: Saravana Kannan Cc: David Brown Cc: Kieran Bingham Cc: Tony Lindgren --- include/linux/remoteproc.h | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index 6040f831f62..7750d8a3093 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -41,6 +41,7 @@ #include #include #include +#include /* * The alignment between the consumer and producer parts of the vring. @@ -387,7 +388,8 @@ enum rproc_state { * @mappings: list of iommu mappings we initiated, needed on shutdown * @firmware_loading_complete: marks e/o asynchronous firmware loading * @bootaddr: address of first instruction to boot rproc with (optional) - * @rvdev: virtio device (we only support a single rpmsg virtio device for now) + * @rvdevs: list of remote virtio devices + * @notifyids: idr for dynamically assigning rproc-wide unique notify ids */ struct rproc { struct klist_node node; @@ -408,23 +410,47 @@ struct rproc { struct list_head mappings; struct completion firmware_loading_complete; u32 bootaddr; + struct list_head rvdevs; + struct idr notifyids; +}; + +/* we currently support only two vrings per rvdev */ +#define RVDEV_NUM_VRINGS 2 + +/** + * struct rproc_vring - remoteproc vring state + * @va: virtual address + * @dma: dma address + * @len: length, in bytes + * @da: device address + * @notifyid: rproc-specific unique vring index + * @rvdev: remote vdev + * @vq: the virtqueue of this vring + */ +struct rproc_vring { + void *va; + dma_addr_t dma; + int len; + u32 da; + int notifyid; struct rproc_vdev *rvdev; + struct virtqueue *vq; }; /** * struct rproc_vdev - remoteproc state for a supported virtio device + * @node: list node * @rproc: the rproc handle * @vdev: the virio device - * @vq: the virtqueues for this vdev * @vring: the vrings for this vdev * @dfeatures: virtio device features * @gfeatures: virtio guest features */ struct rproc_vdev { + struct list_head node; struct rproc *rproc; struct virtio_device vdev; - struct virtqueue *vq[2]; - struct rproc_mem_entry vring[2]; + struct rproc_vring vring[RVDEV_NUM_VRINGS]; unsigned long dfeatures; unsigned long gfeatures; }; @@ -442,9 +468,14 @@ int rproc_unregister(struct rproc *rproc); int rproc_boot(struct rproc *rproc); void rproc_shutdown(struct rproc *rproc); +static inline struct rproc_vdev *vdev_to_rvdev(struct virtio_device *vdev) +{ + return container_of(vdev, struct rproc_vdev, vdev); +} + static inline struct rproc *vdev_to_rproc(struct virtio_device *vdev) { - struct rproc_vdev *rvdev = container_of(vdev, struct rproc_vdev, vdev); + struct rproc_vdev *rvdev = vdev_to_rvdev(vdev); return rvdev->rproc; } -- cgit v1.2.3-18-g5258 From 63140e0ed2e69bdafe62bc19fd6551d9213f80a7 Mon Sep 17 00:00:00 2001 From: Ohad Ben-Cohen Date: Wed, 29 Feb 2012 14:42:13 +0200 Subject: remoteproc: remove the hardcoded vring alignment Remove the hardcoded vring alignment of 4096 bytes, and instead utilize tha vring alignment as specified in the resource table. This is needed for remote processors that have rigid memory requirement, and which have found the alignment of 4096 bytes to be excessively big. Signed-off-by: Ohad Ben-Cohen Cc: Brian Swetland Cc: Iliyan Malchev Cc: Arnd Bergmann Cc: Grant Likely Cc: Rusty Russell Cc: Mark Grosen Cc: John Williams Cc: Michal Simek Cc: Loic PALLARDY Cc: Ludovic BARRE Cc: Omar Ramirez Luna Cc: Guzman Lugo Fernando Cc: Anna Suman Cc: Clark Rob Cc: Stephen Boyd Cc: Saravana Kannan Cc: David Brown Cc: Kieran Bingham Cc: Tony Lindgren --- include/linux/remoteproc.h | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h index 7750d8a3093..f1ffabb978d 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -43,13 +43,6 @@ #include #include -/* - * The alignment between the consumer and producer parts of the vring. - * Note: this is part of the "wire" protocol. If you change this, you need - * to update your peers too. - */ -#define AMP_VRING_ALIGN (4096) - /** * struct resource_table - firmware resource table header * @ver: version number @@ -423,6 +416,7 @@ struct rproc { * @dma: dma address * @len: length, in bytes * @da: device address + * @align: vring alignment * @notifyid: rproc-specific unique vring index * @rvdev: remote vdev * @vq: the virtqueue of this vring @@ -432,6 +426,7 @@ struct rproc_vring { dma_addr_t dma; int len; u32 da; + u32 align; int notifyid; struct rproc_vdev *rvdev; struct virtqueue *vq; -- cgit v1.2.3-18-g5258