Skip to content

Commit

Permalink
soundwire: generic_bandwidth_allocation: select data lane
Browse files Browse the repository at this point in the history
If a peripheral supports multi-lane, we can use data lane x to extend
the bandwidth. The patch suggests to select data lane x where x > 0
when bandwidth is not enough on data lane 0.

Signed-off-by: Bard Liao <[email protected]>
  • Loading branch information
bardliao committed Sep 11, 2024
1 parent 9442548 commit 8c75b35
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 9 deletions.
118 changes: 112 additions & 6 deletions drivers/soundwire/generic_bandwidth_allocation.c
Original file line number Diff line number Diff line change
Expand Up @@ -343,19 +343,56 @@ static bool is_clock_scaling_supported(struct sdw_bus *bus)
return true;
}

/**
* check_all_peripherals_connected: Check if all peripherals can use the lane
*
* @m_rt: Manager runtime
* @lane: Lane number
*/
static bool check_all_peripherals_connected(struct sdw_master_runtime *m_rt, unsigned int lane)
{
struct sdw_slave_prop *slave_prop;
struct sdw_slave_runtime *s_rt;
int i;

list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
slave_prop = &s_rt->slave->prop;
for (i = 1; i < SDW_MAX_LANES; i++) {
if (slave_prop->lane_maps[i] == lane) {
dev_dbg(&s_rt->slave->dev,
"lane_maps[%d] is connected to %d\n",
i, slave_prop->lane_maps[i]);
break;
}
}
if (i == SDW_MAX_LANES) {
dev_dbg(&s_rt->slave->dev, "%d is not connected\n", lane);
return false;
}
}
return true;
}

/**
* sdw_compute_bus_params: Compute bus parameters
*
* @bus: SDW Bus instance
*/
static int sdw_compute_bus_params(struct sdw_bus *bus)
{
unsigned int curr_dr_freq = 0;
struct sdw_master_prop *mstr_prop = &bus->prop;
struct sdw_slave_prop *slave_prop;
struct sdw_port_runtime *m_p_rt;
struct sdw_port_runtime *s_p_rt;
struct sdw_master_runtime *m_rt;
int i, clk_values, ret;
unsigned int required_bandwidth;
struct sdw_slave_runtime *s_rt;
unsigned int curr_dr_freq = 0;
bool use_multi_lane = false;
int i, l, clk_values, ret;
bool is_gear = false;
u32 *clk_buf;
int m_lane;

if (mstr_prop->num_clk_gears) {
clk_values = mstr_prop->num_clk_gears;
Expand All @@ -382,10 +419,56 @@ static int sdw_compute_bus_params(struct sdw_bus *bus)
clk_buf[i] * SDW_DOUBLE_RATE_FACTOR;

if (curr_dr_freq * (mstr_prop->default_col - 1) <
bus->params.bandwidth * mstr_prop->default_col)
continue;

break;
bus->params.bandwidth * mstr_prop->default_col) {
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
/*
* Get the first s_rt that will be used to find the available lane that can be used.
*/
s_rt = list_first_entry(&m_rt->slave_rt_list, struct sdw_slave_runtime, m_rt_node);
slave_prop = &s_rt->slave->prop;

/*
* Find available manager lanes that connected to the first Peripheral.
* No need to check all Peripherals available lanes because we can't use
* multi-lane if we can't find any available lane for the first Peripheral.
*/
for (l = 1; l < SDW_MAX_LANES; l++) {
if (!slave_prop->lane_maps[l])
continue;

dev_dbg(bus->dev, "%s: trying lane %d\n", __func__, l);
required_bandwidth = 0;
list_for_each_entry(m_p_rt, &m_rt->port_list, port_node) {
required_bandwidth += m_rt->stream->params.rate *
hweight32(m_p_rt->ch_mask) *
m_rt->stream->params.bps;
}
if (required_bandwidth <= curr_dr_freq - bus->lane_used_bandwidth[l]) {
/* Check if m_lane is connected to all Peripherals */
if (!check_all_peripherals_connected(m_rt, slave_prop->lane_maps[l])) {
dev_dbg(bus->dev,
"some Peripherals are not connected to %d\n",
slave_prop->lane_maps[l]);
continue;
}
m_lane = slave_prop->lane_maps[l];
dev_dbg(&s_rt->slave->dev,
"M lane %d P lane %d can be used\n",
m_lane, l);
bus->lane_used_bandwidth[l] += required_bandwidth;
/*
* Use non-zero manager lane, subtract the lane 0
* bandwidth that is already calculated
*/
bus->params.bandwidth -= required_bandwidth;
use_multi_lane = true;
goto out;
}
}
}
} else {
break;
}

/*
* TODO: Check all the Slave(s) port(s) audio modes and find
Expand All @@ -399,6 +482,29 @@ static int sdw_compute_bus_params(struct sdw_bus *bus)
__func__, bus->params.bandwidth);
return -EINVAL;
}
out:
if (use_multi_lane) {
/* Set Peripheral lanes */
list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
slave_prop = &s_rt->slave->prop;
for (l = 1; l < SDW_MAX_LANES; l++) {
if (slave_prop->lane_maps[l] == m_lane) {
dev_dbg(&s_rt->slave->dev, "Set Peripheral lane = %d\n", l);
list_for_each_entry(s_p_rt, &s_rt->port_list, port_node) {
s_p_rt->lane = l;
}
break;
}
}
}
/*
* 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.
*/
list_for_each_entry(m_p_rt, &m_rt->port_list, port_node) {
m_p_rt->lane = m_lane;
}
}

/* Get the last m_rt that is recently added to the bus. */
m_rt = list_last_entry(&bus->m_rt_list, struct sdw_master_runtime, bus_node);
Expand Down
21 changes: 18 additions & 3 deletions drivers/soundwire/stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -1681,6 +1681,9 @@ EXPORT_SYMBOL(sdw_disable_stream);
static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
{
struct sdw_master_runtime *m_rt;
struct sdw_port_runtime *p_rt;
unsigned int multi_lane_bandwidth;
unsigned int bandwidth;
struct sdw_bus *bus;
int ret = 0;

Expand All @@ -1694,19 +1697,31 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
return ret;
}

multi_lane_bandwidth = 0;

list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
if (!p_rt->lane)
continue;

bandwidth = m_rt->stream->params.rate * hweight32(p_rt->ch_mask) *
m_rt->stream->params.bps;
multi_lane_bandwidth += bandwidth;
bus->lane_used_bandwidth[p_rt->lane] -= bandwidth;
}
/* TODO: Update this during Device-Device support */
bandwidth = m_rt->stream->params.rate * m_rt->ch_count * m_rt->stream->params.bps;

/* Compute params */
if (bus->compute_params) {
/* No need to compute params if bus->params.bandwidth is unchanged */
if (multi_lane_bandwidth != bandwidth && bus->compute_params) {
ret = bus->compute_params(bus);
if (ret < 0) {
dev_err(bus->dev, "Compute params failed: %d\n",
ret);
return ret;
}
}
bus->params.bandwidth -= m_rt->stream->params.rate *
m_rt->ch_count * m_rt->stream->params.bps;
bus->params.bandwidth -= bandwidth - multi_lane_bandwidth;

/* Program params */
ret = sdw_program_params(bus, false);
Expand Down

0 comments on commit 8c75b35

Please sign in to comment.