Skip to contentSkip to conversation

hwmon: add Altera SoC FPGA hardware monitoring support

PATCH Superseded [email protected] 4 participants 11 messages Jul 3 – Jul 9

Subsystems (4)

v3 of 8 Superseded Latest is v8 →

lore
Share & tools
lore

[email protected]

author maintainer
#0 lore raw

v3 cover hwmon: add Altera SoC FPGA hardware monitoring support

From: Tze Yee Ng <[email protected]>

This series adds hardware monitor support for Altera SoC FPGA devices. Temperature and voltage sensors are accessed through the Stratix 10 service layer and Secure Device Manager (SDM).

Patch 1 adds async HWMON SMC support to stratix10-svc and registers the socfpga-hwmon platform device.

Patch 2 adds the socfpga-hwmon driver, documentation, Kconfig, and MAINTAINERS entry.

Changes in v3:
- Address review feedback on socfpga-hwmon (Patch 2):
- Fix 16-bit Q8.8 temperature sign extension
- Drop unused async callback; pass NULL to stratix10_svc_async_send()
- Document and retain pre-poll wait (RSU pattern; firmware needs time before async_poll())
- Align async poll retry behaviour with RSU
- Use uninterruptible wait_for_completion_timeout() for sync reads
- Handle -EINVAL and -EOPNOTSUPP when falling back to sync mode
- Defer SVC channel cleanup via devm_add_action_or_reset()
- No functional changes in Patch 1

Changes in v2:
- Drop altr,stratix10-hwmon DT binding and intel,stratix10-svc hwmon child property
- Drop Stratix 10 SoCDK DTS hwmon node
- Register socfpga-hwmon from stratix10-svc (RSU-style)
- Replace DT channel parsing with hardcoded Stratix 10 and Agilex tables
- Rename driver/module to socfpga-hwmon (CONFIG_SENSORS_ALTERA_SOCFPGA_HWMON)
- Add Agilex channel support
- Fix SDM value conversion (Q8.8 degrees Celsius and Q16 volts to hwmon millidegrees/millivolts)
- Improve sync-mode error handling via last_err

Previous version:
https://lore.kernel.org/all/[email protected]/

Tze Yee Ng (2):
firmware: stratix10-svc: add async HWMON read commands and register
socfpga-hwmon device
hwmon: add Altera SoC FPGA hardware monitoring driver

 Documentation/hwmon/index.rst                |   1 +
 Documentation/hwmon/socfpga-hwmon.rst        |  34 ++
 MAINTAINERS                                  |   8 +
 drivers/firmware/stratix10-svc.c             |  46 +-
 drivers/hwmon/Kconfig                        |  10 +
 drivers/hwmon/Makefile                       |   1 +
 drivers/hwmon/socfpga-hwmon.c                | 596 +++++++++++++++++++
 include/linux/firmware/intel/stratix10-smc.h |  38 ++
 8 files changed, 731 insertions(+), 3 deletions(-)
 create mode 100644 Documentation/hwmon/socfpga-hwmon.rst
 create mode 100644 drivers/hwmon/socfpga-hwmon.c
Signature · 1 line
2.43.7
author maintainer
#1 lore raw

PATCH v3 1/2 firmware: stratix10-svc: add async HWMON read commands and register socfpga-hwmon device

From: Tze Yee Ng <[email protected]>

Add asynchronous Stratix 10 service layer support for hardware monitor temperature and voltage read commands in stratix10_svc_async_send() and stratix10_svc_async_prepare_response().

Register a socfpga-hwmon platform device from the service layer driver when hardware monitor support is enabled, similar to the RSU device.

---
Changes in v3:
- No functional changes from v2

Changes in v2:
- Extend patch scope beyond async SMC support: register socfpga-hwmon platform device from stratix10-svc when CONFIG_SENSORS_ALTERA_SOCFPGA_HWMON is enabled
- Follow RSU-style registration; RSU probe error handling is unchanged
- Add err_unregister_clients to unregister hwmon and RSU on populate failure
- Unregister hwmon platform device in stratix10-svc remove()

---
 drivers/firmware/stratix10-svc.c             | 46 ++++++++++++++++++--
 include/linux/firmware/intel/stratix10-smc.h | 38 ++++++++++++++++
 2 files changed, 81 insertions(+), 3 deletions(-)
drivers/firmware/stratix10-svc.c +43 -3
index 00e134e663c8..a72b03c37ea8 100644
@@ -45,6 +45,7 @@
 
 /* stratix10 service layer clients */
 #define STRATIX10_RSU				"stratix10-rsu"
+#define SOCFPGA_HWMON				"socfpga-hwmon"
 
 /* Maximum number of SDM client IDs. */
 #define MAX_SDM_CLIENT_IDS			16
@@ -104,9 +105,11 @@ struct stratix10_svc_chan;
 /**
  * struct stratix10_svc - svc private data
  * @stratix10_svc_rsu: pointer to stratix10 RSU device
+ * @stratix10_svc_hwmon: pointer to stratix10 HWMON device
  */
 struct stratix10_svc {
 	struct platform_device *stratix10_svc_rsu;
+	struct platform_device *stratix10_svc_hwmon;
 };
 
 /**
@@ -1323,6 +1326,14 @@ int stratix10_svc_async_send(struct stratix10_svc_chan *chan, void *msg,
 		args.a0 = INTEL_SIP_SMC_ASYNC_RSU_NOTIFY;
 		args.a2 = p_msg->arg[0];
 		break;
+	case COMMAND_HWMON_READTEMP:
+		args.a0 = INTEL_SIP_SMC_ASYNC_HWMON_READTEMP;
+		args.a2 = p_msg->arg[0];
+		break;
+	case COMMAND_HWMON_READVOLT:
+		args.a0 = INTEL_SIP_SMC_ASYNC_HWMON_READVOLT;
+		args.a2 = p_msg->arg[0];
+		break;
 	default:
 		dev_err(ctrl->dev, "Invalid command ,%d\n", p_msg->command);
 		ret = -EINVAL;
@@ -1416,6 +1427,10 @@ static int stratix10_svc_async_prepare_response(struct stratix10_svc_chan *chan,
 		 */
 		data->kaddr1 = (void *)&handle->res;
 		break;
+	case COMMAND_HWMON_READTEMP:
+	case COMMAND_HWMON_READVOLT:
+		data->kaddr1 = (void *)&handle->res.a2;
+		break;
 
 	default:
 		dev_alert(ctrl->dev, "Invalid command\n ,%d", p_msg->command);
@@ -2000,16 +2015,38 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev)
 	if (ret)
 		goto err_put_device;
 
