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 10, 2024
1 parent f375cd8 commit ee77a17
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 13 deletions.
121 changes: 110 additions & 11 deletions drivers/soundwire/generic_bandwidth_allocation.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,20 +326,58 @@ static int sdw_select_row_col(struct sdw_bus *bus, int clk_freq)
return -EINVAL;
}

/**
* 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;
unsigned int required_bandwidth;
struct sdw_slave_runtime *s_rt;
unsigned int curr_dr_freq = 0;
bool use_multi_lane = false;
int frame_int, frame_freq;
int i, clk_values, ret;
int i, l, clk_values, ret;
bool is_gear = false;
int default_col;
u32 *clk_buf;
int m_lane;

if (mstr_prop->num_clk_gears) {
clk_values = mstr_prop->num_clk_gears;
Expand All @@ -353,6 +391,10 @@ static int sdw_compute_bus_params(struct sdw_bus *bus)
clk_buf = NULL;
}

m_rt = list_last_entry(&bus->m_rt_list, struct sdw_master_runtime, bus_node);
s_rt = list_first_entry(&m_rt->slave_rt_list, struct sdw_slave_runtime, m_rt_node);
slave_prop = &s_rt->slave->prop;

for (i = 0; i < clk_values; i++) {
if (!clk_buf)
curr_dr_freq = bus->params.max_dr_freq;
Expand All @@ -365,22 +407,78 @@ static int sdw_compute_bus_params(struct sdw_bus *bus)
frame_freq = curr_dr_freq / frame_int;

if ((curr_dr_freq - (frame_freq * SDW_FRAME_CTRL_BITS)) <
bus->params.bandwidth)
continue;
bus->params.bandwidth) {
/*
* 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.
*/

break;
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
* whether given clock rate is supported with glitchless
* transition.
*/
}

if (i == clk_values) {
dev_err(bus->dev, "%s: could not find clock value for bandwidth %d\n",
__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;
}
}

default_col = curr_dr_freq / m_rt->stream->params.rate / mstr_prop->default_row;
Expand All @@ -397,7 +495,8 @@ static int sdw_compute_bus_params(struct sdw_bus *bus)

ret = sdw_select_row_col(bus, curr_dr_freq);
if (ret < 0) {
dev_err(bus->dev, "%s: could not find frame configuration for bus dr_freq %d\n",
dev_err(bus->dev,
"%s: could not find frame configuration for bus dr_freq %d\n",
__func__, curr_dr_freq);
return -EINVAL;
}
Expand Down
18 changes: 16 additions & 2 deletions drivers/soundwire/stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -1676,6 +1676,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 @@ -1689,9 +1692,20 @@ 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 */
bus->params.bandwidth -= m_rt->stream->params.rate *
m_rt->ch_count * m_rt->stream->params.bps;
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 ee77a17

Please sign in to comment.