soc: Remove copyright notices
[coreboot.git] / src / soc / amd / picasso / mca.c
blob122c751e0b3f296e3fdba24d4f9bb7752d591a49
1 /*
2 * This file is part of the coreboot project.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <cpu/x86/msr.h>
16 #include <arch/acpi.h>
17 #include <soc/cpu.h>
18 #include <soc/northbridge.h>
19 #include <console/console.h>
20 #include <arch/bert_storage.h>
21 #include <cper.h>
23 struct mca_bank {
24 int bank;
25 msr_t ctl;
26 msr_t sts;
27 msr_t addr;
28 msr_t misc;
29 msr_t cmask;
32 static inline size_t mca_report_size_reqd(void)
34 size_t size;
36 size = sizeof(acpi_generic_error_status_t);
38 size += sizeof(acpi_hest_generic_data_v300_t);
39 size += sizeof(cper_proc_generic_error_section_t);
41 size += sizeof(acpi_hest_generic_data_v300_t);
42 size += sizeof(cper_ia32x64_proc_error_section_t);
44 /* Check Error */
45 size += cper_ia32x64_check_sz();
47 /* Context of MCG_CAP, MCG_STAT, MCG_CTL */
48 size += cper_ia32x64_ctx_sz_bytype(CPER_IA32X64_CTX_MSR, 3);
50 /* Context of MCi_CTL, MCi_STATUS, MCi_ADDR, MCi_MISC */
51 size += cper_ia32x64_ctx_sz_bytype(CPER_IA32X64_CTX_MSR, 4);
53 /* Context of CTL_MASK */
54 size += cper_ia32x64_ctx_sz_bytype(CPER_IA32X64_CTX_MSR, 1);
56 return size;
59 static enum cper_x86_check_type error_to_chktype(struct mca_bank *mci)
61 int error = mca_err_type(mci->sts);
63 if (error == MCA_ERRTYPE_BUS)
64 return X86_PROCESSOR_BUS_CHK;
65 if (error == MCA_ERRTYPE_INT)
66 return X86_PROCESSOR_MS_CHK;
67 if (error == MCA_ERRTYPE_MEM)
68 return X86_PROCESSOR_CACHE_CHK;
69 if (error == MCA_ERRTYPE_TLB)
70 return X86_PROCESSOR_TLB_CHK;
72 return X86_PROCESSOR_MS_CHK; /* unrecognized */
75 /* Fill additional information in the Generic Processor Error Section. */
76 static void fill_generic_section(cper_proc_generic_error_section_t *sec,
77 struct mca_bank *mci)
79 int type = mca_err_type(mci->sts);
81 if (type == MCA_ERRTYPE_BUS) /* try to map MCA errors to CPER types */
82 sec->error_type = GENPROC_ERRTYPE_BUS;
83 else if (type == MCA_ERRTYPE_INT)
84 sec->error_type = GENPROC_ERRTYPE_UARCH;
85 else if (type == MCA_ERRTYPE_MEM)
86 sec->error_type = GENPROC_ERRTYPE_CACHE;
87 else if (type == MCA_ERRTYPE_TLB)
88 sec->error_type = GENPROC_ERRTYPE_TLB;
89 else
90 sec->error_type = GENPROC_ERRTYPE_UNKNOWN;
91 sec->validation |= GENPROC_VALID_PROC_ERR_TYPE;
94 /* Convert an error reported by an MCA bank into BERT information to be reported
95 * by the OS. The ACPI driver doesn't recognize/parse the IA32/X64 structure,
96 * which is the best method to report MSR context. As a result, add two
97 * structures: A "processor generic error" that is parsed, and an IA32/X64 one
98 * to capture complete information.
100 static void build_bert_mca_error(struct mca_bank *mci)
102 acpi_generic_error_status_t *status;
103 acpi_hest_generic_data_v300_t *gen_entry;
104 acpi_hest_generic_data_v300_t *x86_entry;
105 cper_proc_generic_error_section_t *gen_sec;
106 cper_ia32x64_proc_error_section_t *x86_sec;
107 cper_ia32x64_proc_error_info_t *chk;
108 cper_ia32x64_context_t *ctx;
110 if (mca_report_size_reqd() > bert_storage_remaining())
111 goto failed;
113 status = bert_new_event(&CPER_SEC_PROC_GENERIC_GUID);
114 if (!status)
115 goto failed;
117 gen_entry = acpi_hest_generic_data3(status);
118 gen_sec = section_of_acpientry(gen_sec, gen_entry);
120 fill_generic_section(gen_sec, mci);
122 x86_entry = bert_append_ia32x64(status);
123 x86_sec = section_of_acpientry(x86_sec, x86_entry);
125 chk = new_cper_ia32x64_check(status, x86_sec, error_to_chktype(mci));
126 if (!chk)
127 goto failed;
129 ctx = cper_new_ia32x64_context_msr(status, x86_sec, IA32_MCG_CAP, 3);
130 if (!ctx)
131 goto failed;
132 ctx = cper_new_ia32x64_context_msr(status, x86_sec,
133 IA32_MC0_CTL + (mci->bank * 4), 4);
134 if (!ctx)
135 goto failed;
136 ctx = cper_new_ia32x64_context_msr(status, x86_sec,
137 MC0_CTL_MASK + mci->bank, 1);
138 if (!ctx)
139 goto failed;
141 return;
143 failed:
144 /* We're here because of a hardware error, don't break something else */
145 printk(BIOS_ERR, "Error: Not enough room in BERT region for Machine Check error\n");
148 static const char *const mca_bank_name[] = {
149 "Load-store unit",
150 "Instruction fetch unit",
151 "Combined unit",
152 "Reserved",
153 "Northbridge",
154 "Execution unit",
155 "Floating point unit"
158 /* Check the Legacy Machine Check Architecture registers */
159 void check_mca(void)
161 int i;
162 msr_t cap;
163 struct mca_bank mci;
164 int num_banks;
166 cap = rdmsr(IA32_MCG_CAP);
167 num_banks = cap.lo & MCA_BANKS_MASK;
169 if (is_warm_reset()) {
170 for (i = 0 ; i < num_banks ; i++) {
171 mci.sts = rdmsr(IA32_MC0_STATUS + (i * 4));
172 if (mci.sts.hi || mci.sts.lo) {
173 int core = cpuid_ebx(1) >> 24;
175 printk(BIOS_WARNING, "#MC Error: core %d, bank %d %s\n",
176 core, i, mca_bank_name[i]);
178 printk(BIOS_WARNING, " MC%d_STATUS = %08x_%08x\n",
179 i, mci.sts.hi, mci.sts.lo);
180 mci.addr = rdmsr(MC0_ADDR + (i * 4));
181 printk(BIOS_WARNING, " MC%d_ADDR = %08x_%08x\n",
182 i, mci.addr.hi, mci.addr.lo);
183 mci.misc = rdmsr(MC0_MISC + (i * 4));
184 printk(BIOS_WARNING, " MC%d_MISC = %08x_%08x\n",
185 i, mci.misc.hi, mci.misc.lo);
186 mci.ctl = rdmsr(IA32_MC0_CTL + (i * 4));
187 printk(BIOS_WARNING, " MC%d_CTL = %08x_%08x\n",
188 i, mci.ctl.hi, mci.ctl.lo);
189 mci.cmask = rdmsr(MC0_CTL_MASK + i);
190 printk(BIOS_WARNING, " MC%d_CTL_MASK = %08x_%08x\n",
191 i, mci.cmask.hi, mci.cmask.lo);
193 mci.bank = i;
194 if (CONFIG(ACPI_BERT)
195 && mca_valid(mci.sts))
196 build_bert_mca_error(&mci);
201 /* zero the machine check error status registers */
202 mci.sts.lo = 0;
203 mci.sts.hi = 0;
204 for (i = 0 ; i < num_banks ; i++)
205 wrmsr(IA32_MC0_STATUS + (i * 4), mci.sts);