+	if (IS_ENABLED(CONFIG_SENSORS_ALTERA_SOCFPGA_HWMON)) {
+		svc->stratix10_svc_hwmon =
+			platform_device_alloc(SOCFPGA_HWMON, 0);
+		if (!svc->stratix10_svc_hwmon) {
+			dev_err(dev, "failed to allocate %s device\n",
+				SOCFPGA_HWMON);
+		} else {
+			svc->stratix10_svc_hwmon->dev.parent = dev;
+
+			ret = platform_device_add(svc->stratix10_svc_hwmon);
+			if (ret) {
+				dev_err(dev, "failed to add %s device: %d\n",
+					SOCFPGA_HWMON, ret);
+				platform_device_put(svc->stratix10_svc_hwmon);
+				svc->stratix10_svc_hwmon = NULL;
+			}
+		}
+	}
+
 	ret = of_platform_default_populate(dev_of_node(dev), NULL, dev);
 	if (ret)
-		goto err_unregister_rsu_dev;
+		goto err_unregister_clients;
 
 	pr_info("Intel Service Layer Driver Initialized\n");
 
 	return 0;
 
-err_unregister_rsu_dev:
-	platform_device_unregister(svc->stratix10_svc_rsu);
+err_unregister_clients:
+	if (svc->stratix10_svc_hwmon)
+		platform_device_unregister(svc->stratix10_svc_hwmon);
+	if (svc->stratix10_svc_rsu)
+		platform_device_unregister(svc->stratix10_svc_rsu);
 	goto err_free_fifos;
 err_put_device:
 	platform_device_put(svc->stratix10_svc_rsu);
@@ -2037,6 +2074,9 @@ static void stratix10_svc_drv_remove(struct platform_device *pdev)
 
 	of_platform_depopulate(ctrl->dev);
 
+	if (svc->stratix10_svc_hwmon)
+		platform_device_unregister(svc->stratix10_svc_hwmon);
+
 	platform_device_unregister(svc->stratix10_svc_rsu);
 
 	for (i = 0; i < SVC_NUM_CHANNEL; i++) {
include/linux/firmware/intel/stratix10-smc.h +38 -0
index 9116512169dc..18ac6fe96d9d 100644
@@ -695,6 +695,44 @@ INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_COMPLETED_WRITE)
 #define INTEL_SIP_SMC_ASYNC_POLL \
 	INTEL_SIP_SMC_ASYNC_VAL(INTEL_SIP_SMC_ASYNC_FUNC_ID_POLL)
 
