Skip to content

Commit a70297d

Browse files
axiqiarafaeljw
authored andcommitted
ACPI: APEI: set memory failure flags as MF_ACTION_REQUIRED on synchronous events
There are two major types of uncorrected recoverable (UCR) errors : - Synchronous error: The error is detected and raised at the point of the consumption in the execution flow, e.g. when a CPU tries to access a poisoned cache line. The CPU will take a synchronous error exception such as Synchronous External Abort (SEA) on Arm64 and Machine Check Exception (MCE) on X86. OS requires to take action (for example, offline failure page/kill failure thread) to recover this uncorrectable error. - Asynchronous error: The error is detected out of processor execution context, e.g. when an error is detected by a background scrubber. Some data in the memory are corrupted. But the data have not been consumed. OS is optional to take action to recover this uncorrectable error. When APEI firmware first is enabled, a platform may describe one error source for the handling of synchronous errors (e.g. MCE or SEA notification ), or for handling asynchronous errors (e.g. SCI or External Interrupt notification). In other words, we can distinguish synchronous errors by APEI notification. For synchronous errors, kernel will kill the current process which accessing the poisoned page by sending SIGBUS with BUS_MCEERR_AR. In addition, for asynchronous errors, kernel will notify the process who owns the poisoned page by sending SIGBUS with BUS_MCEERR_AO in early kill mode. However, the GHES driver always sets mf_flags to 0 so that all synchronous errors are handled as asynchronous errors in memory failure. To this end, set memory failure flags as MF_ACTION_REQUIRED on synchronous events. Signed-off-by: Shuai Xue <xueshuai@linux.alibaba.com> Tested-by: Ma Wupeng <mawupeng1@huawei.com> Reviewed-by: Kefeng Wang <wangkefeng.wang@huawei.com> Reviewed-by: Xiaofei Tan <tanxiaofei@huawei.com> Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com> Reviewed-by: James Morse <james.morse@arm.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent 22fca62 commit a70297d

File tree

1 file changed

+23
-6
lines changed

1 file changed

+23
-6
lines changed

drivers/acpi/apei/ghes.c

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,20 @@ static inline bool is_hest_type_generic_v2(struct ghes *ghes)
101101
return ghes->generic->header.type == ACPI_HEST_TYPE_GENERIC_ERROR_V2;
102102
}
103103

104+
/*
105+
* A platform may describe one error source for the handling of synchronous
106+
* errors (e.g. MCE or SEA), or for handling asynchronous errors (e.g. SCI
107+
* or External Interrupt). On x86, the HEST notifications are always
108+
* asynchronous, so only SEA on ARM is delivered as a synchronous
109+
* notification.
110+
*/
111+
static inline bool is_hest_sync_notify(struct ghes *ghes)
112+
{
113+
u8 notify_type = ghes->generic->notify.type;
114+
115+
return notify_type == ACPI_HEST_NOTIFY_SEA;
116+
}
117+
104118
/*
105119
* This driver isn't really modular, however for the time being,
106120
* continuing to use module_param is the easiest way to remain
@@ -489,7 +503,7 @@ static bool ghes_do_memory_failure(u64 physical_addr, int flags)
489503
}
490504

491505
static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata,
492-
int sev)
506+
int sev, bool sync)
493507
{
494508
int flags = -1;
495509
int sec_sev = ghes_severity(gdata->error_severity);
@@ -503,17 +517,19 @@ static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata,
503517
(gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED))
504518
flags = MF_SOFT_OFFLINE;
505519
if (sev == GHES_SEV_RECOVERABLE && sec_sev == GHES_SEV_RECOVERABLE)
506-
flags = 0;
520+
flags = sync ? MF_ACTION_REQUIRED : 0;
507521

508522
if (flags != -1)
509523
return ghes_do_memory_failure(mem_err->physical_addr, flags);
510524

511525
return false;
512526
}
513527

514-
static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, int sev)
528+
static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata,
529+
int sev, bool sync)
515530
{
516531
struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata);
532+
int flags = sync ? MF_ACTION_REQUIRED : 0;
517533
bool queued = false;
518534
int sec_sev, i;
519535
char *p;
@@ -538,7 +554,7 @@ static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, int s
538554
* and don't filter out 'corrected' error here.
539555
*/
540556
if (is_cache && has_pa) {
541-
queued = ghes_do_memory_failure(err_info->physical_fault_addr, 0);
557+
queued = ghes_do_memory_failure(err_info->physical_fault_addr, flags);
542558
p += err_info->length;
543559
continue;
544560
}
@@ -666,6 +682,7 @@ static bool ghes_do_proc(struct ghes *ghes,
666682
const guid_t *fru_id = &guid_null;
667683
char *fru_text = "";
668684
bool queued = false;
685+
bool sync = is_hest_sync_notify(ghes);
669686

670687
sev = ghes_severity(estatus->error_severity);
671688
apei_estatus_for_each_section(estatus, gdata) {
@@ -683,13 +700,13 @@ static bool ghes_do_proc(struct ghes *ghes,
683700
atomic_notifier_call_chain(&ghes_report_chain, sev, mem_err);
684701

685702
arch_apei_report_mem_error(sev, mem_err);
686-
queued = ghes_handle_memory_failure(gdata, sev);
703+
queued = ghes_handle_memory_failure(gdata, sev, sync);
687704
}
688705
else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
689706
ghes_handle_aer(gdata);
690707
}
691708
else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
692-
queued = ghes_handle_arm_hw_error(gdata, sev);
709+
queued = ghes_handle_arm_hw_error(gdata, sev, sync);
693710
} else {
694711
void *err = acpi_hest_get_payload(gdata);
695712

0 commit comments

Comments
 (0)