Linux Hardware Monitor development
 help / color / mirror / Atom feed
* [PATCH v2 0/5] hwmon: (pmbus/adm1266) blackbox, FW rev, rtc_class, GPIO label
@ 2026-05-11  4:48 Abdurrahman Hussain via B4 Relay
  2026-05-11  4:48 ` [PATCH v2 1/5] hwmon: (pmbus/adm1266) add firmware_revision debugfs entry Abdurrahman Hussain via B4 Relay
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: Abdurrahman Hussain via B4 Relay @ 2026-05-11  4:48 UTC (permalink / raw)
  To: Guenter Roeck, Alexandru Tachici
  Cc: linux-hwmon, linux-kernel, Abdurrahman Hussain

This series fills in some gaps in the adm1266 driver and removes a
probe-time RTC seed that was clobbering valid device state.

Patch 1 exposes the firmware revision (IC_DEVICE_REV, 0xAE) via
debugfs alongside the existing sequencer_state entry.

Patch 2 adds a write-only clear_blackbox debugfs file. Devices
configured for single-recording mode (BLACKBOX_CONFIG[0] = 0) need
an explicit clear once the 32-record buffer fills; the documented
sub-command ({0xFE, 0x00} block-write to 0xDE) wasn't reachable
from userspace.

Patch 3 exposes the non-volatile POWERUP_COUNTER (0xE4) via debugfs.
The same value is embedded in every blackbox record, so the live
value lets userspace match a captured record back to the boot it
came from when correlating logs.

Patch 4 replaces the probe-time SET_RTC seed with an rtc_class
device backed by SET_RTC. The existing seed used CLOCK_MONOTONIC
seconds, which is meaningless as a wall-clock time and clobbers
whatever the device retained across a warm reboot. The data sheet
(Rev. D, p. 22) explicitly recommends "frequently send the time
stamp to the ADM1266 to synchronize the UNIX time and reduce the
time from drifting" when running on the internal oscillator (no
external 32.768 kHz crystal). Letting userspace own the policy via
standard tooling (hwclock, chrony, systemd-timesyncd) against
/dev/rtcN is both more correct and avoids any driver-specific
sysfs ABI.

Patch 5 disambiguates GPIO line labels on platforms that fit two
ADM1266 devices on different I2C buses at the same slave address.

Signed-off-by: Abdurrahman Hussain <abdurrahman@nexthop.ai>
---
Changes in v2:
- Drop the v1 "use wall-clock seconds for SET_RTC" and "write
  fractional-seconds field of SET_RTC" patches. v1 patch 6 already
  added an rtc_class device, so userspace now owns the time-set
  policy and the probe-time seed is no longer needed - removing it
  also fixes the cross-reboot blackbox-correlation regression the
  seed introduced.
- In the rtc_class patch, write the SET_RTC fractional-seconds
  bytes as zero rather than computing them from a timespec64. The
  rtc_class API is second-precision, so the divide that v1 patch 2
  was adding never produced a non-zero result anyway. This also
  drops the 64-bit divide that would have failed to link on 32-bit
  builds (Sashiko review).
- Use %d (decimal) for the I2C adapter number in GPIO line labels,
  matching the i2c-N convention used elsewhere in Linux. v1 used
  %x, which rendered bus numbers >= 10 in hexadecimal (Sashiko
  review).
- Link to v1: https://patch.msgid.link/20260508-adm1266-v1-0-ec08bf29e0ce@nexthop.ai

---
Abdurrahman Hussain (5):
      hwmon: (pmbus/adm1266) add firmware_revision debugfs entry
      hwmon: (pmbus/adm1266) add clear_blackbox debugfs entry
      hwmon: (pmbus/adm1266) add powerup_counter debugfs entry
      hwmon: (pmbus/adm1266) replace probe-time RTC seed with rtc_class device
      hwmon: (pmbus/adm1266) include adapter number in GPIO line label

 drivers/hwmon/pmbus/adm1266.c | 162 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 150 insertions(+), 12 deletions(-)
---
base-commit: 917719c412c48687d4a176965d1fa35320ec457c
change-id: 20260507-adm1266-cf3af42dc3d2

Best regards,
--  
Abdurrahman Hussain <abdurrahman@nexthop.ai>



^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 1/5] hwmon: (pmbus/adm1266) add firmware_revision debugfs entry
  2026-05-11  4:48 [PATCH v2 0/5] hwmon: (pmbus/adm1266) blackbox, FW rev, rtc_class, GPIO label Abdurrahman Hussain via B4 Relay
@ 2026-05-11  4:48 ` Abdurrahman Hussain via B4 Relay
  2026-05-11  4:48 ` [PATCH v2 2/5] hwmon: (pmbus/adm1266) add clear_blackbox " Abdurrahman Hussain via B4 Relay
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 10+ messages in thread
From: Abdurrahman Hussain via B4 Relay @ 2026-05-11  4:48 UTC (permalink / raw)
  To: Guenter Roeck, Alexandru Tachici
  Cc: linux-hwmon, linux-kernel, Abdurrahman Hussain

From: Abdurrahman Hussain <abdurrahman@nexthop.ai>

The ADM1266 reports its firmware revision via the IC_DEVICE_REV
manufacturer-specific block-read command (0xAE, datasheet Rev. D
Table 80). The first three returned bytes are the firmware
major.minor.patch fields. This is useful when correlating field
behaviour against ADI release notes; expose it through debugfs
alongside the existing sequencer_state entry.

The standard PMBus MFR_REVISION (0x9B) register is already exposed
by pmbus_core's debugfs auto-create path and reports the
manufacturer revision, which is a separate thing from the firmware
running on the device.

Signed-off-by: Abdurrahman Hussain <abdurrahman@nexthop.ai>
---
 drivers/hwmon/pmbus/adm1266.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c
index d90f8f80be8e..7b8433226176 100644
--- a/drivers/hwmon/pmbus/adm1266.c
+++ b/drivers/hwmon/pmbus/adm1266.c
@@ -21,6 +21,7 @@
 #include <linux/slab.h>
 #include <linux/timekeeping.h>
 
+#define ADM1266_IC_DEVICE_REV	0xAE
 #define ADM1266_BLACKBOX_CONFIG	0xD3
 #define ADM1266_PDIO_CONFIG	0xD4
 #define ADM1266_READ_STATE	0xD9
@@ -331,6 +332,30 @@ static int adm1266_state_read(struct seq_file *s, void *pdata)
 	return 0;
 }
 
+/*
+ * IC_DEVICE_REV (0xAE) returns an 8-byte block (datasheet Rev. D, Table 80):
+ *   [2:0] firmware revision  major.minor.patch
+ *   [5:3] bootloader revision major.minor.patch
+ *   [7:6] silicon revision    two ASCII characters
+ */
+static int adm1266_firmware_revision_read(struct seq_file *s, void *pdata)
+{
+	struct device *dev = s->private;
+	struct i2c_client *client = to_i2c_client(dev);
+	u8 buf[I2C_SMBUS_BLOCK_MAX];
+	int ret;
+
+	ret = i2c_smbus_read_block_data(client, ADM1266_IC_DEVICE_REV, buf);
+	if (ret < 0)
+		return ret;
+	if (ret < 3)
+		return -EIO;
+
+	seq_printf(s, "%u.%u.%u\n", buf[0], buf[1], buf[2]);
+
+	return 0;
+}
+
 static void adm1266_init_debugfs(struct adm1266_data *data)
 {
 	struct dentry *root;
@@ -343,6 +368,8 @@ static void adm1266_init_debugfs(struct adm1266_data *data)
 
 	debugfs_create_devm_seqfile(&data->client->dev, "sequencer_state", data->debugfs_dir,
 				    adm1266_state_read);
+	debugfs_create_devm_seqfile(&data->client->dev, "firmware_revision", data->debugfs_dir,
+				    adm1266_firmware_revision_read);
 }
 
 static int adm1266_nvmem_read_blackbox(struct adm1266_data *data, u8 *read_buff)

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 2/5] hwmon: (pmbus/adm1266) add clear_blackbox debugfs entry
  2026-05-11  4:48 [PATCH v2 0/5] hwmon: (pmbus/adm1266) blackbox, FW rev, rtc_class, GPIO label Abdurrahman Hussain via B4 Relay
  2026-05-11  4:48 ` [PATCH v2 1/5] hwmon: (pmbus/adm1266) add firmware_revision debugfs entry Abdurrahman Hussain via B4 Relay