+/**
+ * Request INTEL_SIP_SMC_ASYNC_HWMON_READTEMP
+ * Async call to request temperature
+ *
+ * Call register usage:
+ * a0 INTEL_SIP_SMC_ASYNC_HWMON_READTEMP
+ * a1 transaction job id
+ * a2 Temperature Channel
+ * a3-a17 not used
+ *
+ * Return status
+ * a0 INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_STATUS_REJECTED
+ * or INTEL_SIP_SMC_STATUS_BUSY
+ * a1-a17 not used
+ */
+#define INTEL_SIP_SMC_ASYNC_FUNC_ID_HWMON_READTEMP	0xE8
+#define INTEL_SIP_SMC_ASYNC_HWMON_READTEMP \
+	INTEL_SIP_SMC_ASYNC_VAL(INTEL_SIP_SMC_ASYNC_FUNC_ID_HWMON_READTEMP)
+
+/**
+ * Request INTEL_SIP_SMC_ASYNC_HWMON_READVOLT
+ * Async call to request voltage
+ *
+ * Call register usage:
+ * a0 INTEL_SIP_SMC_ASYNC_HWMON_READVOLT
+ * a1 transaction job id
+ * a2 Voltage Channel
+ * a3-a17 not used
+ *
+ * Return status
+ * a0 INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_STATUS_REJECTED
+ * or INTEL_SIP_SMC_STATUS_BUSY
+ * a1-a17 not used
+ */
+#define INTEL_SIP_SMC_ASYNC_FUNC_ID_HWMON_READVOLT	0xE9
+#define INTEL_SIP_SMC_ASYNC_HWMON_READVOLT \
+	INTEL_SIP_SMC_ASYNC_VAL(INTEL_SIP_SMC_ASYNC_FUNC_ID_HWMON_READVOLT)
+
 /**
  * Request INTEL_SIP_SMC_ASYNC_RSU_GET_SPT
  * Async call to get RSU SPT from SDM.
Signature · 1 line
2.43.7
#2 lore raw

Re: [PATCH v3 1/2] firmware: stratix10-svc: add async HWMON read commands and register socfpga-hwmon device

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

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

Pre-existing issues:
- [High] The async service layer is torn down before the child platform devices (HWMON and RSU) are unregistered, leading to a Use-After-Free and NULL pointer dereference if a concurrent async call is made. --

commit 2c6317a7aef89428e616ea8354fab157b27ff35f
Author: Tze Yee Ng <[email protected]>

firmware: stratix10-svc: add async HWMON read commands and register socfpga-hwmon device

Add asynchronous Stratix 10 service layer support for hardware monitor temperature and voltage read commands. Register a socfpga-hwmon platform device when hardware monitor support is enabled.

Quoted 4 lines
drivers/firmware/stratix10-svc.c +0 -0
index c24ca5823078f..716b58f5a6170 100644

[ ... ]

drivers/firmware/stratix10-svc.c static void stratix10_svc_drv_remove(struct platform_device *pdev) · line 2092

Quoted 7 lines
drivers/firmware/stratix10-svc.c +3 -0
@@ -2050,6 +2087,9 @@ static void stratix10_svc_drv_remove(struct platform_device *pdev)
 
 	of_platform_depopulate(ctrl->dev);
 
+	if (svc->stratix10_svc_hwmon)
+		platform_device_unregister(svc->stratix10_svc_hwmon);
+

[Severity: High]
This is a pre-existing issue, but does unregistering the child devices here introduce a race condition with module removal?

In stratix10_svc_drv_remove(), we tear down the async service layer before the child devices are unregistered:

	stratix10_svc_async_exit(ctrl);
	of_platform_depopulate(ctrl->dev);
	if (svc->stratix10_svc_hwmon)
		platform_device_unregister(svc->stratix10_svc_hwmon);

If a sysfs read for the hwmon device (e.g., temp1_input) races with module unload, could it proceed to stratix10_svc_async_send() because the device is not yet unregistered?

If so, it looks like stratix10_svc_async_send() will dereference the achan structure that was already freed:

	ret = ida_alloc_max(&achan->job_id_pool, MAX_SDM_JOB_IDS,
			    GFP_KERNEL);

And later attempt a NULL pointer dereference, as actrl->invoke_fn was set to NULL by stratix10_svc_async_exit():

	actrl->invoke_fn(actrl, &args, &res);

Should the child platform devices be unregistered before stratix10_svc_async_exit() is called?

Quoted 3 lines
drivers/firmware/stratix10-svc.c +0 -0
 	platform_device_unregister(svc->stratix10_svc_rsu);
 
 	for (i = 0; i < SVC_NUM_CHANNEL; i++) {
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
author maintainer
#3 lore raw

Re: [PATCH v3 1/2] firmware: stratix10-svc: add async HWMON read commands and register socfpga-hwmon device

Quoted 52 lines · On 3/7/2026 4:19 pm, [email protected] wrote:

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

Pre-existing issues:
- [High] The async service layer is torn down before the child platform devices (HWMON and RSU) are unregistered, leading to a Use-After-Free and NULL pointer dereference if a concurrent async call is made. --

commit 2c6317a7aef89428e616ea8354fab157b27ff35f
Author: Tze Yee Ng <[email protected]>

firmware: stratix10-svc: add async HWMON read commands and register socfpga-hwmon device

Add asynchronous Stratix 10 service layer support for hardware monitor temperature and voltage read commands. Register a socfpga-hwmon platform device when hardware monitor support is enabled.

Quoted 4 lines
drivers/firmware/stratix10-svc.c +0 -0
index c24ca5823078f..716b58f5a6170 100644

[ ... ]

drivers/firmware/stratix10-svc.c static void stratix10_svc_drv_remove(struct platform_device *pdev) · line 2092

Quoted 7 lines
drivers/firmware/stratix10-svc.c +3 -0
@@ -2050,6 +2087,9 @@ static void stratix10_svc_drv_remove(struct platform_device *pdev)
 
  	of_platform_depopulate(ctrl->dev);
 
+	if (svc->stratix10_svc_hwmon)
+		platform_device_unregister(svc->stratix10_svc_hwmon);
+

[Severity: High]
This is a pre-existing issue, but does unregistering the child devices here introduce a race condition with module removal?

In stratix10_svc_drv_remove(), we tear down the async service layer before the child devices are unregistered:

	stratix10_svc_async_exit(ctrl);
	of_platform_depopulate(ctrl->dev);
	if (svc->stratix10_svc_hwmon)
		platform_device_unregister(svc->stratix10_svc_hwmon);

If a sysfs read for the hwmon device (e.g., temp1_input) races with module unload, could it proceed to stratix10_svc_async_send() because the device is not yet unregistered?

If so, it looks like stratix10_svc_async_send() will dereference the achan structure that was already freed:

	ret = ida_alloc_max(&achan->job_id_pool, MAX_SDM_JOB_IDS,
			    GFP_KERNEL);
Quoted 12 lines

And later attempt a NULL pointer dereference, as actrl->invoke_fn was set to NULL by stratix10_svc_async_exit():

	actrl->invoke_fn(actrl, &args, &res);

Should the child platform devices be unregistered before stratix10_svc_async_exit() is called?

Quoted 3 lines
drivers/firmware/stratix10-svc.c +0 -0
  	platform_device_unregister(svc->stratix10_svc_rsu);
 
  	for (i = 0; i < SVC_NUM_CHANNEL; i++) {

Hi,

Agreed with Sashiko's comment. In stratix10_svc_drv_remove(), stratix10_svc_async_exit() currently runs before the hwmon and RSU platform devices are unregistered. A concurrent sysfs read could still reach stratix10_svc_async_send() and use resources already torn down by stratix10_svc_async_exit().

This ordering predates the hwmon registration in this series; RSU follows the same pattern today. The fix would be to unregister child platform devices (and depopulate) before calling stratix10_svc_async_exit().

We can include that reorder in this series, or send it as a separate stratix10-svc fix.

Let us know your preference.

Thanks,
Tze Yee

maintainer
#4 lore raw

Re: [PATCH v3 1/2] firmware: stratix10-svc: add async HWMON read commands and register socfpga-hwmon device

Quoted 74 lines · TZE YEE
Quoted 52 lines · On 3/7/2026 4:19 pm, [email protected] wrote:

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

Pre-existing issues:
- [High] The async service layer is torn down before the child platform devices (HWMON and RSU) are unregistered, leading to a Use-After-Free and NULL pointer dereference if a concurrent async call is made. --

commit 2c6317a7aef89428e616ea8354fab157b27ff35f
Author: Tze Yee Ng <[email protected]>

firmware: stratix10-svc: add async HWMON read commands and register socfpga-hwmon device

Add asynchronous Stratix 10 service layer support for hardware monitor temperature and voltage read commands. Register a socfpga-hwmon platform device when hardware monitor support is enabled.

Quoted 4 lines
drivers/firmware/stratix10-svc.c +0 -0
index c24ca5823078f..716b58f5a6170 100644

[ ... ]

drivers/firmware/stratix10-svc.c static void stratix10_svc_drv_remove(struct platform_device *pdev) · line 2092

Quoted 7 lines
drivers/firmware/stratix10-svc.c +3 -0
@@ -2050,6 +2087,9 @@ static void stratix10_svc_drv_remove(struct platform_device *pdev)
 
   	of_platform_depopulate(ctrl->dev);
 
+	if (svc->stratix10_svc_hwmon)
+		platform_device_unregister(svc->stratix10_svc_hwmon);
+

[Severity: High]
This is a pre-existing issue, but does unregistering the child devices here introduce a race condition with module removal?

In stratix10_svc_drv_remove(), we tear down the async service layer before the child devices are unregistered:

	stratix10_svc_async_exit(ctrl);
	of_platform_depopulate(ctrl->dev);
	if (svc->stratix10_svc_hwmon)
		platform_device_unregister(svc->stratix10_svc_hwmon);

If a sysfs read for the hwmon device (e.g., temp1_input) races with module unload, could it proceed to stratix10_svc_async_send() because the device is not yet unregistered?

If so, it looks like stratix10_svc_async_send() will dereference the achan structure that was already freed:

	ret = ida_alloc_max(&achan->job_id_pool, MAX_SDM_JOB_IDS,
			    GFP_KERNEL);
Quoted 12 lines

And later attempt a NULL pointer dereference, as actrl->invoke_fn was set to NULL by stratix10_svc_async_exit():

	actrl->invoke_fn(actrl, &args, &res);

Should the child platform devices be unregistered before stratix10_svc_async_exit() is called?

Quoted 3 lines
drivers/firmware/stratix10-svc.c +0 -0
   	platform_device_unregister(svc->stratix10_svc_rsu);
 
   	for (i = 0; i < SVC_NUM_CHANNEL; i++) {

Hi,

Agreed with Sashiko's comment. In stratix10_svc_drv_remove(), stratix10_svc_async_exit() currently runs before the hwmon and RSU platform devices are unregistered. A concurrent sysfs read could still reach stratix10_svc_async_send() and use resources already torn down by stratix10_svc_async_exit().

Quoted 7 lines

This ordering predates the hwmon registration in this series; RSU follows the same pattern today. The fix would be to unregister child platform devices (and depopulate) before calling stratix10_svc_async_exit().

We can include that reorder in this series, or send it as a separate stratix10-svc fix.

Please send that as a separate fix.

Thanks,
Dinh

author maintainer
#5 lore raw

Re: [PATCH v3 1/2] firmware: stratix10-svc: add async HWMON read commands and register socfpga-hwmon device

Quoted 92 lines · Dinh Nguyen
Quoted 89 lines · TZE YEE
Quoted 74 lines · On 3/7/2026 4:19 pm, [email protected] wrote:

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

Pre-existing issues:
- [High] The async service layer is torn down before the child platform devices (HWMON and RSU) are unregistered, leading to a Use- After-Free and NULL pointer dereference if a concurrent async call is made.

Signature · 9 lines
commit 2c6317a7aef89428e616ea8354fab157b27ff35f
Author: Tze Yee Ng <[email protected]>

firmware: stratix10-svc: add async HWMON read commands and register 
socfpga-hwmon device

Add asynchronous Stratix 10 service layer support for hardware monitor
temperature and voltage read commands. Register a socfpga-hwmon platform
device when hardware monitor support is enabled.
Quoted 5 lines
drivers/firmware/ renamed from drivers/firmware/stratix10-svc.c +0 -0

stratix10-svc.c
index c24ca5823078f..716b58f5a6170 100644

drivers/firmware/stratix10-svc.c +0 -0

[ ... ]

drivers/firmware/stratix10-svc.c static void stratix10_svc_drv_remove(struct · line 2091

Quoted 6 lines
drivers/firmware/stratix10-svc.c +3 -0
@@ -2050,6 +2087,9 @@ static void stratix10_svc_drv_remove(struct 
 platform_device *pdev)
        of_platform_depopulate(ctrl->dev);
+    if (svc->stratix10_svc_hwmon)
+        platform_device_unregister(svc->stratix10_svc_hwmon);
+

[Severity: High]
This is a pre-existing issue, but does unregistering the child devices here
introduce a race condition with module removal?

In stratix10_svc_drv_remove(), we tear down the async service layer before
the child devices are unregistered:

    stratix10_svc_async_exit(ctrl); of_platform_depopulate(ctrl->dev);
    if (svc->stratix10_svc_hwmon) platform_device_unregister(svc->stratix10_svc_hwmon);

If a sysfs read for the hwmon device (e.g., temp1_input) races with module
unload, could it proceed to stratix10_svc_async_send() because the device
is not yet unregistered?

If so, it looks like stratix10_svc_async_send() will dereference the achan
structure that was already freed:

    ret = ida_alloc_max(&achan->job_id_pool, MAX_SDM_JOB_IDS, GFP_KERNEL);

And later attempt a NULL pointer dereference, as actrl->invoke_fn was set
to NULL by stratix10_svc_async_exit():

    actrl->invoke_fn(actrl, &args, &res);

Should the child platform devices be unregistered before stratix10_svc_async_exit() is called?

Quoted 2 lines
drivers/firmware/stratix10-svc.c +0 -0
        platform_device_unregister(svc->stratix10_svc_rsu);
        for (i = 0; i < SVC_NUM_CHANNEL; i++) {

Hi,

Agreed with Sashiko's comment. In stratix10_svc_drv_remove(), stratix10_svc_async_exit() currently runs before the hwmon and RSU platform devices are unregistered. A concurrent sysfs read could still reach stratix10_svc_async_send() and use resources already torn down by stratix10_svc_async_exit().

This ordering predates the hwmon registration in this series; RSU follows the same pattern today. The fix would be to unregister child platform devices (and depopulate) before calling stratix10_svc_async_exit().

Quoted 8 lines
Quoted 3 lines

We can include that reorder in this series, or send it as a separate stratix10-svc fix.

Please send that as a separate fix.

Thanks,
Dinh

Hi Dinh,

Sure, we will send the fix in a separate patch series.

Thanks,
Tze Yee

author maintainer
#6 lore raw

PATCH v3 2/2 hwmon: add Altera SoC FPGA hardware monitoring driver

In reply to [email protected]

From: Tze Yee Ng <[email protected]>

Add a hardware monitor driver for Altera SoC FPGA devices using the Stratix 10 service layer. Sensor channels are selected based on the service layer compatible string.

---
Changes in v3:
- Fix 16-bit signed Q8.8 temperature conversion (cast through s16)
- Remove unused async callback; pass NULL to stratix10_svc_async_send()
- Keep wait_for_completion_io_timeout() before polling with comment explaining the service layer never invokes the callback but firmware needs time to complete the transaction (RSU pattern)
- Align async poll loop with RSU (retry on failure instead of aborting)
- Use wait_for_completion_timeout() for synchronous reads
- Handle -EINVAL and -EOPNOTSUPP when async client registration fails
- Defer SVC channel/async cleanup via devm_add_action_or_reset(); drop .remove()

Changes in v2:
- Drop altr,stratix10-hwmon OF compatible and DT channel parsing
- Select channels from hardcoded tables using parent SVC compatible (intel,stratix10-svc or intel,agilex-svc)
- Rename driver from stratix10-hwmon to socfpga-hwmon
- Rename Kconfig symbol to CONFIG_SENSORS_ALTERA_SOCFPGA_HWMON
- Add Agilex voltage and temperature channel tables
- Convert SDM Q8.8 degrees Celsius to hwmon millidegrees
- Convert SDM Q16 volts to hwmon millivolts
- Use socfpga_hwmon as hwmon sysfs device name
- Add last_err for synchronous SVC read error propagation
- Update Documentation/hwmon and MAINTAINERS accordingly

---
 Documentation/hwmon/index.rst         |   1 +
 Documentation/hwmon/socfpga-hwmon.rst |  34 ++
 MAINTAINERS                           |   8 +
 drivers/hwmon/Kconfig                 |  10 +
 drivers/hwmon/Makefile                |   1 +
 drivers/hwmon/socfpga-hwmon.c         | 596 ++++++++++++++++++++++++++
 6 files changed, 650 insertions(+)
 create mode 100644 Documentation/hwmon/socfpga-hwmon.rst
 create mode 100644 drivers/hwmon/socfpga-hwmon.c
Documentation/hwmon/index.rst +1 -0
index 8b655e5d6b68..04b3bce60c98 100644
@@ -244,6 +244,7 @@ Hardware Monitoring Kernel Drivers
    sparx5-temp
    spd5118
    stpddc60
+   socfpga-hwmon
    surface_fan
    sy7636a-hwmon
    tc654
Documentation/hwmon/socfpga-hwmon.rst new file +34 -0
new file mode 100644
index 000000000000..e5da42556a62
@@ -0,0 +1,34 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Kernel driver socfpga-hwmon
+=============================
+
+Supported chips:
+
+ * Altera Stratix 10 SoC FPGA
+ * Altera Agilex SoC FPGA
+
+Authors:
+      - Nazim Amirul <[email protected]>
+      - Tze Yee Ng <[email protected]>
+
+Description
+-----------
+
+This driver supports hardware monitoring for Altera SoC
+FPGA devices through the Secure Device Manager and Stratix 10 service layer.
+
+The following sensor types are supported:
+
+  * temperature
+  * voltage
+
+Usage Notes
+-----------
+
+The stratix10-svc driver registers a socfpga-hwmon platform device when
+hardware monitor support is enabled. Sensor channels are selected in the
+driver based on the service layer compatible string:
+
+  * intel,stratix10-svc
+  * intel,agilex-svc
MAINTAINERS +8 -0
index 2fb1c75afd16..5a032c9931c3 100644
@@ -950,6 +950,14 @@ L:	[email protected]
 S:	Maintained
 F:	drivers/gpio/gpio-altera.c
 
+ALTERA SoC FPGA HWMON DRIVER
+M:	Nazim Amirul <[email protected]>
+M:	Tze Yee Ng <[email protected]>
+L:	[email protected]
+S:	Maintained
+F:	Documentation/hwmon/socfpga-hwmon.rst
+F:	drivers/hwmon/socfpga-hwmon.c
+
 ALTERA TRIPLE SPEED ETHERNET DRIVER
 M:	Boon Khai Ng <[email protected]>
 L:	[email protected]
drivers/hwmon/Kconfig +10 -0
index 14e4cea48acc..05a9c7a6647e 100644
@@ -2112,6 +2112,16 @@ config SENSORS_SMSC47M192
 	  This driver can also be built as a module. If so, the module
 	  will be called smsc47m192.
 
+config SENSORS_ALTERA_SOCFPGA_HWMON
+	tristate "Altera SoC FPGA hardware monitoring features"
+	depends on INTEL_STRATIX10_SERVICE
+	help
+	  If you say yes here you get support for the temperature and
+	  voltage sensors of Altera SoC FPGA devices.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called socfpga-hwmon.
+
 config SENSORS_SMSC47B397
 	tristate "SMSC LPC47B397-NC"
 	depends on HAS_IOPORT
drivers/hwmon/Makefile +1 -0
index 4788996aa137..9d1c5f1bf569 100644
@@ -218,6 +218,7 @@ obj-$(CONFIG_SENSORS_SMPRO)	+= smpro-hwmon.o
 obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
 obj-$(CONFIG_SENSORS_SMSC47M1)	+= smsc47m1.o
 obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
+obj-$(CONFIG_SENSORS_ALTERA_SOCFPGA_HWMON)	+= socfpga-hwmon.o
 obj-$(CONFIG_SENSORS_SPARX5)	+= sparx5-temp.o
 obj-$(CONFIG_SENSORS_SPD5118)	+= spd5118.o
 obj-$(CONFIG_SENSORS_STTS751)	+= stts751.o
drivers/hwmon/socfpga-hwmon.c new file +596 -0

596 lines not on this page · raw message

Signature · 1 line
2.43.7
#7 lore raw

Re: [PATCH v3 2/2] hwmon: add Altera SoC FPGA hardware monitoring driver

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [High] Incorrect devm registration order causes a Use-After-Free vulnerability during device unbind or…

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Incorrect devm registration order causes a Use-After-Free vulnerability during device unbind or probe failure.
- [Medium] Unreferenced completion causes a guaranteed maximum timeout delay on every asynchronous sensor read. --

commit 9e088a070299b309352aa9a88006e3927d0c50bd
Author: Tze Yee Ng <[email protected]>

hwmon: add Altera SoC FPGA hardware monitoring driver

Add a hardware monitor driver for Altera SoC FPGA devices using the Stratix 10 service layer. Sensor channels are selected based on the service layer compatible string.

Quoted 4 lines
drivers/hwmon/socfpga-hwmon.c new file +0 -0
new file mode 100644

[ ... ]

Quoted 24 lines
drivers/hwmon/socfpga-hwmon.c new file +24 -0
+static int socfpga_hwmon_async_read(struct device *dev,
+				    enum hwmon_sensor_types type,
+				    struct stratix10_svc_client_msg *msg)
+{
+	struct socfpga_hwmon_priv *priv = dev_get_drvdata(dev);
+	struct stratix10_svc_cb_data data = {};
+	struct completion completion;
+	unsigned long wait_ret;
+	void *handle = NULL;
+	int status, index, ret;
+
+	init_completion(&completion);
+
+	for (index = 0; index < HWMON_ASYNC_MSG_RETRY; index++) {
+		status = stratix10_svc_async_send(priv->chan, msg, &handle,
+						  NULL, NULL);
+		if (status == 0)
+			break;
+		dev_warn(dev, "Failed to send async message: %d", status);
+		msleep(HWMON_RETRY_SLEEP_MS);
+	}
+
+	if (status && !handle) {
+		dev_err(dev, "Failed to send async message after %u retries: %d\n",

drivers/hwmon/socfpga-hwmon.c line 219

Quoted 10 lines
drivers/hwmon/socfpga-hwmon.c new file +10 -0
+			HWMON_ASYNC_MSG_RETRY, status);
+		return status;
+	}
+
+	/*
+	 * The service layer never invokes the async callback, but wait
+	 * before polling anyway: RSU uses the same pattern and the firmware
+	 * needs time to complete the transaction after async_send().
+	 */
+	wait_ret = wait_for_completion_io_timeout(&completion, HWMON_TIMEOUT);

