aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm64/include/asm/fixmap.h4
-rw-r--r--drivers/firmware/arm_sdei.c68
-rw-r--r--include/linux/arm_sdei.h6
3 files changed, 78 insertions, 0 deletions
diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
index 966dd4bb23f2..f987b8a8f325 100644
--- a/arch/arm64/include/asm/fixmap.h
+++ b/arch/arm64/include/asm/fixmap.h
@@ -56,6 +56,10 @@ enum fixed_addresses {
56 /* Used for GHES mapping from assorted contexts */ 56 /* Used for GHES mapping from assorted contexts */
57 FIX_APEI_GHES_IRQ, 57 FIX_APEI_GHES_IRQ,
58 FIX_APEI_GHES_SEA, 58 FIX_APEI_GHES_SEA,
59#ifdef CONFIG_ARM_SDE_INTERFACE
60 FIX_APEI_GHES_SDEI_NORMAL,
61 FIX_APEI_GHES_SDEI_CRITICAL,
62#endif
59#endif /* CONFIG_ACPI_APEI_GHES */ 63#endif /* CONFIG_ACPI_APEI_GHES */
60 64
61#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 65#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
diff --git a/drivers/firmware/arm_sdei.c b/drivers/firmware/arm_sdei.c
index c64c7da73829..e6376f985ef7 100644
--- a/drivers/firmware/arm_sdei.c
+++ b/drivers/firmware/arm_sdei.c
@@ -2,6 +2,7 @@
2// Copyright (C) 2017 Arm Ltd. 2// Copyright (C) 2017 Arm Ltd.
3#define pr_fmt(fmt) "sdei: " fmt 3#define pr_fmt(fmt) "sdei: " fmt
4 4
5#include <acpi/ghes.h>
5#include <linux/acpi.h> 6#include <linux/acpi.h>
6#include <linux/arm_sdei.h> 7#include <linux/arm_sdei.h>
7#include <linux/arm-smccc.h> 8#include <linux/arm-smccc.h>
@@ -887,6 +888,73 @@ static void sdei_smccc_hvc(unsigned long function_id,
887 arm_smccc_hvc(function_id, arg0, arg1, arg2, arg3, arg4, 0, 0, res); 888 arm_smccc_hvc(function_id, arg0, arg1, arg2, arg3, arg4, 0, 0, res);
888} 889}
889 890
891int sdei_register_ghes(struct ghes *ghes, sdei_event_callback *normal_cb,
892 sdei_event_callback *critical_cb)
893{
894 int err;
895 u64 result;
896 u32 event_num;
897 sdei_event_callback *cb;
898
899 if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
900 return -EOPNOTSUPP;
901
902 event_num = ghes->generic->notify.vector;
903 if (event_num == 0) {
904 /*
905 * Event 0 is reserved by the specification for
906 * SDEI_EVENT_SIGNAL.
907 */
908 return -EINVAL;
909 }
910
911 err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_PRIORITY,
912 &result);
913 if (err)
914 return err;
915
916 if (result == SDEI_EVENT_PRIORITY_CRITICAL)
917 cb = critical_cb;
918 else
919 cb = normal_cb;
920
921 err = sdei_event_register(event_num, cb, ghes);
922 if (!err)
923 err = sdei_event_enable(event_num);
924
925 return err;
926}
927
928int sdei_unregister_ghes(struct ghes *ghes)
929{
930 int i;
931 int err;
932 u32 event_num = ghes->generic->notify.vector;
933
934 might_sleep();
935
936 if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
937 return -EOPNOTSUPP;
938
939 /*
940 * The event may be running on another CPU. Disable it
941 * to stop new events, then try to unregister a few times.
942 */
943 err = sdei_event_disable(event_num);
944 if (err)
945 return err;
946
947 for (i = 0; i < 3; i++) {
948 err = sdei_event_unregister(event_num);
949 if (err != -EINPROGRESS)
950 break;
951
952 schedule();
953 }
954
955 return err;
956}
957
890static int sdei_get_conduit(struct platform_device *pdev) 958static int sdei_get_conduit(struct platform_device *pdev)
891{ 959{
892 const char *method; 960 const char *method;
diff --git a/include/linux/arm_sdei.h b/include/linux/arm_sdei.h
index 942afbd544b7..393899192906 100644
--- a/include/linux/arm_sdei.h
+++ b/include/linux/arm_sdei.h
@@ -11,6 +11,7 @@ enum sdei_conduit_types {
11 CONDUIT_HVC, 11 CONDUIT_HVC,
12}; 12};
13 13
14#include <acpi/ghes.h>
14#include <asm/sdei.h> 15#include <asm/sdei.h>
15 16
16/* Arch code should override this to set the entry point from firmware... */ 17/* Arch code should override this to set the entry point from firmware... */
@@ -39,6 +40,11 @@ int sdei_event_unregister(u32 event_num);
39int sdei_event_enable(u32 event_num); 40int sdei_event_enable(u32 event_num);
40int sdei_event_disable(u32 event_num); 41int sdei_event_disable(u32 event_num);
41 42
43/* GHES register/unregister helpers */
44int sdei_register_ghes(struct ghes *ghes, sdei_event_callback *normal_cb,
45 sdei_event_callback *critical_cb);
46int sdei_unregister_ghes(struct ghes *ghes);
47
42#ifdef CONFIG_ARM_SDE_INTERFACE 48#ifdef CONFIG_ARM_SDE_INTERFACE
43/* For use by arch code when CPU hotplug notifiers are not appropriate. */ 49/* For use by arch code when CPU hotplug notifiers are not appropriate. */
44int sdei_mask_local_cpu(void); 50int sdei_mask_local_cpu(void);