linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/7] Introducing a generic AMP framework
@ 2011-10-25  9:48 Ohad Ben-Cohen
  2011-10-25  9:48 ` [PATCH 1/7] amp/remoteproc: add framework for controlling remote processors Ohad Ben-Cohen
                   ` (8 more replies)
  0 siblings, 9 replies; 34+ messages in thread
From: Ohad Ben-Cohen @ 2011-10-25  9:48 UTC (permalink / raw)
  To: linux-omap, linux-kernel, linux-arm-kernel
  Cc: akpm, Brian Swetland, Arnd Bergmann, Grant Likely, Rusty Russell,
	Tony Lindgren, Russell King, Ohad Ben-Cohen

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.

OMAP4, for example, has dual Cortex-A9, dual Cortex-M3 and a C64x+ DSP.
Typically, the dual cortex-A9 is running Linux in a SMP configuration, and
each of the other three cores (two M3 cores and a DSP) is running its own
instance of RTOS in an AMP configuration.

AMP remote processors typically employ dedicated DSP codecs and multimedia
hardware accelerators, and therefore are often used to offload cpu-intensive
multimedia tasks from the main application processor. They could also be
used to control latency-sensitive sensors, drive 'random' hardware blocks,
or just perform background tasks while the main CPU is idling.

Users of those remote processors can either be userland apps (e.g.
multimedia frameworks talking with remote OMX components) or kernel drivers
(controlling hardware accessible only by the remote processor, reserving
kernel-controlled resources on behalf of the remote processor, etc..).

This patch set adds a generic AMP framework which makes it possible to
control (power on, boot, power off) and communicate (simply send and receive
messages) with those remote processors.

Specifically, we're adding:

* Rpmsg: a virtio-based messaging bus that allows kernel drivers to
communicate with remote processors available on the system. In turn,
drivers could then expose appropriate user space interfaces, if needed
(tasks running on remote processors often have direct access to sensitive
resources like the system's physical memory, gpios, i2c buses, dma
controllers, etc..  so one normally wouldn't want to allow userland to
send everything/everywhere it wants).

Every rpmsg device is a communication channel with a service running on a
remote processor (thus rpmsg devices are called channels). Channels are
identified by a textual name (which is used to match drivers to devices)
and have a local ("source") rpmsg address, and remote ("destination") rpmsg
address. When a driver starts listening on a channel (most commonly when it
is probed), the bus assigns the driver a unique rpmsg src address (a 32 bit
integer) and binds it with the driver's rx callback handler. This way
when inbound messages arrive to this src address, the rpmsg core dispatches
them to that driver, by invoking the driver's rx handler with the payload
of the incoming message.

Once probed, rpmsg drivers can immediately start sending messages to the
remote rpmsg service by using simple sending API; no need even to specify
a destination address, since that's part of the rpmsg channel, and the rpmsg
bus uses the channel's dst address when it constructs the message (for
more demanding use cases, there's also an extended API, which does allow
full control of both the src and dst addresses).

The rpmsg bus is using virtio to send and receive messages: every pair
of processors share two vrings, which are used to send and receive the
messages over shared memory (one vring is used for rx, and the other one
for tx). Kicking the remote processor (i.e. letting it know it has a pending
message on its vring) is accomplished by means available on the platform we
run on (e.g. OMAP is using its mailbox to both interrupt the remote processor
and tell it which vring is kicked at the same time). 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.

One nice property of the rpmsg bus is that device creation is completely
dynamic: remote processors can announce the existence of remote rpmsg
services by sending a "name service" messages (which contain the name and
rpmsg addr of the remote service). Those messages are picked up by the rpmsg
bus, which in turn dynamically creates and registers the rpmsg channels
(i.e devices) which represents the remote services. If/when a relevant rpmsg
driver is registered, it will be immediately probed by the bus, and can then
start "talking" to the remote service.

Similarly, we can use this technique to dynamically create virtio devices
(and new vrings) which would then represent e.g. remote network, console
and block devices that will be driven by the existing virtio drivers
(this is still not implemented though; it requires some RTOS work as we're
currently not booting Linux on OMAP's remote processors). Creating new vrings
might also be desired by users who just don't want to use the shared rpmsg
vrings (for performance or any other functional reasons).

There are already several immediate use cases for rpmsg drivers: OMX
offloading (already being used on OMAP4), hardware resource manager (remote
processors on OMAP4 need to ask Linux to enable/disable hardware resources
on its behalf), remote display driver on Netra (dm8168), where the display
is controlled by a remote M3 processor (and a Linux v4l2/fbdev driver will
use rpmsg to communicate with that remote display driver).

* Remoteproc: a generic framework with which AMP remote processors can
be controlled (powered up/down) using a simple rproc_boot() and
rproc_shutdown() API. A power refcount is maintained, so repeated invocations
of rproc_boot(), and all but the last invocation of rproc_shutdown() will
just immediately return (successfully). Note that rproc_boot() and
rproc_shutdown() take an rproc handle, and are designed for users who already
have a valid rproc handle. In addition, we also have rproc_get_by_name()
and rproc_put() for users which don't have an rproc handle (those functions
manipulate a second refcount which represents the number of users owning
a valid pointer of the rproc object. when that refcount goes to zero, the
rproc object is released). The intention, though, is to move away from
name-based API, as it doesn't scale well.

At this point the latter name-based API isn't even used; I kept it because
I know there are users out there that expect this model, but those use cases
should be scrutinized and preferably migrated to the non name-based model,
and then we can just remove this get_by_name() API.

Hardware differences are abstracted as usual: a platform-specific driver
registers its own start/stop/kick handlers, and those are invoked when its
time to power up/down the processor, or tell it there's a pending message
waiting to be processed, respectively.

Changes from the previous RFC submission:
- We no longer use omap-specific IOMMU API. In fact, the omap rproc driver
  does not do _any_ IOMMU stuff anymore: everything is done generically
  in the remoteproc core, so things sould just work for other platforms too
  (as long as they support the generic IOMMU API). Moreover, IOMMU-related
  stuff that isn't remoteproc-specific is being pushed to the IOMMU API
  instead of implementing it at the remoteproc level (e.g. splitting
  IOMMU mapping to page sizes as supported by the hardware). This way
  remoteproc gets simplified, and other users of the IOMMU API can use
  that functionality too.
  Note: The IOMMU API is only being used where the firmware of the remote
  processor has hardcoded device addresses which cannot be allocated
  dynamically. Where this limitation does not apply, it is expected that
  the upcoming generic iommu-based DMA API will take care of IOMMU mapping.
- We no longer use reserve+ioremap to allocate physically contiguous
  non-cacheable memory. Instead, we're now using CMA with dma_alloc_coherent.
  As a result, one of the patches (the ARM one) now depends on CMA, which is
  still out of tree, but it's still much better than the alternative: the code
  is much cleaner this way (rpmsg bus can simply use the DMA API to grab
  its buffers) and it's generally better that amp users will focus on
  on testing CMA rather than adopting the workarounds we previously had.
- We no longer have platform-specific rpmsg part. Instead, the virtio
  device is added by the remoteproc core itself, as well as the entire set
  of virtio_config_ops handlers. This way we don't need to duplicate these
  handlers for every platform that wants to support rpmsg. Most of that code
  was generic anyway; the only difference between different platforms would
  have been the implementation of ->kick(), which is now added as a
  third handler that remoteproc drivers need to provide. There are several
  other strong advantages for having remoteproc provide this functionality
  rather than keep it independent; see the commit logs for more details.
- We moved to ELF, in the hopes that this will be useful for others too.
  Though it's probably inevitable that other platforms, which we'd like to
  support with this framework at some point, will be based on different binary
  formats. When those users show up we'd probably have to decouple the
  binary format from the core, so we could support them too. At this point
  though the move to ELF was clearly the right thing to do: the code is both
  cleaner and more useful to others (thanks to Arnd and Stephen boyd for
  suggesting ELF).
- remoteproc now uses a klist to maintain the available rprocs (safer, easier)
- remoteproc now uses a kref to maintain the number of rproc copies (Grant)
- remoteproc/debugfs: open code the macros for better readability (Arnd)
- remoteproc/debugfs: split to a different patch/file (Grant)
- ditch the overkill alignment rpmsg_device_id had (Rusty)
- #define VIRTIO_ID_RPMSG 7 (Rusty)
- add an (initial) rpmsg appendix to the virtio spec (Sasha Levin)
- expose the virtio Kconfig to non-virtualisation users (Grant, Randy, Arnd)
- don't kfree a device after put()'ing it (Grant)
- handle register_driver_virtio() failures (Grant)
- prefix init/exit rpmsg functions (Grant)
- Numerous documentation improvements and fixes (Randy)
- s/static inline/static/ (Will Newton)
- no need to pass owner to remoteproc core; it can get it from pdev (Grant)
- remoteproc: use strnlen (akpm)
- remoteproc: s/fogot/forgot/ (akpm)
- remoteproc: try to move away from name-based APIs (Grant)
- remoteproc: power and number of valid users are 2 separate refcounts,
              that also deserve two separate API sets (Grant)
- remoteproc: introduce alloc+add (Grant)
- remoteproc: unregister() should take the previously registered handle (Grant)
- remoteproc: lookup table for state strings (Grant)
- remoteproc: use mutex to protect the rprocs list (Grant)

(thanks everyone for the review!)

I'd also like to thank Iliyan Malchev, Todd Poynor and Rocky Rhodes for
reviewing the code internally (comments were squashed in the previous
RFC submission).

Stuff still in the pipeline:
a) support remoteproc dependencies (core a depends on core b), needed for both
  msm and omap
b) firmware: use TLV-based resource entries (cleaner, typesafer, flexible).
c) use a single resource entry for a complete VIRTIO header (see the patches 
  for more info)
  
I've removed the support for OMAP4's 2nd M3 core until item (a) is completed,
because that 2nd core depends on the first one due to unicache
and AMMU ownership issues (since we moved to ELF, we no longer have
a single image for both cores).

I've also removed the support for static rpmsg channels until
(b)+(c) are completed, because both are needed to implement it properly
(static channels is a firmware property. it should come from
the resource table, and be exposed to the rpmsg bus via the virtio config
space).

In addition there's a bunch of functionality waiting (error recovery,
runtime PM, socket interface, ...) but that will wait until we nail the
basics first.


Important stuff:

* Thanks Brian Swetland for great design ideas and fruitful meetings and
  Arnd Bergmann for pointing us at virtio (and Rusty for creating it :).

* Thanks Bhavin Shah, Mark Grosen, Suman Anna, Fernando Guzman Lugo,
  Iliyan Malchev, Shreyas Prasad, Gilbert Pitney, Armando Uribe De Leon,
  Robert Tivy and Alan DeMars for all your help. You know what you did.

* This patch set includes support for OMAP4, and was tested on the PandaBoard.
  We're refreshing the DaVinci patches too, and will be submitting them
  separately (or in the next iteration).

* Patches are based on 3.1-rc9, with quite a few dependencies:
  - CMA patches from Marek
  - Kevin's omap_device-2 branch
  - Joerg's iommu master branch
  - an omap/iommu patch: https://lkml.org/lkml/2011/9/25/44
  - an omap_device patch: http://www.spinics.net/lists/linux-omap/msg59342.html
  - an ARM/archdata patch: https://lkml.org/lkml/2011/9/25/42
  - iommu pgsize pile: http://www.spinics.net/lists/linux-omap/msg59341.html

  Everything is also available at:
  git://git.wizery.com/pub/rpmsg.git rpmsg_3.1_rc9

* The M3 RTOS source code itself is BSD licensed. An M3 RTOS code base that
  works with the abovementioned rpmsg tree is available at:
  git://git.wizery.com/pub/sysbios-rpmsg.git rpmsg_3.1_rc9

  (Note: I have trees with the latest code on github too, but those
   frequently get rebased and changed, so use with tolerance)

* Licensing: definitions that needs to be shared with remote processors
 were put in BSD-licensed header files, so anyone can use them to develop
 compatible peers.

Ohad Ben-Cohen (7):
  amp/remoteproc: add framework for controlling remote processors
  amp/remoteproc: add debugfs entries
  amp/remoteproc: create rpmsg virtio device
  amp/omap: add a remoteproc driver
  ARM: OMAP: add amp/remoteproc support
  amp/rpmsg: add virtio-based remote processor messaging bus
  samples/amp: add an rpmsg driver sample

 Documentation/ABI/testing/sysfs-bus-rpmsg    |   75 ++
 Documentation/amp/remoteproc.txt             |  324 ++++++
 Documentation/amp/rpmsg.txt                  |  293 ++++++
 Documentation/virtual/virtio-spec.txt        |   94 ++
 MAINTAINERS                                  |   13 +
 arch/arm/mach-omap2/Makefile                 |    4 +
 arch/arm/mach-omap2/remoteproc.c             |  167 +++
 arch/arm/plat-omap/common.c                  |    3 +-
 arch/arm/plat-omap/include/plat/remoteproc.h |   56 +
 drivers/Kconfig                              |    2 +
 drivers/Makefile                             |    1 +
 drivers/amp/Kconfig                          |   11 +
 drivers/amp/Makefile                         |    2 +
 drivers/amp/remoteproc/Kconfig               |   36 +
 drivers/amp/remoteproc/Makefile              |   10 +
 drivers/amp/remoteproc/omap_remoteproc.c     |  248 +++++
 drivers/amp/remoteproc/omap_remoteproc.h     |   69 ++
 drivers/amp/remoteproc/remoteproc_core.c     | 1410 ++++++++++++++++++++++++++
 drivers/amp/remoteproc/remoteproc_debugfs.c  |  182 ++++
 drivers/amp/remoteproc/remoteproc_internal.h |   44 +
 drivers/amp/remoteproc/remoteproc_rpmsg.c    |  297 ++++++
 drivers/amp/rpmsg/Kconfig                    |    6 +
 drivers/amp/rpmsg/Makefile                   |    2 +
 drivers/amp/rpmsg/virtio_rpmsg_bus.c         | 1026 +++++++++++++++++++
 include/linux/amp/remoteproc.h               |  265 +++++
 include/linux/amp/rpmsg.h                    |  326 ++++++
 include/linux/mod_devicetable.h              |    9 +
 include/linux/virtio_ids.h                   |    1 +
 samples/Kconfig                              |    8 +
 samples/Makefile                             |    2 +-
 samples/amp/Makefile                         |    1 +
 samples/amp/rpmsg_client_sample.c            |  100 ++
 32 files changed, 5085 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-rpmsg
 create mode 100644 Documentation/amp/remoteproc.txt
 create mode 100644 Documentation/amp/rpmsg.txt
 create mode 100644 arch/arm/mach-omap2/remoteproc.c
 create mode 100644 arch/arm/plat-omap/include/plat/remoteproc.h
 create mode 100644 drivers/amp/Kconfig
 create mode 100644 drivers/amp/Makefile
 create mode 100644 drivers/amp/remoteproc/Kconfig
 create mode 100644 drivers/amp/remoteproc/Makefile
 create mode 100644 drivers/amp/remoteproc/omap_remoteproc.c
 create mode 100644 drivers/amp/remoteproc/omap_remoteproc.h
 create mode 100644 drivers/amp/remoteproc/remoteproc_core.c
 create mode 100644 drivers/amp/remoteproc/remoteproc_debugfs.c
 create mode 100644 drivers/amp/remoteproc/remoteproc_internal.h
 create mode 100644 drivers/amp/remoteproc/remoteproc_rpmsg.c
 create mode 100644 drivers/amp/rpmsg/Kconfig
 create mode 100644 drivers/amp/rpmsg/Makefile
 create mode 100644 drivers/amp/rpmsg/virtio_rpmsg_bus.c
 create mode 100644 include/linux/amp/remoteproc.h
 create mode 100644 include/linux/amp/rpmsg.h
 create mode 100644 samples/amp/Makefile
 create mode 100644 samples/amp/rpmsg_client_sample.c

-- 
1.7.5.4


^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 1/7] amp/remoteproc: add framework for controlling remote processors
  2011-10-25  9:48 [PATCH 0/7] Introducing a generic AMP framework Ohad Ben-Cohen
