* [PATCH v5 0/3] firmware: arm_scmi: fix module auto-loading
@ 2026-09-02 18:08 Hans de Goede
2026-09-02 18:08 ` [PATCH v5 1/3] module: add SCMI device table alias support Hans de Goede
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Hans de Goede @ 2026-09-02 18:08 UTC (permalink / raw)
To: Bjorn Andersson, Cristian Marussi, Sudeep Holla
Cc: Hans de Goede, Daniel Lezcano, Bjorn Andersson, Frank.Li,
arm-scmi, linux-arm-kernel, linux-arm-msm, imx, linux-kernel
Hi All,
Here is v5 of the patch series fixing arm_scmi module autoloading this
combines:
1. Patch 1/2 from Bjorn to add support for scmi bus modaliases to modpost:
https://lore.kernel.org/all/20260618-scmi-modalias-v2-1-8c7547c1be21@oss.qualcomm.com/
2. A new patch to always create devices for standard protocols, replacing
Cristian's patch to pre-register the standard protocol device-ids from v4.
1. is not enough by itself because driver module auto-loading requires
the devices to already be created for udev to get the necessary uevents
based on which udev auto-loads modules.
But SCMI devices are only created after their { protocol, name } device-id
has been registered which is done from scmi_driver_register(), creating
a circular dependency.
2. breaks the circular dependency by always creating devices for standard
protocols without relying on the requested-devices list. This creates
devices before the module with the driver is loaded, after which module
auto loading works the same as it does on any other bus.
I've tested this on a T14s Snapdragon laptop with Fedora's kernel config
where scmi_cpufreq is a module. With this series scmi_cpufreq correctly
autoloads even if it is not included in the initramfs.
Changes in v5:
- New patch: "firmware: arm_scmi: Fix scmi_protocol_table_register()
error handling"
- Replace "Pre-register protocol, name tupples for standard protocol" with
"Always create devices for standard protocols" pre-registering requires
scmi_protocol_device_request() to allow duplicate device-ids, but then if
the first driver of two with duplicate devce-ids gets unloaded device
creation for the second driver will fail. Allowing duplicates causes all
kinds of problems, so this new approach avoids this.
- Drop "Pre-register protocol, name tupples for IMX protocols" patch.
Shashiko rightfully turns out this will cause problems if other vendors
also use the same vendor protocol-id space values, e.g. 0x80, 0x81 are
likely to also be used by other vendors.
Changes in v4:
- Drop unused driver_data member from struct scmi_device_id (Uwe)
- Drop device-id/scmi.h include from mod_devicetable.h (Uwe)
- Add device-id/scmi.h to devicetable-offsets.c and file2alias.c (Uwe)
Changes in v3:
- v3 is the first series combining Bjorn and Christian's work see above.
Regards,
Hans
Bjorn Andersson (1):
module: add SCMI device table alias support
Hans de Goede (2):
firmware: arm_scmi: Fix scmi_protocol_table_register() error handling
firmware: arm_scmi: Always create devices for standard protocols
MAINTAINERS | 1 +
drivers/firmware/arm_scmi/bus.c | 97 +++++++++++++++++++++++--------
include/linux/device-id/scmi.h | 17 ++++++
include/linux/scmi_protocol.h | 6 +-
scripts/mod/devicetable-offsets.c | 5 ++
scripts/mod/file2alias.c | 12 ++++
6 files changed, 110 insertions(+), 28 deletions(-)
create mode 100644 include/linux/device-id/scmi.h
--
2.55.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v5 1/3] module: add SCMI device table alias support
2026-09-02 18:08 [PATCH v5 0/3] firmware: arm_scmi: fix module auto-loading Hans de Goede
@ 2026-09-02 18:08 ` Hans de Goede
2026-09-02 18:08 ` [PATCH v5 2/3] firmware: arm_scmi: Fix scmi_protocol_table_register() error handling Hans de Goede
2026-09-02 18:08 ` [PATCH v5 3/3] firmware: arm_scmi: Always create devices for standard protocols Hans de Goede
2 siblings, 0 replies; 4+ messages in thread
From: Hans de Goede @ 2026-09-02 18:08 UTC (permalink / raw)
To: Bjorn Andersson, Cristian Marussi, Sudeep Holla
Cc: Hans de Goede, Daniel Lezcano, Bjorn Andersson, Frank.Li,
arm-scmi, linux-arm-kernel, linux-arm-msm, imx, linux-kernel
From: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
SCMI client drivers already describe their bus match data with
MODULE_DEVICE_TABLE(scmi, ...), but modpost does not know how to consume
SCMI device tables. As a result, SCMI modules do not get generated module
aliases from their id tables.
Move struct scmi_device_id to mod_devicetable.h so it has a fixed layout
visible to modpost, add the corresponding generated offsets and teach
file2alias to emit scmi:<protocol>:<name> aliases.
Use the same stable alias format for SCMI device uevents and sysfs
modaliases. The previous string included the instance-specific device
name, which is not useful for matching modules.
Assisted-by: Codex:GPT-5.5
Reviewed-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
Tested-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
Signed-off-by: Bjorn Andersson <bjorn.andersson@oss.qualcomm.com>
Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
---
Changes in v4:
- Drop unused driver_data member from struct scmi_device_id (Uwe)
- Drop device-id/scmi.h include from mod_devicetable.h (Uwe)
- Add device-id/scmi.h to devicetable-offsets.c and file2alias.c (Uwe)
Changes in v3:
- Adjust for ad428f5811bd ("mod_devicetable.h: Split into per subsystem
headers")
- Add '\n' to modalias_show() output, matching other subsystems' modalias
Changes in v2:
- Drop #include <linux/mod_devicetable.h> from scmi_protocol.h
- Link to v1: https://patch.msgid.link/20260616-scmi-modalias-v1-0-662b8dd52ab2@oss.qualcomm.com
---
MAINTAINERS | 1 +
drivers/firmware/arm_scmi/bus.c | 21 ++++++++++-----------
include/linux/device-id/scmi.h | 17 +++++++++++++++++
include/linux/scmi_protocol.h | 6 +-----
scripts/mod/devicetable-offsets.c | 5 +++++
scripts/mod/file2alias.c | 12 ++++++++++++
6 files changed, 46 insertions(+), 16 deletions(-)
create mode 100644 include/linux/device-id/scmi.h
diff --git a/MAINTAINERS b/MAINTAINERS
index fc6ca082106f..ee5beee606fc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -26334,6 +26334,7 @@ F: drivers/pmdomain/arm/
F: drivers/powercap/arm_scmi_powercap.c
F: drivers/regulator/scmi-regulator.c
F: drivers/reset/reset-scmi.c
+F: include/linux/device-id/scmi.h
F: include/linux/sc[mp]i_protocol.h
F: include/trace/events/scmi.h
F: include/uapi/linux/virtio_scmi.h
diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c
index 793be9eabaed..d12d5de15a1a 100644
--- a/drivers/firmware/arm_scmi/bus.c
+++ b/drivers/firmware/arm_scmi/bus.c
@@ -13,11 +13,12 @@
#include <linux/of.h>
#include <linux/kernel.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/device.h>
#include "common.h"
-#define SCMI_UEVENT_MODALIAS_FMT "%s:%02x:%s"
+#define SCMI_UEVENT_MODALIAS_FMT SCMI_MODULE_PREFIX "%02x:%s"
BLOCKING_NOTIFIER_HEAD(scmi_requested_devices_nh);
EXPORT_SYMBOL_GPL(scmi_requested_devices_nh);
@@ -141,7 +142,7 @@ static int scmi_protocol_table_register(const struct scmi_device_id *id_table)
int ret = 0;
const struct scmi_device_id *entry;
- for (entry = id_table; entry->name && ret == 0; entry++)
+ for (entry = id_table; entry->name[0] && ret == 0; entry++)
ret = scmi_protocol_device_request(entry);
return ret;
@@ -197,18 +198,18 @@ scmi_protocol_table_unregister(const struct scmi_device_id *id_table)
{
const struct scmi_device_id *entry;
- for (entry = id_table; entry->name; entry++)
+ for (entry = id_table; entry->name[0]; entry++)
scmi_protocol_device_unrequest(entry);
}
static int scmi_dev_match_by_id_table(struct scmi_device *scmi_dev,
const struct scmi_device_id *id_table)
{
- if (!id_table || !id_table->name)
+ if (!id_table || !id_table->name[0])
return 0;
/* Always skip transport devices from matching */
- for (; id_table->protocol_id && id_table->name; id_table++)
+ for (; id_table->protocol_id && id_table->name[0]; id_table++)
if (id_table->protocol_id == scmi_dev->protocol_id &&
strncmp(scmi_dev->name, "__scmi_transport_device", 23) &&
!strcmp(id_table->name, scmi_dev->name))
@@ -245,7 +246,7 @@ static struct scmi_device *scmi_child_dev_find(struct device *parent,
struct device *dev;
id_table[0].protocol_id = prot_id;
- id_table[0].name = name;
+ strscpy(id_table[0].name, name, sizeof(id_table[0].name));
dev = device_find_child(parent, &id_table, scmi_match_by_id_table);
if (!dev)
@@ -282,8 +283,7 @@ static int scmi_device_uevent(const struct device *dev, struct kobj_uevent_env *
const struct scmi_device *scmi_dev = to_scmi_dev(dev);
return add_uevent_var(env, "MODALIAS=" SCMI_UEVENT_MODALIAS_FMT,
- dev_name(&scmi_dev->dev), scmi_dev->protocol_id,
- scmi_dev->name);
+ scmi_dev->protocol_id, scmi_dev->name);
}
static ssize_t modalias_show(struct device *dev,
@@ -291,9 +291,8 @@ static ssize_t modalias_show(struct device *dev,
{
struct scmi_device *scmi_dev = to_scmi_dev(dev);
- return sysfs_emit(buf, SCMI_UEVENT_MODALIAS_FMT,
- dev_name(&scmi_dev->dev), scmi_dev->protocol_id,
- scmi_dev->name);
+ return sysfs_emit(buf, SCMI_UEVENT_MODALIAS_FMT "\n",
+ scmi_dev->protocol_id, scmi_dev->name);
}
static DEVICE_ATTR_RO(modalias);
diff --git a/include/linux/device-id/scmi.h b/include/linux/device-id/scmi.h
new file mode 100644
index 000000000000..1b4ccfa9dcc5
--- /dev/null
+++ b/include/linux/device-id/scmi.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef LINUX_DEVICE_ID_SCMI_H
+#define LINUX_DEVICE_ID_SCMI_H
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#endif
+
+#define SCMI_NAME_SIZE 32
+#define SCMI_MODULE_PREFIX "scmi:"
+
+struct scmi_device_id {
+ __u8 protocol_id;
+ char name[SCMI_NAME_SIZE];
+};
+
+#endif /* ifndef LINUX_DEVICE_ID_SCMI_H */
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 5ab73b1ab9aa..ba53302d95f5 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -9,6 +9,7 @@
#define _LINUX_SCMI_PROTOCOL_H
#include <linux/bitfield.h>
+#include <linux/device-id/scmi.h>
#include <linux/device.h>
#include <linux/notifier.h>
#include <linux/types.h>
@@ -951,11 +952,6 @@ struct scmi_device {
#define to_scmi_dev(d) container_of_const(d, struct scmi_device, dev)
-struct scmi_device_id {
- u8 protocol_id;
- const char *name;
-};
-
struct scmi_driver {
const char *name;
int (*probe)(struct scmi_device *sdev);
diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c
index b4178c42d08f..91ec3704ee2b 100644
--- a/scripts/mod/devicetable-offsets.c
+++ b/scripts/mod/devicetable-offsets.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#define COMPILE_OFFSETS
+#include <linux/device-id/scmi.h>
#include <linux/kbuild.h>
#include <linux/mod_devicetable.h>
@@ -144,6 +145,10 @@ int main(void)
DEVID(rpmsg_device_id);
DEVID_FIELD(rpmsg_device_id, name);
+ DEVID(scmi_device_id);
+ DEVID_FIELD(scmi_device_id, protocol_id);
+ DEVID_FIELD(scmi_device_id, name);
+
DEVID(i2c_device_id);
DEVID_FIELD(i2c_device_id, name);
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 8d36c74dec2d..5379b1def07b 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -121,6 +121,7 @@ typedef struct {
/* Big exception to the "don't include kernel headers into userspace, which
* even potentially has different endianness and word sizes, since
* we handle those differences explicitly below */
+#include "../../include/linux/device-id/scmi.h"
#include "../../include/linux/mod_devicetable.h"
struct devtable {
@@ -852,6 +853,16 @@ static void do_rpmsg_entry(struct module *mod, void *symval)
module_alias_printf(mod, false, RPMSG_DEVICE_MODALIAS_FMT, *name);
}
+/* Looks like: scmi:NN:S */
+static void do_scmi_entry(struct module *mod, void *symval)
+{
+ DEF_FIELD(symval, scmi_device_id, protocol_id);
+ DEF_FIELD_ADDR(symval, scmi_device_id, name);
+
+ module_alias_printf(mod, false, SCMI_MODULE_PREFIX "%02x:%s",
+ protocol_id, *name);
+}
+
/* Looks like: i2c:S */
static void do_i2c_entry(struct module *mod, void *symval)
{
@@ -1491,6 +1502,7 @@ static const struct devtable devtable[] = {
{"virtio", SIZE_virtio_device_id, do_virtio_entry},
{"vmbus", SIZE_hv_vmbus_device_id, do_vmbus_entry},
{"rpmsg", SIZE_rpmsg_device_id, do_rpmsg_entry},
+ {"scmi", SIZE_scmi_device_id, do_scmi_entry},
{"i2c", SIZE_i2c_device_id, do_i2c_entry},
{"i3c", SIZE_i3c_device_id, do_i3c_entry},
{"slim", SIZE_slim_device_id, do_slim_entry},
--
2.55.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v5 2/3] firmware: arm_scmi: Fix scmi_protocol_table_register() error handling
2026-09-02 18:08 [PATCH v5 0/3] firmware: arm_scmi: fix module auto-loading Hans de Goede
2026-09-02 18:08 ` [PATCH v5 1/3] module: add SCMI device table alias support Hans de Goede
@ 2026-09-02 18:08 ` Hans de Goede
2026-09-02 18:08 ` [PATCH v5 3/3] firmware: arm_scmi: Always create devices for standard protocols Hans de Goede
2 siblings, 0 replies; 4+ messages in thread
From: Hans de Goede @ 2026-09-02 18:08 UTC (permalink / raw)
To: Bjorn Andersson, Cristian Marussi, Sudeep Holla
Cc: Hans de Goede, Daniel Lezcano, Bjorn Andersson, Frank.Li,
arm-scmi, linux-arm-kernel, linux-arm-msm, imx, linux-kernel
scmi_protocol_table_register() stops at the first failure to request
one of the scmi_device_id-s into scmi_requested_devices, but it leaves any
previously successfully requested device-ids in place.
Unrequest any successfully requested device-ids on error to fix this.
The code manually unrequests these rather then calling
scmi_protocol_table_unregister() because one way this can fail is because
of duplicate device-ids and in that case the original device-id must not
be unrequested.
This also moves scmi_protocol_table_register() to below
scmi_protocol_device_unrequest() since it now calls that local function.
Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
---
Changes in v5:
- New patch in v5 of this series
---
drivers/firmware/arm_scmi/bus.c | 30 +++++++++++++++++++-----------
1 file changed, 19 insertions(+), 11 deletions(-)
diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c
index d12d5de15a1a..6f667e4ffeed 100644
--- a/drivers/firmware/arm_scmi/bus.c
+++ b/drivers/firmware/arm_scmi/bus.c
@@ -137,17 +137,6 @@ static int scmi_protocol_device_request(const struct scmi_device_id *id_table)
return ret;
}
-static int scmi_protocol_table_register(const struct scmi_device_id *id_table)
-{
- int ret = 0;
- const struct scmi_device_id *entry;
-
- for (entry = id_table; entry->name[0] && ret == 0; entry++)
- ret = scmi_protocol_device_request(entry);
-
- return ret;
-}
-
/**
* scmi_protocol_device_unrequest - Helper to unrequest a device
*
@@ -193,6 +182,25 @@ static void scmi_protocol_device_unrequest(const struct scmi_device_id *id_table
mutex_unlock(&scmi_requested_devices_mtx);
}
+static int scmi_protocol_table_register(const struct scmi_device_id *id_table)
+{
+ int i, ret;
+
+ for (i = 0; id_table[i].name[0]; i++) {
+ ret = scmi_protocol_device_request(&id_table[i]);
+ if (ret)
+ goto error;
+ }
+
+ return 0;
+
+error:
+ while (--i >= 0)
+ scmi_protocol_device_unrequest(&id_table[i]);
+
+ return ret;
+}
+
static void
scmi_protocol_table_unregister(const struct scmi_device_id *id_table)
{
--
2.55.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v5 3/3] firmware: arm_scmi: Always create devices for standard protocols
2026-09-02 18:08 [PATCH v5 0/3] firmware: arm_scmi: fix module auto-loading Hans de Goede
2026-09-02 18:08 ` [PATCH v5 1/3] module: add SCMI device table alias support Hans de Goede
2026-09-02 18:08 ` [PATCH v5 2/3] firmware: arm_scmi: Fix scmi_protocol_table_register() error handling Hans de Goede
@ 2026-09-02 18:08 ` Hans de Goede
2 siblings, 0 replies; 4+ messages in thread
From: Hans de Goede @ 2026-09-02 18:08 UTC (permalink / raw)
To: Bjorn Andersson, Cristian Marussi, Sudeep Holla
Cc: Hans de Goede, Daniel Lezcano, Bjorn Andersson, Frank.Li,
arm-scmi, linux-arm-kernel, linux-arm-msm, imx, linux-kernel
Protocol driver module auto-loading requires the devices to already be
created for udev to get the necessary uevents based on which udev loads
modules. But SCMI devices are only created after their { protocol, name }
device-id has been added to the requested-devices list which is done from
scmi_driver_register().
This creates a circular dependency where device creation is waiting for
the driver to register and loading the module with the driver is waiting
for the device to be created.
Add a list of standard protocol device-ids and always create devices for
these without relying on these being added to the requested-devices list.
This removes the circular dependency, fixing module auto-loading.
Signed-off-by: Hans de Goede <johannes.goede@oss.qualcomm.com>
---
Changes in v5:
- This is a new patch in v5 replacing "Pre-register protocol, name tupples
for standard protocol". Pre-registering requires
scmi_protocol_device_request() to allow duplicate device-ids, but then if
the first driver of two with duplicate devce-ids gets unloaded device
creation for the second driver will fail. Allowing duplicates causes all
kinds of problems, so this new approach avoids this.
---
drivers/firmware/arm_scmi/bus.c | 48 +++++++++++++++++++++++++++++++--
1 file changed, 46 insertions(+), 2 deletions(-)
diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c
index 6f667e4ffeed..10d15da76f19 100644
--- a/drivers/firmware/arm_scmi/bus.c
+++ b/drivers/firmware/arm_scmi/bus.c
@@ -505,6 +505,34 @@ _scmi_device_create(struct device_node *np, struct device *parent,
return sdev;
}
+/* Standard protocols table */
+static const struct scmi_device_id scmi_std_id_table[] = {
+ { SCMI_PROTOCOL_POWER, "genpd" },
+ { SCMI_PROTOCOL_SYSTEM, "syspower" },
+ { SCMI_PROTOCOL_PERF, "perf" },
+ { SCMI_PROTOCOL_PERF, "cpufreq" },
+ { SCMI_PROTOCOL_CLOCK, "clocks" },
+ { SCMI_PROTOCOL_SENSOR, "hwmon" },
+ { SCMI_PROTOCOL_SENSOR, "iiodev" },
+ { SCMI_PROTOCOL_RESET, "reset" },
+ { SCMI_PROTOCOL_VOLTAGE, "regulator" },
+ { SCMI_PROTOCOL_POWERCAP, "powercap" },
+ { SCMI_PROTOCOL_PINCTRL, "pinctrl" },
+ { SCMI_PROTOCOL_PINCTRL, "pinctrl-imx" },
+ { },
+};
+
+static bool scmi_device_id_in_std_id_table(const struct scmi_device_id *id)
+{
+ for (int i = 0; scmi_std_id_table[i].name[0]; i++) {
+ if (scmi_std_id_table[i].protocol_id == id->protocol_id &&
+ !strcmp(scmi_std_id_table[i].name, id->name))
+ return true;
+ }
+
+ return false;
+}
+
/**
* scmi_device_create - A method to create one or more SCMI devices
*
@@ -534,11 +562,25 @@ struct scmi_device *scmi_device_create(struct device_node *np,
{
struct list_head *phead;
struct scmi_requested_dev *rdev;
- struct scmi_device *scmi_dev = NULL;
+ struct scmi_device *sdev, *scmi_dev = NULL;
if (name)
return _scmi_device_create(np, parent, protocol, name);
+ /*
+ * Always create devices for standard protocols, even if the device-ids
+ * have not been registered into scmi_requested_devices yet. This allows
+ * auto-loading of SCMI protocol driver modules for standard protocols.
+ */
+ for (int i = 0; scmi_std_id_table[i].name[0]; i++) {
+ if (scmi_std_id_table[i].protocol_id != protocol)
+ continue;
+
+ sdev = _scmi_device_create(np, parent, protocol, scmi_std_id_table[i].name);
+ if (sdev)
+ scmi_dev = sdev;
+ }
+
mutex_lock(&scmi_requested_devices_mtx);
phead = idr_find(&scmi_requested_devices, protocol);
/* Nothing to do. */
@@ -549,7 +591,9 @@ struct scmi_device *scmi_device_create(struct device_node *np,
/* Walk the list of requested devices for protocol and create them */
list_for_each_entry(rdev, phead, node) {
- struct scmi_device *sdev;
+ /* Standard proto matches already have their dev created above */
+ if (scmi_device_id_in_std_id_table(rdev->id_table))
+ continue;
sdev = _scmi_device_create(np, parent,
rdev->id_table->protocol_id,
--
2.55.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-02 18:09 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-02 18:08 [PATCH v5 0/3] firmware: arm_scmi: fix module auto-loading Hans de Goede
2026-09-02 18:08 ` [PATCH v5 1/3] module: add SCMI device table alias support Hans de Goede
2026-09-02 18:08 ` [PATCH v5 2/3] firmware: arm_scmi: Fix scmi_protocol_table_register() error handling Hans de Goede
2026-09-02 18:08 ` [PATCH v5 3/3] firmware: arm_scmi: Always create devices for standard protocols Hans de Goede
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox