* [PATCH v5 0/2] AMD Promontory 21 xHCI temperature sensor support
@ 2026-05-12 21:39 Jihong Min
2026-05-12 21:39 ` [PATCH v5 1/2] usb: xhci-pci: add AMD Promontory 21 PCI glue Jihong Min
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Jihong Min @ 2026-05-12 21:39 UTC (permalink / raw)
To: Greg Kroah-Hartman, Mathias Nyman
Cc: Guenter Roeck, Jonathan Corbet, Shuah Khan, Mario Limonciello,
Basavaraj Natikar, linux-usb, linux-hwmon, linux-doc, linux-pci,
linux-kernel, Jihong Min
Hi,
This series adds temperature monitoring for AMD Promontory 21 (PROM21)
xHCI PCI functions.
Patch 1 adds a small PROM21-specific xHCI PCI glue driver. USB host
operation is delegated to the common xhci-pci code, while the PROM21 glue
publishes an auxiliary device for optional sensor support.
Patch 2 adds an auxiliary-bus hwmon driver that binds to that auxiliary
device and exposes the PROM21 xHCI temperature value as temp1_input.
The hwmon driver reads the sensor through a vendor index/data register pair
in the xHCI PCI MMIO BAR. It does not wake the parent PCI device for hwmon
reads; if the parent is suspended, the read returns -ENODATA.
Changes in v5:
- Add support for AMD 1022:43fc PROM21 xHCI controllers and document the
new PCI ID.
- Make USB_XHCI_PCI_PROM21 depend on X86 and default to USB_XHCI_PCI.
- Keep the PROM21 PCI glue built-in-only when enabled, while allowing the
hwmon sensor driver to be built as a separate module.
- Move PROM21 xHCI PCI device IDs to xhci-pci.h so xhci-pci.c and
xhci-pci-prom21.c use shared definitions.
- Pass the parent PCI device, MMIO base, and resource length to the hwmon
driver through platform data defined in a common header, instead of
inspecting the parent driver's drvdata from the hwmon driver.
- Remove the private hwmon mutex and rely on hwmon core serialization for
this driver's callbacks.
- Clarify that the driver only serializes its own hwmon callbacks and does
not synchronize with firmware, SMM, ACPI AML, or other possible users of
the PROM21 vendor index/data register pair.
- Use readb() for the temperature data register, validate the value before
writing the output pointer, and drop the 0xff invalid-value check.
- Use pm_runtime_put() after successful reads with the parent device active
so the PM core can re-evaluate the parent device's idle state.
- Simplify the documentation and use more precise terminology for the
supported device.
Jihong Min (2):
usb: xhci-pci: add AMD Promontory 21 PCI glue
hwmon: add AMD Promontory 21 xHCI temperature sensor support
Documentation/hwmon/index.rst | 1 +
Documentation/hwmon/prom21-xhci.rst | 101 ++++++++
drivers/hwmon/Kconfig | 10 +
drivers/hwmon/Makefile | 1 +
drivers/hwmon/prom21-xhci.c | 238 ++++++++++++++++++
drivers/usb/host/Kconfig | 20 ++
drivers/usb/host/Makefile | 1 +
drivers/usb/host/xhci-pci-prom21.c | 123 +++++++++
drivers/usb/host/xhci-pci.c | 11 +
drivers/usb/host/xhci-pci.h | 3 +
include/linux/platform_data/usb-xhci-prom21.h | 22 ++
11 files changed, 531 insertions(+)
create mode 100644 Documentation/hwmon/prom21-xhci.rst
create mode 100644 drivers/hwmon/prom21-xhci.c
create mode 100644 drivers/usb/host/xhci-pci-prom21.c
create mode 100644 include/linux/platform_data/usb-xhci-prom21.h
--
2.53.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v5 1/2] usb: xhci-pci: add AMD Promontory 21 PCI glue
2026-05-12 21:39 [PATCH v5 0/2] AMD Promontory 21 xHCI temperature sensor support Jihong Min
@ 2026-05-12 21:39 ` Jihong Min
2026-05-12 21:39 ` [PATCH v5 2/2] hwmon: add AMD Promontory 21 xHCI temperature sensor support Jihong Min
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Jihong Min @ 2026-05-12 21:39 UTC (permalink / raw)
To: Greg Kroah-Hartman, Mathias Nyman
Cc: Guenter Roeck, Jonathan Corbet, Shuah Khan, Mario Limonciello,
Basavaraj Natikar, linux-usb, linux-hwmon, linux-doc, linux-pci,
linux-kernel, Jihong Min
AMD Promontory 21 (PROM21) xHCI controllers use generic xHCI
operation, but the PCI function also exposes optional
controller-specific sensor functionality. Add a small PROM21 PCI glue
driver for AMD 1022:43fc and 1022:43fd controllers.
The driver delegates USB host operation to the common xhci-pci core,
collects the parent-provided MMIO resource data, and creates a "hwmon"
auxiliary device for optional child drivers. Failure to create the
auxiliary device is logged but does not fail the xHCI probe, since the
auxiliary device is only needed for sensor support.
Keep the PROM21 PCI glue built-in only when enabled because it owns the
PCI binding for PROM21 xHCI controllers and must be available whenever
the common built-in xhci-pci driver hands those controllers off. This
avoids an early boot case where generic xhci-pci rejects a PROM21
controller but a modular xhci-pci-prom21 driver is not available in the
initramfs, leaving USB devices behind that controller unavailable.
Assisted-by: Codex:gpt-5.5
Signed-off-by: Jihong Min <hurryman2212@gmail.com>
---
drivers/usb/host/Kconfig | 20 +++
drivers/usb/host/Makefile | 1 +
drivers/usb/host/xhci-pci-prom21.c | 123 ++++++++++++++++++
drivers/usb/host/xhci-pci.c | 11 ++
drivers/usb/host/xhci-pci.h | 3 +
include/linux/platform_data/usb-xhci-prom21.h | 22 ++++
6 files changed, 180 insertions(+)
create mode 100644 drivers/usb/host/xhci-pci-prom21.c
create mode 100644 include/linux/platform_data/usb-xhci-prom21.h
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 0a277a07cf70..8b2ad1c27084 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -42,6 +42,26 @@ config USB_XHCI_PCI
depends on USB_PCI
default y
+config USB_XHCI_PCI_PROM21
+ bool "AMD Promontory 21 xHCI PCI support"
+ depends on X86
+ depends on USB_XHCI_PCI=y
+ default USB_XHCI_PCI
+ select AUXILIARY_BUS
+ help
+ Say 'Y' to enable support for the AMD Promontory 21 xHCI PCI
+ controller with optional sensor support. This driver does not add
+ PROM21-specific USB or xHCI operation. It binds PROM21 xHCI PCI
+ functions, delegates USB host operation to the common xHCI PCI core,
+ and creates auxiliary devices for optional sensor drivers.
+
+ This driver is built-in only because it owns the PCI binding for
+ PROM21 xHCI controllers when enabled and must be available whenever
+ the common xHCI PCI driver is available. The optional sensor driver
+ can still be built as a module.
+
+ If unsure, say 'N'.
+
config USB_XHCI_PCI_RENESAS
tristate "Support for additional Renesas xHCI controller with firmware"
depends on USB_XHCI_PCI
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index a07e7ba9cd53..174580c1281a 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -71,6 +71,7 @@ obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_FHCI_HCD) += fhci.o
obj-$(CONFIG_USB_XHCI_HCD) += xhci-hcd.o
obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o
+obj-$(CONFIG_USB_XHCI_PCI_PROM21) += xhci-pci-prom21.o
obj-$(CONFIG_USB_XHCI_PCI_RENESAS) += xhci-pci-renesas.o
obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.o
obj-$(CONFIG_USB_XHCI_HISTB) += xhci-histb.o
diff --git a/drivers/usb/host/xhci-pci-prom21.c b/drivers/usb/host/xhci-pci-prom21.c
new file mode 100644
index 000000000000..70847a2381b7
--- /dev/null
+++ b/drivers/usb/host/xhci-pci-prom21.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AMD Promontory 21 xHCI host controller PCI Bus Glue.
+ *
+ * This does not add any PROM21-specific USB or xHCI operation. It exists only
+ * to publish an auxiliary device for integrated temperature sensor support.
+ *
+ * Copyright (C) 2026 Jihong Min <hurryman2212@gmail.com>
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/device/devres.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_data/usb-xhci-prom21.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+
+#include "xhci-pci.h"
+
+struct prom21_xhci_auxdev {
+ struct auxiliary_device *auxdev;
+ struct prom21_xhci_pdata pdata;
+};
+
+static void prom21_xhci_auxdev_release(struct device *dev, void *res)
+{
+ struct prom21_xhci_auxdev *prom21_auxdev = res;
+
+ auxiliary_device_destroy(prom21_auxdev->auxdev);
+}
+
+static int prom21_xhci_create_auxdev(struct pci_dev *pdev)
+{
+ struct prom21_xhci_auxdev *prom21_auxdev;
+ struct usb_hcd *hcd = pci_get_drvdata(pdev);
+
+ if (!hcd)
+ return -ENODEV;
+
+ prom21_auxdev = devres_alloc(prom21_xhci_auxdev_release,
+ sizeof(*prom21_auxdev), GFP_KERNEL);
+ if (!prom21_auxdev)
+ return -ENOMEM;
+
+ prom21_auxdev->pdata.pdev = pdev;
+ prom21_auxdev->pdata.regs = hcd->regs;
+ prom21_auxdev->pdata.rsrc_len = hcd->rsrc_len;
+
+ prom21_auxdev->auxdev =
+ auxiliary_device_create(&pdev->dev, KBUILD_MODNAME, "hwmon",
+ &prom21_auxdev->pdata,
+ (pci_domain_nr(pdev->bus) << 16) |
+ pci_dev_id(pdev));
+ if (!prom21_auxdev->auxdev) {
+ devres_free(prom21_auxdev);
+ return -ENOMEM;
+ }
+
+ devres_add(&pdev->dev, prom21_auxdev);
+ return 0;
+}
+
+static void prom21_xhci_destroy_auxdev(struct pci_dev *pdev)
+{
+ devres_release(&pdev->dev, prom21_xhci_auxdev_release, NULL, NULL);
+}
+
+static int prom21_xhci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ int retval;
+
+ retval = xhci_pci_common_probe(dev, id);
+ if (retval)
+ return retval;
+
+ retval = prom21_xhci_create_auxdev(dev);
+ if (retval) {
+ /*
+ * The auxiliary device only provides optional temperature sensor
+ * support. Keep the xHCI controller usable if it fails.
+ */
+ dev_err(&dev->dev,
+ "failed to create PROM21 hwmon auxiliary device: %d\n",
+ retval);
+ }
+
+ return 0;
+}
+
+static void prom21_xhci_remove(struct pci_dev *dev)
+{
+ prom21_xhci_destroy_auxdev(dev);
+ xhci_pci_remove(dev);
+}
+
+static const struct pci_device_id pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PROM21_XHCI_43FC) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PROM21_XHCI_43FD) },
+ { /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+static struct pci_driver prom21_xhci_driver = {
+ .name = "xhci-pci-prom21",
+ .id_table = pci_ids,
+
+ .probe = prom21_xhci_probe,
+ .remove = prom21_xhci_remove,
+
+ .shutdown = usb_hcd_pci_shutdown,
+ .driver = {
+ .pm = pm_ptr(&usb_hcd_pci_pm_ops),
+ },
+};
+module_pci_driver(prom21_xhci_driver);
+
+MODULE_AUTHOR("Jihong Min <hurryman2212@gmail.com>");
+MODULE_DESCRIPTION("AMD Promontory 21 xHCI PCI Host Controller Driver");
+MODULE_IMPORT_NS("xhci");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 585b2f3117b0..039c26b241d0 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -696,12 +696,23 @@ static const struct pci_device_id pci_ids_renesas[] = {
{ /* end: all zeroes */ }
};
+/* handled by xhci-pci-prom21 if enabled */
+static const struct pci_device_id pci_ids_prom21[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PROM21_XHCI_43FC) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PROM21_XHCI_43FD) },
+ { /* end: all zeroes */ }
+};
+
static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
if (IS_ENABLED(CONFIG_USB_XHCI_PCI_RENESAS) &&
pci_match_id(pci_ids_renesas, dev))
return -ENODEV;
+ if (IS_ENABLED(CONFIG_USB_XHCI_PCI_PROM21) &&
+ pci_match_id(pci_ids_prom21, dev))
+ return -ENODEV;
+
return xhci_pci_common_probe(dev, id);
}
diff --git a/drivers/usb/host/xhci-pci.h b/drivers/usb/host/xhci-pci.h
index e87c7d9d76b8..11f435f94322 100644
--- a/drivers/usb/host/xhci-pci.h
+++ b/drivers/usb/host/xhci-pci.h
@@ -4,6 +4,9 @@
#ifndef XHCI_PCI_H
#define XHCI_PCI_H
+#define PCI_DEVICE_ID_AMD_PROM21_XHCI_43FC 0x43fc
+#define PCI_DEVICE_ID_AMD_PROM21_XHCI_43FD 0x43fd
+
int xhci_pci_common_probe(struct pci_dev *dev, const struct pci_device_id *id);
void xhci_pci_remove(struct pci_dev *dev);
diff --git a/include/linux/platform_data/usb-xhci-prom21.h b/include/linux/platform_data/usb-xhci-prom21.h
new file mode 100644
index 000000000000..ee672ad452a8
--- /dev/null
+++ b/include/linux/platform_data/usb-xhci-prom21.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * AMD Promontory 21 xHCI auxiliary device platform data.
+ *
+ * Copyright (C) 2026 Jihong Min <hurryman2212@gmail.com>
+ */
+
+#ifndef _LINUX_PLATFORM_DATA_USB_XHCI_PROM21_H
+#define _LINUX_PLATFORM_DATA_USB_XHCI_PROM21_H
+
+#include <linux/compiler_types.h>
+#include <linux/types.h>
+
+struct pci_dev;
+
+struct prom21_xhci_pdata {
+ struct pci_dev *pdev;
+ void __iomem *regs;
+ resource_size_t rsrc_len;
+};
+
+#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v5 2/2] hwmon: add AMD Promontory 21 xHCI temperature sensor support
2026-05-12 21:39 [PATCH v5 0/2] AMD Promontory 21 xHCI temperature sensor support Jihong Min
2026-05-12 21:39 ` [PATCH v5 1/2] usb: xhci-pci: add AMD Promontory 21 PCI glue Jihong Min
@ 2026-05-12 21:39 ` Jihong Min
2026-05-12 21:49 ` [PATCH v5 0/2] " Jihong Min
2026-05-13 14:48 ` Mario Limonciello
3 siblings, 0 replies; 5+ messages in thread
From: Jihong Min @ 2026-05-12 21:39 UTC (permalink / raw)
To: Greg Kroah-Hartman, Mathias Nyman
Cc: Guenter Roeck, Jonathan Corbet, Shuah Khan, Mario Limonciello,
Basavaraj Natikar, linux-usb, linux-hwmon, linux-doc, linux-pci,
linux-kernel, Jihong Min
Add an auxiliary-bus hwmon driver for the temperature sensor exposed by
AMD Promontory 21 (PROM21) xHCI PCI functions. The driver binds to the
"hwmon" auxiliary device published by the PROM21 xHCI PCI glue and
exposes the sensor as temp1_input under the prom21_xhci hwmon device.
The sensor is accessed through a PROM21 vendor index/data register pair
in the xHCI PCI MMIO BAR. The driver consumes parent-provided MMIO data
from the PROM21 PCI glue instead of inspecting the parent PCI driver's
drvdata. The read path restores the previous vendor index value after
sampling and does not runtime-resume the parent PCI device; reads from a
suspended parent return -ENODATA.
Document the supported device, register access, runtime PM behavior, and
sysfs lookup method. The documentation also records the observation
method used to identify the register pair and derive the conversion
formula.
Assisted-by: Codex:gpt-5.5
Signed-off-by: Jihong Min <hurryman2212@gmail.com>
---
Documentation/hwmon/index.rst | 1 +
Documentation/hwmon/prom21-xhci.rst | 101 ++++++++++++
drivers/hwmon/Kconfig | 10 ++
drivers/hwmon/Makefile | 1 +
drivers/hwmon/prom21-xhci.c | 238 ++++++++++++++++++++++++++++
5 files changed, 351 insertions(+)
create mode 100644 Documentation/hwmon/prom21-xhci.rst
create mode 100644 drivers/hwmon/prom21-xhci.c
diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
index 8b655e5d6b68..324208f1faa2 100644
--- a/Documentation/hwmon/index.rst
+++ b/Documentation/hwmon/index.rst
@@ -216,6 +216,7 @@ Hardware Monitoring Kernel Drivers
pmbus
powerz
powr1220
+ prom21-xhci
pt5161l
pxe1610
pwm-fan
diff --git a/Documentation/hwmon/prom21-xhci.rst b/Documentation/hwmon/prom21-xhci.rst
new file mode 100644
index 000000000000..7984fb187bd8
--- /dev/null
+++ b/Documentation/hwmon/prom21-xhci.rst
@@ -0,0 +1,101 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Kernel driver prom21-xhci
+=========================
+
+Supported chips:
+
+ * AMD Promontory 21 (PROM21) xHCI USB host controller
+
+ Prefix: 'prom21_xhci'
+
+ PCI IDs: 1022:43fc, 1022:43fd
+
+Author:
+
+ - Jihong Min <hurryman2212@gmail.com>
+
+Description
+-----------
+
+This driver exposes the temperature sensor in AMD PROM21 xHCI controllers.
+
+The driver binds to an auxiliary device created by the xHCI PCI driver for
+supported controllers. The sensor value is accessed through a vendor-specific
+index/data register pair in the controller's PCI MMIO BAR.
+The auxiliary device is created by the ``xhci-pci-prom21`` PCI glue driver.
+USB host operation is otherwise delegated to the common ``xhci-pci`` code.
+
+PROM21 is an AMD chipset IP used in single-chip or daisy-chained configurations
+to build AMD 6xx/8xx series chipsets. Since the xHCI controllers are
+integrated in PROM21, this temperature can also be used as a monitor for a
+temperature close to the AMD chipset temperature.
+
+Register access
+---------------
+
+The temperature value is read through a vendor-specific index/data register
+pair in the xHCI PCI MMIO BAR. The driver uses the following byte offsets from
+the MMIO BAR base:
+
+======================= =====================================================
+0x3000 Vendor index register
+0x3008 Vendor data register
+======================= =====================================================
+
+The driver saves the current vendor index register value, writes the
+temperature selector ``0x0001e520`` to the vendor index register, reads the
+vendor data register, and restores the previous vendor index value before
+returning. The raw temperature value is the low 8 bits of the vendor data
+register value.
+
+The hwmon core serializes this driver's callbacks, and the driver restores the
+previous index value after each read. This does not provide synchronization
+with firmware, SMM, ACPI AML, or any other user outside this driver.
+
+No public AMD reference is available for the register pair or the raw value.
+The register pair was identified on an X870E system with two PROM21 xHCI
+controllers. One controller was passed through to a Windows VM, and the same
+controller's PCI MMIO BAR was observed from the Linux host while HWiNFO64 was
+reporting the PROM21 xHCI temperature. In the test environment, the reported
+temperature was very stable at idle and the displayed sensor resolution was
+low, which made it possible to look for a consistently repeating MMIO response
+for the same reported temperature. During observation, offset 0x3000 repeatedly
+contained selector ``0x0001e520``. Writing the same selector to offset 0x3000
+from Linux and then reading offset 0x3008 reproduced the same raw value, so the
+offsets are treated as a vendor index/data register pair.
+
+The conversion formula was empirically inferred by matching observed raw
+8-bit values against HWiNFO64's reported PROM21 xHCI temperature for the same
+controller. The observed mapping is:
+
+ temp[C] = raw * 0.9066 - 78.624
+
+Runtime PM
+----------
+
+The driver does not wake the xHCI PCI device for hwmon reads. It reads the
+temperature only when the parent device is already active. A read from a
+suspended device returns ``-ENODATA``. After a successful read, the driver
+drops its active-only runtime PM reference and lets the PM core re-evaluate the
+idle state.
+
+Sysfs entries
+-------------
+
+======================= =====================================================
+temp1_input Temperature in millidegrees Celsius
+======================= =====================================================
+
+The hwmon device name is ``prom21_xhci``. The sysfs path depends on the hwmon
+device number assigned by the kernel. Userspace can locate the device by
+matching the ``name`` attribute:
+
+.. code-block:: sh
+
+ for hwmon in /sys/class/hwmon/hwmon*; do
+ [ "$(cat "$hwmon/name")" = "prom21_xhci" ] || continue
+ cat "$hwmon/temp1_input"
+ done
+
+If the raw register value is invalid, ``temp1_input`` returns ``-ENODATA``.
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 14e4cea48acc..fe0f14e247b5 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -951,6 +951,16 @@ config SENSORS_POWR1220
This driver can also be built as a module. If so, the module
will be called powr1220.
+config SENSORS_PROM21_XHCI
+ tristate "AMD Promontory 21 xHCI temperature sensor"
+ depends on USB_XHCI_PCI_PROM21
+ help
+ If you say yes here you get support for the AMD Promontory 21
+ (PROM21) xHCI temperature sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called prom21-xhci.
+
config SENSORS_LAN966X
tristate "Microchip LAN966x Hardware Monitoring"
depends on SOC_LAN966 || COMPILE_TEST
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 982ee2c6f9de..f833aed890d8 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -196,6 +196,7 @@ obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
obj-$(CONFIG_SENSORS_POWERZ) += powerz.o
obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o
+obj-$(CONFIG_SENSORS_PROM21_XHCI) += prom21-xhci.o
obj-$(CONFIG_SENSORS_PT5161L) += pt5161l.o
obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
obj-$(CONFIG_SENSORS_QNAP_MCU_HWMON) += qnap-mcu-hwmon.o
diff --git a/drivers/hwmon/prom21-xhci.c b/drivers/hwmon/prom21-xhci.c
new file mode 100644
index 000000000000..7124824a1f5e
--- /dev/null
+++ b/drivers/hwmon/prom21-xhci.c
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AMD Promontory 21 xHCI Hwmon Implementation
+ * (only temperature monitoring is supported)
+ *
+ * This can be effectively used as the alternative chipset temperature monitor.
+ *
+ * Copyright (C) 2026 Jihong Min <hurryman2212@gmail.com>
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/hwmon.h>
+#include <linux/io.h>
+#include <linux/math.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_data/usb-xhci-prom21.h>
+#include <linux/pm_runtime.h>
+
+#define PROM21_XHCI_INDEX_OFFSET 0x3000
+#define PROM21_XHCI_DATA_OFFSET 0x3008
+#define PROM21_XHCI_TEMP_SELECTOR 0x0001e520
+
+struct prom21_xhci {
+ struct pci_dev *pdev;
+ struct device *hwmon_dev;
+ void __iomem *regs;
+};
+
+static int prom21_xhci_pm_get(struct prom21_xhci *hwmon)
+{
+ struct device *dev = &hwmon->pdev->dev;
+ int ret;
+
+ /*
+ * PROM21 temperature register access does not return a valid value while
+ * the parent xHCI PCI function is suspended. Do not wake the device from
+ * a hwmon read. On success, hold a usage reference without changing the
+ * runtime PM state; if runtime PM is disabled, allow the read unless the
+ * device is still marked suspended.
+ */
+ ret = pm_runtime_get_if_active(dev);
+ if (ret > 0)
+ return 0;
+
+ if (ret == -EINVAL) {
+ if (pm_runtime_status_suspended(dev))
+ return -ENODATA;
+
+ pm_runtime_get_noresume(dev);
+ return 0;
+ }
+
+ if (!ret)
+ return -ENODATA;
+
+ return ret;
+}
+
+/*
+ * This is not a pure MMIO read. The PROM21 vendor data register is selected
+ * by temporarily writing PROM21_XHCI_TEMP_SELECTOR to the vendor index
+ * register.
+ * The hwmon core already serializes this driver's callbacks, so this driver
+ * does not need an additional private lock. That does not synchronize with
+ * firmware, SMM, ACPI, or other possible users. Keep the sequence short and
+ * restore the previous index before returning.
+ */
+static int prom21_xhci_read_temp_raw_restore_index(struct prom21_xhci *hwmon,
+ u8 *raw)
+{
+ struct device *dev = &hwmon->pdev->dev;
+ u32 index;
+ u8 data;
+ int ret;
+
+ ret = prom21_xhci_pm_get(hwmon);
+ if (ret)
+ return ret;
+
+ index = readl(hwmon->regs + PROM21_XHCI_INDEX_OFFSET);
+ /* Select the PROM21 temperature register through the vendor index. */
+ writel(PROM21_XHCI_TEMP_SELECTOR,
+ hwmon->regs + PROM21_XHCI_INDEX_OFFSET);
+ data = readb(hwmon->regs + PROM21_XHCI_DATA_OFFSET);
+ /* Restore the previous vendor index register value. */
+ writel(index, hwmon->regs + PROM21_XHCI_INDEX_OFFSET);
+ readl(hwmon->regs + PROM21_XHCI_INDEX_OFFSET);
+
+ /*
+ * Drop the usage reference taken by prom21_xhci_pm_get(). This is
+ * enough because the read path never resumes the device; use the normal
+ * put path so the PM core can re-evaluate idle state after the read.
+ * Otherwise, a racing xHCI autosuspend attempt can see a nonzero
+ * runtime PM usage count and skip autosuspend, and a later
+ * pm_runtime_put_noidle(), which does not check for an idle device,
+ * would leave the device active.
+ */
+ pm_runtime_put(dev);
+
+ if (!data)
+ return -ENODATA;
+
+ *raw = data;
+ return 0;
+}
+
+static long prom21_xhci_raw_to_millicelsius(u8 raw)
+{
+ /*
+ * No public AMD reference is available for this value.
+ * The scale was derived from observed PROM21 xHCI temperature readings:
+ * temp[C] = raw * 0.9066 - 78.624
+ */
+ return DIV_ROUND_CLOSEST(raw * 9066, 10) - 78624;
+}
+
+static umode_t prom21_xhci_is_visible(const void *drvdata,
+ enum hwmon_sensor_types type, u32 attr,
+ int channel)
+{
+ if (type != hwmon_temp)
+ return 0;
+
+ switch (attr) {
+ case hwmon_temp_input:
+ return 0444;
+ default:
+ return 0;
+ }
+}
+
+static int prom21_xhci_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct prom21_xhci *hwmon = dev_get_drvdata(dev);
+ u8 raw;
+ int ret;
+
+ if (type != hwmon_temp || attr != hwmon_temp_input)
+ return -EOPNOTSUPP;
+
+ ret = prom21_xhci_read_temp_raw_restore_index(hwmon, &raw);
+ if (ret)
+ return ret;
+
+ *val = prom21_xhci_raw_to_millicelsius(raw);
+ return 0;
+}
+
+static const struct hwmon_ops prom21_xhci_ops = {
+ .is_visible = prom21_xhci_is_visible,
+ .read = prom21_xhci_read,
+};
+
+static const struct hwmon_channel_info *const prom21_xhci_info[] = {
+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
+ NULL,
+};
+
+static const struct hwmon_chip_info prom21_xhci_chip_info = {
+ .ops = &prom21_xhci_ops,
+ .info = prom21_xhci_info,
+};
+
+static int prom21_xhci_probe(struct auxiliary_device *auxdev,
+ const struct auxiliary_device_id *id)
+{
+ struct device *dev = &auxdev->dev;
+ const struct prom21_xhci_pdata *pdata = dev_get_platdata(dev);
+ struct prom21_xhci *hwmon;
+
+ if (!pdata)
+ return dev_err_probe(dev, -ENODEV,
+ "platform data unavailable\n");
+
+ if (!pdata->regs ||
+ pdata->rsrc_len < PROM21_XHCI_DATA_OFFSET + sizeof(u8))
+ return dev_err_probe(dev, -ENODEV, "invalid MMIO resource\n");
+
+ hwmon = devm_kzalloc(dev, sizeof(*hwmon), GFP_KERNEL);
+ if (!hwmon)
+ return -ENOMEM;
+
+ hwmon->pdev = pdata->pdev;
+ hwmon->regs = pdata->regs;
+ auxiliary_set_drvdata(auxdev, hwmon);
+
+ /*
+ * Parent the hwmon device to the PCI function because the temperature
+ * value is read from that function's MMIO BAR, and systems may contain
+ * multiple PROM21 xHCI functions. This lets userspace identify the PCI
+ * endpoint for each reading. The auxiliary driver still owns the hwmon
+ * lifetime and unregisters it before HCD teardown.
+ */
+ hwmon->hwmon_dev =
+ hwmon_device_register_with_info(&pdata->pdev->dev, "prom21_xhci",
+ hwmon, &prom21_xhci_chip_info,
+ NULL);
+ if (IS_ERR(hwmon->hwmon_dev))
+ return PTR_ERR(hwmon->hwmon_dev);
+
+ return 0;
+}
+
+static void prom21_xhci_remove(struct auxiliary_device *auxdev)
+{
+ struct prom21_xhci *hwmon = auxiliary_get_drvdata(auxdev);
+
+ /*
+ * The PROM21 PCI glue destroys the auxiliary device before HCD teardown.
+ * Unregister the hwmon device here so sysfs removes the attributes,
+ * stops new reads, and drains active hwmon callbacks before the xHCI
+ * MMIO mapping is released.
+ */
+ hwmon_device_unregister(hwmon->hwmon_dev);
+}
+
+static const struct auxiliary_device_id prom21_xhci_id_table[] = {
+ { .name = "xhci_pci_prom21.hwmon" },
+ {}
+};
+MODULE_DEVICE_TABLE(auxiliary, prom21_xhci_id_table);
+
+static struct auxiliary_driver prom21_xhci_driver = {
+ .name = "prom21-xhci",
+ .probe = prom21_xhci_probe,
+ .remove = prom21_xhci_remove,
+ .id_table = prom21_xhci_id_table,
+};
+module_auxiliary_driver(prom21_xhci_driver);
+
+MODULE_AUTHOR("Jihong Min <hurryman2212@gmail.com>");
+MODULE_DESCRIPTION("AMD Promontory 21 xHCI temperature sensor driver");
+MODULE_LICENSE("GPL");
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v5 0/2] AMD Promontory 21 xHCI temperature sensor support
2026-05-12 21:39 [PATCH v5 0/2] AMD Promontory 21 xHCI temperature sensor support Jihong Min
2026-05-12 21:39 ` [PATCH v5 1/2] usb: xhci-pci: add AMD Promontory 21 PCI glue Jihong Min
2026-05-12 21:39 ` [PATCH v5 2/2] hwmon: add AMD Promontory 21 xHCI temperature sensor support Jihong Min
@ 2026-05-12 21:49 ` Jihong Min
2026-05-13 14:48 ` Mario Limonciello
3 siblings, 0 replies; 5+ messages in thread
From: Jihong Min @ 2026-05-12 21:49 UTC (permalink / raw)
To: Jihong Min, Greg Kroah-Hartman, Mathias Nyman
Cc: Guenter Roeck, Jonathan Corbet, Shuah Khan, Mario Limonciello,
Basavaraj Natikar, linux-usb, linux-hwmon, linux-doc, linux-pci,
linux-kernel
One additional note about AI assistance and authorship:
I am adding this note because this series has been mentioned in some online
discussions as a newly written Linux driver carrying an AI assistance
tag. I do
not want this to create confusion about authorship or responsibility, so
I would
like to clarify the scope of the AI assistance.
The initial hardware investigation was my work. My starting assumption
was that
the value was exposed through MMIO. I identified the paired MMIO
registers, and
the empirical conversion formula was derived from my own testing,
starting from
the assumption that the raw value could be mapped with a simple linear
formula.
AI assistance was used for writing and refining test scripts around my own
probing library and existing tools such as pciutils, but the probing
approach,
comparison with an existing tool (HWiNFO64), and interpretation of the
results
were mine.
The first hwmon implementation, including the MMIO access sequence, was my
work. I used AI assistance while figuring out how to integrate the
driver with
the existing xhci-pci infrastructure, especially around managed resource
handling and lifetime management.
After review feedback, the design moved toward an auxiliary-device
model. That
direction came from the reviewers. Since I did not have prior experience
with
the auxiliary bus, I used AI assistance extensively while implementing and
iterating on that part. I reviewed and tested the resulting code myself, and
also used AI-assisted review passes to look for mistakes.
In later revisions, the PROM21-specific PCI glue driver and the
platform-data
handoff between the PCI glue and the hwmon auxiliary driver were implemented
based on reviewer feedback and my own PCIe driver experience. The runtime PM
policy was initially chosen by me and later refined through review feedback
from multiple reviewers. The implementation was structured by me based
on that
feedback, with AI assistance used for additional code review and
implementation
checks.
Runtime testing and validation were done by me, using the methods
described in
the driver documentation. The decisions about which reviewer suggestions to
accept and how to revise the design were mine.
I am disclosing this because I want to follow the kernel project's
guidance on
AI-assisted work and be transparent about the process. The Signed-off-by
tag is
mine. I understand that this means I am responsible for the submitted
code, the
design choices, the testing claims, and any mistakes in the patch series.
AI assistance was also used to review and polish some of my English email
replies and documentation wording. I reviewed those texts myself before
sending
them.
P.S. Thanks to Yaroslav Isakov for testing the series on a B850 system and
reporting the additional 1022:43fc PCI ID variant.
Sincerely,
Jihong Min
On 5/13/26 06:39, Jihong Min wrote:
> Hi,
>
> This series adds temperature monitoring for AMD Promontory 21 (PROM21)
> xHCI PCI functions.
>
> Patch 1 adds a small PROM21-specific xHCI PCI glue driver. USB host
> operation is delegated to the common xhci-pci code, while the PROM21 glue
> publishes an auxiliary device for optional sensor support.
>
> Patch 2 adds an auxiliary-bus hwmon driver that binds to that auxiliary
> device and exposes the PROM21 xHCI temperature value as temp1_input.
>
> The hwmon driver reads the sensor through a vendor index/data register pair
> in the xHCI PCI MMIO BAR. It does not wake the parent PCI device for hwmon
> reads; if the parent is suspended, the read returns -ENODATA.
>
> Changes in v5:
> - Add support for AMD 1022:43fc PROM21 xHCI controllers and document the
> new PCI ID.
> - Make USB_XHCI_PCI_PROM21 depend on X86 and default to USB_XHCI_PCI.
> - Keep the PROM21 PCI glue built-in-only when enabled, while allowing the
> hwmon sensor driver to be built as a separate module.
> - Move PROM21 xHCI PCI device IDs to xhci-pci.h so xhci-pci.c and
> xhci-pci-prom21.c use shared definitions.
> - Pass the parent PCI device, MMIO base, and resource length to the hwmon
> driver through platform data defined in a common header, instead of
> inspecting the parent driver's drvdata from the hwmon driver.
> - Remove the private hwmon mutex and rely on hwmon core serialization for
> this driver's callbacks.
> - Clarify that the driver only serializes its own hwmon callbacks and does
> not synchronize with firmware, SMM, ACPI AML, or other possible users of
> the PROM21 vendor index/data register pair.
> - Use readb() for the temperature data register, validate the value before
> writing the output pointer, and drop the 0xff invalid-value check.
> - Use pm_runtime_put() after successful reads with the parent device active
> so the PM core can re-evaluate the parent device's idle state.
> - Simplify the documentation and use more precise terminology for the
> supported device.
>
> Jihong Min (2):
> usb: xhci-pci: add AMD Promontory 21 PCI glue
> hwmon: add AMD Promontory 21 xHCI temperature sensor support
>
> Documentation/hwmon/index.rst | 1 +
> Documentation/hwmon/prom21-xhci.rst | 101 ++++++++
> drivers/hwmon/Kconfig | 10 +
> drivers/hwmon/Makefile | 1 +
> drivers/hwmon/prom21-xhci.c | 238 ++++++++++++++++++
> drivers/usb/host/Kconfig | 20 ++
> drivers/usb/host/Makefile | 1 +
> drivers/usb/host/xhci-pci-prom21.c | 123 +++++++++
> drivers/usb/host/xhci-pci.c | 11 +
> drivers/usb/host/xhci-pci.h | 3 +
> include/linux/platform_data/usb-xhci-prom21.h | 22 ++
> 11 files changed, 531 insertions(+)
> create mode 100644 Documentation/hwmon/prom21-xhci.rst
> create mode 100644 drivers/hwmon/prom21-xhci.c
> create mode 100644 drivers/usb/host/xhci-pci-prom21.c
> create mode 100644 include/linux/platform_data/usb-xhci-prom21.h
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v5 0/2] AMD Promontory 21 xHCI temperature sensor support
2026-05-12 21:39 [PATCH v5 0/2] AMD Promontory 21 xHCI temperature sensor support Jihong Min
` (2 preceding siblings ...)
2026-05-12 21:49 ` [PATCH v5 0/2] " Jihong Min
@ 2026-05-13 14:48 ` Mario Limonciello
3 siblings, 0 replies; 5+ messages in thread
From: Mario Limonciello @ 2026-05-13 14:48 UTC (permalink / raw)
To: Jihong Min, Greg Kroah-Hartman, Mathias Nyman
Cc: Guenter Roeck, Jonathan Corbet, Shuah Khan, Basavaraj Natikar,
linux-usb, linux-hwmon, linux-doc, linux-pci, linux-kernel
On 5/12/26 16:39, Jihong Min wrote:
> Hi,
>
> This series adds temperature monitoring for AMD Promontory 21 (PROM21)
> xHCI PCI functions.
>
> Patch 1 adds a small PROM21-specific xHCI PCI glue driver. USB host
> operation is delegated to the common xhci-pci code, while the PROM21 glue
> publishes an auxiliary device for optional sensor support.
>
> Patch 2 adds an auxiliary-bus hwmon driver that binds to that auxiliary
> device and exposes the PROM21 xHCI temperature value as temp1_input.
>
> The hwmon driver reads the sensor through a vendor index/data register pair
> in the xHCI PCI MMIO BAR. It does not wake the parent PCI device for hwmon
> reads; if the parent is suspended, the read returns -ENODATA.
>
> Changes in v5:
> - Add support for AMD 1022:43fc PROM21 xHCI controllers and document the
> new PCI ID.
> - Make USB_XHCI_PCI_PROM21 depend on X86 and default to USB_XHCI_PCI.
> - Keep the PROM21 PCI glue built-in-only when enabled, while allowing the
> hwmon sensor driver to be built as a separate module.
> - Move PROM21 xHCI PCI device IDs to xhci-pci.h so xhci-pci.c and
> xhci-pci-prom21.c use shared definitions.
> - Pass the parent PCI device, MMIO base, and resource length to the hwmon
> driver through platform data defined in a common header, instead of
> inspecting the parent driver's drvdata from the hwmon driver.
> - Remove the private hwmon mutex and rely on hwmon core serialization for
> this driver's callbacks.
> - Clarify that the driver only serializes its own hwmon callbacks and does
> not synchronize with firmware, SMM, ACPI AML, or other possible users of
> the PROM21 vendor index/data register pair.
> - Use readb() for the temperature data register, validate the value before
> writing the output pointer, and drop the 0xff invalid-value check.
> - Use pm_runtime_put() after successful reads with the parent device active
> so the PM core can re-evaluate the parent device's idle state.
> - Simplify the documentation and use more precise terminology for the
> supported device.
>
> Jihong Min (2):
> usb: xhci-pci: add AMD Promontory 21 PCI glue
> hwmon: add AMD Promontory 21 xHCI temperature sensor support
>
> Documentation/hwmon/index.rst | 1 +
> Documentation/hwmon/prom21-xhci.rst | 101 ++++++++
> drivers/hwmon/Kconfig | 10 +
> drivers/hwmon/Makefile | 1 +
> drivers/hwmon/prom21-xhci.c | 238 ++++++++++++++++++
> drivers/usb/host/Kconfig | 20 ++
> drivers/usb/host/Makefile | 1 +
> drivers/usb/host/xhci-pci-prom21.c | 123 +++++++++
> drivers/usb/host/xhci-pci.c | 11 +
> drivers/usb/host/xhci-pci.h | 3 +
> include/linux/platform_data/usb-xhci-prom21.h | 22 ++
> 11 files changed, 531 insertions(+)
> create mode 100644 Documentation/hwmon/prom21-xhci.rst
> create mode 100644 drivers/hwmon/prom21-xhci.c
> create mode 100644 drivers/usb/host/xhci-pci-prom21.c
> create mode 100644 include/linux/platform_data/usb-xhci-prom21.h
>
Thanks for the driver. I think this looks good now, and thank you
especially for documenting your reverse engineering efforts that led to
it. If there are problems in the future I'm supposing it's going to be
based upon the calculations with the magic values to scale numbers.
There isn't a lot that can be done in the event that BIOS is accessing
the same register pairs, but since you identified that this is exactly
how Windows HWInfo64 does it too; this is 'probably' low risk.
Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-05-13 14:48 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-12 21:39 [PATCH v5 0/2] AMD Promontory 21 xHCI temperature sensor support Jihong Min
2026-05-12 21:39 ` [PATCH v5 1/2] usb: xhci-pci: add AMD Promontory 21 PCI glue Jihong Min
2026-05-12 21:39 ` [PATCH v5 2/2] hwmon: add AMD Promontory 21 xHCI temperature sensor support Jihong Min
2026-05-12 21:49 ` [PATCH v5 0/2] " Jihong Min
2026-05-13 14:48 ` Mario Limonciello
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox