From: Cristian Marussi Date: Mon, 7 Jul 2025 14:42:20 +0000 (+0100) Subject: firmware: arm_scmi: Avoid notifier registration for unsupported events X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b5daf93b809d13a194f8a8eeacfab1cfa241bbc3;p=thirdparty%2Flinux.git firmware: arm_scmi: Avoid notifier registration for unsupported events Some platforms may be configured to not support notification events from certain sources. This scenario is already handled gracefully by avoiding any attempt to send a notification enable request for those sources, as such requests would inevitably fail. However, in a more extreme case, a platform might not support even a single source for a given event type. In this situation, allowing notifier registration is meaningless. Attempting to register a notifier would serve no purpose and only result in unnecessary overhead. To address this, we now detect such conditions during the protocol initialization. When identified, we flag the unsupported event types and reject any subsequent notifier registration attempts for them with -ENOTSUPP. This early rejection avoids redundant processing and simplifies runtime logic. Signed-off-by: Cristian Marussi Message-Id: <20250707144220.485365-1-cristian.marussi@arm.com> Signed-off-by: Sudeep Holla --- diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c index e160ecb22948f..dee9f238f6fdd 100644 --- a/drivers/firmware/arm_scmi/notify.c +++ b/drivers/firmware/arm_scmi/notify.c @@ -318,6 +318,9 @@ struct scmi_registered_events_desc { * customized event report * @num_sources: The number of possible sources for this event as stated at * events' registration time + * @not_supported_by_platform: A flag to indicate that not even one source was + * found to be supported by the platform for this + * event * @sources: A reference to a dynamically allocated array used to refcount the * events' enable requests for all the existing sources * @sources_mtx: A mutex to serialize the access to @sources @@ -334,6 +337,7 @@ struct scmi_registered_event { const struct scmi_event *evt; void *report; u32 num_sources; + bool not_supported_by_platform; refcount_t *sources; /* locking to serialize the access to sources */ struct mutex sources_mtx; @@ -811,10 +815,19 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id, if (!r_evt->report) return -ENOMEM; - for (id = 0; id < r_evt->num_sources; id++) - if (ee->ops->is_notify_supported && - !ee->ops->is_notify_supported(ph, r_evt->evt->id, id)) - refcount_set(&r_evt->sources[id], NOTIF_UNSUPP); + if (ee->ops->is_notify_supported) { + int supported = 0; + + for (id = 0; id < r_evt->num_sources; id++) { + if (!ee->ops->is_notify_supported(ph, r_evt->evt->id, id)) + refcount_set(&r_evt->sources[id], NOTIF_UNSUPP); + else + supported++; + } + + /* Not even one source has been found to be supported */ + r_evt->not_supported_by_platform = !supported; + } pd->registered_events[i] = r_evt; /* Ensure events are updated */ @@ -936,6 +949,11 @@ static inline int scmi_bind_event_handler(struct scmi_notify_instance *ni, * of protocol instance. */ hash_del(&hndl->hash); + + /* Bailout if event is not supported at all */ + if (r_evt->not_supported_by_platform) + return -EOPNOTSUPP; + /* * Acquire protocols only for NON pending handlers, so as NOT to trigger * protocol initialization when a notifier is registered against a still @@ -1060,6 +1078,9 @@ __scmi_event_handler_get_ops(struct scmi_notify_instance *ni, r_evt = SCMI_GET_REVT(ni, KEY_XTRACT_PROTO_ID(evt_key), KEY_XTRACT_EVT_ID(evt_key)); + if (r_evt && r_evt->not_supported_by_platform) + return ERR_PTR(-EOPNOTSUPP); + mutex_lock(&ni->pending_mtx); /* Search registered events at first ... if possible at all */ if (r_evt) { @@ -1087,7 +1108,7 @@ __scmi_event_handler_get_ops(struct scmi_notify_instance *ni, hndl->key); /* this hndl can be only a pending one */ scmi_put_handler_unlocked(ni, hndl); - hndl = NULL; + hndl = ERR_PTR(-EINVAL); } } mutex_unlock(&ni->pending_mtx); @@ -1370,8 +1391,8 @@ static int scmi_notifier_register(const struct scmi_handle *handle, evt_key = MAKE_HASH_KEY(proto_id, evt_id, src_id ? *src_id : SRC_ID_MASK); hndl = scmi_get_or_create_handler(ni, evt_key); - if (!hndl) - return -EINVAL; + if (IS_ERR(hndl)) + return PTR_ERR(hndl); blocking_notifier_chain_register(&hndl->chain, nb); @@ -1416,8 +1437,8 @@ static int scmi_notifier_unregister(const struct scmi_handle *handle, evt_key = MAKE_HASH_KEY(proto_id, evt_id, src_id ? *src_id : SRC_ID_MASK); hndl = scmi_get_handler(ni, evt_key); - if (!hndl) - return -EINVAL; + if (IS_ERR(hndl)) + return PTR_ERR(hndl); /* * Note that this chain unregistration call is safe on its own