All of lore.kernel.org
 help / color / mirror / Atom feed
From: Claudiu Beznea <claudiu.beznea@kernel.org>
To: sashiko-reviews@lists.linux.dev
Cc: linux-i3c@lists.infradead.org, Frank.Li@kernel.org,
	wsa+renesas@sang-engineering.com
Subject: Re: [PATCH v3 06/17] i3c: renesas: Perform Dynamic Address Assignment on resume
Date: Thu, 11 Jun 2026 21:30:01 +0300	[thread overview]
Message-ID: <0b01eebc-ba16-48ff-9b42-eec07dd372ef@kernel.org> (raw)
In-Reply-To: <20260608203648.CAC451F00893@smtp.kernel.org>



On 6/8/26 23:36, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
> 
> New issues:
> - [Critical] `renesas_i3c_group_devs_in_slots()` crashes on free slots and fails to update the `free_pos` bitmask.
> - [Critical] Typo in array swapping logic duplicates I2C devices and corrupts driver state.
> - [High] Call to undefined function `i3c_master_reattach_i3c_dev_locked` and logically invalid usage of the reattach API.
> - [High] Bypassing `i3c_master_add_i3c_dev_locked()` on resume ignores UID arbitration order, breaking device isolation.
> - [High] Redundant and unsafe dereference of `->dev->desc` when retrieving master data.
> - [High] Stale `olddevs` mask corrupts DATBAS registers for relocated I2C devices.
> 
> Pre-existing issues:
> - [High] Integer underflow in `GENMASK` calculation in `renesas_i3c_daa()` causes undefined behavior.
> --
> 
> commit 3b3dbe672a58e6c80b4a3c7aad942c61076f9cd2
> Author: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> 
> i3c: renesas: Perform Dynamic Address Assignment on resume
> 
> The patch modifies the Renesas I3C driver to run Dynamic Address Assignment
> (DAA) in the controller resume path to restore communication with I3C devices
> that lose power during suspend. It groups I2C and I3C devices during resume
> and re-runs ENTDAA for I3C devices.
> 
>> diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
>> --- a/drivers/i3c/master/renesas-i3c.c
>> +++ b/drivers/i3c/master/renesas-i3c.c
> 
> [ ... ]
> 
>> +static u8 renesas_i3c_group_devs_in_slots(struct renesas_i3c *i3c)
>> +{
>> +	struct renesas_i3c_i2c_dev_data *new_i2c_data, *new_i3c_data;
>> +	struct renesas_i3c_addr i2c_addr, i3c_addr;
>> +	struct i3c_dev_desc *i3c_dev;
>> +	struct i2c_dev_desc *i2c_dev;
>> +	u8 i2c_pos = 0;
> 
> [ ... ]
> 
>> +	for (u8 pos = 0; pos < i3c->maxdevs; pos++) {
>> +		if (i3c->free_pos & BIT(pos))
>> +			continue;
>> +
>> +		if (!i3c->addrs[pos].is_i2c)
>> +			continue;
>> +
>> +		if (pos == i2c_pos) {
>> +			i2c_pos++;
>> +			continue;
>> +		}
>> +
>> +		/*
>> +		 * Swap the I3C device on i2c_pos slot with the I2C dev
>> +		 * on pos slot.
>> +		 */
>> +		i3c_addr = i3c->addrs[i2c_pos];
>> +		i3c_dev = i3c_addr.i3c_dev;
>> +
>> +		i2c_addr = i3c->addrs[pos];
> 
> [Severity: Critical]
> If i2c_pos points to a free slot because earlier iterations skipped free
> slots without advancing i2c_pos, won't i3c_dev be NULL?

Since, as of my code inspection, the detach could happen only though a 
re-attachment procedure, this should lead to continuous slots allocation in 
free_pos. Thus, at the point this code is executed there should be no gaps in 
free_pos, unless I'm missing something.

> 
> Furthermore, does this function need to update i3c->free_pos when swapping
> slots to ensure the bitmask stays synchronized with the array layout?

Since, as of my code inspection, the detach could happen only though a 
re-attachment procedure, this should lead to continuous slots allocation in 
free_pos. Thus, at the point this code is executed there should be no gaps in 
free_pos, swapping positions in i3c->addrs[] wouldn't need updating free_pos.

> 
>> +		i2c_dev = i2c_addr.i2c_dev;
>> +
>> +		new_i2c_data = i3c_dev_get_master_data(i3c_dev->dev->desc);
> 
> [Severity: High]
> Is the ->dev->desc dereference here safe?

At the point this code is executed the devices should have already been
properly allocated.

> Since i3c_dev is already a struct i3c_dev_desc *, the dev field might
> be NULL if the device was only partially attached or memory allocation failed,
> causing a crash. i3c_dev_get_master_data() can accept i3c_dev directly.
> 
>> +		new_i3c_data = i2c_dev_get_master_data(i2c_dev);
>> +
>> +		i3c->addrs[i2c_pos] = i3c->addrs[pos];
>> +		i3c->addrs[i2c_pos].is_i2c = true;
>> +		i3c->addrs[i2c_pos].i2c_dev = i2c_dev;
>> +
>> +		i3c->addrs[pos] = i2c_addr;
> 
> [Severity: Critical]
> Since i2c_addr was initialized to i3c->addrs[pos] above, doesn't this
> assign the entry to itself?

Indeed, this looks wrong.

> 
> This would duplicate the I2C device into both slots, destroy the original I3C
> device's dynamic address state, and cross-assign private data structures.
> Should i3c_addr be used instead?
> 
>> +		i3c->addrs[pos].is_i2c = false;
>> +		i3c->addrs[pos].i3c_dev = i3c_dev;
>> +
>> +		new_i2c_data->index = i2c_pos++;
>> +		new_i3c_data->index = pos;
>> +
>> +		i2c_dev_set_master_data(i2c_dev, new_i2c_data);
>> +		i3c_dev_set_master_data(i3c_dev, new_i3c_data);
> 
> [ ... ]
> 
>>   static int renesas_i3c_daa(struct i3c_master_controller *m)
>>   {
>>   	struct renesas_i3c *i3c = to_renesas_i3c(m);
>>   	struct renesas_i3c_cmd *cmd;
>>   	u32 olddevs, newdevs;
>>   	u8 last_addr = 0, pos;
>> +	u8 first_i3c_pos = 0;
>>   	int ret;
> 
> [ ... ]
> 
>> @@ -655,16 +732,25 @@ static int renesas_i3c_daa(struct i3c_master_controller *m)
>>   	olddevs = ~(i3c->free_pos);
>>   	i3c->internal_state = I3C_INTERNAL_STATE_CONTROLLER_ENTDAA;
>>   
>> +	if (i3c->resuming)
>> +		first_i3c_pos = renesas_i3c_group_devs_in_slots(i3c);
> 
> [Severity: High]
> Since olddevs is computed from i3c->free_pos before calling
> renesas_i3c_group_devs_in_slots(), which shuffles the array but doesn't
> update i3c->free_pos, is it possible for olddevs to be stale?

As of the current code base, the i2c slots in free_pos should be continuous
and this should not happen.

> 
> If an I2C device is relocated into an empty slot where the stale mask is 0,
> the subsequent DAA loop might fall through and overwrite the I2C device's slot
> with a new I3C dynamic address.
> 
>> +
>>   	/* Setting DATBASn registers for target devices. */
>>   	for (pos = 0; pos < i3c->maxdevs; pos++) {
> 
> [ ... ]
> 
>> @@ -689,12 +780,38 @@ static int renesas_i3c_daa(struct i3c_master_controller *m)
>>   
>>   	renesas_i3c_wait_xfer(i3c, xfer);
>>   
>> -	newdevs = GENMASK(i3c->maxdevs - cmd->rx_count - 1, 0);
>> -	newdevs &= ~olddevs;
>> +	newdevs = GENMASK(i3c->maxdevs - cmd->rx_count - 1, first_i3c_pos);
> 
> [Severity: High]
> This is a pre-existing issue, but if cmd->rx_count equals i3c->maxdevs
> (e.g., when no devices are assigned), the first argument to GENMASK becomes
> -1.
> 
> Doesn't this invoke undefined behavior via an invalid shift count in the
> GENMASK macro, returning garbage values?
> 
>> +	/* Re-attach all the I3C devices on resume. */
>> +	if (!i3c->resuming)
>> +		newdevs &= ~olddevs;
>>   
>>   	for (pos = 0; pos < i3c->maxdevs; pos++) {
>> -		if (newdevs & BIT(pos))
>> -			i3c_master_add_i3c_dev_locked(m, i3c->addrs[pos]);
>> +		if (!(newdevs & BIT(pos)))
>> +			continue;
>> +
>> +		/*
>> +		 * If the bus was fully occupied before suspend, re-attach the
>> +		 * devices and update the addresses tracked by the subsystem.
>> +		 * Without this, i3c_master_add_i3c_dev_locked() returns errors
>> +		 * due to a lack of free slots (as reported by
>> +		 * renesas_i3c_get_free_pos()), causing the attachment to fail.
>> +		 *
>> +		 * Otherwise, follow the normal
>> +		 * i3c_master_add_i3c_dev_locked() path, which will re-attach the
>> +		 * devices, keep the subsystem state and driver addresses in sync,
>> +		 * and perform all the required internal bookkeeping.
>> +		 */
>> +		if (!i3c->free_pos && i3c->resuming) {
>> +			struct i3c_dev_desc *dev = i3c->addrs[pos].i3c_dev->dev->desc;
> 
> [Severity: High]
> Is it safe to dereference i3c_dev->dev->desc here?
> 
> If dev is NULL due to partial attachment or memory allocation failure prior
> to suspend, this will cause a kernel crash.

This should not happen since at this point the devices should be properly 
attached. Moreover, using directly i3c->addrs[pos].i3c_dev doesn't
work for the case here.

> 
>> +			u8 old_dyn_addr;
>> +
>> +			old_dyn_addr = dev->info.dyn_addr;
>> +			dev->info.dyn_addr = i3c->addrs[pos].addr;
>> +
>> +			i3c_master_reattach_i3c_dev_locked(dev, old_dyn_addr);
> 
> [Severity: High]
> Does i3c_master_reattach_i3c_dev_locked() exist in the kernel?
> 
> Calling a non-existent function will result in a build failure. Additionally,
> even if this was intended to be i3c_master_reattach_i3c_dev(), that API
> sends a SETNEWDA CCC to the device's old dynamic address. Since ENTDAA just
> assigned a new dynamic address via hardware, won't the device NACK the
> command?

The API is part of the series pointed out in the cover letter of this series.

> 
> Furthermore, by bypassing i3c_master_add_i3c_dev_locked(), does this ignore
> the PID arbitration order? ENTDAA assigns addresses based on PID arbitration,
> so the device that won arbitration might not correspond to the descriptor at
> i3c->addrs[pos], breaking device isolation.
> 
>> +		} else {
>> +			i3c_master_add_i3c_dev_locked(m, i3c->addrs[pos].addr);
>> +		}
>>   	}
>>   
>>   	return 0;
> 

-- 
Thank you,
Claudiu


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

  reply	other threads:[~2026-06-11 18:30 UTC|newest]

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-08 20:15 [PATCH v3 00/17] i3c: renesas: Suspend to RAM with power loss and runtime PM Claudiu Beznea
2026-06-08 20:15 ` Claudiu Beznea
2026-06-08 20:15 ` [PATCH v3 01/17] i3c: renesas: Check that the transfer is valid before accessing it Claudiu Beznea
2026-06-08 20:15   ` Claudiu Beznea
2026-06-08 20:31   ` sashiko-bot
2026-06-08 20:15 ` [PATCH v3 02/17] i3c: renesas: Restore STDBR and EXTBR registers on resume Claudiu Beznea
2026-06-08 20:15   ` Claudiu Beznea
2026-06-08 20:32   ` sashiko-bot
2026-06-08 20:15 ` [PATCH v3 03/17] i3c: renesas: Follow the reset deassert order used in probe Claudiu Beznea
2026-06-08 20:15   ` Claudiu Beznea
2026-06-08 20:15 ` [PATCH v3 04/17] i3c: renesas: Reconfigure the DATBAS register on re-attach Claudiu Beznea
2026-06-08 20:15   ` Claudiu Beznea
2026-06-08 20:28   ` sashiko-bot
2026-06-08 20:15 ` [PATCH v3 05/17] i3c: renesas: Reset the controller on resume Claudiu Beznea
2026-06-08 20:15   ` Claudiu Beznea
2026-06-08 20:29   ` sashiko-bot
2026-06-08 20:15 ` [PATCH v3 06/17] i3c: renesas: Perform Dynamic Address Assignment " Claudiu Beznea
2026-06-08 20:15   ` Claudiu Beznea
2026-06-08 20:36   ` sashiko-bot
2026-06-11 18:30     ` Claudiu Beznea [this message]
2026-06-08 20:15 ` [PATCH v3 07/17] i3c: renesas: Do not attach devices if xfer failed Claudiu Beznea
2026-06-08 20:15   ` Claudiu Beznea
2026-06-08 20:29   ` sashiko-bot
2026-06-08 20:15 ` [PATCH v3 08/17] i3c: renesas: Clean DATBAS register on detach Claudiu Beznea
2026-06-08 20:15   ` Claudiu Beznea
2026-06-08 20:38   ` sashiko-bot
2026-06-08 20:15 ` [PATCH v3 09/17] i3c: renesas: Use reset_control_bulk_{assert, deassert}() Claudiu Beznea
2026-06-08 20:15   ` Claudiu Beznea
2026-06-08 20:15 ` [PATCH v3 10/17] i3c: renesas: Return immediately if there is no transfer Claudiu Beznea
2026-06-08 20:15   ` Claudiu Beznea
2026-06-08 20:27   ` sashiko-bot
2026-06-08 20:15 ` [PATCH v3 11/17] i3c: renesas: Follow a unified pattern for transfer and command initialization Claudiu Beznea
2026-06-08 20:15   ` Claudiu Beznea
2026-06-08 20:30   ` sashiko-bot
2026-06-08 20:15 ` [PATCH v3 12/17] i3c: renesas: Drop the explicit memset() call Claudiu Beznea
2026-06-08 20:15   ` Claudiu Beznea
2026-06-08 20:15 ` [PATCH v3 13/17] i3c: renesas: Update HW registers after SW computations are done Claudiu Beznea
2026-06-08 20:15   ` Claudiu Beznea
2026-06-08 20:38   ` sashiko-bot
2026-06-08 20:15 ` [PATCH v3 14/17] i3c: renesas: Organize structures to avoid unnecessary padding Claudiu Beznea
2026-06-08 20:15   ` Claudiu Beznea
2026-06-08 20:15 ` [PATCH v3 15/17] i3c: renesas: Use the "dev_name:irq_name" format for the interrupt name Claudiu Beznea
2026-06-08 20:15   ` Claudiu Beznea
2026-06-08 20:41   ` sashiko-bot
2026-06-08 20:15 ` [PATCH v3 16/17] i3c: renesas: Drop unnecessary tab Claudiu Beznea
2026-06-08 20:15   ` Claudiu Beznea
2026-06-08 20:15 ` [PATCH v3 17/17] i3c: renesas: Add runtime PM support Claudiu Beznea
2026-06-08 20:15   ` Claudiu Beznea
2026-06-08 20:46   ` sashiko-bot
2026-06-11 18:51     ` Claudiu Beznea

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=0b01eebc-ba16-48ff-9b42-eec07dd372ef@kernel.org \
    --to=claudiu.beznea@kernel.org \
    --cc=Frank.Li@kernel.org \
    --cc=linux-i3c@lists.infradead.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=wsa+renesas@sang-engineering.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.