Re: [PATCH v5 2/3] i2c: nt72676: Add Novatek NT72676 I2C controller driver
[email protected] Tue, 04 Aug 2026 03:45:15 +0000
| Newsgroups | org.kernel.vger.linux-devicetree |
|---|---|
| Message-ID | <[email protected]> |
Thank you for your contribution! Sashiko AI review found 6 potential issue(= s) to consider: - [High] The driver unconditionally treats the first message of any 2-messa= ge transfer as a subaddress write, silently dropping it or misinterpreting = read operations. - [High] The interrupt handler returns IRQ_NONE without clearing the hardwa= re interrupt if current_msg is NULL, causing an interrupt storm. - [High] Lack of synchronization between the I2C transfer timeout path and = the interrupt handler leads to a use-after-free of the message buffer. - [High] The I2C controller hardware is disabled before unregistering the a= dapter, breaking concurrent ongoing transfers and client device removal. - [High] The ISR fails to handle the enabled CLK_STR_TIMEOUT interrupt, lea= ving it asserted and causing an interrupt storm. - [Medium] Hardware interrupts are left enabled if `i2c_add_adapter` fails = during probe. -- --- Patch [2]: [PATCH v5 2/3] i2c: nt72676: Add Novatek NT72676 I2C control= ler driver --- commit 2546eac52465a246476611598e7130d303e3cc7f Author: Ben Huang <[email protected]> i2c: nt72676: Add Novatek NT72676 I2C controller driver =20 This driver performs the fundamental read/write functions as an I2C controller and supports Standard-mode and Fast-mode. Default operation is Standard-mode. > diff --git a/drivers/i2c/busses/i2c-nt72676.c b/drivers/i2c/busses/i2c-nt= 72676.c > new file mode 100644 > index 0000000000000..48750b02537fb > --- /dev/null > +++ b/drivers/i2c/busses/i2c-nt72676.c [ ... ] > +static irqreturn_t nvt_i2c_isr(int irq, void *dev_id) > +{ > + struct nvt_i2c_bus *i2c =3D dev_id; > + struct i2c_msg *msg =3D i2c->current_msg; > + unsigned int status =3D nt72676_i2c_readl(i2c, I2C_REG_INTR); > + unsigned int clr =3D 0; > + int do_complete =3D 0; > + > + if (!(status & I2C_IRQ_FLAG) || !i2c->current_msg) > + return IRQ_NONE; [Severity: High] Could this early return cause an interrupt storm if a spurious interrupt fires, or if current_msg is NULL after a timeout? Since it returns IRQ_NONE without writing to the clear register, the level-triggered hardware interrupt might remain asserted indefinitely. > + > + if (status & I2C_IRQ_NACK) { > + i2c->error_code =3D -ENXIO; > + clr |=3D I2C_IRQ_NACK << 8; > + } else if (status & I2C_IRQ_RX_FULL) { [Severity: High] What happens if the hardware asserts I2C_IRQ_CLK_STR_TIMEOUT? The I2C_IRQ_ENABLE_SETTING macro enables this interrupt (bit 12), but it is omitted from this if/else chain. Does this mean it won't be added to the clr variable, leaving it asserted and causing an interrupt storm? > + if (i2c->remaining > 0) > + nvt_i2c_handle(i2c, msg, true); > + clr |=3D I2C_IRQ_RX_FULL << 8; > + } else if (status & I2C_IRQ_TX_EMPTY) { [ ... ] > +static int nvt_i2c_write(struct nvt_i2c_bus *i2c, struct i2c_msg *msg) > +{ [ ... ] > + ret =3D wait_for_completion_timeout(&i2c->msg_complete, i2c->adapter.ti= meout); > + if (ret =3D=3D 0) { > + i2c->error_code =3D -ETIMEDOUT; > + nvt_i2c_reset(i2c); > + } > + if (i2c->error_code) > + dev_err(i2c->dev, "[%s]: write failed (err:%d); SA[0x%X]\n", > + i2c->adapter.name, i2c->error_code, msg->addr); > + > + i2c->current_msg =3D NULL; [Severity: High] Can the timeout path race with the interrupt handler here? If the transfer times out, current_msg is set to NULL and the function returns, leading the caller to free the message buffer. If the ISR executes concurrently on anot= her CPU, could it access the freed buffer via current_msg before it gets fully nullified, causing a use-after-free? > + > + return i2c->error_code; > +} [ ... ] > +static int nvt_i2c_xfer(struct i2c_adapter *adap, > + struct i2c_msg msgs[], > + int num) > +{ > + struct nvt_i2c_bus *i2c =3D i2c_get_adapdata(adap); > + int ret =3D 0, i =3D 0; > + struct i2c_msg *msg =3D NULL; > + > + nvt_i2c_ctrl_init(i2c); > + > + if (num =3D=3D 2) { > + nvt_i2c_set_subaddr(i2c, &msgs[0]); > + msg =3D &msgs[1]; [Severity: High] Is it correct to unconditionally treat the first message of any 2-message transfer as a subaddress write? If a user-space caller sends a 2-message ar= ray where the first message is a read, has a length > 4, or targets a different device address, won't this silently drop or misinterpret the first message = and only execute the second one? > + > + if (msg->flags & I2C_M_RD) > + ret =3D nvt_i2c_read(i2c, msg); > + else > + ret =3D nvt_i2c_write(i2c, msg); > + } else { [ ... ] > +static int nvt_i2c_probe(struct platform_device *pdev) > +{ [ ... ] > + ret =3D nvt_i2c_init(i2c); > + if (ret) > + return ret; > + > + /* Setup I2C adapter */ > + i2c->adapter.owner =3D THIS_MODULE; > + i2c->adapter.algo =3D &nvt_i2c_algo; > + i2c->adapter.dev.of_node =3D pdev->dev.of_node; > + i2c->adapter.dev.parent =3D &pdev->dev; > + i2c->adapter.timeout =3D 3 * HZ; > + strscpy(i2c->adapter.name, dev_name(&pdev->dev), sizeof(i2c->adapter.na= me)); > + i2c_set_adapdata(&i2c->adapter, i2c); > + > + ret =3D i2c_add_adapter(&i2c->adapter); > + if (ret) > + return dev_err_probe(&pdev->dev, ret, "Failed to add adapter\n"); [Severity: Medium] Does this error path need to disable the hardware interrupts that were enabled earlier in nvt_i2c_init()? Returning directly might leave interrupts enabled on a shared IRQ line. > + > + platform_set_drvdata(pdev, i2c); > + > + return 0; > +} > + > +static void nvt_i2c_remove(struct platform_device *pdev) > +{ > + struct nvt_i2c_bus *i2c =3D platform_get_drvdata(pdev); > + > + nt72676_i2c_writel(I2C_IRQ_DISABLE_SETTING, i2c, I2C_REG_INTR); > + nt72676_i2c_writel(nt72676_i2c_readl(i2c, I2C_REG_CTRL) & ~I2C_ENABLE, > + i2c, I2C_REG_CTRL); > + i2c_del_adapter(&i2c->adapter); [Severity: High] Should the adapter be deleted before disabling the I2C controller hardware? Disabling interrupts and clocks first could break concurrent ongoing transfers or client device removal operations that happen during i2c_del_adapter(). > +} --=20 Sashiko AI review =C2=B7 https://sashiko.dev/#/patchset/20260804033419.6938= [email protected]?part=3D2