Skip to content
Draft
97 changes: 80 additions & 17 deletions drivers/soundwire/generic_bandwidth_allocation.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ static void sdw_compute_dp0_slave_ports(struct sdw_master_runtime *m_rt)
list_for_each_entry(p_rt, &s_rt->port_list, port_node) {
sdw_fill_xport_params(&p_rt->transport_params, p_rt->num, false,
SDW_BLK_GRP_CNT_1, bus->params.col, 0, 0, 1,
bus->params.col - 1, SDW_BLK_PKG_PER_PORT, 0x0);
bus->bpt_hstop, SDW_BLK_PKG_PER_PORT, 0x0);

sdw_fill_port_params(&p_rt->port_params, p_rt->num, bus->params.col - 1,
sdw_fill_port_params(&p_rt->port_params, p_rt->num, bus->bpt_hstop,
SDW_PORT_FLOW_MODE_ISOCH, SDW_PORT_DATA_MODE_NORMAL);
}
}
Expand All @@ -113,9 +113,9 @@ static void sdw_compute_dp0_master_ports(struct sdw_master_runtime *m_rt)
list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
sdw_fill_xport_params(&p_rt->transport_params, p_rt->num, false,
SDW_BLK_GRP_CNT_1, bus->params.col, 0, 0, 1,
bus->params.col - 1, SDW_BLK_PKG_PER_PORT, 0x0);
bus->bpt_hstop, SDW_BLK_PKG_PER_PORT, 0x0);

sdw_fill_port_params(&p_rt->port_params, p_rt->num, bus->params.col - 1,
sdw_fill_port_params(&p_rt->port_params, p_rt->num, bus->bpt_hstop,
SDW_PORT_FLOW_MODE_ISOCH, SDW_PORT_DATA_MODE_NORMAL);
}
}
Expand Down Expand Up @@ -190,8 +190,8 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt,
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)
static void _sdw_compute_port_params(struct sdw_bus *bus, struct sdw_group_params *params,
int count, bool update_bpt_hstop)
{
struct sdw_master_runtime *m_rt;
int port_bo, i, l;
Expand All @@ -216,10 +216,23 @@ static void _sdw_compute_port_params(struct sdw_bus *bus,
if (m_rt->stream->state > SDW_STREAM_DISABLED ||
m_rt->stream->state < SDW_STREAM_CONFIGURED)
continue;
/* BPT stream is handled in sdw_compute_dp0_port_params */
if (m_rt->stream->type == SDW_STREAM_BPT)
continue;
sdw_compute_master_ports(m_rt, &params[i], &port_bo, hstop);
}

hstop = hstop - params[i].hwidth;
if (l == 0 && update_bpt_hstop && bus->bpt_hstop > hstop) {
/* Assume BPT stream uses lane 0 */
/*
* hstart = hstop - params->hwidth + 1.
* At this point after hstop = hstop - params[i].hwidth above,
* the hstart is equal to hstop + 1, and bus->bpt_hstop should
* be hstart - 1. so we can set bpt_hstop to hstop directly.
*/
bus->bpt_hstop = hstop;
}
}
}
}
Expand Down Expand Up @@ -359,6 +372,9 @@ static int sdw_get_group_count(struct sdw_bus *bus,
}

list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
if (m_rt->stream->type == SDW_STREAM_BPT)
continue;

if (m_rt->stream->state == SDW_STREAM_DEPREPARED)
continue;

Expand Down Expand Up @@ -415,7 +431,7 @@ static int sdw_compute_port_params(struct sdw_bus *bus, struct sdw_stream_runtim
if (ret < 0)
goto free_params;

_sdw_compute_port_params(bus, params, group.count);
_sdw_compute_port_params(bus, params, group.count, stream->type == SDW_STREAM_BPT);

free_params:
kfree(params);
Expand Down Expand Up @@ -555,6 +571,7 @@ static int sdw_compute_bus_params(struct sdw_bus *bus)
unsigned int curr_dr_freq = 0;
int i, l, clk_values, ret;
bool is_gear = false;
int available_col;
int m_lane = 0;
u32 *clk_buf;

Expand All @@ -570,23 +587,47 @@ static int sdw_compute_bus_params(struct sdw_bus *bus)
clk_buf = NULL;
}

