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);
