Describe statically the protocol events as part of struct scmi_protocol and move the explicit registraton/deregistration code out the per-protocol specific code and into the common core initialization code.
Add .get_num_sources to scmi_event_ops, to resolve at run-time the number of available sources where not statically definable in .num-sources. Simplify scmi_register_protocol_events devres handling since the events resources can now be handled by the per-protocol devres. Signed-off-by: Cristian Marussi <cristian.maru...@arm.com> --- drivers/firmware/arm_scmi/base.c | 15 +++--- drivers/firmware/arm_scmi/common.h | 4 ++ drivers/firmware/arm_scmi/driver.c | 7 +++ drivers/firmware/arm_scmi/notify.c | 77 ++++++++++++++++++++--------- drivers/firmware/arm_scmi/notify.h | 30 +++++++++-- drivers/firmware/arm_scmi/perf.c | 26 +++++++--- drivers/firmware/arm_scmi/power.c | 26 +++++++--- drivers/firmware/arm_scmi/reset.c | 26 +++++++--- drivers/firmware/arm_scmi/sensors.c | 26 +++++++--- drivers/firmware/arm_scmi/system.c | 16 +++--- 10 files changed, 187 insertions(+), 66 deletions(-) diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c index 129633e6fff4..f40821eeb103 100644 --- a/drivers/firmware/arm_scmi/base.c +++ b/drivers/firmware/arm_scmi/base.c @@ -318,6 +318,14 @@ static const struct scmi_event_ops base_event_ops = { .fill_custom_report = scmi_base_fill_custom_report, }; +static const struct scmi_protocol_events base_protocol_events = { + .queue_sz = 4 * SCMI_PROTO_QUEUE_SZ, + .ops = &base_event_ops, + .evts = base_events, + .num_events = ARRAY_SIZE(base_events), + .num_sources = SCMI_BASE_NUM_SOURCES, +}; + static int scmi_base_protocol_init(const struct scmi_handle *h) { int id, ret; @@ -352,12 +360,6 @@ static int scmi_base_protocol_init(const struct scmi_handle *h) dev_dbg(dev, "Found %d protocol(s) %d agent(s)\n", rev->num_protocols, rev->num_agents); - scmi_register_protocol_events(handle, SCMI_PROTOCOL_BASE, - (4 * SCMI_PROTO_QUEUE_SZ), - &base_event_ops, base_events, - ARRAY_SIZE(base_events), - SCMI_BASE_NUM_SOURCES); - for (id = 0; id < rev->num_agents; id++) { scmi_base_discover_agent_get(handle, id, name); dev_dbg(dev, "Agent %d: %s\n", id, name); @@ -370,6 +372,7 @@ static struct scmi_protocol scmi_base = { .id = SCMI_PROTOCOL_BASE, .init = &scmi_base_protocol_init, .ops = NULL, + .events = &base_protocol_events, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(base, scmi_base) diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 56ebb710ee84..66574f57e304 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -19,6 +19,8 @@ #include <asm/unaligned.h> +#include "notify.h" + #define SCMI_MAX_PROTO 256 #define PROTOCOL_REV_MINOR_MASK GENMASK(15, 0) @@ -167,12 +169,14 @@ typedef int (*scmi_prot_init_fn_t)(const struct scmi_handle *); * @deinit: Optional protocol de-initialization function. * @ops: Optional reference to the operations provided by the protocol and * exposed in scmi_protocol.h. + * @events: An optional reference to the events supported by this protocol. */ struct scmi_protocol { const u8 id; const scmi_prot_init_fn_t init; const scmi_prot_init_fn_t deinit; const void *ops; + const struct scmi_protocol_events *events; }; int __init scmi_bus_init(void); diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 049220efd227..378749040162 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -628,6 +628,10 @@ scmi_get_protocol_instance(const struct scmi_handle *handle, u8 protocol_id) /* Ensure initialized protocol is visible */ smp_wmb(); + if (pi->proto->events) + scmi_register_protocol_events(handle, pi->proto->id, + pi->proto->events); + devres_close_group(handle->dev, pi->gid); dev_dbg(handle->dev, "Initialized protocol: 0x%X\n", protocol_id); @@ -685,6 +689,9 @@ void scmi_release_protocol(const struct scmi_handle *handle, u8 protocol_id) if (refcount_dec_and_test(&pi->users)) { void *gid = pi->gid; + if (pi->proto->events) + scmi_deregister_protocol_events(handle, protocol_id); + if (pi->proto->deinit) pi->proto->deinit(handle); diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c index 02b00af9b08f..7ba182d4f2b4 100644 --- a/drivers/firmware/arm_scmi/notify.c +++ b/drivers/firmware/arm_scmi/notify.c @@ -731,14 +731,9 @@ scmi_allocate_registered_events_desc(struct scmi_notify_instance *ni, /** * scmi_register_protocol_events() - Register Protocol Events with the core * @handle: The handle identifying the platform instance against which the - * the protocol's events are registered + * protocol's events are registered * @proto_id: Protocol ID - * @queue_sz: Size in bytes of the associated queue to be allocated - * @ops: Protocol specific event-related operations - * @evt: Event descriptor array - * @num_events: Number of events in @evt array - * @num_sources: Number of possible sources for this protocol on this - * platform. + * @ee: A structure describing the events supported by this protocol. * * Used by SCMI Protocols initialization code to register with the notification * core the list of supported events and their descriptors: takes care to @@ -747,18 +742,18 @@ scmi_allocate_registered_events_desc(struct scmi_notify_instance *ni, * * Return: 0 on Success */ -int scmi_register_protocol_events(const struct scmi_handle *handle, - u8 proto_id, size_t queue_sz, - const struct scmi_event_ops *ops, - const struct scmi_event *evt, int num_events, - int num_sources) +int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id, + const struct scmi_protocol_events *ee) { int i; + unsigned int num_sources; size_t payld_sz = 0; struct scmi_registered_events_desc *pd; struct scmi_notify_instance *ni; + const struct scmi_event *evt; - if (!ops || !evt) + if (!ee || !ee->ops || !ee->evts || + (!ee->num_sources && !ee->ops->get_num_sources)) return -EINVAL; /* Ensure notify_priv is updated */ @@ -767,20 +762,29 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, return -ENOMEM; ni = handle->notify_priv; - /* Attach to the notification main devres group */ - if (!devres_open_group(ni->handle->dev, ni->gid, GFP_KERNEL)) - return -ENOMEM; + /* num_sources cannot be <= 0 */ + if (ee->num_sources) { + num_sources = ee->num_sources; + } else { + int nsrc = ee->ops->get_num_sources(handle); + + if (nsrc <= 0) + return -EINVAL; + num_sources = nsrc; + } - for (i = 0; i < num_events; i++) + evt = ee->evts; + for (i = 0; i < ee->num_events; i++) payld_sz = max_t(size_t, payld_sz, evt[i].max_payld_sz); payld_sz += sizeof(struct scmi_event_header); - pd = scmi_allocate_registered_events_desc(ni, proto_id, queue_sz, - payld_sz, num_events, ops); + pd = scmi_allocate_registered_events_desc(ni, proto_id, ee->queue_sz, + payld_sz, ee->num_events, + ee->ops); if (IS_ERR(pd)) goto err; - for (i = 0; i < num_events; i++, evt++) { + for (i = 0; i < ee->num_events; i++, evt++) { struct scmi_registered_event *r_evt; r_evt = devm_kzalloc(ni->handle->dev, sizeof(*r_evt), @@ -814,8 +818,6 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, /* Ensure protocols are updated */ smp_wmb(); - devres_close_group(ni->handle->dev, ni->gid); - /* * Finalize any pending events' handler which could have been waiting * for this protocol's events registration. @@ -826,12 +828,39 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, err: dev_warn(handle->dev, "Proto:%X - Registration Failed !\n", proto_id); - /* A failing protocol registration does not trigger full failure */ - devres_close_group(ni->handle->dev, ni->gid); return -ENOMEM; } +/** + * scmi_deregister_protocol_events - Deregister protocol events with the core + * @handle: The handle identifying the platform instance against which the + * protocol's events are registered + * @proto_id: Protocol ID + */ +void scmi_deregister_protocol_events(const struct scmi_handle *handle, + u8 proto_id) +{ + struct scmi_notify_instance *ni; + struct scmi_registered_events_desc *pd; + + /* Ensure notify_priv is updated */ + smp_rmb(); + if (!handle->notify_priv) + return; + + ni = handle->notify_priv; + pd = ni->registered_protocols[proto_id]; + if (!pd) + return; + + ni->registered_protocols[proto_id] = NULL; + /* Ensure protocols are updated */ + smp_wmb(); + + cancel_work_sync(&pd->equeue.notify_work); +} + /** * scmi_allocate_event_handler() - Allocate Event handler * @ni: A reference to the notification instance to use diff --git a/drivers/firmware/arm_scmi/notify.h b/drivers/firmware/arm_scmi/notify.h index 3485f20fa70e..bc30167b1dd6 100644 --- a/drivers/firmware/arm_scmi/notify.h +++ b/drivers/firmware/arm_scmi/notify.h @@ -33,6 +33,8 @@ struct scmi_event { /** * struct scmi_event_ops - Protocol helpers called by the notification core. + * @get_num_sources: Returns the number of possible events' sources for this + * protocol * @set_notify_enabled: Enable/disable the required evt_id/src_id notifications * using the proper custom protocol commands. * Return 0 on Success @@ -46,6 +48,7 @@ struct scmi_event { * process context. */ struct scmi_event_ops { + int (*get_num_sources)(const struct scmi_handle *handle); int (*set_notify_enabled)(const struct scmi_handle *handle, u8 evt_id, u32 src_id, bool enabled); void *(*fill_custom_report)(const struct scmi_handle *handle, @@ -54,14 +57,31 @@ struct scmi_event_ops { void *report, u32 *src_id); }; +/** + * struct scmi_protocol_events - Per-protocol description of available events + * @queue_sz: Size in bytes of the per-protocol queue to use. + * @ops: Array of protocol-specific events operations. + * @evts: Array of supported protocol's events. + * @num_events: Number of supported protocol's events described in @evts. + * @num_sources: Number of protocol's sources, should be greater than 0; if not + * available at compile time, it will be provided at run-time via + * @get_num_sources. + */ +struct scmi_protocol_events { + size_t queue_sz; + const struct scmi_event_ops *ops; + const struct scmi_event *evts; + unsigned int num_events; + unsigned int num_sources; +}; + int scmi_notification_init(struct scmi_handle *handle); void scmi_notification_exit(struct scmi_handle *handle); -int scmi_register_protocol_events(const struct scmi_handle *handle, - u8 proto_id, size_t queue_sz, - const struct scmi_event_ops *ops, - const struct scmi_event *evt, int num_events, - int num_sources); +int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id, + const struct scmi_protocol_events *ee); +void scmi_deregister_protocol_events(const struct scmi_handle *handle, + u8 proto_id); int scmi_notify(const struct scmi_handle *handle, u8 proto_id, u8 evt_id, const void *buf, size_t len, ktime_t ts); diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index bd9cb2583557..b3038362f362 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -839,6 +839,17 @@ static void *scmi_perf_fill_custom_report(const struct scmi_handle *handle, return rep; } +static int scmi_perf_get_num_sources(const struct scmi_handle *handle) +{ + struct scmi_perf_info *pinfo = + scmi_get_proto_priv(handle, SCMI_PROTOCOL_PERF); + + if (!pinfo) + return -EINVAL; + + return pinfo->num_domains; +} + static const struct scmi_event perf_events[] = { { .id = SCMI_EVENT_PERFORMANCE_LIMITS_CHANGED, @@ -853,10 +864,18 @@ static const struct scmi_event perf_events[] = { }; static const struct scmi_event_ops perf_event_ops = { + .get_num_sources = scmi_perf_get_num_sources, .set_notify_enabled = scmi_perf_set_notify_enabled, .fill_custom_report = scmi_perf_fill_custom_report, }; +static const struct scmi_protocol_events perf_protocol_events = { + .queue_sz = SCMI_PROTO_QUEUE_SZ, + .ops = &perf_event_ops, + .evts = perf_events, + .num_events = ARRAY_SIZE(perf_events), +}; + static int scmi_perf_protocol_init(const struct scmi_handle *handle) { int domain; @@ -889,12 +908,6 @@ static int scmi_perf_protocol_init(const struct scmi_handle *handle) scmi_perf_domain_init_fc(handle, domain, &dom->fc_info); } - scmi_register_protocol_events(handle, - SCMI_PROTOCOL_PERF, SCMI_PROTO_QUEUE_SZ, - &perf_event_ops, perf_events, - ARRAY_SIZE(perf_events), - pinfo->num_domains); - pinfo->version = version; return scmi_set_proto_priv(handle, SCMI_PROTOCOL_PERF, pinfo); } @@ -903,6 +916,7 @@ static struct scmi_protocol scmi_perf = { .id = SCMI_PROTOCOL_PERF, .init = &scmi_perf_protocol_init, .ops = &perf_ops, + .events = &perf_protocol_events, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(perf, scmi_perf) diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c index 1e026b5530a7..cb9b1f6a56dd 100644 --- a/drivers/firmware/arm_scmi/power.c +++ b/drivers/firmware/arm_scmi/power.c @@ -248,6 +248,17 @@ static void *scmi_power_fill_custom_report(const struct scmi_handle *handle, return r; } +static int scmi_power_get_num_sources(const struct scmi_handle *handle) +{ + struct scmi_power_info *pinfo = + scmi_get_proto_priv(handle, SCMI_PROTOCOL_POWER); + + if (!pinfo) + return -EINVAL; + + return pinfo->num_domains; +} + static const struct scmi_event power_events[] = { { .id = SCMI_EVENT_POWER_STATE_CHANGED, @@ -258,10 +269,18 @@ static const struct scmi_event power_events[] = { }; static const struct scmi_event_ops power_event_ops = { + .get_num_sources = scmi_power_get_num_sources, .set_notify_enabled = scmi_power_set_notify_enabled, .fill_custom_report = scmi_power_fill_custom_report, }; +static const struct scmi_protocol_events power_protocol_events = { + .queue_sz = SCMI_PROTO_QUEUE_SZ, + .ops = &power_event_ops, + .evts = power_events, + .num_events = ARRAY_SIZE(power_events), +}; + static int scmi_power_protocol_init(const struct scmi_handle *handle) { int domain; @@ -290,12 +309,6 @@ static int scmi_power_protocol_init(const struct scmi_handle *handle) scmi_power_domain_attributes_get(handle, domain, dom); } - scmi_register_protocol_events(handle, - SCMI_PROTOCOL_POWER, SCMI_PROTO_QUEUE_SZ, - &power_event_ops, power_events, - ARRAY_SIZE(power_events), - pinfo->num_domains); - pinfo->version = version; return scmi_set_proto_priv(handle, SCMI_PROTOCOL_POWER, pinfo); } @@ -304,6 +317,7 @@ static struct scmi_protocol scmi_power = { .id = SCMI_PROTOCOL_POWER, .init = &scmi_power_protocol_init, .ops = &power_ops, + .events = &power_protocol_events, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(power, scmi_power) diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c index b7da4de0e56e..83bfd0514d4d 100644 --- a/drivers/firmware/arm_scmi/reset.c +++ b/drivers/firmware/arm_scmi/reset.c @@ -261,6 +261,17 @@ static void *scmi_reset_fill_custom_report(const struct scmi_handle *handle, return r; } +static int scmi_reset_get_num_sources(const struct scmi_handle *handle) +{ + struct scmi_reset_info *pinfo = + scmi_get_proto_priv(handle, SCMI_PROTOCOL_RESET); + + if (!pinfo) + return -EINVAL; + + return pinfo->num_domains; +} + static const struct scmi_event reset_events[] = { { .id = SCMI_EVENT_RESET_ISSUED, @@ -270,10 +281,18 @@ static const struct scmi_event reset_events[] = { }; static const struct scmi_event_ops reset_event_ops = { + .get_num_sources = scmi_reset_get_num_sources, .set_notify_enabled = scmi_reset_set_notify_enabled, .fill_custom_report = scmi_reset_fill_custom_report, }; +static const struct scmi_protocol_events reset_protocol_events = { + .queue_sz = SCMI_PROTO_QUEUE_SZ, + .ops = &reset_event_ops, + .evts = reset_events, + .num_events = ARRAY_SIZE(reset_events), +}; + static int scmi_reset_protocol_init(const struct scmi_handle *handle) { int domain; @@ -302,12 +321,6 @@ static int scmi_reset_protocol_init(const struct scmi_handle *handle) scmi_reset_domain_attributes_get(handle, domain, dom); } - scmi_register_protocol_events(handle, - SCMI_PROTOCOL_RESET, SCMI_PROTO_QUEUE_SZ, - &reset_event_ops, reset_events, - ARRAY_SIZE(reset_events), - pinfo->num_domains); - pinfo->version = version; return scmi_set_proto_priv(handle, SCMI_PROTOCOL_RESET, pinfo); } @@ -316,6 +329,7 @@ static struct scmi_protocol scmi_reset = { .id = SCMI_PROTOCOL_RESET, .init = &scmi_reset_protocol_init, .ops = &reset_ops, + .events = &reset_protocol_events, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(reset, scmi_reset) diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c index e0129dcd322f..79bdd53ab7ba 100644 --- a/drivers/firmware/arm_scmi/sensors.c +++ b/drivers/firmware/arm_scmi/sensors.c @@ -321,6 +321,17 @@ static void *scmi_sensor_fill_custom_report(const struct scmi_handle *handle, return r; } +static int scmi_sensor_get_num_sources(const struct scmi_handle *handle) +{ + struct sensors_info *sinfo = + scmi_get_proto_priv(handle, SCMI_PROTOCOL_SENSOR); + + if (!sinfo) + return -EINVAL; + + return sinfo->num_sensors; +} + static const struct scmi_event sensor_events[] = { { .id = SCMI_EVENT_SENSOR_TRIP_POINT_EVENT, @@ -330,10 +341,18 @@ static const struct scmi_event sensor_events[] = { }; static const struct scmi_event_ops sensor_event_ops = { + .get_num_sources = scmi_sensor_get_num_sources, .set_notify_enabled = scmi_sensor_set_notify_enabled, .fill_custom_report = scmi_sensor_fill_custom_report, }; +static const struct scmi_protocol_events sensor_protocol_events = { + .queue_sz = SCMI_PROTO_QUEUE_SZ, + .ops = &sensor_event_ops, + .evts = sensor_events, + .num_events = ARRAY_SIZE(sensor_events), +}; + static int scmi_sensors_protocol_init(const struct scmi_handle *handle) { u32 version; @@ -357,12 +376,6 @@ static int scmi_sensors_protocol_init(const struct scmi_handle *handle) scmi_sensor_description_get(handle, sinfo); - scmi_register_protocol_events(handle, - SCMI_PROTOCOL_SENSOR, SCMI_PROTO_QUEUE_SZ, - &sensor_event_ops, sensor_events, - ARRAY_SIZE(sensor_events), - sinfo->num_sensors); - sinfo->version = version; return scmi_set_proto_priv(handle, SCMI_PROTOCOL_SENSOR, sinfo); } @@ -371,6 +384,7 @@ static struct scmi_protocol scmi_sensors = { .id = SCMI_PROTOCOL_SENSOR, .init = &scmi_sensors_protocol_init, .ops = &sensor_ops, + .events = &sensor_protocol_events, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(sensors, scmi_sensors) diff --git a/drivers/firmware/arm_scmi/system.c b/drivers/firmware/arm_scmi/system.c index 30e3510c1f07..ae884fc669f5 100644 --- a/drivers/firmware/arm_scmi/system.c +++ b/drivers/firmware/arm_scmi/system.c @@ -101,6 +101,14 @@ static const struct scmi_event_ops system_event_ops = { .fill_custom_report = scmi_system_fill_custom_report, }; +static const struct scmi_protocol_events system_protocol_events = { + .queue_sz = SCMI_PROTO_QUEUE_SZ, + .ops = &system_event_ops, + .evts = system_events, + .num_events = ARRAY_SIZE(system_events), + .num_sources = SCMI_SYSTEM_NUM_SOURCES, +}; + static int scmi_system_protocol_init(const struct scmi_handle *handle) { u32 version; @@ -115,13 +123,6 @@ static int scmi_system_protocol_init(const struct scmi_handle *handle) if (!pinfo) return -ENOMEM; - scmi_register_protocol_events(handle, - SCMI_PROTOCOL_SYSTEM, SCMI_PROTO_QUEUE_SZ, - &system_event_ops, - system_events, - ARRAY_SIZE(system_events), - SCMI_SYSTEM_NUM_SOURCES); - pinfo->version = version; return scmi_set_proto_priv(handle, SCMI_PROTOCOL_SYSTEM, pinfo); } @@ -130,6 +131,7 @@ static struct scmi_protocol scmi_system = { .id = SCMI_PROTOCOL_SYSTEM, .init = &scmi_system_protocol_init, .ops = NULL, + .events = &system_protocol_events, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(system, scmi_system) -- 2.17.1