/* If dynamic scaling is not supported, don't try higher freq */
if (!is_clock_scaling_supported(bus))
/*
* If dynamic scaling is not supported, don't try higher freq.
* Use the maximum freq to get maximum bandwidth and no need to try another freq
* if BPT stream is running
*/
if (!is_clock_scaling_supported(bus) || bus->bpt_stream_refcount)
clk_values = 1;

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

for (i = 0; i < clk_values; i++) {
int total_col;

if (!clk_buf)
curr_dr_freq = bus->params.max_dr_freq;
else
curr_dr_freq = (is_gear) ?
(bus->params.max_dr_freq >> clk_buf[i]) :
clk_buf[i] * SDW_DOUBLE_RATE_FACTOR;

if (curr_dr_freq * (mstr_prop->default_col - 1) >=
bus->params.bandwidth * mstr_prop->default_col)
/* Use maximum freq to get maximum bandwidth if BPT stream is running */
if (bus->bpt_stream_refcount)
curr_dr_freq = bus->params.max_dr_freq;

total_col = curr_dr_freq / mstr_prop->default_frame_rate / mstr_prop->default_row;

if (bus->bpt_stream_refcount)
available_col = total_col - bus->bpt_hstop - 1;
else
available_col = total_col;

/* If the bandwidth of the available columns is sufficient, then we are good */
if (curr_dr_freq * (available_col - 1) >=
bus->params.bandwidth * available_col)
break;

list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
/* BPT stream always uses lane 0 */
if (m_rt->stream->type == SDW_STREAM_BPT)
continue;
/*
* Get the first s_rt that will be used to find the available lane that
* can be used. No need to check all Peripherals because we can't use
Expand Down Expand Up @@ -642,9 +683,6 @@ static int sdw_compute_bus_params(struct sdw_bus *bus)
}
}

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

mstr_prop->default_col = curr_dr_freq / mstr_prop->default_frame_rate /
mstr_prop->default_row;

Expand All @@ -659,6 +697,10 @@ static int sdw_compute_bus_params(struct sdw_bus *bus)
return 0;
}

#define SDW_DEFAULT_COL 4
#define SDW_COL_RESERVED_FOR_AUDIO 2


/**
* sdw_compute_params: Compute bus, transport and port parameters
*
Expand All @@ -674,9 +716,20 @@ int sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream)
if (ret < 0)
return ret;

if (stream->type == SDW_STREAM_BPT) {
sdw_compute_dp0_port_params(bus);
return 0;
if (stream->type == SDW_STREAM_BPT && stream->state == SDW_STREAM_CONFIGURED) {
/*
* Set the initial bpt_hstop when the BPT stream is preparing and it will be
* updated in sdw_compute_port_params() below.
*/
bus->bpt_hstop = bus->params.col - 1;
/*
* Reserve 2 columns for future audio stream if the bus->params.col is greater
* than SDW_DEFAULT_COL (4) + reserved columns (2). And don't reserve columns
* for future use otherwise. This ensures that the BPT stream will not meet the
* bandwidth issue when there is no audio stream is open.
*/
if (bus->params.col >= (SDW_DEFAULT_COL + SDW_COL_RESERVED_FOR_AUDIO))
bus->bpt_hstop -= SDW_COL_RESERVED_FOR_AUDIO;
}

/* Compute transport and port params */
Expand All @@ -686,6 +739,16 @@ int sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream)
return ret;
}

if (stream->type == SDW_STREAM_BPT) {
/* If there is only one column left, just use normal write. */
if (bus->bpt_hstop < 1) {
dev_err(bus->dev, "%s: No bandwidth for BPT stream\n",
__func__);
return -EAGAIN;
}
sdw_compute_dp0_port_params(bus);
}

return 0;
}
EXPORT_SYMBOL(sdw_compute_params);
Expand Down
6 changes: 3 additions & 3 deletions drivers/soundwire/intel_ace2x.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *
command = (msg->flags & SDW_MSG_FLAG_WRITE) ? 0 : 1;

