aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Morse <james.morse@arm.com>2019-01-29 13:49:01 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2019-02-11 05:07:49 -0500
commitf96935d3bc38a5f4b5188b6470a10e3fb8c3f0cc (patch)
treeb497ba059c9fccd471f9176289dbe04907c66452
parentb972d2eaf0c7021579755eec6b2b79e0f5bc7930 (diff)
firmware: arm_sdei: Add ACPI GHES registration helper
APEI's Generic Hardware Error Source structures do not describe whether the SDEI event is shared or private, as this information is discoverable via the API. GHES needs to know whether an event is normal or critical to avoid sharing locks or fixmap entries, but GHES shouldn't have to know about the SDEI API. Add a helper to register the GHES using the appropriate normal or critical callback. Signed-off-by: James Morse <james.morse@arm.com> Acked-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-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);