All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Abdurrahman Hussain" <abdurrahman@nexthop.ai>
Cc: devicetree@vger.kernel.org, linux-hwmon@vger.kernel.org,
	robh@kernel.org, conor+dt@kernel.org
Subject: Re: [PATCH v2 3/4] hwmon: (pmbus_core) Support relative encoding of vout related commands
Date: Tue, 20 Oct 2026 08:55:10 +0000	[thread overview]
Message-ID: <sashiko-outbox-178650@kernel.org> (raw)
In-Reply-To: <20261020-hwmon-pmbus-fs1412-v2-3-3396c3a08251@nexthop.ai>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] hwmon: (pmbus_core) divide-by-zero after pmbus_regulator_set_voltage()
- [Medium] hwmon: (pmbus_core) broken relative VOUT margin handling in regulator ops
--

commit 8ccb177073557cf9644c419b791da4a5cf494d3e
Author: Lars Petter Mostad <lars.petter.mostad@appear.net>

hwmon: (pmbus_core) Support relative encoding of vout related commands

This patch adds support for PMBus 1.3 relative encoding of output voltage
related commands, scaling limits relative to VOUT_COMMAND in
pmbus_reg2data() and pmbus_data2reg() and updating the cached VOUT_COMMAND
when setting regulator voltage.

> diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
> index 5f69c1420b4e1..47dff264d28bf 100644
> --- a/drivers/hwmon/pmbus/pmbus_core.c
> +++ b/drivers/hwmon/pmbus/pmbus_core.c

[ ... ]

> @@ -803,6 +806,26 @@ static void pmbus_update_sensor_data(struct i2c_client *client, struct pmbus_sen
>  						     sensor->phase, sensor->reg);
>  }
>  
> +static bool pmbus_sensor_is_vout_relative(struct pmbus_data *data,
> +					  struct pmbus_sensor *sensor)
> +{
> +	if (sensor->class != PSC_VOLTAGE_OUT ||
> +	    !data->vout_mode_relative[sensor->page])
> +		return false;
> +
> +	switch (sensor->reg) {
> +	case PMBUS_VOUT_MARGIN_HIGH:
> +	case PMBUS_VOUT_MARGIN_LOW:
> +	case PMBUS_VOUT_OV_FAULT_LIMIT:
> +	case PMBUS_VOUT_OV_WARN_LIMIT:
> +	case PMBUS_VOUT_UV_WARN_LIMIT:
> +	case PMBUS_VOUT_UV_FAULT_LIMIT:
> +		return true;
> +	default:
> +		return false;
> +	}
> +}

[Severity: Medium]
Can the PMBUS_VOUT_MARGIN_HIGH and PMBUS_VOUT_MARGIN_LOW cases in
pmbus_sensor_is_vout_relative() ever match, and how does
pmbus_regulator_list_voltage() behave in relative mode?

No hwmon sensor attributes are registered for PMBUS_VOUT_MARGIN_LOW or
PMBUS_VOUT_MARGIN_HIGH. The only callers in drivers/hwmon/pmbus/pmbus_core.c
that read these registers and pass them to pmbus_reg2data() are
pmbus_regulator_get_low_margin() and pmbus_regulator_get_high_margin():

static int pmbus_regulator_get_low_margin(struct i2c_client *client, int page)
{
	struct pmbus_data *data = i2c_get_clientdata(client);
	struct pmbus_sensor s = {
		.page = page,
		.class = PSC_VOLTAGE_OUT,
		.convert = true,
		.data = -1,
	};

	if (data->vout_low[page] < 0) {
		if (pmbus_check_word_register(client, page, PMBUS_MFR_VOUT_MIN))
			s.data = _pmbus_read_word_data(client, page, 0xff,
						       PMBUS_MFR_VOUT_MIN);
		if (s.data < 0) {
			s.data = _pmbus_read_word_data(client, page, 0xff,
						       PMBUS_VOUT_MARGIN_LOW);
			if (s.data < 0)
				return s.data;
		}
		data->vout_low[page] = pmbus_reg2data(data, &s);
	}

	return data->vout_low[page];
}

Neither pmbus_regulator_get_low_margin() nor
pmbus_regulator_get_high_margin() initializes s.reg (leaving it as 0), so
when they fall back to PMBUS_VOUT_MARGIN_LOW or PMBUS_VOUT_MARGIN_HIGH,
pmbus_reg2data() -> pmbus_sensor_is_vout_relative() returns false and caches
the unscaled permillage value as mV in data->vout_low[page] and
data->vout_high[page].

In addition, while pmbus_regulator_set_voltage() skips checking these margins
when data->vout_mode_relative[s.page] is true, pmbus_regulator_list_voltage()
still calls pmbus_regulator_get_low_margin() and
pmbus_regulator_get_high_margin() unconditionally:

