提交 9ba61fa5 编写于 作者: J James Morse 提交者: Baolin Wang

firmware: arm_sdei: Add ACPI GHES registration helper

fix #28612342

commit f96935d3bc38a5f4b5188b6470a10e3fb8c3f0cc upstream

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: NJames Morse <james.morse@arm.com>
Acked-by: NCatalin Marinas <catalin.marinas@arm.com>
Signed-off-by: NRafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: NBaolin Wang <baolin.wang@linux.alibaba.com>
Reviewed-by: NAlex Shi <alex.shi@linux.alibaba.com>
Acked-by: NCaspar Zhang <caspar@linux.alibaba.com>
Reviewed-by: Nluanshi <zhangliguang@linux.alibaba.com>
上级 5c61297c
...@@ -56,6 +56,10 @@ enum fixed_addresses { ...@@ -56,6 +56,10 @@ enum fixed_addresses {
/* Used for GHES mapping from assorted contexts */ /* Used for GHES mapping from assorted contexts */
FIX_APEI_GHES_IRQ, FIX_APEI_GHES_IRQ,
FIX_APEI_GHES_SEA, 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 */ #endif /* CONFIG_ACPI_APEI_GHES */
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
// Copyright (C) 2017 Arm Ltd. // Copyright (C) 2017 Arm Ltd.
#define pr_fmt(fmt) "sdei: " fmt #define pr_fmt(fmt) "sdei: " fmt
#include <acpi/ghes.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/arm_sdei.h> #include <linux/arm_sdei.h>
#include <linux/arm-smccc.h> #include <linux/arm-smccc.h>
...@@ -887,6 +888,73 @@ static void sdei_smccc_hvc(unsigned long function_id, ...@@ -887,6 +888,73 @@ static void sdei_smccc_hvc(unsigned long function_id,
arm_smccc_hvc(function_id, arg0, arg1, arg2, arg3, arg4, 0, 0, res); 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) static int sdei_get_conduit(struct platform_device *pdev)
{ {
const char *method; const char *method;
......
...@@ -11,6 +11,7 @@ enum sdei_conduit_types { ...@@ -11,6 +11,7 @@ enum sdei_conduit_types {
CONDUIT_HVC, CONDUIT_HVC,
}; };
#include <acpi/ghes.h>
#include <asm/sdei.h> #include <asm/sdei.h>
/* Arch code should override this to set the entry point from firmware... */ /* Arch code should override this to set the entry point from firmware... */
...@@ -39,6 +40,11 @@ int sdei_event_unregister(u32 event_num); ...@@ -39,6 +40,11 @@ int sdei_event_unregister(u32 event_num);
int sdei_event_enable(u32 event_num); int sdei_event_enable(u32 event_num);
int sdei_event_disable(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 #ifdef CONFIG_ARM_SDE_INTERFACE
/* For use by arch code when CPU hotplug notifiers are not appropriate. */ /* For use by arch code when CPU hotplug notifiers are not appropriate. */
int sdei_mask_local_cpu(void); int sdei_mask_local_cpu(void);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册