@ 2011-10-25  9:48 ` Ohad Ben-Cohen
  2011-10-26  5:16   ` Jean-Christophe PLAGNIOL-VILLARD
                     ` (2 more replies)
  2011-10-25  9:48 ` [PATCH 2/7] amp/remoteproc: add debugfs entries Ohad Ben-Cohen
                   ` (7 subsequent siblings)
  8 siblings, 3 replies; 34+ messages in thread
From: Ohad Ben-Cohen @ 2011-10-25  9:48 UTC (permalink / raw)
  To: linux-omap, linux-kernel, linux-arm-kernel
  Cc: akpm, Brian Swetland, Arnd Bergmann, Grant Likely, Rusty Russell,
	Tony Lindgren, Russell King, Ohad Ben-Cohen, Greg KH,
	Stephen Boyd

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
<fernando.lugo@ti.com>.

ELF loader was written by Mark Grosen <mgrosen@ti.com>, based on
msm's Peripheral Image Loader (PIL) by Stephen Boyd <sboyd@codeaurora.org>.

Designed with Brian Swetland <swetland@google.com>.

Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Cc: Brian Swetland <swetland@google.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Tony Lindgren <tony@atomide.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Greg KH <greg@kroah.com>
Cc: Stephen Boyd <sboyd@codeaurora.org>
---
 Documentation/amp/remoteproc.txt             |  324 ++++++
 MAINTAINERS                                  |    7 +
 drivers/Kconfig                              |    2 +
 drivers/Makefile                             |    1 +
 drivers/amp/Kconfig                          |    9 +
 drivers/amp/Makefile                         |    1 +
 drivers/amp/remoteproc/Kconfig               |    3 +
 drivers/amp/remoteproc/Makefile              |    6 +
 drivers/amp/remoteproc/remoteproc_core.c     | 1410 ++++++++++++++++++++++++++
 drivers/amp/remoteproc/remoteproc_internal.h |   44 +
 include/linux/amp/remoteproc.h               |  265 +++++
 11 files changed, 2072 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/amp/remoteproc.txt
 create mode 100644 drivers/amp/Kconfig
 create mode 100644 drivers/amp/Makefile
 create mode 100644 drivers/amp/remoteproc/Kconfig
 create mode 100644 drivers/amp/remoteproc/Makefile
 create mode 100644 drivers/amp/remoteproc/remoteproc_core.c
 create mode 100644 drivers/amp/remoteproc/remoteproc_internal.h
 create mode 100644 include/linux/amp/remoteproc.h

diff --git a/Documentation/amp/remoteproc.txt b/Documentation/amp/remoteproc.txt
new file mode 100644
index 0000000..63cecd9
--- /dev/null
+++ b/Documentation/amp/remoteproc.txt
@@ -0,0 +1,324 @@
+Remote Processor Framework
+
+1. Introduction
+
+Modern SoCs typically have heterogeneous remote processor devices in asymmetric
+multiprocessing (AMP) configurations, which may be running different instances
+of operating system, whether it's Linux or any other flavor of real-time OS.
+
+OMAP4, for example, has dual Cortex-A9, dual Cortex-M3 and a C64x+ DSP.
+In a typical configuration, the dual cortex-A9 is running Linux in a SMP
+configuration, and each of the other three cores (two M3 cores and a DSP)
+is running its own instance of RTOS in an AMP configuration.
+
+The remoteproc framework allows different platforms/architectures to
+control (power on, load firmware, power off) those remote processors while
+abstracting the hardware differences, so the entire driver doesn't need to be
+duplicated. In addition, this framework also adds rpmsg virtio devices
+for remote processors that supports this kind of communication. This way,
+platform-specific remoteproc drivers only need to provide a few low-level
+handlers, and then all rpmsg drivers will then just work
+(for more information about the virtio-based rpmsg bus and its drivers,
+please read Documentation/amp/rpmsg.txt).
+
+2. User API
+
+  int rproc_boot(struct rproc *rproc)
+    - Boot a remote processor (i.e. load its firmware, power it on, ...).
+      If the remote processor is already powered on, this function immediately
+      returns (successfully).
+      Returns 0 on success, and an appropriate error value otherwise.
+      Note: to use this function you should already have a valid rproc
+      handle. There are several ways to achieve that cleanly (devres, pdata,
+      the way remoteproc_rpmsg.c does this, or, if this becomes prevalent, we
+      might also consider using dev_archdata for this). See also
+      rproc_get_by_name() below.
+
+  void rproc_shutdown(struct rproc *rproc)
+    - Power off a remote processor (previously booted with rproc_boot()).
+      In case @rproc is still being used by an additional user(s), then
+      this function will just decrement the power refcount and exit,
+      without really powering off the device.
+      Every call to rproc_boot() must (eventually) be accompanied by a call
+      to rproc_shutdown(). Calling rproc_shutdown() redundantly is a bug.
+      Notes:
+      - we're not decrementing the rproc's refcount, only the power refcount.
+        which means that the @rproc handle stays valid even after
+        rproc_shutdown() returns, and users can still use it with a subsequent
+        rproc_boot(), if needed.
+      - don't call rproc_shutdown() to unroll rproc_get_by_name(), exactly
+        because rproc_shutdown() _does not_ decrement the refcount of @rproc.
+        To decrement the refcount of @rproc, use rproc_put() (but _only_ if
+        you acquired @rproc using rproc_get_by_name()).
+
+  struct rproc *rproc_get_by_name(const char *name)
+    - Find an rproc handle using the remote processor's name, and then
+      boot it. If it's already powered on, then just immediately return
+      (successfully). Returns the rproc handle on success, and NULL on failure.
+      This function increments the remote processor's refcount, so always
+      use rproc_put() to decrement it back once rproc isn't needed anymore.
+      Note: currently this function (and its counterpart rproc_put()) are not
+      used anymore by the amp sub-system. We need to scrutinize the use cases
+      that still need them, and see if we can migrate them to use the non
+      name-based boot/shutdown interface.
+
+  void rproc_put(struct rproc *rproc)
+    - Decrement @rproc's power refcount and shut it down if it reaches zero
+      (essentially by just calling rproc_shutdown), and then decrement @rproc's
+      validity refcount too.
+      After this function returns, @rproc may _not_ be used anymore, and its
+      handle should be considered invalid.
+      This function should be called _iff_ the @rproc handle was grabbed by
+      calling rproc_get_by_name().
+
+3. Typical usage
+
+#include <linux/amp/remoteproc.h>
+
+/* in case we were given a valid 'rproc' handle */
+int dummy_rproc_example(struct rproc *my_rproc)
+{
+	int ret;
+
+	/* let's power on and boot our remote processor */
+	ret = rproc_boot(my_rproc);
+	if (ret) {
+		/*
+		 * something went wrong. handle it and leave.
+		 */
+	}
+
+	/*
+	 * our remote processor is now powered on... give it some work
+	 */
+
+	/* let's shut it down now */
+	rproc_shutdown(my_rproc);
+}
+
+4. API for implementors
+
+  struct rproc *rproc_alloc(struct device *dev, const char *name,
+				const struct rproc_ops *ops,
+				const char *firmware, int len)
+    - Allocate a new remote processor handle, but don't register
+      it yet. Required parameters are the underlying device, the
+      name of this remote processor, platform-specific ops handlers,
+      the name of the firmware to boot this rproc with, and the
+      length of private data needed by the allocating rproc driver (in bytes).
+
+      This function should be used by rproc implementations during
+      initialization of the remote processor.
+      After creating an rproc handle using this function, and when ready,
+      implementations should then call rproc_register() to complete
+      the registration of the remote processor.
+      On success, the new rproc is returned, and on failure, NULL.
+
+      Note: _never_ directly deallocate @rproc, even if it was not registered
+      yet. Instead, if you just need to unroll rproc_alloc(), use rproc_free().
+
+  void rproc_free(struct rproc *rproc)
+    - Free an rproc handle that was allocated by rproc_alloc.
+      This function should _only_ be used if @rproc was only allocated,
+      but not registered yet.
+      If @rproc was already successfully registered (by calling
+      rproc_register()), then use rproc_unregister() instead.
+
+  int rproc_register(struct rproc *rproc)
+    - Register @rproc with the remoteproc framework, after it has been
+      allocated with rproc_alloc().
+      This is called by the platform-specific rproc implementation, whenever
+      a new remote processor device is probed.
+      Returns 0 on success and an appropriate error code otherwise.
+      Note: this function initiates an asynchronous firmware loading
+      context, which will look for virtio devices supported by the rproc's
+      firmware.
+      If found, those virtio devices will be created and added, so as a result
+      of registering this remote processor, additional virtio drivers might get
+      probed.
+      Currently, though, we only support a single RPMSG virtio vdev per remote
+      processor.
+
+  int rproc_unregister(struct rproc *rproc)
+    - Unregister a remote processor, and decrement its refcount.
+      If its refcount drops to zero, then @rproc will be freed. If not,
+      it will be freed later once the last reference is dropped.
+
+      This function should be called when the platform specific rproc
+      implementation decides to remove the rproc device. it should
+      _only_ be called if a previous invocation of rproc_register()
+      has completed successfully.
+
+      After rproc_unregister() returns, @rproc is _not_ valid anymore and
+      it shouldn't be used. More specifically, don't call rproc_free()
+      or try to directly free @rproc after rproc_unregister() returns;
+      none of these are needed, and calling them is a bug.
+
+      Returns 0 on success and -EINVAL if @rproc isn't valid.
+
+5. Implementation callbacks
+
+These callbacks should be provided by platform-specific remoteproc
+drivers:
+
+/**
+ * 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);
+};
+
+Every remoteproc implementation should at least provide the ->start and ->stop
+handlers. If rpmsg functionality is also desired, then the ->kick handler
+should be provided as well.
+
+The ->start() handler takes an rproc handle and should then power on the
+device and boot it (use rproc->priv to access platform-specific private data).
+The boot address, in case needed, can be found in rproc->bootaddr (remoteproc
+core puts there the ELF entry point).
+On success, 0 should be returned, and on failure, an appropriate error code.
+
+The ->stop() handler takes an rproc handle and powers the device down.
+On success, 0 is returned, and on failure, an appropriate error code.
+
+The ->kick() handler takes an rproc handle, and an index of a virtqueue
+where new message was placed in. Implementations should interrupt the remote
+processor and let it know it has pending messages. Notifying remote processors
+the exact virtqueue index to look in is optional: it is easy (and not
+too expensive) to go through the existing virtqueues and look for new buffers
+in the used rings.
+
+6. Binary Firmware Structure
+
+At this point remoteproc only supports ELF32 firmware binaries. However,
+it is quite expected that other platforms/devices which we'd want to
+support with this framework will be based on different binary formats.
+
+When those use cases show up, we will have to decouple the binary format
+from the framework core, so we can support several binary formats without
+duplicating common code.
+
+When the firmware is parsed, its various segments are loaded to memory
+according to the specified device address (might be a physical address
+if the remote processor is accessing memory directly).
+
+In addition to the standard ELF segments, most remote processors would
+also include a special section which we call "the resource table".
+
+The resource table contains system resources that the remote processor
+requires before it should be powered on, such as allocation of physically
+contiguous memory, or iommu mapping of certain on-chip peripherals.
+Remotecore will only power up the device after all the resource table's
+requirement are met.
+
+In addition to system resources, the resource table may also contain
+resource entries that publish the existence of supported features
+or configurations by the remote processor, such as trace buffers and
+supported virtio devices (and their configurations).
+
+Currently the resource table is just an array of:
+
+/**
+ * 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 fw_resource {
+	u32 type;
+	u32 id;
+	u64 da;
+	u64 pa;
+	u32 len;
+	u32 flags;
+	u8 reserved[16];
+	u8 name[48];
+} __packed;
+
+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 will begin with a type and length fields, followed by
+its own specific structure.
+
+Here are the resource types that are currently being used:
+
+/**
+ * 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: announces support for a virtio device, and serves as
+ *		    the virtio header. 'da' contains the virtio device
+ *		    features, 'pa' holds the virtio guest features (host
+ *		    will write them here after they're negotiated), 'len'
+ *		    holds the virtio status, and 'flags' holds the virtio
+ *		    device id (currently only VIRTIO_ID_RPMSG is supported).
+ */
+enum fw_resource_type {
+	RSC_CARVEOUT	= 0,
+	RSC_DEVMEM	= 1,
+	RSC_TRACE	= 2,
+	RSC_VRING	= 3,
+	RSC_VIRTIO_DEV	= 4,
+	RSC_VIRTIO_CFG	= 5,
+};
+
+Most of the resource entries share the basic idea of address/length
+negotiation with the host: the firmware usually asks 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).
+
+We also expect that platform-specific resource entries will show up
+at some point. When that happens, we could easily add a new RSC_PLAFORM
+type, and hand those resources to the platform-specific rproc driver to handle.
+
+7. Virtio and remoteproc
+
+The firmware should provide remoteproc information about virtio devices
+that it supports, and their configurations: a RSC_VIRTIO_DEV resource entry
+should specify the virtio device id, and subsequent RSC_VRING resource entries
+should indicate the vring size (i.e. how many buffers do they support) and
+where should they be mapped (i.e. which device address). Note: the alignment
+between the consumer and producer parts of the vring is assumed to be 4096.
+
+At this point we only support a single virtio rpmsg device per remote
+processor, but the plan is to remove this limitation. In addition, once we
+move to TLV-based resource table, the plan is to have a single RSC_VIRTIO
+entry per supported virtio device, which will include the virtio header,
+the vrings information and the virtio config space.
+
+Of course, RSC_VIRTIO resource entries are only good enough for static
+allocation of virtio devices. Dynamic allocations will also be made possible
+using the rpmsg bus (similar to how we already do dynamic allocations of
+rpmsg channels; read more about it in rpmsg.txt).
diff --git a/MAINTAINERS b/MAINTAINERS
index ace8f9c..2812cd7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1205,6 +1205,13 @@ L:	lm-sensors@lm-sensors.org
 S:	Maintained
 F:	drivers/hwmon/asb100.c
 
+ASYNCHRONOUS MULTIPROCESSING (AMP) FRAMEWORK
+M:	Ohad Ben-Cohen <ohad@wizery.com>
+S:	Maintained
+F:	drivers/amp/
+F:	Documentation/amp/
+F:	include/linux/amp/
+
 ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT) API
 M:	Dan Williams <dan.j.williams@intel.com>
 W:	http://sourceforge.net/projects/xscaleiop
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 95b9e7e..dfb7d36 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -128,6 +128,8 @@ source "drivers/clocksource/Kconfig"
 
 source "drivers/iommu/Kconfig"
 
+source "drivers/amp/Kconfig"
+
 source "drivers/virt/Kconfig"
 
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 7fa433a..8f41a77 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -124,6 +124,7 @@ obj-y				+= clk/
 obj-$(CONFIG_HWSPINLOCK)	+= hwspinlock/
 obj-$(CONFIG_NFC)		+= nfc/
 obj-$(CONFIG_IOMMU_SUPPORT)	+= iommu/
+obj-y				+= amp/
 
 # Virtualization drivers
 obj-$(CONFIG_VIRT_DRIVERS)	+= virt/
diff --git a/drivers/amp/Kconfig b/drivers/amp/Kconfig
new file mode 100644
index 0000000..23a8ed1
--- /dev/null
+++ b/drivers/amp/Kconfig
@@ -0,0 +1,9 @@
+#
+# AMP subsystem configuration
+#
+
+menu "Asymmetric Multiprocessing (AMP) Framework"
+
+source "drivers/amp/remoteproc/Kconfig"
+
+endmenu
diff --git a/drivers/amp/Makefile b/drivers/amp/Makefile
new file mode 100644
index 0000000..708461d
--- /dev/null
+++ b/drivers/amp/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_REMOTEPROC)	+= remoteproc/
diff --git a/drivers/amp/remoteproc/Kconfig b/drivers/amp/remoteproc/Kconfig
new file mode 100644
index 0000000..b250b15
--- /dev/null
+++ b/drivers/amp/remoteproc/Kconfig
@@ -0,0 +1,3 @@
+# REMOTEPROC gets selected by whoever wants it
+config REMOTEPROC
+	tristate
diff --git a/drivers/amp/remoteproc/Makefile b/drivers/amp/remoteproc/Makefile
new file mode 100644
index 0000000..2a5fd79
--- /dev/null
+++ b/drivers/amp/remoteproc/Makefile
@@ -0,0 +1,6 @@
+#
+# Generic framework for controlling remote processors
+#
+
+obj-$(CONFIG_REMOTEPROC)		+= remoteproc.o
+remoteproc-y				:= remoteproc_core.o
diff --git a/drivers/amp/remoteproc/remoteproc_core.c b/drivers/amp/remoteproc/remoteproc_core.c
new file mode 100644
index 0000000..be6774f
--- /dev/null
+++ b/drivers/amp/remoteproc/remoteproc_core.c
@@ -0,0 +1,1410 @@
+/*
+ * Remote Processor Framework
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ * Mark Grosen <mgrosen@ti.com>
+ * Fernando Guzman Lugo <fernando.lugo@ti.com>
+ * Suman Anna <s-anna@ti.com>
+ * Robert Tivy <rtivy@ti.com>
+ * Armando Uribe De Leon <x0095078@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)    "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
+#include <linux/string.h>
+#include <linux/debugfs.h>
+#include <linux/amp/remoteproc.h>
+#include <linux/iommu.h>
+#include <linux/klist.h>
+#include <linux/elf.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_ring.h>
+
+#include "remoteproc_internal.h"
+
+static void klist_rproc_get(struct klist_node *n);
+static void klist_rproc_put(struct klist_node *n);
+
+/*
+ * klist of the available remote processors.
+ *
+ * We need this in order to support name-based lookups (needed by the
+ * rproc_get_by_name()).
+ *
+ * That said, we don't use rproc_get_by_name() anymore within the amp
+ * framework. The use cases that do require its existence should be
+ * scrutinized, and hopefully migrated to rproc_boot() using device-based
+ * binding.
+ *
+ * If/when this materializes, we could drop the klist (and the by_name
+ * API).
+ */
+static DEFINE_KLIST(rprocs, klist_rproc_get, klist_rproc_put);
+
+typedef int (*rproc_handle_resources_t)(struct rproc *rproc,
+				struct fw_resource *rsc, int len);
+
+/*
+ * This is the IOMMU fault handler we register with the IOMMU API
+ * (when relevant; not all remote processors access memory through
+ * an IOMMU).
+ *
+ * IOMMU core will invoke this handler whenever the remote processor
+ * will try to access an unmapped device address.
+ *
+ * Currently this is mostly a stub, but it will be later used to trigger
+ * the recovery of the remote processor.
+ */
+static int rproc_iommu_fault(struct iommu_domain *domain, struct device *dev,
+		unsigned long iova, int flags)
+{
+	dev_err(dev, "iommu fault: da 0x%lx flags 0x%x\n", iova, flags);
+
+	/*
+	 * Let the iommu core know we're not really handling this fault;
+	 * we just plan to use this as a recovery trigger.
+	 */
+	return -ENOSYS;
+}
+
+static int rproc_enable_iommu(struct rproc *rproc)
+{
+	struct iommu_domain *domain;
+	struct device *dev = rproc->dev;
+	int ret;
+
+	/*
+	 * We currently use iommu_present() to decide if an IOMMU
+	 * setup is needed.
+	 *
+	 * This works for simple cases, but will easily fail with
+	 * platforms that do have an IOMMU, but not for this specific
+	 * rproc.
+	 *
+	 * This will be easily solved by introducing hw capabilities
+	 * that will be set by the remoteproc driver.
+	 */
+	if (!iommu_present(dev->bus)) {
+		dev_err(dev, "iommu not found\n");
+		return -ENODEV;
+	}
+
+	domain = iommu_domain_alloc(dev->bus);
+	if (!domain) {
+		dev_err(dev, "can't alloc iommu domain\n");
+		return -ENOMEM;
+	}
+
+	iommu_set_fault_handler(domain, rproc_iommu_fault);
+
+	ret = iommu_attach_device(domain, dev);
+	if (ret) {
+		dev_err(dev, "can't attach iommu device: %d\n", ret);
+		goto free_domain;
+	}
+
+	rproc->domain = domain;
+
+	return 0;
+
+free_domain:
+	iommu_domain_free(domain);
+	return ret;
+}
+
+static void rproc_disable_iommu(struct rproc *rproc)
+{
+	struct iommu_domain *domain = rproc->domain;
+	struct device *dev = rproc->dev;
+
+	if (!domain)
+		return;
+
+	iommu_detach_device(domain, dev);
+	iommu_domain_free(domain);
+
+	return;
+}
+
+/*
+ * Some remote processors will ask us to allocate them physically contiguous
+ * memory regions (which we call "carveouts"), and map them to specific
+ * device addresses (which are hardcoded in the firmware).
+ *
+ * They may then ask us to copy objects into specific device addresses (e.g.
+ * code/data sections) or expose us certain symbols in other device address
+ * (e.g. their trace buffer).
+ *
+ * This function is an internal helper with which we can go over the allocated
+ * carveouts and translate specific device address to kernel virtual addresses
+ * so we can access the referenced memory.
+ *
+ * Note: phys_to_virt(iommu_iova_to_phys(rproc->domain, da)) will work too,
+ * but only on kernel direct mapped RAM memory. Instead, we're just using
+ * here the output of the DMA API, which should be more correct.
+ */
+static void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+{
+	struct rproc_mem_entry *carveout;
+	void *ptr = NULL;
+
+	list_for_each_entry(carveout, &rproc->carveouts, node) {
+		int offset = da - carveout->da;
+
+		/* try next carveout if da is too small */
+		if (offset < 0)
+			continue;
+
+		/* try next carveout if da is too large */
+		if (offset + len > carveout->len)
+			continue;
+
+		ptr = carveout->va + offset;
+
+		break;
+	}
+
+	return ptr;
+}
+
+/**
+ * rproc_load_segments() - load firmware segments to memory
+ * @rproc: remote processor which will be booted using these fw segments
+ * @elf_data: the content of the ELF firmware image
+ *
+ * This function loads the firmware segments to memory, where the remote
+ * processor expects them.
+ *
+ * Some remote processors will expect their code and data to be placed
+ * in specific device addresses, and can't have them dynamically assigned.
+ *
+ * We currently support only those kind of remote processors, and expect
+ * the program header's paddr member to contain those addresses. We then go
+ * through the physically contiguous "carveout" memory regions which we
+ * allocated (and mapped) earlier on behalf of the remote processor,
+ * and "translate" device address to kernel addresses, so we can copy the
+ * segments where they are expected.
+ *
+ * Currently we only support remote processors that required carveout
+ * allocations and got them mapped onto their iommus. Some processors
+ * might be different: they might not have iommus, and would prefer to
+ * directly allocate memory for every segment/resource. This is not yet
+ * supported, though.
+ */
+static int rproc_load_segments(struct rproc *rproc, const u8 *elf_data)
+{
+	struct device *dev = rproc->dev;
+	struct elf32_hdr *ehdr;
+	struct elf32_phdr *phdr;
+	int i, ret = 0;
+
+	ehdr = (struct elf32_hdr *)elf_data;
+	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
+
+	/* go through the available ELF segments */
+	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
+		u32 da = phdr->p_paddr;
+		u32 memsz = phdr->p_memsz;
+		u32 filesz = phdr->p_filesz;
+		void *ptr;
+
+		if (phdr->p_type != PT_LOAD)
+			continue;
+
+		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
+					phdr->p_type, da, memsz, filesz);
+
+		if (filesz > memsz) {
+			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
+							filesz, memsz);
+			ret = -EINVAL;
+			break;
+		}
+
+		/* grab the kernel address for this device address */
+		ptr = rproc_da_to_va(rproc, da, memsz);
+		if (!ptr) {
+			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
+			ret = -EINVAL;
+			break;
+		}
+
+		/* put the segment where the remote processor expects it */
+		if (phdr->p_filesz)
+			memcpy(ptr, elf_data + phdr->p_offset, filesz);
+
+		/*
+		 * Zero out remaining memory for this segment.
+		 *
+		 * This isn't strictly required since dma_alloc_coherent already
+		 * did this for us. albeit harmless, we may consider removing
+		 * this.
+		 */
+		if (memsz > filesz)
+			memset(ptr + filesz, 0, memsz - filesz);
+	}
+
+	return ret;
+}
+
+/**
+ * rproc_handle_virtio_hdr() - handle a virtio header resource
+ * @rproc: the remote processor
+ * @rsc: the resource descriptor
+ *
+ * The existence of this virtio hdr resource entry means that the firmware
+ * of this @rproc supports this virtio device.
+ *
+ * Currently we support only a single virtio device of type VIRTIO_ID_RPMSG,
+ * but the plan is to remove this limitation and support any number
+ * of virtio devices (and of any type). We'll also add support for dynamically
+ * adding (and removing) virtio devices over the rpmsg bus, but small
+ * firmwares that doesn't want to get involved with rpmsg will be able
+ * to simple use the resource table for this.
+ *
+ * At this point this virtio header entry is rather simple: it just
+ * announces the virtio device id and the supported virtio device features.
+ * The plan though is to extend this to include the vring information and
+ * the virtio config space, too (but first, some resource table overhaul
+ * is needed: move from fixed-sized to variable-length TLV entries).
+ *
+ * For now, the 'flags' member of the resource entry contains the virtio
+ * device id, the 'da' member contains the device features, and 'pa' is
+ * where we need to store the guest features once negotiation completes.
+ * As usual, the 'id' member of this resource contains the index of this
+ * resource type (i.e. is this the first virtio hdr entry, the 2nd, ...).
+ *
+ * Returns 0 on success, or an appropriate error code otherwise
+ */
+static int rproc_handle_virtio_hdr(struct rproc *rproc, struct fw_resource *rsc)
+{
+	struct rproc_vdev *rvdev;
+
+	/* we only support VIRTIO_ID_RPMSG devices for now */
+	if (rsc->flags != VIRTIO_ID_RPMSG) {
+		dev_warn(rproc->dev, "unsupported vdev: %d\n", rsc->flags);
+		return -EINVAL;
+	}
+
+	/* we only support a single vdev per rproc for now */
+	if (rsc->id || rproc->rvdev) {
+		dev_warn(rproc->dev, "redundant vdev entry: %s\n", rsc->name);
+		return -EINVAL;
+	}
+
+	rvdev = kzalloc(sizeof(struct rproc_vdev), GFP_KERNEL);
+	if (!rvdev)
+		return -ENOMEM;
+
+	/* remember the device features */
+	rvdev->dfeatures = rsc->da;
+
+	rproc->rvdev = rvdev;
+	rvdev->rproc = rproc;
+
+	return 0;
+}
+
+/**
+ * rproc_handle_vring() - handle a vring fw resource
+ * @rproc: the remote processor
+ * @rsc: the vring resource descriptor
+ *
+ * This resource entry requires allocation of non-cacheable memory
+ * for a virtio vring. Currently we only support two vrings per remote
+ * processor, required for the virtio rpmsg device.
+ *
+ * The 'len' member of @rsc should contain the number of buffers this vring
+ * support and '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.
+ *
+ * Note: 'da' is currently not handled. This will be revised when the generic
+ * iommu-based DMA API will arrive, or a dynanic & non-iommu use case show
+ * up. Meanwhile, statically-addressed iommu-based images should use
+ * RSC_DEVMEM resource entries to map their require 'da' to the physical
+ * address of their base CMA region.
+ *
+ * Returns 0 on success, or an appropriate error code otherwise
+ */
+static int rproc_handle_vring(struct rproc *rproc, struct fw_resource *rsc)
+{
+	struct device *dev = rproc->dev;
+	struct rproc_vdev *rvdev = rproc->rvdev;
+	dma_addr_t dma;
+	int size, id = rsc->id;
+	void *va;
+
+	/* no vdev is in place ? */
+	if (!rvdev) {
+		dev_err(dev, "vring requested without a virtio dev entry\n");
+		return -EINVAL;
+	}
+
+	/* the firmware must provide the expected queue size */
+	if (!rsc->len) {
+		dev_err(dev, "missing expected queue size\n");
+		return -EINVAL;
+	}
+
+	/* we currently support two vrings per rproc (for rx and tx) */
+	if (id >= ARRAY_SIZE(rvdev->vring)) {
+		dev_err(dev, "%s: invalid vring id %d\n", rsc->name, id);
+		return -EINVAL;
+	}
+
+	/* have we already allocated this vring id ? */
+	if (rvdev->vring[id].len) {
+		dev_err(dev, "%s: duplicated id %d\n", rsc->name, id);
+		return -EINVAL;
+	}
+
+	/* actual size of vring (in bytes) */
+	size = PAGE_ALIGN(vring_size(rsc->len, AMP_VRING_ALIGN));
+
+	/*
+	 * Allocate non-cacheable memory for the vring. In the future
+	 * this call will also configure the IOMMU for us
+	 */
+	va = dma_alloc_coherent(dev, size, &dma, GFP_KERNEL);
+	if (!va) {
+		dev_err(dev, "dma_alloc_coherent failed\n");
+		return -ENOMEM;
+	}
+
+	dev_dbg(dev, "vring%d: va %p dma %x qsz %d ring size %x\n", id, va,
+					dma, rsc->len, size);
+
+	rvdev->vring[id].len = rsc->len;
+	rvdev->vring[id].va = va;
+	rvdev->vring[id].dma = dma;
+
+	return 0;
+}
+
+/**
+ * rproc_handle_trace() - handle a shared trace buffer resource
+ * @rproc: the remote processor
+ * @rsc: the trace resource descriptor
+ *
+ * In case the remote processor dumps trace logs into memory,
+ * export it via debugfs.
+ *
+ * Currently, the 'da' member of @rsc should contain the device address
+ * where the remote processor is dumping the traces. Later we could also
+ * support dynamically allocating this address using the generic
+ * DMA API (but currently there isn't a use case for that).
+ *
+ * Returns 0 on success, or an appropriate error code otherwise
+ */
+static int rproc_handle_trace(struct rproc *rproc, struct fw_resource *rsc)
+{
+	struct rproc_mem_entry *trace;
+	struct device *dev = rproc->dev;
+	void *ptr;
+	char name[15];
+
+	/* what's the kernel address of this resource ? */
+	ptr = rproc_da_to_va(rproc, rsc->da, rsc->len);
+	if (!ptr) {
+		dev_err(dev, "erroneous trace resource entry\n");
+		return -EINVAL;
+	}
+
+	trace = kzalloc(sizeof(*trace), GFP_KERNEL);
+	if (!trace) {
+		dev_err(dev, "kzalloc trace failed\n");
+		return -ENOMEM;
+	}
+
+	/* set the trace buffer dma properties */
+	trace->len = rsc->len;
+	trace->va = ptr;
+
+	/* make sure snprintf always null terminates, even if truncating */
+	snprintf(name, sizeof(name), "trace%d", rproc->num_traces);
+
+	/* create the debugfs entry */
+	trace->priv = rproc_create_trace_file(name, rproc, trace);
+	if (!trace->priv) {
+		trace->va = NULL;
+		kfree(trace);
+		return -EINVAL;
+	}
+
+	list_add_tail(&trace->node, &rproc->traces);
+
+	rproc->num_traces++;
+
+	dev_dbg(dev, "%s added: va %p, da 0x%llx, len 0x%x\n", name, ptr,
+						rsc->da, rsc->len);
+
+	return 0;
+}
+
+/**
+ * rproc_handle_devmem() - handle devmem resource entry
+ * @rproc: remote processor handle
+ * @rsc: the devmem resource entry
+ *
+ * Remote processors commonly need to access certain on-chip peripherals.
+ *
+ * Some of these remote processors access memory via an iommu device,
+ * and might require us to configure their iommu before they can access
+ * the on-chip peripherals they need.
+ *
+ * This resource entry is a request to map such a peripheral device.
+ *
+ * These devmem entries will contain the physical address of the device in
+ * the 'pa' member. If a specific device address is expected, then 'da' will
+ * contain it (currently this is the only use case supported). 'len' will
+ * contain the size of the physical region we need to map.
+ *
+ * Currently we just "trust" those devmem entries to contain valid physical
+ * addresses, but this is going to change: we want the implementations to
+ * tell 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.
+ */
+static int rproc_handle_devmem(struct rproc *rproc, struct fw_resource *rsc)
+{
+	struct rproc_mem_entry *mapping;
+	int ret;
+
+	/* no point in handling this resource without a valid iommu domain */
+	if (!rproc->domain)
+		return -EINVAL;
+
+	mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
+	if (!mapping) {
+		dev_err(rproc->dev, "kzalloc mapping failed\n");
+		return -ENOMEM;
+	}
+
+	ret = iommu_map(rproc->domain, rsc->da, rsc->pa, rsc->len, rsc->flags);
+	if (ret) {
+		dev_err(rproc->dev, "failed to map devmem: %d\n", ret);
+		goto out;
+	}
+
+	/*
+	 * We'll need this info later when we'll want to unmap everything
+	 * (e.g. on shutdown).
+	 *
+	 * We can't trust the remote processor not to change the resource
+	 * table, so we must maintain this info independently.
+	 */
+	mapping->da = rsc->da;
+	mapping->len = rsc->len;
+	list_add_tail(&mapping->node, &rproc->mappings);
+
+	dev_dbg(rproc->dev, "mapped devmem pa 0x%llx, da 0x%llx, len 0x%x\n",
+					rsc->pa, rsc->da, rsc->len);
+
+	return 0;
+
+out:
+	kfree(mapping);
+	return ret;
+}
+
+/**
+ * rproc_handle_carveout() - handle phys contig memory allocation requests
+ * @rproc: rproc handle
+ * @rsc: the resource entry
+ *
+ * This function will handle firmware requests for allocation of physically
+ * contiguous memory regions.
+ *
+ * These request entries should come first in the firmware's resource table,
+ * as other firmware 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.
+ */
+static int rproc_handle_carveout(struct rproc *rproc, struct fw_resource *rsc)
+{
+	struct rproc_mem_entry *carveout, *mapping;
+	struct device *dev = rproc->dev;
+	dma_addr_t dma;
+	void *va;
+	int ret;
+
+	mapping = kzalloc(sizeof(*mapping), GFP_KERNEL);
+	if (!mapping) {
+		dev_err(dev, "kzalloc mapping failed\n");
+		return -ENOMEM;
+	}
+
+	carveout = kzalloc(sizeof(*carveout), GFP_KERNEL);
+	if (!carveout) {
+		dev_err(dev, "kzalloc carveout failed\n");
+		ret = -ENOMEM;
+		goto free_mapping;
+	}
+
+	va = dma_alloc_coherent(dev, rsc->len, &dma, GFP_KERNEL);
+	if (!va) {
+		dev_err(dev, "failed to dma alloc carveout: %d\n", rsc->len);
+		ret = -ENOMEM;
+		goto free_carv;
+	}
+
+	dev_dbg(dev, "carveout va %p, dma %x, len 0x%x\n", va, dma, rsc->len);
+
+	/*
+	 * Ok, this is non-standard.
+	 *
+	 * Sometimes we can't rely on the generic iommu-based DMA API
+	 * to dynamically allocate the device address and then set the IOMMU
+	 * tables accordingly, because some remote processors might
+	 * _require_ us to use hard coded device addresses that their
+	 * firmware was compiled with.
+	 *
+	 * In this case, we must use the IOMMU API directly and map
+	 * the memory to the device address as expected by the remote
+	 * processor.
+	 *
+	 * Obviously such remote processor devices should not be configured
+	 * to use the iommu-based DMA API: we expect 'dma' to contain the
+	 * physical address in this case.
+	 */
+	if (rproc->domain) {
+		ret = iommu_map(rproc->domain, rsc->da, dma, rsc->len,
+								rsc->flags);
+		if (ret) {
+			dev_err(dev, "iommu_map failed: %d\n", ret);
+			goto dma_free;
+		}
+
+		/*
+		 * We'll need this info later when we'll want to unmap
+		 * everything (e.g. on shutdown).
+		 *
+		 * We can't trust the remote processor not to change the
+		 * resource table, so we must maintain this info independently.
+		 */
+		mapping->da = rsc->da;
+		mapping->len = rsc->len;
+		list_add_tail(&mapping->node, &rproc->mappings);
+
+		dev_dbg(dev, "carveout mapped 0x%llx to 0x%x\n", rsc->da, dma);
+
+		/*
+		 * Some remote processors might need to know the pa
+		 * even though they are behind an IOMMU. E.g., OMAP4's
+		 * remote M3 processor needs this so it can control
+		 * on-chip hardware accelerators that are not behind
+		 * the IOMMU, and therefor must know the pa.
+		 *
+		 * 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 do this only for
+		 * remote processor that _must_ have this (e.g. OMAP4's
+		 * dual M3 subsystem).
+		 */
+		rsc->pa = dma;
+	}
+
+	carveout->va = va;
+	carveout->len = rsc->len;
+	carveout->dma = dma;
+	carveout->da = rsc->da;
+
+	list_add_tail(&carveout->node, &rproc->carveouts);
+
+	return 0;
+
+dma_free:
+	dma_free_coherent(dev, rsc->len, va, dma);
+free_carv:
+	kfree(carveout);
+free_mapping:
+	kfree(mapping);
+	return ret;
+}
+
+/* handle firmware resource entries before booting the remote processor */
+static int
+rproc_handle_boot_rsc(struct rproc *rproc, struct fw_resource *rsc, int len)
+{
+	struct device *dev = rproc->dev;
+	int ret = 0;
+
+	while (len >= sizeof(*rsc)) {
+		dev_dbg(dev, "rsc: type %d, da 0x%llx, pa 0x%llx, len 0x%x, "
+			"id %d, name %s, flags %x\n", rsc->type, rsc->da,
+			rsc->pa, rsc->len, rsc->id, rsc->name, rsc->flags);
+
+		switch (rsc->type) {
+		case RSC_CARVEOUT:
+			ret = rproc_handle_carveout(rproc, rsc);
+			break;
+		case RSC_DEVMEM:
+			ret = rproc_handle_devmem(rproc, rsc);
+			break;
+		case RSC_TRACE:
+			ret = rproc_handle_trace(rproc, rsc);
+			break;
+		case RSC_VRING:
+			ret = rproc_handle_vring(rproc, rsc);
+			break;
+		case RSC_VIRTIO_DEV:
+			/* this one is handled early upon registration */
+			break;
+		default:
+			dev_warn(dev, "unsupported resource %d\n", rsc->type);
+			break;
+		}
+
+		if (ret)
+			break;
+
+		rsc++;
+		len -= sizeof(*rsc);
+	}
+
+	return ret;
+}
+
+/* handle firmware resource entries while registering the remote processor */
+static int
+rproc_handle_virtio_rsc(struct rproc *rproc, struct fw_resource *rsc, int len)
+{
+	struct device *dev = rproc->dev;
+	int ret = 0;
+
+	for (; len >= sizeof(*rsc); rsc++, len -= sizeof(*rsc))
+		if (rsc->type == RSC_VIRTIO_DEV) {
+			dev_dbg(dev, "found vdev %d/%s features %llx\n",
+					rsc->flags, rsc->name, rsc->da);
+			ret = rproc_handle_virtio_hdr(rproc, rsc);
+			break;
+		}
+
+	return ret;
+}
+
+/**
+ * rproc_handle_resources() - find and handle the resource table
+ * @rproc: the rproc handle
+ * @elf_data: the content of the ELF firmware image
+ * @handler: function that should be used to handle the resource table
+ *
+ * This function finds the resource table inside the remote processor's
+ * firmware, and invoke a user-supplied handler with it (we have two
+ * possible handlers: one is invoked upon registration of @rproc,
+ * in order to register the supported virito devices, and the other is
+ * invoked when @rproc is actually booted).
+ *
+ * Currently this function fails if a resource table doesn't exist.
+ * This restriction will be removed when we'll start supporting remote
+ * processors that don't need a resource table.
+ */
+static int rproc_handle_resources(struct rproc *rproc, const u8 *elf_data,
+					rproc_handle_resources_t handler)
+
+{
+	struct elf32_hdr *ehdr;
+	struct elf32_shdr *shdr;
+	const char *name_table;
+	int i, ret = -EINVAL;
+
+	ehdr = (struct elf32_hdr *)elf_data;
+	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
+	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
+
+	/* look for the resource table and handle it */
+	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
+		if (!strcmp(name_table + shdr->sh_name, ".resource_table")) {
+			struct fw_resource *table = (struct fw_resource *)
+						(elf_data + shdr->sh_offset);
+
+			ret = handler(rproc, table, shdr->sh_size);
+
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * rproc_resource_cleanup() - clean up and free all acquired resources
+ * @rproc: rproc handle
+ *
+ * This function will free all resources acquired for @rproc, and it
+ * is called when @rproc shuts down, or just failed booting.
+ */
+static void rproc_resource_cleanup(struct rproc *rproc)
+{
+	struct rproc_mem_entry *entry, *tmp;
+	struct device *dev = rproc->dev;
+	struct rproc_vdev *rvdev = rproc->rvdev;
+	int i;
+
+	/* clean up debugfs trace entries */
+	list_for_each_entry_safe(entry, tmp, &rproc->traces, node) {
+		rproc_remove_trace_file(entry->priv);
+		rproc->num_traces--;
+		list_del(&entry->node);
+		kfree(entry);
+	}
+
+	/* free the coherent memory allocated for the vrings */
+	for (i = 0; rvdev && i < ARRAY_SIZE(rvdev->vring); i++) {
+		int qsz = rvdev->vring[i].len;
+		void *va = rvdev->vring[i].va;
+		int dma = rvdev->vring[i].dma;
+
+		/* virtqueue size is expressed in number of buffers supported */
+		if (qsz) {
+			/* how many bytes does this vring really occupy ? */
+			int size = PAGE_ALIGN(vring_size(qsz, AMP_VRING_ALIGN));
+
+			dma_free_coherent(rproc->dev, size, va, dma);
+
+			rvdev->vring[i].len = 0;
+		}
+	}
+
+	/* clean up carveout allocations */
+	list_for_each_entry_safe(entry, tmp, &rproc->carveouts, node) {
+		dma_free_coherent(dev, entry->len, entry->va, entry->dma);
+		list_del(&entry->node);
+		kfree(entry);
+	}
+
+	/* clean up iommu mapping entries */
+	list_for_each_entry_safe(entry, tmp, &rproc->mappings, node) {
+		size_t unmapped;
+
+		unmapped = iommu_unmap(rproc->domain, entry->da, entry->len);
+		if (unmapped != entry->len) {
+			/* nothing much to do besides complaining */
+			dev_err(dev, "failed to unmap %u/%u\n", entry->len,
+								unmapped);
+		}
+
+		list_del(&entry->node);
+		kfree(entry);
+	}
+}
+
+/* make sure this fw image is sane */
+static int rproc_fw_sanity_check(struct rproc *rproc, const struct firmware *fw)
+{
+	const char *name = rproc->firmware;
+	struct device *dev = rproc->dev;
+	struct elf32_hdr *ehdr;
+
+	if (!fw) {
+		dev_err(dev, "failed to load %s\n", name);
+		return -EINVAL;
+	}
+
+	if (fw->size < sizeof(struct elf32_hdr)) {
+		dev_err(dev, "Image is too small\n");
+		return -EINVAL;
+	}
+
+	ehdr = (struct elf32_hdr *)fw->data;
+
+	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+		dev_err(dev, "Image is corrupted (bad magic)\n");
+		return -EINVAL;
+	}
+
+	if (ehdr->e_phnum == 0) {
+		dev_err(dev, "No loadable segments\n");
+		return -EINVAL;
+	}
+
+	if (ehdr->e_phoff > fw->size) {
+		dev_err(dev, "Firmware size is too small\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * take a firmware and boot a remote processor with it.
+ */
+static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw)
+{
+	struct device *dev = rproc->dev;
+	const char *name = rproc->firmware;
+	struct elf32_hdr *ehdr;
+	int ret;
+
+	ret = rproc_fw_sanity_check(rproc, fw);
+	if (ret)
+		return ret;
+
+	ehdr = (struct elf32_hdr *)fw->data;
+
+	dev_info(dev, "Booting fw image %s, size %d\n", name, fw->size);
+
+	/*
+	 * if enabling an IOMMU isn't relevant for this rproc, this is
+	 * just a nop
+	 */
+	ret = rproc_enable_iommu(rproc);
+	if (ret) {
+		dev_err(dev, "can't enable iommu: %d\n", ret);
+		return ret;
+	}
+
+	/*
+	 * The ELF entry point is the rproc's boot addr (though this is not
+	 * a configurable property of all remote processors: some will always
+	 * boot at a specific hardcoded address).
+	 */
+	rproc->bootaddr = ehdr->e_entry;
+
+	/* handle fw resources which are required to boot rproc */
+	ret = rproc_handle_resources(rproc, fw->data, rproc_handle_boot_rsc);
+	if (ret) {
+		dev_err(dev, "Failed to process resources: %d\n", ret);
+		goto clean_up;
+	}
+
+	/* load the ELF segments to memory */
+	ret = rproc_load_segments(rproc, fw->data);
+	if (ret) {
+		dev_err(dev, "Failed to load program segments: %d\n", ret);
+		goto clean_up;
+	}
+
+	/* power up the remote processor */
+	ret = rproc->ops->start(rproc);
+	if (ret) {
+		dev_err(dev, "can't start rproc %s: %d\n", rproc->name, ret);
+		goto clean_up;
+	}
+
+	rproc->state = RPROC_RUNNING;
+
+	dev_info(dev, "remote processor %s is now up\n", rproc->name);
+
+	return 0;
+
+clean_up:
+	rproc_resource_cleanup(rproc);
+	rproc_disable_iommu(rproc);
+	return ret;
+}
+
+/*
+ * take a firmware and look for virtio devices to register.
+ *
+ * Note: this function is called asynchronously upon registration of the
+ * remote processor (so we must wait until it completes before we try
+ * to unregister the device. one other option is just to use kref here,
+ * that might be cleaner).
+ */
+static void rproc_fw_config_virtio(const struct firmware *fw, void *context)
+{
+	struct rproc *rproc = context;
+	struct device *dev = rproc->dev;
+	int ret;
+
+	if (rproc_fw_sanity_check(rproc, fw) < 0)
+		goto out;
+
+	/* does the fw supports any virtio devices ? */
+	ret = rproc_handle_resources(rproc, fw->data, rproc_handle_virtio_rsc);
+	if (ret) {
+		dev_info(dev, "No fw virtio device was found\n");
+		goto out;
+	}
+
+	/* add the virtio device (currently only rpmsg vdevs are supported) */
+	ret = rproc_add_rpmsg_vdev(rproc);
+	if (ret)
+		goto out;
+
+out:
+	if (fw)
+		release_firmware(fw);
+	/* allow rproc_unregister() contexts, if any, to proceed */
+	complete_all(&rproc->firmware_loading_complete);
+}
+
+/**
+ * rproc_boot() - boot a remote processor
+ * @rproc: handle of a remote processor
+ *
+ * Boot a remote processor (i.e. load its firmware, power it on, ...).
+ *
+ * If the remote processor is already powered on, this function immediately
+ * returns (successfully).
+ *
+ * Returns 0 on success, and an appropriate error value otherwise.
+ */
+int rproc_boot(struct rproc *rproc)
+{
+	const struct firmware *firmware_p;
+	struct device *dev;
+	int ret;
+
+	if (!rproc) {
+		pr_err("invalid rproc handle\n");
+		return -EINVAL;
+	}
+
+	dev = rproc->dev;
+
+	ret = mutex_lock_interruptible(&rproc->lock);
+	if (ret) {
+		dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, ret);
+		return ret;
+	}
+
+	/* loading a firmware is required */
+	if (!rproc->firmware) {
+		dev_err(dev, "%s: no firmware to load\n", __func__);
+		ret = -EINVAL;
+		goto unlock_mutex;
+	}
+
+	/* prevent underlying implementation from being removed */
+	if (!try_module_get(dev->driver->owner)) {
+		dev_err(dev, "%s: can't get owner\n", __func__);
+		ret = -EINVAL;
+		goto unlock_mutex;
+	}
+
+	/* skip the boot process if rproc is already powered up */
+	if (atomic_inc_return(&rproc->power) > 1) {
+		ret = 0;
+		goto unlock_mutex;
+	}
+
+	dev_info(dev, "powering up %s\n", rproc->name);
+
+	/* load firmware */
+	ret = request_firmware(&firmware_p, rproc->firmware, dev);
+	if (ret < 0) {
+		dev_err(dev, "request_firmware failed: %d\n", ret);
+		goto downref_rproc;
+	}
+
+	ret = rproc_fw_boot(rproc, firmware_p);
+
+	release_firmware(firmware_p);
+
+downref_rproc:
+	if (ret) {
+		module_put(dev->driver->owner);
+		atomic_dec(&rproc->power);
+	}
+unlock_mutex:
+	mutex_unlock(&rproc->lock);
+	return ret;
+}
+EXPORT_SYMBOL(rproc_boot);
+
+/**
+ * rproc_shutdown() - power off the remote processor
+ * @rproc: the remote processor
+ *
+ * Power off a remote processor (previously booted with rproc_boot()).
+ *
+ * In case @rproc is still being used by an additional user(s), then
+ * this function will just decrement the power refcount and exit,
+ * without really powering off the device.
+ *
+ * Every call to rproc_boot() must (eventually) be accompanied by a call
+ * to rproc_shutdown(). Calling rproc_shutdown() redundantly is a bug.
+ *
+ * Notes:
+ * - we're not decrementing the rproc's refcount, only the power refcount.
+ *   which means that the @rproc handle stays valid even after rproc_shutdown()
+ *   returns, and users can still use it with a subsequent rproc_boot(), if
+ *   needed.
+ * - don't call rproc_shutdown() to unroll rproc_get_by_name(), exactly
+ *   because rproc_shutdown() _does not_ decrement the refcount of @rproc.
+ *   To decrement the refcount of @rproc, use rproc_put() (but _only_ if
+ *   you acquired @rproc using rproc_get_by_name()).
+ */
+void rproc_shutdown(struct rproc *rproc)
+{
+	struct device *dev = rproc->dev;
+	int ret;
+
+	ret = mutex_lock_interruptible(&rproc->lock);
+	if (ret) {
+		dev_err(dev, "can't lock rproc %s: %d\n", rproc->name, ret);
+		return;
+	}
+
+	/* if the remote proc is still needed, bail out */
+	if (!atomic_dec_and_test(&rproc->power))
+		goto out;
+
+	/* power off the remote processor */
+	ret = rproc->ops->stop(rproc);
+	if (ret) {
+		atomic_inc(&rproc->power);
+		dev_err(dev, "can't stop rproc: %d\n", ret);
+		goto out;
+	}
+
+	/* clean up all acquired resources */
+	rproc_resource_cleanup(rproc);
+
+	rproc_disable_iommu(rproc);
+
+	rproc->state = RPROC_OFFLINE;
+
+	dev_info(dev, "stopped remote processor %s\n", rproc->name);
+
+out:
+	mutex_unlock(&rproc->lock);
+	if (!ret)
+		module_put(dev->driver->owner);
+}
+EXPORT_SYMBOL(rproc_shutdown);
+
+/**
+ * rproc_release() - completely deletes the existence of a remote processor
+ * @kref: the rproc's kref
+ *
+ * This function should _never_ be called directly.
+ *
+ * The only reasonable location to use it is as an argument when kref_put'ing
+ * @rproc's refcount.
+ *
+ * This way it will be called when no one holds a valid pointer to this @rproc
+ * anymore (and obviously after it is removed from the rprocs klist).
+ *
+ * Note: this function is not static because rproc_vdev_release() needs it when
+ * it decrements @rproc's refcount.
+ */
+void rproc_release(struct kref *kref)
+{
+	struct rproc *rproc = container_of(kref, struct rproc, refcount);
+
+	dev_info(rproc->dev, "removing %s\n", rproc->name);
+
+	rproc_delete_debug_dir(rproc);
+
+	/* at this point no one holds a reference to rproc anymore */
+	kfree(rproc);
+}
+
+/* will be called when an rproc is added to the rprocs klist */
+static void klist_rproc_get(struct klist_node *n)
+{
+	struct rproc *rproc = container_of(n, struct rproc, node);
+
+	kref_get(&rproc->refcount);
+}
+
+/* will be called when an rproc is removed from the rprocs klist */
+static void klist_rproc_put(struct klist_node *n)
+{
+	struct rproc *rproc = container_of(n, struct rproc, node);
+
+	kref_put(&rproc->refcount, rproc_release);
+}
+
+static struct rproc *next_rproc(struct klist_iter *i)
+{
+	struct klist_node *n;
+
+	n = klist_next(i);
+	if (!n)
+		return NULL;
+
+	return container_of(n, struct rproc, node);
+}
+
+/**
+ * rproc_get_by_name() - find a remote processor by name and boot it
+ * @name: name of the remote processor
+ *
+ * Finds an rproc handle using the remote processor's name, and then
+ * boot it. If it's already powered on, then just immediately return
+ * (successfully).
+ *
+ * Returns the rproc handle on success, and NULL on failure.
+ *
+ * This function increments the remote processor's refcount, so always
+ * use rproc_put() to decrement it back once rproc isn't needed anymore.
+ *
+ * Note: currently this function (and its counterpart rproc_put()) are not
+ * used anymore by the amp sub-system. We need to scrutinize the use cases
+ * that still need them, and see if we can migrate them to use the non
+ * name-based boot/shutdown interface.
+ */
+struct rproc *rproc_get_by_name(const char *name)
+{
+	struct rproc *rproc;
+	struct klist_iter i;
+	int ret;
+
+	/* find the remote processor, and upref its refcount */
+	klist_iter_init(&rprocs, &i);
+	while ((rproc = next_rproc(&i)) != NULL)
+		if (!strcmp(rproc->name, name)) {
+			kref_get(&rproc->refcount);
+			break;
+		}
+	klist_iter_exit(&i);
+
+	/* can't find this rproc ? */
+	if (!rproc) {
+		pr_err("can't find remote processor %s\n", name);
+		return NULL;
+	}
+
+	ret = rproc_boot(rproc);
+	if (ret < 0) {
+		kref_put(&rproc->refcount, rproc_release);
+		return NULL;
+	}
+
+	return rproc;
+}
+EXPORT_SYMBOL(rproc_get_by_name);
+
+/**
+ * rproc_put() - decrement the refcount of a remote processor, and shut it down
+ * @rproc: the remote processor
+ *
+ * This function tries to shutdown @rproc, and it then decrements its
+ * refcount.
+ *
+ * After this function returns, @rproc may _not_ be used anymore, and its
+ * handle should be considered invalid.
+ *
+ * This function should be called _iff_ the @rproc handle was grabbed by
+ * calling rproc_get_by_name().
+ */
+void rproc_put(struct rproc *rproc)
+{
+	/* try to power off the remote processor */
+	rproc_shutdown(rproc);
+
+	/* downref rproc's refcount */
+	kref_put(&rproc->refcount, rproc_release);
+}
+EXPORT_SYMBOL(rproc_put);
+
+/**
+ * rproc_register() - register a remote processor
+ * @rproc: the remote processor handle to register
+ *
+ * Registers @rproc with the remoteproc framework, after it has been
+ * allocated with rproc_alloc().
+ *
+ * This is called by the platform-specific rproc implementation, whenever
+ * a new remote processor device is probed.
+ *
+ * Returns 0 on success and an appropriate error code otherwise.
+ *
+ * Note: this function initiates an asynchronous firmware loading
+ * context, which will look for virtio devices supported by the rproc's
+ * firmware.
+ *
+ * If found, those virtio devices will be created and added, so as a result
+ * of registering this remote processor, additional virtio drivers will be
+ * probed.
+ *
+ * Currently, though, we only support a single RPMSG virtio vdev per remote
+ * processor.
+ */
+int rproc_register(struct rproc *rproc)
+{
+	struct device *dev = rproc->dev;
+	int ret = 0;
+
+	/* expose to rproc_get_by_name users */
+	klist_add_tail(&rproc->node, &rprocs);
+
+	dev_info(rproc->dev, "%s is available\n", rproc->name);
+
+	/* create debugfs entries */
+	rproc_create_debug_dir(rproc);
+
+	/* rproc_unregister() calls must wait until async loader completes */
+	init_completion(&rproc->firmware_loading_complete);
+
+	/*
+	 * We must retrieve early virtio configuration info from
+	 * the firmware (e.g. whether to register a virtio rpmsg device,
+	 * what virtio features does it support, ...).
+	 *
+	 * We're initiating an asynchronous firmware loading, so we can
+	 * be built-in kernel code, without hanging the boot process.
+	 */
+	ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+					rproc->firmware, dev, GFP_KERNEL,
+					rproc, rproc_fw_config_virtio);
+	if (ret < 0) {
+		dev_err(dev, "request_firmware_nowait failed: %d\n", ret);
+		complete_all(&rproc->firmware_loading_complete);
+		klist_remove(&rproc->node);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(rproc_register);
+
+/**
+ * rproc_alloc() - allocate a remote processor handle
+ * @dev: the underlying device
+ * @name: name of this remote processor
+ * @ops: platform-specific handlers (mainly start/stop)
+ * @firmware: name of firmware file to load
+ * @len: length of private data needed by the rproc driver (in bytes)
+ *
+ * Allocates a new remote processor handle, but does not register
+ * it yet.
+ *
+ * This function should be used by rproc implementations during initialization
+ * of the remote processor.
+ *
+ * After creating an rproc handle using this function, and when ready,
+ * implementations should then call rproc_register() to complete
+ * the registration of the remote processor.
+ *
+ * On success the new rproc is returned, and on failure, NULL.
+ *
+ * Note: _never_ directly deallocate @rproc, even if it was not registered
+ * yet. Instead, if you just need to unroll rproc_alloc(), use rproc_free().
+ */
+struct rproc *rproc_alloc(struct device *dev, const char *name,
+				const struct rproc_ops *ops,
+				const char *firmware, int len)
+{
+	struct rproc *rproc;
+
+	if (!dev || !name || !ops)
+		return NULL;
+
+	rproc = kzalloc(sizeof(struct rproc) + len, GFP_KERNEL);
+	if (!rproc) {
+		dev_err(dev, "%s: kzalloc failed\n", __func__);
+		return NULL;
+	}
+
+	rproc->dev = dev;
+	rproc->name = name;
+	rproc->ops = ops;
+	rproc->firmware = firmware;
+	rproc->priv = &rproc[1];
+
+	atomic_set(&rproc->power, 0);
+
+	kref_init(&rproc->refcount);
+
+	mutex_init(&rproc->lock);
+
+	INIT_LIST_HEAD(&rproc->carveouts);
+	INIT_LIST_HEAD(&rproc->mappings);
+	INIT_LIST_HEAD(&rproc->traces);
+
+	rproc->state = RPROC_OFFLINE;
+
+	return rproc;
+}
+EXPORT_SYMBOL(rproc_alloc);
+
+/**
+ * rproc_free() - free an rproc handle that was allocated by rproc_alloc
+ * @rproc: the remote processor handle
+ *
+ * This function should _only_ be used if @rproc was only allocated,
+ * but not registered yet.
+ *
+ * If @rproc was already successfully registered (by calling rproc_register()),
+ * then use rproc_unregister() instead.
+ */
+void rproc_free(struct rproc *rproc)
+{
+	kfree(rproc);
+}
+EXPORT_SYMBOL(rproc_free);
+
+/**
+ * rproc_unregister() - unregister a remote processor
+ * @rproc: rproc handle to unregister
+ *
+ * Unregisters a remote processor, and decrements its refcount.
+ * If its refcount drops to zero, then @rproc will be freed. If not,
+ * it will be freed later once the last reference is dropped.
+ *
+ * This function should be called when the platform specific rproc
+ * implementation decides to remove the rproc device. it should
+ * _only_ be called if a previous invocation of rproc_register()
+ * has completed successfully.
+ *
+ * After rproc_unregister() returns, @rproc is _not_ valid anymore and
+ * it shouldn't be used. More specifically, don't call rproc_free()
+ * or try to directly free @rproc after rproc_unregister() returns;
+ * none of these are needed, and calling them is a bug.
+ *
+ * Returns 0 on success and -EINVAL if @rproc isn't valid.
+ */
+int rproc_unregister(struct rproc *rproc)
+{
+	if (!rproc)
+		return -EINVAL;
+
+	/* if rproc is just being registered, wait */
+	wait_for_completion(&rproc->firmware_loading_complete);
+
+	/* was an rpmsg vdev created ? */
+	if (rproc->rvdev)
+		rproc_remove_rpmsg_vdev(rproc);
+
+	klist_remove(&rproc->node);
+
+	kref_put(&rproc->refcount, rproc_release);
+
+	return 0;
+}
+EXPORT_SYMBOL(rproc_unregister);
+
+static int __init remoteproc_init(void)
+{
+	rproc_init_debugfs();
+	return 0;
+}
+module_init(remoteproc_init);
+
+static void __exit remoteproc_exit(void)
+{
+	rproc_exit_debugfs();
+}
+module_exit(remoteproc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Generic Remote Processor Framework");
diff --git a/drivers/amp/remoteproc/remoteproc_internal.h b/drivers/amp/remoteproc/remoteproc_internal.h
new file mode 100644
index 0000000..8b2fc40
--- /dev/null
+++ b/drivers/amp/remoteproc/remoteproc_internal.h
@@ -0,0 +1,44 @@
+/*
+ * Remote processor framework
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef REMOTEPROC_INTERNAL_H
+#define REMOTEPROC_INTERNAL_H
+
+#include <linux/irqreturn.h>
+
+struct rproc;
+
+/* from remoteproc_core.c */
+void rproc_release(struct kref *kref);
+irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int vq_id);
+
+/* from remoteproc_rpmsg.c */
+int rproc_add_rpmsg_vdev(struct rproc *);
+void rproc_remove_rpmsg_vdev(struct rproc *rproc);
+
+/* from remoteproc_debugfs.c */
+void rproc_remove_trace_file(struct dentry *tfile);
+struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc,
+					struct rproc_mem_entry *trace);
+void rproc_delete_debug_dir(struct rproc *rproc);
+void rproc_create_debug_dir(struct rproc *rproc);
+void rproc_init_debugfs(void);
+void rproc_exit_debugfs(void);
+
+#endif /* REMOTEPROC_INTERNAL_H */
diff --git a/include/linux/amp/remoteproc.h b/include/linux/amp/remoteproc.h
new file mode 100644
index 0000000..1edbfde
--- /dev/null
+++ b/include/linux/amp/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 <linux/types.h>
+#include <linux/kref.h>
+#include <linux/klist.h>
+#include <linux/mutex.h>
+#include <linux/virtio.h>
+#include <linux/completion.h>
+
+/*
+ * 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 */
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 2/7] amp/remoteproc: add debugfs entries
  2011-10-25  9:48 [PATCH 0/7] Introducing a generic AMP framework Ohad Ben-Cohen
  2011-10-25  9:48 ` [PATCH 1/7] amp/remoteproc: add framework for controlling remote processors Ohad Ben-Cohen
@ 2011-10-25  9:48 ` Ohad Ben-Cohen
  2012-01-03 23:36   ` Grant Likely
  2011-10-25  9:48 ` [PATCH 3/7] amp/remoteproc: create rpmsg virtio device Ohad Ben-Cohen
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 34+ messages in thread
From: Ohad Ben-Cohen @ 2011-10-25  9:48 UTC (permalink / raw)
  To: linux-omap, linux-kernel, linux-arm-kernel
  Cc: akpm, Brian Swetland, Arnd Bergmann, Grant Likely, Rusty Russell,
	Tony Lindgren, Russell King, Ohad Ben-Cohen, Greg KH,
	Stephen Boyd

Expose several remote processor properties (name, state, trace buffer)
that are helpful for debugging.

This part is extracted to a separate patch just to keep the review load
down.

Designed with Brian Swetland <swetland@google.com>.

Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Cc: Brian Swetland <swetland@google.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Tony Lindgren <tony@atomide.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Greg KH <greg@kroah.com>
Cc: Stephen Boyd <sboyd@codeaurora.org>
---
 drivers/amp/remoteproc/Makefile             |    1 +
 drivers/amp/remoteproc/remoteproc_debugfs.c |  182 +++++++++++++++++++++++++++
 2 files changed, 183 insertions(+), 0 deletions(-)
 create mode 100644 drivers/amp/remoteproc/remoteproc_debugfs.c

diff --git a/drivers/amp/remoteproc/Makefile b/drivers/amp/remoteproc/Makefile
index 2a5fd79..b888c37 100644
--- a/drivers/amp/remoteproc/Makefile
+++ b/drivers/amp/remoteproc/Makefile
@@ -4,3 +4,4 @@
 
 obj-$(CONFIG_REMOTEPROC)		+= remoteproc.o
 remoteproc-y				:= remoteproc_core.o
+remoteproc-y				+= remoteproc_debugfs.o
\ No newline at end of file
diff --git a/drivers/amp/remoteproc/remoteproc_debugfs.c b/drivers/amp/remoteproc/remoteproc_debugfs.c
new file mode 100644
index 0000000..4c849db
--- /dev/null
+++ b/drivers/amp/remoteproc/remoteproc_debugfs.c
@@ -0,0 +1,182 @@
+/*
+ * Remote Processor Framework
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Mark Grosen <mgrosen@ti.com>
+ * Brian Swetland <swetland@google.com>
+ * Fernando Guzman Lugo <fernando.lugo@ti.com>
+ * Suman Anna <s-anna@ti.com>
+ * Robert Tivy <rtivy@ti.com>
+ * Armando Uribe De Leon <x0095078@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)    "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/amp/remoteproc.h>
+#include <linux/device.h>
+
+/* remoteproc debugfs parent dir */
+static struct dentry *rproc_dbg;
+
+/*
+ * Some remote processors may support dumping trace logs into a shared
+ * memory buffer. We expose this trace buffer using debugfs, so users
+ * can easily tell what's going on remotely.
+ *
+ * We will most probably improve the rproc tracing facilities later on,
+ * but this kind of lightweight and simple mechanism is always good to have,
+ * as it provides very early tracing with little to no dependencies at all.
+ */
+static ssize_t rproc_trace_read(struct file *filp, char __user *userbuf,
+						size_t count, loff_t *ppos)
+{
+	struct rproc_mem_entry *trace = filp->private_data;
+	int len = strnlen(trace->va, trace->len);
+
+	return simple_read_from_buffer(userbuf, count, ppos, trace->va, len);
+}
+
+static int rproc_open_generic(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+
+	return 0;
+}
+
+static const struct file_operations trace_rproc_ops = {
+	.read = rproc_trace_read,
+	.open = rproc_open_generic,
+	.llseek	= generic_file_llseek,
+};
+
+/*
+ * A state-to-string lookup table, for exposing a human readable state
+ * via debugfs. Always keep in sync with enum rproc_state
+ */
+static const char * const rproc_state_string[] = {
+	"offline",
+	"suspended",
+	"running",
+	"crashed",
+	"invalid",
+};
+
+/* expose the state of the remote processor via debugfs */
+static ssize_t rproc_state_read(struct file *filp, char __user *userbuf,
+						size_t count, loff_t *ppos)
+{
+	struct rproc *rproc = filp->private_data;
+	unsigned int state;
+	char buf[30];
+	int i;
+
+	state = rproc->state > RPROC_LAST ? RPROC_LAST : rproc->state;
+
+	i = snprintf(buf, 30, "%.28s (%d)\n", rproc_state_string[state],
+							rproc->state);
+
+	return simple_read_from_buffer(userbuf, count, ppos, buf, i);
+}
+
+static const struct file_operations rproc_state_ops = {
+	.read = rproc_state_read,
+	.open = rproc_open_generic,
+	.llseek	= generic_file_llseek,
+};
+
+/* expose the name of the remote processor via debugfs */
+static ssize_t rproc_name_read(struct file *filp, char __user *userbuf,
+						size_t count, loff_t *ppos)
+{
+	struct rproc *rproc = filp->private_data;
+	/* need room for the name, a newline and a terminating null */
+	char buf[100];
+	int i;
+
+	i = snprintf(buf, sizeof(buf), "%.98s\n", rproc->name);
+
+	return simple_read_from_buffer(userbuf, count, ppos, buf, i);
+}
+
+static const struct file_operations rproc_name_ops = {
+	.read = rproc_name_read,
+	.open = rproc_open_generic,
+	.llseek	= generic_file_llseek,
+};
+
+void rproc_remove_trace_file(struct dentry *tfile)
+{
+	debugfs_remove(tfile);
+}
+
+struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc,
+					struct rproc_mem_entry *trace)
+{
+	struct dentry *tfile;
+
+	tfile = debugfs_create_file(name, 0400, rproc->dbg_dir,
+						trace, &trace_rproc_ops);
+	if (!tfile) {
+		dev_err(rproc->dev, "failed to create debugfs trace entry\n");
+		return NULL;
+	}
+
+	return tfile;
+}
+
+void rproc_delete_debug_dir(struct rproc *rproc)
+{
+	if (!rproc->dbg_dir)
+		return;
+
+	debugfs_remove_recursive(rproc->dbg_dir);
+}
+
+void rproc_create_debug_dir(struct rproc *rproc)
+{
+	struct device *dev = rproc->dev;
+
+	if (!rproc_dbg)
+		return;
+
+	rproc->dbg_dir = debugfs_create_dir(dev_name(dev), rproc_dbg);
+	if (!rproc->dbg_dir)
+		return;
+
+	debugfs_create_file("name", 0400, rproc->dbg_dir,
+					rproc, &rproc_name_ops);
+	debugfs_create_file("state", 0400, rproc->dbg_dir,
+					rproc, &rproc_state_ops);
+}
+
+void __init rproc_init_debugfs(void)
+{
+	if (debugfs_initialized()) {
+		rproc_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL);
+		if (!rproc_dbg)
+			pr_err("can't create debugfs dir\n");
+	}
+}
+
+void __exit rproc_exit_debugfs(void)
+{
+	if (rproc_dbg)
+		debugfs_remove(rproc_dbg);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Generic Remote Processor Framework");
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 3/7] amp/remoteproc: create rpmsg virtio device
  2011-10-25  9:48 [PATCH 0/7] Introducing a generic AMP framework Ohad Ben-Cohen
  2011-10-25  9:48 ` [PATCH 1/7] amp/remoteproc: add framework for controlling remote processors Ohad Ben-Cohen
  2011-10-25  9:48 ` [PATCH 2/7] amp/remoteproc: add debugfs entries Ohad Ben-Cohen
@ 2011-10-25  9:48 ` Ohad Ben-Cohen
  2011-10-25  9:48 ` [PATCH 4/7] amp/omap: add a remoteproc driver Ohad Ben-Cohen
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 34+ messages in thread
From: Ohad Ben-Cohen @ 2011-10-25  9:48 UTC (permalink / raw)
  To: linux-omap, linux-kernel, linux-arm-kernel
  Cc: akpm, Brian Swetland, Arnd Bergmann, Grant Likely, Rusty Russell,
	Tony Lindgren, Russell King, Ohad Ben-Cohen, Greg KH,
	Stephen Boyd

Create an rpmsg virtio device to allow message-based communication
with the remote processor (but only if supported by its firmware).

There are several advantages to provide this functionality at
the remoteproc-level:
- to support it, platforms only have to provide their own ->kick()
  handler; no need to duplicate the rest of the code.
- the virtio device is created only when the remote processor is
  registered and ready to go. No need to depend on initcall magic.
  moreover, we only add the virtio device if the firmware really
  supports it, and only after we know the supported virtio device features.
- correct device model hierarchy can be set, so we can use device-based
  API cleanly (e.g. power management, DMA API, ...).
- when the remote processor crashes (or removed) we only need
  to remove the virtio device, and the driver core will take care of
  the rest. No need to implement any out-of-bound notifiers.
- we can now easily bind the virtio device to its rproc handle, and
  this way we don't need any name-based remoteproc ->get() API.

Currently we only support creating a single rpmsg virtio device per
remote processor, but later this is going to be extended to support
creating numerous virtio devices of other types too (block, net,
console...).

Designed with Brian Swetland <swetland@google.com>.

Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Cc: Brian Swetland <swetland@google.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Tony Lindgren <tony@atomide.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Greg KH <greg@kroah.com>
Cc: Stephen Boyd <sboyd@codeaurora.org>
---
 drivers/amp/remoteproc/Makefile           |    3 +-
 drivers/amp/remoteproc/remoteproc_rpmsg.c |  297 +++++++++++++++++++++++++++++
 2 files changed, 299 insertions(+), 1 deletions(-)
 create mode 100644 drivers/amp/remoteproc/remoteproc_rpmsg.c

diff --git a/drivers/amp/remoteproc/Makefile b/drivers/amp/remoteproc/Makefile
index b888c37..0a24a3b 100644
--- a/drivers/amp/remoteproc/Makefile
+++ b/drivers/amp/remoteproc/Makefile
@@ -4,4 +4,5 @@
 
 obj-$(CONFIG_REMOTEPROC)		+= remoteproc.o
 remoteproc-y				:= remoteproc_core.o
-remoteproc-y				+= remoteproc_debugfs.o
\ No newline at end of file
+remoteproc-y				+= remoteproc_debugfs.o
+remoteproc-y				+= remoteproc_rpmsg.o
\ No newline at end of file
diff --git a/drivers/amp/remoteproc/remoteproc_rpmsg.c b/drivers/amp/remoteproc/remoteproc_rpmsg.c
new file mode 100644
index 0000000..b319e54
--- /dev/null
+++ b/drivers/amp/remoteproc/remoteproc_rpmsg.c
@@ -0,0 +1,297 @@
+/*
+ * Remote processor messaging transport (OMAP platform-specific bits)
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/amp/remoteproc.h>
+#include <linux/amp/rpmsg.h>
+#include <linux/virtio.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_ring.h>
+#include <linux/err.h>
+#include <linux/kref.h>
+#include <linux/slab.h>
+
+#include "remoteproc_internal.h"
+
+/**
+ * struct rproc_virtio_vq_info - virtqueue state
+ * @vq_id: a unique index of this virtqueue (unique for this @rproc)
+ * @rproc: handle to the remote processor
+ *
+ * Such a struct will be maintained for every virtqueue we're
+ * using to communicate with the remote processor
+ */
+struct rproc_virtio_vq_info {
+	__u16 vq_id;
+	struct rproc *rproc;
+};
+
+/* kick the remote processor, and let it know which virtqueue to poke at */
+static void rproc_virtio_notify(struct virtqueue *vq)
+{
+	struct rproc_virtio_vq_info *rpvq = vq->priv;
+	struct rproc *rproc = rpvq->rproc;
+
+	dev_dbg(rproc->dev, "kicking vq id: %d\n", rpvq->vq_id);
+
+	rproc->ops->kick(rproc, rpvq->vq_id);
+}
+
+/**
+ * rproc_vq_interrupt() - tell remoteproc that a virtqueue is interrupted
+ * @rproc: handle to the remote processor
+ * @vq_id: index of the signalled virtqueue
+ *
+ * This function should be called by the platform-specific rproc driver,
+ * when the remote processor signals that a specific virtqueue has pending
+ * messages available.
+ *
+ * Returns IRQ_NONE if no message was found in the @vq_id virtqueue,
+ * and otherwise returns IRQ_HANDLED.
+ */
+irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int vq_id)
+{
+	return vring_interrupt(0, rproc->rvdev->vq[vq_id]);
+}
+EXPORT_SYMBOL(rproc_vq_interrupt);
+
+static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
+				    unsigned id,
+				    void (*callback)(struct virtqueue *vq),
+				    const char *name)
+{
+	struct rproc *rproc = vdev_to_rproc(vdev);
+	struct rproc_vdev *rvdev = rproc->rvdev;
+	struct rproc_virtio_vq_info *rpvq;
+	struct virtqueue *vq;
+	void *addr;
+	int ret, len;
+
+	rpvq = kmalloc(sizeof(*rpvq), GFP_KERNEL);
+	if (!rpvq)
+		return ERR_PTR(-ENOMEM);
+
+	rpvq->rproc = rproc;
+	rpvq->vq_id = id;
+
+	addr = rvdev->vring[id].va;
+	len = rvdev->vring[id].len;
+
+	dev_dbg(rproc->dev, "vring%d: va %p qsz %d\n", id, addr, len);
+
+	vq = vring_new_virtqueue(len, AMP_VRING_ALIGN, vdev, addr,
+					rproc_virtio_notify, callback, name);
+	if (!vq) {
+		dev_err(rproc->dev, "vring_new_virtqueue %s failed\n", name);
+		ret = -ENOMEM;
+		goto free_rpvq;
+	}
+
+	rvdev->vq[id] = vq;
+	vq->priv = rpvq;
+
+	return vq;
+
+free_rpvq:
+	kfree(rpvq);
+	return ERR_PTR(ret);
+}
+
+static void rproc_virtio_del_vqs(struct virtio_device *vdev)
+{
+	struct virtqueue *vq, *n;
+	struct rproc *rproc = vdev_to_rproc(vdev);
+
+	list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
+		struct rproc_virtio_vq_info *rpvq = vq->priv;
+		vring_del_virtqueue(vq);
+		kfree(rpvq);
+	}
+
+	/* power down the remote processor */
+	rproc_shutdown(rproc);
+}
+
+static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs,
+		       struct virtqueue *vqs[],
+		       vq_callback_t *callbacks[],
+		       const char *names[])
+{
+	struct rproc *rproc = vdev_to_rproc(vdev);
+	int i, ret;
+
+	/* we maintain two virtqueues per remote processor (for RX and TX) */
+	if (nvqs != 2)
+		return -EINVAL;
+
+	/* boot the remote processor */
+	ret = rproc_boot(rproc);
+	if (ret) {
+		dev_err(rproc->dev, "rproc_boot() failed %d\n", ret);
+		goto error;
+	}
+
+	for (i = 0; i < nvqs; ++i) {
+		vqs[i] = rp_find_vq(vdev, i, callbacks[i], names[i]);
+		if (IS_ERR(vqs[i])) {
+			ret = PTR_ERR(vqs[i]);
+			goto error;
+		}
+	}
+
+	return 0;
+
+error:
+	rproc_virtio_del_vqs(vdev);
+	return ret;
+}
+
+/*
+ * We don't support yet real virtio status semantics.
+ *
+ * The plan is to provide this via the VIRTIO HDR resource entry
+ * which is part of the firmware: this way the remote processor
+ * will be able to access the status values as set by us.
+ */
+static u8 rproc_virtio_get_status(struct virtio_device *vdev)
+{
+	return 0;
+}
+
+static void rproc_virtio_set_status(struct virtio_device *vdev, u8 status)
+{
+	dev_dbg(&vdev->dev, "new status: %d\n", status);
+}
+
+static void rproc_virtio_reset(struct virtio_device *vdev)
+{
+	dev_dbg(&vdev->dev, "reset !\n");
+}
+
+/* provide the vdev features as retrieved from the firmware */
+static u32 rproc_virtio_get_features(struct virtio_device *vdev)
+{
+	struct rproc *rproc = vdev_to_rproc(vdev);
+
+	/* we only support a single vdev device for now */
+	return rproc->rvdev->dfeatures;
+}
+
+static void rproc_virtio_finalize_features(struct virtio_device *vdev)
+{
+	struct rproc *rproc = vdev_to_rproc(vdev);
+
+	/* Give virtio_ring a chance to accept features */
+	vring_transport_features(vdev);
+
+	/*
+	 * Remember the finalized features of our vdev, and provide it
+	 * to the remote processor once it is powered on.
+	 *
+	 * Similarly to the status field, we don't expose yet the negotiated
+	 * features to the remote processors at this point. This will be
+	 * fixed as part of a small resource table overhaul and then an
+	 * extension of the virtio resource entries.
+	 */
+	rproc->rvdev->gfeatures = vdev->features[0];
+}
+
+static struct virtio_config_ops rproc_virtio_config_ops = {
+	.get_features	= rproc_virtio_get_features,
+	.finalize_features = rproc_virtio_finalize_features,
+	.find_vqs	= rproc_virtio_find_vqs,
+	.del_vqs	= rproc_virtio_del_vqs,
+	.reset		= rproc_virtio_reset,
+	.set_status	= rproc_virtio_set_status,
+	.get_status	= rproc_virtio_get_status,
+};
+
+/*
+ * This function is called whenever vdev is released, and is responsible
+ * to decrement the remote processor's refcount taken when vdev was
+ * added.
+ *
+ * Never call this function directly; it will be called by the driver
+ * core when needed.
+ */
+static void rproc_vdev_release(struct device *dev)
+{
+	struct virtio_device *vdev = dev_to_virtio(dev);
+	struct rproc *rproc = vdev_to_rproc(vdev);
+
+	kref_put(&rproc->refcount, rproc_release);
+}
+
+/**
+ * rproc_add_rpmsg_vdev() - create an rpmsg virtio device
+ * @rproc: the rproc handle
+ *
+ * This function is called if virtio rpmsg support was found in the
+ * firmware of the remote processor.
+ *
+ * Today we only support creating a single rpmsg vdev (virtio device),
+ * but the plan is to remove this limitation. At that point this interface
+ * will be revised/extended.
+ */
+int rproc_add_rpmsg_vdev(struct rproc *rproc)
+{
+	struct device *dev = rproc->dev;
+	struct rproc_vdev *rvdev = rproc->rvdev;
+	int ret;
+
+	rvdev->vdev.id.device	= VIRTIO_ID_RPMSG,
+	rvdev->vdev.config	= &rproc_virtio_config_ops,
+	rvdev->vdev.dev.parent	= dev;
+	rvdev->vdev.dev.release	= rproc_vdev_release;
+
+	/*
+	 * We're indirectly making a non-temporary copy of the rproc pointer
+	 * here, because drivers probed with this vdev will indirectly
+	 * access the wrapping rproc.
+	 *
+	 * Therefore we must increment the rproc refcount here, and decrement
+	 * it _only_ when the vdev is released.
+	 */
+	kref_get(&rproc->refcount);
+
+	ret = register_virtio_device(&rvdev->vdev);
+	if (ret) {
+		kref_put(&rproc->refcount, rproc_release);
+		dev_err(dev, "failed to register vdev: %d\n", ret);
+	}
+
+	return ret;
+}
+
+/**
+ * rproc_remove_rpmsg_vdev() - remove an rpmsg vdev device
+ * @rproc: the rproc handle
+ *
+ * This function is called whenever @rproc is removed _iff_ an rpmsg
+ * vdev was created beforehand.
+ */
+void rproc_remove_rpmsg_vdev(struct rproc *rproc)
+{
+	struct rproc_vdev *rvdev = rproc->rvdev;
+
+	unregister_virtio_device(&rvdev->vdev);
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("OMAP Remote processor messaging virtio device");
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 4/7] amp/omap: add a remoteproc driver
  2011-10-25  9:48 [PATCH 0/7] Introducing a generic AMP framework Ohad Ben-Cohen
                   ` (2 preceding siblings ...)
  2011-10-25  9:48 ` [PATCH 3/7] amp/remoteproc: create rpmsg virtio device Ohad Ben-Cohen
@ 2011-10-25  9:48 ` Ohad Ben-Cohen
  2011-12-08  7:57   ` Ohad Ben-Cohen
  2011-10-25  9:48 ` [PATCH 5/7] ARM: OMAP: add amp/remoteproc support Ohad Ben-Cohen
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 34+ messages in thread
From: Ohad Ben-Cohen @ 2011-10-25  9:48 UTC (permalink / raw)
  To: linux-omap, linux-kernel, linux-arm-kernel
  Cc: akpm, Brian Swetland, Arnd Bergmann, Grant Likely, Rusty Russell,
	Tony Lindgren, Russell King, Ohad Ben-Cohen, Greg KH,
	Stephen Boyd

