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
next prev parent reply other threads:[~2026-06-11 18:30 UTC|newest]
Thread overview: 32+ 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 ` [PATCH v3 01/17] i3c: renesas: Check that the transfer is valid before accessing it 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: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 ` [PATCH v3 04/17] i3c: renesas: Reconfigure the DATBAS register on re-attach 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:29 ` sashiko-bot
2026-06-08 20:15 ` [PATCH v3 06/17] i3c: renesas: Perform Dynamic Address Assignment " 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: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: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 ` [PATCH v3 10/17] i3c: renesas: Return immediately if there is no transfer 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: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 ` [PATCH v3 13/17] i3c: renesas: Update HW registers after SW computations are done 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 ` [PATCH v3 15/17] i3c: renesas: Use the "dev_name:irq_name" format for the interrupt name 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 ` [PATCH v3 17/17] i3c: renesas: Add runtime PM support 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox