Linux Hardware Monitor development
 help / color / mirror / Atom feed
* [PATCH v3 0/8] misc: amd-sbi: Refactor SBTSI driver with I3C support and ioctl interface
@ 2026-06-22 13:58 Akshay Gupta
  2026-06-22 13:58 ` [PATCH v3 1/8] hwmon/misc: amd-sbi: Move core sbtsi support from hwmon to misc Akshay Gupta
                   ` (7 more replies)
  0 siblings, 8 replies; 18+ messages in thread
From: Akshay Gupta @ 2026-06-22 13:58 UTC (permalink / raw)
  To: linux-doc, linux-kernel, linux-hwmon
  Cc: corbet, skhan, linux, arnd, gregkh, NaveenKrishna.Chatradhi,
	Anand.Umarji, Akshay.Gupta, Prathima.Lk

This series refactors the AMD SB-TSI (Side-Band Temperature Sensor
Interface) driver by moving the core from the hwmon subsystem into the
drivers/misc/amd-sbi framework, alongside the existing SB-RMI driver.
Registers an auxiliary device keeping hwmon sensors functionality intact. 

Background:
The SB-TSI driver currently lives under drivers/hwmon/sbtsi_temp.c and
is limited to exposing temperature readings via the hwmon interface.
As AMD platforms evolve, SB-TSI access is required from multiple
consumers (hwmon, userspace via ioctl, I3C-attached devices), making
the hwmon-only placement insufficient.

This series restructures the driver into a layered design:

  - tsi-core.c   : core register access and ioctl/miscdevice support
  - tsi.c        : I2C/I3C probe and glue
  - sbtsi_temp.c : hwmon sensor layer built on top of the core using aux device

Changes in this series:
1. Move core SBTSI driver probe from drivers/hwmon into drivers/misc/amd-sbi,
   and registering an auxiliary device in core for hwmon subsystem probing

2. Register order follows the device ReadOrder bit so both parts latch atomically;
   limit registers (temp / temp1_max / temp1_min) use the same helpers instead of
   separate SMBus calls.

3. Move sbtsi register transfer to core abstraction to decouple the hwmon sensor
   driver from the underlying bus transport. Preparing for I3C support in a
   subsequent patch

4. Refactor I2C probe common functionality to new common helper function to prepare
   for I3C support

5. Extend the driver to support SB-TSI over I3C in addition to I2C.
   Both buses share the same core read/write path via sbtsi_xfer();
   the is_i3c flag selects the underlying transport at probe time.
   Backward compatibility with existing I2C deployments is maintained.

6. Add a miscdevice (/dev/sbtsi-<addr>) and an ioctl interface
   (SBTSI_IOCTL_REG_XFER_CMD) that allows root userspace to perform
   SB-TSI register read/write operations through the APML protocol,
   consistent with the existing SBRMI ioctl interface.

7. Add mutex for SBTSI read/write in hwmon to prevent race condition with IOCTL. 

8. Document the new SBTSI miscdevice and its ioctl in
   Documentation/misc-devices/amd-sbi.rst.

Testing:
Tested on AMD Genoa/Turin/Venice BMC platforms with both I2C and I3C-attached
SB-TSI targets. hwmon sysfs attributes (tempX_input, tempX_max, etc.)
and ioctl register transfers verified against hardware.

Prathima (8):
  hwmon/misc: amd-sbi: Move core sbtsi support from hwmon to misc
  hwmon: sbtsi_temp: Refactor temperature register access into helpers
  hwmon/misc: amd-sbi: Move sbtsi register transfer to core abstraction
  misc: amd-sbi: Consolidate Common SBTSI Probe Path for I2C and I3C
  misc: amd-sbi: Add support for SB-TSI over I3C
  misc: amd-sbi: Add SBTSI ioctl register transfer interface
  hwmon: Add mutex protecting for sbtsi read/write through hwmon
  docs: misc: amd-sbi: Document SBTSI userspace interface

 Documentation/misc-devices/amd-sbi.rst |  68 ++++++++
 drivers/hwmon/Kconfig                  |   2 +-
 drivers/hwmon/sbtsi_temp.c             | 152 ++++++++---------
 drivers/misc/amd-sbi/Kconfig           |  13 ++
 drivers/misc/amd-sbi/Makefile          |   3 +
 drivers/misc/amd-sbi/tsi-core.c        | 202 ++++++++++++++++++++++
 drivers/misc/amd-sbi/tsi-core.h        |  26 +++
 drivers/misc/amd-sbi/tsi.c             | 224 +++++++++++++++++++++++++
 include/linux/misc/tsi.h               |  71 ++++++++
 include/uapi/misc/amd-apml.h           |  23 +++
 10 files changed, 702 insertions(+), 82 deletions(-)
 create mode 100644 drivers/misc/amd-sbi/tsi-core.c
 create mode 100644 drivers/misc/amd-sbi/tsi-core.h
 create mode 100644 drivers/misc/amd-sbi/tsi.c
 create mode 100644 include/linux/misc/tsi.h

-- 
2.34.1


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

* [PATCH v3 1/8] hwmon/misc: amd-sbi: Move core sbtsi support from hwmon to misc
  2026-06-22 13:58 [PATCH v3 0/8] misc: amd-sbi: Refactor SBTSI driver with I3C support and ioctl interface Akshay Gupta
@ 2026-06-22 13:58 ` Akshay Gupta
  2026-06-22 14:12   ` sashiko-bot
  2026-06-22 13:58 ` [PATCH v3 2/8] hwmon: sbtsi_temp: Refactor temperature register access into helpers Akshay Gupta
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 18+ messages in thread
From: Akshay Gupta @ 2026-06-22 13:58 UTC (permalink / raw)
  To: linux-doc, linux-kernel, linux-hwmon
  Cc: corbet, skhan, linux, arnd, gregkh, NaveenKrishna.Chatradhi,
	Anand.Umarji, Akshay.Gupta, Prathima.Lk

From: Prathima <Prathima.Lk@amd.com>

Move SBTSI(Side-Band Temperature Sensor Interface) core functionality out
of the hwmon-only path and into drivers/misc/amd-sbi so it can be reused
by non-hwmon consumers.

I2C probe parsing is moved from drivers/hwmon/sbtsi_temp.c
into drivers/misc/amd-sbi/tsi.c under CONFIG_AMD_SBTSI. The core driver
stores struct sbtsi_data on the bus device and registers an auxiliary
device amd-sbtsi.temp-sensor.<addr> per target.

This split prepares the driver for additional interfaces while keeping
hwmon support in hwmon subsystem on top of common SBTSI core logic.

Reviewed-by: Akshay Gupta <Akshay.Gupta@amd.com>
Signed-off-by: Prathima <Prathima.Lk@amd.com>
---
Changes since v2:
- Change hwmon config symbol dependency, "depends on" to "select"
  as "depends on" could silently disable the hwmon driver
 
Changes since v1:
- Use auxiliary device to probe hwmon sensor instead of moving
  the hwmon functionality to misc subsystem. This change is as
  per feedback.

 drivers/hwmon/Kconfig         |   2 +-
 drivers/hwmon/sbtsi_temp.c    |  71 ++++--------------
 drivers/misc/amd-sbi/Kconfig  |  13 ++++
 drivers/misc/amd-sbi/Makefile |   3 +
 drivers/misc/amd-sbi/tsi.c    | 134 ++++++++++++++++++++++++++++++++++
 include/linux/misc/tsi.h      |  34 +++++++++
 6 files changed, 198 insertions(+), 59 deletions(-)
 create mode 100644 drivers/misc/amd-sbi/tsi.c
 create mode 100644 include/linux/misc/tsi.h

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index e4c4f2b09732..8f204cf49b6e 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1963,7 +1963,7 @@ config SENSORS_SL28CPLD
 
 config SENSORS_SBTSI
 	tristate "Emulated SB-TSI temperature sensor"
-	depends on I2C
+	select AMD_SBTSI
 	help
 	  If you say yes here you get support for emulated temperature
 	  sensors on AMD SoCs with SB-TSI interface connected to a BMC device.
diff --git a/drivers/hwmon/sbtsi_temp.c b/drivers/hwmon/sbtsi_temp.c
index c28f8625cd3a..28258bf49922 100644
--- a/drivers/hwmon/sbtsi_temp.c
+++ b/drivers/hwmon/sbtsi_temp.c
@@ -7,13 +7,12 @@
  * Copyright (c) 2020, Kun Yi <kunyi@google.com>
  */
 
+#include <linux/auxiliary_bus.h>
 #include <linux/err.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
 #include <linux/hwmon.h>
+#include <linux/init.h>
 #include <linux/module.h>
-#include <linux/of.h>
-#include <linux/bitfield.h>
+#include <linux/misc/tsi.h>
 
 /*
  * SB-TSI registers only support SMBus byte data access. "_INT" registers are
@@ -22,39 +21,17 @@
  */
 #define SBTSI_REG_TEMP_INT		0x01 /* RO */
 #define SBTSI_REG_STATUS		0x02 /* RO */
-#define SBTSI_REG_CONFIG		0x03 /* RO */
 #define SBTSI_REG_TEMP_HIGH_INT		0x07 /* RW */
 #define SBTSI_REG_TEMP_LOW_INT		0x08 /* RW */
 #define SBTSI_REG_TEMP_DEC		0x10 /* RW */
 #define SBTSI_REG_TEMP_HIGH_DEC		0x13 /* RW */
 #define SBTSI_REG_TEMP_LOW_DEC		0x14 /* RW */
 
-/*
- * Bit for reporting value with temperature measurement range.
- * bit == 0: Use default temperature range (0C to 255.875C).
- * bit == 1: Use extended temperature range (-49C to +206.875C).
- */
-#define SBTSI_CONFIG_EXT_RANGE_SHIFT	2
-/*
- * ReadOrder bit specifies the reading order of integer and decimal part of
- * CPU temperature for atomic reads. If bit == 0, reading integer part triggers
- * latching of the decimal part, so integer part should be read first.
- * If bit == 1, read order should be reversed.
- */
-#define SBTSI_CONFIG_READ_ORDER_SHIFT	5
-
 #define SBTSI_TEMP_EXT_RANGE_ADJ	49000
 
 #define SBTSI_TEMP_MIN	0
 #define SBTSI_TEMP_MAX	255875
 
-/* Each client has this additional data */
-struct sbtsi_data {
-	struct i2c_client *client;
-	bool ext_range_mode;
-	bool read_order;
-};
-
 /*
  * From SB-TSI spec: CPU temperature readings and limit registers encode the
  * temperature in increments of 0.125 from 0 to 255.875. The "high byte"
@@ -195,55 +172,33 @@ static const struct hwmon_chip_info sbtsi_chip_info = {
 	.info = sbtsi_info,
 };
 
-static int sbtsi_probe(struct i2c_client *client)
+static int sbtsi_probe(struct auxiliary_device *adev,
+		       const struct auxiliary_device_id *id)
 {
-	struct device *dev = &client->dev;
+	struct sbtsi_data *data = dev_get_drvdata(adev->dev.parent);
+	struct device *dev = &adev->dev;
 	struct device *hwmon_dev;
-	struct sbtsi_data *data;
-	int err;
 
-	data = devm_kzalloc(dev, sizeof(struct sbtsi_data), GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-
-	data->client = client;
-
-	err = i2c_smbus_read_byte_data(data->client, SBTSI_REG_CONFIG);
-	if (err < 0)
-		return err;
-	data->ext_range_mode = FIELD_GET(BIT(SBTSI_CONFIG_EXT_RANGE_SHIFT), err);
-	data->read_order = FIELD_GET(BIT(SBTSI_CONFIG_READ_ORDER_SHIFT), err);
-
-	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data,
+	hwmon_dev = devm_hwmon_device_register_with_info(dev, "sbtsi", data,
 							 &sbtsi_chip_info, NULL);
 
 	return PTR_ERR_OR_ZERO(hwmon_dev);
 }
 
-static const struct i2c_device_id sbtsi_id[] = {
-	{ .name = "sbtsi" },
+static const struct auxiliary_device_id sbtsi_id[] = {
+	{ .name = AMD_SBTSI_ADEV "." AMD_SBTSI_AUX_HWMON },
 	{ }
 };
-MODULE_DEVICE_TABLE(i2c, sbtsi_id);
+MODULE_DEVICE_TABLE(auxiliary, sbtsi_id);
 
-static const struct of_device_id __maybe_unused sbtsi_of_match[] = {
-	{
-		.compatible = "amd,sbtsi",
-	},
-	{ },
-};
-MODULE_DEVICE_TABLE(of, sbtsi_of_match);
-
-static struct i2c_driver sbtsi_driver = {
+static struct auxiliary_driver sbtsi_driver = {
 	.driver = {
 		.name = "sbtsi",
-		.of_match_table = of_match_ptr(sbtsi_of_match),
 	},
 	.probe = sbtsi_probe,
 	.id_table = sbtsi_id,
 };
-
-module_i2c_driver(sbtsi_driver);
+module_auxiliary_driver(sbtsi_driver);
 
 MODULE_AUTHOR("Kun Yi <kunyi@google.com>");
 MODULE_DESCRIPTION("Hwmon driver for AMD SB-TSI emulated sensor");
diff --git a/drivers/misc/amd-sbi/Kconfig b/drivers/misc/amd-sbi/Kconfig
index 30e7fad7356c..512251690e0e 100644
--- a/drivers/misc/amd-sbi/Kconfig
+++ b/drivers/misc/amd-sbi/Kconfig
@@ -20,3 +20,16 @@ config AMD_SBRMI_HWMON
 	  This provides support for RMI device hardware monitoring. If enabled,
 	  a hardware monitoring device will be created for each socket in
 	  the system.
+
+config AMD_SBTSI
+	tristate "AMD side band TSI support"
+	depends on I2C
+	depends on ARM || ARM64 || COMPILE_TEST
+	select AUXILIARY_BUS
+	help
+	  Enables support for the AMD SB-TSI (Side Band Temperature Sensor
+	  Interface) driver, which provides access to emulated CPU temperature
+	  sensors on AMD SoCs via an I2C connected BMC device.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called sbtsi.
diff --git a/drivers/misc/amd-sbi/Makefile b/drivers/misc/amd-sbi/Makefile
index 38eaaa651fd9..28f95b9e204f 100644
--- a/drivers/misc/amd-sbi/Makefile
+++ b/drivers/misc/amd-sbi/Makefile
@@ -2,3 +2,6 @@
 sbrmi-i2c-objs  		+= rmi-i2c.o rmi-core.o
 sbrmi-i2c-$(CONFIG_AMD_SBRMI_HWMON)	+= rmi-hwmon.o
 obj-$(CONFIG_AMD_SBRMI_I2C)	+= sbrmi-i2c.o
+# SBTSI Configuration
+sbtsi-objs	+= tsi.o
+obj-$(CONFIG_AMD_SBTSI)	+= sbtsi.o
diff --git a/drivers/misc/amd-sbi/tsi.c b/drivers/misc/amd-sbi/tsi.c
new file mode 100644
index 000000000000..dfdd730b906a
--- /dev/null
+++ b/drivers/misc/amd-sbi/tsi.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * tsi.c - AMD SBTSI I2C core driver. Probes the SBTSI device over I2C
+ *         and publishes an auxiliary device on the auxiliary bus.
+ *
+ * Copyright (C) 2026 Advanced Micro Devices, Inc.
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/bitfield.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/misc/tsi.h>
+#include <linux/slab.h>
+
+#define SBTSI_REG_CONFIG		0x03 /* RO */
+
+/*
+ * Bit for reporting value with temperature measurement range.
+ * bit == 0: Use default temperature range (0C to 255.875C).
+ * bit == 1: Use extended temperature range (-49C to +206.875C).
+ */
+#define SBTSI_CONFIG_EXT_RANGE_SHIFT	2
+
+/*
+ * ReadOrder bit specifies the reading order of integer and decimal part of
+ * CPU temperature for atomic reads. If bit == 0, reading integer part triggers
+ * latching of the decimal part, so integer part should be read first.
+ */
+#define SBTSI_CONFIG_READ_ORDER_SHIFT	5
+
+static void sbtsi_adev_release(struct device *dev)
+{
+	kfree(to_auxiliary_dev(dev));
+}
+
+static void sbtsi_unregister_hwmon_adev(void *_adev)
+{
+	struct auxiliary_device *adev = _adev;
+
+	auxiliary_device_delete(adev);
+	auxiliary_device_uninit(adev);
+}
+
+/*
+ * Create and publish an auxiliary device. The hwmon driver in
+ * drivers/hwmon/sbtsi_temp.c binds to this device.
+ *
+ * @dev:      I2C device (parent of the auxiliary device)
+ * @dev_addr: I2C address — used as the auxiliary device instance ID so that
+ *            each socket gets a unique name.
+ */
+static int sbtsi_create_hwmon_adev(struct device *dev, u8 dev_addr)
+{
+	struct auxiliary_device *adev;
+	int ret;
+
+	adev = kzalloc_obj(*adev);
+	if (!adev)
+		return -ENOMEM;
+
+	adev->name = AMD_SBTSI_AUX_HWMON;
+	/*
+	 * In a multi-socket system, otherwise identical devices do not
+	 * share the same static address; each instance has its own address,
+	 * which must be supplied via the device tree (DTS).
+	 */
+	adev->id = dev_addr;
+	adev->dev.parent = dev;
+	adev->dev.release = sbtsi_adev_release;
+
+	ret = auxiliary_device_init(adev);
+	if (ret) {
+		kfree(adev);
+		return ret;
+	}
+
+	ret = __auxiliary_device_add(adev, AMD_SBTSI_ADEV);
+	if (ret) {
+		auxiliary_device_uninit(adev);
+		return ret;
+	}
+
+	return devm_add_action_or_reset(dev, sbtsi_unregister_hwmon_adev, adev);
+}
+
+static int sbtsi_i2c_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct sbtsi_data *data;
+	int err;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	err = i2c_smbus_read_byte_data(data->client, SBTSI_REG_CONFIG);
+	if (err < 0)
+		return err;
+	data->ext_range_mode = FIELD_GET(BIT(SBTSI_CONFIG_EXT_RANGE_SHIFT), err);
+	data->read_order = FIELD_GET(BIT(SBTSI_CONFIG_READ_ORDER_SHIFT), err);
+
+	dev_set_drvdata(dev, data);
+	return sbtsi_create_hwmon_adev(dev, client->addr);
+}
+
+static const struct i2c_device_id sbtsi_id[] = {
+	{ .name = "sbtsi" },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, sbtsi_id);
+
+static const struct of_device_id __maybe_unused sbtsi_of_match[] = {
+	{
+		.compatible = "amd,sbtsi",
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, sbtsi_of_match);
+
+static struct i2c_driver sbtsi_driver = {
+	.driver = {
+		.name = "sbtsi-i2c",
+		.of_match_table = of_match_ptr(sbtsi_of_match),
+	},
+	.probe = sbtsi_i2c_probe,
+	.id_table = sbtsi_id,
+};
+
+module_i2c_driver(sbtsi_driver);
+
+MODULE_DESCRIPTION("AMD SB-TSI I2C core driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/misc/tsi.h b/include/linux/misc/tsi.h
new file mode 100644
index 000000000000..befdc2d14160
--- /dev/null
+++ b/include/linux/misc/tsi.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * AMD SBTSI shared data structure and auxiliary bus definitions.
+ *
+ * Copyright (C) 2026 Advanced Micro Devices, Inc.
+ */
+
+#ifndef _LINUX_MISC_TSI_H_
+#define _LINUX_MISC_TSI_H_
+
+#include <linux/i2c.h>
+#include <linux/types.h>
+
+/**
+ * struct sbtsi_data - driver private data for an AMD SB-TSI device
+ * @client:	underlying I2C client
+ * @ext_range_mode:	sensor uses extended temperature range
+ * @read_order:	if set, decimal part must be read before integer part
+ */
+struct sbtsi_data {
+	struct i2c_client *client;
+	bool ext_range_mode;
+	bool read_order;
+};
+
+/*
+ * Name of the auxiliary device published on the auxiliary bus by the core
+ * driver.  The full device name is "amd-sbtsi.temp-sensor.<id>". where
+ * <id> is the auxiliary device instance id.
+ */
+#define AMD_SBTSI_ADEV		"amd-sbtsi"
+#define AMD_SBTSI_AUX_HWMON	"temp-sensor"
+
+#endif /* _LINUX_MISC_TSI_H_ */
-- 
2.34.1


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

* [PATCH v3 2/8] hwmon: sbtsi_temp: Refactor temperature register access into helpers
  2026-06-22 13:58 [PATCH v3 0/8] misc: amd-sbi: Refactor SBTSI driver with I3C support and ioctl interface Akshay Gupta
  2026-06-22 13:58 ` [PATCH v3 1/8] hwmon/misc: amd-sbi: Move core sbtsi support from hwmon to misc Akshay Gupta