Add a remoteproc driver for OMAP4, so we can boot the dual-M3 "Ducati"
and DSP subsystems.

Use the omap_device_* API to control the hardware state, and utilize
the OMAP mailbox to interrupt the remote processor when a new message
is pending (the mailbox payload is used to tell it which virtqueue was
the message placed in).

Conversely, when an inbound mailbox message arrives, tell the remoteproc
core which virtqueue is triggered.

Later we will also use the mailbox payload to signal omap-specific
events like remote crashes (which will be used to trigger remoteproc
recovery) and power management transitions. At that point we will also
extend the remoteproc core to support this.

Based on (but now quite far from) work done by Fernando Guzman Lugo
<fernando.lugo@ti.com> and Hari Kanigeri <h-kanigeri2@ti.com>.

Designed with Brian Swetland <swetland@google.com>.

Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Cc: Brian Swetland <swetland@google.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Tony Lindgren <tony@atomide.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Greg KH <greg@kroah.com>
Cc: Stephen Boyd <sboyd@codeaurora.org>
---
 arch/arm/plat-omap/include/plat/remoteproc.h |   56 ++++++
 drivers/amp/remoteproc/Kconfig               |   21 +++
 drivers/amp/remoteproc/Makefile              |    4 +-
 drivers/amp/remoteproc/omap_remoteproc.c     |  248 ++++++++++++++++++++++++++
 drivers/amp/remoteproc/omap_remoteproc.h     |   69 +++++++
 5 files changed, 397 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/plat-omap/include/plat/remoteproc.h
 create mode 100644 drivers/amp/remoteproc/omap_remoteproc.c
 create mode 100644 drivers/amp/remoteproc/omap_remoteproc.h

diff --git a/arch/arm/plat-omap/include/plat/remoteproc.h b/arch/arm/plat-omap/include/plat/remoteproc.h
new file mode 100644
index 0000000..8bfefde
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/remoteproc.h
@@ -0,0 +1,56 @@
+/*
+ * Remote Processor - omap-specific bits
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 _PLAT_REMOTEPROC_H
+#define _PLAT_REMOTEPROC_H
+
+struct rproc_ops;
+struct platform_device;
+
+/*
+ * struct omap_rproc_pdata - omap remoteproc's platform data
+ * @name: the remoteproc's name
+ * @oh_name: omap hwmod device
+ * @oh_name_opt: optional, secondary omap hwmod device
+ * @firmware: name of firmware file to load
+ * @mbox_name: name of omap mailbox device to use with this rproc
+ * @ops: start/stop rproc handlers
+ * @device_enable: omap-specific handler for enabling a device
+ * @device_shutdown: omap-specific handler for shutting down a device
+ */
+struct omap_rproc_pdata {
+	const char *name;
+	const char *oh_name;
+	const char *oh_name_opt;
+	const char *firmware;
+	const char *mbox_name;
+	const struct rproc_ops *ops;
+	int (*device_enable) (struct platform_device *pdev);
+	int (*device_shutdown) (struct platform_device *pdev);
+};
+
+#if defined(CONFIG_OMAP_REMOTEPROC) || defined(CONFIG_OMAP_REMOTEPROC_MODULE)
+
+void __init omap_rproc_reserve_cma(void);
+
+#else
+
+void __init omap_rproc_reserve_cma(void)
+{
+}
+
+#endif
+
+#endif /* _PLAT_REMOTEPROC_H */
diff --git a/drivers/amp/remoteproc/Kconfig b/drivers/amp/remoteproc/Kconfig
index b250b15..78ebff9 100644
--- a/drivers/amp/remoteproc/Kconfig
+++ b/drivers/amp/remoteproc/Kconfig
@@ -1,3 +1,24 @@
 # REMOTEPROC gets selected by whoever wants it
 config REMOTEPROC
 	tristate
+
+config OMAP_REMOTEPROC
+	tristate "OMAP remoteproc support"
+	depends on ARCH_OMAP4
+	select OMAP_IOMMU
+	select REMOTEPROC
+	select OMAP_MBOX_FWK
+	select RPMSG
+	default m
+	help
+	  Say y here to support OMAP's remote processors (dual M3
+	  and DSP on OMAP4) via the remote processor framework.
+
+	  Currently only supported on OMAP4.
+
+	  Usually you want to say y here, in order to enable multimedia
+	  use-cases to run on your platform (multimedia codecs are
+	  offloaded to remote DSP processors using this framework).
+
+	  It's safe to say n here if you're not interested in multimedia
+	  offloading or just want a bare minimum kernel.
\ No newline at end of file
diff --git a/drivers/amp/remoteproc/Makefile b/drivers/amp/remoteproc/Makefile
index 0a24a3b..c948081 100644
--- a/drivers/amp/remoteproc/Makefile
+++ b/drivers/amp/remoteproc/Makefile
@@ -5,4 +5,6 @@
 obj-$(CONFIG_REMOTEPROC)		+= remoteproc.o
 remoteproc-y				:= remoteproc_core.o
 remoteproc-y				+= remoteproc_debugfs.o
-remoteproc-y				+= remoteproc_rpmsg.o
\ No newline at end of file
+remoteproc-y				+= remoteproc_rpmsg.o
+
+obj-$(CONFIG_OMAP_REMOTEPROC)		+= omap_remoteproc.o
\ No newline at end of file
diff --git a/drivers/amp/remoteproc/omap_remoteproc.c b/drivers/amp/remoteproc/omap_remoteproc.c
new file mode 100644
index 0000000..79573c9
--- /dev/null
+++ b/drivers/amp/remoteproc/omap_remoteproc.c
@@ -0,0 +1,248 @@
+/*
+ * OMAP Remote Processor driver
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ * Fernando Guzman Lugo <fernando.lugo@ti.com>
+ * Mark Grosen <mgrosen@ti.com>
+ * Suman Anna <s-anna@ti.com>
+ * Hari Kanigeri <h-kanigeri2@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/amp/remoteproc.h>
+
+#include <plat/mailbox.h>
+#include <plat/remoteproc.h>
+
+#include "omap_remoteproc.h"
+#include "remoteproc_internal.h"
+
+/**
+ * struct omap_rproc - omap remote processor state
+ * @mbox: omap mailbox handle
+ * @nb: notifier block that will be invoked on inbound mailbox messages
+ * @rproc: rproc handle
+ */
+struct omap_rproc {
+	struct omap_mbox *mbox;
+	struct notifier_block nb;
+	struct rproc *rproc;
+};
+
+/**
+ * omap_rproc_mbox_callback() - inbound mailbox message handler
+ * @this: notifier block
+ * @index: unused
+ * @data: mailbox payload
+ *
+ * This handler is invoked by omap's mailbox driver whenever a mailbox
+ * message is received. Usually, the mailbox payload simply contains
+ * the index of the virtqueue that is kicked by the remote processor,
+ * and we let remoteproc core handle it.
+ *
+ * In addition to virtqueue indices, we also have some out-of-band values
+ * that indicates different events. Those values are deliberately very
+ * big so they don't coincide with virtqueue indices.
+ */
+static int omap_rproc_mbox_callback(struct notifier_block *this,
+					unsigned long index, void *data)
+{
+	mbox_msg_t msg = (mbox_msg_t) data;
+	struct omap_rproc *oproc = container_of(this, struct omap_rproc, nb);
+	struct device *dev = oproc->rproc->dev;
+	const char *name = oproc->rproc->name;
+
+	dev_dbg(dev, "mbox msg: 0x%x\n", msg);
+
+	switch (msg) {
+	case RP_MBOX_CRASH:
+		/* just log this for now. later, we'll also do recovery */
+		dev_err(dev, "omap rproc %s crashed\n", name);
+		break;
+	case RP_MBOX_ECHO_REPLY:
+		dev_info(dev, "received echo reply from %s\n", name);
+		break;
+	default:
+		/* ignore vq indices which are too large to be valid */
+		if (msg >= 2) {
+			dev_warn(dev, "invalid mbox msg: 0x%x\n", msg);
+			break;
+		}
+
+		/*
+		 * At this point, 'msg' contains the index of the vring
+		 * which was just triggered.
+		 */
+		if (rproc_vq_interrupt(oproc->rproc, msg) == IRQ_NONE)
+			dev_dbg(dev, "no message was found in vqid %d\n", msg);
+	}
+
+	return NOTIFY_DONE;
+}
+
+/* kick a virtqueue */
+static void omap_rproc_kick(struct rproc *rproc, int vqid)
+{
+	struct omap_rproc *oproc = rproc->priv;
+	int ret;
+
+	/* send the index of the triggered virtqueue in the mailbox payload */
+	ret = omap_mbox_msg_send(oproc->mbox, vqid);
+	if (ret)
+		dev_err(rproc->dev, "omap_mbox_msg_send failed: %d\n", ret);
+}
+
+/*
+ * Power up the remote processor.
+ *
+ * This function will be invoked only after the firmware for this rproc
+ * was loaded, parsed successfully, and all of its resource requirements
+ * were met.
+ */
+static int omap_rproc_start(struct rproc *rproc)
+{
+	struct omap_rproc *oproc = rproc->priv;
+	struct platform_device *pdev = to_platform_device(rproc->dev);
+	struct omap_rproc_pdata *pdata = pdev->dev.platform_data;
+	int ret;
+
+	oproc->nb.notifier_call = omap_rproc_mbox_callback;
+
+	/* every omap rproc is assigned a mailbox instance for messaging */
+	oproc->mbox = omap_mbox_get(pdata->mbox_name, &oproc->nb);
+	if (IS_ERR(oproc->mbox)) {
+		ret = PTR_ERR(oproc->mbox);
+		dev_err(rproc->dev, "omap_mbox_get failed: %d\n", ret);
+		return ret;
+	}
+
+	/*
+	 * Ping the remote processor. this is only for sanity-sake;
+	 * there is no functional effect whatsoever.
+	 *
+	 * Note that the reply will _not_ arrive immediately: this message
+	 * will wait in the mailbox fifo until the remote processor is booted.
+	 */
+	ret = omap_mbox_msg_send(oproc->mbox, RP_MBOX_ECHO_REQUEST);
+	if (ret) {
+		dev_err(rproc->dev, "omap_mbox_get failed: %d\n", ret);
+		goto put_mbox;
+	}
+
+	ret = pdata->device_enable(pdev);
+	if (ret) {
+		dev_err(rproc->dev, "omap_device_enable failed: %d\n", ret);
+		goto put_mbox;
+	}
+
+	return 0;
+
+put_mbox:
+	omap_mbox_put(oproc->mbox, &oproc->nb);
+	return ret;
+}
+
+/* power off the remote processor */
+static int omap_rproc_stop(struct rproc *rproc)
+{
+	struct platform_device *pdev = to_platform_device(rproc->dev);
+	struct omap_rproc_pdata *pdata = pdev->dev.platform_data;
+	struct omap_rproc *oproc = rproc->priv;
+	int ret;
+
+	ret = pdata->device_shutdown(pdev);
+	if (ret)
+		return ret;
+
+	omap_mbox_put(oproc->mbox, &oproc->nb);
+
+	return 0;
+}
+
+static struct rproc_ops omap_rproc_ops = {
+	.start		= omap_rproc_start,
+	.stop		= omap_rproc_stop,
+	.kick		= omap_rproc_kick,
+};
+
+static int __devinit omap_rproc_probe(struct platform_device *pdev)
+{
+	struct omap_rproc_pdata *pdata = pdev->dev.platform_data;
+	struct omap_rproc *oproc;
+	struct rproc *rproc;
+	int ret;
+
+	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+	if (ret) {
+		dev_err(pdev->dev.parent, "dma_set_coherent_mask: %d\n", ret);
+		return ret;
+	}
+
+	rproc = rproc_alloc(&pdev->dev, pdata->name, &omap_rproc_ops,
+				pdata->firmware, sizeof(*oproc));
+	if (!rproc)
+		return -ENOMEM;
+
+	oproc = rproc->priv;
+	oproc->rproc = rproc;
+
+	platform_set_drvdata(pdev, rproc);
+
+	ret = rproc_register(rproc);
+	if (ret)
+		goto free_rproc;
+
+	return 0;
+
+free_rproc:
+	rproc_free(rproc);
+	return ret;
+}
+
+static int __devexit omap_rproc_remove(struct platform_device *pdev)
+{
+	struct rproc *rproc = platform_get_drvdata(pdev);
+
+	return rproc_unregister(rproc);
+}
+
+static struct platform_driver omap_rproc_driver = {
+	.probe = omap_rproc_probe,
+	.remove = __devexit_p(omap_rproc_remove),
+	.driver = {
+		.name = "omap-rproc",
+		.owner = THIS_MODULE,
+	},
+};
+
+/* most of the below will go when module_platform_driver is merged */
+static int __init omap_rproc_init(void)
+{
+	return platform_driver_register(&omap_rproc_driver);
+}
+module_init(omap_rproc_init);
+
+static void __exit omap_rproc_exit(void)
+{
+	platform_driver_unregister(&omap_rproc_driver);
+}
+module_exit(omap_rproc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("OMAP Remote Processor control driver");
diff --git a/drivers/amp/remoteproc/omap_remoteproc.h b/drivers/amp/remoteproc/omap_remoteproc.h
new file mode 100644
index 0000000..f6d2036
--- /dev/null
+++ b/drivers/amp/remoteproc/omap_remoteproc.h
@@ -0,0 +1,69 @@
+/*
+ * 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 _OMAP_RPMSG_H
+#define _OMAP_RPMSG_H
+
+/*
+ * enum - Predefined Mailbox Messages
+ *
+ * @RP_MBOX_READY: informs the M3's that we're up and running. this is
+ * part of the init sequence sent that the M3 expects to see immediately
+ * after it is booted.
+ *
+ * @RP_MBOX_PENDING_MSG: informs the receiver that there is an inbound
+ * message waiting in its own receive-side vring. please note that currently
+ * this message is optional: alternatively, one can explicitly send the index
+ * of the triggered virtqueue itself. the preferred approach will be decided
+ * as we progress and experiment with those two different approaches.
+ *
+ * @RP_MBOX_CRASH: this message is sent if BIOS crashes
+ *
+ * @RP_MBOX_ECHO_REQUEST: a mailbox-level "ping" message.
+ *
+ * @RP_MBOX_ECHO_REPLY: a mailbox-level reply to a "ping"
+ *
+ * @RP_MBOX_ABORT_REQUEST: a "please crash" request, used for testing the
+ * recovery mechanism (to some extent).
+ */
+enum omap_rp_mbox_messages {
+	RP_MBOX_READY		= 0xFFFFFF00,
+	RP_MBOX_PENDING_MSG	= 0xFFFFFF01,
+	RP_MBOX_CRASH		= 0xFFFFFF02,
+	RP_MBOX_ECHO_REQUEST	= 0xFFFFFF03,
+	RP_MBOX_ECHO_REPLY	= 0xFFFFFF04,
+	RP_MBOX_ABORT_REQUEST	= 0xFFFFFF05,
+};
+
+#endif /* _OMAP_RPMSG_H */
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 5/7] ARM: OMAP: add amp/remoteproc support
  2011-10-25  9:48 [PATCH 0/7] Introducing a generic AMP framework Ohad Ben-Cohen
                   ` (3 preceding siblings ...)
  2011-10-25  9:48 ` [PATCH 4/7] amp/omap: add a remoteproc driver Ohad Ben-Cohen
@ 2011-10-25  9:48 ` Ohad Ben-Cohen
  2011-10-25  9:48 ` [PATCH 6/7] amp/rpmsg: add virtio-based remote processor messaging bus Ohad Ben-Cohen
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 34+ messages in thread
From: Ohad Ben-Cohen @ 2011-10-25  9:48 UTC (permalink / raw)
  To: linux-omap, linux-kernel, linux-arm-kernel
  Cc: akpm, Brian Swetland, Arnd Bergmann, Grant Likely, Rusty Russell,
	Tony Lindgren, Russell King, Ohad Ben-Cohen, Greg KH,
	Stephen Boyd

Add an omap-rproc device with which one can start using OMAP4's
dual-M3 "Ducati" ipu subsystem.

Currently we're adding support only for the first M3 core (hence
the name "ipu_c0"); support for the second M3 core, as well as for
the DSP subsystem, will be added later on.

Bind this device to its dedicated IOMMU device, and assign it a
dedicated mailbox instance too.

In addition, reserve it a physically contiguous memory region using
the upcoming CMA mechanism (this makes this patch impossible to merge
at this point, but this patch only).

This patch also depends on:
- https://lkml.org/lkml/2011/9/25/44
- http://www.spinics.net/lists/linux-omap/msg59342.html

Note: at this point we're using a fixed CMA base address (as defined by
OMAP_RPROC_CMA_BASE), but this will go away once the generic iommu-based
DMA API will materialize, because at that point we will (almost) not care about
the physical location of the CMA memory.

Based on (but now quite far from) work done by Fernando Guzman Lugo
<fernando.lugo@ti.com>.

Designed with Brian Swetland <swetland@google.com>.

Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Cc: Brian Swetland <swetland@google.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Tony Lindgren <tony@atomide.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Greg KH <greg@kroah.com>
Cc: Stephen Boyd <sboyd@codeaurora.org>
---
 MAINTAINERS                      |    6 ++
 arch/arm/mach-omap2/Makefile     |    4 +
 arch/arm/mach-omap2/remoteproc.c |  167 ++++++++++++++++++++++++++++++++++++++
 arch/arm/plat-omap/common.c      |    3 +-
 drivers/amp/remoteproc/Kconfig   |   14 +++-
 5 files changed, 192 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/mach-omap2/remoteproc.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 2812cd7..db3b08a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4597,6 +4597,12 @@ T:	git git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap-2.6.git
 S:	Maintained
 F:	arch/arm/*omap*/
 
+OMAP ASYNCHRONOUS MULTIPROCESSING (AMP) SUPPORT
+M:	Ohad Ben-Cohen <ohad@wizery.com>
+L:	linux-omap@vger.kernel.org
+S:	Maintained
+F:	arch/arm/*omap*/*remoteproc*
+
 OMAP CLOCK FRAMEWORK SUPPORT
 M:	Paul Walmsley <paul@pwsan.com>
 L:	linux-omap@vger.kernel.org
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 5129785..6b567ea 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -270,3 +270,7 @@ disp-$(CONFIG_OMAP2_DSS)		:= display.o
 obj-y					+= $(disp-m) $(disp-y)
 
 obj-y					+= common-board-devices.o twl-common.o
+
+ifneq ($(CONFIG_OMAP_REMOTEPROC),)
+obj-y					+= remoteproc.o
+endif
diff --git a/arch/arm/mach-omap2/remoteproc.c b/arch/arm/mach-omap2/remoteproc.c
new file mode 100644
index 0000000..342d446
--- /dev/null
+++ b/arch/arm/mach-omap2/remoteproc.c
@@ -0,0 +1,167 @@
+/*
+ * Remote processor machine-specific module for OMAP4
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt)    "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/amp/remoteproc.h>
+#include <linux/dma-contiguous.h>
+#include <linux/dma-mapping.h>
+
+#include <plat/omap_device.h>
+#include <plat/omap_hwmod.h>
+#include <plat/remoteproc.h>
+#include <plat/iommu.h>
+
+/*
+ * Temporarily define the CMA base address explicitly.
+ *
+ * This will go away as soon as we have the IOMMU-based generic
+ * DMA API in place.
+ */
+#define OMAP_RPROC_CMA_BASE	(0xa9800000)
+
+/*
+ * These data structures define platform-specific information
+ * needed for each supported remote processor.
+ *
+ * At this point we only support the remote dual M3 "Ducati" imaging
+ * subsystem (aka "ipu"), but later on we'll also add support for the
+ * DSP ("Tesla").
+ */
+static struct omap_rproc_pdata omap4_rproc_data[] = {
+	{
+		.name		= "ipu_c0",
+		.firmware	= "ducati-m3-core0.xem3",
+		.mbox_name	= "mailbox-1",
+		.oh_name	= "ipu_c0",
+	},
+};
+
+static struct omap_iommu_arch_data omap4_rproc_iommu[] = {
+	{ .name = "ducati" },
+};
+
+static struct omap_device_pm_latency omap_rproc_latency[] = {
+	{
+		.deactivate_func = omap_device_idle_hwmods,
+		.activate_func = omap_device_enable_hwmods,
+		.flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+	},
+};
+
+static struct platform_device omap4_ducati = {
+	.name	= "omap-rproc",
+	.id	= 1, /* reserve 0 for tesla. we respect. */
+};
+
+static struct platform_device *omap4_rproc_devs[] __initdata = {
+	&omap4_ducati,
+};
+
+void __init omap_rproc_reserve_cma(void)
+{
+	int ret;
+
+	/* reserve CMA memory for OMAP4's M3 "ducati" remote processor */
+	ret = dma_declare_contiguous(&omap4_ducati.dev,
+					CONFIG_OMAP_DUCATI_CMA_SIZE,
+					OMAP_RPROC_CMA_BASE, 0);
+	if (ret)
+		pr_err("dma_declare_contiguous failed %d\n", ret);
+}
+
+static int __init omap_rproc_init(void)
+{
+	struct omap_hwmod *oh[2];
+	struct omap_device *od;
+	int i, ret = 0, oh_count;
+
+	/* names like ipu_cx/dsp_cx might show up on other OMAPs, too */
+	if (!cpu_is_omap44xx())
+		return 0;
+
+	/* build the remote proc devices */
+	for (i = 0; i < ARRAY_SIZE(omap4_rproc_data); i++) {
+		const char *oh_name = omap4_rproc_data[i].oh_name;
+		const char *oh_name_opt = omap4_rproc_data[i].oh_name_opt;
+		struct platform_device *pdev = omap4_rproc_devs[i];
+		oh_count = 0;
+
+		oh[0] = omap_hwmod_lookup(oh_name);
+		if (!oh[0]) {
+			pr_err("could not look up %s\n", oh_name);
+			continue;
+		}
+		oh_count++;
+
+		/*
+		 * ipu might have a secondary hwmod entry (for configurations
+		 * where we want both M3 cores to be represented by a single
+		 * device).
+		 */
+		if (oh_name_opt) {
+			oh[1] = omap_hwmod_lookup(oh_name_opt);
+			if (!oh[1]) {
+				pr_err("could not look up %s\n", oh_name_opt);
+				continue;
+			}
+			oh_count++;
+		}
+
+		omap4_rproc_data[i].device_enable = omap_device_enable;
+		omap4_rproc_data[i].device_shutdown = omap_device_shutdown;
+
+		device_initialize(&pdev->dev);
+
+		/* Set dev_name early to allow dev_xxx in omap_device_alloc */
+		dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
+
+		od = omap_device_alloc(pdev, oh, oh_count,
+					omap_rproc_latency,
+					ARRAY_SIZE(omap_rproc_latency));
+		if (!od) {
+			dev_err(&pdev->dev, "omap_device_alloc failed\n");
+			put_device(&pdev->dev);
+			ret = PTR_ERR(od);
+			continue;
+		}
+
+		ret = platform_device_add_data(pdev,
+					&omap4_rproc_data[i],
+					sizeof(struct omap_rproc_pdata));
+		if (ret) {
+			dev_err(&pdev->dev, "can't add pdata\n");
+			omap_device_delete(od);
+			put_device(&pdev->dev);
+			continue;
+		}
+
+		/* attach the remote processor to its iommu device */
+		pdev->dev.archdata.iommu = &omap4_rproc_iommu[i];
+
+		ret = omap_device_register(pdev);
+		if (ret) {
+			dev_err(&pdev->dev, "omap_device_register failed\n");
+			omap_device_delete(od);
+			put_device(&pdev->dev);
+			continue;
+		}
+	}
+
+	return ret;
+}
+device_initcall(omap_rproc_init);
diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c
index d9f10a3..e2aa143 100644
--- a/arch/arm/plat-omap/common.c
+++ b/arch/arm/plat-omap/common.c
@@ -20,7 +20,7 @@
 #include <plat/board.h>
 #include <plat/vram.h>
 #include <plat/dsp.h>
-
+#include <plat/remoteproc.h>
 
 #define NO_LENGTH_CHECK 0xffffffff
 
@@ -65,4 +65,5 @@ void __init omap_reserve(void)
 	omapfb_reserve_sdram_memblock();
 	omap_vram_reserve_sdram_memblock();
 	omap_dsp_reserve_sdram_memblock();
+	omap_rproc_reserve_cma();
 }
diff --git a/drivers/amp/remoteproc/Kconfig b/drivers/amp/remoteproc/Kconfig
index 78ebff9..e1c617e 100644
--- a/drivers/amp/remoteproc/Kconfig
+++ b/drivers/amp/remoteproc/Kconfig
@@ -21,4 +21,16 @@ config OMAP_REMOTEPROC
 	  offloaded to remote DSP processors using this framework).
 
 	  It's safe to say n here if you're not interested in multimedia
-	  offloading or just want a bare minimum kernel.
\ No newline at end of file
+	  offloading or just want a bare minimum kernel.
+
+# Amount of CMA memory to reserve for OMAP's dual-M3 "Ducati" sub-system.
+# We need quite much. Fortunately, CMA makes sure this memory isn't
+# wasted in case we're not loading the remote processors.
+config OMAP_DUCATI_CMA_SIZE
+	hex "Ducati M3 physically contiguous memory pool size (in bytes)"
+	depends on OMAP_REMOTEPROC
+	default 0x6500000
+	help
+	  Allocate a specified size of physically contiguous memory (CMA)
+	  for OMAP's dual M3 "Ducati" sub-system. Vast majority of this
+	  memory isn't wasted in case the M3 sub-system isn't loaded.
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 6/7] amp/rpmsg: add virtio-based remote processor messaging bus
  2011-10-25  9:48 [PATCH 0/7] Introducing a generic AMP framework Ohad Ben-Cohen
                   ` (4 preceding siblings ...)
  2011-10-25  9:48 ` [PATCH 5/7] ARM: OMAP: add amp/remoteproc support Ohad Ben-Cohen
@ 2011-10-25  9:48 ` Ohad Ben-Cohen
  2011-10-25  9:48 ` [PATCH 7/7] samples/amp: add an rpmsg driver sample Ohad Ben-Cohen
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 34+ messages in thread
From: Ohad Ben-Cohen @ 2011-10-25  9:48 UTC (permalink / raw)
  To: linux-omap, linux-kernel, linux-arm-kernel
  Cc: akpm, Brian Swetland, Arnd Bergmann, Grant Likely, Rusty Russell,
	Tony Lindgren, Russell King, Ohad Ben-Cohen, Greg KH,
	Stephen Boyd

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 <swetland@google.com>.

Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Cc: Brian Swetland <swetland@google.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Tony Lindgren <tony@atomide.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Greg KH <greg@kroah.com>
Cc: Stephen Boyd <sboyd@codeaurora.org>
---
 Documentation/ABI/testing/sysfs-bus-rpmsg |   75 +++
 Documentation/amp/rpmsg.txt               |  293 ++++++++
 Documentation/virtual/virtio-spec.txt     |   94 +++
 drivers/amp/Kconfig                       |    2 +
 drivers/amp/Makefile                      |    1 +
 drivers/amp/rpmsg/Kconfig                 |    6 +
 drivers/amp/rpmsg/Makefile                |    2 +
 drivers/amp/rpmsg/virtio_rpmsg_bus.c      | 1026 +++++++++++++++++++++++++++++
 include/linux/amp/rpmsg.h                 |  326 +++++++++
 include/linux/mod_devicetable.h           |    9 +
 include/linux/virtio_ids.h                |    1 +
 11 files changed, 1835 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-rpmsg
 create mode 100644 Documentation/amp/rpmsg.txt
 create mode 100644 drivers/amp/rpmsg/Kconfig
 create mode 100644 drivers/amp/rpmsg/Makefile
 create mode 100644 drivers/amp/rpmsg/virtio_rpmsg_bus.c
 create mode 100644 include/linux/amp/rpmsg.h

