diff mbox

[v5,6/9] soundwire: Handle multiple master instances in a stream

Message ID 1530791196-15483-7-git-send-email-shreyas.nc@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Shreyas NC July 5, 2018, 11:46 a.m. UTC
From: Vinod Koul <vkoul@kernel.org>

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: Sanyog Kale <sanyog.r.kale@intel.com>
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Signed-off-by: Shreyas NC <shreyas.nc@intel.com>
---
 drivers/soundwire/stream.c    | 309 +++++++++++++++++++++++++-----------------
 include/linux/soundwire/sdw.h |   2 -
 2 files changed, 186 insertions(+), 125 deletions(-)

Comments

Pierre-Louis Bossart July 9, 2018, 11:42 p.m. UTC | #1
Sorry, another issue that I found while reviewing the entire section.
>   }
> @@ -888,6 +918,7 @@ static void sdw_release_slave_stream(struct sdw_slave *slave,
>   /**
>    * sdw_release_master_stream() - Free Master runtime handle
>    *
> + * @m_rt: Master runtime node
>    * @stream: Stream runtime handle.
>    *
>    * This function is to be called with bus_lock held
> @@ -895,16 +926,18 @@ static void sdw_release_slave_stream(struct sdw_slave *slave,
>    * 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.
>    */
> -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;
>   
>   	list_for_each_entry_safe(s_rt, _s_rt,
>   			&m_rt->slave_rt_list, m_rt_node)
>   		sdw_stream_remove_slave(s_rt->slave, stream);
>   
> +	list_del(&m_rt->stream_node);
>   	list_del(&m_rt->bus_node);
> +	kfree(m_rt);
>   }
>   
>   /**
> @@ -918,13 +951,22 @@ static void sdw_release_master_stream(struct sdw_stream_runtime *stream)
>   int sdw_stream_remove_master(struct sdw_bus *bus,
>   		struct sdw_stream_runtime *stream)
>   {
> +	struct sdw_master_runtime *m_rt, *_m_rt;
> +
>   	mutex_lock(&bus->bus_lock);
>   
> -	sdw_release_master_stream(stream);
> -	sdw_master_port_release(bus, stream->m_rt);
> -	stream->state = SDW_STREAM_RELEASED;
> -	kfree(stream->m_rt);
> -	stream->m_rt = NULL;
> +	list_for_each_entry_safe(m_rt, _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;
>   
>   	mutex_unlock(&bus->bus_lock);
>   
>
So the sequence is

mutex_lock
sdw_master_port_release()
sdw_release_master_stream()
     sdw_stream_remove_slave()
         mutex_lock

Is this intentional to take the same mutex twice (not sure if it even 
works).
what you probably wanted is to replace sdw_stream_remove_slave() by the 
equivalent sequence

sdw_slave_port_release()
sdw_release_slave_stream()

which are both supposed to be called with a bus_lock held.
Sanyog Kale July 10, 2018, 5:02 p.m. UTC | #2
On Mon, Jul 09, 2018 at 06:42:34PM -0500, Pierre-Louis Bossart wrote:
> Sorry, another issue that I found while reviewing the entire section.
> >  }
> >@@ -888,6 +918,7 @@ static void sdw_release_slave_stream(struct sdw_slave *slave,
> >  /**
> >   * sdw_release_master_stream() - Free Master runtime handle
> >   *
> >+ * @m_rt: Master runtime node
> >   * @stream: Stream runtime handle.
> >   *
> >   * This function is to be called with bus_lock held
> >@@ -895,16 +926,18 @@ static void sdw_release_slave_stream(struct sdw_slave *slave,
> >   * 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.
> >   */
> >-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;
> >  	list_for_each_entry_safe(s_rt, _s_rt,
> >  			&m_rt->slave_rt_list, m_rt_node)
> >  		sdw_stream_remove_slave(s_rt->slave, stream);
> >+	list_del(&m_rt->stream_node);
> >  	list_del(&m_rt->bus_node);
> >+	kfree(m_rt);
> >  }
> >  /**
> >@@ -918,13 +951,22 @@ static void sdw_release_master_stream(struct sdw_stream_runtime *stream)
> >  int sdw_stream_remove_master(struct sdw_bus *bus,
> >  		struct sdw_stream_runtime *stream)
> >  {
> >+	struct sdw_master_runtime *m_rt, *_m_rt;
> >+
> >  	mutex_lock(&bus->bus_lock);
> >-	sdw_release_master_stream(stream);
> >-	sdw_master_port_release(bus, stream->m_rt);
> >-	stream->state = SDW_STREAM_RELEASED;
> >-	kfree(stream->m_rt);
> >-	stream->m_rt = NULL;
> >+	list_for_each_entry_safe(m_rt, _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;
> >  	mutex_unlock(&bus->bus_lock);
> >
> So the sequence is
> 
> mutex_lock
> sdw_master_port_release()
> sdw_release_master_stream()
> ?????? sdw_stream_remove_slave()
> ?????? ?????? mutex_lock
> 
> Is this intentional to take the same mutex twice (not sure if it even
> works).

sdw_stream_remove_slave is called from sdw_release_master_stream to make
sure all Slave(s) resources are freed up before freeing Master.
sdw_stream_remove_slave is also called by Slave driver to free up Slave
resources. In either case, we wanted to make sure the bus_lock is held
hence the bus lock is held in sdw_stream_remove_slave API as well.

It doesnt look correct to take same mutex twice. Will check on this.

> what you probably wanted is to replace sdw_stream_remove_slave() by the
> equivalent sequence
> 
> sdw_slave_port_release()
> sdw_release_slave_stream()
> 
> which are both supposed to be called with a bus_lock held.

you mean to say perform sdw_slave_port_release and
sdw_release_slave_stream in sdw_release_master_stream instead of calling
sdw_stream_remove_slave??
Pierre-Louis Bossart July 10, 2018, 6:16 p.m. UTC | #3
On 7/10/18 12:02 PM, Sanyog Kale wrote:
> On Mon, Jul 09, 2018 at 06:42:34PM -0500, Pierre-Louis Bossart wrote:
>> Sorry, another issue that I found while reviewing the entire section.
>>>   }
>>> @@ -888,6 +918,7 @@ static void sdw_release_slave_stream(struct sdw_slave *slave,
>>>   /**
>>>    * sdw_release_master_stream() - Free Master runtime handle
>>>    *
>>> + * @m_rt: Master runtime node
>>>    * @stream: Stream runtime handle.
>>>    *
>>>    * This function is to be called with bus_lock held
>>> @@ -895,16 +926,18 @@ static void sdw_release_slave_stream(struct sdw_slave *slave,
>>>    * 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.
>>>    */
>>> -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;
>>>   	list_for_each_entry_safe(s_rt, _s_rt,
>>>   			&m_rt->slave_rt_list, m_rt_node)
>>>   		sdw_stream_remove_slave(s_rt->slave, stream);
>>> +	list_del(&m_rt->stream_node);
>>>   	list_del(&m_rt->bus_node);
>>> +	kfree(m_rt);
>>>   }
>>>   /**
>>> @@ -918,13 +951,22 @@ static void sdw_release_master_stream(struct sdw_stream_runtime *stream)
>>>   int sdw_stream_remove_master(struct sdw_bus *bus,
>>>   		struct sdw_stream_runtime *stream)
>>>   {
>>> +	struct sdw_master_runtime *m_rt, *_m_rt;
>>> +
>>>   	mutex_lock(&bus->bus_lock);
>>> -	sdw_release_master_stream(stream);
>>> -	sdw_master_port_release(bus, stream->m_rt);
>>> -	stream->state = SDW_STREAM_RELEASED;
>>> -	kfree(stream->m_rt);
>>> -	stream->m_rt = NULL;
>>> +	list_for_each_entry_safe(m_rt, _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;
>>>   	mutex_unlock(&bus->bus_lock);
>>>
>> So the sequence is
>>
>> mutex_lock
>> sdw_master_port_release()
>> sdw_release_master_stream()
>> ?????? sdw_stream_remove_slave()
>> ?????? ?????? mutex_lock
>>
>> Is this intentional to take the same mutex twice (not sure if it even
>> works).
> 
> sdw_stream_remove_slave is called from sdw_release_master_stream to make
> sure all Slave(s) resources are freed up before freeing Master.
> sdw_stream_remove_slave is also called by Slave driver to free up Slave
> resources. In either case, we wanted to make sure the bus_lock is held
> hence the bus lock is held in sdw_stream_remove_slave API as well.

Yes, it's fine to take the lock from sdw_stream_remove_slave(), the 
point was to avoid taking the lock twice when the master is removed first.

> 
> It doesnt look correct to take same mutex twice. Will check on this.
> 
>> what you probably wanted is to replace sdw_stream_remove_slave() by the
>> equivalent sequence
>>
>> sdw_slave_port_release()
>> sdw_release_slave_stream()
>>
>> which are both supposed to be called with a bus_lock held.
> 
> you mean to say perform sdw_slave_port_release and
> sdw_release_slave_stream in sdw_release_master_stream instead of calling
> sdw_stream_remove_slave??

Yes, something like the change below:

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;
  	list_for_each_entry_safe(s_rt, _s_rt,
  			&m_rt->slave_rt_list, m_rt_node)
- 		sdw_stream_remove_slave(s_rt->slave, stream);
+		sdw_slave_port_release()
+		sdw_release_slave_stream()
	list_del(&m_rt->stream_node);
  	list_del(&m_rt->bus_node);
	kfree(m_rt);
  }
Sanyog Kale July 11, 2018, 3:47 a.m. UTC | #4
On Tue, Jul 10, 2018 at 01:16:30PM -0500, Pierre-Louis Bossart wrote:
> On 7/10/18 12:02 PM, Sanyog Kale wrote:
> >On Mon, Jul 09, 2018 at 06:42:34PM -0500, Pierre-Louis Bossart wrote:
> >>Sorry, another issue that I found while reviewing the entire section.
> >>>  }
> >>>@@ -888,6 +918,7 @@ static void sdw_release_slave_stream(struct sdw_slave *slave,
> >>>  /**
> >>>   * sdw_release_master_stream() - Free Master runtime handle
> >>>   *
> >>>+ * @m_rt: Master runtime node
> >>>   * @stream: Stream runtime handle.
> >>>   *
> >>>   * This function is to be called with bus_lock held
> >>>@@ -895,16 +926,18 @@ static void sdw_release_slave_stream(struct sdw_slave *slave,
> >>>   * 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.
> >>>   */
> >>>-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;
> >>>  	list_for_each_entry_safe(s_rt, _s_rt,
> >>>  			&m_rt->slave_rt_list, m_rt_node)
> >>>  		sdw_stream_remove_slave(s_rt->slave, stream);
> >>>+	list_del(&m_rt->stream_node);
> >>>  	list_del(&m_rt->bus_node);
> >>>+	kfree(m_rt);
> >>>  }
> >>>  /**
> >>>@@ -918,13 +951,22 @@ static void sdw_release_master_stream(struct sdw_stream_runtime *stream)
> >>>  int sdw_stream_remove_master(struct sdw_bus *bus,
> >>>  		struct sdw_stream_runtime *stream)
> >>>  {
> >>>+	struct sdw_master_runtime *m_rt, *_m_rt;
> >>>+
> >>>  	mutex_lock(&bus->bus_lock);
> >>>-	sdw_release_master_stream(stream);
> >>>-	sdw_master_port_release(bus, stream->m_rt);
> >>>-	stream->state = SDW_STREAM_RELEASED;
> >>>-	kfree(stream->m_rt);
> >>>-	stream->m_rt = NULL;
> >>>+	list_for_each_entry_safe(m_rt, _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;
> >>>  	mutex_unlock(&bus->bus_lock);
> >>>
> >>So the sequence is
> >>
> >>mutex_lock
> >>sdw_master_port_release()
> >>sdw_release_master_stream()
> >>?????? sdw_stream_remove_slave()
> >>?????? ?????? mutex_lock
> >>
> >>Is this intentional to take the same mutex twice (not sure if it even
> >>works).
> >
> >sdw_stream_remove_slave is called from sdw_release_master_stream to make
> >sure all Slave(s) resources are freed up before freeing Master.
> >sdw_stream_remove_slave is also called by Slave driver to free up Slave
> >resources. In either case, we wanted to make sure the bus_lock is held
> >hence the bus lock is held in sdw_stream_remove_slave API as well.
> 
> Yes, it's fine to take the lock from sdw_stream_remove_slave(), the point
> was to avoid taking the lock twice when the master is removed first.
> 
> >
> >It doesnt look correct to take same mutex twice. Will check on this.
> >
> >>what you probably wanted is to replace sdw_stream_remove_slave() by the
> >>equivalent sequence
> >>
> >>sdw_slave_port_release()
> >>sdw_release_slave_stream()
> >>
> >>which are both supposed to be called with a bus_lock held.
> >
> >you mean to say perform sdw_slave_port_release and
> >sdw_release_slave_stream in sdw_release_master_stream instead of calling
> >sdw_stream_remove_slave??
> 
> Yes, something like the change below:
> 
> 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;
>  	list_for_each_entry_safe(s_rt, _s_rt,
>  			&m_rt->slave_rt_list, m_rt_node)
> - 		sdw_stream_remove_slave(s_rt->slave, stream);
> +		sdw_slave_port_release()
> +		sdw_release_slave_stream()
> 	list_del(&m_rt->stream_node);
>  	list_del(&m_rt->bus_node);
> 	kfree(m_rt);
>  }

Ok. Will update in next version.

Thanks

>
diff mbox

Patch

diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
index 8ddaad16..c1a2c3d 100644
--- a/drivers/soundwire/stream.c
+++ b/drivers/soundwire/stream.c
@@ -681,35 +681,45 @@  static int sdw_bank_switch(struct sdw_bus *bus)
 
 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;
-	struct sdw_bus *bus = m_rt->bus;
+	struct sdw_bus *bus = NULL;
 	int ret = 0;
 
-	ops = bus->ops;
 
-	/* Pre-bank switch */
-	if (ops->pre_bank_switch) {
-		ret = ops->pre_bank_switch(bus);
+	list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+		bus = m_rt->bus;
+		ops = bus->ops;
+
+		/* Pre-bank switch */
+		if (ops->pre_bank_switch) {
+			ret = ops->pre_bank_switch(bus);
+			if (ret < 0) {
+				dev_err(bus->dev,
+					"Pre bank switch op failed: %d", ret);
+				return ret;
+			}
+		}
+
+		/* Bank switch */
+		ret = sdw_bank_switch(bus);
 		if (ret < 0) {
-			dev_err(bus->dev, "Pre bank switch op failed: %d", ret);
+			dev_err(bus->dev, "Bank switch failed: %d", ret);
 			return ret;
 		}
 	}
 
