Skip to content

Commit 315a806

Browse files
bardliaoranj063
authored andcommitted
soundwire: generic_bandwidth_allocation: select data lane
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 <yung-chuan.liao@linux.intel.com>
1 parent f1ce288 commit 315a806

2 files changed

Lines changed: 146 additions & 7 deletions

File tree

drivers/soundwire/generic_bandwidth_allocation.c

Lines changed: 128 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -338,17 +338,99 @@ static bool is_clock_scaling_supported(struct sdw_bus *bus)
338338
return true;
339339
}
340340

341+
/**
342+
* is_lane_connected_to_all_peripherals: Check if the given manager lane connects to all peripherals
343+
* So that all peripherals can use the manager lane.
344+
*
345+
* @m_rt: Manager runtime
346+
* @lane: Lane number
347+
*/
348+
static bool is_lane_connected_to_all_peripherals(struct sdw_master_runtime *m_rt, unsigned int lane)
349+
{
350+
struct sdw_slave_prop *slave_prop;
351+
struct sdw_slave_runtime *s_rt;
352+
int i;
353+
354+
list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
355+
slave_prop = &s_rt->slave->prop;
356+
for (i = 1; i < SDW_MAX_LANES; i++) {
357+
if (slave_prop->lane_maps[i] == lane) {
358+
dev_dbg(&s_rt->slave->dev,
359+
"M lane %d is connected to P lane %d\n",
360+
lane, i);
361+
break;
362+
}
363+
}
364+
if (i == SDW_MAX_LANES) {
365+
dev_dbg(&s_rt->slave->dev, "M lane %d is not connected\n", lane);
366+
return false;
367+
}
368+
}
369+
return true;
370+
}
371+
372+
static int get_manager_lane(struct sdw_bus *bus, struct sdw_master_runtime *m_rt,
373+
struct sdw_slave_runtime *s_rt, unsigned int curr_dr_freq)
374+
{
375+
struct sdw_slave_prop *slave_prop = &s_rt->slave->prop;
376+
struct sdw_port_runtime *m_p_rt;
377+
unsigned int required_bandwidth;
378+
int m_lane;
379+
int l;
380+
381+
for (l = 1; l < SDW_MAX_LANES; l++) {
382+
if (!slave_prop->lane_maps[l])
383+
continue;
384+
385+
required_bandwidth = 0;
386+
list_for_each_entry(m_p_rt, &m_rt->port_list, port_node) {
387+
required_bandwidth += m_rt->stream->params.rate *
388+
hweight32(m_p_rt->ch_mask) *
389+
m_rt->stream->params.bps;
390+
}
391+
if (required_bandwidth <=
392+
curr_dr_freq - bus->lane_used_bandwidth[l]) {
393+
/* Check if m_lane is connected to all Peripherals */
394+
if (!is_lane_connected_to_all_peripherals(m_rt,
395+
slave_prop->lane_maps[l])) {
396+
dev_dbg(bus->dev,
397+
"Not all Peripherals are connected to M lane %d\n",
398+
slave_prop->lane_maps[l]);
399+
continue;
400+
}
401+
m_lane = slave_prop->lane_maps[l];
402+
dev_dbg(&s_rt->slave->dev, "M lane %d is used\n", m_lane);
403+
bus->lane_used_bandwidth[l] += required_bandwidth;
404+
/*
405+
* Use non-zero manager lane, subtract the lane 0
406+
* bandwidth that is already calculated
407+
*/
408+
bus->params.bandwidth -= required_bandwidth;
409+
return m_lane;
410+
}
411+
}
412+
413+
/* No available multi lane found, only lane 0 can be used */
414+
return 0;
415+
}
416+
341417
/**
342418
* sdw_compute_bus_params: Compute bus parameters
343419
*
344420
* @bus: SDW Bus instance
345421
*/
346422
static int sdw_compute_bus_params(struct sdw_bus *bus)
347423
{
348-
unsigned int curr_dr_freq = 0;
349424
struct sdw_master_prop *mstr_prop = &bus->prop;
350-
int i, clk_values, ret;
425+
struct sdw_slave_prop *slave_prop;
426+
struct sdw_port_runtime *m_p_rt;
427+
struct sdw_port_runtime *s_p_rt;
428+
struct sdw_master_runtime *m_rt;
429+
struct sdw_slave_runtime *s_rt;
430+
unsigned int curr_dr_freq = 0;
431+
int i, l, clk_values, ret;
351432
bool is_gear = false;
433+
int m_lane = 0;
352434
u32 *clk_buf;
353435

354436
if (mstr_prop->num_clk_gears) {
@@ -375,11 +457,26 @@ static int sdw_compute_bus_params(struct sdw_bus *bus)
375457
(bus->params.max_dr_freq >> clk_buf[i]) :
376458
clk_buf[i] * SDW_DOUBLE_RATE_FACTOR;
377459

378-
if (curr_dr_freq * (mstr_prop->default_col - 1) <
460+
if (curr_dr_freq * (mstr_prop->default_col - 1) >=
379461
bus->params.bandwidth * mstr_prop->default_col)
380-
continue;
462+
break;
463+
464+
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
465+
/*
466+
* Get the first s_rt that will be used to find the available lane that
467+
* can be used. No need to check all Peripherals because we can't use
468+
* multi-lane if we can't find any available lane for the first Peripheral.
469+
*/
470+
s_rt = list_first_entry(&m_rt->slave_rt_list,
471+
struct sdw_slave_runtime, m_rt_node);
381472

382-
break;
473+
/*
474+
* Find the available Manager lane that connected to the first Peripheral.
475+
*/
476+
m_lane = get_manager_lane(bus, m_rt, s_rt, curr_dr_freq);
477+
if (m_lane > 0)
478+
goto out;
479+
}
383480

384481
/*
385482
* TODO: Check all the Slave(s) port(s) audio modes and find
@@ -393,6 +490,32 @@ static int sdw_compute_bus_params(struct sdw_bus *bus)
393490
__func__, bus->params.bandwidth);
394491
return -EINVAL;
395492
}
493+
out:
494+
/* multilane can be used */
495+
if (m_lane > 0) {
496+
/* Set Peripheral lanes */
497+
list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
498+
slave_prop = &s_rt->slave->prop;
499+
for (l = 1; l < SDW_MAX_LANES; l++) {
500+
if (slave_prop->lane_maps[l] == m_lane) {
501+
list_for_each_entry(s_p_rt, &s_rt->port_list, port_node) {
502+
s_p_rt->lane = l;
503+
dev_dbg(&s_rt->slave->dev,
504+
"Set P lane %d for port %d\n",
505+
l, s_p_rt->num);
506+
}
507+
break;
508+
}
509+
}
510+
}
511+
/*
512+
* Set Manager lanes. Configure the last m_rt in bus->m_rt_list only since
513+
* we don't want to touch other m_rts that are already working.
514+
*/
515+
list_for_each_entry(m_p_rt, &m_rt->port_list, port_node) {
516+
m_p_rt->lane = m_lane;
517+
}
518+
}
396519

397520
if (!mstr_prop->default_frame_rate || !mstr_prop->default_row)
398521
return -EINVAL;

drivers/soundwire/stream.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,6 +1684,9 @@ EXPORT_SYMBOL(sdw_disable_stream);
16841684
static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
16851685
{
16861686
struct sdw_master_runtime *m_rt;
1687+
struct sdw_port_runtime *p_rt;
1688+
unsigned int multi_lane_bandwidth;
1689+
unsigned int bandwidth;
16871690
struct sdw_bus *bus;
16881691
int state = stream->state;
16891692
int ret = 0;
@@ -1705,9 +1708,22 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
17051708
return ret;
17061709
}
17071710

1711+
multi_lane_bandwidth = 0;
1712+
1713+
list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
1714+
if (!p_rt->lane)
1715+
continue;
1716+
1717+
bandwidth = m_rt->stream->params.rate * hweight32(p_rt->ch_mask) *
1718+
m_rt->stream->params.bps;
1719+
multi_lane_bandwidth += bandwidth;
1720+
bus->lane_used_bandwidth[p_rt->lane] -= bandwidth;
1721+
if (!bus->lane_used_bandwidth[p_rt->lane])
1722+
p_rt->lane = 0;
1723+
}
17081724
/* TODO: Update this during Device-Device support */
1709-
bus->params.bandwidth -= m_rt->stream->params.rate *
1710-
m_rt->ch_count * m_rt->stream->params.bps;
1725+
bandwidth = m_rt->stream->params.rate * m_rt->ch_count * m_rt->stream->params.bps;
1726+
bus->params.bandwidth -= bandwidth - multi_lane_bandwidth;
17111727

17121728
/* Compute params */
17131729
if (bus->compute_params) {

0 commit comments

Comments
 (0)