diff --git a/Documentation/ABI/testing/sysfs-bus-rpmsg b/Documentation/ABI/testing/sysfs-bus-rpmsg
new file mode 100644
index 0000000..189e419
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-rpmsg
@@ -0,0 +1,75 @@
+What:		/sys/bus/rpmsg/devices/.../name
+Date:		June 2011
+KernelVersion:	3.3
+Contact:	Ohad Ben-Cohen <ohad@wizery.com>
+Description:
+		Every rpmsg device is a communication channel with a remote
+		processor. Channels are identified with a (textual) name,
+		which is maximum 32 bytes long (defined as RPMSG_NAME_SIZE in
+		rpmsg.h).
+
+		This sysfs entry contains the name of this channel.
+
+What:		/sys/bus/rpmsg/devices/.../src
+Date:		June 2011
+KernelVersion:	3.3
+Contact:	Ohad Ben-Cohen <ohad@wizery.com>
+Description:
+		Every rpmsg device is a communication channel with a remote
+		processor. Channels have a local ("source") rpmsg address,
+		and remote ("destination") rpmsg address. When an entity
+		starts listening on one end of a channel, it assigns it with
+		a unique rpmsg address (a 32 bits integer). This way when
+		inbound messages arrive to this address, the rpmsg core
+		dispatches them to the listening entity (a kernel driver).
+
+		This sysfs entry contains the src (local) rpmsg address
+		of this channel. If it contains 0xffffffff, then an address
+		wasn't assigned (can happen if no driver exists for this
+		channel).
+
+What:		/sys/bus/rpmsg/devices/.../dst
+Date:		June 2011
+KernelVersion:	3.3
+Contact:	Ohad Ben-Cohen <ohad@wizery.com>
+Description:
+		Every rpmsg device is a communication channel with a remote
+		processor. Channels have a local ("source") rpmsg address,
+		and remote ("destination") rpmsg address. When an entity
+		starts listening on one end of a channel, it assigns it with
+		a unique rpmsg address (a 32 bits integer). This way when
+		inbound messages arrive to this address, the rpmsg core
+		dispatches them to the listening entity.
+
+		This sysfs entry contains the dst (remote) rpmsg address
+		of this channel. If it contains 0xffffffff, then an address
+		wasn't assigned (can happen if the kernel driver that
+		is attached to this channel is exposing a service to the
+		remote processor. This make it a local rpmsg server,
+		and it is listening for inbound messages that may be sent
+		from any remote rpmsg client; it is not bound to a single
+		remote entity).
+
+What:		/sys/bus/rpmsg/devices/.../announce
+Date:		June 2011
+KernelVersion:	3.3
+Contact:	Ohad Ben-Cohen <ohad@wizery.com>
+Description:
+		Every rpmsg device is a communication channel with a remote
+		processor. Channels are identified by a textual name (see
+		/sys/bus/rpmsg/devices/.../name above) and have a local
+		("source") rpmsg address, and remote ("destination") rpmsg
+		address.
+
+		A channel is first created when an entity, whether local
+		or remote, starts listening on it for messages (and is thus
+		called an rpmsg server).
+
+		When that happens, a "name service" announcement is sent
+		to the other processor, in order to let it know about the
+		creation of the channel (this way remote clients know they
+		can start sending messages).
+
+		This sysfs entry tells us whether the channel is a local
+		server channel that is announced (values are either
+		true or false).
diff --git a/Documentation/amp/rpmsg.txt b/Documentation/amp/rpmsg.txt
new file mode 100644
index 0000000..a41ffd0
--- /dev/null
+++ b/Documentation/amp/rpmsg.txt
@@ -0,0 +1,293 @@
+Remote Processor Messaging (rpmsg) Framework
+
+Note: this document describes the rpmsg bus and how to write rpmsg drivers.
+To learn how to add rpmsg support for new platforms, check out remoteproc.txt
+(also a resident of Documentation/amp/).
+
+1. Introduction
+
+Modern SoCs typically employ heterogeneous remote processor devices in
+asymmetric multiprocessing (AMP) configurations, which may be running
+different instances of operating system, whether it's Linux or any other
+flavor of real-time OS.
+
+OMAP4, for example, has dual Cortex-A9, dual Cortex-M3 and a C64x+ DSP.
+Typically, the dual cortex-A9 is running Linux in a SMP configuration,
+and each of the other three cores (two M3 cores and a DSP) is running
+its own instance of RTOS in an AMP configuration.
+
+Typically AMP remote processors employ dedicated DSP codecs and multimedia
+hardware accelerators, and therefore are often used to offload CPU-intensive
+multimedia tasks from the main application processor.
+
+These remote processors could also be used to control latency-sensitive
+sensors, drive random hardware blocks, or just perform background tasks
+while the main CPU is idling.
+
+Users of those remote processors can either be userland apps (e.g. multimedia
+frameworks talking with remote OMX components) or kernel drivers (controlling
+hardware accessible only by the remote processor, reserving kernel-controlled
+resources on behalf of the remote processor, etc..).
+
+Rpmsg is a virtio-based messaging bus that allows kernel drivers to communicate
+with remote processors available on the system. In turn, drivers could then
+expose appropriate user space interfaces, if needed.
+
+When writing a driver that exposes rpmsg communication to userland, please
+keep in mind that remote processors might have direct access to the
+system's physical memory and other sensitive hardware resources (e.g. on
+OMAP4, remote cores and hardware accelerators may have direct access to the
+physical memory, gpio banks, dma controllers, i2c bus, gptimers, mailbox
+devices, hwspinlocks, etc..). Moreover, those remote processors might be
+running RTOS where every task can access the entire memory/devices exposed
+to the processor. To minimize the risks of rogue (or buggy) userland code
+exploiting remote bugs, and by that taking over the system, it is often
+desired to limit userland to specific rpmsg channels (see definition below)
+it can send messages on, and if possible, minimize how much control
+it has over the content of the messages.
+
+Every rpmsg device is a communication channel with a remote processor (thus
+rpmsg devices are called channels). Channels are identified by a textual name
+and have a local ("source") rpmsg address, and remote ("destination") rpmsg
+address.
+
+When a driver starts listening on a channel, its rx callback is bound with
+a unique rpmsg local address (a 32-bit integer). This way when inbound messages
+arrive, the rpmsg core dispatches them to the appropriate driver according
+to their destination address (this is done by invoking the driver's rx handler
+with the payload of the inbound message).
+
+
+2. User API
+
+  int rpmsg_send(struct rpmsg_channel *rpdev, void *data, int len);
+   - sends a message across to the remote processor on a given channel.
+     The caller should specify the channel, the data it wants to send,
+     and its length (in bytes). The message will be sent on the specified
+     channel, i.e. its source and destination address fields will be
+     set to the channel's src and dst addresses.
+
+     In case there are no TX buffers available, the function will block until
+     one becomes available (i.e. until the remote processor consumes
+     a tx buffer and puts it back on virtio's used descriptor ring),
+     or a timeout of 15 seconds elapses. When the latter happens,
+     -ERESTARTSYS is returned.
+     The function can only be called from a process context (for now).
+     Returns 0 on success and an appropriate error value on failure.
+
+  int rpmsg_sendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst);
+   - sends a message across to the remote processor on a given channel,
+     to a destination address provided by the caller.
+     The caller should specify the channel, the data it wants to send,
+     its length (in bytes), and an explicit destination address.
+     The message will then be sent to the remote processor to which the
+     channel belongs, using the channel's src address, and the user-provided
+     dst address (thus the channel's dst address will be ignored).
+
+     In case there are no TX buffers available, the function will block until
+     one becomes available (i.e. until the remote processor consumes
+     a tx buffer and puts it back on virtio's used descriptor ring),
+     or a timeout of 15 seconds elapses. When the latter happens,
+     -ERESTARTSYS is returned.
+     The function can only be called from a process context (for now).
+     Returns 0 on success and an appropriate error value on failure.
+
+  int rpmsg_send_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
+							void *data, int len);
+   - sends a message across to the remote processor, using the src and dst
+     addresses provided by the user.
+     The caller should specify the channel, the data it wants to send,
+     its length (in bytes), and explicit source and destination addresses.
+     The message will then be sent to the remote processor to which the
+     channel belongs, but the channel's src and dst addresses will be
+     ignored (and the user-provided addresses will be used instead).
+
+     In case there are no TX buffers available, the function will block until
+     one becomes available (i.e. until the remote processor consumes
+     a tx buffer and puts it back on virtio's used descriptor ring),
+     or a timeout of 15 seconds elapses. When the latter happens,
+     -ERESTARTSYS is returned.
+     The function can only be called from a process context (for now).
+     Returns 0 on success and an appropriate error value on failure.
+
+  int rpmsg_trysend(struct rpmsg_channel *rpdev, void *data, int len);
+   - sends a message across to the remote processor on a given channel.
+     The caller should specify the channel, the data it wants to send,
+     and its length (in bytes). The message will be sent on the specified
+     channel, i.e. its source and destination address fields will be
+     set to the channel's src and dst addresses.
+
+     In case there are no TX buffers available, the function will immediately
+     return -ENOMEM without waiting until one becomes available.
+     The function can only be called from a process context (for now).
+     Returns 0 on success and an appropriate error value on failure.
+
+  int rpmsg_trysendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst)
+   - sends a message across to the remote processor on a given channel,
+     to a destination address provided by the user.
+     The user should specify the channel, the data it wants to send,
+     its length (in bytes), and an explicit destination address.
+     The message will then be sent to the remote processor to which the
+     channel belongs, using the channel's src address, and the user-provided
+     dst address (thus the channel's dst address will be ignored).
+
+     In case there are no TX buffers available, the function will immediately
+     return -ENOMEM without waiting until one becomes available.
+     The function can only be called from a process context (for now).
+     Returns 0 on success and an appropriate error value on failure.
+
+  int rpmsg_trysend_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst,
+							void *data, int len);
+   - sends a message across to the remote processor, using source and
+     destination addresses provided by the user.
+     The user should specify the channel, the data it wants to send,
+     its length (in bytes), and explicit source and destination addresses.
+     The message will then be sent to the remote processor to which the
+     channel belongs, but the channel's src and dst addresses will be
+     ignored (and the user-provided addresses will be used instead).
+
+     In case there are no TX buffers available, the function will immediately
+     return -ENOMEM without waiting until one becomes available.
+     The function can only be called from a process context (for now).
+     Returns 0 on success and an appropriate error value on failure.
+
+  struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *rpdev,
+		void (*cb)(struct rpmsg_channel *, void *, int, void *, u32),
+		void *priv, u32 addr);
+   - 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 they provide 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 channel (so the new endpoint would bind
+     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.
+
+  void rpmsg_destroy_ept(struct rpmsg_endpoint *ept);
+   - destroys an existing rpmsg endpoint. user should provide a pointer
+     to an rpmsg endpoint that was previously created with rpmsg_create_ept().
+
+  int register_rpmsg_driver(struct rpmsg_driver *rpdrv);
+   - registers an rpmsg driver with the rpmsg bus. user should provide
+     a pointer to an rpmsg_driver struct, which contains the driver's
+     ->probe() and ->remove() functions, an rx callback, and an id_table
+     specifying the names of the channels this driver is interested to
+     be probed with.
+
+  void unregister_rpmsg_driver(struct rpmsg_driver *rpdrv);
+   - unregisters an rpmsg driver from the rpmsg bus. user should provide
+     a pointer to a previously-registered rpmsg_driver struct.
+     Returns 0 on success, and an appropriate error value on failure.
+
+
+3. Typical usage
+
+The following is a simple rpmsg driver, that sends an "hello!" message
+on probe(), and whenever it receives an incoming message, it dumps its
+content to the console.
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/rpmsg.h>
+
+static void rpmsg_sample_cb(struct rpmsg_channel *rpdev, void *data, int len,
+						void *priv, u32 src)
+{
+	print_hex_dump(KERN_INFO, "incoming message:", DUMP_PREFIX_NONE,
+						16, 1, data, len, true);
+}
+
+static int rpmsg_sample_probe(struct rpmsg_channel *rpdev)
+{
+	int err;
+
+	dev_info(&rpdev->dev, "chnl: 0x%x -> 0x%x\n", rpdev->src, rpdev->dst);
+
+	/* send a message on our channel */
+	err = rpmsg_send(rpdev, "hello!", 6);
+	if (err) {
+		pr_err("rpmsg_send failed: %d\n", err);
+		return err;
+	}
+
+	return 0;
+}
+
+static void __devexit rpmsg_sample_remove(struct rpmsg_channel *rpdev)
+{
+	dev_info(&rpdev->dev, "rpmsg sample client driver is removed\n");
+}
+
+static struct rpmsg_device_id rpmsg_driver_sample_id_table[] = {
+	{ .name	= "rpmsg-client-sample" },
+	{ },
+};
+MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_sample_id_table);
+
+static struct rpmsg_driver rpmsg_sample_client = {
+	.drv.name	= KBUILD_MODNAME,
+	.drv.owner	= THIS_MODULE,
+	.id_table	= rpmsg_driver_sample_id_table,
+	.probe		= rpmsg_sample_probe,
+	.callback	= rpmsg_sample_cb,
+	.remove		= __devexit_p(rpmsg_sample_remove),
+};
+
+static int __init init(void)
+{
+	return register_rpmsg_driver(&rpmsg_sample_client);
+}
+module_init(init);
+
+static void __exit fini(void)
+{
+	unregister_rpmsg_driver(&rpmsg_sample_client);
+}
+module_exit(fini);
+
+Note: a similar sample which can be built and loaded can be found
+in samples/amp/.
+
+4. Allocations of rpmsg channels:
+
+At this point we only support dynamic allocations of rpmsg channels.
+
+This is possible only with remote processors that have the VIRTIO_RPMSG_F_NS
+virtio device feature set. This feature bit means that the remote
+processor supports dynamic name service announcement messages.
+
+When this feature is enabled, creation of rpmsg devices (i.e. channels)
+is completely dynamic: the remote processor announces the existence of a
+remote rpmsg service by sending a name service message (which contains
+the name and rpmsg addr of the remote service, see struct rpmsg_ns_msg).
+
+This message is then handled by the rpmsg bus, which in turn dynamically
+creates and registers an rpmsg channel (which represents the remote service).
+If/when a relevant rpmsg driver is registered, it will be immediately probed
+by the bus, and can then start sending messages to the remote service.
+
+The plan is also to add static creation of rpmsg channels via the virtio
+config space, but it's not implemented yet.
diff --git a/Documentation/virtual/virtio-spec.txt b/Documentation/virtual/virtio-spec.txt
index a350ae1..b574065 100644
--- a/Documentation/virtual/virtio-spec.txt
+++ b/Documentation/virtual/virtio-spec.txt
@@ -106,6 +106,8 @@ for informational purposes by the guest).
 +----------------------+--------------------+---------------+
 |          6           |     ioMemory       |       -       |
 +----------------------+--------------------+---------------+
+|          7           |       rpmsg        |  Appendix H   |
++----------------------+--------------------+---------------+
 |          9           |   9P transport     |       -       |
 +----------------------+--------------------+---------------+
 
@@ -2198,3 +2200,95 @@ as follows:
   VIRTIO_BALLOON_S_MEMTOT The total amount of memory available
   (in bytes).
 
+Appendix H: Rpmsg: Remote Processor Messaging
+
+Virtio rpmsg devices represent remote processors on the system
+which run in asymmetric multi-processing (AMP) configuration, and
+which are usually used to offload cpu-intensive tasks from the main
+application processor.
+
+Virtio is being used to communicate with those remote processors;
+empty buffers are placed in one virtqueue for receiving messages, and
+non-empty buffers, containing outbound messages, are enqueued in
+a second virtqueue for transmission.
+
+Numerous communication channels can be multiplexed over those two
+virtqueues, so different entities, running on the application and remote
+processor, can directly communicate in a point-to-point fashion.
+
+  Configuration
+
+  Subsystem Device ID 7
+
+  Virtqueues 0:receiveq. 1:transmitq.
+
+  Feature bits
+
+  VIRTIO_RPMSG_F_NS (0) Device sends (and capable of receiving) name service
+    messages announcing the creation (or destruction) of a channel:
+
+/**
+ * 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 receives these messages, an appropriate
+ * rpmsg channel (i.e device) is created/destroyed.
+ */
+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 remote service was just destroyed
+ */
+enum rpmsg_ns_flags {
+	RPMSG_NS_CREATE		= 0,
+	RPMSG_NS_DESTROY	= 1,
+};
+
+  Device configuration layout
+
+  At his point none currently defined, but the plan is to use the
+  the config space for announcing the existence of static channels
+  and configuring their addresses.
+
+  Device Initialization
+
+  The initialization routine should identify the receive and
+  transmission virtqueues.
+
+  The receive virtqueue should be filled with receive buffers.
+
+  Device Operation
+
+  Messages are transmitted by placing them in the transmitq, and
+  buffers for inbound messages are placed in the receiveq. In any
+  case, messages are always preceded by the following header:
+
+/**
+ * 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;
diff --git a/drivers/amp/Kconfig b/drivers/amp/Kconfig
index 23a8ed1..9580849 100644
--- a/drivers/amp/Kconfig
+++ b/drivers/amp/Kconfig
@@ -6,4 +6,6 @@ menu "Asymmetric Multiprocessing (AMP) Framework"
 
 source "drivers/amp/remoteproc/Kconfig"
 
+source "drivers/amp/rpmsg/Kconfig"
+
 endmenu
diff --git a/drivers/amp/Makefile b/drivers/amp/Makefile
index 708461d..ea71d56 100644
--- a/drivers/amp/Makefile
+++ b/drivers/amp/Makefile
@@ -1 +1,2 @@
 obj-$(CONFIG_REMOTEPROC)	+= remoteproc/
+obj-$(CONFIG_RPMSG)		+= rpmsg/
diff --git a/drivers/amp/rpmsg/Kconfig b/drivers/amp/rpmsg/Kconfig
new file mode 100644
index 0000000..480944c
--- /dev/null
+++ b/drivers/amp/rpmsg/Kconfig
@@ -0,0 +1,6 @@
+# RPMSG always gets selected by whoever wants it
+config RPMSG
+	tristate
+	select VIRTIO
+	select VIRTIO_RING
+
diff --git a/drivers/amp/rpmsg/Makefile b/drivers/amp/rpmsg/Makefile
new file mode 100644
index 0000000..ba8e3c5
--- /dev/null
+++ b/drivers/amp/rpmsg/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_RPMSG)	+= virtio_rpmsg_bus.o
+
diff --git a/drivers/amp/rpmsg/virtio_rpmsg_bus.c b/drivers/amp/rpmsg/virtio_rpmsg_bus.c
new file mode 100644
index 0000000..f3d111f
--- /dev/null
+++ b/drivers/amp/rpmsg/virtio_rpmsg_bus.c
@@ -0,0 +1,1026 @@
+/*
+ * Virtio-based remote processor messaging bus
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/virtio.h>
+#include <linux/virtio_ids.h>
+#include <linux/virtio_config.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/idr.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/amp/rpmsg.h>
+#include <linux/mutex.h>
+
+/**
+ * struct virtproc_info - virtual remote processor state
+ * @vdev:	the virtio device
+ * @rvq:	rx virtqueue
+ * @svq:	tx virtqueue
+ * @rbufs:	kernel address of rx buffers
+ * @sbufs:	kernel address of tx buffers
+ * @last_sbuf:	index of last tx buffer used
+ * @bufs_dma:	dma base addr of the buffers
+ * @tx_lock:	protects svq, sbufs and sleepers, to allow concurrent senders.
+ *		sending a message might require waking up a dozing remote
+ *		processor, which involves sleeping, hence the mutex.
+ * @endpoints:	idr of local endpoints, allows fast retrieval
+ * @endpoints_lock: lock of the endpoints set
+ * @sendq:	wait queue of sending contexts waiting for a tx buffers
+ * @sleepers:	number of senders that are waiting for a tx buffer
+ * @ns_ept:	the bus's name service endpoint
+ *
+ * This structure stores the rpmsg state of a given virtio remote processor
+ * device (there might be several virtio proc devices for each physical
+ * remote processor).
+ */
+struct virtproc_info {
+	struct virtio_device *vdev;
+	struct virtqueue *rvq, *svq;
+	void *rbufs, *sbufs;
+	int last_sbuf;
+	dma_addr_t bufs_dma;
+	struct mutex tx_lock;
+	struct idr endpoints;
+	struct mutex endpoints_lock;
+	wait_queue_head_t sendq;
+	atomic_t sleepers;
+	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_channel(d) container_of(d, struct rpmsg_channel, dev)
+#define to_rpmsg_driver(d) container_of(d, struct rpmsg_driver, drv)
+
+/*
+ * We're allocating 512 buffers of 512 bytes for communications, and then
+ * using the first 256 buffers for RX, and the last 256 buffers for TX.
+ *
+ * Each buffer will have 16 bytes for the msg header and 496 bytes for
+ * the payload.
+ *
+ * This will require a total space of 256KB for the buffers.
+ *
+ * We might also want to add support for user-provided buffers in time.
+ * This will allow bigger buffer size flexibility, and can also be used
+ * to achieve zero-copy messaging.
+ *
+ * Note that these numbers are purely a decision of this driver - we
+ * can change this without changing anything in the firmware of the remote
+ * processor.
+ */
+#define RPMSG_NUM_BUFS		(512)
+#define RPMSG_BUF_SIZE		(512)
+#define RPMSG_TOTAL_BUF_SPACE	(RPMSG_NUM_BUFS * RPMSG_BUF_SIZE)
+
+/*
+ * Local addresses are dynamically allocated on-demand.
+ * We do not dynamically assign addresses from the low 1024 range,
+ * in order to reserve that address range for predefined services.
+ */
+#define RPMSG_RESERVED_ADDRESSES	(1024)
+
+/* Address 53 is reserved for advertising remote services */
+#define RPMSG_NS_ADDR			(53)
+
+/* 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_channel *rpdev = to_rpmsg_channel(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");
+
+/*
+ * Unique (and free running) index for rpmsg devices.
+ *
+ * Yeah, we're not recycling those numbers (yet?). will be easy
+ * to change if/when we want to.
+ */
+static unsigned int rpmsg_dev_index;
+
+static ssize_t modalias_show(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct rpmsg_channel *rpdev = to_rpmsg_channel(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_channel *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_channel *rpdev = to_rpmsg_channel(dev);
+	struct rpmsg_driver *rpdrv = to_rpmsg_driver(drv);
+	const struct rpmsg_device_id *ids = rpdrv->id_table;
+	unsigned int i;
+
+	for (i = 0; ids[i].name[0]; i++)
+		if (rpmsg_id_match(rpdev, &ids[i]))
+			return 1;
+
+	return 0;
+}
+
+static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+	struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+
+	return add_uevent_var(env, "MODALIAS=" RPMSG_DEVICE_MODALIAS_FMT,
+					rpdev->id.name);
+}
+
+/* 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, rpmsg_rx_cb_t cb,
+		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;
+
+	mutex_lock(&vrp->endpoints_lock);
+
+	/* bind the endpoint to an rpmsg address (and allocate one if needed) */
+	err = idr_get_new_above(&vrp->endpoints, ept, request, &tmpaddr);
+	if (err) {
+		dev_err(dev, "idr_get_new_above failed: %d\n", err);
+		goto free_ept;
+	}
+
+	/* make sure the user's address request is fulfilled, if relevant */
+	if (addr != RPMSG_ADDR_ANY && tmpaddr != addr) {
+		dev_err(dev, "address 0x%x already in use\n", addr);
+		goto rem_idr;
+	}
+
+	ept->addr = tmpaddr;
+
+	mutex_unlock(&vrp->endpoints_lock);
+
+	return ept;
+
+rem_idr:
+	idr_remove(&vrp->endpoints, request);
+free_ept:
+	mutex_unlock(&vrp->endpoints_lock);
+	kfree(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_channel *rpdev,
+				rpmsg_rx_cb_t cb, void *priv, u32 addr)
+{
+	return __rpmsg_create_ept(rpdev->vrp, 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)
+{
+	struct virtproc_info *vrp = ept->rpdev->vrp;
+
+	mutex_lock(&vrp->endpoints_lock);
+	idr_remove(&vrp->endpoints, ept->addr);
+	mutex_unlock(&vrp->endpoints_lock);
+
+	kfree(ept);
+}
+EXPORT_SYMBOL(rpmsg_destroy_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_channel *rpdev = to_rpmsg_channel(dev);
+	struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
+	struct virtproc_info *vrp = rpdev->vrp;
+	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;
+	}
+
+	/* need to tell remote processor's name service about this channel ? */
+	if (rpdev->announce &&
+			virtio_has_feature(vrp->vdev, VIRTIO_RPMSG_F_NS)) {
+		struct rpmsg_ns_msg nsm;
+
+		strncpy(nsm.name, rpdev->id.name, RPMSG_NAME_SIZE);
+		nsm.addr = rpdev->src;
+		nsm.flags = RPMSG_NS_CREATE;
+
+		err = rpmsg_sendto(rpdev, &nsm, sizeof(nsm), RPMSG_NS_ADDR);
+		if (err)
+			dev_err(dev, "failed to announce service %d\n", err);
+	}
+
+out:
+	return err;
+}
+
+static int rpmsg_dev_remove(struct device *dev)
+{
+	struct rpmsg_channel *rpdev = to_rpmsg_channel(dev);
+	struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
+	struct virtproc_info *vrp = rpdev->vrp;
+	int err = 0;
+
+	/* tell remote processor's name service we're removing this channel */
+	if (rpdev->announce &&
+			virtio_has_feature(vrp->vdev, VIRTIO_RPMSG_F_NS)) {
+		struct rpmsg_ns_msg nsm;
+
+		strncpy(nsm.name, rpdev->id.name, RPMSG_NAME_SIZE);
+		nsm.addr = rpdev->src;
+		nsm.flags = RPMSG_NS_DESTROY;
+
+		err = rpmsg_sendto(rpdev, &nsm, sizeof(nsm), RPMSG_NS_ADDR);
+		if (err)
+			dev_err(dev, "failed to announce service %d\n", err);
+	}
+
+	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
+ *
+ * Returns 0 on success, and an appropriate error value on failure.
+ */
+int register_rpmsg_driver(struct rpmsg_driver *rpdrv)
+{
+	rpdrv->drv.bus = &rpmsg_bus;
+	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_channel *rpdev = to_rpmsg_channel(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_channel_match(struct device *dev, void *data)
+{
+	struct rpmsg_channel_info *chinfo = data;
+	struct rpmsg_channel *rpdev = to_rpmsg_channel(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;
+}
+
+/*
+ * create an rpmsg channel using its name and address info.
+ * this function will be used to create both static and dynamic
+ * channels.
+ */
+static struct rpmsg_channel *rpmsg_create_channel(struct virtproc_info *vrp,
+				struct rpmsg_channel_info *chinfo)
+{
+	struct rpmsg_channel *rpdev;
+	struct device *tmp, *dev = &vrp->vdev->dev;
+	int ret;
+
+	/* make sure a similar channel doesn't already exist */
+	tmp = device_find_child(dev, chinfo, rpmsg_channel_match);
+	if (tmp) {
+		/* decrement the matched device's refcount back */
+		put_device(tmp);
+		dev_err(dev, "channel %s:%x:%x already exist\n",
+				chinfo->name, chinfo->src, chinfo->dst);
+		return NULL;
+	}
+
+	rpdev = kzalloc(sizeof(struct rpmsg_channel), GFP_KERNEL);
+	if (!rpdev) {
+		pr_err("kzalloc failed\n");
+		return NULL;
+	}
+
+	rpdev->vrp = vrp;
+	rpdev->src = chinfo->src;
+	rpdev->dst = chinfo->dst;
+
+	/*
+	 * rpmsg server channels has predefined local address (for now),
+	 * and their existence needs to be announced remotely
+	 */
+	rpdev->announce = rpdev->src != RPMSG_ADDR_ANY ? true : false;
+
+	strncpy(rpdev->id.name, chinfo->name, RPMSG_NAME_SIZE);
+
+	/* very simple device indexing plumbing which is enough for now */
+	dev_set_name(&rpdev->dev, "rpmsg%d", rpmsg_dev_index++);
+
+	rpdev->dev.parent = &vrp->vdev->dev;
+	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 NULL;
+	}
+
+	return rpdev;
+}
+
+/*
+ * 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);
+
+	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 */
+	mutex_lock(&vrp->tx_lock);
+
+	/*
+	 * either pick the next unused tx buffer
+	 * (half of our buffers are used for sending messages)
+	 */
+	if (vrp->last_sbuf < RPMSG_NUM_BUFS / 2)
+		ret = vrp->sbufs + RPMSG_BUF_SIZE * vrp->last_sbuf++;
+	/* or recycle a used one */
+	else
+		ret = virtqueue_get_buf(vrp->svq, &len);
+
+	mutex_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 */
+	mutex_lock(&vrp->tx_lock);
+
+	/* are we the first sleeping context waiting for tx buffers ? */
+	if (atomic_inc_return(&vrp->sleepers) == 1)
+		/* enable "tx-complete" interrupts before dozing off */
+		virtqueue_enable_cb(vrp->svq);
+
+	mutex_unlock(&vrp->tx_lock);
+}
+
+/**
+ * rpmsg_downref_sleepers() - disable "tx-complete" interrupts, if needed
+ * @vrp: virtual remote processor state
+ *
+ * This function is called after a sender, that waited for a tx buffer
+ * to become available, is unblocked.
+ *
+ * If we still have blocking senders, this function merely decreases
+ * the "sleepers" reference count, and exits.
+ *
+ * Otherwise, if there are no more blocking senders, we also disable
+ * virtio's tx callbacks, to avoid the overhead incurred with handling
+ * those (now redundant) interrupts.
+ */
+static void rpmsg_downref_sleepers(struct virtproc_info *vrp)
+{
+	/* support multiple concurrent senders */
+	mutex_lock(&vrp->tx_lock);
+
+	/* are we the last sleeping context waiting for tx buffers ? */
+	if (atomic_dec_and_test(&vrp->sleepers))
+		/* disable "tx-complete" interrupts */
+		virtqueue_disable_cb(vrp->svq);
+
+	mutex_unlock(&vrp->tx_lock);
+}
+
+/**
+ * rpmsg_send_offchannel_raw() - send a message across to the remote processor
+ * @rpdev: the rpmsg channel
+ * @src: source address
+ * @dst: destination address
+ * @data: payload of message
+ * @len: length of payload
+ * @wait: indicates whether caller should block in case no TX buffers available
+ *
+ * This function is the base implementation for all of the rpmsg sending API.
+ *
+ * It will send @data of length @len to @dst, and say it's from @src. The
+ * message will be sent to the remote processor which the @rpdev channel
+ * belongs to.
+ *
+ * The message is sent using one of the TX buffers that are available for
+ * communication with this remote processor.
+ *
+ * If @wait is true, the caller will be blocked until either a TX buffer is
+ * available, or 15 seconds elapses (we don't want callers to
+ * sleep indefinitely due to misbehaving remote processors), and in that
+ * case -ERESTARTSYS is returned. The number '15' itself was picked
+ * arbitrarily; there's little point in asking drivers to provide a timeout
+ * value themselves.
+ *
+ * Otherwise, if @wait is false, and there are no TX buffers available,
+ * the function will immediately fail, and -ENOMEM will be returned.
+ *
+ * Normally drivers shouldn't use this function directly; instead, drivers
+ * should use the appropriate rpmsg_{try}send{to, _offchannel} API
+ * (see include/linux/rpmsg.h).
+ *
+ * Returns 0 on success and an appropriate error value on failure.
+ */
+int rpmsg_send_offchannel_raw(struct rpmsg_channel *rpdev, u32 src, u32 dst,
+					void *data, int len, bool wait)
+{
+	struct virtproc_info *vrp = rpdev->vrp;
+	struct device *dev = &rpdev->dev;
+	struct scatterlist sg;
+	struct rpmsg_hdr *msg;
+	int err;
+
+	/* bcasting isn't allowed */
+	if (src == RPMSG_ADDR_ANY || dst == RPMSG_ADDR_ANY) {
+		dev_err(dev, "invalid addr (src 0x%x, dst 0x%x)\n", src, dst);
+		return -EINVAL;
+	}
+
+	/*
+	 * We currently use fixed-sized buffers, and therefore the payload
+	 * length is limited.
+	 *
+	 * One of the possible improvements here is either to support
+	 * user-provided buffers (and then we can also support zero-copy
+	 * messaging), or to improve the buffer allocator, to support
+	 * variable-length buffer sizes.
+	 */
+	if (len > RPMSG_BUF_SIZE - sizeof(struct rpmsg_hdr)) {
+		dev_err(dev, "message is too big (%d)\n", len);
+		return -EMSGSIZE;
+	}
+
+	/* grab a buffer */
+	msg = get_a_tx_buf(vrp);
+	if (!msg && !wait)
+		return -ENOMEM;
+
+	/* no free buffer ? wait for one (but bail after 15 seconds) */
+	while (!msg) {
+		/* enable "tx-complete" interrupts, if not already enabled */
+		rpmsg_upref_sleepers(vrp);
+
+		/*
+		 * sleep until a free buffer is available or 15 secs elapse.
+		 * the timeout period is not configurable because there's
+		 * little point in asking drivers to specify that.
+		 * if later this happens to be required, it'd be easy to add.
+		 */
+		err = wait_event_interruptible_timeout(vrp->sendq,
+					(msg = get_a_tx_buf(vrp)),
+					msecs_to_jiffies(15000));
+
+		/* disable "tx-complete" interrupts if we're the last sleeper */
+		rpmsg_downref_sleepers(vrp);
+
+		/* timeout ? */
+		if (!err) {
+			dev_err(dev, "timeout waiting for a tx buffer\n");
+			return -ERESTARTSYS;
+		}
+	}
+
+	msg->len = len;
+	msg->flags = 0;
+	msg->src = src;
+	msg->dst = dst;
+	msg->reserved = 0;
+	memcpy(msg->data, data, len);
+
+	dev_dbg(dev, "TX From 0x%x, To 0x%x, Len %d, Flags %d, Reserved %d\n",
+					msg->src, msg->dst, msg->len,
+					msg->flags, msg->reserved);
+	print_hex_dump(KERN_DEBUG, "rpmsg_virtio TX: ", DUMP_PREFIX_NONE, 16, 1,
+					msg, sizeof(*msg) + msg->len, true);
+
+	sg_init_one(&sg, msg, sizeof(*msg) + len);
+
+	mutex_lock(&vrp->tx_lock);
+
+	/* add message to the remote processor's virtqueue */
+	err = virtqueue_add_buf_gfp(vrp->svq, &sg, 1, 0, msg, GFP_KERNEL);
+	if (err < 0) {
+		/*
+		 * need to reclaim the buffer here, otherwise it's lost
+		 * (memory won't leak, but rpmsg won't use it again for TX).
+		 * this will wait for a buffer management overhaul.
+		 */
+		dev_err(dev, "virtqueue_add_buf_gfp failed: %d\n", err);
+		goto out;
+	}
+
+	/* tell the remote processor it has a pending message to read */
+	virtqueue_kick(vrp->svq);
+
+	err = 0;
+out:
+	mutex_unlock(&vrp->tx_lock);
+	return err;
+}
+EXPORT_SYMBOL(rpmsg_send_offchannel_raw);
+
+/* called when an rx buffer is used, and it's time to digest a message */
+static void rpmsg_recv_done(struct virtqueue *rvq)
+{
+	struct rpmsg_hdr *msg;
+	unsigned int len;
+	struct rpmsg_endpoint *ept;
+	struct scatterlist sg;
+	struct virtproc_info *vrp = rvq->vdev->priv;
+	struct device *dev = &rvq->vdev->dev;
+	int err;
+
+	msg = virtqueue_get_buf(rvq, &len);
+	if (!msg) {
+		dev_err(dev, "uhm, incoming signal, but no used buffer ?\n");
+		return;
+	}
+
+	dev_dbg(dev, "From: 0x%x, To: 0x%x, Len: %d, Flags: %d, Reserved: %d\n",
+					msg->src, msg->dst, msg->len,
+					msg->flags, msg->reserved);
+	print_hex_dump(KERN_DEBUG, "rpmsg_virtio RX: ", DUMP_PREFIX_NONE, 16, 1,
+					msg, sizeof(*msg) + msg->len, true);
+
+	/* use the dst addr to fetch the callback of the appropriate user */
+	mutex_lock(&vrp->endpoints_lock);
+	ept = idr_find(&vrp->endpoints, msg->dst);
+	mutex_unlock(&vrp->endpoints_lock);
+
+	if (ept && ept->cb)
+		ept->cb(ept->rpdev, msg->data, msg->len, ept->priv, msg->src);
+	else
+		dev_warn(dev, "msg received with no recepient\n");
+
+	sg_init_one(&sg, msg, sizeof(*msg) + len);
+
+	/* add the buffer back to the remote processor's virtqueue */
+	err = virtqueue_add_buf_gfp(vrp->rvq, &sg, 0, 1, msg, GFP_KERNEL);
+	if (err < 0) {
+		dev_err(dev, "failed to add a virtqueue buffer: %d\n", err);
+		return;
+	}
+
+	/* tell the remote processor we added another available rx buffer */
+	virtqueue_kick(vrp->rvq);
+}
+
+/*
+ * This is invoked whenever the remote processor completed processing
+ * a TX msg we just sent it, and the buffer is put back to the used ring.
+ *
+ * Normally, though, we suppress this "tx complete" interrupt in order to
+ * avoid the incurred overhead.
+ */
+static void rpmsg_xmit_done(struct virtqueue *svq)
+{
+	struct virtproc_info *vrp = svq->vdev->priv;
+
+	dev_dbg(&svq->vdev->dev, "%s\n", __func__);
+
+	/* wake up potential senders that are waiting for a tx buffer */
+	wake_up_interruptible(&vrp->sendq);
+}
+
+/* invoked when a name service announcement arrives */
+static void rpmsg_ns_cb(struct rpmsg_channel *rpdev, void *data, int len,
+							void *priv, u32 src)
+{
+	struct rpmsg_ns_msg *msg = data;
+	struct rpmsg_channel *newch;
+	struct rpmsg_channel_info chinfo;
+	struct virtproc_info *vrp = priv;
+	struct device *dev = &vrp->vdev->dev;
+	int ret;
+
+	print_hex_dump(KERN_DEBUG, "NS announcement: ",
+			DUMP_PREFIX_NONE, 16, 1,
+			data, len, true);
+
+	if (len != sizeof(*msg)) {
+		dev_err(dev, "malformed ns msg (%d)\n", len);
+		return;
+	}
+
+	/*
+	 * the name service ept does _not_ belong to a real rpmsg channel,
+	 * and is handled by the rpmsg bus itself.
+	 * for sanity reasons, make sure a valid rpdev has _not_ sneaked
+	 * in somehow.
+	 */
+	if (rpdev) {
+		dev_err(dev, "anomaly: ns ept has an rpdev handle\n");
+		return;
+	}
+
+	/* don't trust the remote processor for null terminating the name */
+	msg->name[RPMSG_NAME_SIZE - 1] = '\0';
+
+	dev_info(dev, "%sing channel %s addr 0x%x\n",
+			msg->flags & RPMSG_NS_DESTROY ? "destroy" : "creat",
+			msg->name, msg->addr);
+
+	strncpy(chinfo.name, msg->name, sizeof(chinfo.name));
+	chinfo.src = RPMSG_ADDR_ANY;
+	chinfo.dst = msg->addr;
+
+	if (msg->flags & RPMSG_NS_DESTROY) {
+		ret = rpmsg_destroy_channel(vrp, &chinfo);
+		if (ret)
+			dev_err(dev, "rpmsg_destroy_channel failed: %d\n", ret);
+	} else {
+		newch = rpmsg_create_channel(vrp, &chinfo);
+		if (!newch)
+			dev_err(dev, "rpmsg_create_channel failed\n");
+	}
+}
+
+static int rpmsg_probe(struct virtio_device *vdev)
+{
+	vq_callback_t *vq_cbs[] = { rpmsg_recv_done, rpmsg_xmit_done };
+	const char *names[] = { "input", "output" };
+	struct virtqueue *vqs[2];
+	struct virtproc_info *vrp;
+	void *bufs_va;
+	int err = 0, i;
+
+	vrp = kzalloc(sizeof(*vrp), GFP_KERNEL);
+	if (!vrp)
+		return -ENOMEM;
+
+	vrp->vdev = vdev;
+
+	idr_init(&vrp->endpoints);
+	mutex_init(&vrp->endpoints_lock);
+	mutex_init(&vrp->tx_lock);
+	init_waitqueue_head(&vrp->sendq);
+
+	/* We expect two virtqueues, rx and tx (and in this order) */
+	err = vdev->config->find_vqs(vdev, 2, vqs, vq_cbs, names);
+	if (err)
+		goto free_vrp;
+
+	vrp->rvq = vqs[0];
+	vrp->svq = vqs[1];
+
+	/* allocate coherent memory for the buffers */
+	bufs_va = dma_alloc_coherent(vdev->dev.parent, RPMSG_TOTAL_BUF_SPACE,
+				&vrp->bufs_dma, GFP_KERNEL);
+	if (!bufs_va)
+		goto vqs_del;
+
+	dev_dbg(&vdev->dev, "buffers: va %p, dma 0x%x\n", bufs_va,
+						vrp->bufs_dma);
+
+	/* half of the buffers is dedicated for RX */
+	vrp->rbufs = bufs_va;
+
+	/* and half is dedicated for TX */
+	vrp->sbufs = bufs_va + RPMSG_TOTAL_BUF_SPACE / 2;
+
+	/* set up the receive buffers */
+	for (i = 0; i < RPMSG_NUM_BUFS / 2; i++) {
+		struct scatterlist sg;
+		void *cpu_addr = vrp->rbufs + i * RPMSG_BUF_SIZE;
+
+		sg_init_one(&sg, cpu_addr, RPMSG_BUF_SIZE);
+
+		err = virtqueue_add_buf_gfp(vrp->rvq, &sg, 0, 1, cpu_addr,
+								GFP_KERNEL);
+		WARN_ON(err < 0); /* sanity check; this can't really happen */
+	}
+
+	/* suppress "tx-complete" interrupts */
+	virtqueue_disable_cb(vrp->svq);
+
+	vdev->priv = vrp;
+
+	/* if supported by the remote processor, enable the name service */
+	if (virtio_has_feature(vdev, VIRTIO_RPMSG_F_NS)) {
+		/* a dedicated endpoint handles the name service msgs */
+		vrp->ns_ept = __rpmsg_create_ept(vrp, NULL, rpmsg_ns_cb,
+						vrp, RPMSG_NS_ADDR);
+		if (!vrp->ns_ept) {
+			dev_err(&vdev->dev, "failed to create the ns ept\n");
+			err = -ENOMEM;
+			goto free_coherent;
+		}
+	}
+
+	/* tell the remote processor it can start sending messages */
+	virtqueue_kick(vrp->rvq);
+
+	dev_info(&vdev->dev, "rpmsg host is online\n");
+
+	return 0;
+
+free_coherent:
+	dma_free_coherent(vdev->dev.parent, RPMSG_TOTAL_BUF_SPACE, bufs_va,
+					vrp->bufs_dma);
+vqs_del:
+	vdev->config->del_vqs(vrp->vdev);
+free_vrp:
+	kfree(vrp);
+	return err;
+}
+
+static int rpmsg_remove_device(struct device *dev, void *data)
+{
+	device_unregister(dev);
+
+	return 0;
+}
+
+static void __devexit rpmsg_remove(struct virtio_device *vdev)
+{
+	struct virtproc_info *vrp = vdev->priv;
+	int ret;
+
+	vdev->config->reset(vdev);
+
+	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);
+
+	dma_free_coherent(vdev->dev.parent, RPMSG_TOTAL_BUF_SPACE,
+					vrp->rbufs, vrp->bufs_dma);
+
+	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 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) {
+		pr_err("failed to register virtio driver: %d\n", ret);
+		bus_unregister(&rpmsg_bus);
+	}
+
+	return ret;
+}
+module_init(rpmsg_init);
+
+static void __exit rpmsg_fini(void)
+{
+	unregister_virtio_driver(&virtio_ipc_driver);
+	bus_unregister(&rpmsg_bus);
+}
+module_exit(rpmsg_fini);
+
+MODULE_DEVICE_TABLE(virtio, id_table);
+MODULE_DESCRIPTION("Virtio-based remote processor messaging bus");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/amp/rpmsg.h b/include/linux/amp/rpmsg.h
new file mode 100644
index 0000000..a8e50e4
--- /dev/null
+++ b/include/linux/amp/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 <linux/types.h>
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+
+/* 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/mod_devicetable.h b/include/linux/mod_devicetable.h
index ae28e93..6176f29 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -405,6 +405,15 @@ struct virtio_device_id {
 };
 #define VIRTIO_DEV_ANY_ID	0xffffffff
 
+/* 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/virtio_ids.h b/include/linux/virtio_ids.h
index 85bb0bb..b37c521 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 */
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 7/7] samples/amp: add an rpmsg driver sample
  2011-10-25  9:48 [PATCH 0/7] Introducing a generic AMP framework Ohad Ben-Cohen
                   ` (5 preceding siblings ...)
  2011-10-25  9:48 ` [PATCH 6/7] amp/rpmsg: add virtio-based remote processor messaging bus Ohad Ben-Cohen
