Re: [PATCH] i3c: master: dw-i3c-master: fix OD timing for first broadcast

"NG, TZE YEE" <[email protected]>
Newsgroups org.infradead.lists.linux-i3c
Message-ID <[email protected]>
On 12/6/2026 12:21 am, Frank Li wrote:
> [You don't often get email from [email protected]. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>
> On Wed, Jun 10, 2026 at 08:36:55AM +0000, [email protected] wrote:
>> Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
>>
>> New issues:
>> - [High] The newly introduced `dw_i3c_master_set_speed()` permanently overwrites hardware-specific AMD timings with generic timings.
>> - [High] The `od_hcnt` calculation for `I3C_OPEN_DRAIN_SLOW_SPEED` violates the `tHIGH_INIT` minimum requirement.
>>
>> Pre-existing issues:
>> - [High] The IRQ handler accesses hardware registers without Runtime PM protection.
>> - [High] Use-After-Free and invalid `queue_work()` due to improper teardown ordering in `dw_i3c_common_remove()`.
>> - [High] `dw_i3c_master_set_dev_nack_retry` modifies hardware registers without resuming the device via Runtime PM.
>> --
>>
>> commit bd5322e3d6d6cd3a6a8155f24cc89a12fe61be00
>> Author: Tze Yee Ng <[email protected]>
>>
>> i3c: master: dw-i3c-master: fix OD timing for first broadcast
>>
>> This commit implements the set_speed() callback to switch open-drain timing
>> for the first broadcast address to slow speed. It aims to fix I2C devices
>> with spike filters not being detected on mixed buses by dynamically
>> switching between slow and normal open drain speeds.
>>
>>> diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
>>> index a7593d6efac5a..6cf7071d3d06b 100644
>>> --- a/drivers/i3c/master/dw-i3c-master.c
>>> +++ b/drivers/i3c/master/dw-i3c-master.c
>> [ ... ]
>>> @@ -1484,6 +1485,57 @@ static irqreturn_t dw_i3c_master_irq_handler(int irq, void *dev_id)
>>>      return IRQ_HANDLED;
>>>   }
>>
>> [Severity: High]
>> This is a pre-existing issue, but does the IRQ handler access hardware
>> registers without Runtime PM protection?
>>
>> The interrupt handler directly reads hardware registers before checking the
>> device's PM active state:
>>
>> drivers/i3c/master/dw-i3c-master.c:dw_i3c_master_irq_handler() {
>>      ...
>>      status = readl(master->regs + INTR_STATUS);
>>      ...
>> }
>>
>> Since the driver does not synchronize IRQs in its runtime_suspend callback,
>> if an interrupt arrives right as the device enters runtime suspend (or if a
>> spurious interrupt occurs), will this raw register read access powered-down
>> hardware and cause a synchronous external abort?
>>
>>> +static int dw_i3c_master_set_speed(struct i3c_master_controller *m,
>>> +                              enum i3c_open_drain_speed speed)
>>> +{
>> [ ... ]
>>> +   switch (speed) {
>>> +   case I3C_OPEN_DRAIN_SLOW_SPEED:
>> [ ... ]
>>> +           core_period = DIV_ROUND_UP(1000000000, core_rate);
>>> +           lcnt = SCL_I3C_TIMING_LCNT(master->i3c_od_timing_normal);
>>> +           od_hcnt = max_t(u8, SCL_I3C_TIMING_CNT_MIN,
>>> +                           DIV_ROUND_UP(I3C_BUS_THIGH_INIT_OD_MIN_NS,
>>> +                                        core_period) - 1);
>>
>> [Severity: High]
>> Does this precision loss guarantee the resulting pulse is shorter than the
>> specification minimum for certain clock frequencies?
>>
>> If core_period is calculated by rounding up 1000000000 / core_rate, using
>> this overestimated integer in the division
>> DIV_ROUND_UP(I3C_BUS_THIGH_INIT_OD_MIN_NS, core_period) - 1 underestimates
>> the necessary cycle count.
>>
>> For example, at a 133.3 MHz core rate, the exact period is 7.5 ns but
>> core_period evaluates to 8 ns. The calculated cycle count evaluates to 25
>> cycles, which produces a 187.5 ns pulse.
>>
>> Does this violate the strict 200 ns minimum for tHIGH_INIT required by the
>> I3C specification?
>
> Is it true?
>
>>
>>> +           scl_timing = SCL_I3C_TIMING_HCNT(od_hcnt) |
>>> +                        SCL_I3C_TIMING_LCNT(lcnt);
>>> +           writel(scl_timing, master->regs + SCL_I3C_OD_TIMING);
>>> +           master->i3c_od_timing = scl_timing;
>>> +           break;
>>> +
>>> +   case I3C_OPEN_DRAIN_NORMAL_SPEED:
>>> +           writel(master->i3c_od_timing_normal,
>>> +                  master->regs + SCL_I3C_OD_TIMING);
>>
>> [Severity: High]
>> Does unconditionally restoring master->i3c_od_timing_normal here permanently
>> overwrite hardware-specific AMD timings with generic timings?
>>
>> If amd_configure_od_pp_quirk() is not updated to modify
>> master->i3c_od_timing_normal, restoring it after a broadcast destroys the
>> required AMD-specific quirk timings.
>>
>> Additionally, does dw_i3c_master_send_ccc_cmd() unconditionally overwrite
>> the OD timing with AMD normal timing right before sending a broadcast CCC,
>> bypassing the I3C_OPEN_DRAIN_SLOW_SPEED state expected by the I3C core?
>>
>>> +           master->i3c_od_timing = master->i3c_od_timing_normal;
>>> +           break;
>
> Please check this also?
>
> Frank
>
>> [ ... ]
>>> +static int dw_i3c_master_set_dev_nack_retry(struct i3c_master_controller *m,
>>> +                                       unsigned long dev_nack_retry_cnt)
>>> +{
>> [ ... ]
>>> +   for (i = 0; i < master->maxdevs; i++) {
>>> +           /* Skip free/empty slots */
>>> +           if (master->free_pos & BIT(i))
>>> +                   continue;
>>> +
>>> +           reg = readl(master->regs +
>>> +                           DEV_ADDR_TABLE_LOC(master->datstartaddr, i));
>>
>> [Severity: High]
>> This is a pre-existing issue, but does this function modify hardware
>> registers without resuming the device via Runtime PM?
>>
>> The sysfs attribute dev_nack_retry_count directly invokes
>> master->ops->set_dev_nack_retry(). Since sysfs callbacks can be triggered
>> from userspace at any time, executing this while the device is runtime
>> suspended will access powered-down hardware.
>>
>> On ARM SoCs, can this trigger a kernel panic (external abort) and allow
>> userspace to trivially crash the system?
>>
>> [ ... ]
>>
>> [Severity: High]
>> This is a pre-existing issue, but is there a use-after-free or invalid
>> queue_work() due to improper teardown ordering in dw_i3c_common_remove()?
>>
>> dw_i3c_common_remove() calls cancel_work_sync(&master->hj_work) before the
>> hardware interrupt is disabled and freed by devres:
>>
>> drivers/i3c/master/dw-i3c-master.c:dw_i3c_common_remove() {
>>      ...
>>      cancel_work_sync(&master->hj_work);
>>      i3c_master_unregister(&master->base);
>>      ...
>> }
>>
>> Because the IRQ remains active throughout the function and during early
>> devres teardown, can an incoming Hot Join interrupt trigger the IRQ handler,
>> which will call queue_work() to re-queue hj_work?
>>
>> Does this either cause queue_work() to execute on a destroyed workqueue or
>> result in a use-after-free when the workqueue subsequently processes the
>> work using the master object that has already been freed by devres?
>>
>> --
>> Sashiko AI review · https://sashiko.dev/#/patchset/ebddb8b62eae92de0a7eeda93cb18213c677ae96.1781077653.git.tze.yee.ng@altera.com?part=1
>>
>> --
>> linux-i3c mailing list
>> [email protected]
>> http://lists.infradead.org/mailman/listinfo/linux-i3c

Hi Frank,

Sashiko is correct that the initial core_period-based calculation could
undershoot the 200 ns tHIGH_INIT minimum at some core clock rates. I
checked the Zephyr DesignWare I3C driver, which uses a core_rate-based
calculation aligned with the DWC timing model. v2 will adopt the same
approach:

od_hcnt = DIV_ROUND_UP((u64)I3C_BUS_THIGH_INIT_OD_MIN_NS * core_rate,
                                       1000000000ULL) - 1;

still using the existing - 1 and SCL_I3C_TIMING_CNT_MIN convention from
dw_i3c_clk_cfg().

Reference:
https://github.com/zephyrproject-rtos/zephyr/commit/4d6673bc693920bdacf96d7cd3cfeb71d421e0ae
  (drivers/i3c/i3c_dw.c, dw_i3c_init_scl_timing())

For AMD specific timings,  I left existing AMD behavior unchanged in v1.
@Manikanta Guntupalli, for AMDI0015, should ->set_speed() use
AMD_I3C_OD_TIMING or generic timing as the normal OD baseline at
slow/normal speed? I can add AMD-specific handling in v2 once that is
clarified.

Thanks,
Tze Yee
-- 
linux-i3c mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-i3c
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.