Skip to content

Commit

Permalink
soundwire: generic_bandwidth_allocation: add lane in sdw_group_params
Browse files Browse the repository at this point in the history
All active streams with the same parameters are grouped together and the
params are store in the sdw_group struct. We compute the required
bandwidth for each group. However, each lane has individual bandwidth.
Therefore, we should separate different lanes in different params groups.
Add lane variable to separate params groups.

Signed-off-by: Bard Liao <[email protected]>
  • Loading branch information
bardliao committed Oct 17, 2024
1 parent cd102c6 commit 00d0f43
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 30 deletions.
1 change: 1 addition & 0 deletions drivers/soundwire/bus.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ struct sdw_transport_data {
int hstop;
int block_offset;
int sub_block_offset;
unsigned int lane;
};

struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave,
Expand Down
117 changes: 87 additions & 30 deletions drivers/soundwire/generic_bandwidth_allocation.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

struct sdw_group_params {
unsigned int rate;
unsigned int lane;
int full_bw;
int payload_bw;
int hwidth;
Expand All @@ -27,6 +28,7 @@ struct sdw_group {
unsigned int count;
unsigned int max_size;
unsigned int *rates;
unsigned int *lanes;
};

void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt,
Expand All @@ -48,6 +50,9 @@ void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt,
slave_total_ch = 0;

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

ch = hweight32(p_rt->ch_mask);

dev_dbg(&s_rt->slave->dev, "%s p_rt->lane %d\n", __func__, p_rt->lane);
Expand Down Expand Up @@ -106,6 +111,8 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt,
t_data.hstart = hstart;

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

dev_dbg(bus->dev, "%s p_rt->lane %d\n", __func__, p_rt->lane);
sdw_fill_xport_params(&p_rt->transport_params, p_rt->num,
Expand Down Expand Up @@ -133,94 +140,130 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt,
(*port_bo) += bps * ch;
}

t_data.lane = params->lane;
sdw_compute_slave_ports(m_rt, &t_data);
}

static void _sdw_compute_port_params(struct sdw_bus *bus,
struct sdw_group_params *params, int count)
{
struct sdw_master_runtime *m_rt;
int hstop = bus->params.col - 1;
int port_bo, i;
int port_bo, i, l;
int hstop;

/* Run loop for all groups to compute transport parameters */
for (i = 0; i < count; i++) {
port_bo = 1;
for (l = 0; l < SDW_MAX_LANES; l++) {
if (l > 0 && !bus->lane_used_bandwidth[l])
continue;
/* reset hstop for each lane */
hstop = bus->params.col - 1;
for (i = 0; i < count; i++) {
if (params[i].lane != l)
continue;
port_bo = 1;

list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
sdw_compute_master_ports(m_rt, &params[i], &port_bo, hstop);
}
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
sdw_compute_master_ports(m_rt, &params[i], &port_bo, hstop);
}

hstop = hstop - params[i].hwidth;
hstop = hstop - params[i].hwidth;
}
}
}

static int sdw_compute_group_params(struct sdw_bus *bus,
struct sdw_group_params *params,
int *rates, int count)
int *rates, int *lanes, int count)
{
struct sdw_master_runtime *m_rt;
struct sdw_port_runtime *p_rt;
int sel_col = bus->params.col;
unsigned int rate, bps, ch;
int i, column_needed = 0;
int i, l, column_needed;

/* Calculate bandwidth per group */
for (i = 0; i < count; i++) {
params[i].rate = rates[i];
params[i].lane = lanes[i];
params[i].full_bw = bus->params.curr_dr_freq / params[i].rate;
}

list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
rate = m_rt->stream->params.rate;
bps = m_rt->stream->params.bps;
ch = m_rt->ch_count;
list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
rate = m_rt->stream->params.rate;
bps = m_rt->stream->params.bps;
ch = hweight32(p_rt->ch_mask);

for (i = 0; i < count; i++) {
if (rate == params[i].rate)
params[i].payload_bw += bps * ch;
for (i = 0; i < count; i++) {
if (rate == params[i].rate && p_rt->lane == params[i].lane)
params[i].payload_bw += bps * ch;
}
}
}