@ 2011-10-25  9:48 ` Ohad Ben-Cohen
  2011-10-26  4:00 ` [PATCH 0/7] Introducing a generic AMP framework Rusty Russell
  2011-11-23  3:25 ` Saravana Kannan
  8 siblings, 0 replies; 34+ messages in thread
From: Ohad Ben-Cohen @ 2011-10-25  9:48 UTC (permalink / raw)
  To: linux-omap, linux-kernel, linux-arm-kernel
  Cc: akpm, Brian Swetland, Arnd Bergmann, Grant Likely, Rusty Russell,
	Tony Lindgren, Russell King, Ohad Ben-Cohen, Greg KH,
	Stephen Boyd

Add an rpmsg driver sample, which demonstrates how to communicate with
an AMP-configured remote processor over the rpmsg bus.

The driver repeatedly sends a "Hello World!" message to the remote
processor.

Note that once probed, the driver can immediately start sending messages
using the rpmsg_send() API, without having to worry about creating endpoints
or allocating rpmsg addresses: all that work is done by the rpmsg bus,
and the required information is already embedded in the rpmsg channel
that the driver is probed with.

Designed with Brian Swetland <swetland@google.com>.

Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Cc: Brian Swetland <swetland@google.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: Tony Lindgren <tony@atomide.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Greg KH <greg@kroah.com>
Cc: Stephen Boyd <sboyd@codeaurora.org>
---
 samples/Kconfig                   |    8 +++
 samples/Makefile                  |    2 +-
 samples/amp/Makefile              |    1 +
 samples/amp/rpmsg_client_sample.c |  100 +++++++++++++++++++++++++++++++++++++
 4 files changed, 110 insertions(+), 1 deletions(-)
 create mode 100644 samples/amp/Makefile
 create mode 100644 samples/amp/rpmsg_client_sample.c

diff --git a/samples/Kconfig b/samples/Kconfig
index 96a7572..997ddd3 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -67,4 +67,12 @@ config SAMPLE_HIDRAW
 	help
 	  Build an example of how to use hidraw from userspace.
 
+config SAMPLE_RPMSG_CLIENT
+	tristate "Build rpmsg client sample -- loadable modules only"
+	depends on RPMSG && m
+	help
+	  Build an rpmsg client sample driver, which demonstrates how
+	  to communicate with an AMP-configured remote processor over
+	  the rpmsg bus.
+
 endif # SAMPLES
diff --git a/samples/Makefile b/samples/Makefile
index 6280817..040f424 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -1,4 +1,4 @@
 # Makefile for Linux samples code
 
 obj-$(CONFIG_SAMPLES)	+= kobject/ kprobes/ tracepoints/ trace_events/ \
-			   hw_breakpoint/ kfifo/ kdb/ hidraw/
+			   hw_breakpoint/ kfifo/ kdb/ hidraw/ amp/
diff --git a/samples/amp/Makefile b/samples/amp/Makefile
new file mode 100644
index 0000000..2d4973c
--- /dev/null
+++ b/samples/amp/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SAMPLE_RPMSG_CLIENT) += rpmsg_client_sample.o
diff --git a/samples/amp/rpmsg_client_sample.c b/samples/amp/rpmsg_client_sample.c
new file mode 100644
index 0000000..7b23380
--- /dev/null
+++ b/samples/amp/rpmsg_client_sample.c
@@ -0,0 +1,100 @@
+/*
+ * Remote processor messaging - sample client driver
+ *
+ * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Ohad Ben-Cohen <ohad@wizery.com>
+ * Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/amp/rpmsg.h>
+
+#define MSG		"hello world!"
+#define MSG_LIMIT	100
+
+static void rpmsg_sample_cb(struct rpmsg_channel *rpdev, void *data, int len,
+						void *priv, u32 src)
+{
+	int ret;
+	static int rx_count;
+
+	dev_info(&rpdev->dev, "incoming msg %d (src: 0x%x)\n", ++rx_count, src);
+
+	print_hex_dump(KERN_DEBUG, __func__, DUMP_PREFIX_NONE, 16, 1,
+		       data, len,  true);
+
+	/* samples should not live forever */
+	if (rx_count >= MSG_LIMIT) {
+		dev_info(&rpdev->dev, "goodbye!\n");
+		return;
+	}
+
+	/* send a new message now */
+	ret = rpmsg_send(rpdev, MSG, strlen(MSG));
+	if (ret)
+		dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
+}
+
+static int rpmsg_sample_probe(struct rpmsg_channel *rpdev)
+{
+	int ret;
+
+	dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
+					rpdev->src, rpdev->dst);
+
+	/* send a message to our remote processor */
+	ret = rpmsg_send(rpdev, MSG, strlen(MSG));
+	if (ret) {
+		dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void __devexit rpmsg_sample_remove(struct rpmsg_channel *rpdev)
+{
+	dev_info(&rpdev->dev, "rpmsg sample client driver is removed\n");
+}
+
+static struct rpmsg_device_id rpmsg_driver_sample_id_table[] = {
+	{ .name	= "rpmsg-client-sample" },
+	{ },
+};
+MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_sample_id_table);
+
+static struct rpmsg_driver rpmsg_sample_client = {
+	.drv.name	= KBUILD_MODNAME,
+	.drv.owner	= THIS_MODULE,
+	.id_table	= rpmsg_driver_sample_id_table,
+	.probe		= rpmsg_sample_probe,
+	.callback	= rpmsg_sample_cb,
+	.remove		= __devexit_p(rpmsg_sample_remove),
+};
+
+static int __init rpmsg_client_sample_init(void)
+{
+	return register_rpmsg_driver(&rpmsg_sample_client);
+}
+module_init(rpmsg_client_sample_init);
+
+static void __exit rpmsg_client_sample_fini(void)
+{
+	unregister_rpmsg_driver(&rpmsg_sample_client);
+}
+module_exit(rpmsg_client_sample_fini);
+
+MODULE_DESCRIPTION("Remote processor messaging sample client driver");
+MODULE_LICENSE("GPL v2");
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 34+ messages in thread

* Re: [PATCH 0/7] Introducing a generic AMP framework
  2011-10-25  9:48 [PATCH 0/7] Introducing a generic AMP framework Ohad Ben-Cohen
                   ` (6 preceding siblings ...)
  2011-10-25  9:48 ` [PATCH 7/7] samples/amp: add an rpmsg driver sample Ohad Ben-Cohen
@ 2011-10-26  4:00 ` Rusty Russell
  2011-10-26  5:26   ` Ohad Ben-Cohen
  2011-11-22 11:40   ` Ohad Ben-Cohen
  2011-11-23  3:25 ` Saravana Kannan
  8 siblings, 2 replies; 34+ messages in thread
From: Rusty Russell @ 2011-10-26  4:00 UTC (permalink / raw)
  To: Ohad Ben-Cohen, linux-omap, linux-kernel, linux-arm-kernel
  Cc: akpm, Brian Swetland, Arnd Bergmann, Grant Likely, Tony Lindgren,
	Russell King, Ohad Ben-Cohen

On Tue, 25 Oct 2011 11:48:19 +0200, Ohad Ben-Cohen <ohad@wizery.com> wrote:
> 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.

OK, I'm not even sure who this should go through, but no objections here
but one:

virtio-spec.txt is a derived document, so I'd prefer that patch to go
through me so I can patch the (LyX) master copy.

Thanks!
Rusty.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 1/7] amp/remoteproc: add framework for controlling remote processors
  2011-10-25  9:48 ` [PATCH 1/7] amp/remoteproc: add framework for controlling remote processors Ohad Ben-Cohen
@ 2011-10-26  5:16   ` Jean-Christophe PLAGNIOL-VILLARD
  2011-10-26  5:25     ` Ohad Ben-Cohen
  2011-11-23  3:27   ` Stephen Boyd
  2012-01-03 23:35   ` Grant Likely
  2 siblings, 1 reply; 34+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2011-10-26  5:16 UTC (permalink / raw)
  To: Ohad Ben-Cohen
  Cc: linux-omap, linux-kernel, linux-arm-kernel, Russell King,
	Arnd Bergmann, Tony Lindgren, Brian Swetland, Rusty Russell,
	Stephen Boyd, Grant Likely, Greg KH, akpm

