-
Notifications
You must be signed in to change notification settings - Fork 133
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
soundwire: add multi-lane support #4733
Conversation
92e8966
to
96b2055
Compare
Hmm, the CI test Failure on TGLU_RVP_SDW-ipc4 is because that 2 1308 amps are on the same sdw link, and 1 controller data port maps to 2 peripheral data ports. But I assume that controller data port and peripheral data port is 1:1 mapping. I need to think about how to handle this case. |
96b2055
to
d08d891
Compare
6a87659
to
8b8ec3b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good start @bardliao and @aiChaoSONG. I added a number of comments to make this PR more precise and clarify a number of technical opens.
drivers/soundwire/mipi_disco.c
Outdated
len = strlen(prop_val); | ||
/* The last character is enough to identify the connection */ | ||
prop->lane_maps[i] = prop_val[len - 1]; | ||
dev_err(dev, "[Chao] %c\n", prop->lane_maps[i]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove this dev_err or demote to dev_dbg.
include/linux/soundwire/sdw.h
Outdated
@@ -363,6 +365,7 @@ struct sdw_dpn_prop { | |||
* @p15_behave: Slave behavior when the Master attempts a read to the Port15 | |||
* alias | |||
* @lane_control_support: Slave supports lane control | |||
* @lane_maps: Lane mapping for the slave |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
presumably only valid if lane_control_support is true?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
presumably only valid if lane_control_support is true?
Yes, and changed the description to "Lane mapping for the slave, only valid if lane_control_support is set"
@@ -314,7 +314,7 @@ static int sdw_select_row_col(struct sdw_bus *bus, int clk_freq) | |||
frame_freq = clk_freq / frame_int; | |||
|
|||
if ((clk_freq - (frame_freq * SDW_FRAME_CTRL_BITS)) < | |||
bus->params.bandwidth) | |||
bandwidth) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't follow this patch at all.
First, we need to avoid that the frame size selected depends on the bandwidth required on each lane. It would be a disaster we had different results for each lane.
Second, this definition
include/linux/soundwire/sdw.h:#define SDW_FRAME_CTRL_BITS 48
is ONLY valid for lane0. There are no control bits on non-zero lanes, we can use the entire set of columns for audio data (or BPT/BRA).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me think more about it. My intent is to allocate lane according to available bandwidth on each lane. That's why I extend bandwidth to an array.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, but you could pick the lane which has the lowest bandwidth used, or conversely try to use the lane that's the most used. You have two dimensions to play with.
For corner cases, we will have to use max speed and max lanes. It's the intermediate cases that aren't so clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I guess I can use a new lane if current bandwidth is not enough in sdw_compute_bus_params(). I will try it.
drivers/soundwire/bus.h
Outdated
@@ -97,7 +97,7 @@ int sdw_find_col_index(int col); | |||
*/ | |||
struct sdw_port_runtime { | |||
int num; | |||
int ch_mask; | |||
u32 ch_mask; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
commit title prefix: s/soundwore/soundwire/
include/linux/soundwire/sdw.h
Outdated
*/ | ||
struct sdw_port_config { | ||
unsigned int num; | ||
unsigned int ch_mask; | ||
unsigned int lane_mask; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lane 0 can only be used by port 1
I don't think it's realistic to assume that some ports can only be used with non-zero lanes. By default I think the behavior is that all ports support Lane0. It'd be surprised if this wasn't the case, since that's the common denominator for all systems. It's possible that some non-zero lanes are not supported, e.g. a device could perfectly well support lane0..3 only.
The lane_maps[i] will be 0 by default and we can't tell if a lane is connected to lane 0 or not connected.
I couldn't follow the "lane is connected to lane0"....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lane 0 can only be used by port 1
That is just an example to describe codec driver may want to specify a port to use a specific lane.
For example, headphone playback uses port 0 and lane 0. In that case, codec driver can set port_config.num=0 and port_config.lane_mask=0x1;
I don't think it's realistic to assume that some ports can only be used with non-zero lanes.
No, I don't assume that some ports can only be used with non-zero lanes.
The issue is that if peripheral lane x is not connected, the mipi-sdw-lane-x-mapping property will not be set and prop->lane_maps[x] will be 0 which is the same as if peripheral lane x is connected to manager lane 0.
The lane_maps[i] will be 0 by default and we can't tell if a lane is connected to lane 0 or not connected.
I couldn't follow the "lane is connected to lane0"....
Sorry, it should be "a peripheral lane is connected to manager lane 0".
drivers/soundwire/stream.c
Outdated
for (i = 0; i < SDW_MAX_LANES; i++) | ||
available_bandwidth[i] = bus->params.max_dr_freq - bus->params.bandwidth[i]; | ||
|
||
/* find available lane */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
find first available lane?
I think the algorithm described tries to use a minimal number of lanes, instead of spreading the load on multiple lanes? It could be interesting if we try to change the frequency as well :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the algorithm described tries to use a minimal number of lanes, instead of spreading the load on multiple lanes? It could be interesting if we try to change the frequency as well
Good point. I was thinking to use as less lanes as possible. Let me try to spread the load on multiple lanes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know what's best in terms of power consumption.
There are two options:
- optimize the clock and reduce the number of lanes, i.e. only use additional lanes when the bandwidth is too low at max speed
- always use additional lanes to reduce the speed.
If the speed is fixed, it's not clear either. On one hand there's a need to enable a new line, but with the NRZI encoding if there's nothing to transmit then there are no transitions on the data line.
drivers/soundwire/stream.c
Outdated
int ret; | ||
int i; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"A controller should use the lane that connects to the peripheral"
That wording is controversial.
First we are talking about a Manager. Controllers don't have a concept of Lanes, they are made of one or more Managers. Each Manager can have one or more Lanes. Different level.
Also, you could perfectly well have multiple lanes connecting a Manager and a Peripheral. For example to transmit 8ch 192kHz 24 bits we would need 4 lanes, one for each stereo pair.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The commit is to map the lane that connects to a specific peripheral lane. For example, peripheral lane 1 connects to manager lane 2. We already know which peripheral lane is used and need to get the manager lane by slave_prop->lane_maps
.
aac2feb
to
c8fea39
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the late review @bardliao, see comments below.
drivers/soundwire/mipi_disco.c
Outdated
continue; | ||
len = strlen(prop_val); | ||
/* The last character is enough to identify the connection */ | ||
prop->lane_maps[i] = prop_val[len - 1] - '0'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment from @andy-shev still applies
https://github.com/thesofproject/linux/pull/4857/files/856d130a14d412c016565ba7a429df38eb07b7a4..618319957b33c5a7638becc6ef7d3aefdeb0b822#r1529112951
"
IIRC, the string can be empty, this code then has a potential out-of-boundary access.
"
|
||
/* Find a non-zero manager lane */ | ||
for (i = 1; i < SDW_MAX_LANES; i++) { | ||
if (!slave_prop->lane_maps[i]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you should first check that all peripherals connected to that manager and using that stream do support the same lanes. Otherwise you may pick a lane that works for one of the peripherals but not for another.
This is a bit paranoid but it's not that crazy: we could have a big all-in-one device along with a companion amplifier on the same link. The big device will likely support multi-lane, the companion amplifier probably not.
181bbf0
to
e4313db
Compare
2f65517
to
2b2853f
Compare
2b2853f
to
c542de2
Compare
drivers/soundwire/mipi_disco.c
Outdated
ret = kstrtou8(&prop_val[len - 1], 10, &lane); | ||
if (ret) | ||
return ret; | ||
if (in_range(lane, 1, 7)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1, SDW_MAX_LANES - 1 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ack
drivers/soundwire/mipi_disco.c
Outdated
@@ -382,6 +415,8 @@ int sdw_slave_read_prop(struct sdw_slave *slave) | |||
sdw_slave_read_dpn(slave, prop->sink_dpn_prop, nval, | |||
prop->sink_ports, "sink"); | |||
|
|||
sdw_slave_read_lane_mapping(slave); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we want to discard errors? The error codes are not handled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to return sdw_slave_read_lane_mapping(slave);
/* | ||
* Find an available manager lane for the first Peripheral | ||
* Testing the first Peripheral is enough because we can't use multi-lane | ||
* if we can't find any available lane for the first Peripheral |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't follow the logic.
If we can't find any available lanes for the first Peripheral, then we can't use multi-lane.
Buf if we want one available lane for the first Peripheral, we still need to check if other peripherals can use this lane.
Edit: and later you actually test all lanes so the comment is misleading. You start by testing the first peripheral and later verify that that this configuration works for all peripherals.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic here is to find an available lane from the first Peripheral, then check if the lane is available to all Peripherals.
The comment is to explain why I use s_rt = list_first_entry(&m_rt->slave_rt_list, struct sdw_slave_runtime, m_rt_node);
} | ||
} | ||
/* Set Manager lanes */ | ||
/* Assume there is only one Manager in multi-lane configurations. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't follow this comment, in the most agressive 192kHz 8ch bandwidth, we will have two links with two lanes each.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't follow this comment, in the most agressive 192kHz 8ch bandwidth, we will have two links with two lanes each.
Hmm, I can't test the 2 links case for now. But for that case, sdw_compute_bus_params() will be called twice for each Manager, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Edited the comments. Hope it will be more readable.
f388e84
to
137b0e8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good except for the first patch missing your sign-off @bardliao
The DisCo for SoundWire 2.0 added support for the 'mipi-sdw-lane-<n>-mapping' property. Co-developed-by: Chao Song <chao.song@linux.intel.com> Signed-off-by: Chao Song <chao.song@linux.intel.com> Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
To support multi-lane, we need to know how much bandwidth is used on each lane. And to use the lane that has enough bandwidth. Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
b425ded
to
a49a843
Compare
Updated to
|
a49a843
to
fba53ae
Compare
@plbossart @ranj063 @ujfalusi I just found an issue when I tested with dynamic sdw bus clock. We need to clear |
It will impact the multi-lane support. I need to think more about it. |
fba53ae
to
9a34250
Compare
@bardliao are you saying this PR is not ready for merging then? Also, what is the plan for testing multilane? I understand you have tested this locally but do we need to add tests to our CI also? |
9a34250
to
999288c
Compare
After 1 and half day's investigation, I decide to roll back to the reviewed/approved and full tested version. I.e. remove the set p_rt->ch_mask = 0 in deprepare change. I will continue debug the issue when enabling dynamic sdw clock change. But in the meantime, we can merge this if you agree. @ranj063 @plbossart @ujfalusi. And yes, we need to setup a device to test multilane in CI. We will need a codec that can support multilane like rt722, rt712-vb |
999288c
to
620edbe
Compare
change: remove duplicated trace. |
column_needed += params[i].hwidth; | ||
params[i].hwidth = (sel_col * | ||
params[i].payload_bw + params[i].full_bw - 1) / | ||
params[i].full_bw; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick, but I think it would be easier to grasp this way:
params[i].hwidth = (sel_col * params[i].payload_bw +
params[i].full_bw - 1) / params[i].full_bw;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
620edbe
to
72fc8f1
Compare
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>
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 <yung-chuan.liao@linux.intel.com>
Rt722 supports multi-lane and the driver doesn't call sdw_slave_read_prop() to get all properties. Add sdw_slave_read_lane_mapping() to get the required lane mapping property. Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
72fc8f1
to
1b15719
Compare
The first 2 commits are from #4704.
This PR adds SoundWire multi-lane support.