Skip to content
This repository has been archived by the owner on Jul 16, 2024. It is now read-only.

Commit

Permalink
BACKPORT: firmware: arm_sdei: Add ACPI GHES registration helper
Browse files Browse the repository at this point in the history
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.

This patch is needed because Quicksilver firmware-first error handling
uses the SDEI notification type for communication between trusted
firmware and the OS. This adds needed NMI and SDEI functionality so
that the SDEI path in the kernel through APEI acts as an NMI and is
properly wired up to the APEI interfaces.

Backported from: torvalds/linux@f96935d

Signed-off-by: James Morse <[email protected]>
Acked-by: Catalin Marinas <[email protected]>
Signed-off-by: Tyler Baicar <[email protected]>
  • Loading branch information
James Morse authored and tphan-ampere committed Apr 21, 2020
1 parent 76f72cb commit 535e7eb
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 0 deletions.
4 changes: 4 additions & 0 deletions arch/arm64/include/asm/fixmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ enum fixed_addresses {
/* 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
Expand Down
68 changes: 68 additions & 0 deletions drivers/firmware/arm_sdei.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// 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>
Expand Down Expand Up @@ -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);
}

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;
Expand Down
6 changes: 6 additions & 0 deletions include/linux/arm_sdei.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ enum sdei_conduit_types {
CONDUIT_HVC,
};

#include <acpi/ghes.h>
#include <asm/sdei.h>

/* Arch code should override this to set the entry point from firmware... */
Expand Down Expand Up @@ -39,6 +40,11 @@ int sdei_event_unregister(u32 event_num);
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);
Expand Down

0 comments on commit 535e7eb

Please sign in to comment.