On 11:48 Tue 25 Oct     , Ohad Ben-Cohen wrote:
> 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
> <fernando.lugo@ti.com>.
> 
> ELF loader was written by Mark Grosen <mgrosen@ti.com>, based on
> msm's Peripheral Image Loader (PIL) by Stephen Boyd <sboyd@codeaurora.org>.
> 
> Designed with Brian Swetland <swetland@google.com>.
> 
> Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
> Cc: Brian Swetland <swetland@google.com>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: Tony Lindgren <tony@atomide.com>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: Rusty Russell <rusty@rustcorp.com.au>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: Greg KH <greg@kroah.com>
> Cc: Stephen Boyd <sboyd@codeaurora.org>
> ---
>  Documentation/amp/remoteproc.txt             |  324 ++++++
>  MAINTAINERS                                  |    7 +
>  drivers/Kconfig                              |    2 +
>  drivers/Makefile                             |    1 +
>  drivers/amp/Kconfig                          |    9 +
>  drivers/amp/Makefile                         |    1 +
>  drivers/amp/remoteproc/Kconfig               |    3 +
>  drivers/amp/remoteproc/Makefile              |    6 +
>  drivers/amp/remoteproc/remoteproc_core.c     | 1410 ++++++++++++++++++++++++++
>  drivers/amp/remoteproc/remoteproc_internal.h |   44 +
>  include/linux/amp/remoteproc.h               |  265 +++++
>  11 files changed, 2072 insertions(+), 0 deletions(-)
>  create mode 100644 Documentation/amp/remoteproc.txt
>  create mode 100644 drivers/amp/Kconfig
>  create mode 100644 drivers/amp/Makefile
>  create mode 100644 drivers/amp/remoteproc/Kconfig
>  create mode 100644 drivers/amp/remoteproc/Makefile
>  create mode 100644 drivers/amp/remoteproc/remoteproc_core.c
>  create mode 100644 drivers/amp/remoteproc/remoteproc_internal.h
>  create mode 100644 include/linux/amp/remoteproc.h
> 
> diff --git a/Documentation/amp/remoteproc.txt b/Documentation/amp/remoteproc.txt
> new file mode 100644
> index 0000000..63cecd9
> --- /dev/null
> +++ b/Documentation/amp/remoteproc.txt
> @@ -0,0 +1,324 @@
> +Remote Processor Framework
> +
> +1. Introduction
> +
> +Modern SoCs typically have heterogeneous remote processor devices in asymmetric
> +multiprocessing (AMP) configurations, which may be running different instances
> +of operating system, whether it's Linux or any other flavor of real-time OS.
> +
> +OMAP4, for example, has dual Cortex-A9, dual Cortex-M3 and a C64x+ DSP.
> +In a typical configuration, the dual cortex-A9 is running Linux in a SMP
> +configuration, and each of the other three cores (two M3 cores and a DSP)
> +is running its own instance of RTOS in an AMP configuration.
> +
> +The remoteproc framework allows different platforms/architectures to
> +control (power on, load firmware, power off) those remote processors while
> +abstracting the hardware differences, so the entire driver doesn't need to be
> +duplicated. In addition, this framework also adds rpmsg virtio devices
> +for remote processors that supports this kind of communication. This way,
> +platform-specific remoteproc drivers only need to provide a few low-level
> +handlers, and then all rpmsg drivers will then just work
> +(for more information about the virtio-based rpmsg bus and its drivers,
> +please read Documentation/amp/rpmsg.txt).
> +
> +2. User API
> +
> +  int rproc_boot(struct rproc *rproc)
> +    - Boot a remote processor (i.e. load its firmware, power it on, ...).
> +      If the remote processor is already powered on, this function immediately
> +      returns (successfully).
> +      Returns 0 on success, and an appropriate error value otherwise.
> +      Note: to use this function you should already have a valid rproc
> +      handle. There are several ways to achieve that cleanly (devres, pdata,
> +      the way remoteproc_rpmsg.c does this, or, if this becomes prevalent, we
> +      might also consider using dev_archdata for this). See also
> +      rproc_get_by_name() below.
> +
> +  void rproc_shutdown(struct rproc *rproc)
> +    - Power off a remote processor (previously booted with rproc_boot()).
> +      In case @rproc is still being used by an additional user(s), then
> +      this function will just decrement the power refcount and exit,
> +      without really powering off the device.
> +      Every call to rproc_boot() must (eventually) be accompanied by a call
> +      to rproc_shutdown(). Calling rproc_shutdown() redundantly is a bug.
> +      Notes:
> +      - we're not decrementing the rproc's refcount, only the power refcount.
> +        which means that the @rproc handle stays valid even after
> +        rproc_shutdown() returns, and users can still use it with a subsequent
> +        rproc_boot(), if needed.
> +      - don't call rproc_shutdown() to unroll rproc_get_by_name(), exactly
> +        because rproc_shutdown() _does not_ decrement the refcount of @rproc.
> +        To decrement the refcount of @rproc, use rproc_put() (but _only_ if
> +        you acquired @rproc using rproc_get_by_name()).
> +
> +  struct rproc *rproc_get_by_name(const char *name)
> +    - Find an rproc handle using the remote processor's name, and then
> +      boot it. If it's already powered on, then just immediately return
> +      (successfully). Returns the rproc handle on success, and NULL on failure.
> +      This function increments the remote processor's refcount, so always
> +      use rproc_put() to decrement it back once rproc isn't needed anymore.
> +      Note: currently this function (and its counterpart rproc_put()) are not
> +      used anymore by the amp sub-system. We need to scrutinize the use cases
> +      that still need them, and see if we can migrate them to use the non
> +      name-based boot/shutdown interface.
> +
> +  void rproc_put(struct rproc *rproc)
> +    - Decrement @rproc's power refcount and shut it down if it reaches zero
> +      (essentially by just calling rproc_shutdown), and then decrement @rproc's
> +      validity refcount too.
> +      After this function returns, @rproc may _not_ be used anymore, and its
> +      handle should be considered invalid.
> +      This function should be called _iff_ the @rproc handle was grabbed by
> +      calling rproc_get_by_name().
> +
> +3. Typical usage
> +
> +#include <linux/amp/remoteproc.h>
> +
> +/* in case we were given a valid 'rproc' handle */
> +int dummy_rproc_example(struct rproc *my_rproc)
> +{
> +	int ret;
> +
> +	/* let's power on and boot our remote processor */
> +	ret = rproc_boot(my_rproc);
> +	if (ret) {
> +		/*
> +		 * something went wrong. handle it and leave.
> +		 */
> +	}
> +
> +	/*
> +	 * our remote processor is now powered on... give it some work
> +	 */
> +
> +	/* let's shut it down now */
> +	rproc_shutdown(my_rproc);
> +}
> +
> +4. API for implementors
> +
> +  struct rproc *rproc_alloc(struct device *dev, const char *name,
> +				const struct rproc_ops *ops,
> +				const char *firmware, int len)
> +    - Allocate a new remote processor handle, but don't register
> +      it yet. Required parameters are the underlying device, the
> +      name of this remote processor, platform-specific ops handlers,
> +      the name of the firmware to boot this rproc with, and the
> +      length of private data needed by the allocating rproc driver (in bytes).
> +
> +      This function should be used by rproc implementations during
> +      initialization of the remote processor.
> +      After creating an rproc handle using this function, and when ready,
> +      implementations should then call rproc_register() to complete
> +      the registration of the remote processor.
> +      On success, the new rproc is returned, and on failure, NULL.
> +
> +      Note: _never_ directly deallocate @rproc, even if it was not registered
> +      yet. Instead, if you just need to unroll rproc_alloc(), use rproc_free().
> +
> +  void rproc_free(struct rproc *rproc)
> +    - Free an rproc handle that was allocated by rproc_alloc.
> +      This function should _only_ be used if @rproc was only allocated,
> +      but not registered yet.
> +      If @rproc was already successfully registered (by calling
> +      rproc_register()), then use rproc_unregister() instead.
> +
> +  int rproc_register(struct rproc *rproc)
> +    - Register @rproc with the remoteproc framework, after it has been
> +      allocated with rproc_alloc().
> +      This is called by the platform-specific rproc implementation, whenever
> +      a new remote processor device is probed.
> +      Returns 0 on success and an appropriate error code otherwise.
> +      Note: this function initiates an asynchronous firmware loading
> +      context, which will look for virtio devices supported by the rproc's
> +      firmware.
> +      If found, those virtio devices will be created and added, so as a result
> +      of registering this remote processor, additional virtio drivers might get
> +      probed.
> +      Currently, though, we only support a single RPMSG virtio vdev per remote
> +      processor.
> +
> +  int rproc_unregister(struct rproc *rproc)
> +    - Unregister a remote processor, and decrement its refcount.
> +      If its refcount drops to zero, then @rproc will be freed. If not,
> +      it will be freed later once the last reference is dropped.
> +
> +      This function should be called when the platform specific rproc
> +      implementation decides to remove the rproc device. it should
> +      _only_ be called if a previous invocation of rproc_register()
> +      has completed successfully.
> +
> +      After rproc_unregister() returns, @rproc is _not_ valid anymore and
> +      it shouldn't be used. More specifically, don't call rproc_free()
> +      or try to directly free @rproc after rproc_unregister() returns;
> +      none of these are needed, and calling them is a bug.
> +
> +      Returns 0 on success and -EINVAL if @rproc isn't valid.
> +
> +5. Implementation callbacks
> +
> +These callbacks should be provided by platform-specific remoteproc
> +drivers:
> +
> +/**
> + * 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);
> +};
> +
> +Every remoteproc implementation should at least provide the ->start and ->stop
> +handlers. If rpmsg functionality is also desired, then the ->kick handler
> +should be provided as well.
> +
> +The ->start() handler takes an rproc handle and should then power on the
> +device and boot it (use rproc->priv to access platform-specific private data).
> +The boot address, in case needed, can be found in rproc->bootaddr (remoteproc
> +core puts there the ELF entry point).
> +On success, 0 should be returned, and on failure, an appropriate error code.
> +
> +The ->stop() handler takes an rproc handle and powers the device down.
> +On success, 0 is returned, and on failure, an appropriate error code.
> +
> +The ->kick() handler takes an rproc handle, and an index of a virtqueue
> +where new message was placed in. Implementations should interrupt the remote
> +processor and let it know it has pending messages. Notifying remote processors
> +the exact virtqueue index to look in is optional: it is easy (and not
> +too expensive) to go through the existing virtqueues and look for new buffers
> +in the used rings.
> +
> +6. Binary Firmware Structure
> +
> +At this point remoteproc only supports ELF32 firmware binaries. However,
> +it is quite expected that other platforms/devices which we'd want to
> +support with this framework will be based on different binary formats.
> +
> +When those use cases show up, we will have to decouple the binary format
> +from the framework core, so we can support several binary formats without
> +duplicating common code.
> +
> +When the firmware is parsed, its various segments are loaded to memory
> +according to the specified device address (might be a physical address
> +if the remote processor is accessing memory directly).
> +
> +In addition to the standard ELF segments, most remote processors would
> +also include a special section which we call "the resource table".
> +
> +The resource table contains system resources that the remote processor
> +requires before it should be powered on, such as allocation of physically
> +contiguous memory, or iommu mapping of certain on-chip peripherals.
> +Remotecore will only power up the device after all the resource table's
> +requirement are met.
> +
> +In addition to system resources, the resource table may also contain
> +resource entries that publish the existence of supported features
> +or configurations by the remote processor, such as trace buffers and
> +supported virtio devices (and their configurations).
> +
> +Currently the resource table is just an array of:
> +
> +/**
> + * 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 fw_resource {
> +	u32 type;
> +	u32 id;
> +	u64 da;
> +	u64 pa;
> +	u32 len;
> +	u32 flags;
> +	u8 reserved[16];
> +	u8 name[48];
> +} __packed;
> +
> +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 will begin with a type and length fields, followed by
> +its own specific structure.
> +
> +Here are the resource types that are currently being used:
> +
> +/**
> + * 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: announces support for a virtio device, and serves as
> + *		    the virtio header. 'da' contains the virtio device
> + *		    features, 'pa' holds the virtio guest features (host
> + *		    will write them here after they're negotiated), 'len'
> + *		    holds the virtio status, and 'flags' holds the virtio
> + *		    device id (currently only VIRTIO_ID_RPMSG is supported).
> + */
> +enum fw_resource_type {
> +	RSC_CARVEOUT	= 0,
> +	RSC_DEVMEM	= 1,
> +	RSC_TRACE	= 2,
> +	RSC_VRING	= 3,
> +	RSC_VIRTIO_DEV	= 4,
> +	RSC_VIRTIO_CFG	= 5,
> +};
> +
> +Most of the resource entries share the basic idea of address/length
> +negotiation with the host: the firmware usually asks 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).
> +
> +We also expect that platform-specific resource entries will show up
> +at some point. When that happens, we could easily add a new RSC_PLAFORM
> +type, and hand those resources to the platform-specific rproc driver to handle.
> +
> +7. Virtio and remoteproc
> +
> +The firmware should provide remoteproc information about virtio devices
> +that it supports, and their configurations: a RSC_VIRTIO_DEV resource entry
> +should specify the virtio device id, and subsequent RSC_VRING resource entries
> +should indicate the vring size (i.e. how many buffers do they support) and
> +where should they be mapped (i.e. which device address). Note: the alignment
> +between the consumer and producer parts of the vring is assumed to be 4096.
> +
> +At this point we only support a single virtio rpmsg device per remote
> +processor, but the plan is to remove this limitation. In addition, once we
> +move to TLV-based resource table, the plan is to have a single RSC_VIRTIO
> +entry per supported virtio device, which will include the virtio header,
> +the vrings information and the virtio config space.
> +
> +Of course, RSC_VIRTIO resource entries are only good enough for static
> +allocation of virtio devices. Dynamic allocations will also be made possible
> +using the rpmsg bus (similar to how we already do dynamic allocations of
> +rpmsg channels; read more about it in rpmsg.txt).
> diff --git a/MAINTAINERS b/MAINTAINERS
> index ace8f9c..2812cd7 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1205,6 +1205,13 @@ L:	lm-sensors@lm-sensors.org
>  S:	Maintained
>  F:	drivers/hwmon/asb100.c
>  
> +ASYNCHRONOUS MULTIPROCESSING (AMP) FRAMEWORK
> +M:	Ohad Ben-Cohen <ohad@wizery.com>
> +S:	Maintained
> +F:	drivers/amp/
> +F:	Documentation/amp/
> +F:	include/linux/amp/
> +
>  ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT) API
>  M:	Dan Williams <dan.j.williams@intel.com>
>  W:	http://sourceforge.net/projects/xscaleiop
> diff --git a/drivers/Kconfig b/drivers/Kconfig
> index 95b9e7e..dfb7d36 100644
> --- a/drivers/Kconfig
> +++ b/drivers/Kconfig
> @@ -128,6 +128,8 @@ source "drivers/clocksource/Kconfig"
>  
>  source "drivers/iommu/Kconfig"
>  
> +source "drivers/amp/Kconfig"
> +
>  source "drivers/virt/Kconfig"
>  
>  endmenu
> diff --git a/drivers/Makefile b/drivers/Makefile
> index 7fa433a..8f41a77 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -124,6 +124,7 @@ obj-y				+= clk/
>  obj-$(CONFIG_HWSPINLOCK)	+= hwspinlock/
>  obj-$(CONFIG_NFC)		+= nfc/
>  obj-$(CONFIG_IOMMU_SUPPORT)	+= iommu/
> +obj-y				+= amp/
>  
>  # Virtualization drivers
>  obj-$(CONFIG_VIRT_DRIVERS)	+= virt/
> diff --git a/drivers/amp/Kconfig b/drivers/amp/Kconfig
> new file mode 100644
> index 0000000..23a8ed1
> --- /dev/null
> +++ b/drivers/amp/Kconfig
> @@ -0,0 +1,9 @@
> +#
> +# AMP subsystem configuration
> +#
> +
> +menu "Asymmetric Multiprocessing (AMP) Framework"
> +
> +source "drivers/amp/remoteproc/Kconfig"
> +
> +endmenu
> diff --git a/drivers/amp/Makefile b/drivers/amp/Makefile
> new file mode 100644
> index 0000000..708461d
> --- /dev/null
> +++ b/drivers/amp/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_REMOTEPROC)	+= remoteproc/
> diff --git a/drivers/amp/remoteproc/Kconfig b/drivers/amp/remoteproc/Kconfig
> new file mode 100644
> index 0000000..b250b15
> --- /dev/null
> +++ b/drivers/amp/remoteproc/Kconfig
> @@ -0,0 +1,3 @@
> +# REMOTEPROC gets selected by whoever wants it
> +config REMOTEPROC
> +	tristate
> diff --git a/drivers/amp/remoteproc/Makefile b/drivers/amp/remoteproc/Makefile
> new file mode 100644
> index 0000000..2a5fd79
> --- /dev/null
> +++ b/drivers/amp/remoteproc/Makefile
> @@ -0,0 +1,6 @@
> +#
> +# Generic framework for controlling remote processors
> +#
> +
> +obj-$(CONFIG_REMOTEPROC)		+= remoteproc.o
> +remoteproc-y				:= remoteproc_core.o
> diff --git a/drivers/amp/remoteproc/remoteproc_core.c b/drivers/amp/remoteproc/remoteproc_core.c
> new file mode 100644
> index 0000000..be6774f
> --- /dev/null
> +++ b/drivers/amp/remoteproc/remoteproc_core.c
> @@ -0,0 +1,1410 @@
> +/*
> + * Remote Processor Framework
> + *
> + * Copyright (C) 2011 Texas Instruments, Inc.
> + * Copyright (C) 2011 Google, Inc.
> + *
> + * Ohad Ben-Cohen <ohad@wizery.com>
> + * Brian Swetland <swetland@google.com>
> + * Mark Grosen <mgrosen@ti.com>
> + * Fernando Guzman Lugo <fernando.lugo@ti.com>
> + * Suman Anna <s-anna@ti.com>
> + * Robert Tivy <rtivy@ti.com>
> + * Armando Uribe De Leon <x0095078@ti.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#define pr_fmt(fmt)    "%s: " fmt, __func__
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/slab.h>
> +#include <linux/mutex.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/firmware.h>
> +#include <linux/string.h>
> +#include <linux/debugfs.h>
> +#include <linux/amp/remoteproc.h>
> +#include <linux/iommu.h>
> +#include <linux/klist.h>
> +#include <linux/elf.h>
> +#include <linux/virtio_ids.h>
> +#include <linux/virtio_ring.h>
> +
> +#include "remoteproc_internal.h"
> +
> +static void klist_rproc_get(struct klist_node *n);
> +static void klist_rproc_put(struct klist_node *n);
> +
> +/*
> + * klist of the available remote processors.
> + *
> + * We need this in order to support name-based lookups (needed by the
> + * rproc_get_by_name()).
> + *
> + * That said, we don't use rproc_get_by_name() anymore within the amp
> + * framework. The use cases that do require its existence should be
> + * scrutinized, and hopefully migrated to rproc_boot() using device-based
> + * binding.
> + *
> + * If/when this materializes, we could drop the klist (and the by_name
> + * API).
> + */
> +static DEFINE_KLIST(rprocs, klist_rproc_get, klist_rproc_put);
> +
> +typedef int (*rproc_handle_resources_t)(struct rproc *rproc,
> +				struct fw_resource *rsc, int len);
> +
> +/*
> + * This is the IOMMU fault handler we register with the IOMMU API
> + * (when relevant; not all remote processors access memory through
> + * an IOMMU).
> + *
> + * IOMMU core will invoke this handler whenever the remote processor
> + * will try to access an unmapped device address.
> + *
> + * Currently this is mostly a stub, but it will be later used to trigger
> + * the recovery of the remote processor.
> + */
> +static int rproc_iommu_fault(struct iommu_domain *domain, struct device *dev,
> +		unsigned long iova, int flags)
> +{
> +	dev_err(dev, "iommu fault: da 0x%lx flags 0x%x\n", iova, flags);
> +
> +	/*
> +	 * Let the iommu core know we're not really handling this fault;
> +	 * we just plan to use this as a recovery trigger.
> +	 */
> +	return -ENOSYS;
> +}
> +
> +static int rproc_enable_iommu(struct rproc *rproc)
> +{
> +	struct iommu_domain *domain;
> +	struct device *dev = rproc->dev;
> +	int ret;
> +
> +	/*
> +	 * We currently use iommu_present() to decide if an IOMMU
> +	 * setup is needed.
> +	 *
> +	 * This works for simple cases, but will easily fail with
> +	 * platforms that do have an IOMMU, but not for this specific
> +	 * rproc.
> +	 *
> +	 * This will be easily solved by introducing hw capabilities
> +	 * that will be set by the remoteproc driver.
> +	 */
> +	if (!iommu_present(dev->bus)) {
> +		dev_err(dev, "iommu not found\n");
> +		return -ENODEV;
> +	}
> +
> +	domain = iommu_domain_alloc(dev->bus);
> +	if (!domain) {
> +		dev_err(dev, "can't alloc iommu domain\n");
> +		return -ENOMEM;
> +	}
> +
> +	iommu_set_fault_handler(domain, rproc_iommu_fault);
> +
> +	ret = iommu_attach_device(domain, dev);
> +	if (ret) {
> +		dev_err(dev, "can't attach iommu device: %d\n", ret);
> +		goto free_domain;
> +	}
> +
> +	rproc->domain = domain;
> +
> +	return 0;
> +
> +free_domain:
> +	iommu_domain_free(domain);
> +	return ret;
> +}
> +
> +static void rproc_disable_iommu(struct rproc *rproc)
> +{
> +	struct iommu_domain *domain = rproc->domain;
> +	struct device *dev = rproc->dev;
> +
> +	if (!domain)
> +		return;
> +
> +	iommu_detach_device(domain, dev);
> +	iommu_domain_free(domain);
> +
> +	return;
> +}
> +
> +/*
> + * Some remote processors will ask us to allocate them physically contiguous
> + * memory regions (which we call "carveouts"), and map them to specific
> + * device addresses (which are hardcoded in the firmware).
> + *
> + * They may then ask us to copy objects into specific device addresses (e.g.
> + * code/data sections) or expose us certain symbols in other device address
> + * (e.g. their trace buffer).
> + *
> + * This function is an internal helper with which we can go over the allocated
> + * carveouts and translate specific device address to kernel virtual addresses
> + * so we can access the referenced memory.
> + *
> + * Note: phys_to_virt(iommu_iova_to_phys(rproc->domain, da)) will work too,
> + * but only on kernel direct mapped RAM memory. Instead, we're just using
> + * here the output of the DMA API, which should be more correct.
> + */
> +static void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +{
> +	struct rproc_mem_entry *carveout;
> +	void *ptr = NULL;
> +
> +	list_for_each_entry(carveout, &rproc->carveouts, node) {
> +		int offset = da - carveout->da;
> +
> +		/* try next carveout if da is too small */
> +		if (offset < 0)
> +			continue;
> +
> +		/* try next carveout if da is too large */
> +		if (offset + len > carveout->len)
> +			continue;
> +
> +		ptr = carveout->va + offset;
> +
> +		break;
> +	}
> +
> +	return ptr;
> +}
> +
> +/**
> + * rproc_load_segments() - load firmware segments to memory
> + * @rproc: remote processor which will be booted using these fw segments
> + * @elf_data: the content of the ELF firmware image
> + *
> + * This function loads the firmware segments to memory, where the remote
> + * processor expects them.
> + *
> + * Some remote processors will expect their code and data to be placed
> + * in specific device addresses, and can't have them dynamically assigned.
> + *
> + * We currently support only those kind of remote processors, and expect
> + * the program header's paddr member to contain those addresses. We then go
> + * through the physically contiguous "carveout" memory regions which we
> + * allocated (and mapped) earlier on behalf of the remote processor,
> + * and "translate" device address to kernel addresses, so we can copy the
> + * segments where they are expected.
On STM Soc you can upload the firmware code where you want
the you just have to specify in 2 register where the entry point of the co-pro

we need to support this too

the elf can be self relocated, I used barebox this way.

BTW do you plan to support CMA as a lot of copro will request a big
contineuous memory to work on between the cpus.

I've to go to the ELCE will continue the review later

Best Regards,
J.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 1/7] amp/remoteproc: add framework for controlling remote processors
  2011-10-26  5:16   ` Jean-Christophe PLAGNIOL-VILLARD
@ 2011-10-26  5:25     ` Ohad Ben-Cohen
  0 siblings, 0 replies; 34+ messages in thread
From: Ohad Ben-Cohen @ 2011-10-26  5:25 UTC (permalink / raw)
  To: Jean-Christophe PLAGNIOL-VILLARD
  Cc: Russell King, Arnd Bergmann, Tony Lindgren, Brian Swetland,
	Rusty Russell, Stephen Boyd, linux-kernel, Grant Likely, Greg KH,
	akpm, linux-omap, linux-arm-kernel

On Wed, Oct 26, 2011 at 7:16 AM, Jean-Christophe PLAGNIOL-VILLARD > On
STM Soc > you can upload the firmware code where you want
> the you just have to specify in 2 register where the entry point of the co-pro

great, can you provide more info ? are you using an iommu ?

> BTW do you plan to support CMA as a lot of copro will request a big
> contineuous memory to work on between the cpus.

sure, this patch set is already using CMA.

> I've to go to the ELCE will continue the review later

come to "Tycho" today at 11:45 :)

Thanks,
Ohad.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 0/7] Introducing a generic AMP framework
  2011-10-26  4:00 ` [PATCH 0/7] Introducing a generic AMP framework Rusty Russell
@ 2011-10-26  5:26   ` Ohad Ben-Cohen
  2011-11-22 11:40   ` Ohad Ben-Cohen
  1 sibling, 0 replies; 34+ messages in thread
From: Ohad Ben-Cohen @ 2011-10-26  5:26 UTC (permalink / raw)
  To: Rusty Russell
  Cc: linux-omap, linux-kernel, linux-arm-kernel, akpm, Brian Swetland,
	Arnd Bergmann, Grant Likely, Tony Lindgren, Russell King

On Wed, Oct 26, 2011 at 6:00 AM, Rusty Russell <rusty@rustcorp.com.au> wrote:
> virtio-spec.txt is a derived document, so I'd prefer that patch to go
> through me so I can patch the (LyX) master copy.

Sure thing, I'll probably just submit changes against virtio-spec.txt
separately then.

Thanks,
Ohad.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 0/7] Introducing a generic AMP framework
  2011-10-26  4:00 ` [PATCH 0/7] Introducing a generic AMP framework Rusty Russell
  2011-10-26  5:26   ` Ohad Ben-Cohen
@ 2011-11-22 11:40   ` Ohad Ben-Cohen
  2011-11-23  1:33     ` Rusty Russell
  1 sibling, 1 reply; 34+ messages in thread
From: Ohad Ben-Cohen @ 2011-11-22 11:40 UTC (permalink / raw)
  To: Rusty Russell, Arnd Bergmann
  Cc: linux-omap, linux-kernel, linux-arm-kernel, akpm, Brian Swetland,
	Grant Likely, Tony Lindgren, Russell King

On Wed, Oct 26, 2011 at 6:00 AM, Rusty Russell <rusty@rustcorp.com.au> wrote:
> On Tue, 25 Oct 2011 11:48:19 +0200, Ohad Ben-Cohen <ohad@wizery.com> wrote:
>> 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.
>
> OK, I'm not even sure who this should go through

We shortly discussed this in ELCE, and this can either go through the
arm-soc tree or directly to Linus; however Arnd prefers really.

The previous RFC iteration was reviewed quite extensively (especially
by Grant. thanks Grant!) but I was hoping to get some more review or
feedback on this iteration as well (any form of Acked-by, Reviewed-by,
+1-by or No-way-by are welcome).

At this point I know of at least four vendors (besides TI) who are
actively looking into supporting this, and it's getting a bit hard to
collaborate, so I plan to get this into linux-next later this week
(minus the virtio-spec.txt change which I'll send directly to you,
Rusty) in the hope of getting this merged into 3.3.

>, but no objections here

Can I add your Acked-by on the virtio parts (mainly patches 3 and 6) ?

Thanks!
Ohad.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 0/7] Introducing a generic AMP framework
  2011-11-22 11:40   ` Ohad Ben-Cohen
@ 2011-11-23  1:33     ` Rusty Russell
  2011-11-23  9:58       ` Ohad Ben-Cohen
  0 siblings, 1 reply; 34+ messages in thread
From: Rusty Russell @ 2011-11-23  1:33 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Arnd Bergmann
  Cc: linux-omap, linux-kernel, linux-arm-kernel, akpm, Brian Swetland,
	Grant Likely, Tony Lindgren, Russell King

On Tue, 22 Nov 2011 13:40:04 +0200, Ohad Ben-Cohen <ohad@wizery.com> wrote:
> At this point I know of at least four vendors (besides TI) who are
> actively looking into supporting this, and it's getting a bit hard to
> collaborate, so I plan to get this into linux-next later this week
> (minus the virtio-spec.txt change which I'll send directly to you,
> Rusty) in the hope of getting this merged into 3.3.

Good.  Thanks.

> >, but no objections here
> 
> Can I add your Acked-by on the virtio parts (mainly patches 3 and 6) ?

That would imply that I'd done more than glance over them, and
unfortunately I haven't :(

Thanks,
Rusty.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 0/7] Introducing a generic AMP framework
  2011-10-25  9:48 [PATCH 0/7] Introducing a generic AMP framework Ohad Ben-Cohen
                   ` (7 preceding siblings ...)
  2011-10-26  4:00 ` [PATCH 0/7] Introducing a generic AMP framework Rusty Russell
@ 2011-11-23  3:25 ` Saravana Kannan
  2011-11-23 10:27   ` Ohad Ben-Cohen
  8 siblings, 1 reply; 34+ messages in thread
From: Saravana Kannan @ 2011-11-23  3:25 UTC (permalink / raw)
  To: Ohad Ben-Cohen
  Cc: linux-omap, linux-kernel, linux-arm-kernel, Russell King,
	Arnd Bergmann, Tony Lindgren, Brian Swetland, Rusty Russell,
	Grant Likely, akpm

On 10/25/2011 02:48 AM, Ohad Ben-Cohen wrote:
> 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.
>
> OMAP4, for example, has dual Cortex-A9, dual Cortex-M3 and a C64x+ DSP.
> Typically, the dual cortex-A9 is running Linux in a SMP configuration, and
> each of the other three cores (two M3 cores and a DSP) is running its own
> instance of RTOS in an AMP configuration.
>
> AMP remote processors typically employ dedicated DSP codecs and multimedia
> hardware accelerators, and therefore are often used to offload cpu-intensive
> multimedia tasks from the main application processor. They could also be
> used to control latency-sensitive sensors, drive 'random' hardware blocks,
> or just perform background tasks while the main CPU is idling.
>

I understand that I might be saying this pretty late in the review, but 
can we please stop calling these as AMP configurations? IMHO, in the 
kernel, we should limit the terms AMP and SMP to be based on the 
processors/CPUs on which this specific instance of the Linux kernel can 
schedule processes on.

With the definition of AMP that you are trying to use, even a Intel 
386/486 machine with just one Intel core will be an AMP system. I'm sure 
even those old PCs had other processors inside other devices (HDDs, 
GPUs, etc) executing random firmware.

So, what would you call Intel dual core machines? SMP-AMP? Your proposed 
use of AMP muddles these terms and makes them useless. I think AMP 
should be reserved for things like the ARM Big-little architecture, etc, 
where the CPUs in which the kernel schedules processes are not identical.

Sorry for the rant, this naming just rubs me the wrong way. I definitely 
appreciate the idea behind these patches.

Thanks,
Saravana

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 1/7] amp/remoteproc: add framework for controlling remote processors
  2011-10-25  9:48 ` [PATCH 1/7] amp/remoteproc: add framework for controlling remote processors Ohad Ben-Cohen
  2011-10-26  5:16   ` Jean-Christophe PLAGNIOL-VILLARD
@ 2011-11-23  3:27   ` Stephen Boyd
  2011-11-23 15:34     ` Ohad Ben-Cohen
  2012-01-03 23:35   ` Grant Likely
  2 siblings, 1 reply; 34+ messages in thread
From: Stephen Boyd @ 2011-11-23  3:27 UTC (permalink / raw)
  To: Ohad Ben-Cohen
  Cc: linux-omap, linux-kernel, linux-arm-kernel, akpm, Brian Swetland,
	Arnd Bergmann, Grant Likely, Rusty Russell, Tony Lindgren,
	Russell King, Greg KH, Saravana Kannan

On 10/25/11 02:48, Ohad Ben-Cohen wrote:
> +static int rproc_load_segments(struct rproc *rproc, const u8 *elf_data)
> +{
> +	struct device *dev = rproc->dev;
> +	struct elf32_hdr *ehdr;
> +	struct elf32_phdr *phdr;
> +	int i, ret = 0;
> +
> +	ehdr = (struct elf32_hdr *)elf_data;
> +	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
> +
> +	/* go through the available ELF segments */
> +	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
> +		u32 da = phdr->p_paddr;
> +		u32 memsz = phdr->p_memsz;
> +		u32 filesz = phdr->p_filesz;
> +		void *ptr;
> +
> +		if (phdr->p_type != PT_LOAD)
> +			continue;
> +
> +		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
> +					phdr->p_type, da, memsz, filesz);
> +
> +		if (filesz > memsz) {
> +			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
> +							filesz, memsz);
> +			ret = -EINVAL;
> +			break;
> +		}
> +
> +		/* grab the kernel address for this device address */
> +		ptr = rproc_da_to_va(rproc, da, memsz);
> +		if (!ptr) {
> +			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
> +			ret = -EINVAL;
> +			break;
> +		}
> +
> +		/* put the segment where the remote processor expects it */
> +		if (phdr->p_filesz)
> +			memcpy(ptr, elf_data + phdr->p_offset, filesz);

How big are the images you're loading? I had to split the memcpy up into
megabyte chunks because I was running out of virtual memory to map in
two huge chunks (one for the firmware and one for the image's resting
place). This may work for now, but I think it will fail for limited
virtual memory environments. Unless CMA solves this problem?

Also, this code assumes the firmware is actually as big as the elf
header says it is. It should be checking to make sure the elf_data is
actually big enough to copy from.

> +
> +		/*
> +		 * Zero out remaining memory for this segment.
> +		 *
> +		 * This isn't strictly required since dma_alloc_coherent already
> +		 * did this for us. albeit harmless, we may consider removing
> +		 * this.
> +		 */
> +		if (memsz > filesz)
> +			memset(ptr + filesz, 0, memsz - filesz);
> +	}
> +
> +	return ret;
> +}
> +
[...]
> +int rproc_register(struct rproc *rproc)
> +{
> +	struct device *dev = rproc->dev;
> +	int ret = 0;
> +
> +	/* expose to rproc_get_by_name users */
> +	klist_add_tail(&rproc->node, &rprocs);
> +
> +	dev_info(rproc->dev, "%s is available\n", rproc->name);
> +
> +	/* create debugfs entries */
> +	rproc_create_debug_dir(rproc);
> +
> +	/* rproc_unregister() calls must wait until async loader completes */
> +	init_completion(&rproc->firmware_loading_complete);
> +
> +	/*
> +	 * We must retrieve early virtio configuration info from
> +	 * the firmware (e.g. whether to register a virtio rpmsg device,
> +	 * what virtio features does it support, ...).
> +	 *
> +	 * We're initiating an asynchronous firmware loading, so we can
> +	 * be built-in kernel code, without hanging the boot process.
> +	 */
> +	ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
> +					rproc->firmware, dev, GFP_KERNEL,
> +					rproc, rproc_fw_config_virtio);

This is a bit odd. If I understand correctly, you load the firmware at
least twice. Once to see if the firmware has any virtio devices in the
resource table, and again when the image is actually loaded into RAM. Is
there any way to avoid loading it twice? I ask because we have something
like a 20Mb image that needs to be loaded and I'd like to avoid loading
it twice just to read a section out of it the first time.

> +	if (ret < 0) {
> +		dev_err(dev, "request_firmware_nowait failed: %d\n", ret);
> +		complete_all(&rproc->firmware_loading_complete);
> +		klist_remove(&rproc->node);
> +	}
> +
> +	return ret;
> +}
[...]
> +struct rproc *rproc_alloc(struct device *dev, const char *name,
> +				const struct rproc_ops *ops,
> +				const char *firmware, int len)
> +{
> +	struct rproc *rproc;
> +
> +	if (!dev || !name || !ops)
> +		return NULL;
> +
> +	rproc = kzalloc(sizeof(struct rproc) + len, GFP_KERNEL);
> +	if (!rproc) {
> +		dev_err(dev, "%s: kzalloc failed\n", __func__);
> +		return NULL;
> +	}
> +
> +	rproc->dev = dev;

What do you do if dev goes away? Does request_firmware() work? What do
you think about making remoteproc into a bus? I imagine this function
would allocate a struct device and then rproc_register() would actually
hook it into the device layer. Then we could use the device we allocate
here for the firmware requests and we also have a nice namespace for all
remote processors in the system. Plus all the management code for
refcounting would come for free with the device layer (modulo the
rproc_boot() count).

> +	rproc->name = name;
> +	rproc->ops = ops;
> +	rproc->firmware = firmware;
> +	rproc->priv = &rproc[1];
> +
> +	atomic_set(&rproc->power, 0);
> +
> +	kref_init(&rproc->refcount);
> +
> +	mutex_init(&rproc->lock);
> +
> +	INIT_LIST_HEAD(&rproc->carveouts);
> +	INIT_LIST_HEAD(&rproc->mappings);
> +	INIT_LIST_HEAD(&rproc->traces);
> +
> +	rproc->state = RPROC_OFFLINE;
> +
> +	return rproc;
> +}
> +EXPORT_SYMBOL(rproc_alloc);
> +
[...]
> +/**
> + * 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,

What is RSC_VIRTIO_CFG?

> +enum fw_resource_type {
> +	RSC_CARVEOUT	= 0,
> +	RSC_DEVMEM	= 1,
> +	RSC_TRACE	= 2,
> +	RSC_VRING	= 3,
> +	RSC_VIRTIO_DEV	= 4,
> +	RSC_VIRTIO_CFG	= 5,
> +};

For MSM I see two main pain points:

 * CMA is new and untested on MSM. I imagine in MSM's situation we would
carve out the memory chunks early on for each processor and then only
remove that memory if the processor is booted? I hope that just works
somehow.

 * rproc is tied to virtio fairly closely. We probably won't be using
virtio anytime soon on MSM, unless we can do smd over virtio or
something. I'm not particularly knowledgeable about that though. Would
something like that be possible?

We would also have to keep using the rproc_get_by_name() approach until
we can actually start tying rproc devices to other devices in the kernel.

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 0/7] Introducing a generic AMP framework
  2011-11-23  1:33     ` Rusty Russell
@ 2011-11-23  9:58       ` Ohad Ben-Cohen
  2011-12-08  7:50         ` Ohad Ben-Cohen
  0 siblings, 1 reply; 34+ messages in thread
From: Ohad Ben-Cohen @ 2011-11-23  9:58 UTC (permalink / raw)
  To: Rusty Russell
  Cc: Arnd Bergmann, linux-omap, linux-kernel, linux-arm-kernel, akpm,
	Brian Swetland, Grant Likely, Tony Lindgren, Russell King

On Wed, Nov 23, 2011 at 3:33 AM, Rusty Russell <rusty@rustcorp.com.au> wrote:
> That would imply that I'd done more than glance over them, and
> unfortunately I haven't :(

Np, thanks for glancing :)

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 0/7] Introducing a generic AMP framework
  2011-11-23  3:25 ` Saravana Kannan
@ 2011-11-23 10:27   ` Ohad Ben-Cohen
  2011-11-23 16:10     ` Mark Brown
  0 siblings, 1 reply; 34+ messages in thread
From: Ohad Ben-Cohen @ 2011-11-23 10:27 UTC (permalink / raw)
  To: Saravana Kannan
  Cc: linux-omap, linux-kernel, linux-arm-kernel, Russell King,
	Arnd Bergmann, Tony Lindgren, Brian Swetland, Rusty Russell,
	Grant Likely, akpm

On Wed, Nov 23, 2011 at 5:25 AM, Saravana Kannan <skannan@codeaurora.org> wrote:
> Sorry for the rant, this naming just rubs me the wrong way. I definitely
> appreciate the idea behind these patches.

I don't share the same naming concerns you have (if any, then
confusion with the bluetooth AMP patches and prefixes is more of a
concern to me), but I don't care deeply about names.

Feel free to offer a different name, though really 'amp' here only
describes the general model and motivation and is rarely used
throughout the code; we mostly either use 'remoteproc' or 'rpmsg',
which respectively refer to the two frameworks that are being added
(the former responsible for controlling the state of the remote
processors, and the latter for communicating with them).

Thanks,
Ohad.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 1/7] amp/remoteproc: add framework for controlling remote processors
  2011-11-23  3:27   ` Stephen Boyd
@ 2011-11-23 15:34     ` Ohad Ben-Cohen
  0 siblings, 0 replies; 34+ messages in thread
From: Ohad Ben-Cohen @ 2011-11-23 15:34 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: linux-omap, linux-kernel, linux-arm-kernel, akpm, Brian Swetland,
	Arnd Bergmann, Grant Likely, Rusty Russell, Tony Lindgren,
	Russell King, Greg KH, Saravana Kannan

Hi Stephen,

Thanks for the review !

On Wed, Nov 23, 2011 at 5:27 AM, Stephen Boyd <sboyd@codeaurora.org> wrote:
> How big are the images you're loading? I had to split the memcpy up into
> megabyte chunks because I was running out of virtual memory to map in
> two huge chunks (one for the firmware and one for the image's resting
> place). This may work for now, but I think it will fail for limited
> virtual memory environments. Unless CMA solves this problem?

It definitely should.

The images we specifically load aren't that big (~5MB) but some of the
use cases we have do require around a whopping 100MB, and with CMA
things just work (we do have to reserve a private CMA pool obviously,
but it's a no brainer).

> Also, this code assumes the firmware is actually as big as the elf
> header says it is. It should be checking to make sure the elf_data is
> actually big enough to copy from.

Good point, thanks.

> This is a bit odd. If I understand correctly, you load the firmware at
> least twice. Once to see if the firmware has any virtio devices in the
> resource table, and again when the image is actually loaded into RAM.

Right; the firmware is loaded once at boot time, and then every time
the remote processor is powered up.

The former is required since we publish the remote services and their
configurations (i.e. virtio devices, features and configurations) in
the firmware, as a separate section (i.e. the "resource table"). We
could use a separate file for this table, but we chose to couple it
with the firmware in order to eliminate potential problems where the
wrong resource table is loaded for a given firmware. It really makes
sense since the resource table reflects the capabilities/requirements
of the firmware.

> Is
> there any way to avoid loading it twice? I ask because we have something
> like a 20Mb image that needs to be loaded and I'd like to avoid loading
> it twice just to read a section out of it the first time.

Sure, we could think of several approaches to optimize this, e.g.
either keep the firmware loaded after boot (possibly to some limited
period of time) or just allow platforms to provide their resource
table as a separate file.

Though frankly I'd just prefer to trust the page cache to eliminate
any redundant overhead (at least when the rproc is powered up close
enough to boot time), or just ignore this issue completely: since this
overhead happens only once on boot, and users tend not to really power
off their devices so much, i'm not sure how painful it really is ?

> What do you do if dev goes away?

Call rproc_unregister(), which blocks if request_firmware_nowait()
didn't complete yet.

> What do you think about making remoteproc into a bus?

That's a really interesting idea, with some nice properties.

But I'm not sure if the bus model fits our use cases: buses
exclusively couple a single driver to any given hardware instance
(i.e. device), and I think that a remote processor is more like an
IOMMU: it's a hardware device that is being used by many drivers, and
not exclusively driven by a single one. So we really end up having
several (completely different) drivers that depend on this hardware
block, and need some API to power it up, rather than having a single
driver that manipulates it exclusively.

> I imagine this function
> would allocate a struct device and then rproc_register() would actually
> hook it into the device layer. Then we could use the device we allocate
> here for the firmware requests and we also have a nice namespace for all
> remote processors in the system. Plus all the management code for
> refcounting would come for free with the device layer (modulo the
> rproc_boot() count).

We can probably still do this even without turning remoteproc into a
bus (i.e. by creating this device inside rproc_register()). I
originally pondered whether to do this or not, as many other kernel
frameworks do this too when their ->register() API is invoked, but I
couldn't think of any strong advantages in doing so. Sounds like it
does worth exploring thought, thanks for the comment.

> What is RSC_VIRTIO_CFG?

Sorry, that's an undocumented (and unused) resource entry that is going away.

It was supposed to specify virtio device features for a given virtio
device, but I'm removing it as part of the resource table overhaul I'm
doing: once the resource entries will have a variable length, the
virtio header will just be an inherent part of the virtio device
resource entry.

> For MSM I see two main pain points:
>
>  * CMA is new and untested on MSM. I imagine in MSM's situation we would
> carve out the memory chunks early on for each processor and then only
> remove that memory if the processor is booted? I hope that just works
> somehow.

For ARM v6+, CMA just works. It's really simple and straight forward to use.

>  * rproc is tied to virtio fairly closely.

Only for firmwares that supports virtio. If yours doesn't, you can
probably just ignore the virtio parts (though I really recommend to
think of supporting it in the next relevant generation of chipsets of
yours. It really is great.)

> We probably won't be using
> virtio anytime soon on MSM, unless we can do smd over virtio or
> something. I'm not particularly knowledgeable about that though. Would
> something like that be possible?

Virtio today is highly coupled with its vring transport, which defines
the shared memory "wire" protocol. Using it as-is pretty much means
replacing smd completely (I assume that by smd you mostly care about
keeping your firmware images as-is, which pretty much means using the
smd's shared memory transport).

But there's another way: virtio was originally designed to support
several different transports, and actually had pluggable virtqueue ops
which allowed several different transport implementations to co-exist.
Since virtio_ring was the only transport that anyone ever used for a
few years, the virtqueue ops were squashed and today virtio directly
calls virtio_vring (see 7c5e9ed0c84e7d70d887878574590638d5572659).

By reverting the aforementioned commit, you can potentially do virtio
over smd, where smd will plug as another virtqueue_ops implementation.
This is probably worth exploring, as you could then use rpmsg and the
plethora of virtio drivers without really changing your firmware.

> We would also have to keep using the rproc_get_by_name() approach until
> we can actually start tying rproc devices to other devices in the kernel.

I kept rproc_get_by_name() mainly for you guys :)

I'd really want us to scrutinize its use cases though and see if we
can get rid of it, as explained in the commentary.

Thanks again for your review,
Ohad.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 0/7] Introducing a generic AMP framework
  2011-11-23 10:27   ` Ohad Ben-Cohen
@ 2011-11-23 16:10     ` Mark Brown
  2011-11-23 20:28       ` Saravana Kannan
  0 siblings, 1 reply; 34+ messages in thread
From: Mark Brown @ 2011-11-23 16:10 UTC (permalink / raw)
  To: Ohad Ben-Cohen
  Cc: Saravana Kannan, Russell King, Arnd Bergmann, Tony Lindgren,
	Brian Swetland, Rusty Russell, linux-kernel, Grant Likely, akpm,
	linux-omap, linux-arm-kernel

On Wed, Nov 23, 2011 at 12:27:31PM +0200, Ohad Ben-Cohen wrote:
> On Wed, Nov 23, 2011 at 5:25 AM, Saravana Kannan <skannan@codeaurora.org> wrote:

> > Sorry for the rant, this naming just rubs me the wrong way. I definitely
> > appreciate the idea behind these patches.

> I don't share the same naming concerns you have (if any, then
> confusion with the bluetooth AMP patches and prefixes is more of a
> concern to me), but I don't care deeply about names.

I guess one very real potential for confusion here is the big/little
stuff that ARM are pushing for next generation SoCs where a Linux image
does actually run on muliple asymmetric cores.

> Feel free to offer a different name, though really 'amp' here only
> describes the general model and motivation and is rarely used
> throughout the code; we mostly either use 'remoteproc' or 'rpmsg',
> which respectively refer to the two frameworks that are being added
> (the former responsible for controlling the state of the remote
> processors, and the latter for communicating with them).

How about using remoteproc then?

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 0/7] Introducing a generic AMP framework
  2011-11-23 16:10     ` Mark Brown
@ 2011-11-23 20:28       ` Saravana Kannan
  2011-11-24  8:43         ` Ohad Ben-Cohen
  0 siblings, 1 reply; 34+ messages in thread
From: Saravana Kannan @ 2011-11-23 20:28 UTC (permalink / raw)
  To: Mark Brown
  Cc: Ohad Ben-Cohen, Russell King, Arnd Bergmann, Tony Lindgren,
	Brian Swetland, Rusty Russell, linux-kernel, Grant Likely, akpm,
	linux-omap, linux-arm-kernel

On 11/23/2011 08:10 AM, Mark Brown wrote:
> On Wed, Nov 23, 2011 at 12:27:31PM +0200, Ohad Ben-Cohen wrote:
>> On Wed, Nov 23, 2011 at 5:25 AM, Saravana Kannan<skannan@codeaurora.org>  wrote:
>
>>> Sorry for the rant, this naming just rubs me the wrong way. I definitely
>>> appreciate the idea behind these patches.
>
>> I don't share the same naming concerns you have (if any, then
>> confusion with the bluetooth AMP patches and prefixes is more of a
>> concern to me), but I don't care deeply about names.
>
> I guess one very real potential for confusion here is the big/little
> stuff that ARM are pushing for next generation SoCs where a Linux image
> does actually run on muliple asymmetric cores.
>
>> Feel free to offer a different name, though really 'amp' here only
>> describes the general model and motivation and is rarely used
>> throughout the code; we mostly either use 'remoteproc' or 'rpmsg',
>> which respectively refer to the two frameworks that are being added
>> (the former responsible for controlling the state of the remote
>> processors, and the latter for communicating with them).
>
> How about using remoteproc then?

remoteproc, peripheral proc, device proc, firmware proc (kinda lines up 
with request_firmware naming). Just throwing out names. Any one of these 
are okay with me.

remoteproc would probably be the best fit since it's already used in the 
code and people are used to discussing about it.

Thanks,
Saravana

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 0/7] Introducing a generic AMP framework
  2011-11-23 20:28       ` Saravana Kannan
@ 2011-11-24  8:43         ` Ohad Ben-Cohen
  2011-12-06 22:09           ` Saravana Kannan
  0 siblings, 1 reply; 34+ messages in thread
From: Ohad Ben-Cohen @ 2011-11-24  8:43 UTC (permalink / raw)
  To: Saravana Kannan
  Cc: Mark Brown, Russell King, Arnd Bergmann, Tony Lindgren,
	Brian Swetland, Rusty Russell, linux-kernel, Grant Likely, akpm,
	linux-omap, linux-arm-kernel

On Wed, Nov 23, 2011 at 10:28 PM, Saravana Kannan
<skannan@codeaurora.org> wrote:
> remoteproc would probably be the best fit since it's already used in the
> code and people are used to discussing about it.

Guys you realize that 'amp' isn't really being used in the code
itself; this discussion boils down to the text we have in the patches'
subject line and the top level Kconfig/folder entry :)

But, sure, I'll just drop those 'amp' text instances, and we'll have
'remoteproc' and 'rpmsg' as separate top-level frameworks again.

Thanks,
Ohad.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 0/7] Introducing a generic AMP framework
  2011-11-24  8:43         ` Ohad Ben-Cohen
@ 2011-12-06 22:09           ` Saravana Kannan
  2011-12-07 18:53             ` Ohad Ben-Cohen
  0 siblings, 1 reply; 34+ messages in thread
From: Saravana Kannan @ 2011-12-06 22:09 UTC (permalink / raw)
  To: Ohad Ben-Cohen
  Cc: Mark Brown, Russell King, Arnd Bergmann, Tony Lindgren,
	Brian Swetland, Rusty Russell, linux-kernel, Grant Likely, akpm,
	linux-omap, linux-arm-kernel

On 11/24/2011 12:43 AM, Ohad Ben-Cohen wrote:
> On Wed, Nov 23, 2011 at 10:28 PM, Saravana Kannan
> <skannan@codeaurora.org>  wrote:
>> remoteproc would probably be the best fit since it's already used in the
>> code and people are used to discussing about it.
>
> Guys you realize that 'amp' isn't really being used in the code
> itself; this discussion boils down to the text we have in the patches'
> subject line and the top level Kconfig/folder entry :)
>
> But, sure, I'll just drop those 'amp' text instances, and we'll have
> 'remoteproc' and 'rpmsg' as separate top-level frameworks again.
>
> Thanks,
> Ohad.

Yes, I did realize it's not used in the code. I just wanted to prevent 
what I considered a misuse of "AMP". Thanks for accommodating my request.

-Saravana

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 0/7] Introducing a generic AMP framework
  2011-12-06 22:09           ` Saravana Kannan
@ 2011-12-07 18:53             ` Ohad Ben-Cohen
  0 siblings, 0 replies; 34+ messages in thread
From: Ohad Ben-Cohen @ 2011-12-07 18:53 UTC (permalink / raw)
  To: Saravana Kannan
  Cc: Mark Brown, Russell King, Arnd Bergmann, Tony Lindgren,
	Brian Swetland, Rusty Russell, linux-kernel, Grant Likely, akpm,
	linux-omap, linux-arm-kernel

On Wed, Dec 7, 2011 at 12:09 AM, Saravana Kannan <skannan@codeaurora.org> wrote:
> Yes, I did realize it's not used in the code. I just wanted to prevent what
> I considered a misuse of "AMP". Thanks for accommodating my request.

Sure thing, and thanks for the feedback.

Dropping the 'amp' prefix also went well with my gut feeling that
remoteproc and rpmsg should again be made as independent top-level
subsystems, just like they were in the first patch set submission;
they're not really coupled, and putting them together under the 'amp'
folder just confused people and somewhat convoluted development.

I suspect that once the basic functionality will be merged, the
development of remoteproc and rpmsg will become completely orthogonal
and it would then make sense to start queueing patches separately, so
I've created two trees for them:

git://git.kernel.org/pub/scm/linux/kernel/git/ohad/remoteproc.git
git://git.kernel.org/pub/scm/linux/kernel/git/ohad/rpmsg.git

Though at this point splitting the patches into two separate trees
will just make it harder for people to work with the code, so both
trees currently have the entire patch-set (and some other wip stuff).

I've also created a for-next branch which I'll send to Stephen, and
then we could start doing linear development (there's a bunch of
patches I'll post soon, including stuff that was reported-by Stephen
earlier) - that will hopefully make it easier for people to use this
code, but also to review patches.

Thanks,
Ohad.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 0/7] Introducing a generic AMP framework
  2011-11-23  9:58       ` Ohad Ben-Cohen
@ 2011-12-08  7:50         ` Ohad Ben-Cohen
  2011-12-09  5:38           ` Rusty Russell
  0 siblings, 1 reply; 34+ messages in thread
From: Ohad Ben-Cohen @ 2011-12-08  7:50 UTC (permalink / raw)
  To: Rusty Russell
  Cc: Arnd Bergmann, linux-omap, linux-kernel, linux-arm-kernel, akpm,
	Brian Swetland, Grant Likely, Tony Lindgren, Russell King

Hi Rusty,

On Wed, Nov 23, 2011 at 11:58 AM, Ohad Ben-Cohen <ohad@wizery.com> wrote:
> On Wed, Nov 23, 2011 at 3:33 AM, Rusty Russell <rusty@rustcorp.com.au> wrote:
>> That would imply that I'd done more than glance over them, and
>> unfortunately I haven't :(
>
> Np, thanks for glancing :)

I'd still like to ask for your Ack at least for the virtio_ids.h
change (please see below, and for the full patch, see
http://www.spinics.net/lists/linux-omap/msg59537.html):

Anyone following our threads will know you approved it, but I'm still
technically required to have your explicit ack as long as the patch
isn't going through your tree.

I can always add something like:

Virtio_ids.h-change-acked-by: Rusty Russell <rusty@rustcorp.com.au>

So it doesn't imply anything else but this specific change, or I can
just put that hunk in a separate patch, and add then add your Acked-by
(so it doesn't imply anything on the rest of the patch set).

Does that sound reasonable to you ?

Thanks,
Ohad.

diff --git a/include/linux/virtio_ids.h b/include/linux/virtio_ids.h
index 85bb0bb..b37c521 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 */

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* Re: [PATCH 4/7] amp/omap: add a remoteproc driver
  2011-10-25  9:48 ` [PATCH 4/7] amp/omap: add a remoteproc driver Ohad Ben-Cohen
@ 2011-12-08  7:57   ` Ohad Ben-Cohen
  2011-12-08 17:01     ` Tony Lindgren
  0 siblings, 1 reply; 34+ messages in thread
From: Ohad Ben-Cohen @ 2011-12-08  7:57 UTC (permalink / raw)
  To: linux-omap, linux-kernel, linux-arm-kernel, Tony Lindgren
  Cc: akpm, Brian Swetland, Arnd Bergmann, Grant Likely, Rusty Russell,
	Russell King, Greg KH, Stephen Boyd

Hi Tony,

On Tue, Oct 25, 2011 at 11:48 AM, Ohad Ben-Cohen <ohad@wizery.com> wrote:
> Add a remoteproc driver for OMAP4, so we can boot the dual-M3 "Ducati"
> and DSP subsystems.
>
> Use the omap_device_* API to control the hardware state, and utilize
> the OMAP mailbox to interrupt the remote processor when a new message
> is pending (the mailbox payload is used to tell it which virtqueue was
> the message placed in).
>
> Conversely, when an inbound mailbox message arrives, tell the remoteproc
> core which virtqueue is triggered.
>
> Later we will also use the mailbox payload to signal omap-specific
> events like remote crashes (which will be used to trigger remoteproc
> recovery) and power management transitions. At that point we will also
> extend the remoteproc core to support this.
>
> Based on (but now quite far from) work done by Fernando Guzman Lugo
> <fernando.lugo@ti.com> and Hari Kanigeri <h-kanigeri2@ti.com>.
>
> Designed with Brian Swetland <swetland@google.com>.
>
> Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
> Cc: Brian Swetland <swetland@google.com>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: Tony Lindgren <tony@atomide.com>
> Cc: Russell King <linux@arm.linux.org.uk>
> Cc: Rusty Russell <rusty@rustcorp.com.au>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: Greg KH <greg@kroah.com>
> Cc: Stephen Boyd <sboyd@codeaurora.org>
> ---
>  arch/arm/plat-omap/include/plat/remoteproc.h |   56 ++++++
>  drivers/amp/remoteproc/Kconfig               |   21 +++
>  drivers/amp/remoteproc/Makefile              |    4 +-
>  drivers/amp/remoteproc/omap_remoteproc.c     |  248 ++++++++++++++++++++++++++
>  drivers/amp/remoteproc/omap_remoteproc.h     |   69 +++++++
>  5 files changed, 397 insertions(+), 1 deletions(-)
>  create mode 100644 arch/arm/plat-omap/include/plat/remoteproc.h
>  create mode 100644 drivers/amp/remoteproc/omap_remoteproc.c
>  create mode 100644 drivers/amp/remoteproc/omap_remoteproc.h

I'm about to add this to linux-next (minus the 'amp' wording); can I
please have your Acked-by for this (at least for the plat-omap change) ?

Thanks,
Ohad.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 4/7] amp/omap: add a remoteproc driver
  2011-12-08  7:57   ` Ohad Ben-Cohen
@ 2011-12-08 17:01     ` Tony Lindgren
  2011-12-08 17:08       ` Ohad Ben-Cohen
  0 siblings, 1 reply; 34+ messages in thread
From: Tony Lindgren @ 2011-12-08 17:01 UTC (permalink / raw)
  To: Ohad Ben-Cohen
  Cc: linux-omap, linux-kernel, linux-arm-kernel, akpm, Brian Swetland,
	Arnd Bergmann, Grant Likely, Rusty Russell, Russell King,
	Greg KH, Stephen Boyd

* Ohad Ben-Cohen <ohad@wizery.com> [111207 23:26]:
> Hi Tony,
> 
> On Tue, Oct 25, 2011 at 11:48 AM, Ohad Ben-Cohen <ohad@wizery.com> wrote:
> > Add a remoteproc driver for OMAP4, so we can boot the dual-M3 "Ducati"
> > and DSP subsystems.
> >
> > Use the omap_device_* API to control the hardware state, and utilize
> > the OMAP mailbox to interrupt the remote processor when a new message
> > is pending (the mailbox payload is used to tell it which virtqueue was
> > the message placed in).
> >
> > Conversely, when an inbound mailbox message arrives, tell the remoteproc
> > core which virtqueue is triggered.
> >
> > Later we will also use the mailbox payload to signal omap-specific
> > events like remote crashes (which will be used to trigger remoteproc
> > recovery) and power management transitions. At that point we will also
> > extend the remoteproc core to support this.
> >
> > Based on (but now quite far from) work done by Fernando Guzman Lugo
> > <fernando.lugo@ti.com> and Hari Kanigeri <h-kanigeri2@ti.com>.
> >
> > Designed with Brian Swetland <swetland@google.com>.
> >
> > Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
> > Cc: Brian Swetland <swetland@google.com>
> > Cc: Arnd Bergmann <arnd@arndb.de>
> > Cc: Grant Likely <grant.likely@secretlab.ca>
> > Cc: Tony Lindgren <tony@atomide.com>
> > Cc: Russell King <linux@arm.linux.org.uk>
> > Cc: Rusty Russell <rusty@rustcorp.com.au>
> > Cc: Andrew Morton <akpm@linux-foundation.org>
> > Cc: Greg KH <greg@kroah.com>
> > Cc: Stephen Boyd <sboyd@codeaurora.org>
> > ---
> >  arch/arm/plat-omap/include/plat/remoteproc.h |   56 ++++++
> >  drivers/amp/remoteproc/Kconfig               |   21 +++
> >  drivers/amp/remoteproc/Makefile              |    4 +-
> >  drivers/amp/remoteproc/omap_remoteproc.c     |  248 ++++++++++++++++++++++++++
> >  drivers/amp/remoteproc/omap_remoteproc.h     |   69 +++++++
> >  5 files changed, 397 insertions(+), 1 deletions(-)
> >  create mode 100644 arch/arm/plat-omap/include/plat/remoteproc.h
> >  create mode 100644 drivers/amp/remoteproc/omap_remoteproc.c
> >  create mode 100644 drivers/amp/remoteproc/omap_remoteproc.h
> 
> I'm about to add this to linux-next (minus the 'amp' wording); can I
> please have your Acked-by for this (at least for the plat-omap change) ?

The platform init code looks OK to me. Please also start considering
how to do the DT bindings for it. For patches 4 & 5:

Acked-by: Tony Lindgren <tony@atomide.com>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 4/7] amp/omap: add a remoteproc driver
  2011-12-08 17:01     ` Tony Lindgren
@ 2011-12-08 17:08       ` Ohad Ben-Cohen
  0 siblings, 0 replies; 34+ messages in thread
From: Ohad Ben-Cohen @ 2011-12-08 17:08 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: linux-omap, linux-kernel, linux-arm-kernel, akpm, Brian Swetland,
	Arnd Bergmann, Grant Likely, Rusty Russell, Russell King,
	Greg KH, Stephen Boyd

On Thu, Dec 8, 2011 at 7:01 PM, Tony Lindgren <tony@atomide.com> wrote:
> The platform init code looks OK to me. Please also start considering
> how to do the DT bindings for it.

Will do. Thanks !

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 0/7] Introducing a generic AMP framework
  2011-12-08  7:50         ` Ohad Ben-Cohen
@ 2011-12-09  5:38           ` Rusty Russell
  2011-12-09 14:15             ` Ohad Ben-Cohen
  0 siblings, 1 reply; 34+ messages in thread
From: Rusty Russell @ 2011-12-09  5:38 UTC (permalink / raw)
  To: Ohad Ben-Cohen
  Cc: Arnd Bergmann, linux-omap, linux-kernel, linux-arm-kernel, akpm,
	Brian Swetland, Grant Likely, Tony Lindgren, Russell King

On Thu, 8 Dec 2011 09:50:59 +0200, Ohad Ben-Cohen <ohad@wizery.com> wrote:
> Hi Rusty,
> 
> On Wed, Nov 23, 2011 at 11:58 AM, Ohad Ben-Cohen <ohad@wizery.com> wrote:
> > On Wed, Nov 23, 2011 at 3:33 AM, Rusty Russell <rusty@rustcorp.com.au> wrote:
> >> That would imply that I'd done more than glance over them, and
> >> unfortunately I haven't :(
> >
> > Np, thanks for glancing :)
> 
> I'd still like to ask for your Ack at least for the virtio_ids.h
> change (please see below, and for the full patch, see
> http://www.spinics.net/lists/linux-omap/msg59537.html):
> 
> Anyone following our threads will know you approved it, but I'm still
> technically required to have your explicit ack as long as the patch
> isn't going through your tree.
> 
> I can always add something like:
> 
> Virtio_ids.h-change-acked-by: Rusty Russell <rusty@rustcorp.com.au>
> 
> So it doesn't imply anything else but this specific change, or I can
> just put that hunk in a separate patch, and add then add your Acked-by
> (so it doesn't imply anything on the rest of the patch set).

It's usually done:

Acked-by: Rusty Russell <rusty@rustcorp.com.au> (virtio_ids.h)

And I've added it to the next version of the virtio-spec, so noone else
grabs it.

Thanks!
Rusty.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 0/7] Introducing a generic AMP framework
  2011-12-09  5:38           ` Rusty Russell
@ 2011-12-09 14:15             ` Ohad Ben-Cohen
  0 siblings, 0 replies; 34+ messages in thread
From: Ohad Ben-Cohen @ 2011-12-09 14:15 UTC (permalink / raw)
  To: Rusty Russell
  Cc: Arnd Bergmann, linux-omap, linux-kernel, linux-arm-kernel, akpm,
	Brian Swetland, Grant Likely, Tony Lindgren, Russell King

On Fri, Dec 9, 2011 at 7:38 AM, Rusty Russell <rusty@rustcorp.com.au> wrote:
> It's usually done:
>
> Acked-by: Rusty Russell <rusty@rustcorp.com.au> (virtio_ids.h)
>
> And I've added it to the next version of the virtio-spec, so noone else
> grabs it.

Great, thanks a lot !

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 1/7] amp/remoteproc: add framework for controlling remote processors
  2011-10-25  9:48 ` [PATCH 1/7] amp/remoteproc: add framework for controlling remote processors Ohad Ben-Cohen
  2011-10-26  5:16   ` Jean-Christophe PLAGNIOL-VILLARD
  2011-11-23  3:27   ` Stephen Boyd
@ 2012-01-03 23:35   ` Grant Likely
  2012-01-04  7:29     ` Mark Grosen
  2012-01-05 13:58     ` Ohad Ben-Cohen
  2 siblings, 2 replies; 34+ messages in thread
From: Grant Likely @ 2012-01-03 23:35 UTC (permalink / raw)
  To: Ohad Ben-Cohen
  Cc: linux-omap, linux-kernel, linux-arm-kernel, akpm, Brian Swetland,
	Arnd Bergmann, Rusty Russell, Tony Lindgren, Russell King,
	Greg KH, Stephen Boyd

On Tue, Oct 25, 2011 at 11:48:20AM +0200, Ohad Ben-Cohen wrote:
> 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
> <fernando.lugo@ti.com>.
[...]
> +static int rproc_load_segments(struct rproc *rproc, const u8 *elf_data)
> +{
> +	struct device *dev = rproc->dev;
> +	struct elf32_hdr *ehdr;
> +	struct elf32_phdr *phdr;
> +	int i, ret = 0;
> +
> +	ehdr = (struct elf32_hdr *)elf_data;
> +	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
> +
> +	/* go through the available ELF segments */
> +	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
> +		u32 da = phdr->p_paddr;
> +		u32 memsz = phdr->p_memsz;
> +		u32 filesz = phdr->p_filesz;

This could be an endianess problem.  If the endianess of the host and
the rproc are different, then what is the endianess of the elf file?
Is the endianess of the elf file verified before attempting to parse it?

> +/* handle firmware resource entries before booting the remote processor */
> +static int
> +rproc_handle_boot_rsc(struct rproc *rproc, struct fw_resource *rsc, int len)
> +{
> +	struct device *dev = rproc->dev;
> +	int ret = 0;
> +
> +	while (len >= sizeof(*rsc)) {
> +		dev_dbg(dev, "rsc: type %d, da 0x%llx, pa 0x%llx, len 0x%x, "
> +			"id %d, name %s, flags %x\n", rsc->type, rsc->da,
> +			rsc->pa, rsc->len, rsc->id, rsc->name, rsc->flags);
> +
> +		switch (rsc->type) {
> +		case RSC_CARVEOUT:
> +			ret = rproc_handle_carveout(rproc, rsc);
> +			break;
> +		case RSC_DEVMEM:
> +			ret = rproc_handle_devmem(rproc, rsc);
> +			break;
> +		case RSC_TRACE:
> +			ret = rproc_handle_trace(rproc, rsc);
> +			break;
> +		case RSC_VRING:
> +			ret = rproc_handle_vring(rproc, rsc);
> +			break;
> +		case RSC_VIRTIO_DEV:
> +			/* this one is handled early upon registration */
> +			break;
> +		default:
> +			dev_warn(dev, "unsupported resource %d\n", rsc->type);
> +			break;
> +		}

Nitpick: A look up table would be easier to extend in the future.

Otherwise;

Acked-by: Grant Likely <grant.likely@secretlab.ca>

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 2/7] amp/remoteproc: add debugfs entries
  2011-10-25  9:48 ` [PATCH 2/7] amp/remoteproc: add debugfs entries Ohad Ben-Cohen
@ 2012-01-03 23:36   ` Grant Likely
  0 siblings, 0 replies; 34+ messages in thread
From: Grant Likely @ 2012-01-03 23:36 UTC (permalink / raw)
  To: Ohad Ben-Cohen
  Cc: linux-omap, linux-kernel, linux-arm-kernel, akpm, Brian Swetland,
	Arnd Bergmann, Rusty Russell, Tony Lindgren, Russell King,
	Greg KH, Stephen Boyd

On Tue, Oct 25, 2011 at 11:48:21AM +0200, Ohad Ben-Cohen wrote:
> Expose several remote processor properties (name, state, trace buffer)
> that are helpful for debugging.
> 
> This part is extracted to a separate patch just to keep the review load
> down.
> 
> Designed with Brian Swetland <swetland@google.com>.
> 
> Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>

Acked-by: Grant Likely <grant.likely@secretlab.ca>

> ---
>  drivers/amp/remoteproc/Makefile             |    1 +
>  drivers/amp/remoteproc/remoteproc_debugfs.c |  182 +++++++++++++++++++++++++++
>  2 files changed, 183 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/amp/remoteproc/remoteproc_debugfs.c

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 1/7] amp/remoteproc: add framework for controlling remote processors
  2012-01-03 23:35   ` Grant Likely
@ 2012-01-04  7:29     ` Mark Grosen
  2012-01-05 13:58     ` Ohad Ben-Cohen
  1 sibling, 0 replies; 34+ messages in thread
From: Mark Grosen @ 2012-01-04  7:29 UTC (permalink / raw)
  To: Grant Likely
  Cc: Ohad Ben-Cohen, linux-omap, linux-kernel, linux-arm-kernel, akpm,
	Brian Swetland, Arnd Bergmann, Rusty Russell, Tony Lindgren,
	Russell King, Greg KH, Stephen Boyd

On 01/03/2012 03:35 PM, Grant Likely wrote:
> On Tue, Oct 25, 2011 at 11:48:20AM +0200, Ohad Ben-Cohen wrote:
>> 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
>> <fernando.lugo@ti.com>.
> [...]
>> +static int rproc_load_segments(struct rproc *rproc, const u8 *elf_data)
>> +{
>> +	struct device *dev = rproc->dev;
>> +	struct elf32_hdr *ehdr;
>> +	struct elf32_phdr *phdr;
>> +	int i, ret = 0;
>> +
>> +	ehdr = (struct elf32_hdr *)elf_data;
>> +	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
>> +
>> +	/* go through the available ELF segments */
>> +	for (i = 0; i<  ehdr->e_phnum; i++, phdr++) {
>> +		u32 da = phdr->p_paddr;
>> +		u32 memsz = phdr->p_memsz;
>> +		u32 filesz = phdr->p_filesz;
> This could be an endianess problem.  If the endianess of the host and
> the rproc are different, then what is the endianess of the elf file?
> Is the endianess of the elf file verified before attempting to parse it?

Yes, this could be a problem, but most likely only in theory. I think it 
would be
unlikely that the host and the rproc would run different endian-ness due 
to the
hassles and overhead of converting data (although TI has processors that
allow it to be done). That said, we should check to prevent an oops.

Another sanity check to add is for the machine type. Some of the TI SoCs
have more than one type of rproc; e.g., OMAP4 has Cortex M3 and C6000 DSP.
We should not load the wrong code on an rproc.

Mark


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 1/7] amp/remoteproc: add framework for controlling remote processors
  2012-01-03 23:35   ` Grant Likely
  2012-01-04  7:29     ` Mark Grosen
@ 2012-01-05 13:58     ` Ohad Ben-Cohen
  1 sibling, 0 replies; 34+ messages in thread
From: Ohad Ben-Cohen @ 2012-01-05 13:58 UTC (permalink / raw)
  To: Grant Likely
  Cc: linux-omap, linux-kernel, linux-arm-kernel, akpm, Brian Swetland,
	Arnd Bergmann, Rusty Russell, Tony Lindgren, Russell King,
	Greg KH, Stephen Boyd

On Wed, Jan 4, 2012 at 1:35 AM, Grant Likely <grant.likely@secretlab.ca> wrote:
>> +     /* go through the available ELF segments */
>> +     for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
>> +             u32 da = phdr->p_paddr;
>> +             u32 memsz = phdr->p_memsz;
>> +             u32 filesz = phdr->p_filesz;
>
> This could be an endianess problem.  If the endianess of the host and
> the rproc are different, then what is the endianess of the elf file?
> Is the endianess of the elf file verified before attempting to parse it?
...
> Nitpick: A look up table would be easier to extend in the future.
>
> Otherwise;
>
> Acked-by: Grant Likely <grant.likely@secretlab.ca>

Thanks, Grant!

If I may, I'll add something like this to the commit log:

Acked-by: Grant Likely <grant.likely@secretlab.ca> (minus two
Reported-by issues)

And then we could fix those two issues in two subsequent patches
(carrying your Reported-by) so reviewing the change would be much
easier, and we don't end up changing code (that has been lying in
linux-next) just before it is sent it to Linus.

Thanks a lot for your review!
Ohad.

^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2012-01-05 13:59 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-10-25  9:48 [PATCH 0/7] Introducing a generic AMP framework Ohad Ben-Cohen
2011-10-25  9:48 ` [PATCH 1/7] amp/remoteproc: add framework for controlling remote processors Ohad Ben-Cohen
2011-10-26  5:16   ` Jean-Christophe PLAGNIOL-VILLARD
2011-10-26  5:25     ` Ohad Ben-Cohen
2011-11-23  3:27   ` Stephen Boyd
2011-11-23 15:34     ` Ohad Ben-Cohen
2012-01-03 23:35   ` Grant Likely
2012-01-04  7:29     ` Mark Grosen
2012-01-05 13:58     ` Ohad Ben-Cohen
2011-10-25  9:48 ` [PATCH 2/7] amp/remoteproc: add debugfs entries Ohad Ben-Cohen
2012-01-03 23:36   ` Grant Likely
2011-10-25  9:48 ` [PATCH 3/7] amp/remoteproc: create rpmsg virtio device Ohad Ben-Cohen
2011-10-25  9:48 ` [PATCH 4/7] amp/omap: add a remoteproc driver Ohad Ben-Cohen
2011-12-08  7:57   ` Ohad Ben-Cohen
2011-12-08 17:01     ` Tony Lindgren
2011-12-08 17:08       ` Ohad Ben-Cohen
2011-10-25  9:48 ` [PATCH 5/7] ARM: OMAP: add amp/remoteproc support Ohad Ben-Cohen
2011-10-25  9:48 ` [PATCH 6/7] amp/rpmsg: add virtio-based remote processor messaging bus Ohad Ben-Cohen
2011-10-25  9:48 ` [PATCH 7/7] samples/amp: add an rpmsg driver sample Ohad Ben-Cohen
2011-10-26  4:00 ` [PATCH 0/7] Introducing a generic AMP framework Rusty Russell
2011-10-26  5:26   ` Ohad Ben-Cohen
2011-11-22 11:40   ` Ohad Ben-Cohen
2011-11-23  1:33     ` Rusty Russell
2011-11-23  9:58       ` Ohad Ben-Cohen
2011-12-08  7:50         ` Ohad Ben-Cohen
2011-12-09  5:38           ` Rusty Russell
2011-12-09 14:15             ` Ohad Ben-Cohen
2011-11-23  3:25 ` Saravana Kannan
2011-11-23 10:27   ` Ohad Ben-Cohen
2011-11-23 16:10     ` Mark Brown
2011-11-23 20:28       ` Saravana Kannan
2011-11-24  8:43         ` Ohad Ben-Cohen
2011-12-06 22:09           ` Saravana Kannan
2011-12-07 18:53             ` Ohad Ben-Cohen

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).