[Severity: Medium]
Will this cause a guaranteed timeout delay on every sensor read?

In socfpga_hwmon_async_read(), a local completion is initialized but is never passed to any asynchronous function or callback (the function stratix10_svc_async_send() receives NULL for the callback).

Because the completion can never be signaled, the execution will unconditionally block in an uninterruptible sleep for the entire HWMON_TIMEOUT duration on every single sensor read. Only after this maximum timeout expires does the function proceed to poll for the response.

Quoted 2 lines
drivers/hwmon/socfpga-hwmon.c new file +2 -0
+	if (wait_ret > 0)
+		dev_dbg(dev, "Received async interrupt\n");

[ ... ]

Quoted 2 lines
drivers/hwmon/socfpga-hwmon.c new file +2 -0
+static int socfpga_hwmon_probe(struct platform_device *pdev)
+{

[ ... ]

drivers/hwmon/socfpga-hwmon.c line 577

Quoted 12 lines
drivers/hwmon/socfpga-hwmon.c new file +12 -0
+	hwmon_dev = devm_hwmon_device_register_with_info(dev, "socfpga_hwmon",
+							 priv,
+							 &socfpga_hwmon_chip_info,
+							 NULL);
+	if (IS_ERR(hwmon_dev)) {
+		if (priv->async)
+			stratix10_svc_remove_async_client(priv->chan);
+		stratix10_svc_free_channel(priv->chan);
+		return PTR_ERR(hwmon_dev);
+	}
+
+	ret = devm_add_action_or_reset(dev, socfpga_hwmon_release_svc, priv);

[Severity: High]
Does this devres registration order create a use-after-free vulnerability during device unbind?

In socfpga_hwmon_probe(), the hwmon device is registered via devm_hwmon_device_register_with_info() before the cleanup action socfpga_hwmon_release_svc is added via devm_add_action_or_reset().

Because devres unwinds actions in reverse order of addition (LIFO), upon device unbind, socfpga_hwmon_release_svc will execute first, freeing the service layer channel (priv->chan).

However, the hwmon device will still be active and its sysfs attributes accessible to user space during this time. A concurrent sysfs read can invoke socfpga_hwmon_read(), which will attempt to use the already-freed priv->chan, resulting in a use-after-free.

Quoted 6 lines
drivers/hwmon/socfpga-hwmon.c new file +6 -0
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, priv);
+	return 0;
+}
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
author maintainer
#8 lore raw

