aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiu, Jinsong <jinsong.liu@intel.com>2012-06-07 07:56:51 -0400
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2012-07-19 15:51:36 -0400
commitcef12ee52b054282461a6d5fe7742755fa6e3bd3 (patch)
tree01f7c85832beaee257e99c8fb57cf8294774afb6
parent485802a6c524e62b5924849dd727ddbb1497cc71 (diff)
xen/mce: Add mcelog support for Xen platform
When MCA error occurs, it would be handled by Xen hypervisor first, and then the error information would be sent to initial domain for logging. This patch gets error information from Xen hypervisor and convert Xen format error into Linux format mcelog. This logic is basically self-contained, not touching other kernel components. By using tools like mcelog tool users could read specific error information, like what they did under native Linux. To test follow directions outlined in Documentation/acpi/apei/einj.txt Acked-and-tested-by: Borislav Petkov <borislav.petkov@amd.com> Signed-off-by: Ke, Liping <liping.ke@intel.com> Signed-off-by: Jiang, Yunhong <yunhong.jiang@intel.com> Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> Signed-off-by: Liu, Jinsong <jinsong.liu@intel.com> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
-rw-r--r--arch/x86/include/asm/xen/hypercall.h8
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c4
-rw-r--r--arch/x86/xen/enlighten.c5
-rw-r--r--drivers/xen/Kconfig8
-rw-r--r--drivers/xen/Makefile1
-rw-r--r--drivers/xen/mcelog.c392
-rw-r--r--include/linux/miscdevice.h1
-rw-r--r--include/xen/interface/xen-mca.h385
8 files changed, 798 insertions, 6 deletions
diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h
index 5728852fb90f..59c226d120cd 100644
--- a/arch/x86/include/asm/xen/hypercall.h
+++ b/arch/x86/include/asm/xen/hypercall.h
@@ -48,6 +48,7 @@
48#include <xen/interface/sched.h> 48#include <xen/interface/sched.h>
49#include <xen/interface/physdev.h> 49#include <xen/interface/physdev.h>
50#include <xen/interface/platform.h> 50#include <xen/interface/platform.h>
51#include <xen/interface/xen-mca.h>
51 52
52/* 53/*
53 * The hypercall asms have to meet several constraints: 54 * The hypercall asms have to meet several constraints:
@@ -302,6 +303,13 @@ HYPERVISOR_set_timer_op(u64 timeout)
302} 303}
303 304
304static inline int 305static inline int
306HYPERVISOR_mca(struct xen_mc *mc_op)
307{
308 mc_op->interface_version = XEN_MCA_INTERFACE_VERSION;
309 return _hypercall1(int, mca, mc_op);
310}
311
312static inline int
305HYPERVISOR_dom0_op(struct xen_platform_op *platform_op) 313HYPERVISOR_dom0_op(struct xen_platform_op *platform_op)
306{ 314{
307 platform_op->interface_version = XENPF_INTERFACE_VERSION; 315 platform_op->interface_version = XENPF_INTERFACE_VERSION;
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index da27c5d2168a..aa7548799af4 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -57,8 +57,6 @@ static DEFINE_MUTEX(mce_chrdev_read_mutex);
57 57
58int mce_disabled __read_mostly; 58int mce_disabled __read_mostly;
59 59
60#define MISC_MCELOG_MINOR 227
61
62#define SPINUNIT 100 /* 100ns */ 60#define SPINUNIT 100 /* 100ns */
63 61
64atomic_t mce_entry; 62atomic_t mce_entry;
@@ -2342,7 +2340,7 @@ static __init int mcheck_init_device(void)
2342 2340
2343 return err; 2341 return err;
2344} 2342}
2345device_initcall(mcheck_init_device); 2343device_initcall_sync(mcheck_init_device);
2346 2344
2347/* 2345/*
2348 * Old style boot options parsing. Only for compatibility. 2346 * Old style boot options parsing. Only for compatibility.
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index ff962d4b821e..9a6346865c49 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -38,6 +38,7 @@
38#include <xen/interface/physdev.h> 38#include <xen/interface/physdev.h>
39#include <xen/interface/vcpu.h> 39#include <xen/interface/vcpu.h>
40#include <xen/interface/memory.h> 40#include <xen/interface/memory.h>
41#include <xen/interface/xen-mca.h>
41#include <xen/features.h> 42#include <xen/features.h>
42#include <xen/page.h> 43#include <xen/page.h>
43#include <xen/hvm.h> 44#include <xen/hvm.h>
@@ -341,9 +342,7 @@ static void __init xen_init_cpuid_mask(void)
341 unsigned int xsave_mask; 342 unsigned int xsave_mask;
342 343
343 cpuid_leaf1_edx_mask = 344 cpuid_leaf1_edx_mask =
344 ~((1 << X86_FEATURE_MCE) | /* disable MCE */ 345 ~((1 << X86_FEATURE_MTRR) | /* disable MTRR */
345 (1 << X86_FEATURE_MCA) | /* disable MCA */
346 (1 << X86_FEATURE_MTRR) | /* disable MTRR */
347 (1 << X86_FEATURE_ACC)); /* thermal monitoring */ 346 (1 << X86_FEATURE_ACC)); /* thermal monitoring */
348 347
349 if (!xen_initial_domain()) 348 if (!xen_initial_domain())
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 8d2501e604dd..d4dffcd52873 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -196,4 +196,12 @@ config XEN_ACPI_PROCESSOR
196 called xen_acpi_processor If you do not know what to choose, select 196 called xen_acpi_processor If you do not know what to choose, select
197 M here. If the CPUFREQ drivers are built in, select Y here. 197 M here. If the CPUFREQ drivers are built in, select Y here.
198 198
199config XEN_MCE_LOG
200 bool "Xen platform mcelog"
201 depends on XEN_DOM0 && X86_64 && X86_MCE
202 default n
203 help
204 Allow kernel fetching MCE error from Xen platform and
205 converting it into Linux mcelog format for mcelog tools
206
199endmenu 207endmenu
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index fc3488631136..a7870292bc75 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_XEN_PVHVM) += platform-pci.o
18obj-$(CONFIG_XEN_TMEM) += tmem.o 18obj-$(CONFIG_XEN_TMEM) += tmem.o
19obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o 19obj-$(CONFIG_SWIOTLB_XEN) += swiotlb-xen.o
20obj-$(CONFIG_XEN_DOM0) += pci.o acpi.o 20obj-$(CONFIG_XEN_DOM0) += pci.o acpi.o
21obj-$(CONFIG_XEN_MCE_LOG) += mcelog.o
21obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback/ 22obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback/
22obj-$(CONFIG_XEN_PRIVCMD) += xen-privcmd.o 23obj-$(CONFIG_XEN_PRIVCMD) += xen-privcmd.o
23obj-$(CONFIG_XEN_ACPI_PROCESSOR) += xen-acpi-processor.o 24obj-$(CONFIG_XEN_ACPI_PROCESSOR) += xen-acpi-processor.o
diff --git a/drivers/xen/mcelog.c b/drivers/xen/mcelog.c
new file mode 100644
index 000000000000..72e87d2f1929
--- /dev/null
+++ b/drivers/xen/mcelog.c
@@ -0,0 +1,392 @@
1/******************************************************************************
2 * mcelog.c
3 * Driver for receiving and transferring machine check error infomation
4 *
5 * Copyright (c) 2012 Intel Corporation
6 * Author: Liu, Jinsong <jinsong.liu@intel.com>
7 * Author: Jiang, Yunhong <yunhong.jiang@intel.com>
8 * Author: Ke, Liping <liping.ke@intel.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation; or, when distributed
13 * separately from the Linux kernel or incorporated into other
14 * software packages, subject to the following license:
15 *
16 * Permission is hereby granted, free of charge, to any person obtaining a copy
17 * of this source file (the "Software"), to deal in the Software without
18 * restriction, including without limitation the rights to use, copy, modify,
19 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
20 * and to permit persons to whom the Software is furnished to do so, subject to
21 * the following conditions:
22 *
23 * The above copyright notice and this permission notice shall be included in
24 * all copies or substantial portions of the Software.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
31 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
32 * IN THE SOFTWARE.
33 */
34
35#include <linux/init.h>
36#include <linux/types.h>
37#include <linux/kernel.h>
38#include <linux/slab.h>
39#include <linux/fs.h>
40#include <linux/device.h>
41#include <linux/miscdevice.h>
42#include <linux/uaccess.h>
43#include <linux/capability.h>
44
45#include <xen/interface/xen.h>
46#include <xen/events.h>
47#include <xen/interface/vcpu.h>
48#include <xen/xen.h>
49#include <asm/xen/hypercall.h>
50#include <asm/xen/hypervisor.h>
51
52#define XEN_MCELOG "xen_mcelog: "
53
54static struct mc_info g_mi;
55static struct mcinfo_logical_cpu *g_physinfo;
56static uint32_t ncpus;
57
58static DEFINE_SPINLOCK(mcelog_lock);
59
60static struct xen_mce_log xen_mcelog = {
61 .signature = XEN_MCE_LOG_SIGNATURE,
62 .len = XEN_MCE_LOG_LEN,
63 .recordlen = sizeof(struct xen_mce),
64};
65
66static DEFINE_SPINLOCK(xen_mce_chrdev_state_lock);
67static int xen_mce_chrdev_open_count; /* #times opened */
68static int xen_mce_chrdev_open_exclu; /* already open exclusive? */
69
70static int xen_mce_chrdev_open(struct inode *inode, struct file *file)
71{
72 spin_lock(&xen_mce_chrdev_state_lock);
73
74 if (xen_mce_chrdev_open_exclu ||
75 (xen_mce_chrdev_open_count && (file->f_flags & O_EXCL))) {
76 spin_unlock(&xen_mce_chrdev_state_lock);
77
78 return -EBUSY;
79 }
80
81 if (file->f_flags & O_EXCL)
82 xen_mce_chrdev_open_exclu = 1;
83 xen_mce_chrdev_open_count++;
84
85 spin_unlock(&xen_mce_chrdev_state_lock);
86
87 return nonseekable_open(inode, file);
88}
89
90static int xen_mce_chrdev_release(struct inode *inode, struct file *file)
91{
92 spin_lock(&xen_mce_chrdev_state_lock);
93
94 xen_mce_chrdev_open_count--;
95 xen_mce_chrdev_open_exclu = 0;
96
97 spin_unlock(&xen_mce_chrdev_state_lock);
98
99 return 0;
100}
101
102static ssize_t xen_mce_chrdev_read(struct file *filp, char __user *ubuf,
103 size_t usize, loff_t *off)
104{
105 char __user *buf = ubuf;
106 unsigned num;
107 int i, err;
108
109 spin_lock(&mcelog_lock);
110
111 num = xen_mcelog.next;
112
113 /* Only supports full reads right now */
114 err = -EINVAL;
115 if (*off != 0 || usize < XEN_MCE_LOG_LEN*sizeof(struct xen_mce))
116 goto out;
117
118 err = 0;
119 for (i = 0; i < num; i++) {
120 struct xen_mce *m = &xen_mcelog.entry[i];
121
122 err |= copy_to_user(buf, m, sizeof(*m));
123 buf += sizeof(*m);
124 }
125
126 memset(xen_mcelog.entry, 0, num * sizeof(struct xen_mce));
127 xen_mcelog.next = 0;
128
129 if (err)
130 err = -EFAULT;
131
132out:
133 spin_unlock(&mcelog_lock);
134
135 return err ? err : buf - ubuf;
136}
137
138static long xen_mce_chrdev_ioctl(struct file *f, unsigned int cmd,
139 unsigned long arg)
140{
141 int __user *p = (int __user *)arg;
142
143 if (!capable(CAP_SYS_ADMIN))
144 return -EPERM;
145
146 switch (cmd) {
147 case MCE_GET_RECORD_LEN:
148 return put_user(sizeof(struct xen_mce), p);
149 case MCE_GET_LOG_LEN:
150 return put_user(XEN_MCE_LOG_LEN, p);
151 case MCE_GETCLEAR_FLAGS: {
152 unsigned flags;
153
154 do {
155 flags = xen_mcelog.flags;
156 } while (cmpxchg(&xen_mcelog.flags, flags, 0) != flags);
157
158 return put_user(flags, p);
159 }
160 default:
161 return -ENOTTY;
162 }
163}
164
165static const struct file_operations xen_mce_chrdev_ops = {
166 .open = xen_mce_chrdev_open,
167 .release = xen_mce_chrdev_release,
168 .read = xen_mce_chrdev_read,
169 .unlocked_ioctl = xen_mce_chrdev_ioctl,
170 .llseek = no_llseek,
171};
172
173static struct miscdevice xen_mce_chrdev_device = {
174 MISC_MCELOG_MINOR,
175 "mcelog",
176 &xen_mce_chrdev_ops,
177};
178
179/*
180 * Caller should hold the mcelog_lock
181 */
182static void xen_mce_log(struct xen_mce *mce)
183{
184 unsigned entry;
185
186 entry = xen_mcelog.next;
187
188 /*
189 * When the buffer fills up discard new entries.
190 * Assume that the earlier errors are the more
191 * interesting ones:
192 */
193 if (entry >= XEN_MCE_LOG_LEN) {
194 set_bit(XEN_MCE_OVERFLOW,
195 (unsigned long *)&xen_mcelog.flags);
196 return;
197 }
198
199 memcpy(xen_mcelog.entry + entry, mce, sizeof(struct xen_mce));
200
201 xen_mcelog.next++;
202}
203
204static int convert_log(struct mc_info *mi)
205{
206 struct mcinfo_common *mic;
207 struct mcinfo_global *mc_global;
208 struct mcinfo_bank *mc_bank;
209 struct xen_mce m;
210 uint32_t i;
211
212 mic = NULL;
213 x86_mcinfo_lookup(&mic, mi, MC_TYPE_GLOBAL);
214 if (unlikely(!mic)) {
215 pr_warning(XEN_MCELOG "Failed to find global error info\n");
216 return -ENODEV;
217 }
218
219 memset(&m, 0, sizeof(struct xen_mce));
220
221 mc_global = (struct mcinfo_global *)mic;
222 m.mcgstatus = mc_global->mc_gstatus;
223 m.apicid = mc_global->mc_apicid;
224
225 for (i = 0; i < ncpus; i++)
226 if (g_physinfo[i].mc_apicid == m.apicid)
227 break;
228 if (unlikely(i == ncpus)) {
229 pr_warning(XEN_MCELOG "Failed to match cpu with apicid %d\n",
230 m.apicid);
231 return -ENODEV;
232 }
233
234 m.socketid = g_physinfo[i].mc_chipid;
235 m.cpu = m.extcpu = g_physinfo[i].mc_cpunr;
236 m.cpuvendor = (__u8)g_physinfo[i].mc_vendor;
237 m.mcgcap = g_physinfo[i].mc_msrvalues[__MC_MSR_MCGCAP].value;
238
239 mic = NULL;
240 x86_mcinfo_lookup(&mic, mi, MC_TYPE_BANK);
241 if (unlikely(!mic)) {
242 pr_warning(XEN_MCELOG "Fail to find bank error info\n");
243 return -ENODEV;
244 }
245
246 do {
247 if ((!mic) || (mic->size == 0) ||
248 (mic->type != MC_TYPE_GLOBAL &&
249 mic->type != MC_TYPE_BANK &&
250 mic->type != MC_TYPE_EXTENDED &&
251 mic->type != MC_TYPE_RECOVERY))
252 break;
253
254 if (mic->type == MC_TYPE_BANK) {
255 mc_bank = (struct mcinfo_bank *)mic;
256 m.misc = mc_bank->mc_misc;
257 m.status = mc_bank->mc_status;
258 m.addr = mc_bank->mc_addr;
259 m.tsc = mc_bank->mc_tsc;
260 m.bank = mc_bank->mc_bank;
261 m.finished = 1;
262 /*log this record*/
263 xen_mce_log(&m);
264 }
265 mic = x86_mcinfo_next(mic);
266 } while (1);
267
268 return 0;
269}
270
271static int mc_queue_handle(uint32_t flags)
272{
273 struct xen_mc mc_op;
274 int ret = 0;
275
276 mc_op.cmd = XEN_MC_fetch;
277 mc_op.interface_version = XEN_MCA_INTERFACE_VERSION;
278 set_xen_guest_handle(mc_op.u.mc_fetch.data, &g_mi);
279 do {
280 mc_op.u.mc_fetch.flags = flags;
281 ret = HYPERVISOR_mca(&mc_op);
282 if (ret) {
283 pr_err(XEN_MCELOG "Failed to fetch %s error log\n",
284 (flags == XEN_MC_URGENT) ?
285 "urgnet" : "nonurgent");
286 break;
287 }
288
289 if (mc_op.u.mc_fetch.flags & XEN_MC_NODATA ||
290 mc_op.u.mc_fetch.flags & XEN_MC_FETCHFAILED)
291 break;
292 else {
293 ret = convert_log(&g_mi);
294 if (ret)
295 pr_warning(XEN_MCELOG
296 "Failed to convert this error log, "
297 "continue acking it anyway\n");
298
299 mc_op.u.mc_fetch.flags = flags | XEN_MC_ACK;
300 ret = HYPERVISOR_mca(&mc_op);
301 if (ret) {
302 pr_err(XEN_MCELOG
303 "Failed to ack previous error log\n");
304 break;
305 }
306 }
307 } while (1);
308
309 return ret;
310}
311
312/* virq handler for machine check error info*/
313static irqreturn_t xen_mce_interrupt(int irq, void *dev_id)
314{
315 int err;
316 unsigned long tmp;
317
318 spin_lock_irqsave(&mcelog_lock, tmp);
319
320 /* urgent mc_info */
321 err = mc_queue_handle(XEN_MC_URGENT);
322 if (err)
323 pr_err(XEN_MCELOG
324 "Failed to handle urgent mc_info queue, "
325 "continue handling nonurgent mc_info queue anyway.\n");
326
327 /* nonurgent mc_info */
328 err = mc_queue_handle(XEN_MC_NONURGENT);
329 if (err)
330 pr_err(XEN_MCELOG
331 "Failed to handle nonurgent mc_info queue.\n");
332
333 spin_unlock_irqrestore(&mcelog_lock, tmp);
334
335 return IRQ_HANDLED;
336}
337
338static int bind_virq_for_mce(void)
339{
340 int ret;
341 struct xen_mc mc_op;
342
343 memset(&mc_op, 0, sizeof(struct xen_mc));
344
345 /* Fetch physical CPU Numbers */
346 mc_op.cmd = XEN_MC_physcpuinfo;
347 mc_op.interface_version = XEN_MCA_INTERFACE_VERSION;
348 set_xen_guest_handle(mc_op.u.mc_physcpuinfo.info, g_physinfo);
349 ret = HYPERVISOR_mca(&mc_op);
350 if (ret) {
351 pr_err(XEN_MCELOG "Failed to get CPU numbers\n");
352 return ret;
353 }
354
355 /* Fetch each CPU Physical Info for later reference*/
356 ncpus = mc_op.u.mc_physcpuinfo.ncpus;
357 g_physinfo = kcalloc(ncpus, sizeof(struct mcinfo_logical_cpu),
358 GFP_KERNEL);
359 if (!g_physinfo)
360 return -ENOMEM;
361 set_xen_guest_handle(mc_op.u.mc_physcpuinfo.info, g_physinfo);
362 ret = HYPERVISOR_mca(&mc_op);
363 if (ret) {
364 pr_err(XEN_MCELOG "Failed to get CPU info\n");
365 kfree(g_physinfo);
366 return ret;
367 }
368
369 ret = bind_virq_to_irqhandler(VIRQ_MCA, 0,
370 xen_mce_interrupt, 0, "mce", NULL);
371 if (ret < 0) {
372 pr_err(XEN_MCELOG "Failed to bind virq\n");
373 kfree(g_physinfo);
374 return ret;
375 }
376
377 return 0;
378}
379
380static int __init xen_late_init_mcelog(void)
381{
382 /* Only DOM0 is responsible for MCE logging */
383 if (xen_initial_domain()) {
384 /* register character device /dev/mcelog for xen mcelog */
385 if (misc_register(&xen_mce_chrdev_device))
386 return -ENODEV;
387 return bind_virq_for_mce();
388 }
389
390 return -ENODEV;
391}
392device_initcall(xen_late_init_mcelog);
diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h
index 0549d2115507..e0deeb2cc939 100644
--- a/include/linux/miscdevice.h
+++ b/include/linux/miscdevice.h
@@ -35,6 +35,7 @@
35#define MPT_MINOR 220 35#define MPT_MINOR 220
36#define MPT2SAS_MINOR 221 36#define MPT2SAS_MINOR 221
37#define UINPUT_MINOR 223 37#define UINPUT_MINOR 223
38#define MISC_MCELOG_MINOR 227
38#define HPET_MINOR 228 39#define HPET_MINOR 228
39#define FUSE_MINOR 229 40#define FUSE_MINOR 229
40#define KVM_MINOR 232 41#define KVM_MINOR 232
diff --git a/include/xen/interface/xen-mca.h b/include/xen/interface/xen-mca.h
new file mode 100644
index 000000000000..73a4ea714d93
--- /dev/null
+++ b/include/xen/interface/xen-mca.h
@@ -0,0 +1,385 @@
1/******************************************************************************
2 * arch-x86/mca.h
3 * Guest OS machine check interface to x86 Xen.
4 *
5 * Contributed by Advanced Micro Devices, Inc.
6 * Author: Christoph Egger <Christoph.Egger@amd.com>
7 *
8 * Updated by Intel Corporation
9 * Author: Liu, Jinsong <jinsong.liu@intel.com>
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to
13 * deal in the Software without restriction, including without limitation the
14 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
15 * sell copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 */
29
30#ifndef __XEN_PUBLIC_ARCH_X86_MCA_H__
31#define __XEN_PUBLIC_ARCH_X86_MCA_H__
32
33/* Hypercall */
34#define __HYPERVISOR_mca __HYPERVISOR_arch_0
35
36#define XEN_MCA_INTERFACE_VERSION 0x01ecc003
37
38/* IN: Dom0 calls hypercall to retrieve nonurgent error log entry */
39#define XEN_MC_NONURGENT 0x1
40/* IN: Dom0 calls hypercall to retrieve urgent error log entry */
41#define XEN_MC_URGENT 0x2
42/* IN: Dom0 acknowledges previosly-fetched error log entry */
43#define XEN_MC_ACK 0x4
44
45/* OUT: All is ok */
46#define XEN_MC_OK 0x0
47/* OUT: Domain could not fetch data. */
48#define XEN_MC_FETCHFAILED 0x1
49/* OUT: There was no machine check data to fetch. */
50#define XEN_MC_NODATA 0x2
51
52#ifndef __ASSEMBLY__
53/* vIRQ injected to Dom0 */
54#define VIRQ_MCA VIRQ_ARCH_0
55
56/*
57 * mc_info entry types
58 * mca machine check info are recorded in mc_info entries.
59 * when fetch mca info, it can use MC_TYPE_... to distinguish
60 * different mca info.
61 */
62#define MC_TYPE_GLOBAL 0
63#define MC_TYPE_BANK 1
64#define MC_TYPE_EXTENDED 2
65#define MC_TYPE_RECOVERY 3
66
67struct mcinfo_common {
68 uint16_t type; /* structure type */
69 uint16_t size; /* size of this struct in bytes */
70};
71
72#define MC_FLAG_CORRECTABLE (1 << 0)
73#define MC_FLAG_UNCORRECTABLE (1 << 1)
74#define MC_FLAG_RECOVERABLE (1 << 2)
75#define MC_FLAG_POLLED (1 << 3)
76#define MC_FLAG_RESET (1 << 4)
77#define MC_FLAG_CMCI (1 << 5)
78#define MC_FLAG_MCE (1 << 6)
79
80/* contains x86 global mc information */
81struct mcinfo_global {
82 struct mcinfo_common common;
83
84 uint16_t mc_domid; /* running domain at the time in error */
85 uint16_t mc_vcpuid; /* virtual cpu scheduled for mc_domid */
86 uint32_t mc_socketid; /* physical socket of the physical core */
87 uint16_t mc_coreid; /* physical impacted core */
88 uint16_t mc_core_threadid; /* core thread of physical core */
89 uint32_t mc_apicid;
90 uint32_t mc_flags;
91 uint64_t mc_gstatus; /* global status */
92};
93
94/* contains x86 bank mc information */
95struct mcinfo_bank {
96 struct mcinfo_common common;
97
98 uint16_t mc_bank; /* bank nr */
99 uint16_t mc_domid; /* domain referenced by mc_addr if valid */
100 uint64_t mc_status; /* bank status */
101 uint64_t mc_addr; /* bank address */
102 uint64_t mc_misc;
103 uint64_t mc_ctrl2;
104 uint64_t mc_tsc;
105};
106
107struct mcinfo_msr {
108 uint64_t reg; /* MSR */
109 uint64_t value; /* MSR value */
110};
111
112/* contains mc information from other or additional mc MSRs */
113struct mcinfo_extended {
114 struct mcinfo_common common;
115 uint32_t mc_msrs; /* Number of msr with valid values. */
116 /*
117 * Currently Intel extended MSR (32/64) include all gp registers
118 * and E(R)FLAGS, E(R)IP, E(R)MISC, up to 11/19 of them might be
119 * useful at present. So expand this array to 16/32 to leave room.
120 */
121 struct mcinfo_msr mc_msr[sizeof(void *) * 4];
122};
123
124/* Recovery Action flags. Giving recovery result information to DOM0 */
125
126/* Xen takes successful recovery action, the error is recovered */
127#define REC_ACTION_RECOVERED (0x1 << 0)
128/* No action is performed by XEN */
129#define REC_ACTION_NONE (0x1 << 1)
130/* It's possible DOM0 might take action ownership in some case */
131#define REC_ACTION_NEED_RESET (0x1 << 2)
132
133/*
134 * Different Recovery Action types, if the action is performed successfully,
135 * REC_ACTION_RECOVERED flag will be returned.
136 */
137
138/* Page Offline Action */
139#define MC_ACTION_PAGE_OFFLINE (0x1 << 0)
140/* CPU offline Action */
141#define MC_ACTION_CPU_OFFLINE (0x1 << 1)
142/* L3 cache disable Action */
143#define MC_ACTION_CACHE_SHRINK (0x1 << 2)
144
145/*
146 * Below interface used between XEN/DOM0 for passing XEN's recovery action
147 * information to DOM0.
148 */
149struct page_offline_action {
150 /* Params for passing the offlined page number to DOM0 */
151 uint64_t mfn;
152 uint64_t status;
153};
154
155struct cpu_offline_action {
156 /* Params for passing the identity of the offlined CPU to DOM0 */
157 uint32_t mc_socketid;
158 uint16_t mc_coreid;
159 uint16_t mc_core_threadid;
160};
161
162#define MAX_UNION_SIZE 16
163struct mcinfo_recovery {
164 struct mcinfo_common common;
165 uint16_t mc_bank; /* bank nr */
166 uint8_t action_flags;
167 uint8_t action_types;
168 union {
169 struct page_offline_action page_retire;
170 struct cpu_offline_action cpu_offline;
171 uint8_t pad[MAX_UNION_SIZE];
172 } action_info;
173};
174
175
176#define MCINFO_MAXSIZE 768
177struct mc_info {
178 /* Number of mcinfo_* entries in mi_data */
179 uint32_t mi_nentries;
180 uint32_t flags;
181 uint64_t mi_data[(MCINFO_MAXSIZE - 1) / 8];
182};
183DEFINE_GUEST_HANDLE_STRUCT(mc_info);
184
185#define __MC_MSR_ARRAYSIZE 8
186#define __MC_MSR_MCGCAP 0
187#define __MC_NMSRS 1
188#define MC_NCAPS 7
189struct mcinfo_logical_cpu {
190 uint32_t mc_cpunr;
191 uint32_t mc_chipid;
192 uint16_t mc_coreid;
193 uint16_t mc_threadid;
194 uint32_t mc_apicid;
195 uint32_t mc_clusterid;
196 uint32_t mc_ncores;
197 uint32_t mc_ncores_active;
198 uint32_t mc_nthreads;
199 uint32_t mc_cpuid_level;
200 uint32_t mc_family;
201 uint32_t mc_vendor;
202 uint32_t mc_model;
203 uint32_t mc_step;
204 char mc_vendorid[16];
205 char mc_brandid[64];
206 uint32_t mc_cpu_caps[MC_NCAPS];
207 uint32_t mc_cache_size;
208 uint32_t mc_cache_alignment;
209 uint32_t mc_nmsrvals;
210 struct mcinfo_msr mc_msrvalues[__MC_MSR_ARRAYSIZE];
211};
212DEFINE_GUEST_HANDLE_STRUCT(mcinfo_logical_cpu);
213
214/*
215 * Prototype:
216 * uint32_t x86_mcinfo_nentries(struct mc_info *mi);
217 */
218#define x86_mcinfo_nentries(_mi) \
219 ((_mi)->mi_nentries)
220/*
221 * Prototype:
222 * struct mcinfo_common *x86_mcinfo_first(struct mc_info *mi);
223 */
224#define x86_mcinfo_first(_mi) \
225 ((struct mcinfo_common *)(_mi)->mi_data)
226/*
227 * Prototype:
228 * struct mcinfo_common *x86_mcinfo_next(struct mcinfo_common *mic);
229 */
230#define x86_mcinfo_next(_mic) \
231 ((struct mcinfo_common *)((uint8_t *)(_mic) + (_mic)->size))
232
233/*
234 * Prototype:
235 * void x86_mcinfo_lookup(void *ret, struct mc_info *mi, uint16_t type);
236 */
237static inline void x86_mcinfo_lookup(struct mcinfo_common **ret,
238 struct mc_info *mi, uint16_t type)
239{
240 uint32_t i;
241 struct mcinfo_common *mic;
242 bool found = 0;
243
244 if (!ret || !mi)
245 return;
246
247 mic = x86_mcinfo_first(mi);
248 for (i = 0; i < x86_mcinfo_nentries(mi); i++) {
249 if (mic->type == type) {
250 found = 1;
251 break;
252 }
253 mic = x86_mcinfo_next(mic);
254 }
255
256 *ret = found ? mic : NULL;
257}
258
259/*
260 * Fetch machine check data from hypervisor.
261 */
262#define XEN_MC_fetch 1
263struct xen_mc_fetch {
264 /*
265 * IN: XEN_MC_NONURGENT, XEN_MC_URGENT,
266 * XEN_MC_ACK if ack'king an earlier fetch
267 * OUT: XEN_MC_OK, XEN_MC_FETCHAILED, XEN_MC_NODATA
268 */
269 uint32_t flags;
270 uint32_t _pad0;
271 /* OUT: id for ack, IN: id we are ack'ing */
272 uint64_t fetch_id;
273
274 /* OUT variables. */
275 GUEST_HANDLE(mc_info) data;
276};
277DEFINE_GUEST_HANDLE_STRUCT(xen_mc_fetch);
278
279
280/*
281 * This tells the hypervisor to notify a DomU about the machine check error
282 */
283#define XEN_MC_notifydomain 2
284struct xen_mc_notifydomain {
285 /* IN variables */
286 uint16_t mc_domid; /* The unprivileged domain to notify */
287 uint16_t mc_vcpuid; /* The vcpu in mc_domid to notify */
288
289 /* IN/OUT variables */
290 uint32_t flags;
291};
292DEFINE_GUEST_HANDLE_STRUCT(xen_mc_notifydomain);
293
294#define XEN_MC_physcpuinfo 3
295struct xen_mc_physcpuinfo {
296 /* IN/OUT */
297 uint32_t ncpus;
298 uint32_t _pad0;
299 /* OUT */
300 GUEST_HANDLE(mcinfo_logical_cpu) info;
301};
302
303#define XEN_MC_msrinject 4
304#define MC_MSRINJ_MAXMSRS 8
305struct xen_mc_msrinject {
306 /* IN */
307 uint32_t mcinj_cpunr; /* target processor id */
308 uint32_t mcinj_flags; /* see MC_MSRINJ_F_* below */
309 uint32_t mcinj_count; /* 0 .. count-1 in array are valid */
310 uint32_t _pad0;
311 struct mcinfo_msr mcinj_msr[MC_MSRINJ_MAXMSRS];
312};
313
314/* Flags for mcinj_flags above; bits 16-31 are reserved */
315#define MC_MSRINJ_F_INTERPOSE 0x1
316
317#define XEN_MC_mceinject 5
318struct xen_mc_mceinject {
319 unsigned int mceinj_cpunr; /* target processor id */
320};
321
322struct xen_mc {
323 uint32_t cmd;
324 uint32_t interface_version; /* XEN_MCA_INTERFACE_VERSION */
325 union {
326 struct xen_mc_fetch mc_fetch;
327 struct xen_mc_notifydomain mc_notifydomain;
328 struct xen_mc_physcpuinfo mc_physcpuinfo;
329 struct xen_mc_msrinject mc_msrinject;
330 struct xen_mc_mceinject mc_mceinject;
331 } u;
332};
333DEFINE_GUEST_HANDLE_STRUCT(xen_mc);
334
335/* Fields are zero when not available */
336struct xen_mce {
337 __u64 status;
338 __u64 misc;
339 __u64 addr;
340 __u64 mcgstatus;
341 __u64 ip;
342 __u64 tsc; /* cpu time stamp counter */
343 __u64 time; /* wall time_t when error was detected */
344 __u8 cpuvendor; /* cpu vendor as encoded in system.h */
345 __u8 inject_flags; /* software inject flags */
346 __u16 pad;
347 __u32 cpuid; /* CPUID 1 EAX */
348 __u8 cs; /* code segment */
349 __u8 bank; /* machine check bank */
350 __u8 cpu; /* cpu number; obsolete; use extcpu now */
351 __u8 finished; /* entry is valid */
352 __u32 extcpu; /* linux cpu number that detected the error */
353 __u32 socketid; /* CPU socket ID */
354 __u32 apicid; /* CPU initial apic ID */
355 __u64 mcgcap; /* MCGCAP MSR: machine check capabilities of CPU */
356};
357
358/*
359 * This structure contains all data related to the MCE log. Also
360 * carries a signature to make it easier to find from external
361 * debugging tools. Each entry is only valid when its finished flag
362 * is set.
363 */
364
365#define XEN_MCE_LOG_LEN 32
366
367struct xen_mce_log {
368 char signature[12]; /* "MACHINECHECK" */
369 unsigned len; /* = XEN_MCE_LOG_LEN */
370 unsigned next;
371 unsigned flags;
372 unsigned recordlen; /* length of struct xen_mce */
373 struct xen_mce entry[XEN_MCE_LOG_LEN];
374};
375
376#define XEN_MCE_OVERFLOW 0 /* bit 0 in flags means overflow */
377
378#define XEN_MCE_LOG_SIGNATURE "MACHINECHECK"
379
380#define MCE_GET_RECORD_LEN _IOR('M', 1, int)
381#define MCE_GET_LOG_LEN _IOR('M', 2, int)
382#define MCE_GETCLEAR_FLAGS _IOR('M', 3, int)
383
384#endif /* __ASSEMBLY__ */
385#endif /* __XEN_PUBLIC_ARCH_X86_MCA_H__ */