Commit 48949722 authored by Vinod Koul's avatar Vinod Koul

soundwire: Handle multiple master instances in a stream

For each SoundWire stream operation, we need to parse master
list and operate upon all master runtime.

This is a preparatory patch to do the boilerplate conversion
of stream handling from single master runtime to handle a
list of master runtime. The code to support bank switch for
multiple master instances is added in the next patch.
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 0c4a1049
...@@ -681,18 +681,22 @@ static int sdw_bank_switch(struct sdw_bus *bus) ...@@ -681,18 +681,22 @@ static int sdw_bank_switch(struct sdw_bus *bus)
static int do_bank_switch(struct sdw_stream_runtime *stream) static int do_bank_switch(struct sdw_stream_runtime *stream)
{ {
struct sdw_master_runtime *m_rt = stream->m_rt; struct sdw_master_runtime *m_rt = NULL;
const struct sdw_master_ops *ops; const struct sdw_master_ops *ops;
struct sdw_bus *bus = m_rt->bus; struct sdw_bus *bus = NULL;
int ret = 0; int ret = 0;
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
bus = m_rt->bus;
ops = bus->ops; ops = bus->ops;
/* Pre-bank switch */ /* Pre-bank switch */
if (ops->pre_bank_switch) { if (ops->pre_bank_switch) {
ret = ops->pre_bank_switch(bus); ret = ops->pre_bank_switch(bus);
if (ret < 0) { if (ret < 0) {
dev_err(bus->dev, "Pre bank switch op failed: %d", ret); dev_err(bus->dev,
"Pre bank switch op failed: %d", ret);
return ret; return ret;
} }
} }
...@@ -703,6 +707,11 @@ static int do_bank_switch(struct sdw_stream_runtime *stream) ...@@ -703,6 +707,11 @@ static int do_bank_switch(struct sdw_stream_runtime *stream)
dev_err(bus->dev, "Bank switch failed: %d", ret); dev_err(bus->dev, "Bank switch failed: %d", ret);
return ret; return ret;
} }
}
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
bus = m_rt->bus;
ops = bus->ops;
/* Post-bank switch */ /* Post-bank switch */
if (ops->post_bank_switch) { if (ops->post_bank_switch) {
...@@ -712,6 +721,7 @@ static int do_bank_switch(struct sdw_stream_runtime *stream) ...@@ -712,6 +721,7 @@ static int do_bank_switch(struct sdw_stream_runtime *stream)
"Post bank switch op failed: %d", ret); "Post bank switch op failed: %d", ret);
} }
} }
}
return ret; return ret;
} }
...@@ -754,6 +764,21 @@ struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name) ...@@ -754,6 +764,21 @@ struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name)
} }
EXPORT_SYMBOL(sdw_alloc_stream); EXPORT_SYMBOL(sdw_alloc_stream);
static struct sdw_master_runtime
*sdw_find_master_rt(struct sdw_bus *bus,
struct sdw_stream_runtime *stream)
{
struct sdw_master_runtime *m_rt = NULL;
/* Retrieve Bus handle if already available */
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
if (m_rt->bus == bus)
return m_rt;
}
return NULL;
}
/** /**
* sdw_alloc_master_rt() - Allocates and initialize Master runtime handle * sdw_alloc_master_rt() - Allocates and initialize Master runtime handle
* *
...@@ -770,12 +795,11 @@ static struct sdw_master_runtime ...@@ -770,12 +795,11 @@ static struct sdw_master_runtime
{ {
struct sdw_master_runtime *m_rt; struct sdw_master_runtime *m_rt;
m_rt = stream->m_rt;
/* /*
* check if Master is already allocated (as a result of Slave adding * check if Master is already allocated (as a result of Slave adding
* it first), if so skip allocation and go to configure * it first), if so skip allocation and go to configure
*/ */
m_rt = sdw_find_master_rt(bus, stream);
if (m_rt) if (m_rt)
goto stream_config; goto stream_config;
...@@ -786,7 +810,7 @@ static struct sdw_master_runtime ...@@ -786,7 +810,7 @@ static struct sdw_master_runtime
/* Initialization of Master runtime handle */ /* Initialization of Master runtime handle */
INIT_LIST_HEAD(&m_rt->port_list); INIT_LIST_HEAD(&m_rt->port_list);
INIT_LIST_HEAD(&m_rt->slave_rt_list); INIT_LIST_HEAD(&m_rt->slave_rt_list);
stream->m_rt = m_rt; list_add_tail(&m_rt->stream_node, &stream->master_list);
list_add_tail(&m_rt->bus_node, &bus->m_rt_list); list_add_tail(&m_rt->bus_node, &bus->m_rt_list);
...@@ -844,19 +868,23 @@ static void sdw_slave_port_release(struct sdw_bus *bus, ...@@ -844,19 +868,23 @@ static void sdw_slave_port_release(struct sdw_bus *bus,
struct sdw_stream_runtime *stream) struct sdw_stream_runtime *stream)
{ {
struct sdw_port_runtime *p_rt, *_p_rt; struct sdw_port_runtime *p_rt, *_p_rt;
struct sdw_master_runtime *m_rt = stream->m_rt; struct sdw_master_runtime *m_rt;
struct sdw_slave_runtime *s_rt; struct sdw_slave_runtime *s_rt;
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
if (s_rt->slave != slave) if (s_rt->slave != slave)
continue; continue;
list_for_each_entry_safe(p_rt, _p_rt, list_for_each_entry_safe(p_rt, _p_rt,
&s_rt->port_list, port_node) { &s_rt->port_list, port_node) {
list_del(&p_rt->port_node); list_del(&p_rt->port_node);
kfree(p_rt); kfree(p_rt);
} }
} }
}
} }
/** /**
...@@ -871,8 +899,9 @@ static void sdw_release_slave_stream(struct sdw_slave *slave, ...@@ -871,8 +899,9 @@ static void sdw_release_slave_stream(struct sdw_slave *slave,
struct sdw_stream_runtime *stream) struct sdw_stream_runtime *stream)
{ {
struct sdw_slave_runtime *s_rt, *_s_rt; struct sdw_slave_runtime *s_rt, *_s_rt;
struct sdw_master_runtime *m_rt = stream->m_rt; struct sdw_master_runtime *m_rt;
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
/* Retrieve Slave runtime handle */ /* Retrieve Slave runtime handle */
list_for_each_entry_safe(s_rt, _s_rt, list_for_each_entry_safe(s_rt, _s_rt,
&m_rt->slave_rt_list, m_rt_node) { &m_rt->slave_rt_list, m_rt_node) {
...@@ -883,11 +912,13 @@ static void sdw_release_slave_stream(struct sdw_slave *slave, ...@@ -883,11 +912,13 @@ static void sdw_release_slave_stream(struct sdw_slave *slave,
return; return;
} }
} }
}
} }
/** /**
* sdw_release_master_stream() - Free Master runtime handle * sdw_release_master_stream() - Free Master runtime handle
* *
* @m_rt: Master runtime node
* @stream: Stream runtime handle. * @stream: Stream runtime handle.
* *
* This function is to be called with bus_lock held * This function is to be called with bus_lock held
...@@ -895,9 +926,9 @@ static void sdw_release_slave_stream(struct sdw_slave *slave, ...@@ -895,9 +926,9 @@ static void sdw_release_slave_stream(struct sdw_slave *slave,
* handle. If this is called first then sdw_release_slave_stream() will have * handle. If this is called first then sdw_release_slave_stream() will have
* no effect as Slave(s) runtime handle would already be freed up. * no effect as Slave(s) runtime handle would already be freed up.
*/ */
static void sdw_release_master_stream(struct sdw_stream_runtime *stream) static void sdw_release_master_stream(struct sdw_master_runtime *m_rt,
struct sdw_stream_runtime *stream)
{ {
struct sdw_master_runtime *m_rt = stream->m_rt;
struct sdw_slave_runtime *s_rt, *_s_rt; struct sdw_slave_runtime *s_rt, *_s_rt;
list_for_each_entry_safe(s_rt, _s_rt, &m_rt->slave_rt_list, m_rt_node) { list_for_each_entry_safe(s_rt, _s_rt, &m_rt->slave_rt_list, m_rt_node) {
...@@ -905,7 +936,9 @@ static void sdw_release_master_stream(struct sdw_stream_runtime *stream) ...@@ -905,7 +936,9 @@ static void sdw_release_master_stream(struct sdw_stream_runtime *stream)
sdw_release_slave_stream(s_rt->slave, stream); sdw_release_slave_stream(s_rt->slave, stream);
} }
list_del(&m_rt->stream_node);
list_del(&m_rt->bus_node); list_del(&m_rt->bus_node);
kfree(m_rt);
} }
/** /**
...@@ -919,13 +952,22 @@ static void sdw_release_master_stream(struct sdw_stream_runtime *stream) ...@@ -919,13 +952,22 @@ static void sdw_release_master_stream(struct sdw_stream_runtime *stream)
int sdw_stream_remove_master(struct sdw_bus *bus, int sdw_stream_remove_master(struct sdw_bus *bus,
struct sdw_stream_runtime *stream) struct sdw_stream_runtime *stream)
{ {
struct sdw_master_runtime *m_rt, *_m_rt;
mutex_lock(&bus->bus_lock); mutex_lock(&bus->bus_lock);
sdw_release_master_stream(stream); list_for_each_entry_safe(m_rt, _m_rt,
sdw_master_port_release(bus, stream->m_rt); &stream->master_list, stream_node) {
if (m_rt->bus != bus)
continue;
sdw_master_port_release(bus, m_rt);
sdw_release_master_stream(m_rt, stream);
}
if (list_empty(&stream->master_list))
stream->state = SDW_STREAM_RELEASED; stream->state = SDW_STREAM_RELEASED;
kfree(stream->m_rt);
stream->m_rt = NULL;
mutex_unlock(&bus->bus_lock); mutex_unlock(&bus->bus_lock);
...@@ -1128,7 +1170,7 @@ int sdw_stream_add_master(struct sdw_bus *bus, ...@@ -1128,7 +1170,7 @@ int sdw_stream_add_master(struct sdw_bus *bus,
goto unlock; goto unlock;
stream_error: stream_error:
sdw_release_master_stream(stream); sdw_release_master_stream(m_rt, stream);
unlock: unlock:
mutex_unlock(&bus->bus_lock); mutex_unlock(&bus->bus_lock);
return ret; return ret;
...@@ -1206,7 +1248,7 @@ int sdw_stream_add_slave(struct sdw_slave *slave, ...@@ -1206,7 +1248,7 @@ int sdw_stream_add_slave(struct sdw_slave *slave,
* we hit error so cleanup the stream, release all Slave(s) and * we hit error so cleanup the stream, release all Slave(s) and
* Master runtime * Master runtime
*/ */
sdw_release_master_stream(stream); sdw_release_master_stream(m_rt, stream);
error: error:
mutex_unlock(&slave->bus->bus_lock); mutex_unlock(&slave->bus->bus_lock);
return ret; return ret;
...@@ -1275,6 +1317,8 @@ static void sdw_acquire_bus_lock(struct sdw_stream_runtime *stream) ...@@ -1275,6 +1317,8 @@ static void sdw_acquire_bus_lock(struct sdw_stream_runtime *stream)
* @stream: SoundWire stream * @stream: SoundWire stream
* *
* Release the previously held bus_lock after reconfiguring the bus. * Release the previously held bus_lock after reconfiguring the bus.
* NOTE: This function is called from SoundWire stream ops and is
* expected that a global lock is held before releasing bus_lock.
*/ */
static void sdw_release_bus_lock(struct sdw_stream_runtime *stream) static void sdw_release_bus_lock(struct sdw_stream_runtime *stream)
{ {
...@@ -1290,12 +1334,15 @@ static void sdw_release_bus_lock(struct sdw_stream_runtime *stream) ...@@ -1290,12 +1334,15 @@ static void sdw_release_bus_lock(struct sdw_stream_runtime *stream)
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 = NULL;
struct sdw_bus *bus = m_rt->bus; struct sdw_bus *bus = NULL;
struct sdw_master_prop *prop = NULL; struct sdw_master_prop *prop = NULL;
struct sdw_bus_params params; struct sdw_bus_params params;
int ret; int ret;
/* Prepare Master(s) and Slave(s) port(s) associated with stream */
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
bus = m_rt->bus;
prop = &bus->prop; prop = &bus->prop;
memcpy(&params, &bus->params, sizeof(params)); memcpy(&params, &bus->params, sizeof(params));
...@@ -1317,12 +1364,17 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream) ...@@ -1317,12 +1364,17 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream)
goto restore_params; goto restore_params;
} }
}
ret = do_bank_switch(stream); ret = do_bank_switch(stream);
if (ret < 0) { if (ret < 0) {
dev_err(bus->dev, "Bank switch failed: %d", ret); dev_err(bus->dev, "Bank switch failed: %d", ret);
goto restore_params; goto restore_params;
} }
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
bus = m_rt->bus;
/* Prepare port(s) on the new clock configuration */ /* Prepare port(s) on the new clock configuration */
ret = sdw_prep_deprep_ports(m_rt, true); ret = sdw_prep_deprep_ports(m_rt, true);
if (ret < 0) { if (ret < 0) {
...@@ -1330,6 +1382,7 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream) ...@@ -1330,6 +1382,7 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream)
ret); ret);
return ret; return ret;
} }
}
stream->state = SDW_STREAM_PREPARED; stream->state = SDW_STREAM_PREPARED;
...@@ -1356,23 +1409,27 @@ int sdw_prepare_stream(struct sdw_stream_runtime *stream) ...@@ -1356,23 +1409,27 @@ int sdw_prepare_stream(struct sdw_stream_runtime *stream)
return -EINVAL; return -EINVAL;
} }
mutex_lock(&stream->m_rt->bus->bus_lock); sdw_acquire_bus_lock(stream);
ret = _sdw_prepare_stream(stream); ret = _sdw_prepare_stream(stream);
if (ret < 0) if (ret < 0)
pr_err("Prepare for stream:%s failed: %d", stream->name, ret); pr_err("Prepare for stream:%s failed: %d", stream->name, ret);
mutex_unlock(&stream->m_rt->bus->bus_lock); sdw_release_bus_lock(stream);
return ret; return ret;
} }
EXPORT_SYMBOL(sdw_prepare_stream); EXPORT_SYMBOL(sdw_prepare_stream);
static int _sdw_enable_stream(struct sdw_stream_runtime *stream) static int _sdw_enable_stream(struct sdw_stream_runtime *stream)
{ {
struct sdw_master_runtime *m_rt = stream->m_rt; struct sdw_master_runtime *m_rt = NULL;
struct sdw_bus *bus = m_rt->bus; struct sdw_bus *bus = NULL;
int ret; int ret;
/* Enable Master(s) and Slave(s) port(s) associated with stream */
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
bus = m_rt->bus;
/* Program params */ /* Program params */
ret = sdw_program_params(bus); ret = sdw_program_params(bus);
if (ret < 0) { if (ret < 0) {
...@@ -1386,6 +1443,7 @@ static int _sdw_enable_stream(struct sdw_stream_runtime *stream) ...@@ -1386,6 +1443,7 @@ static int _sdw_enable_stream(struct sdw_stream_runtime *stream)
dev_err(bus->dev, "Enable port(s) failed ret: %d", ret); dev_err(bus->dev, "Enable port(s) failed ret: %d", ret);
return ret; return ret;
} }
}
ret = do_bank_switch(stream); ret = do_bank_switch(stream);
if (ret < 0) { if (ret < 0) {
...@@ -1413,38 +1471,43 @@ int sdw_enable_stream(struct sdw_stream_runtime *stream) ...@@ -1413,38 +1471,43 @@ int sdw_enable_stream(struct sdw_stream_runtime *stream)
return -EINVAL; return -EINVAL;
} }
mutex_lock(&stream->m_rt->bus->bus_lock); sdw_acquire_bus_lock(stream);
ret = _sdw_enable_stream(stream); ret = _sdw_enable_stream(stream);
if (ret < 0) if (ret < 0)
pr_err("Enable for stream:%s failed: %d", stream->name, ret); pr_err("Enable for stream:%s failed: %d", stream->name, ret);
mutex_unlock(&stream->m_rt->bus->bus_lock); sdw_release_bus_lock(stream);
return ret; return ret;
} }
EXPORT_SYMBOL(sdw_enable_stream); EXPORT_SYMBOL(sdw_enable_stream);
static int _sdw_disable_stream(struct sdw_stream_runtime *stream) static int _sdw_disable_stream(struct sdw_stream_runtime *stream)
{ {
struct sdw_master_runtime *m_rt = stream->m_rt; struct sdw_master_runtime *m_rt = NULL;
struct sdw_bus *bus = m_rt->bus; struct sdw_bus *bus = NULL;
int ret; int ret;
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
bus = m_rt->bus;
/* Disable port(s) */ /* Disable port(s) */
ret = sdw_enable_disable_ports(m_rt, false); ret = sdw_enable_disable_ports(m_rt, false);
if (ret < 0) { if (ret < 0) {
dev_err(bus->dev, "Disable port(s) failed: %d", ret); dev_err(bus->dev, "Disable port(s) failed: %d", ret);
return ret; return ret;
} }
}
stream->state = SDW_STREAM_DISABLED; stream->state = SDW_STREAM_DISABLED;
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
bus = m_rt->bus;
/* Program params */ /* Program params */
ret = sdw_program_params(bus); ret = sdw_program_params(bus);
if (ret < 0) { if (ret < 0) {
dev_err(bus->dev, "Program params failed: %d", ret); dev_err(bus->dev, "Program params failed: %d", ret);
return ret; return ret;
} }
}
return do_bank_switch(stream); return do_bank_switch(stream);
} }
...@@ -1465,23 +1528,25 @@ int sdw_disable_stream(struct sdw_stream_runtime *stream) ...@@ -1465,23 +1528,25 @@ int sdw_disable_stream(struct sdw_stream_runtime *stream)
return -EINVAL; return -EINVAL;
} }
mutex_lock(&stream->m_rt->bus->bus_lock); sdw_acquire_bus_lock(stream);
ret = _sdw_disable_stream(stream); ret = _sdw_disable_stream(stream);
if (ret < 0) if (ret < 0)
pr_err("Disable for stream:%s failed: %d", stream->name, ret); pr_err("Disable for stream:%s failed: %d", stream->name, ret);
mutex_unlock(&stream->m_rt->bus->bus_lock); sdw_release_bus_lock(stream);
return ret; return ret;
} }
EXPORT_SYMBOL(sdw_disable_stream); EXPORT_SYMBOL(sdw_disable_stream);
static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream) static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
{ {
struct sdw_master_runtime *m_rt = stream->m_rt; struct sdw_master_runtime *m_rt = NULL;
struct sdw_bus *bus = m_rt->bus; struct sdw_bus *bus = NULL;
int ret = 0; int ret = 0;
list_for_each_entry(m_rt, &stream->master_list, stream_node) {
bus = m_rt->bus;
/* De-prepare port(s) */ /* De-prepare port(s) */
ret = sdw_prep_deprep_ports(m_rt, false); ret = sdw_prep_deprep_ports(m_rt, false);
if (ret < 0) { if (ret < 0) {
...@@ -1489,8 +1554,6 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream) ...@@ -1489,8 +1554,6 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
return ret; return ret;
} }
stream->state = SDW_STREAM_DEPREPARED;
/* TODO: Update this during Device-Device support */ /* TODO: Update this during Device-Device support */
bus->params.bandwidth -= m_rt->stream->params.rate * bus->params.bandwidth -= m_rt->stream->params.rate *
m_rt->ch_count * m_rt->stream->params.bps; m_rt->ch_count * m_rt->stream->params.bps;
...@@ -1502,6 +1565,9 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream) ...@@ -1502,6 +1565,9 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
return ret; return ret;
} }
}
stream->state = SDW_STREAM_DEPREPARED;
return do_bank_switch(stream); return do_bank_switch(stream);
} }
...@@ -1521,13 +1587,12 @@ int sdw_deprepare_stream(struct sdw_stream_runtime *stream) ...@@ -1521,13 +1587,12 @@ int sdw_deprepare_stream(struct sdw_stream_runtime *stream)
return -EINVAL; return -EINVAL;
} }
mutex_lock(&stream->m_rt->bus->bus_lock); sdw_acquire_bus_lock(stream);
ret = _sdw_deprepare_stream(stream); ret = _sdw_deprepare_stream(stream);
if (ret < 0) if (ret < 0)
pr_err("De-prepare for stream:%d failed: %d", ret, ret); pr_err("De-prepare for stream:%d failed: %d", ret, ret);
mutex_unlock(&stream->m_rt->bus->bus_lock); sdw_release_bus_lock(stream);
return ret; return ret;
} }
EXPORT_SYMBOL(sdw_deprepare_stream); EXPORT_SYMBOL(sdw_deprepare_stream);
...@@ -768,7 +768,6 @@ struct sdw_stream_params { ...@@ -768,7 +768,6 @@ struct sdw_stream_params {
* @params: Stream parameters * @params: Stream parameters
* @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
* @master_list: List of Master runtime(s) in this stream. * @master_list: List of Master runtime(s) in this stream.
* master_list can contain only one m_rt per Master instance * master_list can contain only one m_rt per Master instance
* for a stream * for a stream
...@@ -778,7 +777,6 @@ struct sdw_stream_runtime { ...@@ -778,7 +777,6 @@ struct sdw_stream_runtime {
struct sdw_stream_params params; struct sdw_stream_params params;
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 list_head master_list; struct list_head master_list;
}; };
......
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