diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c index 0d28f0f825b6fb1a384b56c3fbe909f5ac7ac68d..de416f9e792132ad944a697a46ac2e87f7a84999 100644 --- a/drivers/firmware/arm_scmi/base.c +++ b/drivers/firmware/arm_scmi/base.c @@ -7,6 +7,7 @@ #define pr_fmt(fmt) "SCMI Notifications BASE - " fmt +#include #include #include "common.h" @@ -373,6 +374,7 @@ static int scmi_base_protocol_init(const struct scmi_protocol_handle *ph) static const struct scmi_protocol scmi_base = { .id = SCMI_PROTOCOL_BASE, + .owner = NULL, .instance_init = &scmi_base_protocol_init, .ops = NULL, .events = &base_protocol_events, diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c index 992d50e101112cbb4edf0557477939a71fbe0486..aadf2da215619db2efc8aa48eee4156b3d0bfee7 100644 --- a/drivers/firmware/arm_scmi/bus.c +++ b/drivers/firmware/arm_scmi/bus.c @@ -56,7 +56,7 @@ const struct scmi_protocol *scmi_protocol_get(int protocol_id) const struct scmi_protocol *proto; proto = idr_find(&scmi_protocols, protocol_id); - if (!proto) { + if (!proto || !try_module_get(proto->owner)) { pr_warn("SCMI Protocol 0x%x not found!\n", protocol_id); return NULL; } @@ -66,6 +66,15 @@ const struct scmi_protocol *scmi_protocol_get(int protocol_id) return proto; } +void scmi_protocol_put(int protocol_id) +{ + const struct scmi_protocol *proto; + + proto = idr_find(&scmi_protocols, protocol_id); + if (proto) + module_put(proto->owner); +} + static int scmi_dev_probe(struct device *dev) { struct scmi_driver *scmi_drv = to_scmi_driver(dev->driver); diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c index 827cf25fc122f969188e136adea7a5ca3abf80bd..35b56c8ba0c0ef7047ecb0e87678df889385758e 100644 --- a/drivers/firmware/arm_scmi/clock.c +++ b/drivers/firmware/arm_scmi/clock.c @@ -5,6 +5,7 @@ * Copyright (C) 2018-2021 ARM Ltd. */ +#include #include #include "common.h" @@ -367,6 +368,7 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph) static const struct scmi_protocol scmi_clock = { .id = SCMI_PROTOCOL_CLOCK, + .owner = THIS_MODULE, .instance_init = &scmi_clock_protocol_init, .ops = &clk_proto_ops, }; diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index c093f332cdcdc5fcf662140e2e3aec79f38be7ab..762dd5419700c133741920603421a1cfad135351 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -214,6 +215,7 @@ typedef int (*scmi_prot_init_ph_fn_t)(const struct scmi_protocol_handle *); /** * struct scmi_protocol - Protocol descriptor * @id: Protocol ID. + * @owner: Module reference if any. * @instance_init: Mandatory protocol initialization function. * @instance_deinit: Optional protocol de-initialization function. * @ops: Optional reference to the operations provided by the protocol and @@ -222,6 +224,7 @@ typedef int (*scmi_prot_init_ph_fn_t)(const struct scmi_protocol_handle *); */ struct scmi_protocol { const u8 id; + struct module *owner; const scmi_prot_init_ph_fn_t instance_init; const scmi_prot_init_ph_fn_t instance_deinit; const void *ops; @@ -257,6 +260,7 @@ void __exit scmi_##name##_unregister(void) \ } const struct scmi_protocol *scmi_protocol_get(int protocol_id); +void scmi_protocol_put(int protocol_id); int scmi_protocol_acquire(const struct scmi_handle *handle, u8 protocol_id); void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id); diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 563a641310357b547c9d0e8a2409df56b5e6c29f..c25c20c150dc961c9b2ecf9e46dd77083c999ec4 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -660,7 +660,8 @@ scmi_revision_area_get(const struct scmi_protocol_handle *ph) * * Context: Assumes to be called with @protocols_mtx already acquired. * Return: A reference to a freshly allocated and initialized protocol instance - * or ERR_PTR on failure. + * or ERR_PTR on failure. On failure the @proto reference is at first + * put using @scmi_protocol_put() before releasing all the devres group. */ static struct scmi_protocol_instance * scmi_alloc_init_protocol_instance(struct scmi_info *info, @@ -673,8 +674,10 @@ scmi_alloc_init_protocol_instance(struct scmi_info *info, /* Protocol specific devres group */ gid = devres_open_group(handle->dev, NULL, GFP_KERNEL); - if (!gid) + if (!gid) { + scmi_protocol_put(proto->id); goto out; + } pi = devm_kzalloc(handle->dev, sizeof(*pi), GFP_KERNEL); if (!pi) @@ -718,6 +721,8 @@ scmi_alloc_init_protocol_instance(struct scmi_info *info, return pi; clean: + /* Take care to put the protocol module's owner before releasing all */ + scmi_protocol_put(proto->id); devres_release_group(handle->dev, gid); out: return ERR_PTR(ret); @@ -732,7 +737,9 @@ scmi_alloc_init_protocol_instance(struct scmi_info *info, * instance, allocate and initialize all the needed structures while handling * resource allocation with a dedicated per-protocol devres subgroup. * - * Return: A reference to an initialized protocol instance or error on failure. + * Return: A reference to an initialized protocol instance or error on failure: + * in particular returns -EPROBE_DEFER when the desired protocol could + * NOT be found. */ static struct scmi_protocol_instance * __must_check scmi_get_protocol_instance(const struct scmi_handle *handle, u8 protocol_id) @@ -753,7 +760,7 @@ scmi_get_protocol_instance(const struct scmi_handle *handle, u8 protocol_id) if (proto) pi = scmi_alloc_init_protocol_instance(info, proto); else - pi = ERR_PTR(-ENODEV); + pi = ERR_PTR(-EPROBE_DEFER); } mutex_unlock(&info->protocols_mtx); @@ -804,6 +811,8 @@ void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id) idr_remove(&info->protocols, protocol_id); + scmi_protocol_put(protocol_id); + devres_release_group(handle->dev, gid); dev_dbg(handle->dev, "De-Initialized protocol: 0x%X\n", protocol_id); diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index 059d6214f93b8c769d32811265bee08e0a608f01..f4cd5193b9617f8ed70bd3d5fd10d24573130c96 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -909,6 +910,7 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph) static const struct scmi_protocol scmi_perf = { .id = SCMI_PROTOCOL_PERF, + .owner = THIS_MODULE, .instance_init = &scmi_perf_protocol_init, .ops = &perf_proto_ops, .events = &perf_protocol_events, diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c index e0987f0a8fb276ecbc9f925b9b7fd6320e4cc725..ad2ab080f3443c251153fa606f2f4fd53e369655 100644 --- a/drivers/firmware/arm_scmi/power.c +++ b/drivers/firmware/arm_scmi/power.c @@ -7,6 +7,7 @@ #define pr_fmt(fmt) "SCMI Notifications POWER - " fmt +#include #include #include "common.h" @@ -312,6 +313,7 @@ static int scmi_power_protocol_init(const struct scmi_protocol_handle *ph) static const struct scmi_protocol scmi_power = { .id = SCMI_PROTOCOL_POWER, + .owner = THIS_MODULE, .instance_init = &scmi_power_protocol_init, .ops = &power_proto_ops, .events = &power_protocol_events, diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c index 48b487302db8372fb373bda5dfcfc87a86b70900..9bf2478ec6d1765d81e8afafc8b9ec4df0b74ebc 100644 --- a/drivers/firmware/arm_scmi/reset.c +++ b/drivers/firmware/arm_scmi/reset.c @@ -7,6 +7,7 @@ #define pr_fmt(fmt) "SCMI Notifications RESET - " fmt +#include #include #include "common.h" @@ -324,6 +325,7 @@ static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph) static const struct scmi_protocol scmi_reset = { .id = SCMI_PROTOCOL_RESET, + .owner = THIS_MODULE, .instance_init = &scmi_reset_protocol_init, .ops = &reset_proto_ops, .events = &reset_protocol_events, diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c index 935c4b08829dab914bdb841c3d3e0d5aa60f05ba..2c88aa22155972e1085b60faa4223dec3f1012dd 100644 --- a/drivers/firmware/arm_scmi/sensors.c +++ b/drivers/firmware/arm_scmi/sensors.c @@ -8,6 +8,7 @@ #define pr_fmt(fmt) "SCMI Notifications SENSOR - " fmt #include +#include #include #include "common.h" @@ -990,6 +991,7 @@ static int scmi_sensors_protocol_init(const struct scmi_protocol_handle *ph) static const struct scmi_protocol scmi_sensors = { .id = SCMI_PROTOCOL_SENSOR, + .owner = THIS_MODULE, .instance_init = &scmi_sensors_protocol_init, .ops = &sensor_proto_ops, .events = &sensor_protocol_events, diff --git a/drivers/firmware/arm_scmi/system.c b/drivers/firmware/arm_scmi/system.c index 3631a9f94d277761c4ac3a319a41a923ca07326b..e5175ef73b40e0d0375466f647203dd91299f3eb 100644 --- a/drivers/firmware/arm_scmi/system.c +++ b/drivers/firmware/arm_scmi/system.c @@ -7,6 +7,7 @@ #define pr_fmt(fmt) "SCMI Notifications SYSTEM - " fmt +#include #include #include "common.h" @@ -130,6 +131,7 @@ static int scmi_system_protocol_init(const struct scmi_protocol_handle *ph) static const struct scmi_protocol scmi_system = { .id = SCMI_PROTOCOL_SYSTEM, + .owner = THIS_MODULE, .instance_init = &scmi_system_protocol_init, .ops = NULL, .events = &system_protocol_events, diff --git a/drivers/firmware/arm_scmi/voltage.c b/drivers/firmware/arm_scmi/voltage.c index 364bc14aa5fe7d62fd27f589ee979f1b09a1d8aa..a5048956a0be9441be1cb9035b50933b929d658e 100644 --- a/drivers/firmware/arm_scmi/voltage.c +++ b/drivers/firmware/arm_scmi/voltage.c @@ -5,6 +5,7 @@ * Copyright (C) 2020-2021 ARM Ltd. */ +#include #include #include "common.h" @@ -371,6 +372,7 @@ static int scmi_voltage_protocol_init(const struct scmi_protocol_handle *ph) static const struct scmi_protocol scmi_voltage = { .id = SCMI_PROTOCOL_VOLTAGE, + .owner = THIS_MODULE, .instance_init = &scmi_voltage_protocol_init, .ops = &voltage_proto_ops, }; diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h index b80496d519f30a0aeb4edf91893edf6891b6151d..79d0a1237e6cabef0decff4b43cd7536ad5d9536 100644 --- a/include/linux/scmi_protocol.h +++ b/include/linux/scmi_protocol.h @@ -704,6 +704,18 @@ static inline void scmi_driver_unregister(struct scmi_driver *driver) {} #define module_scmi_driver(__scmi_driver) \ module_driver(__scmi_driver, scmi_register, scmi_unregister) +/** + * module_scmi_protocol() - Helper macro for registering a scmi protocol + * @__scmi_protocol: scmi_protocol structure + * + * Helper macro for scmi drivers to set up proper module init / exit + * functions. Replaces module_init() and module_exit() and keeps people from + * printing pointless things to the kernel log when their driver is loaded. + */ +#define module_scmi_protocol(__scmi_protocol) \ + module_driver(__scmi_protocol, \ + scmi_protocol_register, scmi_protocol_unregister) + struct scmi_protocol; int scmi_protocol_register(const struct scmi_protocol *proto); void scmi_protocol_unregister(const struct scmi_protocol *proto);