All of lore.kernel.org
 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 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.