@ 2026-06-22 13:58 ` Akshay Gupta
  2026-06-22 14:11   ` sashiko-bot
  2026-06-22 13:58 ` [PATCH v3 3/8] hwmon/misc: amd-sbi: Move sbtsi register transfer to core abstraction Akshay Gupta
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 18+ messages in thread
From: Akshay Gupta @ 2026-06-22 13:58 UTC (permalink / raw)
  To: linux-doc, linux-kernel, linux-hwmon
  Cc: corbet, skhan, linux, arnd, gregkh, NaveenKrishna.Chatradhi,
	Anand.Umarji, Akshay.Gupta, Prathima.Lk

From: Prathima <Prathima.Lk@amd.com>

Extract the paired integer/decimal register reads and writes from the
hwmon read/write callbacks into sbtsi_temp_read() and sbtsi_temp_write()
helpers. This consolidates error handling and respects the ReadOrder bit
for atomic temperature latching.

This keeps register access independent while preserving existing hwmon
functionality.

Reviewed-by: Akshay Gupta <Akshay.Gupta@amd.com>
Signed-off-by: Prathima <Prathima.Lk@amd.com>
---
Changes since v1:
- New patch

 drivers/hwmon/sbtsi_temp.c | 84 +++++++++++++++++++++++++++-----------
 1 file changed, 61 insertions(+), 23 deletions(-)

diff --git a/drivers/hwmon/sbtsi_temp.c b/drivers/hwmon/sbtsi_temp.c
index 28258bf49922..078f4ab25bde 100644
--- a/drivers/hwmon/sbtsi_temp.c
+++ b/drivers/hwmon/sbtsi_temp.c
@@ -61,40 +61,82 @@ static inline void sbtsi_mc_to_reg(s32 temp, u8 *integer, u8 *decimal)
 	*decimal = (temp & 0x7) << 5;
 }
 
+/*
+ * Read integer and decimal parts of an SB-TSI temperature register pair
+ * The read order is determined by the ReadOrder bit to ensure atomic latching.
+ */
+static int sbtsi_temp_read(struct sbtsi_data *data, u8 reg1, u8 reg2,
+			   u8 *val1, u8 *val2)
+{
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(data->client, reg1);
+	if (ret < 0)
+		return ret;
+	*val1 = ret;
+	ret = i2c_smbus_read_byte_data(data->client, reg2);
+	if (ret < 0)
+		return ret;
+	*val2 = ret;
+	return 0;
+}
+
+/*
+ * Write integer and decimal parts of an SB-TSI temperature register pair.
+ */
+static int sbtsi_temp_write(struct sbtsi_data *data, u8 reg_int, u8 reg_dec,
+			    u8 val_int, u8 val_dec)
+{
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(data->client, reg_int, val_int);
+	if (!ret)
+		ret = i2c_smbus_write_byte_data(data->client, reg_dec, val_dec);
+	return ret;
+}
+
 static int sbtsi_read(struct device *dev, enum hwmon_sensor_types type,
 		      u32 attr, int channel, long *val)
 {
 	struct sbtsi_data *data = dev_get_drvdata(dev);
 	s32 temp_int, temp_dec;
+	int err;
+	u8 val_int, val_dec;
 
 	switch (attr) {
 	case hwmon_temp_input:
-		if (data->read_order) {
-			temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_DEC);
-			temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_INT);
-		} else {
-			temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_INT);
-			temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_DEC);
-		}
+		if (data->read_order)
+			err = sbtsi_temp_read(data,
+					      SBTSI_REG_TEMP_DEC, SBTSI_REG_TEMP_INT,
+					      &val_dec, &val_int);
+		else
+			err = sbtsi_temp_read(data,
+					      SBTSI_REG_TEMP_INT, SBTSI_REG_TEMP_DEC,
+					      &val_int, &val_dec);
+		if (err < 0)
+			return err;
 		break;
 	case hwmon_temp_max:
-		temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_HIGH_INT);
-		temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_HIGH_DEC);
+		err = sbtsi_temp_read(data,
+				      SBTSI_REG_TEMP_HIGH_INT, SBTSI_REG_TEMP_HIGH_DEC,
+				      &val_int, &val_dec);
+		if (err < 0)
+			return err;
 		break;
 	case hwmon_temp_min:
-		temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_LOW_INT);
-		temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_LOW_DEC);
+		err = sbtsi_temp_read(data,
+				      SBTSI_REG_TEMP_LOW_INT, SBTSI_REG_TEMP_LOW_DEC,
+				      &val_int, &val_dec);
+
+		if (err < 0)
+			return err;
 		break;
 	default:
 		return -EINVAL;
 	}
 
-
-	if (temp_int < 0)
-		return temp_int;
-	if (temp_dec < 0)
-		return temp_dec;
-
+	temp_int = val_int;
+	temp_dec = val_dec;
 	*val = sbtsi_reg_to_mc(temp_int, temp_dec);
 	if (data->ext_range_mode)
 		*val -= SBTSI_TEMP_EXT_RANGE_ADJ;
@@ -106,7 +148,7 @@ static int sbtsi_write(struct device *dev, enum hwmon_sensor_types type,
 		       u32 attr, int channel, long val)
 {
 	struct sbtsi_data *data = dev_get_drvdata(dev);
-	int reg_int, reg_dec, err;
+	int reg_int, reg_dec;
 	u8 temp_int, temp_dec;
 
 	switch (attr) {
@@ -127,11 +169,7 @@ static int sbtsi_write(struct device *dev, enum hwmon_sensor_types type,
 	val = clamp_val(val, SBTSI_TEMP_MIN, SBTSI_TEMP_MAX);
 	sbtsi_mc_to_reg(val, &temp_int, &temp_dec);
 
-	err = i2c_smbus_write_byte_data(data->client, reg_int, temp_int);
-	if (err)
-		return err;
-
-	return i2c_smbus_write_byte_data(data->client, reg_dec, temp_dec);
+	return sbtsi_temp_write(data, reg_int, reg_dec, temp_int, temp_dec);
 }
 
 static umode_t sbtsi_is_visible(const void *data,
-- 
2.34.1


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

* [PATCH v3 3/8] hwmon/misc: amd-sbi: Move sbtsi register transfer to core abstraction
  2026-06-22 13:58 [PATCH v3 0/8] misc: amd-sbi: Refactor SBTSI driver with I3C support and ioctl interface Akshay Gupta
  2026-06-22 13:58 ` [PATCH v3 1/8] hwmon/misc: amd-sbi: Move core sbtsi support from hwmon to misc Akshay Gupta
  2026-06-22 13:58 ` [PATCH v3 2/8] hwmon: sbtsi_temp: Refactor temperature register access into helpers Akshay Gupta
@ 2026-06-22 13:58 ` Akshay Gupta
  2026-06-22 14:18   ` sashiko-bot
  2026-06-22 13:58 ` [PATCH v3 4/8] misc: amd-sbi: Consolidate Common SBTSI Probe Path for I2C and I3C Akshay Gupta
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 18+ messages in thread
From: Akshay Gupta @ 2026-06-22 13:58 UTC (permalink / raw)
  To: linux-doc, linux-kernel, linux-hwmon
  Cc: corbet, skhan, linux, arnd, gregkh, NaveenKrishna.Chatradhi,
	Anand.Umarji, Akshay.Gupta, Prathima.Lk

