diff options
| -rw-r--r-- | arch/arm64/include/asm/fixmap.h | 4 | ||||
| -rw-r--r-- | drivers/firmware/arm_sdei.c | 68 | ||||
| -rw-r--r-- | include/linux/arm_sdei.h | 6 |
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 | ||
| 891 | int 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 | |||
| 928 | int 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 | |||
| 890 | static int sdei_get_conduit(struct platform_device *pdev) | 958 | static 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); | |||
| 39 | int sdei_event_enable(u32 event_num); | 40 | int sdei_event_enable(u32 event_num); |
| 40 | int sdei_event_disable(u32 event_num); | 41 | int sdei_event_disable(u32 event_num); |
| 41 | 42 | ||
| 43 | /* GHES register/unregister helpers */ | ||
| 44 | int sdei_register_ghes(struct ghes *ghes, sdei_event_callback *normal_cb, | ||
| 45 | sdei_event_callback *critical_cb); | ||
| 46 | int 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. */ |
| 44 | int sdei_mask_local_cpu(void); | 50 | int sdei_mask_local_cpu(void); |