@ 2026-05-11  4:48 ` Abdurrahman Hussain via B4 Relay
  2026-05-12  0:03   ` sashiko-bot
  2026-05-11  4:48 ` [PATCH v2 3/5] hwmon: (pmbus/adm1266) add powerup_counter " Abdurrahman Hussain via B4 Relay
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 10+ messages in thread
From: Abdurrahman Hussain via B4 Relay @ 2026-05-11  4:48 UTC (permalink / raw)
  To: Guenter Roeck, Alexandru Tachici
  Cc: linux-hwmon, linux-kernel, Abdurrahman Hussain

From: Abdurrahman Hussain <abdurrahman@nexthop.ai>

The ADM1266 blackbox can be configured in two recording modes via
BLACKBOX_CONFIG[0]: cyclic, where the device overwrites the oldest
record once the 32-record buffer fills, and single, where it stops
recording until the buffer is cleared. Deployments that need to
preserve the full record history across multiple fault episodes
typically run in single mode and need a way to clear the buffer
after the records have been collected.

Expose a write-only debugfs file alongside sequencer_state. Writing
any data to it issues the documented clear-blackbox sub-command:
a 2-byte block-write to READ_BLACKBOX (0xDE) with payload
{0xFE, 0x00} (datasheet Rev. D).

Signed-off-by: Abdurrahman Hussain <abdurrahman@nexthop.ai>
---
 drivers/hwmon/pmbus/adm1266.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c
index 7b8433226176..31aefa8fc75f 100644
--- a/drivers/hwmon/pmbus/adm1266.c
+++ b/drivers/hwmon/pmbus/adm1266.c
@@ -356,6 +356,36 @@ static int adm1266_firmware_revision_read(struct seq_file *s, void *pdata)
 	return 0;
 }
 
+/*
+ * Clearing the blackbox is required when the device is configured in
+ * single-recording mode (BLACKBOX_CONFIG[0] = 0): once the 32-record
+ * buffer is full the device stops recording until cleared.
+ *
+ * The clear is issued as a 2-byte block-write to READ_BLACKBOX with
+ * payload {0xFE, 0x00} per the datasheet.
+ */
+static ssize_t adm1266_clear_blackbox_write(struct file *file, const char __user *ubuf,
+					    size_t count, loff_t *ppos)
+{
+	struct i2c_client *client = file->private_data;
+	u8 payload[2] = { 0xFE, 0x00 };
+	int ret;
+
+	ret = i2c_smbus_write_block_data(client, ADM1266_READ_BLACKBOX,
+					 sizeof(payload), payload);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static const struct file_operations adm1266_clear_blackbox_fops = {
+	.owner = THIS_MODULE,
+	.open = simple_open,
+	.write = adm1266_clear_blackbox_write,
+	.llseek = noop_llseek,
+};
+
 static void adm1266_init_debugfs(struct adm1266_data *data)
 {
 	struct dentry *root;
@@ -370,6 +400,8 @@ static void adm1266_init_debugfs(struct adm1266_data *data)
 				    adm1266_state_read);
 	debugfs_create_devm_seqfile(&data->client->dev, "firmware_revision", data->debugfs_dir,
 				    adm1266_firmware_revision_read);
+	debugfs_create_file("clear_blackbox", 0200, data->debugfs_dir, data->client,
+			    &adm1266_clear_blackbox_fops);
 }
 
 static int adm1266_nvmem_read_blackbox(struct adm1266_data *data, u8 *read_buff)

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 3/5] hwmon: (pmbus/adm1266) add powerup_counter debugfs entry
  2026-05-11  4:48 [PATCH v2 0/5] hwmon: (pmbus/adm1266) blackbox, FW rev, rtc_class, GPIO label Abdurrahman Hussain via B4 Relay
  2026-05-11  4:48 ` [PATCH v2 1/5] hwmon: (pmbus/adm1266) add firmware_revision debugfs entry Abdurrahman Hussain via B4 Relay
  2026-05-11  4:48 ` [PATCH v2 2/5] hwmon: (pmbus/adm1266) add clear_blackbox " Abdurrahman Hussain via B4 Relay
@ 2026-05-11  4:48 ` Abdurrahman Hussain via B4 Relay
  2026-05-12  0:34   ` sashiko-bot
  2026-05-11  4:48 ` [PATCH v2 4/5] hwmon: (pmbus/adm1266) replace probe-time RTC seed with rtc_class device Abdurrahman Hussain via B4 Relay
  2026-05-11  4:48 ` [PATCH v2 5/5] hwmon: (pmbus/adm1266) include adapter number in GPIO line label Abdurrahman Hussain via B4 Relay
  4 siblings, 1 reply; 10+ messages in thread
From: Abdurrahman Hussain via B4 Relay @ 2026-05-11  4:48 UTC (permalink / raw)
  To: Guenter Roeck, Alexandru Tachici
  Cc: linux-hwmon, linux-kernel, Abdurrahman Hussain

From: Abdurrahman Hussain <abdurrahman@nexthop.ai>

The ADM1266 maintains a 16-bit non-volatile POWERUP_COUNTER register
(0xE4, datasheet Rev. D, Table 93) that increments on every power
cycle and cannot be reset by the host. Each blackbox record already
embeds the counter at record time, so the standalone live value is
primarily useful for matching a captured record back to the boot it
came from when correlating logs.

Expose it as a read-only debugfs file alongside firmware_revision.
The block-read returns two payload bytes in little-endian order.

Signed-off-by: Abdurrahman Hussain <abdurrahman@nexthop.ai>
---
 drivers/hwmon/pmbus/adm1266.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c
index 31aefa8fc75f..99e92a8365fb 100644
--- a/drivers/hwmon/pmbus/adm1266.c
+++ b/drivers/hwmon/pmbus/adm1266.c
@@ -28,6 +28,7 @@
 #define ADM1266_READ_BLACKBOX	0xDE
 #define ADM1266_SET_RTC		0xDF
 #define ADM1266_GPIO_CONFIG	0xE1
+#define ADM1266_POWERUP_COUNTER	0xE4
 #define ADM1266_BLACKBOX_INFO	0xE6
 #define ADM1266_PDIO_STATUS	0xE9
 #define ADM1266_GPIO_STATUS	0xEA
@@ -356,6 +357,31 @@ static int adm1266_firmware_revision_read(struct seq_file *s, void *pdata)
 	return 0;
 }
 
+/*
+ * POWERUP_COUNTER (0xE4) is a 2-byte little-endian non-volatile counter
+ * that increments on every device power cycle (datasheet Rev. D, Table
+ * 93). It saturates at 65535 and cannot be reset by the host. Each
+ * blackbox record embeds the counter value at record time, so this live
+ * read is mainly useful for matching a record back to its boot.
+ */
+static int adm1266_powerup_counter_read(struct seq_file *s, void *pdata)
+{
+	struct device *dev = s->private;
+	struct i2c_client *client = to_i2c_client(dev);
+	u8 buf[I2C_SMBUS_BLOCK_MAX];
+	int ret;
+
+	ret = i2c_smbus_read_block_data(client, ADM1266_POWERUP_COUNTER, buf);
+	if (ret < 0)
+		return ret;
+	if (ret != 2)
+		return -EIO;
+
+	seq_printf(s, "%u\n", buf[0] | (buf[1] << 8));
+
+	return 0;
+}
+
 /*
  * Clearing the blackbox is required when the device is configured in
  * single-recording mode (BLACKBOX_CONFIG[0] = 0): once the 32-record
@@ -400,6 +426,8 @@ static void adm1266_init_debugfs(struct adm1266_data *data)
 				    adm1266_state_read);
 	debugfs_create_devm_seqfile(&data->client->dev, "firmware_revision", data->debugfs_dir,
 				    adm1266_firmware_revision_read);
+	debugfs_create_devm_seqfile(&data->client->dev, "powerup_counter", data->debugfs_dir,
+				    adm1266_powerup_counter_read);
 	debugfs_create_file("clear_blackbox", 0200, data->debugfs_dir, data->client,
 			    &adm1266_clear_blackbox_fops);
 }

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 4/5] hwmon: (pmbus/adm1266) replace probe-time RTC seed with rtc_class device
  2026-05-11  4:48 [PATCH v2 0/5] hwmon: (pmbus/adm1266) blackbox, FW rev, rtc_class, GPIO label Abdurrahman Hussain via B4 Relay
                   ` (2 preceding siblings ...)
  2026-05-11  4:48 ` [PATCH v2 3/5] hwmon: (pmbus/adm1266) add powerup_counter " Abdurrahman Hussain via B4 Relay
@ 2026-05-11  4:48 ` Abdurrahman Hussain via B4 Relay
  2026-05-12  1:12   ` sashiko-bot
  2026-05-11  4:48 ` [PATCH v2 5/5] hwmon: (pmbus/adm1266) include adapter number in GPIO line label Abdurrahman Hussain via B4 Relay
  4 siblings, 1 reply; 10+ messages in thread
From: Abdurrahman Hussain via B4 Relay @ 2026-05-11  4:48 UTC (permalink / raw)
  To: Guenter Roeck, Alexandru Tachici
  Cc: linux-hwmon, linux-kernel, Abdurrahman Hussain

From: Abdurrahman Hussain <abdurrahman@nexthop.ai>

The driver currently writes the device's internal RTC at probe with
ktime_get_seconds(), which returns CLOCK_MONOTONIC seconds since boot
and is not a wall-clock value. The resulting timestamps embedded in
blackbox records are therefore meaningless across reboots, defeating
the cross-reboot record-correlation use case the field exists for.

Switching the seed to ktime_get_real_seconds() does not actually fix
this: at probe the system wall clock may not yet have been set (no
external RTC, no userspace NTP), and seeding unconditionally also
clobbers whatever valid time the ADM1266 retained across a warm
reboot.

The data sheet (Rev. D, p. 22) recommends "frequently send the time
stamp to the ADM1266 to synchronize the UNIX time and reduce the time
from drifting" when running on the internal oscillator. The clean way
to expose that policy is an rtc_class device backed by SET_RTC, so
that userspace tooling (hwclock, chrony, systemd-timesyncd) can drive
the re-sync against /dev/rtcN once it trusts the system clock - with
no driver-specific sysfs ABI.

