[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <b6c75eee-761d-44c8-8413-2a5b34ee2f98@linux.intel.com>
Date: Tue, 3 Sep 2024 15:34:39 +0800
From: "Liao, Bard" <yung-chuan.liao@...ux.intel.com>
To: Vinod Koul <vkoul@...nel.org>,
Pierre-Louis Bossart <pierre-louis.bossart@...ux.intel.com>
Cc: Krzysztof Kozlowski <krzysztof.kozlowski@...aro.org>,
Sanyog Kale <sanyog.r.kale@...el.com>, Shreyas NC <shreyas.nc@...el.com>,
alsa-devel@...a-project.org, linux-kernel@...r.kernel.org,
stable@...r.kernel.org, bard.liao@...el.com
Subject: Re: [PATCH] soundwire: stream: fix programming slave ports for
non-continous port maps
On 7/31/2024 2:56 PM, Vinod Koul wrote:
> On 29-07-24, 16:25, Pierre-Louis Bossart wrote:
>>
>> On 7/29/24 16:01, Krzysztof Kozlowski wrote:
>>> Two bitmasks in 'struct sdw_slave_prop' - 'source_ports' and
>>> 'sink_ports' - define which ports to program in
>>> sdw_program_slave_port_params(). The masks are used to get the
>>> appropriate data port properties ('struct sdw_get_slave_dpn_prop') from
>>> an array.
>>>
>>> Bitmasks can be non-continuous or can start from index different than 0,
>>> thus when looking for matching port property for given port, we must
>>> iterate over mask bits, not from 0 up to number of ports.
>>>
>>> This fixes allocation and programming slave ports, when a source or sink
>>> masks start from further index.
>>>
>>> Fixes: f8101c74aa54 ("soundwire: Add Master and Slave port programming")
>>> Cc: <stable@...r.kernel.org>
>>> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@...aro.org>
>> This is a valid change to optimize how the port are accessed.
>>
>> But the commit message is not completely clear, the allocation in
>> mipi_disco.c is not modified and I don't think there's anything that
>> would crash. If there are non-contiguous ports, we will still allocate
>> space that will not be initialized/used.
>>
>> /* Allocate memory for set bits in port lists */
>> nval = hweight32(prop->source_ports);
>> prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval,
>> sizeof(*prop->src_dpn_prop),
>> GFP_KERNEL);
>> if (!prop->src_dpn_prop)
>> return -ENOMEM;
>>
>> /* Read dpn properties for source port(s) */
>> sdw_slave_read_dpn(slave, prop->src_dpn_prop, nval,
>> prop->source_ports, "source");
>>
>> IOW, this is a valid change, but it's an optimization, not a fix in the
>> usual sense of 'kernel oops otherwise'.
>>
>> Am I missing something?
>>
>> BTW, the notion of DPn is that n > 0. DP0 is a special case with
>> different properties, BIT(0) cannot be set for either of the sink/source
>> port bitmask.
> The fix seems right to me, we cannot have assumption that ports are
> contagious, so we need to iterate over all valid ports and not to N
> ports which code does now!
Sorry to jump in after the commit was applied. But, it breaks my test.
The point is that dpn_prop[i].num where the i is the array index, and
num is the port number. So, `for (i = 0; i < num_ports; i++)` will iterate
over all valid ports.
We can see in below drivers/soundwire/mipi_disco.c
nval = hweight32(prop->sink_ports);
prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval,
sizeof(*prop->sink_dpn_prop),
GFP_KERNEL);
And sdw_slave_read_dpn() set data port properties one by one.
`for_each_set_bit(i, &mask, 32)` will break the system when port numbers
are not continuous. For example, a codec has source port number = 1 and 3,
then dpn_prop[0].num = 1 and dpn_prop[1].num = 3. And we need to go
throuth dpn_prop[0] and dpn_prop[1] instead of dpn_prop[1] and dpn_prop[3].
>
>>
>>> ---
>>> drivers/soundwire/stream.c | 8 ++++----
>>> 1 file changed, 4 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
>>> index 7aa4900dcf31..f275143d7b18 100644
>>> --- a/drivers/soundwire/stream.c
>>> +++ b/drivers/soundwire/stream.c
>>> @@ -1291,18 +1291,18 @@ struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave,
>>> unsigned int port_num)
>>> {
>>> struct sdw_dpn_prop *dpn_prop;
>>> - u8 num_ports;
>>> + unsigned long mask;
>>> int i;
>>>
>>> if (direction == SDW_DATA_DIR_TX) {
>>> - num_ports = hweight32(slave->prop.source_ports);
>>> + mask = slave->prop.source_ports;
>>> dpn_prop = slave->prop.src_dpn_prop;
>>> } else {
>>> - num_ports = hweight32(slave->prop.sink_ports);
>>> + mask = slave->prop.sink_ports;
>>> dpn_prop = slave->prop.sink_dpn_prop;
>>> }
>>>
>>> - for (i = 0; i < num_ports; i++) {
>>> + for_each_set_bit(i, &mask, 32) {
>>> if (dpn_prop[i].num == port_num)
>>> return &dpn_prop[i];
>>> }
Powered by blists - more mailing lists