Re: [PATCH v3 2/2] hwmon: add Altera SoC FPGA hardware monitoring driver

Quoted 102 lines · On 3/7/2026 4:18 pm, [email protected] wrote:

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Incorrect devm registration order causes a Use-After-Free vulnerability during device unbind or probe failure.
- [Medium] Unreferenced completion causes a guaranteed maximum timeout delay on every asynchronous sensor read. --

commit 9e088a070299b309352aa9a88006e3927d0c50bd
Author: Tze Yee Ng <[email protected]>

hwmon: add Altera SoC FPGA hardware monitoring driver

Add a hardware monitor driver for Altera SoC FPGA devices using the Stratix 10 service layer. Sensor channels are selected based on the service layer compatible string.

Quoted 4 lines
drivers/hwmon/socfpga-hwmon.c new file +0 -0
new file mode 100644

[ ... ]

Quoted 24 lines
drivers/hwmon/socfpga-hwmon.c new file +24 -0
+static int socfpga_hwmon_async_read(struct device *dev,
+				    enum hwmon_sensor_types type,
+				    struct stratix10_svc_client_msg *msg)
+{
+	struct socfpga_hwmon_priv *priv = dev_get_drvdata(dev);
+	struct stratix10_svc_cb_data data = {};
+	struct completion completion;
+	unsigned long wait_ret;
+	void *handle = NULL;
+	int status, index, ret;
+
+	init_completion(&completion);
+
+	for (index = 0; index < HWMON_ASYNC_MSG_RETRY; index++) {
+		status = stratix10_svc_async_send(priv->chan, msg, &handle,
+						  NULL, NULL);
+		if (status == 0)
+			break;
+		dev_warn(dev, "Failed to send async message: %d", status);
+		msleep(HWMON_RETRY_SLEEP_MS);
+	}
+
+	if (status && !handle) {
+		dev_err(dev, "Failed to send async message after %u retries: %d\n",

drivers/hwmon/socfpga-hwmon.c line 219

Quoted 10 lines
drivers/hwmon/socfpga-hwmon.c new file +10 -0
+			HWMON_ASYNC_MSG_RETRY, status);
+		return status;
+	}
+
+	/*
+	 * The service layer never invokes the async callback, but wait
+	 * before polling anyway: RSU uses the same pattern and the firmware
+	 * needs time to complete the transaction after async_send().
+	 */
+	wait_ret = wait_for_completion_io_timeout(&completion, HWMON_TIMEOUT);

[Severity: Medium]
Will this cause a guaranteed timeout delay on every sensor read?

In socfpga_hwmon_async_read(), a local completion is initialized but is never passed to any asynchronous function or callback (the function stratix10_svc_async_send() receives NULL for the callback).

Because the completion can never be signaled, the execution will unconditionally block in an uninterruptible sleep for the entire HWMON_TIMEOUT duration on every single sensor read. Only after this maximum timeout expires does the function proceed to poll for the response.

Quoted 2 lines
drivers/hwmon/socfpga-hwmon.c new file +2 -0
+	if (wait_ret > 0)
+		dev_dbg(dev, "Received async interrupt\n");

[ ... ]

Quoted 2 lines
drivers/hwmon/socfpga-hwmon.c new file +2 -0
+static int socfpga_hwmon_probe(struct platform_device *pdev)
+{

[ ... ]

drivers/hwmon/socfpga-hwmon.c line 577

Quoted 12 lines
drivers/hwmon/socfpga-hwmon.c new file +12 -0
+	hwmon_dev = devm_hwmon_device_register_with_info(dev, "socfpga_hwmon",
+							 priv,
+							 &socfpga_hwmon_chip_info,
+							 NULL);
+	if (IS_ERR(hwmon_dev)) {
+		if (priv->async)
+			stratix10_svc_remove_async_client(priv->chan);
+		stratix10_svc_free_channel(priv->chan);
+		return PTR_ERR(hwmon_dev);
+	}
+
+	ret = devm_add_action_or_reset(dev, socfpga_hwmon_release_svc, priv);

[Severity: High]
Does this devres registration order create a use-after-free vulnerability during device unbind?

In socfpga_hwmon_probe(), the hwmon device is registered via devm_hwmon_device_register_with_info() before the cleanup action socfpga_hwmon_release_svc is added via devm_add_action_or_reset().

Because devres unwinds actions in reverse order of addition (LIFO), upon device unbind, socfpga_hwmon_release_svc will execute first, freeing the service layer channel (priv->chan).

However, the hwmon device will still be active and its sysfs attributes accessible to user space during this time. A concurrent sysfs read can invoke socfpga_hwmon_read(), which will attempt to use the already-freed priv->chan, resulting in a use-after-free.

Quoted 7 lines

drivers/hwmon/socfpga-hwmon.c line 583

Quoted 6 lines
drivers/hwmon/socfpga-hwmon.c new file +6 -0
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, priv);
+	return 0;
+}

