aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac
diff options
context:
space:
mode:
authorBorislav Petkov <bp@suse.de>2014-11-22 05:47:07 -0500
committerBorislav Petkov <bp@suse.de>2014-11-25 07:09:45 -0500
commit51756a5034c12da3ce1286749b0e05de8bfbbbaf (patch)
treef60f8cf4b3ec58e703c5b96985aba8a58de67748 /drivers/edac
parentb18f3864bfb4ef2af0e25b6ed5e1292f2ac36878 (diff)
EDAC, mce_amd_inj: Add an injector function
Selectively inject either a real MCE or a sw-only version which exercises the decoding path only. The hardware-injected MCE triggers a machine check exception (#MC) so that the MCE handler can be bothered to do something too. Signed-off-by: Borislav Petkov <bp@suse.de>
Diffstat (limited to 'drivers/edac')
-rw-r--r--drivers/edac/mce_amd_inj.c53
1 files changed, 51 insertions, 2 deletions
diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c
index 5a758d63a8cc..0bd91a802c67 100644
--- a/drivers/edac/mce_amd_inj.c
+++ b/drivers/edac/mce_amd_inj.c
@@ -14,6 +14,7 @@
14#include <linux/debugfs.h> 14#include <linux/debugfs.h>
15#include <linux/device.h> 15#include <linux/device.h>
16#include <linux/module.h> 16#include <linux/module.h>
17#include <linux/cpu.h>
17#include <asm/mce.h> 18#include <asm/mce.h>
18 19
19#include "mce_amd.h" 20#include "mce_amd.h"
@@ -116,6 +117,55 @@ static int inj_extcpu_set(void *data, u64 val)
116 117
117DEFINE_SIMPLE_ATTRIBUTE(extcpu_fops, inj_extcpu_get, inj_extcpu_set, "%llu\n"); 118DEFINE_SIMPLE_ATTRIBUTE(extcpu_fops, inj_extcpu_get, inj_extcpu_set, "%llu\n");
118 119
120static void trigger_mce(void *info)
121{
122 asm volatile("int $18");
123}
124
125static void do_inject(void)
126{
127 u64 mcg_status = 0;
128 unsigned int cpu = i_mce.extcpu;
129 u8 b = i_mce.bank;
130
131 if (!(i_mce.inject_flags & MCJ_EXCEPTION)) {
132 amd_decode_mce(NULL, 0, &i_mce);
133 return;
134 }
135
136 get_online_cpus();
137 if (!cpu_online(cpu))
138 goto err;
139
140 /* prep MCE global settings for the injection */
141 mcg_status = MCG_STATUS_MCIP | MCG_STATUS_EIPV;
142
143 if (!(i_mce.status & MCI_STATUS_PCC))
144 mcg_status |= MCG_STATUS_RIPV;
145
146 toggle_hw_mce_inject(cpu, true);
147
148 wrmsr_on_cpu(cpu, MSR_IA32_MCG_STATUS,
149 (u32)mcg_status, (u32)(mcg_status >> 32));
150
151 wrmsr_on_cpu(cpu, MSR_IA32_MCx_STATUS(b),
152 (u32)i_mce.status, (u32)(i_mce.status >> 32));
153
154 wrmsr_on_cpu(cpu, MSR_IA32_MCx_ADDR(b),
155 (u32)i_mce.addr, (u32)(i_mce.addr >> 32));
156
157 wrmsr_on_cpu(cpu, MSR_IA32_MCx_MISC(b),
158 (u32)i_mce.misc, (u32)(i_mce.misc >> 32));
159
160 toggle_hw_mce_inject(cpu, false);
161
162 smp_call_function_single(cpu, trigger_mce, NULL, 0);
163
164err:
165 put_online_cpus();
166
167}
168
119/* 169/*
120 * This denotes into which bank we're injecting and triggers 170 * This denotes into which bank we're injecting and triggers
121 * the injection, at the same time. 171 * the injection, at the same time.
@@ -132,8 +182,7 @@ static int inj_bank_set(void *data, u64 val)
132 } 182 }
133 183
134 m->bank = val; 184 m->bank = val;
135 185 do_inject();
136 amd_decode_mce(NULL, 0, m);
137 186
138 return 0; 187 return 0;
139} 188}