Message ID | 1492556723-9189-7-git-send-email-tbaicar@codeaurora.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Tue, Apr 18, 2017 at 05:05:18PM -0600, Tyler Baicar wrote: > ARM APEI extension proposal added SEA (Synchronous External Abort) > notification type for ARMv8. > Add a new GHES error source handling function for SEA. If an error > source's notification type is SEA, then this function can be registered > into the SEA exception handler. That way GHES will parse and report > SEA exceptions when they occur. > An SEA can interrupt code that had interrupts masked and is treated as > an NMI. To aid this the page of address space for mapping APEI buffers > while in_nmi() is always reserved, and ghes_ioremap_pfn_nmi() is > changed to use the helper methods to find the prot_t to map with in > the same way as ghes_ioremap_pfn_irq(). ... > @@ -518,6 +520,17 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) > pr_err("Synchronous External Abort: %s (0x%08x) at 0x%016lx\n", > inf->name, esr, addr); > > + /* > + * Synchronous aborts may interrupt code which had interrupts masked. > + * Before calling out into the wider kernel tell the interested > + * subsystems. > + */ > + if (IS_ENABLED(CONFIG_ACPI_APEI_SEA)) { > + nmi_enter(); > + ghes_notify_sea(); > + nmi_exit(); > + } Well, the other GHES notification methods use a notifier: ghes_notify_sci, ghes_notify_nmi. You probably should do that too instead of calling straight into a driver from arch code.
On 4/25/2017 11:21 AM, Borislav Petkov wrote: > On Tue, Apr 18, 2017 at 05:05:18PM -0600, Tyler Baicar wrote: >> ARM APEI extension proposal added SEA (Synchronous External Abort) >> notification type for ARMv8. >> Add a new GHES error source handling function for SEA. If an error >> source's notification type is SEA, then this function can be registered >> into the SEA exception handler. That way GHES will parse and report >> SEA exceptions when they occur. >> An SEA can interrupt code that had interrupts masked and is treated as >> an NMI. To aid this the page of address space for mapping APEI buffers >> while in_nmi() is always reserved, and ghes_ioremap_pfn_nmi() is >> changed to use the helper methods to find the prot_t to map with in >> the same way as ghes_ioremap_pfn_irq(). > ... > >> @@ -518,6 +520,17 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) >> pr_err("Synchronous External Abort: %s (0x%08x) at 0x%016lx\n", >> inf->name, esr, addr); >> >> + /* >> + * Synchronous aborts may interrupt code which had interrupts masked. >> + * Before calling out into the wider kernel tell the interested >> + * subsystems. >> + */ >> + if (IS_ENABLED(CONFIG_ACPI_APEI_SEA)) { >> + nmi_enter(); >> + ghes_notify_sea(); >> + nmi_exit(); >> + } > Well, the other GHES notification methods use a notifier: > ghes_notify_sci, ghes_notify_nmi. You probably should do that too > instead of calling straight into a driver from arch code. I originally had this as a notifier, but Will requested to remove the notifier. That conversation is here: https://lkml.org/lkml/2017/1/18/1018 Thanks, Tyler
On Tue, Apr 25, 2017 at 11:41:39AM -0600, Baicar, Tyler wrote: > I originally had this as a notifier, but Will requested to remove the > notifier. That conversation is here: https://lkml.org/lkml/2017/1/18/1018 Yeah, he mentioned on IRC. I just think notifiers would be the cleaner thing but whatever you guys say. Just we had a nasty hack on x86 which I got rid of recently: https://lkml.kernel.org/r/20170406090634.30950-1-bp@alien8.de and I wouldn't want you guys to have the same "fun". :)
Hi Tyler, On 19/04/17 00:05, Tyler Baicar wrote: > ARM APEI extension proposal added SEA (Synchronous External Abort) > notification type for ARMv8. > Add a new GHES error source handling function for SEA. If an error > source's notification type is SEA, then this function can be registered > into the SEA exception handler. That way GHES will parse and report > SEA exceptions when they occur. > An SEA can interrupt code that had interrupts masked and is treated as > an NMI. To aid this the page of address space for mapping APEI buffers > while in_nmi() is always reserved, and ghes_ioremap_pfn_nmi() is > changed to use the helper methods to find the prot_t to map with in > the same way as ghes_ioremap_pfn_irq(). > diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c > index b74d8b7..10013ff 100644 > --- a/arch/arm64/mm/fault.c > +++ b/arch/arm64/mm/fault.c > @@ -518,6 +520,17 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) > pr_err("Synchronous External Abort: %s (0x%08x) at 0x%016lx\n", > inf->name, esr, addr); > > + /* > + * Synchronous aborts may interrupt code which had interrupts masked. > + * Before calling out into the wider kernel tell the interested > + * subsystems. > + */ > + if (IS_ENABLED(CONFIG_ACPI_APEI_SEA)) { > + nmi_enter(); > + ghes_notify_sea(); > + nmi_exit(); > + } > + > info.si_signo = SIGBUS; > info.si_errno = 0; > info.si_code = 0; I was tidying up the masking/unmasking in entry.S, something I wasn't aware of that leads to a bug: entry.S will unmask interrupts for instruction/data aborts that came from a context with interrupts enabled. This makes sense for get_user() and friends... For do_sea() we pull nmi_enter() as this can interrupt interrupts-masked code, such as APEI, but if we end up in here with interrupts unmasked we can take an IRQ from this 'NMI' context, which will inherit the in_nmi() and could lead to the deadlock we were originally trying to avoid. Teaching entry.S to spot external aborts is messy. I think the two choices are to either mask interrupts when calling nmi_enter() (as these things should be mutually exclusive), or to conditionally call nmi_enter() based on interrupts_enabled(regs). I prefer the second one as it matches the notify_sea() while interruptible that happens when KVM takes one of these. Thanks, James
On 5/8/2017 11:28 AM, James Morse wrote: > Hi Tyler, > > On 19/04/17 00:05, Tyler Baicar wrote: >> ARM APEI extension proposal added SEA (Synchronous External Abort) >> notification type for ARMv8. >> Add a new GHES error source handling function for SEA. If an error >> source's notification type is SEA, then this function can be registered >> into the SEA exception handler. That way GHES will parse and report >> SEA exceptions when they occur. >> An SEA can interrupt code that had interrupts masked and is treated as >> an NMI. To aid this the page of address space for mapping APEI buffers >> while in_nmi() is always reserved, and ghes_ioremap_pfn_nmi() is >> changed to use the helper methods to find the prot_t to map with in >> the same way as ghes_ioremap_pfn_irq(). >> diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c >> index b74d8b7..10013ff 100644 >> --- a/arch/arm64/mm/fault.c >> +++ b/arch/arm64/mm/fault.c >> @@ -518,6 +520,17 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) >> pr_err("Synchronous External Abort: %s (0x%08x) at 0x%016lx\n", >> inf->name, esr, addr); >> >> + /* >> + * Synchronous aborts may interrupt code which had interrupts masked. >> + * Before calling out into the wider kernel tell the interested >> + * subsystems. >> + */ >> + if (IS_ENABLED(CONFIG_ACPI_APEI_SEA)) { >> + nmi_enter(); >> + ghes_notify_sea(); >> + nmi_exit(); >> + } >> + >> info.si_signo = SIGBUS; >> info.si_errno = 0; >> info.si_code = 0; > > I was tidying up the masking/unmasking in entry.S, something I wasn't aware of > that leads to a bug: > entry.S will unmask interrupts for instruction/data aborts that came from a > context with interrupts enabled. This makes sense for get_user() and friends... > For do_sea() we pull nmi_enter() as this can interrupt interrupts-masked code, > such as APEI, but if we end up in here with interrupts unmasked we can take an > IRQ from this 'NMI' context, which will inherit the in_nmi() and could lead to > the deadlock we were originally trying to avoid. > > Teaching entry.S to spot external aborts is messy. I think the two choices are > to either mask interrupts when calling nmi_enter() (as these things should be > mutually exclusive), or to conditionally call nmi_enter() based on > interrupts_enabled(regs). I prefer the second one as it matches the notify_sea() > while interruptible that happens when KVM takes one of these. Hello James, So it would need to be like this? if(interrupts_enabled(regs)) nmi_enter(); ghes_notify_sea(); if(interrupts_enabled(regs)) nmi_exit(); Thanks, Tyler
Hi Tyler, On 08/05/17 20:59, Baicar, Tyler wrote: > On 5/8/2017 11:28 AM, James Morse wrote: >> I was tidying up the masking/unmasking in entry.S, something I wasn't aware of >> that leads to a bug: >> entry.S will unmask interrupts for instruction/data aborts that came from a >> context with interrupts enabled. This makes sense for get_user() and friends... >> For do_sea() we pull nmi_enter() as this can interrupt interrupts-masked code, >> such as APEI, but if we end up in here with interrupts unmasked we can take an >> IRQ from this 'NMI' context, which will inherit the in_nmi() and could lead to >> the deadlock we were originally trying to avoid. >> >> Teaching entry.S to spot external aborts is messy. I think the two choices are >> to either mask interrupts when calling nmi_enter() (as these things should be >> mutually exclusive), or to conditionally call nmi_enter() based on >> interrupts_enabled(regs). I prefer the second one as it matches the notify_sea() >> while interruptible that happens when KVM takes one of these. Thinking about this some more: the KVM case is different as we know it was a guest that triggered the external abort. Nothing the host kernel does is likely to trigger either the same error or a related one. But I can't think of a way this would trip twice on the host... yes your suggestion looks fine. (When we add SError/SEI support too we will need to change it as SEA may interrupt SEI, and nmi_enter() has a BUG_ON(in_nmi()), so this nesting will need explicitly checking.) Thanks, James
Hi Tyler, On 2017/4/19 7:05, Tyler Baicar wrote: > ARM APEI extension proposal added SEA (Synchronous External Abort) > notification type for ARMv8. > Add a new GHES error source handling function for SEA. If an error > source's notification type is SEA, then this function can be registered > into the SEA exception handler. That way GHES will parse and report > SEA exceptions when they occur. > An SEA can interrupt code that had interrupts masked and is treated as > an NMI. To aid this the page of address space for mapping APEI buffers > while in_nmi() is always reserved, and ghes_ioremap_pfn_nmi() is > changed to use the helper methods to find the prot_t to map with in > the same way as ghes_ioremap_pfn_irq(). > > Signed-off-by: Tyler Baicar <tbaicar@codeaurora.org> > CC: Jonathan (Zhixiong) Zhang <zjzhang@codeaurora.org> > Reviewed-by: James Morse <james.morse@arm.com> > Acked-by: Catalin Marinas <catalin.marinas@arm.com> > --- > @@ -518,6 +520,17 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) > pr_err("Synchronous External Abort: %s (0x%08x) at 0x%016lx\n", > inf->name, esr, addr); > > + /* > + * Synchronous aborts may interrupt code which had interrupts masked. > + * Before calling out into the wider kernel tell the interested > + * subsystems. > + */ > + if (IS_ENABLED(CONFIG_ACPI_APEI_SEA)) { > + nmi_enter(); > + ghes_notify_sea(); > + nmi_exit(); > + } > + > info.si_signo = SIGBUS; > info.si_errno = 0; > info.si_code = 0; For instruction abort, if there exists memory section in ghes, we will call memory_failure() in ghes_notify_sea() and reread the instruction from the disk. In this case, we don't have to send SIGBUS to the application. But memory_failure() is scheduled in a work queue, we don't what the result of memory_failure will be when ghes_notify_sea() returned. Do you have any idea about how to fix this, so we don't have to kill the application in the instruction abort case. Thanks, Wang Xiongfeng > diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig > index b0140c8..de14d49 100644 > --- a/drivers/acpi/apei/Kconfig > +++ b/drivers/acpi/apei/Kconfig > @@ -39,6 +39,21 @@ config ACPI_APEI_PCIEAER > PCIe AER errors may be reported via APEI firmware first mode. > Turn on this option to enable the corresponding support. > > +config ACPI_APEI_SEA > + bool "APEI Synchronous External Abort logging/recovering support" > + depends on ARM64 && ACPI_APEI_GHES > + default y > + help > + This option should be enabled if the system supports > + firmware first handling of SEA (Synchronous External Abort). > + SEA happens with certain faults of data abort or instruction > + abort synchronous exceptions on ARMv8 systems. If a system > + supports firmware first handling of SEA, the platform analyzes > + and handles hardware error notifications from SEA, and it may then > + form a HW error record for the OS to parse and handle. This > + option allows the OS to look for such hardware error record, and > + take appropriate action. > + > config ACPI_APEI_MEMORY_FAILURE > bool "APEI memory error recovering support" > depends on ACPI_APEI && MEMORY_FAILURE > diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c > index dfb7dd2..2d387f8 100644 > --- a/drivers/acpi/apei/ghes.c > +++ b/drivers/acpi/apei/ghes.c > @@ -115,11 +115,7 @@ > * Two virtual pages are used, one for IRQ/PROCESS context, the other for > * NMI context (optionally). > */ > -#ifdef CONFIG_HAVE_ACPI_APEI_NMI > #define GHES_IOREMAP_PAGES 2 > -#else > -#define GHES_IOREMAP_PAGES 1 > -#endif > #define GHES_IOREMAP_IRQ_PAGE(base) (base) > #define GHES_IOREMAP_NMI_PAGE(base) ((base) + PAGE_SIZE) > > @@ -158,10 +154,14 @@ static void ghes_ioremap_exit(void) > static void __iomem *ghes_ioremap_pfn_nmi(u64 pfn) > { > unsigned long vaddr; > + phys_addr_t paddr; > + pgprot_t prot; > > vaddr = (unsigned long)GHES_IOREMAP_NMI_PAGE(ghes_ioremap_area->addr); > - ioremap_page_range(vaddr, vaddr + PAGE_SIZE, > - pfn << PAGE_SHIFT, PAGE_KERNEL); > + > + paddr = pfn << PAGE_SHIFT; > + prot = arch_apei_get_mem_attribute(paddr); > + ioremap_page_range(vaddr, vaddr + PAGE_SIZE, paddr, prot); > > return (void __iomem *)vaddr; > } > @@ -771,6 +771,50 @@ static int ghes_notify_sci(struct notifier_block *this, > .notifier_call = ghes_notify_sci, > }; > > +#ifdef CONFIG_ACPI_APEI_SEA > +static LIST_HEAD(ghes_sea); > + > +void ghes_notify_sea(void) > +{ > + struct ghes *ghes; > + > + /* > + * synchronize_rcu() will wait for nmi_exit(), so no need to > + * rcu_read_lock(). > + */ > + list_for_each_entry_rcu(ghes, &ghes_sea, list) { > + ghes_proc(ghes); > + } > +} > + > +static void ghes_sea_add(struct ghes *ghes) > +{ > + mutex_lock(&ghes_list_mutex); > + list_add_rcu(&ghes->list, &ghes_sea); > + mutex_unlock(&ghes_list_mutex); > +} > + > +static void ghes_sea_remove(struct ghes *ghes) > +{ > + mutex_lock(&ghes_list_mutex); > + list_del_rcu(&ghes->list); > + mutex_unlock(&ghes_list_mutex); > + synchronize_rcu(); > +} > +#else /* CONFIG_ACPI_APEI_SEA */ > +static inline void ghes_sea_add(struct ghes *ghes) > +{ > + pr_err(GHES_PFX "ID: %d, trying to add SEA notification which is not supported\n", > + ghes->generic->header.source_id); > +} > + > +static inline void ghes_sea_remove(struct ghes *ghes) > +{ > + pr_err(GHES_PFX "ID: %d, trying to remove SEA notification which is not supported\n", > + ghes->generic->header.source_id); > +} > +#endif /* CONFIG_ACPI_APEI_SEA */ > + > #ifdef CONFIG_HAVE_ACPI_APEI_NMI > /* > * printk is not safe in NMI context. So in NMI handler, we allocate > @@ -1016,6 +1060,14 @@ static int ghes_probe(struct platform_device *ghes_dev) > case ACPI_HEST_NOTIFY_EXTERNAL: > case ACPI_HEST_NOTIFY_SCI: > break; > + case ACPI_HEST_NOTIFY_SEA: > + if (!IS_ENABLED(CONFIG_ACPI_APEI_SEA)) { > + pr_warn(GHES_PFX "Generic hardware error source: %d notified via SEA is not supported\n", > + generic->header.source_id); > + rc = -ENOTSUPP; > + goto err; > + } > + break; > case ACPI_HEST_NOTIFY_NMI: > if (!IS_ENABLED(CONFIG_HAVE_ACPI_APEI_NMI)) { > pr_warn(GHES_PFX "Generic hardware error source: %d notified via NMI interrupt is not supported!\n", > @@ -1081,6 +1133,9 @@ static int ghes_probe(struct platform_device *ghes_dev) > list_add_rcu(&ghes->list, &ghes_sci); > mutex_unlock(&ghes_list_mutex); > break; > + case ACPI_HEST_NOTIFY_SEA: > + ghes_sea_add(ghes); > + break; > case ACPI_HEST_NOTIFY_NMI: > ghes_nmi_add(ghes); > break; > @@ -1124,6 +1179,9 @@ static int ghes_remove(struct platform_device *ghes_dev) > mutex_unlock(&ghes_list_mutex); > synchronize_rcu(); > break; > + case ACPI_HEST_NOTIFY_SEA: > + ghes_sea_remove(ghes); > + break; > case ACPI_HEST_NOTIFY_NMI: > ghes_nmi_remove(ghes); > break; > diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h > index b89361a..ef0040893 100644 > --- a/include/acpi/ghes.h > +++ b/include/acpi/ghes.h > @@ -1,3 +1,6 @@ > +#ifndef GHES_H > +#define GHES_H > + > #include <acpi/apei.h> > #include <acpi/hed.h> > > @@ -95,3 +98,7 @@ static inline void *acpi_hest_get_payload(struct acpi_hest_generic_data *gdata) > > return gdata + 1; > } > + > +void ghes_notify_sea(void); > + > +#endif /* GHES_H */ >
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 3741859..36226c2 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -18,6 +18,7 @@ config ARM64 select ARCH_HAS_STRICT_KERNEL_RWX select ARCH_HAS_STRICT_MODULE_RWX select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST + select ARCH_HAVE_NMI_SAFE_CMPXCHG if ACPI_APEI_SEA select ARCH_USE_CMPXCHG_LOCKREF select ARCH_SUPPORTS_ATOMIC_RMW select ARCH_SUPPORTS_NUMA_BALANCING @@ -92,6 +93,7 @@ config ARM64 select HAVE_IRQ_TIME_ACCOUNTING select HAVE_MEMBLOCK select HAVE_MEMBLOCK_NODE_MAP if NUMA + select HAVE_NMI if ACPI_APEI_SEA select HAVE_PATA_PLATFORM select HAVE_PERF_EVENTS select HAVE_PERF_REGS diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index b74d8b7..10013ff 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -42,6 +42,8 @@ #include <asm/pgtable.h> #include <asm/tlbflush.h> +#include <acpi/ghes.h> + struct fault_info { int (*fn)(unsigned long addr, unsigned int esr, struct pt_regs *regs); @@ -518,6 +520,17 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs) pr_err("Synchronous External Abort: %s (0x%08x) at 0x%016lx\n", inf->name, esr, addr); + /* + * Synchronous aborts may interrupt code which had interrupts masked. + * Before calling out into the wider kernel tell the interested + * subsystems. + */ + if (IS_ENABLED(CONFIG_ACPI_APEI_SEA)) { + nmi_enter(); + ghes_notify_sea(); + nmi_exit(); + } + info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = 0; diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig index b0140c8..de14d49 100644 --- a/drivers/acpi/apei/Kconfig +++ b/drivers/acpi/apei/Kconfig @@ -39,6 +39,21 @@ config ACPI_APEI_PCIEAER PCIe AER errors may be reported via APEI firmware first mode. Turn on this option to enable the corresponding support. +config ACPI_APEI_SEA + bool "APEI Synchronous External Abort logging/recovering support" + depends on ARM64 && ACPI_APEI_GHES + default y + help + This option should be enabled if the system supports + firmware first handling of SEA (Synchronous External Abort). + SEA happens with certain faults of data abort or instruction + abort synchronous exceptions on ARMv8 systems. If a system + supports firmware first handling of SEA, the platform analyzes + and handles hardware error notifications from SEA, and it may then + form a HW error record for the OS to parse and handle. This + option allows the OS to look for such hardware error record, and + take appropriate action. + config ACPI_APEI_MEMORY_FAILURE bool "APEI memory error recovering support" depends on ACPI_APEI && MEMORY_FAILURE diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index dfb7dd2..2d387f8 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -115,11 +115,7 @@ * Two virtual pages are used, one for IRQ/PROCESS context, the other for * NMI context (optionally). */ -#ifdef CONFIG_HAVE_ACPI_APEI_NMI #define GHES_IOREMAP_PAGES 2 -#else -#define GHES_IOREMAP_PAGES 1 -#endif #define GHES_IOREMAP_IRQ_PAGE(base) (base) #define GHES_IOREMAP_NMI_PAGE(base) ((base) + PAGE_SIZE) @@ -158,10 +154,14 @@ static void ghes_ioremap_exit(void) static void __iomem *ghes_ioremap_pfn_nmi(u64 pfn) { unsigned long vaddr; + phys_addr_t paddr; + pgprot_t prot; vaddr = (unsigned long)GHES_IOREMAP_NMI_PAGE(ghes_ioremap_area->addr); - ioremap_page_range(vaddr, vaddr + PAGE_SIZE, - pfn << PAGE_SHIFT, PAGE_KERNEL); + + paddr = pfn << PAGE_SHIFT; + prot = arch_apei_get_mem_attribute(paddr); + ioremap_page_range(vaddr, vaddr + PAGE_SIZE, paddr, prot); return (void __iomem *)vaddr; } @@ -771,6 +771,50 @@ static int ghes_notify_sci(struct notifier_block *this, .notifier_call = ghes_notify_sci, }; +#ifdef CONFIG_ACPI_APEI_SEA +static LIST_HEAD(ghes_sea); + +void ghes_notify_sea(void) +{ + struct ghes *ghes; + + /* + * synchronize_rcu() will wait for nmi_exit(), so no need to + * rcu_read_lock(). + */ + list_for_each_entry_rcu(ghes, &ghes_sea, list) { + ghes_proc(ghes); + } +} + +static void ghes_sea_add(struct ghes *ghes) +{ + mutex_lock(&ghes_list_mutex); + list_add_rcu(&ghes->list, &ghes_sea); + mutex_unlock(&ghes_list_mutex); +} + +static void ghes_sea_remove(struct ghes *ghes) +{ + mutex_lock(&ghes_list_mutex); + list_del_rcu(&ghes->list); + mutex_unlock(&ghes_list_mutex); + synchronize_rcu(); +} +#else /* CONFIG_ACPI_APEI_SEA */ +static inline void ghes_sea_add(struct ghes *ghes) +{ + pr_err(GHES_PFX "ID: %d, trying to add SEA notification which is not supported\n", + ghes->generic->header.source_id); +} + +static inline void ghes_sea_remove(struct ghes *ghes) +{ + pr_err(GHES_PFX "ID: %d, trying to remove SEA notification which is not supported\n", + ghes->generic->header.source_id); +} +#endif /* CONFIG_ACPI_APEI_SEA */ + #ifdef CONFIG_HAVE_ACPI_APEI_NMI /* * printk is not safe in NMI context. So in NMI handler, we allocate @@ -1016,6 +1060,14 @@ static int ghes_probe(struct platform_device *ghes_dev) case ACPI_HEST_NOTIFY_EXTERNAL: case ACPI_HEST_NOTIFY_SCI: break; + case ACPI_HEST_NOTIFY_SEA: + if (!IS_ENABLED(CONFIG_ACPI_APEI_SEA)) { + pr_warn(GHES_PFX "Generic hardware error source: %d notified via SEA is not supported\n", + generic->header.source_id); + rc = -ENOTSUPP; + goto err; + } + break; case ACPI_HEST_NOTIFY_NMI: if (!IS_ENABLED(CONFIG_HAVE_ACPI_APEI_NMI)) { pr_warn(GHES_PFX "Generic hardware error source: %d notified via NMI interrupt is not supported!\n", @@ -1081,6 +1133,9 @@ static int ghes_probe(struct platform_device *ghes_dev) list_add_rcu(&ghes->list, &ghes_sci); mutex_unlock(&ghes_list_mutex); break; + case ACPI_HEST_NOTIFY_SEA: + ghes_sea_add(ghes); + break; case ACPI_HEST_NOTIFY_NMI: ghes_nmi_add(ghes); break; @@ -1124,6 +1179,9 @@ static int ghes_remove(struct platform_device *ghes_dev) mutex_unlock(&ghes_list_mutex); synchronize_rcu(); break; + case ACPI_HEST_NOTIFY_SEA: + ghes_sea_remove(ghes); + break; case ACPI_HEST_NOTIFY_NMI: ghes_nmi_remove(ghes); break; diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h index b89361a..ef0040893 100644 --- a/include/acpi/ghes.h +++ b/include/acpi/ghes.h @@ -1,3 +1,6 @@ +#ifndef GHES_H +#define GHES_H + #include <acpi/apei.h> #include <acpi/hed.h> @@ -95,3 +98,7 @@ static inline void *acpi_hest_get_payload(struct acpi_hest_generic_data *gdata) return gdata + 1; } + +void ghes_notify_sea(void); + +#endif /* GHES_H */