[PATCH 12/14] drivers/firmware/sdei: Identify event by struct sdei_event

Gavin Shan gshan at redhat.com
Mon Jul 6 01:47:30 EDT 2020


There are 4 APIs exported by the driver as below. They are using
the event number as the identifier to the event. It's conflicting
with the requirement to dereference the event by struct sdei_event
instance when SDEI virtualization is supported. So this reworks on
the APIs according to dereference the event by struct sdei_event
instance:

   * sdei_event_register() returns the struct sdei_event instance.
   * sdei_event_unregister() and sdei_event_{enable, disable}()
     accepts struct sdei_event instance as the parameter.
   * Rework sdei_{register,unregister}_ghes() to use the modified
     APIs.

Signed-off-by: Gavin Shan <gshan at redhat.com>
---
 drivers/firmware/arm_sdei.c | 145 +++++++++++++++++-------------------
 include/linux/arm_sdei.h    |  71 ++++++++++--------
 2 files changed, 108 insertions(+), 108 deletions(-)

diff --git a/drivers/firmware/arm_sdei.c b/drivers/firmware/arm_sdei.c
index 8f53bef88379..8e5f6683c155 100644
--- a/drivers/firmware/arm_sdei.c
+++ b/drivers/firmware/arm_sdei.c
@@ -44,26 +44,6 @@ static asmlinkage void (*sdei_firmware_call)(unsigned long function_id,
 /* entry point from firmware to arch asm code */
 static unsigned long sdei_entry_point;
 
-struct sdei_event {
-	/* These three are protected by the sdei_list_lock */
-	struct list_head	list;
-	bool			reregister;
-	bool			reenable;
-
-	u32			event_num;
-	u8			type;
-	u8			priority;
-
-	/* This pointer is handed to firmware as the event argument. */
-	union {
-		/* Shared events */
-		struct sdei_registered_event *registered;
-
-		/* CPU private events */
-		struct sdei_registered_event __percpu *private_registered;
-	};
-};
-
 /* Take the mutex for any API call or modification. Take the mutex first. */
 static DEFINE_MUTEX(sdei_events_lock);
 
@@ -393,30 +373,26 @@ static void _local_event_enable(void *data)
 	sdei_cross_call_return(arg, err);
 }
 
-int sdei_event_enable(u32 event_num)
+int sdei_event_enable(struct sdei_event *event)
 {
 	int err = -EINVAL;
-	struct sdei_event *event;
 
 	mutex_lock(&sdei_events_lock);
-	event = sdei_event_find(event_num);
-	if (!event) {
-		mutex_unlock(&sdei_events_lock);
-		return -ENOENT;
-	}
-
-
 	cpus_read_lock();
+
 	if (event->type == SDEI_EVENT_TYPE_SHARED)
 		err = sdei_api_event_enable(event->event_num);
 	else
 		err = sdei_do_cross_call(_local_event_enable, event);
 
-	if (!err) {
-		spin_lock(&sdei_list_lock);
-		event->reenable = true;
-		spin_unlock(&sdei_list_lock);
-	}
+	if (err)
+		goto cpu_unlock;
+
+	spin_lock(&sdei_list_lock);
+	event->reenable = true;
+	spin_unlock(&sdei_list_lock);
+
+cpu_unlock:
 	cpus_read_unlock();
 	mutex_unlock(&sdei_events_lock);
 
@@ -439,28 +415,26 @@ static void _ipi_event_disable(void *data)
 	sdei_cross_call_return(arg, err);
 }
 
-int sdei_event_disable(u32 event_num)
+int sdei_event_disable(struct sdei_event *event)
 {
 	int err = -EINVAL;
-	struct sdei_event *event;
 
 	mutex_lock(&sdei_events_lock);
-	event = sdei_event_find(event_num);
-	if (!event) {
-		mutex_unlock(&sdei_events_lock);
-		return -ENOENT;
-	}
-
-	spin_lock(&sdei_list_lock);
-	event->reenable = false;
-	spin_unlock(&sdei_list_lock);
 
 	if (event->type == SDEI_EVENT_TYPE_SHARED)
 		err = sdei_api_event_disable(event->event_num);
 	else
 		err = sdei_do_cross_call(_ipi_event_disable, event);
-	mutex_unlock(&sdei_events_lock);
 
+	if (err)
+		goto out;
+
+	spin_lock(&sdei_list_lock);
+	event->reenable = false;
+	spin_unlock(&sdei_list_lock);
+
+out:
+	mutex_unlock(&sdei_events_lock);
 	return err;
 }
 
