[alsa-devel] [PATCH v2 01/13] soundwire: Add more documentation
Pierre-Louis Bossart
pierre-louis.bossart at linux.intel.com
Thu Apr 5 23:37:14 CEST 2018
On 4/5/18 11:48 AM, Vinod Koul wrote:
> From: Sanyog Kale <sanyog.r.kale at intel.com>
>
> This adds documentation for error handling, locking and streams.
>
> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
> Signed-off-by: Sanyog Kale <sanyog.r.kale at intel.com>
> Signed-off-by: Shreyas NC <shreyas.nc at intel.com>
> Signed-off-by: Vinod Koul <vinod.koul at intel.com>
> ---
> .../driver-api/soundwire/error_handling.rst | 65 ++++
> Documentation/driver-api/soundwire/index.rst | 3 +
> Documentation/driver-api/soundwire/locking.rst | 106 ++++++
> Documentation/driver-api/soundwire/stream.rst | 368 +++++++++++++++++++++
> 4 files changed, 542 insertions(+)
> create mode 100644 Documentation/driver-api/soundwire/error_handling.rst
> create mode 100644 Documentation/driver-api/soundwire/locking.rst
> create mode 100644 Documentation/driver-api/soundwire/stream.rst
>
> diff --git a/Documentation/driver-api/soundwire/error_handling.rst b/Documentation/driver-api/soundwire/error_handling.rst
> new file mode 100644
> index 000000000000..aa3a0a23a066
> --- /dev/null
> +++ b/Documentation/driver-api/soundwire/error_handling.rst
> @@ -0,0 +1,65 @@
> +========================
> +SoundWire Error Handling
> +========================
> +
> +The SoundWire PHY was designed with care and errors on the bus are going to
> +be very unlikely, and if they happen it should be limited to single bit
> +errors. Examples of this design can be found in the synchronization
> +mechanism (sync loss after two errors) and short CRCs used for the Bulk
> +Register Access.
> +
> +The errors can be detected with multiple mechanisms:
> +
> +1. Bus clash or parity errors: This mechanism relies on low-level detectors
> + that are independent of the payload and usages, and they cover both control
> + and audio data. The current implementation only logs such errors.
> + Improvements could be invalidating an entire programming sequence and
> + restarting from a known position. In the case of such errors outside of a
> + control/command sequence, there is no concealment or recovery for audio
> + data enabled by the SoundWire protocol, the location of the error will also
> + impact its audibility (most-significant bits will be more impacted in PCM),
> + and after a number of such errors are detected the bus might be reset. Note
> + that bus clashes due to programming errors (two streams using the same bit
> + slots) or electrical issues during the transmit/receive transition cannot
> + be distinguished, although a recurring bus clash when audio is enabled is a
> + indication of a bus allocation issue. The interrupt mechanism can also help
> + identify Slaves which detected a Bus Clash or a Parity Error, but they may
> + not be responsible for the errors so resetting them individually is not a
> + viable recovery strategy.
> +
> +2. Command status: Each command is associated with a status, which only
> + covers transmission of the data between devices. The ACK status indicates
> + that the command was received and will be executed by the end of the
> + current frame. A NAK indicates that the command was in error and will not
> + be applied. In case of a bad programming (command sent to non-existent
> + Slave or to a non-implemented register) or electrical issue, no response
> + signals the command was ignored. Some Master implementations allow for a
> + command to be retransmitted several times. If the retransmission fails,
> + backtracking and restarting the entire programming sequence might be a
> + solution. Alternatively some implementations might directly issue a bus
> + reset and re-enumerate all devices.
> +
> +3. Timeouts: In a number of cases such as ChannelPrepare or
> + ClockStopPrepare, the bus driver is supposed to poll a register field until
> + it transitions to a NotFinished value of zero. The MIPI SoundWire spec 1.1
> + does not define timeouts but the MIPI SoundWire DisCo document adds
> + recommendation on timeouts. If such configurations do not complete, the
> + driver will return a -ETIMEOUT. Such timeouts are symptoms of a faulty
> + Slave device and are likely impossible to recover from.
> +
> +Errors during global reconfiguration sequences are extremely difficult to
> +handle:
> +
> +1. BankSwitch: An error during the last command issuing a BankSwitch is
> + difficult to backtrack from. Retransmitting the Bank Switch command may be
> + possible in a single segment setup, but this can lead to synchronization
> + problems when enabling multiple bus segments (a command with side effects
> + such as frame reconfiguration would be handled at different times). A global
> + hard-reset might be the best solution.
> +
> +Note that SoundWire does not provide a mechanism to detect illegal values
> +written in valid registers. In a number of cases the standard even mentions
> +that the Slave might behave in implementation-defined ways. The bus
> +implementation does not provide a recovery mechanism for such errors, Slave
> +or Master driver implementers are responsible for writing valid values in
> +valid registers and implement additional range checking if needed.
> diff --git a/Documentation/driver-api/soundwire/index.rst b/Documentation/driver-api/soundwire/index.rst
> index 647e94654752..6db026028f27 100644
> --- a/Documentation/driver-api/soundwire/index.rst
> +++ b/Documentation/driver-api/soundwire/index.rst
> @@ -6,6 +6,9 @@ SoundWire Documentation
> :maxdepth: 1
>
> summary
> + stream
> + error_handling
> + locking
>
> .. only:: subproject
>
> diff --git a/Documentation/driver-api/soundwire/locking.rst b/Documentation/driver-api/soundwire/locking.rst
> new file mode 100644
> index 000000000000..253f73555255
> --- /dev/null
> +++ b/Documentation/driver-api/soundwire/locking.rst
> @@ -0,0 +1,106 @@
> +=================
> +SoundWire Locking
> +=================
> +
> +This document explains locking mechanism of the SoundWire Bus. Bus uses
> +following locks in order to avoid race conditions in Bus operations on
> +shared resources.
> +
> + - Bus lock
> +
> + - Message lock
> +
> +Bus lock
> +========
> +
> +SoundWire Bus lock is a mutex and is part of Bus data structure
> +(sdw_bus) which is used for every Bus instance. This lock is used to
> +serialize each of the following operations(s) within SoundWire Bus instance.
> +
> + - Addition and removal of Slave(s), changing Slave status.
> +
> + - Prepare, Enable, Disable and De-prepare stream operations.
> +
> + - Access of Stream data structure.
> +
> +Message lock
> +============
> +
> +SoundWire message transfer lock. This mutex is part of
> +Bus data structure (sdw_bus). This lock is used to serialize the message
> +transfers (read/write) within a SoundWire Bus instance.
> +
> +Below examples show how locks are acquired.
> +
> +Example 1
> +---------
> +
> +Message transfer.
> +
> + 1. For every message transfer
> +
> + a. Acquire Message lock.
> +
> + b. Transfer message (Read/Write) to Slave1 or broadcast message on
> + Bus in case of bank switch.
> +
> + c. Release Message lock ::
> +
> + +----------+ +---------+
> + | | | |
> + | Bus | | Master |
> + | | | Driver |
> + | | | |
> + +----+-----+ +----+----+
> + | |
> + | bus->ops->xfer_msg() |
> + <-------------------------------+ a. Acquire Message lock
> + | | b. Transfer message
> + | |
> + +-------------------------------> c. Release Message lock
> + | return success/error | d. Return success/error
> + | |
> + + +
> +
> +Example 2
> +---------
> +
> +Prepare operation.
> +
> + 1. Acquire lock for Bus instance associated with Master 1.
> +
> + 2. For every message transfer in Prepare operation
> +
> + a. Acquire Message lock.
> +
> + b. Transfer message (Read/Write) to Slave1 or broadcast message on
> + Bus in case of bank switch.
> +
> + c. Release Message lock.
> +
> + 3. Release lock for Bus instance associated with Master 1 ::
> +
> + +----------+ +---------+
> + | | | |
> + | Bus | | Master |
> + | | | Driver |
> + | | | |
> + +----+-----+ +----+----+
> + | |
> + | sdw_prepare_stream() |
> + <-------------------------------+ 1. Acquire bus lock
> + | | 2. Perform stream prepare
> + | |
> + | |
> + | bus->ops->xfer_msg() |
> + <-------------------------------+ a. Acquire Message lock
> + | | b. Transfer message
> + | |
> + +-------------------------------> c. Release Message lock
> + | return success/error | d. Return success/error
> + | |
> + | |
> + | return success/error | 3. Release bus lock
> + +-------------------------------> 4. Return success/error
> + | |
> + + +
> diff --git a/Documentation/driver-api/soundwire/stream.rst b/Documentation/driver-api/soundwire/stream.rst
> new file mode 100644
> index 000000000000..83830e1dd138
> --- /dev/null
> +++ b/Documentation/driver-api/soundwire/stream.rst
> @@ -0,0 +1,368 @@
> +=========================
> +Audio Stream in SoundWire
> +=========================
> +
> +An audio stream is a logical or virtual connection created between
> +
> + (1) System memory buffer(s) and Codec(s)
> +
> + (2) DSP memory buffer(s) and Codec(s)
> +
> + (3) FIFO(s) and Codec(s)
> +
> + (4) Codec(s) and Codec(s)
> +
> +which is typically driven by a DMA(s) channel through the data link. An
> +audio stream contains one or more channels of data. All channels within
> +stream must have same sample rate and same sample size.
> +
> +Assume a stream with two channels (Left & Right) is opened using SoundWire
> +interface. Below are some ways a stream can be represented in SoundWire.
> +
> +Stream Sample in memory (System memory, DSP memory or FIFOs) ::
> +
> + -------------------------
> + | L | R | L | R | L | R |
> + -------------------------
> +
> +Example 1: Stereo Stream with L and R channels is rendered from Master to
> +Slave. Both Master and Slave is using single port. ::
> +
> + +---------------+ Clock Signal +---------------+
> + | Master +----------------------------------+ Slave |
> + | Interface | | Interface |
> + | | | 1 |
> + | | Data Signal | |
> + | L + R +----------------------------------+ L + R |
> + | (Data) | Data Direction | (Data) |
> + +---------------+ +-----------------------> +---------------+
> +
> +
> +Example 2: Stereo Stream with L and R channels is captured from Slave to
> +Master. Both Master and Slave is using single port. ::
> +
> +
> + +---------------+ Clock Signal +---------------+
> + | Master +----------------------------------+ Slave |
> + | Interface | | Interface |
> + | | | 1 |
> + | | Data Signal | |
> + | L + R +----------------------------------+ L + R |
> + | (Data) | Data Direction | (Data) |
> + +---------------+ <-----------------------+ +---------------+
> +
> +
> +Example 3: Stereo Stream with L and R channels is rendered by Master. Each
> +of the L and R channel is received by two different Slaves. Master and both
> +Slaves are using single port. ::
> +
> + +---------------+ Clock Signal +---------------+
> + | Master +---------+------------------------+ Slave |
> + | Interface | | | Interface |
> + | | | | 1 |
> + | | | Data Signal | |
> + | L + R +---+------------------------------+ L |
> + | (Data) | | | Data Direction | (Data) |
> + +---------------+ | | +-------------> +---------------+
> + | |
> + | |
> + | | +---------------+
> + | +----------------------> | Slave |
> + | | Interface |
> + | | 2 |
> + | | |
> + +----------------------------> | R |
> + | (Data) |
> + +---------------+
> +
> +
> +Example 4: Stereo Stream with L and R channel is rendered by two different
> +Ports of the Master and is received by only single Port of the Slave
> +interface. ::
> +
> + +--------------------+
> + | |
> + | +--------------+ +----------------+
> + | | || | |
> + | | Data Port || L Channel | |
> + | | 1 |------------+ | |
> + | | L Channel || | +-----+----+ |
> + | | (Data) || | L + R Channel || Data | |
> + | Master +----------+ | +---+---------> || Port | |
> + | Interface | | || 1 | |
> + | +--------------+ | || | |
> + | | || | +----------+ |
> + | | Data Port |------------+ | |
> + | | 2 || R Channel | Slave |
> + | | R Channel || | Interface |
> + | | (Data) || | 1 |
> + | +--------------+ Clock Signal | L + R |
> + | +---------------------------> | (Data) |
> + +--------------------+ | |
> + +----------------+
> +
> +SoundWire Stream Management flow
> +================================
> +
> +Stream definitions
> +------------------
> +
> + (1) Current stream: This is classified as the stream on which operation has
> + to be performed like prepare, enable, disable, de-prepare etc.
> +
> + (2) Active stream: This is classified as the stream which is already active
> + on Bus other than current stream. There can be multiple active streams
> + on the Bus.
> +
> +SoundWire Bus manages stream operations for each stream getting
> +rendered/captured on the SoundWire Bus. This section explains Bus operations
> +done for each of the stream allocated/released on Bus. Following are the
> +stream states maintained by the Bus for each of the audio stream.
> +
> +
> +SoundWire stream states
> +-----------------------
> +
> +Below shows the SoundWire stream states and state transition diagram. ::
> +
> + +-----------+ +------------+ +----------+ +----------+
> + | ALLOCATED +---->| CONFIGURED +---->| PREPARED +---->| ENABLED |
> + | STATE | | STATE | | STATE | | STATE |
> + +-----------+ +------------+ +----------+ +----+-----+
> + ^
> + |
> + |
> + v
> + +----------+ +------------+ +----+-----+
> + | RELEASED |<----------+ DEPREPARED |<-------+ DISABLED |
> + | STATE | | STATE | | STATE |
> + +----------+ +------------+ +----------+
> +
Patch 2 describes the states as below:
+enum sdw_stream_state {
+ SDW_STREAM_RELEASED = 0,
+ SDW_STREAM_ALLOCATED = 1,
+ SDW_STREAM_CONFIGURED = 2,
+ SDW_STREAM_PREPARED = 3,
+ SDW_STREAM_ENABLED = 4,
+ SDW_STREAM_DISABLED = 5,
+ SDW_STREAM_DEPREPARED = 6,
which isn't the same picture as the ascii art above. The RELEASED state
is the starting point, and there's an arrow missing from RELEASED to
ALLOCATED.
> +NOTE: State transition between prepare and deprepare is supported in Spec
> +but not in the software (subsystem)
> +
> +Stream State Operations
> +-----------------------
> +
> +Below section explains the operations done by the Bus on Master(s) and
> +Slave(s) as part of stream state transitions.
> +
> +SDW_STREAM_ALLOCATED
> +~~~~~~~~~~~~~~~~~~~~
> +
> +Allocation state for stream. This is the entry state
> +of the stream. Operations performed before entering in this state:
> +
> + (1) A stream runtime is allocated for the stream. This stream
> + runtime is used as a reference for all the operations performed
> + on the stream.
> +
> + (2) The resources required for holding stream runtime information are
> + allocated and initialized. This holds all stream related information
> + such as stream type (PCM/PDM) and parameters, Master and Slave
> + interface associated with the stream, stream state etc.
> +
> +After all above operations are successful, stream state is set to
> +``SDW_STREAM_ALLOCATED``.
> +
> +Bus implements below API for allocate a stream which needs to be called once
> +per stream. From ASoC DPCM framework, this stream state maybe linked to
> +.startup() operation.
> +
> + .. code-block:: c
> + int sdw_alloc_stream(char * stream_name);
> +
> +
> +SDW_STREAM_CONFIGURED
> +~~~~~~~~~~~~~~~~~~~~~
> +
> +Configuration state of stream. Operations performed before entering in
> +this state:
> +
> + (1) The resources allocated for stream information in SDW_STREAM_ALLOCATED
> + state are updated here. This includes stream parameters, Master(s)
> + and Slave(s) runtime information associated with current stream.
> +
> + (2) All the Master(s) and Slave(s) associated with current stream provide
> + the port information to Bus which includes port numbers allocated by
> + Master(s) and Slave(s) for current stream and their channel mask.
> +
> +After all above operations are successful, stream state is set to
> +``SDW_STREAM_CONFIGURED``.
> +
> +Bus implements below APIs for CONFIG state which needs to be called by
> +the respective Master(s) and Slave(s) associated with stream. These APIs can
> +only be invoked once by respective Master(s) and Slave(s). From ASoC DPCM
> +framework, this stream state is linked to .hw_params() operation.
> +
> + .. code-block:: c
> + int sdw_stream_add_master(struct sdw_bus * bus,
> + struct sdw_stream_config * stream_config,
> + struct sdw_ports_config * ports_config,
> + struct sdw_stream_runtime * stream);
> +
> + int sdw_stream_add_slave(struct sdw_slave * slave,
> + struct sdw_stream_config * stream_config,
> + struct sdw_ports_config * ports_config,
> + struct sdw_stream_runtime * stream);
> +
> +
> +SDW_STREAM_PREPARED
> +~~~~~~~~~~~~~~~~~~~
> +
> +Prepare state of stream. Operations performed before entering in this state:
> +
> + (1) Bus parameters such as bandwidth, frame shape, clock frequency,
> + are computed based on current stream as well as already active
> + stream(s) on Bus. Re-computation is required to accommodate current
> + stream on the Bus.
> +
> + (2) Transport and port parameters of all Master(s) and Slave(s) port(s) are
> + computed for the current as well as already active stream based on frame
> + shape and clock frequency computed in step 1.
> +
> + (3) Computed Bus and transport parameters are programmed in Master(s) and
> + Slave(s) registers. The banked registers programming is done on the
> + alternate bank (bank currently unused). Port(s) are enabled for the
> + already active stream(s) on the alternate bank (bank currently unused).
> + This is done in order to not disrupt already active stream(s).
> +
> + (4) Once all the values are programmed, Bus initiates switch to alternate
> + bank where all new values programmed gets into effect.
> +
> + (5) Ports of Master(s) and Slave(s) for current stream are prepared by
> + programming PrepareCtrl register.
> +
> +After all above operations are successful, stream state is set to
> +``SDW_STREAM_PREPARED``.
> +
> +Bus implements below API for PREPARE state which needs to be called once per
> +stream. From ASoC DPCM framework, this stream state is linked to
> +.prepare() operation.
> +
> + .. code-block:: c
> + int sdw_prepare_stream(struct sdw_stream_runtime * stream);
> +
> +
> +SDW_STREAM_ENABLED
> +~~~~~~~~~~~~~~~~~~
> +
> +Enable state of stream. The data port(s) are enabled upon entering this state.
> +Operations performed before entering in this state:
> +
> + (1) All the values computed in SDW_STREAM_PREPARED state are programmed
> + in alternate bank (bank currently unused). It includes programming of
> + already active stream(s) as well.
> +
> + (2) All the Master(s) and Slave(s) port(s) for the current stream are
> + enabled on alternate bank (bank currently unused) by programming
> + ChannelEn register.
> +
> + (3) Once all the values are programmed, Bus initiates switch to alternate
> + bank where all new values programmed gets into effect and port(s)
> + associated with current stream are enabled.
> +
> +After all above operations are successful, stream state is set to
> +``SDW_STREAM_ENABLED``.
> +
> +Bus implements below API for ENABLE state which needs to be called once per
> +stream. From ASoC DPCM framework, this stream state is linked to
> +.trigger() start operation.
> +
> + .. code-block:: c
> + int sdw_enable_stream(struct sdw_stream_runtime * stream);
> +
> +SDW_STREAM_DISABLED
> +~~~~~~~~~~~~~~~~~~~
> +
> +Disable state of stream. The data port(s) are disabled upon exiting this state.
> +Operations performed before entering in this state:
> +
> + (1) All the Master(s) and Slave(s) port(s) for the current stream are
> + disabled on alternate bank (bank currently unused) by programming
> + ChannelEn register.
> +
> + (2) All the current configuration of Bus and active stream(s) are programmed
> + into alternate bank (bank currently unused).
> +
> + (3) Once all the values are programmed, Bus initiates switch to alternate
> + bank where all new values programmed gets into effect and port(s) associated
> + with current stream are disabled.
> +
> +After all above operations are successful, stream state is set to
> +``SDW_STREAM_DISABLED``.
> +
> +Bus implements below API for DISABLED state which needs to be called once
> +per stream. From ASoC DPCM framework, this stream state is linked to
> +.trigger() stop operation.
> +
> + .. code-block:: c
> + int sdw_disable_stream(struct sdw_stream_runtime * stream);
> +
> +
> +SDW_STREAM_DEPREPARED
> +~~~~~~~~~~~~~~~~~~~~~
> +
> +De-prepare state of stream. Operations performed before entering in this
> +state:
> +
> + (1) All the port(s) of Master(s) and Slave(s) for current stream are
> + de-prepared by programming PrepareCtrl register.
> +
> + (2) The payload bandwidth of current stream is reduced from the total
> + bandwidth requirement of bus and new parameters calculated and
> + applied by performing bank switch etc.
> +
> +After all above operations are successful, stream state is set to
> +``SDW_STREAM_DEPREPARED``.
> +
> +Bus implements below API for DEPREPARED state which needs to be called once
> +per stream. From ASoC DPCM framework, this stream state is linked to
> +.trigger() stop operation.
> +
> + .. code-block:: c
> + int sdw_deprepare_stream(struct sdw_stream_runtime * stream);
> +
> +
> +SDW_STREAM_RELEASED
> +~~~~~~~~~~~~~~~~~~~
> +
> +Release state of stream. Operations performed before entering in this state:
> +
> + (1) Release port resources for all Master(s) and Slave(s) port(s)
> + associated with current stream.
> +
> + (2) Release Master(s) and Slave(s) runtime resources associated with
> + current stream.
> +
> + (3) Release stream runtime resources associated with current stream.
> +
> +After all above operations are successful, stream state is set to
> +``SDW_STREAM_RELEASED``.
> +
> +Bus implements below APIs for RELEASE state which needs to be called by
> +all the Master(s) and Slave(s) associated with stream. From ASoC DPCM
> +framework, this stream state is linked to .hw_free() operation.
> +
> + .. code-block:: c
> + int sdw_stream_remove_master(struct sdw_bus * bus,
> + struct sdw_stream_runtime * stream);
> + int sdw_stream_remove_slave(struct sdw_slave * slave,
> + struct sdw_stream_runtime * stream);
> +
> +
> +The .shutdown() ASoC DPCM operation calls below Bus API to release
> +stream assigned as part of ALLOCATED state.
> +
> +In .shutdown() the data structure maintaining stream state are freed up.
> +
> + .. code-block:: c
> + void sdw_release_stream(struct sdw_stream_runtime * stream);
> +
> +Not Supported
> +=============
> +
> +1. A single port with multiple channels supported cannot be used between two
> +streams or across stream. For example a port with 4 channels cannot be used
> +to handle 2 independent stereo streams even though it's possible in theory
> +in SoundWire.
>
More information about the Alsa-devel
mailing list