2
0
mirror of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2025-09-04 20:19:47 +08:00

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 <cristian.marussi@arm.com>
Message-Id: <20250707144220.485365-1-cristian.marussi@arm.com>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
This commit is contained in:
Cristian Marussi 2025-07-07 15:42:20 +01:00 committed by Sudeep Holla
parent 9a0658d399
commit b5daf93b80

View File

@ -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