firmware: arm_scmi: Check for notification support
authorCristian Marussi <cristian.marussi@arm.com>
Mon, 12 Feb 2024 12:32:23 +0000 (12:32 +0000)
committerSudeep Holla <sudeep.holla@arm.com>
Tue, 20 Feb 2024 06:35:55 +0000 (06:35 +0000)
When registering protocol events, use the optional .is_notify_supported
callback provided by the protocol to check if that specific notification
type is available for that particular resource on the running system,
marking it as unsupported otherwise.

Then, when a notification enable request is received, return an error if
it was previously marked as unsuppported, so avoiding to send a needless
notification enable command and check the returned value for failure.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
Link: https://lore.kernel.org/r/20240212123233.1230090-2-cristian.marussi@arm.com
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
drivers/firmware/arm_scmi/notify.c
drivers/firmware/arm_scmi/notify.h

index 0efd20c..27c5253 100644 (file)
@@ -99,6 +99,7 @@
 #define PROTO_ID_MASK          GENMASK(31, 24)
 #define EVT_ID_MASK            GENMASK(23, 16)
 #define SRC_ID_MASK            GENMASK(15, 0)
+#define NOTIF_UNSUPP           -1
 
 /*
  * Builds an unsigned 32bit key from the given input tuple to be used
@@ -788,6 +789,7 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id,
 
        pd->ph = ph;
        for (i = 0; i < ee->num_events; i++, evt++) {
+               int id;
                struct scmi_registered_event *r_evt;
 
                r_evt = devm_kzalloc(ni->handle->dev, sizeof(*r_evt),
@@ -809,6 +811,11 @@ 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);
+
                pd->registered_events[i] = r_evt;
                /* Ensure events are updated */
                smp_wmb();
@@ -1166,7 +1173,13 @@ static inline int __scmi_enable_evt(struct scmi_registered_event *r_evt,
                        int ret = 0;
 
                        sid = &r_evt->sources[src_id];
-                       if (refcount_read(sid) == 0) {
+                       if (refcount_read(sid) == NOTIF_UNSUPP) {
+                               dev_dbg(r_evt->proto->ph->dev,
+                                       "Notification NOT supported - proto_id:%d  evt_id:%d  src_id:%d",
+                                       r_evt->proto->id, r_evt->evt->id,
+                                       src_id);
+                               ret = -EOPNOTSUPP;
+                       } else if (refcount_read(sid) == 0) {
                                ret = REVT_NOTIFY_ENABLE(r_evt, r_evt->evt->id,
                                                         src_id);
                                if (!ret)
@@ -1179,6 +1192,8 @@ static inline int __scmi_enable_evt(struct scmi_registered_event *r_evt,
        } else {
                for (; num_sources; src_id++, num_sources--) {
                        sid = &r_evt->sources[src_id];
+                       if (refcount_read(sid) == NOTIF_UNSUPP)
+                               continue;
                        if (refcount_dec_and_test(sid))
                                REVT_NOTIFY_DISABLE(r_evt,
                                                    r_evt->evt->id, src_id);
index 4e9b627..76758a7 100644 (file)
@@ -35,6 +35,8 @@ struct scmi_protocol_handle;
 
 /**
  * struct scmi_event_ops  - Protocol helpers called by the notification core.
+ * @is_notify_supported: Return 0 if the specified notification for the
+ *                      specified resource (src_id) is supported.
  * @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
@@ -50,6 +52,8 @@ struct scmi_protocol_handle;
  *         process context.
  */
 struct scmi_event_ops {
+       bool (*is_notify_supported)(const struct scmi_protocol_handle *ph,
+                                   u8 evt_id, u32 src_id);
        int (*get_num_sources)(const struct scmi_protocol_handle *ph);
        int (*set_notify_enabled)(const struct scmi_protocol_handle *ph,
                                  u8 evt_id, u32 src_id, bool enabled);