Drop the probe-time seed and adm1266_set_rtc() entirely. Add an
rtc_class device whose ->read_time and ->set_time callbacks read and
write the SET_RTC frame. The rtc_class API is second-precision, so
the SET_RTC fractional-seconds bytes are always written as zero.

Fixes: 15609d189302 ("hwmon: (pmbus/adm1266) read blackbox")
Signed-off-by: Abdurrahman Hussain <abdurrahman@nexthop.ai>
---
 drivers/hwmon/pmbus/adm1266.c | 70 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 60 insertions(+), 10 deletions(-)

diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c
index 99e92a8365fb..0dfb02db8683 100644
--- a/drivers/hwmon/pmbus/adm1266.c
+++ b/drivers/hwmon/pmbus/adm1266.c
@@ -18,8 +18,8 @@
 #include <linux/nvmem-consumer.h>
 #include <linux/nvmem-provider.h>
 #include "pmbus.h"
+#include <linux/rtc.h>
 #include <linux/slab.h>
-#include <linux/timekeeping.h>
 
 #define ADM1266_IC_DEVICE_REV	0xAE
 #define ADM1266_BLACKBOX_CONFIG	0xD3
@@ -513,21 +513,71 @@ static int adm1266_config_nvmem(struct adm1266_data *data)
 	return 0;
 }
 
