From: sashiko-bot@kernel.org
To: "Viken Dadhaniya" <viken.dadhaniya@oss.qualcomm.com>
Cc: conor+dt@kernel.org, devicetree@vger.kernel.org, robh@kernel.org
Subject: Re: [PATCH v3 2/2] i2c: qcom-target: Add driver for Qualcomm I2C target controller
Date: Thu, 13 Aug 2026 16:05:11 +0000 [thread overview]
Message-ID: <20260813160512.393D51F00A3A@smtp.kernel.org> (raw)
In-Reply-To: <20260813-i2c-qcom-slave-v3-2-1d3742e2ad47@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] Calling usleep_range() from the hardirq handler will cause a 'scheduling while atomic' kernel panic.
- [High] Risk of synchronous external abort due to clocks being disabled before the IRQ is freed in the remove path.
- [High] The driver calls sleeping functions (clock APIs and icc_set_bw) from a `noirq` power management context.
- [High] Premature clock stretch release during a Repeated Start condition.
- [Medium] Missing cleanup of clocks and interconnect bandwidth vote on probe error paths.
--
--- Patch [2]: [PATCH v3 2/2] i2c: qcom-target: Add driver for Qualcomm I2C target controller ---
commit 1029beb1e1d38e9f7984ad5331b9a78f18027431
Author: Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com>
Subject: i2c: qcom-target: Add driver for Qualcomm I2C target controller
QDU1000 and related Qualcomm SoCs include a dedicated I2C target
controller that operates exclusively in target mode. This patch registers
the controller with the Linux I2C slave framework and handles IRQ events,
clocks, and power management.
> diff --git a/drivers/i2c/busses/i2c-qcom-target.c b/drivers/i2c/busses/i2c-qcom-target.c
> new file mode 100644
> index 0000000000000..277ea944eedb6
> --- /dev/null
> +++ b/drivers/i2c/busses/i2c-qcom-target.c
[ ... ]
> @@ -187,15 +187,15 @@ static int qcom_i2c_target_drain_rx_fifo(struct qcom_i2c_target *target)
> static void qcom_i2c_target_hw_reset(struct qcom_i2c_target *target)
> {
> /* Clear error bits before SW_RESET; the reset may not be instantaneous */
> writel(BIT(ERR_CONDITION) | BIT(CLOCK_LOW_TIMEOUT),
> target->base + I2C_S_IRQ_CLR);
> writel(SW_RESET, target->base + I2C_S_SW_RESET_REG);
> /*
> * I2C_S_SW_RESET_REG is write-only so completion cannot be polled.
> * Use a conservative delay to allow the reset to finish before
> * reconfiguring the controller.
> */
> usleep_range(10, 20);
[Severity: High]
Does calling usleep_range() here cause a scheduling while atomic kernel
panic?
qcom_i2c_target_hw_reset() is called from qcom_i2c_target_handle_error(),
which is invoked directly from the hardirq handler qcom_i2c_target_irq()
when an error condition or clock low timeout occurs.
> qcom_i2c_target_hw_init(target);
> writel(target->slave->addr, target->base + I2C_S_DEVICE_ADDR);
> writel(I2C_S_CORE_EN, target->base + I2C_S_CONFIG);
> }
[ ... ]
> @@ -279,15 +279,15 @@ static irqreturn_t qcom_i2c_target_irq(int irq, void *dev)
> if (!READ_ONCE(target->slave)) {
> writel(irq_stat, target->base + I2C_S_IRQ_CLR);
> return IRQ_HANDLED;
> }
>
> if (irq_stat & (BIT(ERR_CONDITION) | BIT(CLOCK_LOW_TIMEOUT)))
> return qcom_i2c_target_handle_error(target, irq_stat);
>
> if (irq_stat & BIT(STOP_DETECTED))
> return qcom_i2c_target_handle_stop(target, irq_stat);
>
> if (irq_stat & BIT(RESTART_DETECTED)) {
> dev_dbg(target->dev, "Repeated start bit detected\n");
> target->status = 0;
> writel(ACK_RESUME, target->base + I2C_S_CONTROL);
[Severity: High]
If a repeated start occurs and STRCH_RD is co-asserted, does writing
ACK_RESUME here release the clock stretch prematurely?
Releasing it here would happen before the STRCH_RD handler below has a
chance to write the required payload to I2C_S_TX_FIFO, potentially corrupting
the data sent to the I2C master.
> writel(BIT(RESTART_DETECTED), target->base + I2C_S_IRQ_CLR);
> }
>
> if (irq_stat & BIT(STRCH_RD))
> qcom_i2c_target_handle_strch_rd(target);
[ ... ]
> @@ -482,15 +482,15 @@ static int qcom_i2c_target_probe(struct platform_device *pdev)
> target->ahb_clk = devm_clk_get(dev, "ahb");
> if (IS_ERR(target->ahb_clk))
> return dev_err_probe(dev, PTR_ERR(target->ahb_clk),
> "failed to get AHB clock\n");
>
> ret = clk_prepare_enable(target->xo_clk);
> if (ret)
> return dev_err_probe(dev, ret, "failed to enable XO clock\n");
>
> ret = clk_prepare_enable(target->ahb_clk);
> if (ret) {
> clk_disable_unprepare(target->xo_clk);
> return dev_err_probe(dev, ret, "failed to enable AHB clock\n");
> }
>
> target->irq = platform_get_irq(pdev, 0);
> if (target->irq < 0)
> return target->irq;
[Severity: Medium]
Are xo_clk and ahb_clk leaked here if platform_get_irq() fails?
It appears clk_disable_unprepare() is missing for both clocks in this error
path, as well as in the subsequent qcom_i2c_target_icc_init() and
devm_request_irq() error paths.
>
> ret = qcom_i2c_target_icc_init(target);
> if (ret)
> return ret;
[ ... ]
> @@ -511,11 +511,11 @@ static void qcom_i2c_target_remove(struct platform_device *pdev)
> {
> struct qcom_i2c_target *target = platform_get_drvdata(pdev);
>
> writel(0, target->base + I2C_S_CONFIG);
> i2c_del_adapter(&target->adap);
> icc_set_bw(target->icc_path, 0, 0);
> clk_disable_unprepare(target->xo_clk);
> clk_disable_unprepare(target->ahb_clk);
[Severity: High]
Since the IRQ is devm-managed, can it fire after the clocks are disabled here?
If the interrupt fires during this window, the handler will read
I2C_S_IRQ_STATUS while the clocks are off, which could cause a synchronous
external abort.
> }
>
> static int qcom_i2c_target_suspend(struct device *dev)
[ ... ]
> @@ -561,11 +561,11 @@ static int qcom_i2c_target_resume(struct device *dev)
> return 0;
>
> err_disable_xo:
> clk_disable_unprepare(target->xo_clk);
> err_disable_ahb:
> clk_disable_unprepare(target->ahb_clk);
> return ret;
> }
>
> static const struct dev_pm_ops qcom_i2c_target_pm_ops = {
> SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(qcom_i2c_target_suspend,
> qcom_i2c_target_resume)
[Severity: High]
Does using the noirq PM macros here cause a scheduling while atomic panic
during suspend and resume?
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS binds the callbacks to the suspend_noirq and
resume_noirq phases, which run with local interrupts disabled. However,
qcom_i2c_target_suspend() and qcom_i2c_target_resume() both call
clk_disable_unprepare() or clk_prepare_enable(), and icc_set_bw(), which
can sleep.
> };
>
> static const struct of_device_id qcom_i2c_target_dt_match[] = {
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260813-i2c-qcom-slave-v3-0-1d3742e2ad47@oss.qualcomm.com?part=2
prev parent reply other threads:[~2026-08-13 16:05 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-13 15:52 [PATCH v3 0/2] Add Qualcomm I2C target controller driver Viken Dadhaniya
2026-08-13 15:52 ` [PATCH v3 1/2] dt-bindings: i2c: Add Qualcomm I2C target controller Viken Dadhaniya
2026-08-13 16:01 ` sashiko-bot
2026-08-13 15:52 ` [PATCH v3 2/2] i2c: qcom-target: Add driver for " Viken Dadhaniya
2026-08-13 16:05 ` sashiko-bot [this message]
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=20260813160512.393D51F00A3A@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=robh@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=viken.dadhaniya@oss.qualcomm.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