From: Prathima <Prathima.Lk@amd.com>

Move the I2C read/write byte operations from the sbtsi hwmon driver into
a common sbtsi_xfer() function in tsi-core.c.
This decouples the hwmon sensor driver from the underlying bus transport,
preparing for I3C support in a subsequent patch.
This patch does not introduce any functional changes. The updates are
limited to code organization/cleanup and should not affect the runtime
behavior of the driver

Reviewed-by: Akshay Gupta <Akshay.Gupta@amd.com>
Signed-off-by: Prathima <Prathima.Lk@amd.com>
---
Changes since v2:
- Name change for header inclusion guard to misc specific 

Changes since v1:
- New patch
 drivers/hwmon/sbtsi_temp.c      | 17 ++++++-----------
 drivers/misc/amd-sbi/Makefile   |  2 +-
 drivers/misc/amd-sbi/tsi-core.c | 30 ++++++++++++++++++++++++++++++
 include/linux/misc/tsi.h        | 13 +++++++++++++
 4 files changed, 50 insertions(+), 12 deletions(-)
 create mode 100644 drivers/misc/amd-sbi/tsi-core.c

diff --git a/drivers/hwmon/sbtsi_temp.c b/drivers/hwmon/sbtsi_temp.c
index 078f4ab25bde..d7ae986d824c 100644
--- a/drivers/hwmon/sbtsi_temp.c
+++ b/drivers/hwmon/sbtsi_temp.c
@@ -70,15 +70,10 @@ static int sbtsi_temp_read(struct sbtsi_data *data, u8 reg1, u8 reg2,
 {
 	int ret;
 
-	ret = i2c_smbus_read_byte_data(data->client, reg1);
-	if (ret < 0)
-		return ret;
-	*val1 = ret;
-	ret = i2c_smbus_read_byte_data(data->client, reg2);
-	if (ret < 0)
-		return ret;
-	*val2 = ret;
-	return 0;
+	ret = sbtsi_xfer(data, reg1, val1, true);
+	if (!ret)
+		ret = sbtsi_xfer(data, reg2, val2, true);
+	return ret;
 }
 
 /*
@@ -89,9 +84,9 @@ static int sbtsi_temp_write(struct sbtsi_data *data, u8 reg_int, u8 reg_dec,
 {
 	int ret;
 
-	ret = i2c_smbus_write_byte_data(data->client, reg_int, val_int);
+	ret = sbtsi_xfer(data, reg_int, &val_int, false);
 	if (!ret)
-		ret = i2c_smbus_write_byte_data(data->client, reg_dec, val_dec);
+		ret = sbtsi_xfer(data, reg_dec, &val_dec, false);
 	return ret;
 }
 
diff --git a/drivers/misc/amd-sbi/Makefile b/drivers/misc/amd-sbi/Makefile
index 28f95b9e204f..ce9321f5c601 100644
--- a/drivers/misc/amd-sbi/Makefile
+++ b/drivers/misc/amd-sbi/Makefile
@@ -3,5 +3,5 @@ sbrmi-i2c-objs  		+= rmi-i2c.o rmi-core.o
 sbrmi-i2c-$(CONFIG_AMD_SBRMI_HWMON)	+= rmi-hwmon.o
 obj-$(CONFIG_AMD_SBRMI_I2C)	+= sbrmi-i2c.o
 # SBTSI Configuration
-sbtsi-objs	+= tsi.o
+sbtsi-objs	+= tsi.o tsi-core.o
 obj-$(CONFIG_AMD_SBTSI)	+= sbtsi.o
diff --git a/drivers/misc/amd-sbi/tsi-core.c b/drivers/misc/amd-sbi/tsi-core.c
new file mode 100644
index 000000000000..6ef1831515bb
--- /dev/null
+++ b/drivers/misc/amd-sbi/tsi-core.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * tsi-core.c - file defining SB-TSI protocols compliant
+ *              AMD SoC device.
+ *
+ * Copyright (C) 2026 Advanced Micro Devices, Inc.
+ */
+
+#include <linux/module.h>
+#include <linux/misc/tsi.h>
+
+/* I2C transfer function */
+static int sbtsi_i2c_xfer(struct sbtsi_data *data, u8 reg, u8 *val, bool is_read)
+{
+	if (is_read) {
+		int ret = i2c_smbus_read_byte_data(data->client, reg);
+
+		if (ret < 0)
+			return ret;
+		*val = ret;
+		return 0;
+	}
+	return i2c_smbus_write_byte_data(data->client, reg, *val);
+}
+
+int sbtsi_xfer(struct sbtsi_data *data, u8 reg, u8 *val, bool is_read)
+{
+	return sbtsi_i2c_xfer(data, reg, val, is_read);
+}
+EXPORT_SYMBOL_GPL(sbtsi_xfer);
diff --git a/include/linux/misc/tsi.h b/include/linux/misc/tsi.h
index befdc2d14160..2d2709f1ff32 100644
--- a/include/linux/misc/tsi.h
+++ b/include/linux/misc/tsi.h
@@ -31,4 +31,17 @@ struct sbtsi_data {
 #define AMD_SBTSI_ADEV		"amd-sbtsi"
 #define AMD_SBTSI_AUX_HWMON	"temp-sensor"
 
+/**
+ * sbtsi_xfer - Perform a register read or write transfer on an AMD SB-TSI device.
+ *
+ * @data:    Pointer to the sbtsi_data structure containing the device context
+ * @reg:     Register address to access.
+ * @val:     Pointer to the value to read into or write from.
+ * @is_read: If true, performs a read transfer and stores the result in @val.
+ *           If false, performs a write transfer using the value in @val.
+ *
+ * Returns 0 on success, or a negative error code on failure.
+ */
+int sbtsi_xfer(struct sbtsi_data *data, u8 reg, u8 *val, bool is_read);
+
 #endif /* _LINUX_MISC_TSI_H_ */
-- 
2.34.1


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

* [PATCH v3 4/8] misc: amd-sbi: Consolidate Common SBTSI Probe Path for I2C and I3C
  2026-06-22 13:58 [PATCH v3 0/8] misc: amd-sbi: Refactor SBTSI driver with I3C support and ioctl interface Akshay Gupta
                   ` (2 preceding siblings ...)
  2026-06-22 13:58 ` [PATCH v3 3/8] hwmon/misc: amd-sbi: Move sbtsi register transfer to core abstraction Akshay Gupta
@ 2026-06-22 13:58 ` Akshay Gupta
  2026-06-22 14:11   ` sashiko-bot
  2026-06-22 13:58 ` [PATCH v3 5/8] misc: amd-sbi: Add support for SB-TSI over I3C Akshay Gupta
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 18+ messages in thread
From: Akshay Gupta @ 2026-06-22 13:58 UTC (permalink / raw)
  To: linux-doc, linux-kernel, linux-hwmon
  Cc: corbet, skhan, linux, arnd, gregkh, NaveenKrishna.Chatradhi,
	Anand.Umarji, Akshay.Gupta, Prathima.Lk

From: Prathima <Prathima.Lk@amd.com>

Refactor shared probe procedures into sbtsi_probe_common() to ensure
that I2C and I3C probes focus solely on bus-specific allocation and
device configuration.
The utility function reads the configuration register via sbtsi_xfer(),
initializes ext_range_mode and read_order, assigns the driver data,
and registers the hwmon auxiliary device.
Utilizing sbtsi_xfer() for both buses eliminates the need to duplicate
the I2C SMBus and I3C transfer paths within tsi.c.

Reviewed-by: Akshay Gupta <Akshay.Gupta@amd.com>
Signed-off-by: Prathima <Prathima.Lk@amd.com>
---
Changes since v2:
- New patch to refactor SBTSI common probe

 drivers/misc/amd-sbi/tsi.c | 26 ++++++++++++++++++--------
 include/linux/misc/tsi.h   |  2 ++
 2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/drivers/misc/amd-sbi/tsi.c b/drivers/misc/amd-sbi/tsi.c
index dfdd730b906a..a4c7e1be5624 100644
--- a/drivers/misc/amd-sbi/tsi.c
+++ b/drivers/misc/amd-sbi/tsi.c
@@ -84,25 +84,35 @@ static int sbtsi_create_hwmon_adev(struct device *dev, u8 dev_addr)
 	return devm_add_action_or_reset(dev, sbtsi_unregister_hwmon_adev, adev);
 }
 
+static int sbtsi_probe_common(struct device *dev, struct sbtsi_data *data)
+{
+	u8 val;
+	int err;
+
+	err = sbtsi_xfer(data, SBTSI_REG_CONFIG, &val, true);
+	if (err)
+		return err;
+
+	data->ext_range_mode = FIELD_GET(BIT(SBTSI_CONFIG_EXT_RANGE_SHIFT), val);
+	data->read_order = FIELD_GET(BIT(SBTSI_CONFIG_READ_ORDER_SHIFT), val);
+
+	dev_set_drvdata(dev, data);
+	return sbtsi_create_hwmon_adev(dev, data->dev_addr);
+}
+
 static int sbtsi_i2c_probe(struct i2c_client *client)
 {
 	struct device *dev = &client->dev;
 	struct sbtsi_data *data;
-	int err;
 
 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
 	data->client = client;
-	err = i2c_smbus_read_byte_data(data->client, SBTSI_REG_CONFIG);
-	if (err < 0)
-		return err;
-	data->ext_range_mode = FIELD_GET(BIT(SBTSI_CONFIG_EXT_RANGE_SHIFT), err);
-	data->read_order = FIELD_GET(BIT(SBTSI_CONFIG_READ_ORDER_SHIFT), err);
+	data->dev_addr = client->addr;
 
-	dev_set_drvdata(dev, data);
-	return sbtsi_create_hwmon_adev(dev, client->addr);
+	return sbtsi_probe_common(dev, data);
 }
 
 static const struct i2c_device_id sbtsi_id[] = {
diff --git a/include/linux/misc/tsi.h b/include/linux/misc/tsi.h
index 2d2709f1ff32..55ee7e42a65d 100644
--- a/include/linux/misc/tsi.h
+++ b/include/linux/misc/tsi.h
@@ -14,11 +14,13 @@
 /**
  * struct sbtsi_data - driver private data for an AMD SB-TSI device
  * @client:	underlying I2C client
+ * @dev_addr:	I2C device address, used to name the misc device node
  * @ext_range_mode:	sensor uses extended temperature range
  * @read_order:	if set, decimal part must be read before integer part
  */
 struct sbtsi_data {
 	struct i2c_client *client;
+	u8 dev_addr;
 	bool ext_range_mode;
 	bool read_order;
 };
-- 
2.34.1


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

* [PATCH v3 5/8] misc: amd-sbi: Add support for SB-TSI over I3C
  2026-06-22 13:58 [PATCH v3 0/8] misc: amd-sbi: Refactor SBTSI driver with I3C support and ioctl interface Akshay Gupta
                   ` (3 preceding siblings ...)
  2026-06-22 13:58 ` [PATCH v3 4/8] misc: amd-sbi: Consolidate Common SBTSI Probe Path for I2C and I3C Akshay Gupta
@ 2026-06-22 13:58 ` Akshay Gupta
  2026-06-22 14:19   ` sashiko-bot
  2026-06-22 13:58 ` [PATCH v3 6/8] misc: amd-sbi: Add SBTSI ioctl register transfer interface Akshay Gupta
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 18+ messages in thread
From: Akshay Gupta @ 2026-06-22 13:58 UTC (permalink / raw)
  To: linux-doc, linux-kernel, linux-hwmon
  Cc: corbet, skhan, linux, arnd, gregkh, NaveenKrishna.Chatradhi,
	Anand.Umarji, Akshay.Gupta, Prathima.Lk

From: Prathima <Prathima.Lk@amd.com>

AMD SB-TSI temperature sensors can be accessed over both
I2C and I3C buses depending on the platform configuration.
Extend the SB-TSI driver to support both I2C and I3C bus interfaces
by selecting the appropriate transport based on the probed bus type.
The driver maintains backward compatibility with existing I2C
deployments while enabling support for systems using the I3C bus.
Register both I2C and I3C drivers using module_i3c_i2c_driver() and
update the Kconfig dependency from I2C to I3C_OR_I2C.

Reviewed-by: Akshay Gupta <Akshay.Gupta@amd.com>
Signed-off-by: Prathima <Prathima.Lk@amd.com>
---
Changes since v2:
- Fix DMA mapping issue to prevent memory corruption or kernel panics
when CONFIG_VMAP_STACK is enabled
- Use i3c_device_get_info() to populate i3c_device_info structure fields
- Remove unused header file inclusion from "include/linux/misc/tsi.h"

Changes since v1:
- Changes in accordance with usage of auxiliary device

 drivers/misc/amd-sbi/Kconfig    |  4 +--
 drivers/misc/amd-sbi/tsi-core.c | 58 ++++++++++++++++++++++++++++++++-
 drivers/misc/amd-sbi/tsi-core.h | 23 +++++++++++++
 drivers/misc/amd-sbi/tsi.c      | 58 ++++++++++++++++++++++++++++++---
 include/linux/misc/tsi.h        | 11 +++++--
 5 files changed, 145 insertions(+), 9 deletions(-)
 create mode 100644 drivers/misc/amd-sbi/tsi-core.h

diff --git a/drivers/misc/amd-sbi/Kconfig b/drivers/misc/amd-sbi/Kconfig
index 512251690e0e..1a96b71f8506 100644
--- a/drivers/misc/amd-sbi/Kconfig
+++ b/drivers/misc/amd-sbi/Kconfig
@@ -23,13 +23,13 @@ config AMD_SBRMI_HWMON
 
 config AMD_SBTSI
 	tristate "AMD side band TSI support"
-	depends on I2C
+	depends on I3C_OR_I2C
 	depends on ARM || ARM64 || COMPILE_TEST
 	select AUXILIARY_BUS
 	help
 	  Enables support for the AMD SB-TSI (Side Band Temperature Sensor
 	  Interface) driver, which provides access to emulated CPU temperature
-	  sensors on AMD SoCs via an I2C connected BMC device.
+	  sensors on AMD SoCs via an I2C/I3C connected BMC device.
 
 	  This driver can also be built as a module. If so, the module will
 	  be called sbtsi.
diff --git a/drivers/misc/amd-sbi/tsi-core.c b/drivers/misc/amd-sbi/tsi-core.c
index 6ef1831515bb..9278d06d8e5f 100644
--- a/drivers/misc/amd-sbi/tsi-core.c
+++ b/drivers/misc/amd-sbi/tsi-core.c
@@ -7,7 +7,17 @@
  */
 
 #include <linux/module.h>
-#include <linux/misc/tsi.h>
+#include "tsi-core.h"
+
+static inline struct sbtsi_i3c_priv *to_sbtsi_i3c_priv(struct sbtsi_data *data)
+{
+	return container_of(data, struct sbtsi_i3c_priv, data);
+}
+
+static u8 *sbtsi_i3c_buf(struct sbtsi_data *data)
+{
+	return to_sbtsi_i3c_priv(data)->buf;
+}
 
 /* I2C transfer function */
 static int sbtsi_i2c_xfer(struct sbtsi_data *data, u8 reg, u8 *val, bool is_read)
@@ -23,8 +33,54 @@ static int sbtsi_i2c_xfer(struct sbtsi_data *data, u8 reg, u8 *val, bool is_read
 	return i2c_smbus_write_byte_data(data->client, reg, *val);
 }
 
+/* I3C read transfer function */
+static int sbtsi_i3c_read(struct sbtsi_data *data, u8 reg, u8 *val)
+{
+	struct i3c_xfer xfers[2] = { };
+	u8 *buf = sbtsi_i3c_buf(data);
+	int ret;
+
+	buf[0] = reg;
+	/* Add Register data to read/write */
+	xfers[0].rnw = false;
+	xfers[0].len = 1;
+	xfers[0].data.out = &buf[0];
+
+	xfers[1].rnw = true;
+	xfers[1].len = 1;
+	xfers[1].data.in = &buf[1];
+
+	ret = i3c_device_do_xfers(data->i3cdev, xfers, 2, I3C_SDR);
+	if (ret)
+		return ret;
+
+	*val = buf[1];
+	return ret;
+}
+
+/* I3C write transfer function */
+static int sbtsi_i3c_write(struct sbtsi_data *data, u8 reg, u8 val)
+{
+	u8 *buf = sbtsi_i3c_buf(data);
+	struct i3c_xfer xfers = {
+		.rnw = false,
+		.len = 2,
+		.data.out = buf,
+	};
+
+	buf[0] = reg;
+	buf[1] = val;
+
+	return i3c_device_do_xfers(data->i3cdev, &xfers, 1, I3C_SDR);
+}
+
+/* Unified transfer function for I2C and I3C access */
 int sbtsi_xfer(struct sbtsi_data *data, u8 reg, u8 *val, bool is_read)
 {
+	if (data->is_i3c)
+		return is_read ? sbtsi_i3c_read(data, reg, val)
+			       : sbtsi_i3c_write(data, reg, *val);
+
 	return sbtsi_i2c_xfer(data, reg, val, is_read);
 }
 EXPORT_SYMBOL_GPL(sbtsi_xfer);
diff --git a/drivers/misc/amd-sbi/tsi-core.h b/drivers/misc/amd-sbi/tsi-core.h
new file mode 100644
index 000000000000..7dde040caf30
--- /dev/null
+++ b/drivers/misc/amd-sbi/tsi-core.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * AMD SBTSI core driver private definitions.
+ *
+ * Copyright (C) 2026 Advanced Micro Devices, Inc.
+ */
+
+#ifndef _LINUX_TSI_CORE_H_
+#define _LINUX_TSI_CORE_H_
+
+#include <linux/misc/tsi.h>
+
+/**
+ * struct sbtsi_i3c_priv - per-device state for I3C SBTSI (includes DMA-safe buffers)
+ * @data: public device state exposed via dev_set_drvdata()
+ * @buf:  I3C transfer buffer; [0] register address, [1] data byte
+ */
+struct sbtsi_i3c_priv {
+	struct sbtsi_data data;
+	u8 buf[2];
+};
+
+#endif /* _LINUX_TSI_CORE_H_ */
diff --git a/drivers/misc/amd-sbi/tsi.c b/drivers/misc/amd-sbi/tsi.c
index a4c7e1be5624..8fb17ccab73d 100644
--- a/drivers/misc/amd-sbi/tsi.c
+++ b/drivers/misc/amd-sbi/tsi.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * tsi.c - AMD SBTSI I2C core driver. Probes the SBTSI device over I2C
+ * tsi.c - AMD SBTSI I2C/I3C core driver. Probes the SBTSI device over I2C/I3C
  *         and publishes an auxiliary device on the auxiliary bus.
  *
  * Copyright (C) 2026 Advanced Micro Devices, Inc.
@@ -10,8 +10,8 @@
 #include <linux/bitfield.h>
 #include <linux/module.h>
 #include <linux/of.h>
-#include <linux/misc/tsi.h>
 #include <linux/slab.h>
+#include "tsi-core.h"
 
 #define SBTSI_REG_CONFIG		0x03 /* RO */
 
@@ -109,6 +109,7 @@ static int sbtsi_i2c_probe(struct i2c_client *client)
 	if (!data)
 		return -ENOMEM;
 
+	data->is_i3c = false;
 	data->client = client;
 	data->dev_addr = client->addr;
 
@@ -138,7 +139,56 @@ static struct i2c_driver sbtsi_driver = {
 	.id_table = sbtsi_id,
 };
 
-module_i2c_driver(sbtsi_driver);
+static int sbtsi_i3c_probe(struct i3c_device *i3cdev)
+{
+	struct device *dev = i3cdev_to_dev(i3cdev);
+	struct i3c_device_info devinfo;
+	struct sbtsi_i3c_priv *i3c_priv;
+	struct sbtsi_data *data;
+
+	/*
+	 * AMD OOB devices differ on basis of Instance ID,
+	 * for SBTSI, instance ID is 0.
+	 * As the device Id match is not on basis of Instance ID,
+	 * add the below check to probe the SBTSI device only and
+	 * not other OOB devices.
+	 */
+	i3c_device_get_info(i3cdev, &devinfo);
+	if (I3C_PID_INSTANCE_ID(devinfo.pid) != 0)
+		return -ENXIO;
+
+	i3c_priv = devm_kzalloc(dev, sizeof(*i3c_priv), GFP_KERNEL);
+	if (!i3c_priv)
+		return -ENOMEM;
+
+	data = &i3c_priv->data;
+	data->i3cdev = i3cdev;
+	data->is_i3c = true;
+	data->dev_addr = devinfo.dyn_addr;
+
+	return sbtsi_probe_common(dev, data);
+}
+
+static const struct i3c_device_id sbtsi_i3c_id[] = {
+	/* PID for AMD SBTSI device */
+	I3C_DEVICE_EXTRA_INFO(0x112, 0x0, 0x1, NULL),	/* Socket:0, Turin and Genoa */
+	I3C_DEVICE_EXTRA_INFO(0x0, 0x0, 0x118, NULL),	/* Socket:0, Venice */
+	I3C_DEVICE_EXTRA_INFO(0x0, 0x100, 0x118, NULL),	/* Socket:1, Venice */
+	I3C_DEVICE_EXTRA_INFO(0x112, 0x0, 0x119, NULL),	/* Socket:0, Venice */
+	I3C_DEVICE_EXTRA_INFO(0x112, 0x100, 0x119, NULL),	/* Socket:1, Venice */
+	{}
+};
+MODULE_DEVICE_TABLE(i3c, sbtsi_i3c_id);
+
+static struct i3c_driver sbtsi_i3c_driver = {
+	.driver = {
+		.name = "sbtsi-i3c",
+	},
+	.probe = sbtsi_i3c_probe,
+	.id_table = sbtsi_i3c_id,
+};
+
+module_i3c_i2c_driver(sbtsi_i3c_driver, &sbtsi_driver);
 
-MODULE_DESCRIPTION("AMD SB-TSI I2C core driver");
+MODULE_DESCRIPTION("AMD SB-TSI I2C/I3C core driver");
 MODULE_LICENSE("GPL");
diff --git a/include/linux/misc/tsi.h b/include/linux/misc/tsi.h
index 55ee7e42a65d..02c90ec285ec 100644
--- a/include/linux/misc/tsi.h
+++ b/include/linux/misc/tsi.h
@@ -9,20 +9,27 @@
 #define _LINUX_MISC_TSI_H_
 
 #include <linux/i2c.h>
+#include <linux/i3c/device.h>
 #include <linux/types.h>
 
 /**
  * struct sbtsi_data - driver private data for an AMD SB-TSI device
  * @client:	underlying I2C client
- * @dev_addr:	I2C device address, used to name the misc device node
+ * @i3cdev:	underlying I3C device (when using I3C bus)
+ * @dev_addr:	I2C/I3C device address, used to name the misc device node
  * @ext_range_mode:	sensor uses extended temperature range
  * @read_order:	if set, decimal part must be read before integer part
+ * @is_i3c:	true when the device is accessed over I3C
  */
 struct sbtsi_data {
-	struct i2c_client *client;
+	union {
+		struct i2c_client *client;
+		struct i3c_device *i3cdev;
+	};
 	u8 dev_addr;
 	bool ext_range_mode;
 	bool read_order;
+	bool is_i3c;
 };
 
 /*
-- 
2.34.1


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

* [PATCH v3 6/8] misc: amd-sbi: Add SBTSI ioctl register transfer interface
  2026-06-22 13:58 [PATCH v3 0/8] misc: amd-sbi: Refactor SBTSI driver with I3C support and ioctl interface Akshay Gupta
                   ` (4 preceding siblings ...)
  2026-06-22 13:58 ` [PATCH v3 5/8] misc: amd-sbi: Add support for SB-TSI over I3C Akshay Gupta
@ 2026-06-22 13:58 ` Akshay Gupta
  2026-06-22 14:15   ` sashiko-bot
  2026-06-22 13:58 ` [PATCH v3 7/8] hwmon: Add mutex protecting for sbtsi read/write through hwmon Akshay Gupta
  2026-06-22 13:58 ` [PATCH v3 8/8] docs: misc: amd-sbi: Document SBTSI userspace interface Akshay Gupta
  7 siblings, 1 reply; 18+ messages in thread
From: Akshay Gupta @ 2026-06-22 13:58 UTC (permalink / raw)
  To: linux-doc, linux-kernel, linux-hwmon
  Cc: corbet, skhan, linux, arnd, gregkh, NaveenKrishna.Chatradhi,
	Anand.Umarji, Akshay.Gupta, Prathima.Lk

From: Prathima <Prathima.Lk@amd.com>

Implement IOCTL interface for SB-TSI driver to enable userspace access
to TSI register read/write operations through the AMD Advanced Platform
Management Link (APML) protocol.
Add an ioctl command (SBTSI_IOCTL_REG_XFER_CMD) that accepts a register
address, data byte, and direction flag. Serialize access with a mutex
shared between the hwmon and ioctl paths to prevent concurrent bus
transactions from corrupting register state.

Reviewed-by: Akshay Gupta <Akshay.Gupta@amd.com>
Signed-off-by: Prathima <Prathima.Lk@amd.com>
---
Changes since v2:
- Address feedback to hide mutex with common guard function
- Separate out mutex patch in hwmon file to next patch, 7/8
- Use file operation, open/release and kref to prevent use-after-free
  if the device is unbound in IOCTL
- Add check for msg.pad
 
Changes since v1:
- Use of devm_mutex_init in place of mutex_init
- Use of guard_mutex in place of mutex_lock()/mutex_unlock()
- Use of devm_add_action_or_reset() for clean removal
 drivers/misc/amd-sbi/tsi-core.c | 118 +++++++++++++++++++++++++++++++-
 drivers/misc/amd-sbi/tsi-core.h |   3 +
 drivers/misc/amd-sbi/tsi.c      |  36 +++++++++-
 include/linux/misc/tsi.h        |  15 ++++
 include/uapi/misc/amd-apml.h    |  23 +++++++
 5 files changed, 191 insertions(+), 4 deletions(-)

diff --git a/drivers/misc/amd-sbi/tsi-core.c b/drivers/misc/amd-sbi/tsi-core.c
index 9278d06d8e5f..688b9221868f 100644
--- a/drivers/misc/amd-sbi/tsi-core.c
+++ b/drivers/misc/amd-sbi/tsi-core.c
@@ -6,7 +6,11 @@
  * Copyright (C) 2026 Advanced Micro Devices, Inc.
  */
 
+#include <linux/fs.h>
+#include <linux/ioctl.h>
 #include <linux/module.h>
+#include <linux/uaccess.h>
+#include <uapi/misc/amd-apml.h>
 #include "tsi-core.h"
 
 static inline struct sbtsi_i3c_priv *to_sbtsi_i3c_priv(struct sbtsi_data *data)
@@ -19,6 +23,17 @@ static u8 *sbtsi_i3c_buf(struct sbtsi_data *data)
 	return to_sbtsi_i3c_priv(data)->buf;
 }
 
+void sbtsi_data_release(struct kref *kref)
+{
+	struct sbtsi_data *data = container_of(kref, struct sbtsi_data, kref);
+
+	mutex_destroy(&data->lock);
+	if (data->is_i3c)
+		kfree(to_sbtsi_i3c_priv(data));
+	else
+		kfree(data);
+}
+
 /* I2C transfer function */
 static int sbtsi_i2c_xfer(struct sbtsi_data *data, u8 reg, u8 *val, bool is_read)
 {
@@ -80,7 +95,108 @@ int sbtsi_xfer(struct sbtsi_data *data, u8 reg, u8 *val, bool is_read)
 	if (data->is_i3c)
 		return is_read ? sbtsi_i3c_read(data, reg, val)
 			       : sbtsi_i3c_write(data, reg, *val);
-
 	return sbtsi_i2c_xfer(data, reg, val, is_read);
 }
 EXPORT_SYMBOL_GPL(sbtsi_xfer);
+
+/*
+ * The mutex protects against concurrent access to the shared I2C/I3C bus by
+ * the hwmon sysfs and a userspace ioctl.
+ */
+static int sbtsi_xfer_ioctl(struct sbtsi_data *data, u8 reg, u8 *val, bool is_read)
+{
+	guard(sbtsi)(data);
+	return sbtsi_xfer(data, reg, val, is_read);
+}
+
+static int apml_tsi_reg_xfer(struct sbtsi_data *data,
+			     struct apml_tsi_xfer_msg __user *arg)
+{
+	struct apml_tsi_xfer_msg msg = { 0 };
+	int ret;
+
+	if (data->detached)
+		return -ENODEV;
+
+	if (copy_from_user(&msg, arg, sizeof(struct apml_tsi_xfer_msg)))
+		return -EFAULT;
+
+	if (msg.pad)
+		return -EINVAL;
+
+	ret = sbtsi_xfer_ioctl(data, msg.reg_addr, &msg.data_in_out, msg.rflag);
+
+	if (msg.rflag && !ret) {
+		if (copy_to_user(arg, &msg, sizeof(struct apml_tsi_xfer_msg)))
+			return -EFAULT;
+	}
+	return ret;
+}
+
+static int sbtsi_open(struct inode *inode, struct file *fp)
+{
+	struct sbtsi_data *data;
+
+	data = container_of(fp->private_data, struct sbtsi_data, sbtsi_misc_dev);
+	if (data->detached)
+		return -ENODEV;
+
+	kref_get(&data->kref);
+
+	return 0;
+}
+
+static int sbtsi_release(struct inode *inode, struct file *fp)
+{
+	struct sbtsi_data *data;
+
+	data = container_of(fp->private_data, struct sbtsi_data, sbtsi_misc_dev);
+	kref_put(&data->kref, sbtsi_data_release);
+	return 0;
+}
+
+static long sbtsi_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	struct sbtsi_data *data;
+
+	data = container_of(fp->private_data, struct sbtsi_data, sbtsi_misc_dev);
+	switch (cmd) {
+	case SBTSI_IOCTL_REG_XFER_CMD:
+		return apml_tsi_reg_xfer(data, argp);
+	default:
+		return -ENOTTY;
+	}
+}
+
+static const struct file_operations sbtsi_fops = {
+	.owner		= THIS_MODULE,
+	.open		= sbtsi_open,
+	.release	= sbtsi_release,
+	.unlocked_ioctl	= sbtsi_ioctl,
+	.compat_ioctl	= compat_ptr_ioctl,
+};
+
+int create_misc_tsi_device(struct sbtsi_data *data, struct device *dev)
+{
+	int ret;
+
+	data->sbtsi_misc_dev.name = devm_kasprintf(dev, GFP_KERNEL,
+						   "sbtsi-%x", data->dev_addr);
+	if (!data->sbtsi_misc_dev.name)
+		return -ENOMEM;
+	data->sbtsi_misc_dev.minor    = MISC_DYNAMIC_MINOR;
+	data->sbtsi_misc_dev.fops     = &sbtsi_fops;
+	data->sbtsi_misc_dev.parent   = dev;
+	data->sbtsi_misc_dev.nodename = devm_kasprintf(dev, GFP_KERNEL,
+						       "sbtsi-%x", data->dev_addr);
+	if (!data->sbtsi_misc_dev.nodename)
+		return -ENOMEM;
+	data->sbtsi_misc_dev.mode = 0600;
+
+	ret = misc_register(&data->sbtsi_misc_dev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
diff --git a/drivers/misc/amd-sbi/tsi-core.h b/drivers/misc/amd-sbi/tsi-core.h
index 7dde040caf30..c0849c704c7b 100644
--- a/drivers/misc/amd-sbi/tsi-core.h
+++ b/drivers/misc/amd-sbi/tsi-core.h
@@ -20,4 +20,7 @@ struct sbtsi_i3c_priv {
 	u8 buf[2];
 };
 
+int create_misc_tsi_device(struct sbtsi_data *data, struct device *dev);
+
+void sbtsi_data_release(struct kref *kref);
 #endif /* _LINUX_TSI_CORE_H_ */
diff --git a/drivers/misc/amd-sbi/tsi.c b/drivers/misc/amd-sbi/tsi.c
index 8fb17ccab73d..6649cd8cdf85 100644
--- a/drivers/misc/amd-sbi/tsi.c
+++ b/drivers/misc/amd-sbi/tsi.c
@@ -42,6 +42,21 @@ static void sbtsi_unregister_hwmon_adev(void *_adev)
 	auxiliary_device_uninit(adev);
 }
 
+static void sbtsi_misc_unregister(void *arg)
+{
+	struct sbtsi_data *data = arg;
+
+	misc_deregister(&data->sbtsi_misc_dev);
+	data->detached = true;
+}
+
+static void sbtsi_driver_unref(void *arg)
+{
+	struct sbtsi_data *data = arg;
+
+	kref_put(&data->kref, sbtsi_data_release);
+}
+
 /*
  * Create and publish an auxiliary device. The hwmon driver in
  * drivers/hwmon/sbtsi_temp.c binds to this device.
@@ -89,6 +104,13 @@ static int sbtsi_probe_common(struct device *dev, struct sbtsi_data *data)
 	u8 val;
 	int err;
 
+	mutex_init(&data->lock);
+	kref_init(&data->kref);
+
+	err = devm_add_action_or_reset(dev, sbtsi_driver_unref, data);
+	if (err)
+		return err;
+
 	err = sbtsi_xfer(data, SBTSI_REG_CONFIG, &val, true);
 	if (err)
 		return err;
@@ -97,7 +119,15 @@ static int sbtsi_probe_common(struct device *dev, struct sbtsi_data *data)
 	data->read_order = FIELD_GET(BIT(SBTSI_CONFIG_READ_ORDER_SHIFT), val);
 
 	dev_set_drvdata(dev, data);
-	return sbtsi_create_hwmon_adev(dev, data->dev_addr);
+	err = sbtsi_create_hwmon_adev(dev, data->dev_addr);
+	if (err < 0)
+		return err;
+
+	err = create_misc_tsi_device(data, dev);
+	if (err)
+		return err;
+
+	return devm_add_action(dev, sbtsi_misc_unregister, data);
 }
 
 static int sbtsi_i2c_probe(struct i2c_client *client)
@@ -105,7 +135,7 @@ static int sbtsi_i2c_probe(struct i2c_client *client)
 	struct device *dev = &client->dev;
 	struct sbtsi_data *data;
 
-	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	data = kzalloc_obj(*data);
 	if (!data)
 		return -ENOMEM;
 
@@ -157,7 +187,7 @@ static int sbtsi_i3c_probe(struct i3c_device *i3cdev)
 	if (I3C_PID_INSTANCE_ID(devinfo.pid) != 0)
 		return -ENXIO;
 
-	i3c_priv = devm_kzalloc(dev, sizeof(*i3c_priv), GFP_KERNEL);
+	i3c_priv = kzalloc_obj(*i3c_priv);
 	if (!i3c_priv)
 		return -ENOMEM;
 
diff --git a/include/linux/misc/tsi.h b/include/linux/misc/tsi.h
index 02c90ec285ec..3ce3770d1ad5 100644
--- a/include/linux/misc/tsi.h
+++ b/include/linux/misc/tsi.h
@@ -8,30 +8,45 @@
 #ifndef _LINUX_MISC_TSI_H_
 #define _LINUX_MISC_TSI_H_
 
+#include <linux/cleanup.h>
 #include <linux/i2c.h>
 #include <linux/i3c/device.h>
+#include <linux/kref.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
 #include <linux/types.h>
 
 /**
  * struct sbtsi_data - driver private data for an AMD SB-TSI device
  * @client:	underlying I2C client
  * @i3cdev:	underlying I3C device (when using I3C bus)
+ * @sbtsi_misc_dev: miscdevice exposing ioctl interface at /dev/sbtsi-<addr>
+ * @lock:           mutex protecting concurrent access to the device
+ * @kref:      reference count; keeps @sbtsi_data alive while misc fds are open
  * @dev_addr:	I2C/I3C device address, used to name the misc device node
  * @ext_range_mode:	sensor uses extended temperature range
  * @read_order:	if set, decimal part must be read before integer part
  * @is_i3c:	true when the device is accessed over I3C
+ * @detached:  set on driver unbind; open/ioctl return -ENODEV afterward
  */
 struct sbtsi_data {
 	union {
 		struct i2c_client *client;
 		struct i3c_device *i3cdev;
 	};
+	struct miscdevice sbtsi_misc_dev;
+	struct mutex lock;	/* protects concurrent access to the device */
+	struct kref kref;
 	u8 dev_addr;
 	bool ext_range_mode;
 	bool read_order;
 	bool is_i3c;
+	bool detached;
 };
 
+DEFINE_GUARD(sbtsi, struct sbtsi_data *, mutex_lock(&_T->lock),
+	     mutex_unlock(&_T->lock))
+
 /*
  * Name of the auxiliary device published on the auxiliary bus by the core
  * driver.  The full device name is "amd-sbtsi.temp-sensor.<id>". where
diff --git a/include/uapi/misc/amd-apml.h b/include/uapi/misc/amd-apml.h
index 745b3338fc06..8a85f79b0938 100644
--- a/include/uapi/misc/amd-apml.h
+++ b/include/uapi/misc/amd-apml.h
@@ -73,6 +73,13 @@ struct apml_reg_xfer_msg {
 	__u8 rflag;
 };
 
+struct apml_tsi_xfer_msg {
+	__u8 reg_addr;		/* TSI register address offset */
+	__u8 data_in_out;	/* Register data for read/write */
+	__u8 rflag;		/* Register read or write */
+	__u8 pad;		/* Explicit padding */
+};
+
 /*
  * AMD sideband interface base IOCTL
  */
@@ -149,4 +156,20 @@ struct apml_reg_xfer_msg {
  */
 #define SBRMI_IOCTL_REG_XFER_CMD	_IOWR(SB_BASE_IOCTL_NR, 3, struct apml_reg_xfer_msg)
 
+/**
+ * DOC: SBTSI_IOCTL_REG_XFER_CMD
+ *
+ * @Parameters
+ *
+ * @struct apml_tsi_xfer_msg
+ *	Pointer to the &struct apml_tsi_xfer_msg that will contain the protocol
+ *	information
+ *
+ * @Description
+ * IOCTL command for APML TSI messages using generic _IOWR
+ * The IOCTL provides userspace access to AMD sideband TSI register xfer protocol
+ * - TSI protocol to read/write temperature sensor registers
+ */
+#define SBTSI_IOCTL_REG_XFER_CMD	_IOWR(SB_BASE_IOCTL_NR, 4, struct apml_tsi_xfer_msg)
+
 #endif /*_AMD_APML_H_*/
-- 
2.34.1


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

* [PATCH v3 7/8] hwmon: Add mutex protecting for sbtsi read/write through hwmon
  2026-06-22 13:58 [PATCH v3 0/8] misc: amd-sbi: Refactor SBTSI driver with I3C support and ioctl interface Akshay Gupta
                   ` (5 preceding siblings ...)
  2026-06-22 13:58 ` [PATCH v3 6/8] misc: amd-sbi: Add SBTSI ioctl register transfer interface Akshay Gupta
@ 2026-06-22 13:58 ` Akshay Gupta
  2026-06-22 14:17   ` sashiko-bot
  2026-06-22 13:58 ` [PATCH v3 8/8] docs: misc: amd-sbi: Document SBTSI userspace interface Akshay Gupta
  7 siblings, 1 reply; 18+ messages in thread
From: Akshay Gupta @ 2026-06-22 13:58 UTC (permalink / raw)
  To: linux-doc, linux-kernel, linux-hwmon
  Cc: corbet, skhan, linux, arnd, gregkh, NaveenKrishna.Chatradhi,
	Anand.Umarji, Akshay.Gupta, Prathima.Lk

From: Prathima <Prathima.Lk@amd.com>

Add a mutex and take it around SBTSI read/write paths so that only
one transaction runs at a time. The lock is held only for the
duration of the bus transfer and associated driver bookkeeping, not
across blocking work unrelated to SBTSI.

This is a concurrency hardening fix.

Reviewed-by: Akshay Gupta <Akshay.Gupta@amd.com>
Signed-off-by: Prathima <Prathima.Lk@amd.com>
---
Changes since v2:
- New patch

 drivers/hwmon/sbtsi_temp.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/hwmon/sbtsi_temp.c b/drivers/hwmon/sbtsi_temp.c
index d7ae986d824c..11c8108d69b2 100644
--- a/drivers/hwmon/sbtsi_temp.c
+++ b/drivers/hwmon/sbtsi_temp.c
@@ -70,6 +70,7 @@ static int sbtsi_temp_read(struct sbtsi_data *data, u8 reg1, u8 reg2,
 {
 	int ret;
 
+	guard(sbtsi)(data);
 	ret = sbtsi_xfer(data, reg1, val1, true);
 	if (!ret)
 		ret = sbtsi_xfer(data, reg2, val2, true);
@@ -84,6 +85,7 @@ static int sbtsi_temp_write(struct sbtsi_data *data, u8 reg_int, u8 reg_dec,
 {
 	int ret;
 
+	guard(sbtsi)(data);
 	ret = sbtsi_xfer(data, reg_int, &val_int, false);
 	if (!ret)
 		ret = sbtsi_xfer(data, reg_dec, &val_dec, false);
-- 
2.34.1


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

* [PATCH v3 8/8] docs: misc: amd-sbi: Document SBTSI userspace interface
  2026-06-22 13:58 [PATCH v3 0/8] misc: amd-sbi: Refactor SBTSI driver with I3C support and ioctl interface Akshay Gupta
                   ` (6 preceding siblings ...)
  2026-06-22 13:58 ` [PATCH v3 7/8] hwmon: Add mutex protecting for sbtsi read/write through hwmon Akshay Gupta
@ 2026-06-22 13:58 ` Akshay Gupta
  2026-06-22 14:12   ` sashiko-bot
  2026-06-22 16:57   ` Randy Dunlap
  7 siblings, 2 replies; 18+ messages in thread
From: Akshay Gupta @ 2026-06-22 13:58 UTC (permalink / raw)
  To: linux-doc, linux-kernel, linux-hwmon
  Cc: corbet, skhan, linux, arnd, gregkh, NaveenKrishna.Chatradhi,
	Anand.Umarji, Akshay.Gupta, Prathima.Lk

From: Prathima <Prathima.Lk@amd.com>

- Document AMD sideband IOCTL description defined
  for SBTSI and its usage.
  User space C-APIs are made available by esmi_oob_library [1],
  which is provided by the E-SMS project [2].

  Link: https://github.com/amd/esmi_oob_library [1]
  Link: https://www.amd.com/en/developer/e-sms.html [2]

Include a user-space open example for /dev/sbtsi-* and list auxiliary
bus sysfs paths.

Reviewed-by: Akshay Gupta <Akshay.Gupta@amd.com>
Signed-off-by: Prathima <Prathima.Lk@amd.com>
---
Changes since v2:
- Update misc node names info as per socket

Changes since v1:
- Elaborate the document
 Documentation/misc-devices/amd-sbi.rst | 68 ++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)