-static int adm1266_set_rtc(struct adm1266_data *data)
+/*
+ * SET_RTC frame layout (datasheet Rev. D, Table 84):
+ *   bytes [1:0] = fractional seconds, LSB = 1/65536 s
+ *   bytes [5:2] = seconds since 1970-01-01 UTC
+ * The rtc_class API is second-precision, so the fractional bytes are
+ * always written as zero.
+ */
+static int adm1266_write_rtc(struct i2c_client *client, time64_t secs)
 {
-	time64_t kt;
-	char write_buf[6];
+	u8 buf[6] = { 0 };
 	int i;
 
-	kt = ktime_get_seconds();
+	for (i = 0; i < 4; i++)
+		buf[2 + i] = (secs >> (i * 8)) & 0xFF;
+
+	return i2c_smbus_write_block_data(client, ADM1266_SET_RTC, sizeof(buf), buf);
+}
+
+static int adm1266_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	u8 buf[I2C_SMBUS_BLOCK_MAX];
+	u32 secs;
+	int ret;
+	int i;
 
-	memset(write_buf, 0, sizeof(write_buf));
+	ret = i2c_smbus_read_block_data(client, ADM1266_SET_RTC, buf);
+	if (ret < 0)
+		return ret;
+	if (ret != 6)
+		return -EIO;
 
+	secs = 0;
 	for (i = 0; i < 4; i++)
-		write_buf[2 + i] = (kt >> (i * 8)) & 0xFF;
+		secs |= (u32)buf[2 + i] << (i * 8);
+
+	rtc_time64_to_tm(secs, tm);
+	return 0;
+}
+
+static int adm1266_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+
+	return adm1266_write_rtc(client, rtc_tm_to_time64(tm));
+}
+
+static const struct rtc_class_ops adm1266_rtc_ops = {
+	.read_time = adm1266_rtc_read_time,
+	.set_time = adm1266_rtc_set_time,
+};
+
+static int adm1266_register_rtc(struct adm1266_data *data)
+{
+	struct rtc_device *rtc;
+
+	rtc = devm_rtc_allocate_device(&data->client->dev);
+	if (IS_ERR(rtc))
+		return PTR_ERR(rtc);
+
+	rtc->ops = &adm1266_rtc_ops;
+	rtc->range_min = 0;
+	rtc->range_max = U32_MAX;
 
-	return i2c_smbus_write_block_data(data->client, ADM1266_SET_RTC, sizeof(write_buf),
-					  write_buf);
+	return devm_rtc_register_device(rtc);
 }
 
 static int adm1266_probe(struct i2c_client *client)
@@ -553,7 +603,7 @@ static int adm1266_probe(struct i2c_client *client)
 	if (ret < 0)
 		return ret;
 
-	ret = adm1266_set_rtc(data);
+	ret = adm1266_register_rtc(data);
 	if (ret < 0)
 		return ret;
 

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 5/5] hwmon: (pmbus/adm1266) include adapter number in GPIO line label
  2026-05-11  4:48 [PATCH v2 0/5] hwmon: (pmbus/adm1266) blackbox, FW rev, rtc_class, GPIO label Abdurrahman Hussain via B4 Relay
                   ` (3 preceding siblings ...)
  2026-05-11  4:48 ` [PATCH v2 4/5] hwmon: (pmbus/adm1266) replace probe-time RTC seed with rtc_class device Abdurrahman Hussain via B4 Relay
@ 2026-05-11  4:48 ` Abdurrahman Hussain via B4 Relay
  2026-05-12  1:31   ` sashiko-bot
  4 siblings, 1 reply; 10+ messages in thread
From: Abdurrahman Hussain via B4 Relay @ 2026-05-11  4:48 UTC (permalink / raw)
  To: Guenter Roeck, Alexandru Tachici
  Cc: linux-hwmon, linux-kernel, Abdurrahman Hussain

From: Abdurrahman Hussain <abdurrahman@nexthop.ai>