static int pmbus_regulator_list_voltage(struct regulator_dev *rdev,
					unsigned int selector)
{
...
	low = pmbus_regulator_get_low_margin(client, rdev_get_id(rdev));
	if (low < 0)
		return low;

	high = pmbus_regulator_get_high_margin(client, rdev_get_id(rdev));
	if (high < 0)
		return high;

	if (val >= low && val <= high)
		return val * 1000; /* unit is uV */

	return 0;
}

Even if s.reg were populated when reading the margin registers,
data->vout_low[page] and data->vout_high[page] are cached once and not
updated when pmbus_regulator_set_voltage() changes VOUT_COMMAND. Should
pmbus_regulator_get_low_margin(), pmbus_regulator_get_high_margin(), and
pmbus_regulator_list_voltage() also account for relative mode?

[ ... ]

> @@ -3351,29 +3419,38 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv,
>  		.data = -1,
>  	};
>  	int val = DIV_ROUND_CLOSEST(min_uv, 1000); /* convert to mV */
> -	int low, high;
> +	int low, high, ret;
>  
>  	*selector = 0;
>  
>  	guard(pmbus_lock)(client);
>  
> -	low = pmbus_regulator_get_low_margin(client, s.page);
> -	if (low < 0)
> -		return low;
> +	if (!data->vout_mode_relative[s.page]) {
> +		low = pmbus_regulator_get_low_margin(client, s.page);
> +		if (low < 0)
> +			return low;
>  
> -	high = pmbus_regulator_get_high_margin(client, s.page);
> -	if (high < 0)
> -		return high;
> +		high = pmbus_regulator_get_high_margin(client, s.page);
> +		if (high < 0)
> +			return high;
>  
> -	/* Make sure we are within margins */
> -	if (low > val)
> -		val = low;
> -	if (high < val)
> -		val = high;
> +		/* Make sure we are within margins */
> +		if (low > val)
> +			val = low;
> +		if (high < val)
> +			val = high;
> +	}
>  
>  	val = pmbus_data2reg(data, &s, val);
>  
> -	return _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val);
> +	ret = _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (data->vout_mode_relative[s.page])
> +		pmbus_init_vout_relative(data, s.page, val);
> +
> +	return 0;
>  }

[Severity: High]
Could updating data->vout_command[s.page] in pmbus_regulator_set_voltage()
lead to a division by zero in pmbus_data2reg()?

At probe time, pmbus_init_common() rejects non-positive values in
data->vout_command[page] after calling pmbus_init_vout_relative(). However,
in pmbus_regulator_set_voltage(), when data->vout_mode_relative[s.page] is
true, margin clamping is skipped and pmbus_init_vout_relative(data, s.page,
val) updates data->vout_command[s.page] without checking whether the decoded
voltage is <= 0.

If a consumer requests a small voltage (for example min_uv < 500 uV, or a
value that rounds to 0 in pmbus_data2reg()), data->vout_command[s.page]
becomes 0. A subsequent write to a relative VOUT limit attribute in sysfs
will then call pmbus_set_sensor() -> pmbus_data2reg() and divide by zero:

	if (pmbus_sensor_is_vout_relative(data, sensor)) {
		val = clamp_val(val, -INT_MAX, INT_MAX);
		val = DIV_S64_ROUND_CLOSEST(val * 1000,
					    data->vout_command[sensor->page]);
	}

Should pmbus_regulator_set_voltage() or pmbus_data2reg() guard against a
non-positive vout_command?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261020-hwmon-pmbus-fs1412-v2-0-3396c3a08251@nexthop.ai?part=3

  reply	other threads:[~2026-10-20  8:55 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-20  7:43 [PATCH v2 0/4] hwmon: (pmbus) Support relative VOUT mode, add TDK FS1412 and FS1525 Abdurrahman Hussain
2026-10-20  7:43 ` [PATCH v2 1/4] dt-bindings: vendor-prefixes: Add TDK Corporation Abdurrahman Hussain
2026-10-20  8:39   ` sashiko-bot
2026-10-20  7:43 ` [PATCH v2 2/4] dt-bindings: trivial-devices: Add TDK FS1412 and FS1525 Abdurrahman Hussain
2026-10-20  8:40   ` sashiko-bot
2026-10-20  7:43 ` [PATCH v2 3/4] hwmon: (pmbus_core) Support relative encoding of vout related commands Abdurrahman Hussain
2026-10-20  8:55   ` sashiko-bot [this message]
2026-10-20 15:37     ` Guenter Roeck
2026-10-20 18:58       ` Abdurrahman Hussain
2026-10-20  7:43 ` [PATCH v2 4/4] hwmon: (pmbus/fs1412) Add TDK FS1412 and FS1525 driver Abdurrahman Hussain
2026-10-20  8:58   ` sashiko-bot

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-178650@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=abdurrahman@nexthop.ai \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=linux-hwmon@vger.kernel.org \
    --cc=robh@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /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.