/* Used for GHES mapping from assorted contexts */
        FIX_APEI_GHES_IRQ,
        FIX_APEI_GHES_SEA,
+#ifdef CONFIG_ARM_SDE_INTERFACE
+       FIX_APEI_GHES_SDEI_NORMAL,
+       FIX_APEI_GHES_SDEI_CRITICAL,
+#endif
 #endif /* CONFIG_ACPI_APEI_GHES */
 
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
 
 // Copyright (C) 2017 Arm Ltd.
 #define pr_fmt(fmt) "sdei: " fmt
 
+#include <acpi/ghes.h>
 #include <linux/acpi.h>
 #include <linux/arm_sdei.h>
 #include <linux/arm-smccc.h>
        arm_smccc_hvc(function_id, arg0, arg1, arg2, arg3, arg4, 0, 0, res);
 }
 
+int sdei_register_ghes(struct ghes *ghes, sdei_event_callback *normal_cb,
+                      sdei_event_callback *critical_cb)
+{
+       int err;
+       u64 result;
+       u32 event_num;
+       sdei_event_callback *cb;
+
+       if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
+               return -EOPNOTSUPP;
+
+       event_num = ghes->generic->notify.vector;
+       if (event_num == 0) {
+               /*
+                * Event 0 is reserved by the specification for
+                * SDEI_EVENT_SIGNAL.
+                */
+               return -EINVAL;
+       }
+
+       err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_PRIORITY,
+                                     &result);
+       if (err)
+               return err;
+
+       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);
+
+       return err;
+}
+
+int sdei_unregister_ghes(struct ghes *ghes)
+{
+       int i;
+       int err;
+       u32 event_num = ghes->generic->notify.vector;
+
+       might_sleep();
+
+       if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
+               return -EOPNOTSUPP;
+
+       /*
+        * 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);
+       if (err)
+               return err;
+
+       for (i = 0; i < 3; i++) {
+               err = sdei_event_unregister(event_num);
+               if (err != -EINPROGRESS)
+                       break;
+
+               schedule();
+       }
+
+       return err;
+}
+
 static int sdei_get_conduit(struct platform_device *pdev)
 {
        const char *method;
 
        CONDUIT_HVC,
 };
 
+#include <acpi/ghes.h>
 #include <asm/sdei.h>
 
 /* Arch code should override this to set the entry point from firmware... */
 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);