ret = sdw_cdns_bpt_find_bandwidth(command, cdns->bus.params.row,
cdns->bus.params.col,
cdns->bus.bpt_hstop + 1,
prop->default_frame_rate,
&tx_dma_bandwidth, &rx_dma_bandwidth);
if (ret < 0)
Expand All @@ -166,7 +166,7 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *
/* Add up pdi buffer size and frame numbers of each BPT sections */
for (i = 0; i < msg->sections; i++) {
ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row,
cdns->bus.params.col,
cdns->bus.bpt_hstop + 1,
msg->sec[i].len, SDW_BPT_MSG_MAX_BYTES,
&data_per_frame, &pdi0_buffer_size_,
&pdi1_buffer_size_, &num_frames_);
Expand All @@ -190,7 +190,7 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *
if (command) { /* read */
/* Get buffer size of a full frame */
ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row,
cdns->bus.params.col,
cdns->bus.bpt_hstop + 1,
data_per_frame, SDW_BPT_MSG_MAX_BYTES,
&data_per_frame, &pdi0_buf_size_pre_frame,
&pdi1_buf_size_pre_frame, &fake_num_frames);
Expand Down
28 changes: 14 additions & 14 deletions drivers/soundwire/stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -1237,18 +1237,10 @@ static struct sdw_master_runtime
struct sdw_master_runtime *m_rt, *walk_m_rt;
struct list_head *insert_after;

if (stream->type == SDW_STREAM_BPT) {
if (bus->stream_refcount > 0 || bus->bpt_stream_refcount > 0) {
dev_err(bus->dev, "%s: %d/%d audio/BPT stream already allocated\n",
__func__, bus->stream_refcount, bus->bpt_stream_refcount);
return ERR_PTR(-EBUSY);
}
} else {
if (bus->bpt_stream_refcount > 0) {
dev_err(bus->dev, "%s: BPT stream already allocated\n",
__func__);
return ERR_PTR(-EAGAIN);
}
if (stream->type == SDW_STREAM_BPT && bus->bpt_stream_refcount > 0) {
dev_err(bus->dev, "%s: BPT stream already allocated\n",
__func__);
return ERR_PTR(-EAGAIN);
}

m_rt = kzalloc(sizeof(*m_rt), GFP_KERNEL);
Expand Down Expand Up @@ -1484,8 +1476,11 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream,
if (update_params) {
/* Increment cumulative bus 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;
/* Don't count BPT stream bandwidth, it will use the remaining bandwidth */
if (m_rt->stream->type != SDW_STREAM_BPT) {
bus->params.bandwidth += m_rt->stream->params.rate *
m_rt->ch_count * m_rt->stream->params.bps;
}

/* Compute params */
if (bus->compute_params) {
Expand Down Expand Up @@ -1774,6 +1769,10 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)

multi_lane_bandwidth = 0;

/* Don't count BPT stream bandwidth, it will use the remaining bandwidth */
if (m_rt->stream->type == SDW_STREAM_BPT)
goto skip_bpt_stream;

list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
if (!p_rt->lane)
continue;
Expand All @@ -1789,6 +1788,7 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
bandwidth = m_rt->stream->params.rate * m_rt->ch_count * m_rt->stream->params.bps;
bus->params.bandwidth -= bandwidth - multi_lane_bandwidth;

skip_bpt_stream:
/* Compute params */
if (bus->compute_params) {
ret = bus->compute_params(bus, stream);
Expand Down
2 changes: 2 additions & 0 deletions include/linux/soundwire/sdw.h
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,7 @@ struct sdw_stream_runtime {
* @stream_refcount: number of streams currently using this bus
* @btp_stream_refcount: number of BTP streams currently using this bus (should
* be zero or one, multiple streams per link is not supported).
* @bpt_hstop: The hstop of the BPT stream.
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent terminology: comment uses 'hstop' (without underscore) while field name is 'bpt_hstop' (with underscore). Also, line 986 above uses 'BTP' while this and line 989 use 'BPT'. The terminology should be consistent throughout.

Suggested change
* @bpt_hstop: The hstop of the BPT stream.
* @bpt_hstop: The bpt_hstop of the BTP stream.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BPT is the right terminology. Also hstop is a terminology of SoundWire. I will leave it as it is.

* @bpt_stream: pointer stored to handle BTP streams.
* @ops: Master callback ops
* @port_ops: Master port callback ops
Expand Down Expand Up @@ -1025,6 +1026,7 @@ struct sdw_bus {
struct sdw_bus_params params;
int stream_refcount;
int bpt_stream_refcount;
int bpt_hstop;
struct sdw_stream_runtime *bpt_stream;
const struct sdw_master_ops *ops;
const struct sdw_master_port_ops *port_ops;
Expand Down
Loading