Commit 0c4a1049 authored by Sanyog Kale's avatar Sanyog Kale Committed by Vinod Koul

soundwire: Add support to lock across bus instances

Currently, the stream concept is limited to single Master and one
or more Codecs.

This patch extends the concept to support multiple Master(s)
sharing the same reference clock and synchronized in the hardware.
Modify sdw_stream_runtime to support a list of sdw_master_runtime
for the same. The existing reference to a single m_rt is removed
in the next patch.

Typically to lock, one would acquire a global lock and then lock
bus instances. In this case, the caller framework(ASoC DPCM)
guarantees that stream operations on a card are always serialized.
So, there is no race condition and hence no need for global lock.

Bus lock(s) are acquired to reconfigure the bus while the stream
is set-up.
So, we add sdw_acquire_bus_lock()/sdw_release_bus_lock() APIs which
are used only to reconfigure the bus.
Signed-off-by: default avatarSanyog Kale <sanyog.r.kale@intel.com>
Signed-off-by: default avatarShreyas NC <shreyas.nc@intel.com>
Acked-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent a306a0e4
...@@ -99,6 +99,7 @@ struct sdw_slave_runtime { ...@@ -99,6 +99,7 @@ struct sdw_slave_runtime {
* this stream, can be zero. * this stream, can be zero.
* @slave_rt_list: Slave runtime list * @slave_rt_list: Slave runtime list
* @port_list: List of Master Ports configured for this stream, can be zero. * @port_list: List of Master Ports configured for this stream, can be zero.
* @stream_node: sdw_stream_runtime master_list node
* @bus_node: sdw_bus m_rt_list node * @bus_node: sdw_bus m_rt_list node
*/ */
struct sdw_master_runtime { struct sdw_master_runtime {
...@@ -108,6 +109,7 @@ struct sdw_master_runtime { ...@@ -108,6 +109,7 @@ struct sdw_master_runtime {
unsigned int ch_count; unsigned int ch_count;
struct list_head slave_rt_list; struct list_head slave_rt_list;
struct list_head port_list; struct list_head port_list;
struct list_head stream_node;
struct list_head bus_node; struct list_head bus_node;
}; };
......
...@@ -747,6 +747,7 @@ struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name) ...@@ -747,6 +747,7 @@ struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name)
return NULL; return NULL;
stream->name = stream_name; stream->name = stream_name;
INIT_LIST_HEAD(&stream->master_list);
stream->state = SDW_STREAM_ALLOCATED; stream->state = SDW_STREAM_ALLOCATED;
return stream; return stream;
...@@ -1245,6 +1246,48 @@ struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave, ...@@ -1245,6 +1246,48 @@ struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave,
return NULL; return NULL;
} }
/**
* sdw_acquire_bus_lock: Acquire bus lock for all Master runtime(s)
*
* @stream: SoundWire stream
*
* Acquire bus_lock for each of the master runtime(m_rt) part of this
* stream to reconfigure the bus.
* NOTE: This function is called from SoundWire stream ops and is
* expected that a global lock is held before acquiring bus_lock.
*/
static void sdw_acquire_bus_lock(struct sdw_stream_runtime *stream)
{
struct sdw_master_runtime *m_rt = NULL;
struct sdw_bus *bus = NULL;
/* Iterate for all Master(s) in Master list */
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
bus = m_rt->bus;
mutex_lock(&bus->bus_lock);
}
}
/**
* sdw_release_bus_lock: Release bus lock for all Master runtime(s)
*
* @stream: SoundWire stream
*
* Release the previously held bus_lock after reconfiguring the bus.
*/
static void sdw_release_bus_lock(struct sdw_stream_runtime *stream)
{
struct sdw_master_runtime *m_rt = NULL;
struct sdw_bus *bus = NULL;
/* Iterate for all Master(s) in Master list */
list_for_each_entry_reverse(m_rt, &stream->master_list, stream_node) {
bus = m_rt->bus;
mutex_unlock(&bus->bus_lock);
}
}
static int _sdw_prepare_stream(struct sdw_stream_runtime *stream) static int _sdw_prepare_stream(struct sdw_stream_runtime *stream)
{ {
struct sdw_master_runtime *m_rt = stream->m_rt; struct sdw_master_runtime *m_rt = stream->m_rt;
......
...@@ -769,6 +769,9 @@ struct sdw_stream_params { ...@@ -769,6 +769,9 @@ struct sdw_stream_params {
* @state: Current state of the stream * @state: Current state of the stream
* @type: Stream type PCM or PDM * @type: Stream type PCM or PDM
* @m_rt: Master runtime * @m_rt: Master runtime
* @master_list: List of Master runtime(s) in this stream.
* master_list can contain only one m_rt per Master instance
* for a stream
*/ */
struct sdw_stream_runtime { struct sdw_stream_runtime {
char *name; char *name;
...@@ -776,6 +779,7 @@ struct sdw_stream_runtime { ...@@ -776,6 +779,7 @@ struct sdw_stream_runtime {
enum sdw_stream_state state; enum sdw_stream_state state;
enum sdw_stream_type type; enum sdw_stream_type type;
struct sdw_master_runtime *m_rt; struct sdw_master_runtime *m_rt;
struct list_head master_list;
}; };
struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name); struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment