aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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__ */