Platforms that fit more than one ADM1266 on different I2C buses at
the same 7-bit slave address (a common shelf-management pattern,
e.g. one device per power domain) end up with duplicate GPIO line
labels because the existing format only includes the slave address.
Including the adapter number disambiguates them.

The adapter number is formatted as decimal to match the i2c-N
convention used elsewhere in Linux (sysfs paths, dev nodes); the
slave address keeps its conventional hexadecimal form.

The label is purely informational (visible via gpioinfo and the
gpiochip /sys/class/gpio name); no DT or ABI consumer parses it.

Signed-off-by: Abdurrahman Hussain <abdurrahman@nexthop.ai>
---
 drivers/hwmon/pmbus/adm1266.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c
index 0dfb02db8683..479e768ff87c 100644
--- a/drivers/hwmon/pmbus/adm1266.c
+++ b/drivers/hwmon/pmbus/adm1266.c
@@ -292,8 +292,9 @@ static int adm1266_config_gpio(struct adm1266_data *data)
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(data->gpio_names); i++) {
-		gpio_name = devm_kasprintf(&data->client->dev, GFP_KERNEL, "adm1266-%x-%s",
-					   data->client->addr, adm1266_names[i]);
+		gpio_name = devm_kasprintf(&data->client->dev, GFP_KERNEL, "adm1266-%d-%x-%s",
+					   data->client->adapter->nr, data->client->addr,
+					   adm1266_names[i]);
 		if (!gpio_name)
 			return -ENOMEM;
 

-- 
2.53.0



^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 2/5] hwmon: (pmbus/adm1266) add clear_blackbox debugfs entry
  2026-05-11  4:48 ` [PATCH v2 2/5] hwmon: (pmbus/adm1266) add clear_blackbox " Abdurrahman Hussain via B4 Relay
@ 2026-05-12  0:03   ` sashiko-bot
  0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-05-12  0:03 UTC (permalink / raw)
  To: Abdurrahman Hussain via B4 Relay; +Cc: linux-hwmon

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The `adm1266_clear_blackbox_write` debugfs attribute modifies hardware state without holding the required subsystem locks.
- [Low] A zero-byte write to the `clear_blackbox` debugfs file unconditionally triggers the destructive blackbox clear command.
--

commit cd08cab7d449e0fd299c995ec4c83c7a5b860128
Author: Abdurrahman Hussain <abdurrahman@nexthop.ai>

hwmon: (pmbus/adm1266) add clear_blackbox debugfs entry

This commit exposes a write-only debugfs file to issue the clear-blackbox
sub-command for deployments running in single recording mode. Writing any
data to the file triggers a 2-byte block-write to READ_BLACKBOX.

> diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c
> --- a/drivers/hwmon/pmbus/adm1266.c
> +++ b/drivers/hwmon/pmbus/adm1266.c
[ ... ]
> +/*
> + * Clearing the blackbox is required when the device is configured in
> + * single-recording mode (BLACKBOX_CONFIG[0] = 0): once the 32-record
> + * buffer is full the device stops recording until cleared.
> + *
> + * The clear is issued as a 2-byte block-write to READ_BLACKBOX with
> + * payload {0xFE, 0x00} per the datasheet.
> + */
> +static ssize_t adm1266_clear_blackbox_write(struct file *file, const char __user *ubuf,
> +					    size_t count, loff_t *ppos)
> +{
> +	struct i2c_client *client = file->private_data;
> +	u8 payload[2] = { 0xFE, 0x00 };
> +	int ret;

Does this code trigger the hardware clear even for a zero-byte write?
The VFS layer can invoke the write handler with count == 0. Should we
verify that count > 0 before issuing the I2C command?

Is locking required here to prevent races with other device accesses?

The hardware monitoring subsystem guidelines state that drivers must
implement locking (e.g., using hwmon_lock()) for attributes registered
outside the core, such as debugfs files.

If a write to this file occurs concurrently with the multi-step read loop
in adm1266_nvmem_read_blackbox():

drivers/hwmon/pmbus/adm1266.c:adm1266_nvmem_read_blackbox() {
    ...
    for (index = 0; index < record_count; index++) {
        ret = adm1266_pmbus_block_xfer(data, ADM1266_READ_BLACKBOX, ...);
    ...
}

could it clear the hardware buffer mid-read and cause corrupted data or
I2C errors?

> +
> +	ret = i2c_smbus_write_block_data(client, ADM1266_READ_BLACKBOX,
> +					 sizeof(payload), payload);
> +	if (ret < 0)
> +		return ret;
> +
> +	return count;
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260510-adm1266-v2-0-3a22b903c2f1@nexthop.ai?part=2

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 3/5] hwmon: (pmbus/adm1266) add powerup_counter debugfs entry
  2026-05-11  4:48 ` [PATCH v2 3/5] hwmon: (pmbus/adm1266) add powerup_counter " Abdurrahman Hussain via B4 Relay
@ 2026-05-12  0:34   ` sashiko-bot
  0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-05-12  0:34 UTC (permalink / raw)
  To: Abdurrahman Hussain via B4 Relay; +Cc: linux-hwmon

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The debugfs read function adm1266_powerup_counter_read() lacks mandatory subsystem locking.
--

commit 7f6c699c3d3803ae6836691f51cc018599b04811
Author: Abdurrahman Hussain <abdurrahman@nexthop.ai>

hwmon: (pmbus/adm1266) add powerup_counter debugfs entry

This commit adds a read-only debugfs file to expose the ADM1266's 16-bit
non-volatile powerup counter.

> diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c
> index 31aefa8fc75f5..99e92a8365fb7 100644
> --- a/drivers/hwmon/pmbus/adm1266.c
> +++ b/drivers/hwmon/pmbus/adm1266.c

[ ... ]

> +static int adm1266_powerup_counter_read(struct seq_file *s, void *pdata)
> +{
> +	struct device *dev = s->private;
> +	struct i2c_client *client = to_i2c_client(dev);
> +	u8 buf[I2C_SMBUS_BLOCK_MAX];
> +	int ret;
> +
> +	ret = i2c_smbus_read_block_data(client, ADM1266_POWERUP_COUNTER, buf);

Does this debugfs read need to be protected by a lock?

The hardware monitoring subsystem guidelines state that drivers must
implement locking for attributes registered outside of the core info
struct, typically using hwmon_lock() or pmbus_lock().

Without synchronization here, could this I2C read interleave with multi-step
PMBus operations from other sysfs attributes or interrupt handlers and break
command atomicity?

> +	if (ret < 0)
> +		return ret;
> +	if (ret != 2)
> +		return -EIO;
> +
> +	seq_printf(s, "%u\n", buf[0] | (buf[1] << 8));
> +
> +	return 0;
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260510-adm1266-v2-0-3a22b903c2f1@nexthop.ai?part=3

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 4/5] hwmon: (pmbus/adm1266) replace probe-time RTC seed with rtc_class device
  2026-05-11  4:48 ` [PATCH v2 4/5] hwmon: (pmbus/adm1266) replace probe-time RTC seed with rtc_class device Abdurrahman Hussain via B4 Relay
@ 2026-05-12  1:12   ` sashiko-bot
  0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-05-12  1:12 UTC (permalink / raw)
  To: Abdurrahman Hussain via B4 Relay; +Cc: linux-hwmon

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Missing Kconfig dependency on `RTC_CLASS` leads to undefined reference linker errors.
- [High] Premature RTC device registration leads to race conditions during probe and potential Use-After-Free during teardown.
- [High] RTC read/write operations perform unprotected I2C bus transactions, violating hardware monitoring subsystem locking guidelines.
--

commit acf9685b4d9858e1995d0669238f315fc9a4e09f
Author: Abdurrahman Hussain <abdurrahman@nexthop.ai>

hwmon: (pmbus/adm1266) replace probe-time RTC seed with rtc_class device

This commit removes the unconditional probe-time RTC seeding. It adds
an rtc_class device to allow userspace to synchronize the device's internal
clock.

> diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c
> --- a/drivers/hwmon/pmbus/adm1266.c
> +++ b/drivers/hwmon/pmbus/adm1266.c
[ ... ]
> @@ -513,21 +513,71 @@ static int adm1266_config_nvmem(struct adm1266_data *data)
[ ... ]
> +static int adm1266_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct i2c_client *client = to_i2c_client(dev);
> +	u8 buf[I2C_SMBUS_BLOCK_MAX];
> +	u32 secs;
> +	int ret;
> +	int i;
>  
> -	memset(write_buf, 0, sizeof(write_buf));
> +	ret = i2c_smbus_read_block_data(client, ADM1266_SET_RTC, buf);

Does this code violate the hardware monitoring subsystem locking guidelines?

The hwmon subsystem guidelines state that drivers must implement locking
required for attributes registered outside of the core, and should use
hwmon_lock() and hwmon_unlock() for this purpose.

Since adm1266_rtc_read_time() and adm1266_rtc_set_time() invoke raw i2c
transactions without acquiring a lock, could these operations interleave
with multi-transaction PMBus sequences and lead to corrupted hardware state?

[ ... ]
> +static int adm1266_register_rtc(struct adm1266_data *data)
> +{
> +	struct rtc_device *rtc;
> +
> +	rtc = devm_rtc_allocate_device(&data->client->dev);

Is there a missing Kconfig dependency for the RTC subsystem?

This code calls devm_rtc_allocate_device() and devm_rtc_register_device(),
but if the driver is enabled while the RTC subsystem is disabled, the build
will fail with undefined reference errors during linking.

Unlike some other subsystems, linux/rtc.h does not provide static inline
stubs for these functions when the subsystem is disabled.

[ ... ]
> @@ -553,7 +603,7 @@ static int adm1266_probe(struct i2c_client *client)
>  	if (ret < 0)
>  		return ret;
>  
> -	ret = adm1266_set_rtc(data);
> +	ret = adm1266_register_rtc(data);
>  	if (ret < 0)
>  		return ret;

Can this registration sequence lead to race conditions or a use-after-free
during teardown?

By calling adm1266_register_rtc() before pmbus_do_probe() (which happens
later in this function), the rtc device is exposed to userspace while
the PMBus hardware probe is still executing. Userspace could trigger
read or write operations before the PMBus core is fully initialized.

Additionally, devm_rtc_register_device() registers a devres action. If
pmbus_do_probe() later fails, or during normal device unbind, the LIFO
devres teardown will release the PMBus core structures before the rtc
device is unregistered.

If rtc callbacks are accessed during this window, could they dereference
freed PMBus structures?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260510-adm1266-v2-0-3a22b903c2f1@nexthop.ai?part=4

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 5/5] hwmon: (pmbus/adm1266) include adapter number in GPIO line label
  2026-05-11  4:48 ` [PATCH v2 5/5] hwmon: (pmbus/adm1266) include adapter number in GPIO line label Abdurrahman Hussain via B4 Relay
@ 2026-05-12  1:31   ` sashiko-bot
  0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-05-12  1:31 UTC (permalink / raw)
  To: Abdurrahman Hussain via B4 Relay; +Cc: linux-hwmon

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Critical] Changing the generated GPIO line names breaks backwards compatibility for userspace tools and scripts.
--