-	/* Bank switch */
-	ret = sdw_bank_switch(bus);
-	if (ret < 0) {
-		dev_err(bus->dev, "Bank switch failed: %d", ret);
-		return ret;
-	}
+	list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+		bus = m_rt->bus;
+		ops = bus->ops;
 
-	/* Post-bank switch */
-	if (ops->post_bank_switch) {
-		ret = ops->post_bank_switch(bus);
-		if (ret < 0) {
-			dev_err(bus->dev,
+		/* Post-bank switch */
+		if (ops->post_bank_switch) {
+			ret = ops->post_bank_switch(bus);
+			if (ret < 0) {
+				dev_err(bus->dev,
 					"Post bank switch op failed: %d", ret);
+			}
 		}
 	}
 
@@ -754,6 +764,21 @@  struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name)
 }
 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
  *
@@ -770,12 +795,11 @@  static struct sdw_master_runtime
 {
 	struct sdw_master_runtime *m_rt;
 
-	m_rt = stream->m_rt;
-
 	/*
 	 * check if Master is already allocated (as a result of Slave adding
 	 * it first), if so skip allocation and go to configure
 	 */
+	m_rt = sdw_find_master_rt(bus, stream);
 	if (m_rt)
 		goto stream_config;
 
@@ -786,7 +810,7 @@  static struct sdw_master_runtime
 	/* Initialization of Master runtime handle */
 	INIT_LIST_HEAD(&m_rt->port_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);
 
@@ -844,17 +868,21 @@  static void sdw_slave_port_release(struct sdw_bus *bus,
 			struct sdw_stream_runtime *stream)
 {
 	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;
 
-	list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
-		if (s_rt->slave != slave)
-			continue;
+	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_safe(p_rt, _p_rt,
-				&s_rt->port_list, port_node) {
-			list_del(&p_rt->port_node);
-			kfree(p_rt);
+			if (s_rt->slave != slave)
+				continue;
+
+			list_for_each_entry_safe(p_rt, _p_rt,
+					&s_rt->port_list, port_node) {
+
+				list_del(&p_rt->port_node);
+				kfree(p_rt);
+			}
 		}
 	}
 }
@@ -871,16 +899,18 @@  static void sdw_release_slave_stream(struct sdw_slave *slave,
 			struct sdw_stream_runtime *stream)
 {
 	struct sdw_slave_runtime *s_rt, *_s_rt;
-	struct sdw_master_runtime *m_rt = stream->m_rt;
-
-	/* Retrieve Slave runtime handle */
-	list_for_each_entry_safe(s_rt, _s_rt,
-			&m_rt->slave_rt_list, m_rt_node) {
+	struct sdw_master_runtime *m_rt;
 
-		if (s_rt->slave == slave) {
-			list_del(&s_rt->m_rt_node);
-			kfree(s_rt);
-			return;
+	list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+		/* Retrieve Slave runtime handle */
+		list_for_each_entry_safe(s_rt, _s_rt,
+					&m_rt->slave_rt_list, m_rt_node) {
+
+			if (s_rt->slave == slave) {
+				list_del(&s_rt->m_rt_node);
+				kfree(s_rt);
+				return;
+			}
 		}
 	}
 }
@@ -888,6 +918,7 @@  static void sdw_release_slave_stream(struct sdw_slave *slave,
 /**
  * sdw_release_master_stream() - Free Master runtime handle
  *
+ * @m_rt: Master runtime node
  * @stream: Stream runtime handle.
  *
  * This function is to be called with bus_lock held
@@ -895,16 +926,18 @@  static void sdw_release_slave_stream(struct sdw_slave *slave,
  * 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.
  */
-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;
 
 	list_for_each_entry_safe(s_rt, _s_rt,
 			&m_rt->slave_rt_list, m_rt_node)
 		sdw_stream_remove_slave(s_rt->slave, stream);
 
+	list_del(&m_rt->stream_node);
 	list_del(&m_rt->bus_node);
+	kfree(m_rt);
 }
 
 /**
@@ -918,13 +951,22 @@  static void sdw_release_master_stream(struct sdw_stream_runtime *stream)
 int sdw_stream_remove_master(struct sdw_bus *bus,
 		struct sdw_stream_runtime *stream)
 {
+	struct sdw_master_runtime *m_rt, *_m_rt;
+
 	mutex_lock(&bus->bus_lock);
 
-	sdw_release_master_stream(stream);
-	sdw_master_port_release(bus, stream->m_rt);
-	stream->state = SDW_STREAM_RELEASED;
-	kfree(stream->m_rt);
-	stream->m_rt = NULL;
+	list_for_each_entry_safe(m_rt, _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;
 
 	mutex_unlock(&bus->bus_lock);
 
@@ -1127,7 +1169,7 @@  int sdw_stream_add_master(struct sdw_bus *bus,
 	goto unlock;
 
 stream_error:
-	sdw_release_master_stream(stream);
+	sdw_release_master_stream(m_rt, stream);
 unlock:
 	mutex_unlock(&bus->bus_lock);
 	return ret;
@@ -1204,7 +1246,7 @@  int sdw_stream_add_slave(struct sdw_slave *slave,
 	 * we hit error so cleanup the stream, release all Slave(s) and
 	 * Master runtime
 	 */
-	sdw_release_master_stream(stream);
+	sdw_release_master_stream(m_rt, stream);
 error:
 	mutex_unlock(&slave->bus->bus_lock);
 	return ret;
@@ -1290,31 +1332,36 @@  static void sdw_release_bus_lock(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_bus *bus = m_rt->bus;
+	struct sdw_master_runtime *m_rt = NULL;
+	struct sdw_bus *bus = NULL;
 	struct sdw_master_prop *prop = NULL;
 	struct sdw_bus_params params;
 	int ret;
 
-	prop = &bus->prop;
-	memcpy(&params, &bus->params, sizeof(params));
+	/* 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;
+		memcpy(&params, &bus->params, sizeof(params));
 
-	/* TODO: Support Asynchronous mode */
-	if ((prop->max_freq % stream->params.rate) != 0) {
-		dev_err(bus->dev, "Async mode not supported");
-		return -EINVAL;
-	}
+		/* TODO: Support Asynchronous mode */
+		if ((prop->max_freq % stream->params.rate) != 0) {
+			dev_err(bus->dev, "Async mode not supported");
+			return -EINVAL;
+		}
 
-	/* Increment cumulative bus bandwidth */
-	/* TODO: Update this during Device-Device support */
-	bus->params.bandwidth += m_rt->stream->params.rate *
-		m_rt->ch_count * m_rt->stream->params.bps;
+		/* Increment cumulative bus bandwidth */
+		/* TODO: Update this during Device-Device support */
+		bus->params.bandwidth += m_rt->stream->params.rate *
+			m_rt->ch_count * m_rt->stream->params.bps;
+
+		/* Program params */
+		ret = sdw_program_params(bus);
+		if (ret < 0) {
+			dev_err(bus->dev, "Program params failed: %d", ret);
+			goto restore_params;
+		}
 
-	/* Program params */
-	ret = sdw_program_params(bus);
-	if (ret < 0) {
-		dev_err(bus->dev, "Program params failed: %d", ret);
-		goto restore_params;
 	}
 
 	ret = do_bank_switch(stream);
@@ -1323,12 +1370,16 @@  static int _sdw_prepare_stream(struct sdw_stream_runtime *stream)
 		goto restore_params;
 	}
 
-	/* Prepare port(s) on the new clock configuration */
-	ret = sdw_prep_deprep_ports(m_rt, true);
-	if (ret < 0) {
-		dev_err(bus->dev, "Prepare port(s) failed ret = %d",
-				ret);
-		return ret;
+	list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+		bus = m_rt->bus;
+
+		/* Prepare port(s) on the new clock configuration */
+		ret = sdw_prep_deprep_ports(m_rt, true);
+		if (ret < 0) {
+			dev_err(bus->dev, "Prepare port(s) failed ret = %d",
+					ret);
+			return ret;
+		}
 	}
 
 	stream->state = SDW_STREAM_PREPARED;
@@ -1356,35 +1407,40 @@  int sdw_prepare_stream(struct sdw_stream_runtime *stream)
 		return -EINVAL;
 	}
 
-	mutex_lock(&stream->m_rt->bus->bus_lock);
+	sdw_acquire_bus_lock(stream);
 
 	ret = _sdw_prepare_stream(stream);
 	if (ret < 0)
 		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;
 }
 EXPORT_SYMBOL(sdw_prepare_stream);
 
 static int _sdw_enable_stream(struct sdw_stream_runtime *stream)
 {
-	struct sdw_master_runtime *m_rt = stream->m_rt;
-	struct sdw_bus *bus = m_rt->bus;
+	struct sdw_master_runtime *m_rt = NULL;
+	struct sdw_bus *bus = NULL;
 	int ret;
 
-	/* Program params */
-	ret = sdw_program_params(bus);
-	if (ret < 0) {
-		dev_err(bus->dev, "Program params failed: %d", ret);
-		return 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;
 
-	/* Enable port(s) */
-	ret = sdw_enable_disable_ports(m_rt, true);
-	if (ret < 0) {
-		dev_err(bus->dev, "Enable port(s) failed ret: %d", ret);
-		return ret;
+		/* Program params */
+		ret = sdw_program_params(bus);
+		if (ret < 0) {
+			dev_err(bus->dev, "Program params failed: %d", ret);
+			return ret;
+		}
+
+		/* Enable port(s) */
+		ret = sdw_enable_disable_ports(m_rt, true);
+		if (ret < 0) {
+			dev_err(bus->dev, "Enable port(s) failed ret: %d", ret);
+			return ret;
+		}
 	}
 
 	ret = do_bank_switch(stream);
@@ -1413,37 +1469,42 @@  int sdw_enable_stream(struct sdw_stream_runtime *stream)
 		return -EINVAL;
 	}
 
-	mutex_lock(&stream->m_rt->bus->bus_lock);
+	sdw_acquire_bus_lock(stream);
 
 	ret = _sdw_enable_stream(stream);
 	if (ret < 0)
 		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;
 }
 EXPORT_SYMBOL(sdw_enable_stream);
 
 static int _sdw_disable_stream(struct sdw_stream_runtime *stream)
 {
-	struct sdw_master_runtime *m_rt = stream->m_rt;
-	struct sdw_bus *bus = m_rt->bus;
+	struct sdw_master_runtime *m_rt = NULL;
+	struct sdw_bus *bus = NULL;
 	int ret;
 
-	/* Disable port(s) */
-	ret = sdw_enable_disable_ports(m_rt, false);
-	if (ret < 0) {
-		dev_err(bus->dev, "Disable port(s) failed: %d", ret);
-		return ret;
+	list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+		bus = m_rt->bus;
+		/* Disable port(s) */
+		ret = sdw_enable_disable_ports(m_rt, false);
+		if (ret < 0) {
+			dev_err(bus->dev, "Disable port(s) failed: %d", ret);
+			return ret;
+		}
 	}
-
 	stream->state = SDW_STREAM_DISABLED;
 
-	/* Program params */
-	ret = sdw_program_params(bus);
-	if (ret < 0) {
-		dev_err(bus->dev, "Program params failed: %d", ret);
-		return ret;
+	list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+		bus = m_rt->bus;
+		/* Program params */
+		ret = sdw_program_params(bus);
+		if (ret < 0) {
+			dev_err(bus->dev, "Program params failed: %d", ret);
+			return ret;
+		}
 	}
 
 	return do_bank_switch(stream);
@@ -1465,43 +1526,46 @@  int sdw_disable_stream(struct sdw_stream_runtime *stream)
 		return -EINVAL;
 	}
 
-	mutex_lock(&stream->m_rt->bus->bus_lock);
+	sdw_acquire_bus_lock(stream);
 
 	ret = _sdw_disable_stream(stream);
 	if (ret < 0)
 		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;
 }
 EXPORT_SYMBOL(sdw_disable_stream);
 
 static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
 {
-	struct sdw_master_runtime *m_rt = stream->m_rt;
-	struct sdw_bus *bus = m_rt->bus;
+	struct sdw_master_runtime *m_rt = NULL;
+	struct sdw_bus *bus = NULL;
 	int ret = 0;
 
-	/* De-prepare port(s) */
-	ret = sdw_prep_deprep_ports(m_rt, false);
-	if (ret < 0) {
-		dev_err(bus->dev, "De-prepare port(s) failed: %d", ret);
-		return ret;
-	}
+	list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+		bus = m_rt->bus;
+		/* De-prepare port(s) */
+		ret = sdw_prep_deprep_ports(m_rt, false);
+		if (ret < 0) {
+			dev_err(bus->dev, "De-prepare port(s) failed: %d", ret);
+			return ret;
+		}
 
-	stream->state = SDW_STREAM_DEPREPARED;
+		/* TODO: Update this during Device-Device support */
+		bus->params.bandwidth -= m_rt->stream->params.rate *
+			m_rt->ch_count * m_rt->stream->params.bps;
 
-	/* TODO: Update this during Device-Device support */
-	bus->params.bandwidth -= m_rt->stream->params.rate *
-		m_rt->ch_count * m_rt->stream->params.bps;
+		/* Program params */
+		ret = sdw_program_params(bus);
+		if (ret < 0) {
+			dev_err(bus->dev, "Program params failed: %d", ret);
+			return ret;
+		}
 
-	/* Program params */
-	ret = sdw_program_params(bus);
-	if (ret < 0) {
-		dev_err(bus->dev, "Program params failed: %d", ret);
-		return ret;
 	}
 
+	stream->state = SDW_STREAM_DEPREPARED;
 	return do_bank_switch(stream);
 }
 
@@ -1521,13 +1585,12 @@  int sdw_deprepare_stream(struct sdw_stream_runtime *stream)
 		return -EINVAL;
 	}
 
-	mutex_lock(&stream->m_rt->bus->bus_lock);
-
+	sdw_acquire_bus_lock(stream);
 	ret = _sdw_deprepare_stream(stream);
 	if (ret < 0)
 		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;
 }
 EXPORT_SYMBOL(sdw_deprepare_stream);
diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index ccd8dcdf..03df709 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -768,7 +768,6 @@  struct sdw_stream_params {
  * @params: Stream parameters
  * @state: Current state of the stream
  * @type: Stream type PCM or PDM
- * @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
@@ -778,7 +777,6 @@  struct sdw_stream_runtime {
 	struct sdw_stream_params params;
 	enum sdw_stream_state state;
 	enum sdw_stream_type type;
-	struct sdw_master_runtime *m_rt;
 	struct list_head master_list;
 };