diff --git a/Documentation/misc-devices/amd-sbi.rst b/Documentation/misc-devices/amd-sbi.rst
index f91ddadefe48..fbbbc504119f 100644
--- a/Documentation/misc-devices/amd-sbi.rst
+++ b/Documentation/misc-devices/amd-sbi.rst
@@ -48,6 +48,60 @@ Access restrictions:
  * APML Mailbox messages and Register xfer access are read-write,
  * CPUID and MCA_MSR access is read-only.
 
+SBTSI device
+============
+
+sbtsi driver under the drivers/misc/amd-sbi creates miscdevice
+/dev/sbtsi-* to let user space programs run APML TSI register xfer
+commands.
+
+The driver supports both I2C and I3C transports for SB-TSI targets.
+The transport is selected by the bus where the device is enumerated.
+
+Misc device:
+ * In 1P socket 0: /dev/sbtsi-4c
+ * In 2P socket 0: /dev/sbtsi-4c, socket 1: /dev/sbtsi-48
+
+.. code-block:: bash
+
+   $ ls -al /dev/sbtsi-4c
+   crw-------    1 root     root       10, 116 Apr  2 05:22 /dev/sbtsi-4c
+
+
+Access restrictions:
+ * Only root user is allowed to open the file.
+ * APML TSI Register xfer access is read-write.
+
+SBTSI hwmon interface
+=====================
+
+The sbtsi_temp auxiliary driver binds to the auxiliary device published
+by the core sbtsi driver on the auxiliary bus. The auxiliary device is
+named amd-sbtsi.temp-sensor.<addr> where <addr> is the device's dynamic
+address.
+
+It registers a hwmon device, providing a standard Linux hwmon interface
+for reading CPU temperature and managing temperature limits.
+
+The hwmon device appears under ``/sys/class/hwmon/`` when both ``sbtsi.ko``
+and ``sbtsi_temp.ko`` are loaded.
+
+Verify auxiliary bus device::
+
+  ls /sys/bus/auxiliary/devices/
+  # e.g. amd-sbtsi.temp-sensor.X
+
+Example usage::
+
+  # Read current temperature
+  cat /sys/class/hwmon/hwmon<N>/temp1_input
+
+  # Set high temperature limit to 70 °C
+  echo 70000 > /sys/class/hwmon/hwmon<N>/temp1_max
+
+  # Verify
+  cat /sys/class/hwmon/hwmon<N>/temp1_max
+
 Driver IOCTLs
 =============
 
@@ -63,6 +117,9 @@ Driver IOCTLs
 .. c:macro:: SBRMI_IOCTL_REG_XFER_CMD
 .. kernel-doc:: include/uapi/misc/amd-apml.h
    :doc: SBRMI_IOCTL_REG_XFER_CMD
+.. c:macro:: SBTSI_IOCTL_REG_XFER_CMD
+.. kernel-doc:: include/uapi/misc/amd-apml.h
+   :doc: SBTSI_IOCTL_REG_XFER_CMD
 
 User-space usage
 ================
@@ -85,6 +142,16 @@ Next thing, open the device file, as follows::
     exit(1);
   }
 
+To open SB-TSI device::
+
+  int file;
+
+  file = open("/dev/sbtsi-4c", O_RDWR);
+  if (file < 0) {
+    /* ERROR HANDLING */
+    exit(1);
+  }
+
 The following IOCTLs are defined:
 
 ``#define SB_BASE_IOCTL_NR      	0xF9``
@@ -92,6 +159,7 @@ The following IOCTLs are defined:
 ``#define SBRMI_IOCTL_CPUID_CMD		_IOWR(SB_BASE_IOCTL_NR, 1, struct apml_cpuid_msg)``
 ``#define SBRMI_IOCTL_MCAMSR_CMD	_IOWR(SB_BASE_IOCTL_NR, 2, struct apml_mcamsr_msg)``
 ``#define SBRMI_IOCTL_REG_XFER_CMD	_IOWR(SB_BASE_IOCTL_NR, 3, struct apml_reg_xfer_msg)``
+``#define SBTSI_IOCTL_REG_XFER_CMD      _IOWR(SB_BASE_IOCTL_NR, 4, struct apml_tsi_xfer_msg)``
 
 
 User space C-APIs are made available by esmi_oob_library, hosted at
-- 
2.34.1


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

* Re: [PATCH v3 2/8] hwmon: sbtsi_temp: Refactor temperature register access into helpers
  2026-06-22 13:58 ` [PATCH v3 2/8] hwmon: sbtsi_temp: Refactor temperature register access into helpers Akshay Gupta
@ 2026-06-22 14:11   ` sashiko-bot
  0 siblings, 0 replies; 18+ messages in thread
From: sashiko-bot @ 2026-06-22 14:11 UTC (permalink / raw)
  To: Akshay Gupta; +Cc: linux-hwmon

> From: Prathima <Prathima.Lk@amd.com>
> 
> Extract the paired integer/decimal register reads and writes from the
> hwmon read/write callbacks into sbtsi_temp_read() and sbtsi_temp_write()
> helpers. This consolidates error handling and respects the ReadOrder bit
> for atomic temperature latching.
> 
> This keeps register access independent while preserving existing hwmon
> functionality.
> 
> Reviewed-by: Akshay Gupta <Akshay.Gupta@amd.com>
> Signed-off-by: Prathima <Prathima.Lk@amd.com>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260622135821.2190260-1-Akshay.Gupta@amd.com?part=2


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

* Re: [PATCH v3 4/8] misc: amd-sbi: Consolidate Common SBTSI Probe Path for I2C and I3C
  2026-06-22 13:58 ` [PATCH v3 4/8] misc: amd-sbi: Consolidate Common SBTSI Probe Path for I2C and I3C Akshay Gupta
@ 2026-06-22 14:11   ` sashiko-bot
  0 siblings, 0 replies; 18+ messages in thread
From: sashiko-bot @ 2026-06-22 14:11 UTC (permalink / raw)
  To: Akshay Gupta; +Cc: linux-hwmon

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] The auxiliary device ID (`adev->id`) is set directly to the bus device address, causing sysfs naming collisions on multi-bus systems.
--

commit 30f30dcfe1c0110443187a8e9e5a7a6452445301
Author: Prathima <Prathima.Lk@amd.com>

misc: amd-sbi: Consolidate Common SBTSI Probe Path for I2C and I3C

This commit refactors the shared probe procedures into a new common
function, sbtsi_probe_common(). This consolidation ensures that I2C
and I3C probes can share the bus-specific allocation and device
configuration logic.

> diff --git a/drivers/misc/amd-sbi/tsi.c b/drivers/misc/amd-sbi/tsi.c
> index dfdd730b906af..a4c7e1be5624d 100644
> --- a/drivers/misc/amd-sbi/tsi.c
> +++ b/drivers/misc/amd-sbi/tsi.c
> @@ -84,25 +84,35 @@ static int sbtsi_create_hwmon_adev(struct device *dev, u8 dev_addr)

[ ... ]

> +static int sbtsi_probe_common(struct device *dev, struct sbtsi_data *data)
> +{
> +	u8 val;
> +	int err;
> +
> +	err = sbtsi_xfer(data, SBTSI_REG_CONFIG, &val, true);
> +	if (err)
> +		return err;
> +
> +	data->ext_range_mode = FIELD_GET(BIT(SBTSI_CONFIG_EXT_RANGE_SHIFT), val);
> +	data->read_order = FIELD_GET(BIT(SBTSI_CONFIG_READ_ORDER_SHIFT), val);
> +
> +	dev_set_drvdata(dev, data);
> +	return sbtsi_create_hwmon_adev(dev, data->dev_addr);

[Severity: High]
This isn't a bug introduced by this patch, but is it safe to use
data->dev_addr directly as the auxiliary device ID here?

Looking at sbtsi_create_hwmon_adev(), it assigns adev->id = dev_addr. This
causes sysfs naming collisions on multi-bus systems. While the existing code
comment assumes unique static addresses per socket, this breaks down on
topologies where identical sensors reside on independent I2C controllers.

Furthermore, if an upcoming patch introduces I3C support and sets this
address from the I3C dynamic address, collisions are virtually guaranteed
on multi-bus I3C systems. When a collision occurs, device_add() will fail
with a duplicate sysfs kobject name error, causing the probe to
deterministically fail.

Should this be updated to use the ida subsystem (e.g., ida_alloc()) to
assign guaranteed unique auxiliary device IDs?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260622135821.2190260-1-Akshay.Gupta@amd.com?part=4

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

* Re: [PATCH v3 8/8] docs: misc: amd-sbi: Document SBTSI userspace interface
  2026-06-22 13:58 ` [PATCH v3 8/8] docs: misc: amd-sbi: Document SBTSI userspace interface Akshay Gupta
@ 2026-06-22 14:12   ` sashiko-bot
  2026-06-22 16:57   ` Randy Dunlap
  1 sibling, 0 replies; 18+ messages in thread
From: sashiko-bot @ 2026-06-22 14:12 UTC (permalink / raw)
  To: Akshay Gupta; +Cc: linux-hwmon

> From: Prathima <Prathima.Lk@amd.com>
> 
> - Document AMD sideband IOCTL description defined
>   for SBTSI and its usage.
>   User space C-APIs are made available by esmi_oob_library [1],
>   which is provided by the E-SMS project [2].
> 
>   Link: https://github.com/amd/esmi_oob_library [1]
>   Link: https://www.amd.com/en/developer/e-sms.html [2]
> 
> Include a user-space open example for /dev/sbtsi-* and list auxiliary
> bus sysfs paths.
> 
> Reviewed-by: Akshay Gupta <Akshay.Gupta@amd.com>
> Signed-off-by: Prathima <Prathima.Lk@amd.com>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260622135821.2190260-1-Akshay.Gupta@amd.com?part=8


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

* Re: [PATCH v3 1/8] hwmon/misc: amd-sbi: Move core sbtsi support from hwmon to misc
  2026-06-22 13:58 ` [PATCH v3 1/8] hwmon/misc: amd-sbi: Move core sbtsi support from hwmon to misc Akshay Gupta
@ 2026-06-22 14:12   ` sashiko-bot
  0 siblings, 0 replies; 18+ messages in thread
From: sashiko-bot @ 2026-06-22 14:12 UTC (permalink / raw)
  To: Akshay Gupta; +Cc: linux-hwmon

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Auxiliary device ID collision prevents probing multiple sensors with identical addresses on different buses.
- [Low] SENSORS_SBTSI selects AMD_SBTSI but fails to inherit its dependencies, causing Kconfig unmet dependency warnings and potential build failures.
--

commit 66b0cf6c2e144993bdd6fedccce15184c3257aaf
Author: Prathima <Prathima.Lk@amd.com>

hwmon/misc: amd-sbi: Move core sbtsi support from hwmon to misc

This commit moves the SBTSI core functionality out of the hwmon subsystem
and into drivers/misc/amd-sbi so it can be reused by non-hwmon consumers.
It registers an auxiliary device that the hwmon driver can bind to.

> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index e4c4f2b09732d..8f204cf49b6e0 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -1963,7 +1963,7 @@ config SENSORS_SL28CPLD
>  
>  config SENSORS_SBTSI
>  	tristate "Emulated SB-TSI temperature sensor"
> -	depends on I2C
> +	select AMD_SBTSI

[Severity: Low]
Will this cause a Kconfig unmet dependency warning?

Because the target config depends on I2C and ARM || ARM64 || COMPILE_TEST,
selecting it here without those same dependencies means SENSORS_SBTSI can
be enabled on unsupported architectures or when I2C is disabled.

This forces the target to be built despite its unsatisfied dependencies,
which could lead to build or link errors.

>  	help
>  	  If you say yes here you get support for emulated temperature
>  	  sensors on AMD SoCs with SB-TSI interface connected to a BMC device.

[ ... ]

> diff --git a/drivers/misc/amd-sbi/tsi.c b/drivers/misc/amd-sbi/tsi.c
> new file mode 100644
> index 0000000000000..dfdd730b906af
> --- /dev/null
> +++ b/drivers/misc/amd-sbi/tsi.c
> @@ -0,0 +1,134 @@

[ ... ]

> +static int sbtsi_create_hwmon_adev(struct device *dev, u8 dev_addr)
> +{
> +	struct auxiliary_device *adev;
> +	int ret;
> +
> +	adev = kzalloc_obj(*adev);
> +	if (!adev)
> +		return -ENOMEM;
> +
> +	adev->name = AMD_SBTSI_AUX_HWMON;
> +	/*
> +	 * In a multi-socket system, otherwise identical devices do not
> +	 * share the same static address; each instance has its own address,
> +	 * which must be supplied via the device tree (DTS).
> +	 */
> +	adev->id = dev_addr;

[Severity: High]
Does this risk a sysfs name collision on systems with multiple I2C buses?

If multiple independent I2C buses each have a sensor at the same address,
the assigned id will be identical for both.

Because the auxiliary device name is constructed as
amd-sbtsi.temp-sensor.<id>, the second device to probe might fail the
device addition with a sysfs duplicate name warning, leaving the sensor
unusable.

Could a globally unique ID be generated here instead, perhaps using the
IDA framework?

> +	adev->dev.parent = dev;
> +	adev->dev.release = sbtsi_adev_release;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260622135821.2190260-1-Akshay.Gupta@amd.com?part=1

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

* Re: [PATCH v3 6/8] misc: amd-sbi: Add SBTSI ioctl register transfer interface
  2026-06-22 13:58 ` [PATCH v3 6/8] misc: amd-sbi: Add SBTSI ioctl register transfer interface Akshay Gupta
@ 2026-06-22 14:15   ` sashiko-bot
  0 siblings, 0 replies; 18+ messages in thread
From: sashiko-bot @ 2026-06-22 14:15 UTC (permalink / raw)
  To: Akshay Gupta; +Cc: linux-hwmon

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] TOCTOU race in IOCTL during device unbind leads to use-after-free of I2C/I3C device.
- [High] Using `devm_add_action()` instead of `devm_add_action_or_reset()` fails to unregister the misc device on error, causing a use-after-free.
--

commit 68509c62bd1860c432a2e05da7ef0faad793172b
Author: Prathima <Prathima.Lk@amd.com>

misc: amd-sbi: Add SBTSI ioctl register transfer interface

Implement ioctl interface for SB-TSI driver to enable userspace access
to TSI register read/write operations through the AMD Advanced Platform
Management Link (APML) protocol. Serialize access with a mutex shared
between the hwmon and ioctl paths.

> diff --git a/drivers/misc/amd-sbi/tsi-core.c b/drivers/misc/amd-sbi/tsi-core.c
> index 9278d06d8e5f6..688b9221868fe 100644
> --- a/drivers/misc/amd-sbi/tsi-core.c
> +++ b/drivers/misc/amd-sbi/tsi-core.c
[ ... ]
> @@ -80,7 +95,108 @@ int sbtsi_xfer(struct sbtsi_data *data, u8 reg, u8 *val, bool is_read)
[ ... ]
> +static int apml_tsi_reg_xfer(struct sbtsi_data *data,
> +			     struct apml_tsi_xfer_msg __user *arg)
> +{
> +	struct apml_tsi_xfer_msg msg = { 0 };
> +	int ret;
> +
> +	if (data->detached)
> +		return -ENODEV;
> +
> +	if (copy_from_user(&msg, arg, sizeof(struct apml_tsi_xfer_msg)))
> +		return -EFAULT;

[Severity: High]
Is there a time-of-check to time-of-use race here if the device is unbound
during this ioctl?

Since copy_from_user() can sleep, if the device is removed or unbound while
the thread is sleeping, devres cleanup will execute sbtsi_misc_unregister().

This sets data->detached = true locklessly and the subsystem frees
the data->client or data->i3cdev pointer.

Since sbtsi_data is kept alive by the kref, the ioctl thread can wake up, call
sbtsi_xfer_ioctl(), acquire data->lock, and call sbtsi_xfer().

Could this cause a use-after-free since sbtsi_xfer_ioctl() doesn't
re-check data->detached under the lock before accessing the freed client?

> +
> +	if (msg.pad)
> +		return -EINVAL;
> +
> +	ret = sbtsi_xfer_ioctl(data, msg.reg_addr, &msg.data_in_out, msg.rflag);
> +
> +	if (msg.rflag && !ret) {
> +		if (copy_to_user(arg, &msg, sizeof(struct apml_tsi_xfer_msg)))
> +			return -EFAULT;
> +	}
> +	return ret;
> +}
[ ... ]
> diff --git a/drivers/misc/amd-sbi/tsi.c b/drivers/misc/amd-sbi/tsi.c
> index 8fb17ccab73de..6649cd8cdf850 100644
> --- a/drivers/misc/amd-sbi/tsi.c
> +++ b/drivers/misc/amd-sbi/tsi.c
[ ... ]
> @@ -89,6 +104,13 @@ static int sbtsi_probe_common(struct device *dev, struct sbtsi_data *data)
[ ... ]
>  	dev_set_drvdata(dev, data);
> -	return sbtsi_create_hwmon_adev(dev, data->dev_addr);
> +	err = sbtsi_create_hwmon_adev(dev, data->dev_addr);
> +	if (err < 0)
> +		return err;
> +
> +	err = create_misc_tsi_device(data, dev);
> +	if (err)
> +		return err;
> +
> +	return devm_add_action(dev, sbtsi_misc_unregister, data);

[Severity: High]
If devm_add_action() fails here, will it leave the misc device registered?

Unlike devm_add_action_or_reset(), devm_add_action() returns an error on
failure without executing the provided callback.

If this fails (e.g. due to memory allocation failure), the probe aborts and
devres cleanup frees struct sbtsi_data.

Because sbtsi_misc_unregister() is never called, the misc device would remain
registered. Any subsequent attempt to open or interact with the leaked device
node would access the freed sbtsi_data.

Should this use devm_add_action_or_reset() instead?

>  }

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260622135821.2190260-1-Akshay.Gupta@amd.com?part=6

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

* Re: [PATCH v3 7/8] hwmon: Add mutex protecting for sbtsi read/write through hwmon
  2026-06-22 13:58 ` [PATCH v3 7/8] hwmon: Add mutex protecting for sbtsi read/write through hwmon Akshay Gupta
@ 2026-06-22 14:17   ` sashiko-bot
  0 siblings, 0 replies; 18+ messages in thread
From: sashiko-bot @ 2026-06-22 14:17 UTC (permalink / raw)
  To: Akshay Gupta; +Cc: linux-hwmon

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

New issues:
- [High] Unsafe DMA buffer allocation risking memory corruption due to cacheline sharing in I3C driver.
- [High] Use-After-Free and resource leak on the probe error path due to missing devres rollback.
- [High] TOCTOU race condition in IOCTL leading to Use-After-Free of underlying I2C/I3C device.

Pre-existing issues:
- [High] Signed integer overflow when setting extended temperature limit results in minimum limit instead of maximum.
--

commit 73c231fb30add9ba7fc881d929121fb0a885ff0d
Author: Prathima <Prathima.Lk@amd.com>
Subject: hwmon: Add mutex protecting for sbtsi read/write through hwmon

This commit adds a mutex using guard(sbtsi) around the SBTSI read and write
paths in the hwmon driver to serialize bus transactions.

> diff --git a/drivers/hwmon/sbtsi_temp.c b/drivers/hwmon/sbtsi_temp.c
> index d7ae986d824c4..11c8108d69b2a 100644
> --- a/drivers/hwmon/sbtsi_temp.c
> +++ b/drivers/hwmon/sbtsi_temp.c

[ ... ]

While reviewing this patch, I noticed a few other issues in the surrounding code
and the core driver.

drivers/misc/amd-sbi/tsi-core.h:struct sbtsi_i3c_priv {
	struct sbtsi_data data;
	u8 buf[2];
};

[Severity: High]
Does this buf array risk memory corruption during I3C transfers?

Because buf immediately follows struct sbtsi_data without explicit
cacheline alignment (____cacheline_aligned), it shares a CPU cacheline with
the trailing fields of struct sbtsi_data.

When the I3C master controller maps this buffer for DMA, it flushes or
invalidates the cacheline. Will concurrent CPU access to the adjacent
sbtsi_data fields (like data->detached or data->lock) during the
transfer cause cacheline bouncing, leading to either silent loss of state
updates or corruption of the DMA buffer?


drivers/hwmon/sbtsi_temp.c:sbtsi_write() {
    ...
	if (data->ext_range_mode)
		val += SBTSI_TEMP_EXT_RANGE_ADJ;
	val = clamp_val(val, SBTSI_TEMP_MIN, SBTSI_TEMP_MAX);
    ...
}

[Severity: High]
This isn't a bug introduced by this patch, but can this code wrap to a negative
value when setting an extended temperature limit?

If a user provides an extremely large value (e.g. LONG_MAX) to maximize the
limit via sysfs, the val += SBTSI_TEMP_EXT_RANGE_ADJ operation could cause a
signed integer overflow. In the kernel, this wraps to a large negative number.

When subsequently passed to clamp_val(), it is clamped to SBTSI_TEMP_MIN
(0). Does this mean attempting to disable or maximize a thermal limit sets it
to 0 instead, potentially triggering unintended hardware thermal throttling
or system shutdown?


drivers/misc/amd-sbi/tsi.c:sbtsi_probe_common() {
    ...
	err = create_misc_tsi_device(data, dev);
	if (err)
		return err;

	return devm_add_action(dev, sbtsi_misc_unregister, data);
}

[Severity: High]
Could this error path cause a use-after-free and leave the misc device
registered?

devm_add_action() is used to queue sbtsi_misc_unregister. If
devm_add_action() fails to allocate devres memory, it returns an error but
does not execute the action. This causes the probe to fail and devres unwinding
to start. Devres then executes previously added cleanup actions, such as
sbtsi_driver_unref, which drops the kref and frees the data struct.

Because sbtsi_misc_unregister was not executed, the misc device remains
registered globally with its private_data pointing to the now-freed data.
Should this use devm_add_action_or_reset() to ensure the cleanup executes
if action registration fails?


drivers/misc/amd-sbi/tsi-core.c:apml_tsi_reg_xfer() {
    ...
	if (data->detached)
		return -ENODEV;

	if (copy_from_user(&msg, arg, sizeof(struct apml_tsi_xfer_msg)))
		return -EFAULT;
    ...
}

[Severity: High]
Is there a race condition here that could lead to a use-after-free of the
underlying I2C/I3C device?

The driver checks data->detached before acquiring data->lock and before
sleeping in copy_from_user(). If the device is hot-unplugged concurrently,
the devres unbind path executes sbtsi_misc_unregister():

drivers/misc/amd-sbi/tsi.c:sbtsi_misc_unregister() {
    ...
	misc_deregister(&data->sbtsi_misc_dev);
	data->detached = true;
    ...
}

This sets data->detached = true without acquiring data->lock and completes
device unbind. Completing unbind drops the device reference and frees the
i2c_client or i3c_device structure.

When the IOCTL thread wakes up, it calls sbtsi_xfer_ioctl(), which takes the
lock but does not recheck data->detached. Will it then access the
already-freed data->client?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260622135821.2190260-1-Akshay.Gupta@amd.com?part=7

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

* Re: [PATCH v3 3/8] hwmon/misc: amd-sbi: Move sbtsi register transfer to core abstraction
  2026-06-22 13:58 ` [PATCH v3 3/8] hwmon/misc: amd-sbi: Move sbtsi register transfer to core abstraction Akshay Gupta
@ 2026-06-22 14:18   ` sashiko-bot
  0 siblings, 0 replies; 18+ messages in thread
From: sashiko-bot @ 2026-06-22 14:18 UTC (permalink / raw)
  To: Akshay Gupta; +Cc: linux-hwmon

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Using `select AMD_SBTSI` in `CONFIG_SENSORS_SBTSI` bypasses the dependencies of `AMD_SBTSI`, which can cause Kconfig warnings and linker errors (Build Failure).
--

commit 244321241d8d6647a9adc1fb143dcedb41e11593
Author: Prathima <Prathima.Lk@amd.com>

hwmon/misc: amd-sbi: Move sbtsi register transfer to core abstraction
    
Move the I2C read/write byte operations from the sbtsi hwmon driver into
a common sbtsi_xfer() function in tsi-core.c. This decouples the hwmon
sensor driver from the underlying bus transport, preparing for I3C
support in a subsequent patch.

> diff --git a/drivers/misc/amd-sbi/tsi-core.c b/drivers/misc/amd-sbi/tsi-core.c
> new file mode 100644
> index 0000000000000..6ef1831515bbb
> --- /dev/null
> +++ b/drivers/misc/amd-sbi/tsi-core.c
> @@ -0,0 +1,30 @@
[ ... ]
> +/* I2C transfer function */
> +static int sbtsi_i2c_xfer(struct sbtsi_data *data, u8 reg, u8 *val, bool is_read)
> +{
> +	if (is_read) {
> +		int ret = i2c_smbus_read_byte_data(data->client, reg);

[Severity: High]
Will this lead to a linker error (undefined reference to
i2c_smbus_read_byte_data) if a user configures CONFIG_SENSORS_SBTSI=y and
CONFIG_I2C=m?

The Kconfig option SENSORS_SBTSI uses select AMD_SBTSI but fails to
mirror the dependencies required by AMD_SBTSI (such as depends on
I3C_OR_I2C and architecture restrictions like depends on ARM || ARM64 ||
COMPILE_TEST). 

If CONFIG_I2C=m and CONFIG_SENSORS_SBTSI=y, Kconfig forcefully sets
CONFIG_AMD_SBTSI=y. This triggers an unmet direct dependencies Kconfig
warning, and since tsi-core.c is built-in (y) while I2C is a module (m),
it breaks the build.

This problem was introduced earlier in the series, but it remains
unresolved at the end of the series.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260622135821.2190260-1-Akshay.Gupta@amd.com?part=3

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

* Re: [PATCH v3 5/8] misc: amd-sbi: Add support for SB-TSI over I3C
  2026-06-22 13:58 ` [PATCH v3 5/8] misc: amd-sbi: Add support for SB-TSI over I3C Akshay Gupta
@ 2026-06-22 14:19   ` sashiko-bot
  0 siblings, 0 replies; 18+ messages in thread
From: sashiko-bot @ 2026-06-22 14:19 UTC (permalink / raw)
  To: Akshay Gupta; +Cc: linux-hwmon

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The I3C transfer buffer shares a CPU cacheline with the device structure and other DMA mappings, causing unsafe DMA operations and potential memory corruption.
- [Low] Unmet Kconfig dependency warning triggered because `SENSORS_SBTSI` unconditionally selects `AMD_SBTSI` without inheriting its dependencies.
--

commit 6d735915bcef7f51c2d83398a0f1592836ede997
Author: Prathima <Prathima.Lk@amd.com>

misc: amd-sbi: Add support for SB-TSI over I3C

This patch extends the SB-TSI driver to support both I2C and I3C bus
interfaces. It registers both I2C and I3C drivers using
module_i3c_i2c_driver() and updates the Kconfig dependency from I2C to
I3C_OR_I2C.

> diff --git a/drivers/misc/amd-sbi/Kconfig b/drivers/misc/amd-sbi/Kconfig
> index 512251690e0e9..1a96b71f85069 100644
> --- a/drivers/misc/amd-sbi/Kconfig
> +++ b/drivers/misc/amd-sbi/Kconfig
> @@ -23,13 +23,13 @@ config AMD_SBRMI_HWMON
>  
>  config AMD_SBTSI
>  	tristate "AMD side band TSI support"
> -	depends on I2C
> +	depends on I3C_OR_I2C

[Severity: Low]
Could this change cause unmet direct dependencies warnings if another Kconfig
symbol selects AMD_SBTSI without inheriting this new dependency?

For example, if SENSORS_SBTSI selects AMD_SBTSI, it would need to have
compatible dependencies to prevent build failures on unsupported
architectures or when I3C/I2C is disabled.

>  	depends on ARM || ARM64 || COMPILE_TEST
>  	select AUXILIARY_BUS

[ ... ]

> diff --git a/drivers/misc/amd-sbi/tsi-core.c b/drivers/misc/amd-sbi/tsi-core.c
> index 6ef1831515bbb..9278d06d8e5f6 100644
> --- a/drivers/misc/amd-sbi/tsi-core.c
> +++ b/drivers/misc/amd-sbi/tsi-core.c

[ ... ]

> @@ -23,8 +33,54 @@ static int sbtsi_i2c_xfer(struct sbtsi_data *data, u8 reg, u8 *val, bool is_read
>  	return i2c_smbus_write_byte_data(data->client, reg, *val);
>  }
>  
> +/* I3C read transfer function */
> +static int sbtsi_i3c_read(struct sbtsi_data *data, u8 reg, u8 *val)
> +{
> +	struct i3c_xfer xfers[2] = { };
> +	u8 *buf = sbtsi_i3c_buf(data);
> +	int ret;
> +
> +	buf[0] = reg;
> +	/* Add Register data to read/write */
> +	xfers[0].rnw = false;
> +	xfers[0].len = 1;
> +	xfers[0].data.out = &buf[0];
> +
> +	xfers[1].rnw = true;
> +	xfers[1].len = 1;
> +	xfers[1].data.in = &buf[1];

[Severity: High]
Does this code risk memory corruption or unsafe DMA operations?

If the underlying I3C host controller processes these transfers using DMA,
mapping &buf[1] as DMA_FROM_DEVICE requires a cache invalidation upon
unmap.

This invalidation could silently destroy concurrent CPU writes to
variables sharing the same cacheline, such as the kref in struct
sbtsi_data.

Additionally, passing adjacent 1-byte buffers for overlapping
DMA_TO_DEVICE and DMA_FROM_DEVICE mappings in a single transaction
violates the Linux DMA API.

> +
> +	ret = i3c_device_do_xfers(data->i3cdev, xfers, 2, I3C_SDR);

[ ... ]

> diff --git a/drivers/misc/amd-sbi/tsi-core.h b/drivers/misc/amd-sbi/tsi-core.h
> new file mode 100644
> index 0000000000000..7dde040caf308
> --- /dev/null
> +++ b/drivers/misc/amd-sbi/tsi-core.h
> @@ -0,0 +1,23 @@

[ ... ]

> +struct sbtsi_i3c_priv {
> +	struct sbtsi_data data;
> +	u8 buf[2];

[Severity: High]
Is it safe to define this buffer without explicit cacheline alignment?

Without ____cacheline_aligned, buf shares a CPU cacheline with adjacent
fields in struct sbtsi_data. As this buffer is used in I3C transfers in
sbtsi_i3c_read() and sbtsi_i3c_write(), this could lead to cacheline
sharing issues during DMA.

> +};
> +
> +#endif /* _LINUX_TSI_CORE_H_ */

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260622135821.2190260-1-Akshay.Gupta@amd.com?part=5

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

* Re: [PATCH v3 8/8] docs: misc: amd-sbi: Document SBTSI userspace interface
  2026-06-22 13:58 ` [PATCH v3 8/8] docs: misc: amd-sbi: Document SBTSI userspace interface Akshay Gupta
  2026-06-22 14:12   ` sashiko-bot
@ 2026-06-22 16:57   ` Randy Dunlap
  1 sibling, 0 replies; 18+ messages in thread
From: Randy Dunlap @ 2026-06-22 16:57 UTC (permalink / raw)
  To: Akshay Gupta, linux-doc, linux-kernel, linux-hwmon
  Cc: corbet, skhan, linux, arnd, gregkh, NaveenKrishna.Chatradhi,
	Anand.Umarji, Prathima.Lk



On 6/22/26 6:58 AM, Akshay Gupta wrote:
> From: Prathima <Prathima.Lk@amd.com>
> 
> - Document AMD sideband IOCTL description defined
>   for SBTSI and its usage.
>   User space C-APIs are made available by esmi_oob_library [1],
>   which is provided by the E-SMS project [2].
> 
>   Link: https://github.com/amd/esmi_oob_library [1]
>   Link: https://www.amd.com/en/developer/e-sms.html [2]
> 
> Include a user-space open example for /dev/sbtsi-* and list auxiliary
> bus sysfs paths.
> 
> Reviewed-by: Akshay Gupta <Akshay.Gupta@amd.com>
> Signed-off-by: Prathima <Prathima.Lk@amd.com>
> ---
> Changes since v2:
> - Update misc node names info as per socket
> 
> Changes since v1:
> - Elaborate the document
>  Documentation/misc-devices/amd-sbi.rst | 68 ++++++++++++++++++++++++++
>  1 file changed, 68 insertions(+)
> 
> diff --git a/Documentation/misc-devices/amd-sbi.rst b/Documentation/misc-devices/amd-sbi.rst
> index f91ddadefe48..fbbbc504119f 100644
> --- a/Documentation/misc-devices/amd-sbi.rst
> +++ b/Documentation/misc-devices/amd-sbi.rst
> @@ -48,6 +48,60 @@ Access restrictions:
>   * APML Mailbox messages and Register xfer access are read-write,
>   * CPUID and MCA_MSR access is read-only.
>  
> +SBTSI device
> +============
> +
> +sbtsi driver under the drivers/misc/amd-sbi creates miscdevice

   The sbtsi driver in the drivers/misc/amd-sbi/ directory creates a miscdevice

> +/dev/sbtsi-* to let user space programs run APML TSI register xfer

                                                                 transfer
?

> +commands.
> +
> +The driver supports both I2C and I3C transports for SB-TSI targets.
> +The transport is selected by the bus where the device is enumerated.
> +
> +Misc device:
> + * In 1P socket 0: /dev/sbtsi-4c
> + * In 2P socket 0: /dev/sbtsi-4c, socket 1: /dev/sbtsi-48
> +
> +.. code-block:: bash
> +
> +   $ ls -al /dev/sbtsi-4c
> +   crw-------    1 root     root       10, 116 Apr  2 05:22 /dev/sbtsi-4c
> +
> +
> +Access restrictions:
> + * Only root user is allowed to open the file.
> + * APML TSI Register xfer access is read-write.

                        transfer
?

> +
> +SBTSI hwmon interface
> +=====================
[snip]

-- 
~Randy


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

end of thread, other threads:[~2026-06-22 16:57 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-22 13:58 [PATCH v3 0/8] misc: amd-sbi: Refactor SBTSI driver with I3C support and ioctl interface Akshay Gupta
2026-06-22 13:58 ` [PATCH v3 1/8] hwmon/misc: amd-sbi: Move core sbtsi support from hwmon to misc Akshay Gupta
2026-06-22 14:12   ` sashiko-bot
2026-06-22 13:58 ` [PATCH v3 2/8] hwmon: sbtsi_temp: Refactor temperature register access into helpers Akshay Gupta
2026-06-22 14:11   ` sashiko-bot
2026-06-22 13:58 ` [PATCH v3 3/8] hwmon/misc: amd-sbi: Move sbtsi register transfer to core abstraction Akshay Gupta
2026-06-22 14:18   ` sashiko-bot
2026-06-22 13:58 ` [PATCH v3 4/8] misc: amd-sbi: Consolidate Common SBTSI Probe Path for I2C and I3C Akshay Gupta
2026-06-22 14:11   ` sashiko-bot
2026-06-22 13:58 ` [PATCH v3 5/8] misc: amd-sbi: Add support for SB-TSI over I3C Akshay Gupta
2026-06-22 14:19   ` sashiko-bot
2026-06-22 13:58 ` [PATCH v3 6/8] misc: amd-sbi: Add SBTSI ioctl register transfer interface Akshay Gupta
2026-06-22 14:15   ` sashiko-bot
2026-06-22 13:58 ` [PATCH v3 7/8] hwmon: Add mutex protecting for sbtsi read/write through hwmon Akshay Gupta
2026-06-22 14:17   ` sashiko-bot
2026-06-22 13:58 ` [PATCH v3 8/8] docs: misc: amd-sbi: Document SBTSI userspace interface Akshay Gupta
2026-06-22 14:12   ` sashiko-bot
2026-06-22 16:57   ` Randy Dunlap

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