All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Claudiu Beznea" <claudiu.beznea@kernel.org>
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: Mon, 08 Jun 2026 20:36:48 +0000	[thread overview]
Message-ID: <20260608203648.CAC451F00893@smtp.kernel.org> (raw)
In-Reply-To: <20260608201543.804902-7-claudiu.beznea@kernel.org>

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?

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

> +		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?

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?

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?

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.

> +			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?

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;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260608201543.804902-1-claudiu.beznea@kernel.org?part=6

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

  reply	other threads:[~2026-06-08 20:36 UTC|newest]

Thread overview: 48+ 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 [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

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=20260608203648.CAC451F00893@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=Frank.Li@kernel.org \
    --cc=claudiu.beznea@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.