Hi maintainers,

1. [High] Incorrect devm registration order causes a Use-After-Free vulnerability during device unbind or probe failure.

Agreed. v4 will register devm_add_action_or_reset() before devm_hwmon_device_register_with_info(), matching other hwmon drivers (e.g. pwm-fan, qnap-mcu-hwmon). On hwmon registration failure, probe returns and devm runs the release action automatically, so manual channel cleanup on that path is no longer needed.

2. [Medium] Unreferenced completion causes a guaranteed maximum timeout delay on every asynchronous sensor read.

Agreed that the completion is never signaled because the service layer does not invoke the async callback. rsu_send_async_msg() in stratix10-rsu.c uses the same send → wait → poll pattern, so we followed RSU for consistency with the existing Stratix 10 async SVC client.

We are happy to change this if you prefer — for example a deadline-based poll loop without the fixed wait, or a proper fix in stratix10-svc to invoke the callback. Please let us know your preference.

We will send v4 with the devm fix; the async wait approach can follow your guidance above.

Thanks,
Tze Yee

maintainer
#9 lore raw

Re: [PATCH v3 2/2] hwmon: add Altera SoC FPGA hardware monitoring driver

Quoted 122 lines · TZE YEE
Quoted 102 lines · On 3/7/2026 4:18 pm, [email protected] wrote:

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Incorrect devm registration order causes a Use-After-Free vulnerability during device unbind or probe failure.
- [Medium] Unreferenced completion causes a guaranteed maximum timeout delay on every asynchronous sensor read. --

