blob: f976158071de1ddf3f581d773eede83190d823c3 [file] [log] [blame]
Felix Held2ecf1562021-07-14 00:30:53 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <amdblocks/mca.h>
4#include <amdblocks/msr_zen.h>
5#include <cpu/x86/msr.h>
6#include <acpi/acpi.h>
7#include <console/console.h>
8#include <arch/bert_storage.h>
9#include <cper.h>
10#include <types.h>
11
12/* MISC4 is the last used register in the MCAX banks of Picasso */
13#define MCAX_USED_REGISTERS_PER_BANK (MCAX_MISC4_OFFSET + 1)
14
15static inline size_t mca_report_size_reqd(void)
16{
17 size_t size;
18
19 size = sizeof(acpi_generic_error_status_t);
20
21 size += sizeof(acpi_hest_generic_data_v300_t);
22 size += sizeof(cper_proc_generic_error_section_t);
23
24 size += sizeof(acpi_hest_generic_data_v300_t);
25 size += sizeof(cper_ia32x64_proc_error_section_t);
26
27 /* Check Error */
28 size += cper_ia32x64_check_sz();
29
30 /* Context of MCG_CAP, MCG_STAT, MCG_CTL */
31 size += cper_ia32x64_ctx_sz_bytype(CPER_IA32X64_CTX_MSR, 3);
32
33 /* Context of CTL, STATUS, ADDR, MISC0, CONFIG, IPID, SYND, RESERVED, DESTAT, DEADDR,
34 MISC1, MISC2, MISC3, MISC4 */
35 size += cper_ia32x64_ctx_sz_bytype(CPER_IA32X64_CTX_MSR, MCAX_USED_REGISTERS_PER_BANK);
36
37 /* Context of CTL_MASK */
38 size += cper_ia32x64_ctx_sz_bytype(CPER_IA32X64_CTX_MSR, 1);
39
40 return size;
41}
42
43static enum cper_x86_check_type error_to_chktype(struct mca_bank_status *mci)
44{
45 int error = mca_err_type(mci->sts);
46
47 if (error == MCA_ERRTYPE_BUS)
48 return X86_PROCESSOR_BUS_CHK;
49 if (error == MCA_ERRTYPE_INT)
50 return X86_PROCESSOR_MS_CHK;
51 if (error == MCA_ERRTYPE_MEM)
52 return X86_PROCESSOR_CACHE_CHK;
53 if (error == MCA_ERRTYPE_TLB)
54 return X86_PROCESSOR_TLB_CHK;
55
56 return X86_PROCESSOR_MS_CHK; /* unrecognized */
57}
58
59/* Fill additional information in the Generic Processor Error Section. */
60static void fill_generic_section(cper_proc_generic_error_section_t *sec,
61 struct mca_bank_status *mci)
62{
63 int type = mca_err_type(mci->sts);
64
65 if (type == MCA_ERRTYPE_BUS) /* try to map MCA errors to CPER types */
66 sec->error_type = GENPROC_ERRTYPE_BUS;
67 else if (type == MCA_ERRTYPE_INT)
68 sec->error_type = GENPROC_ERRTYPE_UARCH;
69 else if (type == MCA_ERRTYPE_MEM)
70 sec->error_type = GENPROC_ERRTYPE_CACHE;
71 else if (type == MCA_ERRTYPE_TLB)
72 sec->error_type = GENPROC_ERRTYPE_TLB;
73 else
74 sec->error_type = GENPROC_ERRTYPE_UNKNOWN;
75 sec->validation |= GENPROC_VALID_PROC_ERR_TYPE;
76}
77
78/* Convert an error reported by an MCA bank into BERT information to be reported
79 * by the OS. The ACPI driver doesn't recognize/parse the IA32/X64 structure,
80 * which is the best method to report MSR context. As a result, add two
81 * structures: A "processor generic error" that is parsed, and an IA32/X64 one
82 * to capture complete information.
83 */
84void build_bert_mca_error(struct mca_bank_status *mci)
85{
86 acpi_generic_error_status_t *status;
87 acpi_hest_generic_data_v300_t *gen_entry;
88 acpi_hest_generic_data_v300_t *x86_entry;
89 cper_proc_generic_error_section_t *gen_sec;
90 cper_ia32x64_proc_error_section_t *x86_sec;
91 cper_ia32x64_proc_error_info_t *chk;
92 cper_ia32x64_context_t *ctx;
93
94 if (mca_report_size_reqd() > bert_storage_remaining())
95 goto failed;
96
97 status = bert_new_event(&CPER_SEC_PROC_GENERIC_GUID);
98 if (!status)
99 goto failed;
100
101 gen_entry = acpi_hest_generic_data3(status);
102 gen_sec = section_of_acpientry(gen_sec, gen_entry);
103
104 fill_generic_section(gen_sec, mci);
105
106 x86_entry = bert_append_ia32x64(status);
107 x86_sec = section_of_acpientry(x86_sec, x86_entry);
108
109 chk = new_cper_ia32x64_check(status, x86_sec, error_to_chktype(mci));
110 if (!chk)
111 goto failed;
112
113 ctx = cper_new_ia32x64_context_msr(status, x86_sec, IA32_MCG_CAP, 3);
114 if (!ctx)
115 goto failed;
116 ctx = cper_new_ia32x64_context_msr(status, x86_sec, MCAX_CTL_MSR(mci->bank),
117 MCAX_USED_REGISTERS_PER_BANK);
118 if (!ctx)
119 goto failed;
120 ctx = cper_new_ia32x64_context_msr(status, x86_sec, MCA_CTL_MASK_MSR(mci->bank), 1);
121 if (!ctx)
122 goto failed;
123
124 return;
125
126failed:
127 /* We're here because of a hardware error, don't break something else */
128 printk(BIOS_ERR, "Error: Not enough room in BERT region for Machine Check error\n");
129}