Skip to content

Commit 7a30292

Browse files
bardliaovinodkoul
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 <[email protected]> Reviewed-by: Ranjani Sridharan <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent 4a7927d commit 7a30292

File tree

2 files changed

+146
-7
lines changed

2 files changed

+146
-7
lines changed

drivers/soundwire/generic_bandwidth_allocation.c

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

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

352434
if (mstr_prop->num_clk_gears) {
@@ -373,11 +455,26 @@ static int sdw_compute_bus_params(struct sdw_bus *bus)
373455
(bus->params.max_dr_freq >> clk_buf[i]) :
374456
clk_buf[i] * SDW_DOUBLE_RATE_FACTOR;
375457

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

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

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

395518
if (!mstr_prop->default_frame_rate || !mstr_prop->default_row)
396519
return -EINVAL;

drivers/soundwire/stream.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1678,6 +1678,9 @@ EXPORT_SYMBOL(sdw_disable_stream);
16781678
static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
16791679
{
16801680
struct sdw_master_runtime *m_rt;
1681+
struct sdw_port_runtime *p_rt;
1682+
unsigned int multi_lane_bandwidth;
1683+
unsigned int bandwidth;
16811684
struct sdw_bus *bus;
16821685
int state = stream->state;
16831686
int ret = 0;
@@ -1699,9 +1702,22 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
16991702
return ret;
17001703
}
17011704

1705+
multi_lane_bandwidth = 0;
1706+
1707+
list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
1708+
if (!p_rt->lane)
1709+
continue;
1710+
1711+
bandwidth = m_rt->stream->params.rate * hweight32(p_rt->ch_mask) *
1712+
m_rt->stream->params.bps;
1713+
multi_lane_bandwidth += bandwidth;
1714+
bus->lane_used_bandwidth[p_rt->lane] -= bandwidth;
1715+
if (!bus->lane_used_bandwidth[p_rt->lane])
1716+
p_rt->lane = 0;
1717+
}
17021718
/* TODO: Update this during Device-Device support */
1703-
bus->params.bandwidth -= m_rt->stream->params.rate *
1704-
m_rt->ch_count * m_rt->stream->params.bps;
1719+
bandwidth = m_rt->stream->params.rate * m_rt->ch_count * m_rt->stream->params.bps;
1720+
bus->params.bandwidth -= bandwidth - multi_lane_bandwidth;
17051721

17061722
/* Compute params */
17071723
if (bus->compute_params) {

0 commit comments

Comments
 (0)