commit 9e088a070299b309352aa9a88006e3927d0c50bd
Author: Tze Yee Ng <[email protected]>

hwmon: add Altera SoC FPGA hardware monitoring driver

Add a hardware monitor driver for Altera SoC FPGA devices using the Stratix 10 service layer. Sensor channels are selected based on the service layer compatible string.

Quoted 4 lines
drivers/hwmon/socfpga-hwmon.c new file +0 -0
new file mode 100644

[ ... ]

Quoted 24 lines
drivers/hwmon/socfpga-hwmon.c new file +24 -0
+static int socfpga_hwmon_async_read(struct device *dev,
+				    enum hwmon_sensor_types type,
+				    struct stratix10_svc_client_msg *msg)
+{
+	struct socfpga_hwmon_priv *priv = dev_get_drvdata(dev);
+	struct stratix10_svc_cb_data data = {};
+	struct completion completion;
+	unsigned long wait_ret;
+	void *handle = NULL;
+	int status, index, ret;
+
+	init_completion(&completion);
+
+	for (index = 0; index < HWMON_ASYNC_MSG_RETRY; index++) {
+		status = stratix10_svc_async_send(priv->chan, msg, &handle,
+						  NULL, NULL);
+		if (status == 0)
+			break;
+		dev_warn(dev, "Failed to send async message: %d", status);
+		msleep(HWMON_RETRY_SLEEP_MS);
+	}
+
+	if (status && !handle) {
+		dev_err(dev, "Failed to send async message after %u retries: %d\n",

drivers/hwmon/socfpga-hwmon.c line 219

Quoted 10 lines
drivers/hwmon/socfpga-hwmon.c new file +10 -0
+			HWMON_ASYNC_MSG_RETRY, status);
+		return status;
+	}
+
+	/*
+	 * The service layer never invokes the async callback, but wait
+	 * before polling anyway: RSU uses the same pattern and the firmware
+	 * needs time to complete the transaction after async_send().
+	 */
+	wait_ret = wait_for_completion_io_timeout(&completion, HWMON_TIMEOUT);

[Severity: Medium]
Will this cause a guaranteed timeout delay on every sensor read?

In socfpga_hwmon_async_read(), a local completion is initialized but is never passed to any asynchronous function or callback (the function stratix10_svc_async_send() receives NULL for the callback).

Because the completion can never be signaled, the execution will unconditionally block in an uninterruptible sleep for the entire HWMON_TIMEOUT duration on every single sensor read. Only after this maximum timeout expires does the function proceed to poll for the response.

Quoted 2 lines
drivers/hwmon/socfpga-hwmon.c new file +2 -0
+	if (wait_ret > 0)
+		dev_dbg(dev, "Received async interrupt\n");

[ ... ]

Quoted 2 lines
drivers/hwmon/socfpga-hwmon.c new file +2 -0
+static int socfpga_hwmon_probe(struct platform_device *pdev)
+{

[ ... ]

drivers/hwmon/socfpga-hwmon.c line 577

Quoted 12 lines
drivers/hwmon/socfpga-hwmon.c new file +12 -0
+	hwmon_dev = devm_hwmon_device_register_with_info(dev, "socfpga_hwmon",
+							 priv,
+							 &socfpga_hwmon_chip_info,
+							 NULL);
+	if (IS_ERR(hwmon_dev)) {
+		if (priv->async)
+			stratix10_svc_remove_async_client(priv->chan);
+		stratix10_svc_free_channel(priv->chan);
+		return PTR_ERR(hwmon_dev);
+	}
+
+	ret = devm_add_action_or_reset(dev, socfpga_hwmon_release_svc, priv);

[Severity: High]
Does this devres registration order create a use-after-free vulnerability during device unbind?

In socfpga_hwmon_probe(), the hwmon device is registered via devm_hwmon_device_register_with_info() before the cleanup action socfpga_hwmon_release_svc is added via devm_add_action_or_reset().

Because devres unwinds actions in reverse order of addition (LIFO), upon device unbind, socfpga_hwmon_release_svc will execute first, freeing the service layer channel (priv->chan).

However, the hwmon device will still be active and its sysfs attributes accessible to user space during this time. A concurrent sysfs read can invoke socfpga_hwmon_read(), which will attempt to use the already-freed priv->chan, resulting in a use-after-free.

Quoted 7 lines

drivers/hwmon/socfpga-hwmon.c line 583

Quoted 6 lines
drivers/hwmon/socfpga-hwmon.c new file +6 -0
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, priv);
+	return 0;
+}

Hi maintainers,

1. [High] Incorrect devm registration order causes a Use-After-Free vulnerability during device unbind or probe failure.

Agreed. v4 will register devm_add_action_or_reset() before devm_hwmon_device_register_with_info(), matching other hwmon drivers (e.g. pwm-fan, qnap-mcu-hwmon). On hwmon registration failure, probe returns and devm runs the release action automatically, so manual channel cleanup on that path is no longer needed.

Quoted 8 lines

2. [Medium] Unreferenced completion causes a guaranteed maximum timeout delay on every asynchronous sensor read.

Agreed that the completion is never signaled because the service layer does not invoke the async callback. rsu_send_async_msg() in stratix10-rsu.c uses the same send → wait → poll pattern, so we followed RSU for consistency with the existing Stratix 10 async SVC client.

Sorry, I am not willing to accept the "other code is buggy, therefore it is ok to introduce the same bug here" argument (Is that some new trend ? I hear it so often lately that I am getting tired of it). You'll have to provide a better argument explaining why it would make sense to call wait_for_completion_io_timeout() if it is known to always time out. You might as well just call usleep_range() or similar; while that would still be bad code, at least it would not be misleading. Just add a comment explaining the reason when you do that.

Guenter

author maintainer
#10 lore raw

Re: [PATCH v3 2/2] hwmon: add Altera SoC FPGA hardware monitoring driver

Quoted 153 lines · Guenter Roeck
Quoted 134 lines · TZE YEE
Quoted 121 lines · On 3/7/2026 4:18 pm, [email protected] wrote:

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Incorrect devm registration order causes a Use-After-Free vulnerability during device unbind or probe failure.
- [Medium] Unreferenced completion causes a guaranteed maximum timeout delay on every asynchronous sensor read.

Signature · 9 lines
commit 9e088a070299b309352aa9a88006e3927d0c50bd
Author: Tze Yee Ng <[email protected]>

hwmon: add Altera SoC FPGA hardware monitoring driver

Add a hardware monitor driver for Altera SoC FPGA devices using the 
Stratix 10
service layer. Sensor channels are selected based on the service layer
compatible string.
Quoted 5 lines
drivers/hwmon/socfpga- renamed from drivers/hwmon/socfpga-hwmon.c +0 -0

hwmon.c
new file mode 100644

drivers/hwmon/socfpga-hwmon.c new file +0 -0

[ ... ]

Quoted 29 lines
drivers/hwmon/socfpga-hwmon.c new file +24 -0
+static int socfpga_hwmon_async_read(struct device *dev,
+                    enum hwmon_sensor_types type,
+                    struct stratix10_svc_client_msg *msg)
+{
+    struct socfpga_hwmon_priv *priv = dev_get_drvdata(dev);
+    struct stratix10_svc_cb_data data = {};
+    struct completion completion;
+    unsigned long wait_ret;
+    void *handle = NULL;
+    int status, index, ret;
+
+    init_completion(&completion);
+
+    for (index = 0; index < HWMON_ASYNC_MSG_RETRY; index++) {
+        status = stratix10_svc_async_send(priv->chan, msg, &handle,
+                          NULL, NULL);
+        if (status == 0)
+            break;
+        dev_warn(dev, "Failed to send async message: %d", status);
+        msleep(HWMON_RETRY_SLEEP_MS);
+    }
+
+    if (status && !handle) {
+        dev_err(dev, "Failed to send async message after %u 

retries: %d\n",
+            HWMON_ASYNC_MSG_RETRY, status);
+        return status;
+    }
+

Quoted 8 lines

+    /*
+     * The service layer never invokes the async callback, but wait +     * before polling anyway: RSU uses the same pattern and the firmware
+     * needs time to complete the transaction after async_send(). +     */
+    wait_ret = wait_for_completion_io_timeout(&completion, HWMON_TIMEOUT);

[Severity: Medium]
Will this cause a guaranteed timeout delay on every sensor read?

In socfpga_hwmon_async_read(), a local completion is initialized but is never passed to any asynchronous function or callback (the function stratix10_svc_async_send() receives NULL for the callback).

Because the completion can never be signaled, the execution will unconditionally block in an uninterruptible sleep for the entire HWMON_TIMEOUT duration on every single sensor read. Only after this maximum
timeout expires does the function proceed to poll for the response.

Quoted 2 lines

+    if (wait_ret > 0)
+        dev_dbg(dev, "Received async interrupt\n");

[ ... ]

Quoted 2 lines
drivers/hwmon/socfpga-hwmon.c new file +2 -0
+static int socfpga_hwmon_probe(struct platform_device *pdev)
+{

[ ... ]

Quoted 6 lines

+    hwmon_dev = devm_hwmon_device_register_with_info(dev, "socfpga_hwmon",
+                             priv,
+                             &socfpga_hwmon_chip_info, +                             NULL);
+    if (IS_ERR(hwmon_dev)) {

Quoted 8 lines

+        if (priv->async)
+            stratix10_svc_remove_async_client(priv->chan); +        stratix10_svc_free_channel(priv->chan);
+        return PTR_ERR(hwmon_dev);
+    }
+
+    ret = devm_add_action_or_reset(dev, socfpga_hwmon_release_svc, priv);

[Severity: High]
Does this devres registration order create a use-after-free vulnerability
during device unbind?

In socfpga_hwmon_probe(), the hwmon device is registered via devm_hwmon_device_register_with_info() before the cleanup action socfpga_hwmon_release_svc is added via devm_add_action_or_reset().

Because devres unwinds actions in reverse order of addition (LIFO), upon device unbind, socfpga_hwmon_release_svc will execute first, freeing the service layer channel (priv->chan).

However, the hwmon device will still be active and its sysfs attributes accessible to user space during this time. A concurrent sysfs read can invoke socfpga_hwmon_read(), which will attempt to use the already-freed priv->chan, resulting in a use-after-free.

drivers/hwmon/socfpga-hwmon.c line 583

Quoted 6 lines

+    if (ret)
+        return ret;

drivers/hwmon/socfpga-hwmon.c new file +4 -0
+
+    platform_set_drvdata(pdev, priv);
+    return 0;
+}

Hi maintainers,

1. [High] Incorrect devm registration order causes a Use-After-Free vulnerability during device unbind or probe failure.

Agreed. v4 will register devm_add_action_or_reset() before devm_hwmon_device_register_with_info(), matching other hwmon drivers (e.g. pwm-fan, qnap-mcu-hwmon). On hwmon registration failure, probe returns and devm runs the release action automatically, so manual channel cleanup on that path is no longer needed.

Quoted 8 lines

2. [Medium] Unreferenced completion causes a guaranteed maximum timeout delay on every asynchronous sensor read.

Agreed that the completion is never signaled because the service layer does not invoke the async callback. rsu_send_async_msg() in stratix10-rsu.c uses the same send → wait → poll pattern, so we followed RSU for consistency with the existing Stratix 10 async SVC client.

Sorry, I am not willing to accept the "other code is buggy, therefore it is ok to introduce the same bug here" argument (Is that some new trend ? I hear it so often lately that I am getting tired of it). You'll have to provide a better argument explaining why it would make sense to call wait_for_completion_io_timeout() if it is known to always time out. You might as well just call usleep_range() or similar; while that would still be bad code, at least it would not be misleading. Just add a comment explaining the reason when you do that.

Quoted 2 lines

Guenter

Hi Guenter,

You are right — arguing that RSU does the same thing is not a good justification, and using wait_for_completion_io_timeout() on a completion that is never signaled is misleading.

After reviewing the stratix10-svc driver, we confirmed that the async path does not invoke the callback registered in stratix10_svc_async_send(); results are obtained via stratix10_svc_async_poll() instead. Completion-based waiting is only appropriate for the synchronous path, where stratix10_svc_send() delivers the response through receive_cb (which signals priv->completion in socfpga_hwmon_sync_read()).

We will remove the local completion and pre-poll wait from socfpga_hwmon_async_read() in v4. After stratix10_svc_async_send(), the driver polls directly with the existing retry loop.

Thanks,
Tze Yee