[PATCH] firmware: arm_scpi: publish scpi_ops with release semantics

Jaidev Shastri via B4 Relay devnull+jaidevshastri.vt.edu at kernel.org
Mon Sep 21 18:06:04 PDT 2026


From: Jaidev Shastri <jaidevshastri at vt.edu>

scpi_probe() stores scpi_info early because scpi_init_versions() sends
messages through it, and sets scpi_drvinfo->scpi_ops as its last step.
get_scpi_ops() returns scpi_info->scpi_ops, so the ops pointer is the
gate that scpi-cpufreq, scpi_pm_domain, clk-scpi and scpi-hwmon test
before they use the driver.

Both accesses to scpi_ops are plain, and a consumer that passes the gate
reads scpi_info->channels, ->commands, ->num_chans and
->protocol_version through a fresh load of scpi_info rather than through
the ops pointer. The version fields are written by scpi_init_versions()
after scpi_info was published, so a consumer on another CPU can see a
non-NULL scpi_ops together with stale versions.

Publish scpi_ops with smp_store_release() and read it with
smp_load_acquire() in get_scpi_ops().

Found with MBCheck, a static herd7-based memory consistency checker.

Signed-off-by: Jaidev Shastri <jaidevshastri at vt.edu>
---
 drivers/firmware/arm_scpi.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c
index 68a730d22..eaf8134d7 100644
--- a/drivers/firmware/arm_scpi.c
+++ b/drivers/firmware/arm_scpi.c
@@ -809,7 +809,10 @@ static struct scpi_ops scpi_ops = {
 
 struct scpi_ops *get_scpi_ops(void)
 {
-	return scpi_info ? scpi_info->scpi_ops : NULL;
+	struct scpi_drvinfo *info = READ_ONCE(scpi_info);
+
+	/* Pairs with the smp_store_release() of scpi_ops in scpi_probe(). */
+	return info ? smp_load_acquire(&info->scpi_ops) : NULL;
 }
 EXPORT_SYMBOL_GPL(get_scpi_ops);
 
@@ -1029,7 +1032,13 @@ static int scpi_probe(struct platform_device *pdev)
 			 FIELD_GET(FW_REV_PATCH_MASK,
 				   scpi_drvinfo->firmware_version));
 
-	scpi_drvinfo->scpi_ops = &scpi_ops;
+	/*
+	 * scpi_info is already visible (scpi_init_versions() needs it), so the
+	 * scpi_ops field is what get_scpi_ops() callers gate on. Publish it
+	 * with release semantics so that a consumer that sees the ops also
+	 * sees the channels, the command table and the version fields.
+	 */
+	smp_store_release(&scpi_drvinfo->scpi_ops, &scpi_ops);
 
 	ret = devm_of_platform_populate(dev);
 	if (ret)

---
base-commit: 93f51579e7df248780214094418f205253383cc5
change-id: 20260921-mb-arm-scpi-904141530492

Best regards,
--  
Jaidev Shastri <jaidevshastri at vt.edu>





More information about the linux-arm-kernel mailing list