Skip to content

Commit 8e40612

Browse files
justin-hesuryasaimadhu
authored andcommitted
EDAC/ghes: Add a notifier for reporting memory errors
In order to make it a proper module and disentangle it from facilities, add a notifier for reporting memory errors. Use an atomic notifier because calls sites like ghes_proc_in_irq() run in interrupt context. [ bp: Massage commit message. ] Suggested-by: Borislav Petkov <bp@alien8.de> Signed-off-by: Jia He <justin.he@arm.com> Signed-off-by: Borislav Petkov <bp@suse.de> Link: https://lore.kernel.org/r/20221010023559.69655-3-justin.he@arm.com
1 parent 5012524 commit 8e40612

3 files changed

Lines changed: 35 additions & 10 deletions

File tree

drivers/acpi/apei/ghes.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@
9494
#define FIX_APEI_GHES_SDEI_CRITICAL __end_of_fixed_addresses
9595
#endif
9696

97+
static ATOMIC_NOTIFIER_HEAD(ghes_report_chain);
98+
9799
static inline bool is_hest_type_generic_v2(struct ghes *ghes)
98100
{
99101
return ghes->generic->header.type == ACPI_HEST_TYPE_GENERIC_ERROR_V2;
@@ -645,7 +647,7 @@ static bool ghes_do_proc(struct ghes *ghes,
645647
if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
646648
struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
647649

648-
ghes_edac_report_mem_error(sev, mem_err);
650+
atomic_notifier_call_chain(&ghes_report_chain, sev, mem_err);
649651

650652
arch_apei_report_mem_error(sev, mem_err);
651653
queued = ghes_handle_memory_failure(gdata, sev);
@@ -1497,3 +1499,15 @@ void __init acpi_ghes_init(void)
14971499
else
14981500
pr_info(GHES_PFX "Failed to enable APEI firmware first mode.\n");
14991501
}
1502+
1503+
void ghes_register_report_chain(struct notifier_block *nb)
1504+
{
1505+
atomic_notifier_chain_register(&ghes_report_chain, nb);
1506+
}
1507+
EXPORT_SYMBOL_GPL(ghes_register_report_chain);
1508+
1509+
void ghes_unregister_report_chain(struct notifier_block *nb)
1510+
{
1511+
atomic_notifier_chain_unregister(&ghes_report_chain, nb);
1512+
}
1513+
EXPORT_SYMBOL_GPL(ghes_unregister_report_chain);

drivers/edac/ghes_edac.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/dmi.h>
1515
#include "edac_module.h"
1616
#include <ras/ras_event.h>
17+
#include <linux/notifier.h>
1718

1819
#define OTHER_DETAIL_LEN 400
1920

@@ -267,11 +268,14 @@ static int print_mem_error_other_detail(const struct cper_sec_mem_err *mem, char
267268
return n;
268269
}
269270

270-
void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
271+
static int ghes_edac_report_mem_error(struct notifier_block *nb,
272+
unsigned long val, void *data)
271273
{
274+
struct cper_sec_mem_err *mem_err = (struct cper_sec_mem_err *)data;
272275
struct cper_mem_err_compact cmem;
273276
struct edac_raw_error_desc *e;
274277
struct mem_ctl_info *mci;
278+
unsigned long sev = val;
275279
struct ghes_pvt *pvt;
276280
unsigned long flags;
277281
char *p;
@@ -282,7 +286,7 @@ void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
282286
* know.
283287
*/
284288
if (WARN_ON_ONCE(in_nmi()))
285-
return;
289+
return NOTIFY_OK;
286290

287291
spin_lock_irqsave(&ghes_lock, flags);
288292

@@ -374,8 +378,15 @@ void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err)
374378

375379
unlock:
376380
spin_unlock_irqrestore(&ghes_lock, flags);
381+
382+
return NOTIFY_OK;
377383
}
378384

385+
static struct notifier_block ghes_edac_mem_err_nb = {
386+
.notifier_call = ghes_edac_report_mem_error,
387+
.priority = 0,
388+
};
389+
379390
/*
380391
* Known systems that are safe to enable this module.
381392
*/
@@ -503,6 +514,8 @@ int ghes_edac_register(struct ghes *ghes, struct device *dev)
503514
ghes_pvt = pvt;
504515
spin_unlock_irqrestore(&ghes_lock, flags);
505516

517+
ghes_register_report_chain(&ghes_edac_mem_err_nb);
518+
506519
/* only set on success */
507520
refcount_set(&ghes_refcount, 1);
508521

@@ -548,6 +561,8 @@ void ghes_edac_unregister(struct ghes *ghes)
548561
if (mci)
549562
edac_mc_free(mci);
550563

564+
ghes_unregister_report_chain(&ghes_edac_mem_err_nb);
565+
551566
unlock:
552567
mutex_unlock(&ghes_reg_mutex);
553568
}

include/acpi/ghes.h

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,18 +76,11 @@ int ghes_estatus_pool_init(int num_ghes);
7676
/* From drivers/edac/ghes_edac.c */
7777

7878
#ifdef CONFIG_EDAC_GHES
79-
void ghes_edac_report_mem_error(int sev, struct cper_sec_mem_err *mem_err);
80-
8179
int ghes_edac_register(struct ghes *ghes, struct device *dev);
8280

8381
void ghes_edac_unregister(struct ghes *ghes);
8482

8583
#else
86-
static inline void ghes_edac_report_mem_error(int sev,
87-
struct cper_sec_mem_err *mem_err)
88-
{
89-
}
90-
9184
static inline int ghes_edac_register(struct ghes *ghes, struct device *dev)
9285
{
9386
return -ENODEV;
@@ -145,4 +138,7 @@ int ghes_notify_sea(void);
145138
static inline int ghes_notify_sea(void) { return -ENOENT; }
146139
#endif
147140

141+
struct notifier_block;
142+
extern void ghes_register_report_chain(struct notifier_block *nb);
143+
extern void ghes_unregister_report_chain(struct notifier_block *nb);
148144
#endif /* GHES_H */

0 commit comments

Comments
 (0)