Devicetree
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Adrian Nguyen" <thenguyen1024@gmail.com>
Cc: devicetree@vger.kernel.org, robh@kernel.org, conor+dt@kernel.org
Subject: Re: [PATCH v3 2/2] power: supply: Add Qualcomm SMB1351 charger driver
Date: Sat, 14 Nov 2026 11:40:29 +0000	[thread overview]
Message-ID: <sashiko-outbox-214415@kernel.org> (raw)
In-Reply-To: <20261114112155.85068-3-thenguyen1024@gmail.com>

Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [Medium] power: supply: qcom_smb1351: race on retry_until while
  smb1351_work() runs
- [Low] power: supply: qcom_smb1351: unlocked work scheduling in
  smb1351_probe()
--

commit 51205e0d5cfa98bce2fcb03aa43f9fb231439ca3
Author: Adrian Nguyen <thenguyen1024@gmail.com>

power: supply: Add Qualcomm SMB1351 charger driver

This commit adds a power supply driver for the Qualcomm SMB1351/SMB1350
parallel charger that keeps charging disabled over I2C and reports VBUS
presence and charger status.

> diff --git a/drivers/power/supply/qcom_smb1351.c b/drivers/power/supply/qcom_smb1351.c
> new file mode 100644
> index 0000000000000..33289c767bdb1
> --- /dev/null
> +++ b/drivers/power/supply/qcom_smb1351.c

[ ... ]

> @@ -0,0 +1,439 @@
> +	/*
> +	 * The chip can lose VBUS, and with it its configuration, without the
> +	 * PMIC charger reporting a change. If it has been reset or does not
> +	 * answer, run the work again, unless a run with its own deadline is
> +	 * already pending. Report "Unknown" rather than an error, which would
> +	 * drop the whole uevent.
> +	 */
> +	ret = smb1351_read_status(chip, &stat);
> +	if (ret) {
> +		spin_lock(&chip->lock);
> +		if (!delayed_work_pending(&chip->work)) {
> +			WRITE_ONCE(chip->retry_until, jiffies +
> +				   msecs_to_jiffies(SMB1351_RETRY_TIMEOUT_MS));
> +			queue_delayed_work(system_freezable_wq, &chip->work, 0);
> +		}
> +		spin_unlock(&chip->lock);
> +	}

[Severity: Medium]
Can smb1351_get_property() still overwrite chip->retry_until and bypass the
retry backoff while smb1351_work() is running?

The workqueue core clears WORK_STRUCT_PENDING_BIT before calling
smb1351_work(), so delayed_work_pending(&chip->work) returns false while
smb1351_work() is executing I2C transfers:

CPU0 (kworker)                    CPU1
smb1351_work()
  /* pending bit cleared */
  regmap_read(..., &version)
    /* fails when VBUS is lost */
                                  smb1351_get_property()
                                    smb1351_read_status() -> -ENXIO
                                    spin_lock(&chip->lock)
                                    !delayed_work_pending(&chip->work)
                                    chip->retry_until = jiffies + 2s
                                    queue_delayed_work(..., 0)
                                    spin_unlock(&chip->lock)
  time_before(jiffies, retry_until)
  queue_delayed_work(..., 200ms)  <-- ignored, already queued with delay 0

When userspace reads status or charge_type while smb1351_work() is running,
smb1351_get_property() extends chip->retry_until by another 2 seconds and
queues chip->work with a 0 ms delay.  smb1351_work() then sees the extended
deadline instead of expiring and setting chip->online to false, and its own
queue_delayed_work() with SMB1351_RETRY_MS becomes a no-op because the work
is already pending, re-running smb1351_work() immediately without the 200 ms
backoff.

In addition, because smb1351_get_property() reads chip->online before
smb1351_read_status() and does not recheck it under chip->lock (and
smb1351_work() updates chip->online outside chip->lock), a status read that
races with the final retry in smb1351_work() setting chip->online to false
will find !delayed_work_pending(&chip->work) after smb1351_work() finishes
and start a new 2-second retry loop.

[ ... ]

> +	/* Leave the chip to the work, it does not answer without VBUS */
> +	WRITE_ONCE(chip->retry_until,
> +		   jiffies + msecs_to_jiffies(SMB1351_RETRY_TIMEOUT_MS));
> +	enable_delayed_work(&chip->work);
> +	mod_delayed_work(system_freezable_wq, &chip->work, 0);
> +
> +	return 0;
> +}

[Severity: Low]
Can smb1351_probe() race with smb1351_external_power_changed() when enabling
and scheduling chip->work without holding chip->lock?

chip->psy is already live after devm_power_supply_register(), so
smb1351_external_power_changed() can run on another CPU while probe finishes:

CPU0                              CPU1
smb1351_probe()
  devm_power_supply_register()
  ...
  chip->retry_until = jiffies + 2s
  enable_delayed_work(&chip->work)
                                  smb1351_external_power_changed()
                                    spin_lock(&chip->lock)
                                    chip->retry_until = jiffies + 2.3s
                                    mod_delayed_work(..., 300ms)
                                    spin_unlock(&chip->lock)
  mod_delayed_work(..., 0)        <-- overwrites 300ms settle delay with 0

If smb1351_external_power_changed() runs between enable_delayed_work() and
mod_delayed_work(), smb1351_probe() replaces the 300 ms VBUS settle delay
(SMB1351_SETTLE_MS) with 0, running smb1351_work() before VBUS has settled.
If smb1351_external_power_changed() runs just before enable_delayed_work(),
its mod_delayed_work() is dropped while the work is disabled and
smb1351_probe() overwrites the longer retry_until deadline and schedules the
work without the settle delay.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261114112155.85068-1-thenguyen1024@gmail.com?part=2

      parent reply	other threads:[~2026-11-14 11:40 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-14 11:21 [PATCH v3 0/2] power: supply: Add Qualcomm SMB1351 charger driver Adrian Nguyen
2026-11-14 11:21 ` [PATCH v3 1/2] dt-bindings: power: supply: Add Qualcomm SMB1351 charger Adrian Nguyen
2026-11-14 11:21 ` [PATCH v3 2/2] power: supply: Add Qualcomm SMB1351 charger driver Adrian Nguyen
2026-11-14 11:39   ` Markus Elfring
2026-11-14 11:40   ` 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=sashiko-outbox-214415@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=thenguyen1024@gmail.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