for (i = 0; i < count; i++) {
params[i].hwidth = (sel_col *
params[i].payload_bw + params[i].full_bw - 1) /
params[i].full_bw;
for (l = 0; l < SDW_MAX_LANES; l++) {
if (l > 0 && !bus->lane_used_bandwidth[l])
continue;
/* reset column_needed for each lane */
column_needed = 0;
for (i = 0; i < count; i++) {
if (params[i].lane != l)
continue;

params[i].hwidth = (sel_col * params[i].payload_bw +
params[i].full_bw - 1) / params[i].full_bw;

column_needed += params[i].hwidth;
column_needed += params[i].hwidth;
/* There is no control column for lane 1 and above */
if (column_needed > sel_col)
return -EINVAL;
/* Column 0 is control column on lane 0 */
if (params[i].lane == 0 && column_needed > sel_col - 1)
return -EINVAL;
}
}

if (column_needed > sel_col - 1)
return -EINVAL;

return 0;
}

static int sdw_add_element_group_count(struct sdw_group *group,
unsigned int rate)
unsigned int rate, unsigned int lane)
{
int num = group->count;
int i;

for (i = 0; i <= num; i++) {
if (rate == group->rates[i])
if (rate == group->rates[i] && lane == group->lanes[i])
break;

if (i != num)
continue;

if (group->count >= group->max_size) {
unsigned int *rates;
unsigned int *lanes;

group->max_size += 1;
rates = krealloc(group->rates,
(sizeof(int) * group->max_size),
GFP_KERNEL);
if (!rates)
return -ENOMEM;

group->rates = rates;

lanes = krealloc(group->lanes,
(sizeof(int) * group->max_size),
GFP_KERNEL);
if (!lanes)
return -ENOMEM;

group->lanes = lanes;
}

group->rates[group->count++] = rate;
group->rates[group->count] = rate;
group->lanes[group->count++] = lane;
}

return 0;
Expand All @@ -230,6 +273,7 @@ static int sdw_get_group_count(struct sdw_bus *bus,
struct sdw_group *group)
{
struct sdw_master_runtime *m_rt;
struct sdw_port_runtime *p_rt;
unsigned int rate;
int ret = 0;

Expand All @@ -239,6 +283,13 @@ static int sdw_get_group_count(struct sdw_bus *bus,
if (!group->rates)
return -ENOMEM;

group->lanes = kcalloc(group->max_size, sizeof(int), GFP_KERNEL);
if (!group->lanes) {
kfree(group->rates);
group->rates = NULL;
return -ENOMEM;
}

list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
if (m_rt->stream->state == SDW_STREAM_DEPREPARED)
continue;
Expand All @@ -248,11 +299,16 @@ static int sdw_get_group_count(struct sdw_bus *bus,
struct sdw_master_runtime,
bus_node)) {
group->rates[group->count++] = rate;

} else {
ret = sdw_add_element_group_count(group, rate);
}
/*
* Different ports could use different lane, add group element
* even if m_rt is the first entry
*/
list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
ret = sdw_add_element_group_count(group, rate, p_rt->lane);
if (ret < 0) {
kfree(group->rates);
kfree(group->lanes);
return ret;
}
}
Expand Down Expand Up @@ -287,7 +343,7 @@ static int sdw_compute_port_params(struct sdw_bus *bus)

/* Compute transport parameters for grouped streams */
ret = sdw_compute_group_params(bus, params,
&group.rates[0], group.count);
&group.rates[0], &group.lanes[0], group.count);
if (ret < 0)
goto free_params;

Expand All @@ -297,6 +353,7 @@ static int sdw_compute_port_params(struct sdw_bus *bus)
kfree(params);
out:
kfree(group.rates);
kfree(group.lanes);

return ret;
}
Expand Down

0 comments on commit 00d0f43

Please sign in to comment.