aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/ras/Kconfig4
-rw-r--r--arch/x86/ras/mce_amd_inj.c52
2 files changed, 53 insertions, 3 deletions
diff --git a/arch/x86/ras/Kconfig b/arch/x86/ras/Kconfig
index 10fea5fc821e..df280da34825 100644
--- a/arch/x86/ras/Kconfig
+++ b/arch/x86/ras/Kconfig
@@ -1,11 +1,9 @@
1config AMD_MCE_INJ 1config AMD_MCE_INJ
2 tristate "Simple MCE injection interface for AMD processors" 2 tristate "Simple MCE injection interface for AMD processors"
3 depends on RAS && EDAC_DECODE_MCE && DEBUG_FS 3 depends on RAS && EDAC_DECODE_MCE && DEBUG_FS && AMD_NB
4 default n 4 default n
5 help 5 help
6 This is a simple debugfs interface to inject MCEs and test different 6 This is a simple debugfs interface to inject MCEs and test different
7 aspects of the MCE handling code. 7 aspects of the MCE handling code.
8 8
9 WARNING: Do not even assume this interface is staying stable! 9 WARNING: Do not even assume this interface is staying stable!
10
11
diff --git a/arch/x86/ras/mce_amd_inj.c b/arch/x86/ras/mce_amd_inj.c
index 4d3bafb540c2..55d38cfa46c2 100644
--- a/arch/x86/ras/mce_amd_inj.c
+++ b/arch/x86/ras/mce_amd_inj.c
@@ -17,8 +17,10 @@
17#include <linux/cpu.h> 17#include <linux/cpu.h>
18#include <linux/string.h> 18#include <linux/string.h>
19#include <linux/uaccess.h> 19#include <linux/uaccess.h>
20#include <linux/pci.h>
20 21
21#include <asm/mce.h> 22#include <asm/mce.h>
23#include <asm/amd_nb.h>
22#include <asm/irq_vectors.h> 24#include <asm/irq_vectors.h>
23 25
24#include "../kernel/cpu/mcheck/mce-internal.h" 26#include "../kernel/cpu/mcheck/mce-internal.h"
@@ -32,6 +34,7 @@ static struct dentry *dfs_inj;
32static u8 n_banks; 34static u8 n_banks;
33 35
34#define MAX_FLAG_OPT_SIZE 3 36#define MAX_FLAG_OPT_SIZE 3
37#define NBCFG 0x44
35 38
36enum injection_type { 39enum injection_type {
37 SW_INJ = 0, /* SW injection, simply decode the error */ 40 SW_INJ = 0, /* SW injection, simply decode the error */
@@ -198,6 +201,45 @@ static void trigger_thr_int(void *info)
198 asm volatile("int %0" :: "i" (THRESHOLD_APIC_VECTOR)); 201 asm volatile("int %0" :: "i" (THRESHOLD_APIC_VECTOR));
199} 202}
200 203
204static u32 get_nbc_for_node(int node_id)
205{
206 struct cpuinfo_x86 *c = &boot_cpu_data;
207 u32 cores_per_node;
208
209 cores_per_node = c->x86_max_cores / amd_get_nodes_per_socket();
210
211 return cores_per_node * node_id;
212}
213
214static void toggle_nb_mca_mst_cpu(u16 nid)
215{
216 struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
217 u32 val;
218 int err;
219
220 if (!F3)
221 return;
222
223 err = pci_read_config_dword(F3, NBCFG, &val);
224 if (err) {
225 pr_err("%s: Error reading F%dx%03x.\n",
226 __func__, PCI_FUNC(F3->devfn), NBCFG);
227 return;
228 }
229
230 if (val & BIT(27))
231 return;
232
233 pr_err("%s: Set D18F3x44[NbMcaToMstCpuEn] which BIOS hasn't done.\n",
234 __func__);
235
236 val |= BIT(27);
237 err = pci_write_config_dword(F3, NBCFG, val);
238 if (err)
239 pr_err("%s: Error writing F%dx%03x.\n",
240 __func__, PCI_FUNC(F3->devfn), NBCFG);
241}
242
201static void do_inject(void) 243static void do_inject(void)
202{ 244{
203 u64 mcg_status = 0; 245 u64 mcg_status = 0;
@@ -228,6 +270,16 @@ static void do_inject(void)
228 i_mce.status |= (i_mce.status & ~MCI_STATUS_UC); 270 i_mce.status |= (i_mce.status & ~MCI_STATUS_UC);
229 } 271 }
230 272
273 /*
274 * For multi node CPUs, logging and reporting of bank 4 errors happens
275 * only on the node base core. Refer to D18F3x44[NbMcaToMstCpuEn] for
276 * Fam10h and later BKDGs.
277 */
278 if (static_cpu_has(X86_FEATURE_AMD_DCM) && b == 4) {
279 toggle_nb_mca_mst_cpu(amd_get_nb_id(cpu));
280 cpu = get_nbc_for_node(amd_get_nb_id(cpu));
281 }
282
231 get_online_cpus(); 283 get_online_cpus();
232 if (!cpu_online(cpu)) 284 if (!cpu_online(cpu))
233 goto err; 285 goto err;