@@ -483,25 +457,13 @@ static void _local_event_unregister(void *data)
 	sdei_cross_call_return(arg, err);
 }
 
-int sdei_event_unregister(u32 event_num)
+int sdei_event_unregister(struct sdei_event *event)
 {
 	int err;
-	struct sdei_event *event;
 
 	WARN_ON(in_nmi());
 
 	mutex_lock(&sdei_events_lock);
-	event = sdei_event_find(event_num);
-	if (!event) {
-		pr_warn("Event %u not registered\n", event_num);
-		err = -ENOENT;
-		goto out;
-	}
-
-	spin_lock(&sdei_list_lock);
-	event->reregister = false;
-	event->reenable = false;
-	spin_unlock(&sdei_list_lock);
 
 	if (event->type == SDEI_EVENT_TYPE_SHARED)
 		err = sdei_api_event_unregister(event->event_num);
@@ -511,6 +473,11 @@ int sdei_event_unregister(u32 event_num)
 	if (err)
 		goto out;
 
+	spin_lock(&sdei_list_lock);
+	event->reregister = false;
+	event->reenable = false;
+	spin_unlock(&sdei_list_lock);
+
 	sdei_event_destroy(event);
 
 out:
@@ -567,17 +534,18 @@ static void _local_event_register(void *data)
 	sdei_cross_call_return(arg, err);
 }
 
-int sdei_event_register(u32 event_num, sdei_event_callback *cb, void *arg)
+struct sdei_event *sdei_event_register(u32 event_num,
+				       sdei_event_callback *cb, void *arg)
 {
+	struct sdei_event *event = NULL;
 	int err;
-	struct sdei_event *event;
 
 	WARN_ON(in_nmi());
 
 	mutex_lock(&sdei_events_lock);
 	if (sdei_event_find(event_num)) {
 		pr_warn("Event %u already registered\n", event_num);
-		err = -EBUSY;
+		event = ERR_PTR(-EBUSY);
 		goto out;
 	}
 
@@ -603,6 +571,7 @@ int sdei_event_register(u32 event_num, sdei_event_callback *cb, void *arg)
 
 	if (err) {
 		sdei_event_destroy(event);
+		event = ERR_PTR(err);
 		pr_warn("Failed to register event %u: %d\n", event_num,
 			err);
 		goto cpu_unlock;
@@ -616,7 +585,7 @@ int sdei_event_register(u32 event_num, sdei_event_callback *cb, void *arg)
 	cpus_read_unlock();
 out:
 	mutex_unlock(&sdei_events_lock);
-	return err;
+	return event;
 }
 
 static int sdei_reregister_shared(void)
@@ -857,13 +826,16 @@ NOKPROBE_SYMBOL(sdei_smccc_hvc);
 int sdei_register_ghes(struct ghes *ghes, sdei_event_callback *normal_cb,
 		       sdei_event_callback *critical_cb)
 {
-	int err;
+	struct sdei_event *event;
 	u64 result;
 	u32 event_num;
 	sdei_event_callback *cb;
+	int err;
 
-	if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
-		return -EOPNOTSUPP;
+	if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES)) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
 
 	event_num = ghes->generic->notify.vector;
 	if (event_num == 0) {
@@ -871,53 +843,70 @@ int sdei_register_ghes(struct ghes *ghes, sdei_event_callback *normal_cb,
 		 * Event 0 is reserved by the specification for
 		 * SDEI_EVENT_SIGNAL.
 		 */
-		return -EINVAL;
+		err = -EINVAL;
+		goto out;
 	}
 
 	err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_PRIORITY,
 				      &result);
 	if (err)
-		return err;
+		goto out;
 
 	if (result == SDEI_EVENT_PRIORITY_CRITICAL)
 		cb = critical_cb;
 	else
 		cb = normal_cb;
 
-	err = sdei_event_register(event_num, cb, ghes);
-	if (!err)
-		err = sdei_event_enable(event_num);
+	event = sdei_event_register(event_num, cb, ghes);
+	if (IS_ERR(event)) {
+		err = PTR_ERR(event);
+		goto out;
+	}
 
+	err = sdei_event_enable(event);
+
+out:
 	return err;
 }
 
 int sdei_unregister_ghes(struct ghes *ghes)
 {
-	int i;
-	int err;
+	struct sdei_event *event;
 	u32 event_num = ghes->generic->notify.vector;
+	int err, i;
 
 	might_sleep();
 
-	if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
-		return -EOPNOTSUPP;
+	if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES)) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	mutex_lock(&sdei_events_lock);
+	event = sdei_event_find(event_num);
+	mutex_unlock(&sdei_events_lock);
+	if (!event) {
+		err = -ENOENT;
+		goto out;
+	}
 
 	/*
 	 * The event may be running on another CPU. Disable it
 	 * to stop new events, then try to unregister a few times.
 	 */
-	err = sdei_event_disable(event_num);
+	err = sdei_event_disable(event);
 	if (err)
-		return err;
+		goto out;
 
 	for (i = 0; i < 3; i++) {
-		err = sdei_event_unregister(event_num);
+		err = sdei_event_unregister(event);
 		if (err != -EINPROGRESS)
 			break;
 
 		schedule();
 	}
 
+out:
 	return err;
 }
 
diff --git a/include/linux/arm_sdei.h b/include/linux/arm_sdei.h
index 0a241c5c911d..fb6aa455e51d 100644
--- a/include/linux/arm_sdei.h
+++ b/include/linux/arm_sdei.h
@@ -22,36 +22,6 @@
  */
 typedef int (sdei_event_callback)(u32 event, struct pt_regs *regs, void *arg);
 
-/*
- * Register your callback to claim an event. The event must be described
- * by firmware.
- */
-int sdei_event_register(u32 event_num, sdei_event_callback *cb, void *arg);
-
-/*
- * Calls to sdei_event_unregister() may return EINPROGRESS. Keep calling
- * it until it succeeds.
- */
-int sdei_event_unregister(u32 event_num);
-
-int sdei_event_enable(u32 event_num);
-int sdei_event_disable(u32 event_num);
-
-/* GHES register/unregister helpers */
-int sdei_register_ghes(struct ghes *ghes, sdei_event_callback *normal_cb,
-		       sdei_event_callback *critical_cb);
-int sdei_unregister_ghes(struct ghes *ghes);
-
-#ifdef CONFIG_ARM_SDE_INTERFACE
-/* For use by arch code when CPU hotplug notifiers are not appropriate. */
-int sdei_mask_local_cpu(void);
-int sdei_unmask_local_cpu(void);
-#else
-static inline int sdei_mask_local_cpu(void) { return 0; }
-static inline int sdei_unmask_local_cpu(void) { return 0; }
-#endif /* CONFIG_ARM_SDE_INTERFACE */
-
-
 /*
  * This struct represents an event that has been registered. The driver
  * maintains a list of all events, and which ones are registered. (Private
@@ -72,6 +42,47 @@ struct sdei_registered_event {
 	u8			 priority;
 };
 
+struct sdei_event {
+	/* These three are protected by the sdei_list_lock */
+	struct list_head	list;
+	bool			reregister;
+	bool			reenable;
+
+	u32			event_num;
+	u8			type;
+	u8			priority;
+
+	/* This pointer is handed to firmware as the event argument. */
+	union {
+		/* Shared events */
+		struct sdei_registered_event *registered;
+
+		/* CPU private events */
+		struct sdei_registered_event __percpu *private_registered;
+	};
+};
+
+/* APIs */
+struct sdei_event *sdei_event_register(u32 event_num,
+				       sdei_event_callback *cb, void *arg);
+int sdei_event_unregister(struct sdei_event *event);
+int sdei_event_enable(struct sdei_event *event);
+int sdei_event_disable(struct sdei_event *event);
+
+/* GHES register/unregister helpers */
+int sdei_register_ghes(struct ghes *ghes, sdei_event_callback *normal_cb,
+		       sdei_event_callback *critical_cb);
+int sdei_unregister_ghes(struct ghes *ghes);
+
+#ifdef CONFIG_ARM_SDE_INTERFACE
+/* For use by arch code when CPU hotplug notifiers are not appropriate. */
+int sdei_mask_local_cpu(void);
+int sdei_unmask_local_cpu(void);
+#else
+static inline int sdei_mask_local_cpu(void) { return 0; }
+static inline int sdei_unmask_local_cpu(void) { return 0; }
+#endif /* CONFIG_ARM_SDE_INTERFACE */
+
 /* The arch code entry point should then call this when an event arrives. */
 int notrace sdei_event_handler(struct pt_regs *regs,
 			       struct sdei_registered_event *arg);
-- 
2.23.0




More information about the linux-arm-kernel mailing list