Introduction
============

The MSM ADSPRPC driver implements an IPC (Inter-Processor Communication)
mechanism that allows for clients to transparently make remote method
invocations across processor boundaries.

The below diagram depicts invocation of a single method where the client
and objects reside on different processors. An object could expose
multiple methods which can be grouped together and referred to as an
interface.

: ,--------,        ,------,  ,-----------,  ,------,        ,--------,
: |        | method |      |  |           |  |      | method |        |
: | Client |------->| Stub |->| Transport |->| Skel |------->| Object |
: |        |        |      |  |           |  |      |        |        |
: `--------`        `------`  `-----------`  `------`        `--------`

Client:    Linux user mode process that initiates the remote invocation
Stub:      Auto generated code linked in with the user mode process that
           takes care of marshaling parameters
Transport: Involved in carrying an invocation from a client to an
           object. This involves two portions: 1) MSM ADSPRPC Linux
           kernel driver that receives the remote invocation, queues
           them up and then waits for the response after signaling the
           remote side. 2) Service running on the remote side that
           dequeues the messages from the queue and dispatches them for
           processing.
Skel:      Auto generated code that takes care of un-marshaling
           parameters
Object:    Method implementation

Hardware description
====================

The driver interfaces with the components in the DSP subsystem and does
not drive or manage any hardware resources.

Software description
====================

The MSM ADSPRPC driver uses SMD (Shared Memory Driver) to send and
receive messages with the remote processor. The SMD channel used for
communication is opened during initialization of the driver and is
closed when the driver module is unloaded. The driver does not expose
HLOS memory to the remote processor but rather communication of
invocation parameters happen over ION allocated buffers.

The driver receives remote call invocations via an ioctl call. When a
remote call invocation is received, the driver does the following:
- Retrieves the invocation parameters
- Copies input buffers in HLOS memory to ION allocated buffers
- Allocates ION buffers for output buffers in HLOS memory as required
- Scatter-gathers list of pages for ION allocated input and output
  buffers
- Coalesces information about the contiguous page buffers
- Builds up a message with the received information
- Sends the message to a remote processor through an SMD channel
- Waits for a response from the remote processor through the SMD channel
- Reads the message available from the shared memory SMD channel
- Copies back from ION buffers to HLOS memory for output buffers
- Returns the response of the remote invocation

Design
======

The design goals of this transport mechanism are:
- Fast and efficient ways to transfer huge buffers across
  inter-processor boundaries
- Zero copy of ION allocated buffers passed during invocations

To achieve the zero copy approach of ION allocated user space buffers,
the driver scatter-gathers the list of pages of the buffers being passed
in. This information is then sent over to the remote processor for it
to map into its address space.

The invocation requests sent over the SMD channel carry context
information as to whom the request is originating from. The responses
received over the SMD channel have context information in the message
which is then used to wake the thread waiting for a response.

If the remote processor goes down and gets restarted, the SMD channel
is re-initialized when the remote processor comes back up. An
error code would be returned to the client for all invocations that
happen before the SMD channel could get completely re-initialized.

Power Management
================

None

SMP/multi-core
==============

The driver uses semaphores to wake up clients waiting for a remote
invocation response.

Security
========

Use of the zero copy approach results in a page-size granularity of
all buffers being passed to the remote processor. The objects that will
be manipulating these buffers on the remote processor will be signed
and trusted entities, thereby alleviating any fear of intentional
scribbling of these buffers.

Performance
===========

In order to minimize latencies across remote invocations:
- messages exchanged between the remote processors are kept short
- zero copy approach for ION allocated user space buffers

Interface
=========

The driver exposes a user space interface through /dev/adsprpc-smd and
the user space clients send commands to the driver by using the
following ioctl command:

- FASTRPC_IOCTL_INVOKE: Parameters passed in includes the buffers and
  data related to remote invocation.

  /*
   * Information about the input/output buffer or an handle to the
   * object being passed in the remote invocation
   *
   * @pv:     Pointer to input/output buffer
   * @len:    Length of the input/output buffer
   * @handle: Handle to the remote object
   */
  typedef union {
	struct remote_buf {
		void *pv;
		int len;
	} buf;
	unsigned int handle;
  } remote_arg;

  /*
   * Invocation parameters passed via ioctl call by the client
   *
   * @handle: Handle to the object on which the method is to be
   *          invoked
   * @sc:     Scalars detailing the parameters being passed in
   *          bits 0-3: Number of output handles
   *          bits 4-7: Number of input handles
   *          bits 8-15: Number of output buffers
   *          bits 16-23: Number of input buffers
   *          bits 24-28: Method to be invoked
   *          bits 29-31: Method attributes
   * @pra:    Remote arguments to be passed for method invocation
   */
  struct fastrpc_ioctl_invoke {
	unsigned int handle;
	unsigned int sc;
	remote_arg *pra;
  };

Driver parameters
=================

None

Config options
==============

None

Dependencies
============

The ADSPRPC driver requires that the ADSP RPC SMD channel be created and
the SMD subsystem be initialized. During initialization, the driver
opens an existing SMD edge channel between ADSP and Apps processor. On
success, the driver waits for the "channel opened" event from SMD,
acknowledging the channel availability from the remote SMD driver for
communication to begin.

User space utilities
====================

None

Other
=====

None

Known issues
============

None

To do
=====

None