commit c155c76ac978e1fe6990333ff1cb0db4a1c40a1e
Author: Abdurrahman Hussain <abdurrahman@nexthop.ai>

hwmon: (pmbus/adm1266) include adapter number in GPIO line label
    
This commit updates the GPIO line labels for the ADM1266 driver to include
the I2C adapter number, in addition to the slave address. This is intended
to disambiguate labels when multiple devices use the same 7-bit address on
different buses.

> The label is purely informational (visible via gpioinfo and the
> gpiochip /sys/class/gpio name); no DT or ABI consumer parses it.

Does changing the generated GPIO line names risk breaking backwards
compatibility for userspace tools and scripts? 

These names are exposed to userspace via the GPIO chardev API and sysfs, and
userspace tools (such as libgpiod) or custom scripts can request GPIO lines
by their names. Modifying these names might break existing userspace
deployments that rely on the old naming convention.

> diff --git a/drivers/hwmon/pmbus/adm1266.c b/drivers/hwmon/pmbus/adm1266.c
> index 0dfb02db86837..479e768ff87ca 100644
> --- a/drivers/hwmon/pmbus/adm1266.c
> +++ b/drivers/hwmon/pmbus/adm1266.c
> @@ -292,8 +292,9 @@ static int adm1266_config_gpio(struct adm1266_data *data)
>  	int i;
>  
>  	for (i = 0; i < ARRAY_SIZE(data->gpio_names); i++) {
> -		gpio_name = devm_kasprintf(&data->client->dev, GFP_KERNEL, "adm1266-%x-%s",
> -					   data->client->addr, adm1266_names[i]);
> +		gpio_name = devm_kasprintf(&data->client->dev, GFP_KERNEL, "adm1266-%d-%x-%s",
> +					   data->client->adapter->nr, data->client->addr,
> +					   adm1266_names[i]);

Could this naming format change cause regressions for userspace applications
that are already matching on the previous adm1266-%x-%s format?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260510-adm1266-v2-0-3a22b903c2f1@nexthop.ai?part=5

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-05-12  1:31 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-11  4:48 [PATCH v2 0/5] hwmon: (pmbus/adm1266) blackbox, FW rev, rtc_class, GPIO label Abdurrahman Hussain via B4 Relay
2026-05-11  4:48 ` [PATCH v2 1/5] hwmon: (pmbus/adm1266) add firmware_revision debugfs entry Abdurrahman Hussain via B4 Relay
2026-05-11  4:48 ` [PATCH v2 2/5] hwmon: (pmbus/adm1266) add clear_blackbox " Abdurrahman Hussain via B4 Relay
2026-05-12  0:03   ` sashiko-bot
2026-05-11  4:48 ` [PATCH v2 3/5] hwmon: (pmbus/adm1266) add powerup_counter " Abdurrahman Hussain via B4 Relay
2026-05-12  0:34   ` sashiko-bot
2026-05-11  4:48 ` [PATCH v2 4/5] hwmon: (pmbus/adm1266) replace probe-time RTC seed with rtc_class device Abdurrahman Hussain via B4 Relay
2026-05-12  1:12   ` sashiko-bot
2026-05-11  4:48 ` [PATCH v2 5/5] hwmon: (pmbus/adm1266) include adapter number in GPIO line label Abdurrahman Hussain via B4 Relay
2026-05-12  1:31   ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox