diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c index a3316efdf8ac27..f40a3af4351f6e 100644 --- a/drivers/soundwire/amd_manager.c +++ b/drivers/soundwire/amd_manager.c @@ -465,7 +465,8 @@ static u32 amd_sdw_read_ping_status(struct sdw_bus *bus) return slave_stat; } -static int amd_sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream) +static int amd_sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream, + bool prepare) { struct amd_sdw_manager *amd_manager = to_amd_sdw(bus); struct sdw_transport_data t_data = {0}; diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index 29d9fcef8c709b..d7a3de324b17d1 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -190,7 +190,8 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt, } static void _sdw_compute_port_params(struct sdw_bus *bus, - struct sdw_group_params *params, int count) + struct sdw_group_params *params, int count, + struct sdw_stream_runtime *stream, bool prepare) { struct sdw_master_runtime *m_rt; int port_bo, i, l; @@ -211,9 +212,12 @@ static void _sdw_compute_port_params(struct sdw_bus *bus, /* * Only runtimes with CONFIGURED, PREPARED, ENABLED, and DISABLED * states should be included in the bandwidth calculation. + * Include the current stream during prepare even if it is + * still in the DEPREPARED state. */ - if (m_rt->stream->state > SDW_STREAM_DISABLED || - m_rt->stream->state < SDW_STREAM_CONFIGURED) + if (!(prepare && m_rt->stream == stream) && + (m_rt->stream->state > SDW_STREAM_DISABLED || + m_rt->stream->state < SDW_STREAM_CONFIGURED)) continue; sdw_compute_master_ports(m_rt, ¶ms[i], &port_bo, hstop); } @@ -226,7 +230,7 @@ static void _sdw_compute_port_params(struct sdw_bus *bus, static int sdw_compute_group_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream, struct sdw_group_params *params, - struct sdw_group *group) + struct sdw_group *group, bool prepare) { struct sdw_master_runtime *m_rt; struct sdw_port_runtime *p_rt; @@ -242,20 +246,16 @@ static int sdw_compute_group_params(struct sdw_bus *bus, } list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { - if (m_rt->stream == stream) { - /* Only runtime during prepare should be added */ - if (stream->state != SDW_STREAM_CONFIGURED) - continue; - } else { - /* - * Include runtimes with running (ENABLED/PREPARED state) and - * paused (DISABLED state) streams - */ - if (m_rt->stream->state != SDW_STREAM_ENABLED && - m_rt->stream->state != SDW_STREAM_PREPARED && - m_rt->stream->state != SDW_STREAM_DISABLED) - continue; - } + /* + * Include the current stream during prepare even if it is still + * DEPREPARED. Otherwise, include only other running or paused streams. + */ + if (!(prepare && m_rt->stream == stream) && + (m_rt->stream == stream || + (m_rt->stream->state != SDW_STREAM_ENABLED && + m_rt->stream->state != SDW_STREAM_PREPARED && + m_rt->stream->state != SDW_STREAM_DISABLED))) + continue; list_for_each_entry(p_rt, &m_rt->port_list, port_node) { rate = m_rt->stream->params.rate; bps = m_rt->stream->params.bps; @@ -333,7 +333,8 @@ static int sdw_add_element_group_count(struct sdw_group *group, } static int sdw_get_group_count(struct sdw_bus *bus, - struct sdw_group *group) + struct sdw_group *group, + struct sdw_stream_runtime *stream, bool prepare) { struct sdw_master_runtime *m_rt; struct sdw_port_runtime *p_rt; @@ -354,7 +355,12 @@ static int sdw_get_group_count(struct sdw_bus *bus, } list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { - if (m_rt->stream->state == SDW_STREAM_DEPREPARED) + /* + * Include the current stream during prepare even if it is still + * in the DEPREPARED state. + */ + if (!(prepare && m_rt->stream == stream) && + m_rt->stream->state == SDW_STREAM_DEPREPARED) continue; rate = m_rt->stream->params.rate; @@ -385,14 +391,16 @@ static int sdw_get_group_count(struct sdw_bus *bus, * * @bus: SDW Bus instance * @stream: Soundwire stream + * @prepare: True when preparing, false when depreparing */ -static int sdw_compute_port_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream) +static int sdw_compute_port_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream, + bool prepare) { struct sdw_group_params *params = NULL; struct sdw_group group; int ret; - ret = sdw_get_group_count(bus, &group); + ret = sdw_get_group_count(bus, &group, stream, prepare); if (ret < 0) return ret; @@ -406,11 +414,11 @@ static int sdw_compute_port_params(struct sdw_bus *bus, struct sdw_stream_runtim } /* Compute transport parameters for grouped streams */ - ret = sdw_compute_group_params(bus, stream, params, &group); + ret = sdw_compute_group_params(bus, stream, params, &group, prepare); if (ret < 0) goto free_params; - _sdw_compute_port_params(bus, params, group.count); + _sdw_compute_port_params(bus, params, group.count, stream, prepare); free_params: kfree(params); @@ -538,8 +546,11 @@ static int get_manager_lane(struct sdw_bus *bus, struct sdw_master_runtime *m_rt * sdw_compute_bus_params: Compute bus parameters * * @bus: SDW Bus instance + * @stream: SoundWire stream being prepared or deprepared + * @prepare: True when preparing, false when depreparing */ -static int sdw_compute_bus_params(struct sdw_bus *bus) +static int sdw_compute_bus_params(struct sdw_bus *bus, + struct sdw_stream_runtime *stream, bool prepare) { struct sdw_master_prop *mstr_prop = &bus->prop; struct sdw_slave_prop *slave_prop; @@ -582,6 +593,14 @@ static int sdw_compute_bus_params(struct sdw_bus *bus) break; list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { + /* + * Select only the current stream's runtime. Check prepare + * to avoid computing m_lane during deprepare, when the + * stream's bandwidth reservation has already been released. + */ + if (m_rt->stream != stream || !prepare) + continue; + /* * Get the first s_rt that will be used to find the available lane that * can be used. No need to check all Peripherals because we can't use @@ -629,12 +648,26 @@ static int sdw_compute_bus_params(struct sdw_bus *bus) } } /* - * Set Manager lanes. Configure the last m_rt in bus->m_rt_list only since - * we don't want to touch other m_rts that are already working. + * Set Manager lanes for the stream being prepared without changing + * other runtimes that are already working. */ list_for_each_entry(m_p_rt, &m_rt->port_list, port_node) { m_p_rt->lane = m_lane; } + } else if (prepare) { + /* Clear stale lane assignments when preparing on lane 0. */ + list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { + if (m_rt->stream != stream) + continue; + + list_for_each_entry(m_p_rt, &m_rt->port_list, port_node) + m_p_rt->lane = 0; + + list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) + list_for_each_entry(s_p_rt, &s_rt->port_list, port_node) + s_p_rt->lane = 0; + break; + } } if (!mstr_prop->default_frame_rate || !mstr_prop->default_row) @@ -659,13 +692,15 @@ static int sdw_compute_bus_params(struct sdw_bus *bus) * * @bus: SDW Bus instance * @stream: Soundwire stream + * @prepare: True when preparing, false when depreparing */ -int sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream) +int sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream, + bool prepare) { int ret; /* Computes clock frequency, frame shape and frame frequency */ - ret = sdw_compute_bus_params(bus); + ret = sdw_compute_bus_params(bus, stream, prepare); if (ret < 0) return ret; @@ -675,7 +710,7 @@ int sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream) } /* Compute transport and port params */ - ret = sdw_compute_port_params(bus, stream); + ret = sdw_compute_port_params(bus, stream, prepare); if (ret < 0) { dev_err(bus->dev, "Compute transport params failed: %d\n", ret); return ret; diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 6e0c5fb10efad4..f9500d387c7b49 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -1215,7 +1215,8 @@ static const struct sdw_master_ops qcom_swrm_ops = { .pre_bank_switch = qcom_swrm_pre_bank_switch, }; -static int qcom_swrm_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream) +static int qcom_swrm_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream, + bool prepare) { struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); struct sdw_master_runtime *m_rt; diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index c158bf91e020f9..403e00b7327a8a 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -1513,7 +1513,7 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream, /* Compute params */ if (bus->compute_params) { - ret = bus->compute_params(bus, stream); + ret = bus->compute_params(bus, stream, true); if (ret < 0) { dev_err(bus->dev, "Compute params failed: %d\n", ret); @@ -1821,7 +1821,7 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream) /* Compute params */ if (bus->compute_params) { - ret = bus->compute_params(bus, stream); + ret = bus->compute_params(bus, stream, false); if (ret < 0) { dev_err(bus->dev, "Compute params failed: %d\n", ret); diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 326db122bbe6ea..b5fe0774332c56 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -1021,7 +1021,8 @@ struct sdw_stream_runtime { * @controller_id: system-unique controller ID. If set to -1, the bus @id will be used. * @link_id: Link id number, can be 0 to N, unique for each Controller * @id: bus system-wide unique id - * @compute_params: points to Bus resource management implementation + * @compute_params: points to Bus resource management implementation; the prepare + * argument is true when preparing a stream and false when depreparing it * @assigned: Bitmap for Slave device numbers. * Bit set implies used number, bit clear implies unused number. * @clk_stop_timeout: Clock stop timeout computed @@ -1058,7 +1059,8 @@ struct sdw_bus { int controller_id; unsigned int link_id; int id; - int (*compute_params)(struct sdw_bus *bus, struct sdw_stream_runtime *stream); + int (*compute_params)(struct sdw_bus *bus, struct sdw_stream_runtime *stream, + bool prepare); DECLARE_BITMAP(assigned, SDW_MAX_DEVICES); unsigned int clk_stop_timeout; u32 bank_switch_timeout; @@ -1074,7 +1076,8 @@ struct sdw_bus { struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name, enum sdw_stream_type type); void sdw_release_stream(struct sdw_stream_runtime *stream); -int sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream); +int sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream, + bool prepare); int sdw_stream_add_master(struct sdw_bus *bus, struct sdw_stream_config *stream_config,