1cef12ee5SLiu, Jinsong /****************************************************************************** 2cef12ee5SLiu, Jinsong * mcelog.c 3cef12ee5SLiu, Jinsong * Driver for receiving and transferring machine check error infomation 4cef12ee5SLiu, Jinsong * 5cef12ee5SLiu, Jinsong * Copyright (c) 2012 Intel Corporation 6cef12ee5SLiu, Jinsong * Author: Liu, Jinsong <jinsong.liu@intel.com> 7cef12ee5SLiu, Jinsong * Author: Jiang, Yunhong <yunhong.jiang@intel.com> 8cef12ee5SLiu, Jinsong * Author: Ke, Liping <liping.ke@intel.com> 9cef12ee5SLiu, Jinsong * 10cef12ee5SLiu, Jinsong * This program is free software; you can redistribute it and/or 11cef12ee5SLiu, Jinsong * modify it under the terms of the GNU General Public License version 2 12cef12ee5SLiu, Jinsong * as published by the Free Software Foundation; or, when distributed 13cef12ee5SLiu, Jinsong * separately from the Linux kernel or incorporated into other 14cef12ee5SLiu, Jinsong * software packages, subject to the following license: 15cef12ee5SLiu, Jinsong * 16cef12ee5SLiu, Jinsong * Permission is hereby granted, free of charge, to any person obtaining a copy 17cef12ee5SLiu, Jinsong * of this source file (the "Software"), to deal in the Software without 18cef12ee5SLiu, Jinsong * restriction, including without limitation the rights to use, copy, modify, 19cef12ee5SLiu, Jinsong * merge, publish, distribute, sublicense, and/or sell copies of the Software, 20cef12ee5SLiu, Jinsong * and to permit persons to whom the Software is furnished to do so, subject to 21cef12ee5SLiu, Jinsong * the following conditions: 22cef12ee5SLiu, Jinsong * 23cef12ee5SLiu, Jinsong * The above copyright notice and this permission notice shall be included in 24cef12ee5SLiu, Jinsong * all copies or substantial portions of the Software. 25cef12ee5SLiu, Jinsong * 26cef12ee5SLiu, Jinsong * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27cef12ee5SLiu, Jinsong * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28cef12ee5SLiu, Jinsong * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29cef12ee5SLiu, Jinsong * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30cef12ee5SLiu, Jinsong * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 31cef12ee5SLiu, Jinsong * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 32cef12ee5SLiu, Jinsong * IN THE SOFTWARE. 33cef12ee5SLiu, Jinsong */ 34cef12ee5SLiu, Jinsong 35cef12ee5SLiu, Jinsong #include <linux/init.h> 36cef12ee5SLiu, Jinsong #include <linux/types.h> 37cef12ee5SLiu, Jinsong #include <linux/kernel.h> 38cef12ee5SLiu, Jinsong #include <linux/slab.h> 39cef12ee5SLiu, Jinsong #include <linux/fs.h> 40cef12ee5SLiu, Jinsong #include <linux/device.h> 41cef12ee5SLiu, Jinsong #include <linux/miscdevice.h> 42cef12ee5SLiu, Jinsong #include <linux/uaccess.h> 43cef12ee5SLiu, Jinsong #include <linux/capability.h> 44cef12ee5SLiu, Jinsong 45cef12ee5SLiu, Jinsong #include <xen/interface/xen.h> 46cef12ee5SLiu, Jinsong #include <xen/events.h> 47cef12ee5SLiu, Jinsong #include <xen/interface/vcpu.h> 48cef12ee5SLiu, Jinsong #include <xen/xen.h> 49cef12ee5SLiu, Jinsong #include <asm/xen/hypercall.h> 50cef12ee5SLiu, Jinsong #include <asm/xen/hypervisor.h> 51cef12ee5SLiu, Jinsong 52cef12ee5SLiu, Jinsong #define XEN_MCELOG "xen_mcelog: " 53cef12ee5SLiu, Jinsong 54cef12ee5SLiu, Jinsong static struct mc_info g_mi; 55cef12ee5SLiu, Jinsong static struct mcinfo_logical_cpu *g_physinfo; 56cef12ee5SLiu, Jinsong static uint32_t ncpus; 57cef12ee5SLiu, Jinsong 58*1b2a0551SLiu, Jinsong static DEFINE_MUTEX(mcelog_lock); 59cef12ee5SLiu, Jinsong 60cef12ee5SLiu, Jinsong static struct xen_mce_log xen_mcelog = { 61cef12ee5SLiu, Jinsong .signature = XEN_MCE_LOG_SIGNATURE, 62cef12ee5SLiu, Jinsong .len = XEN_MCE_LOG_LEN, 63cef12ee5SLiu, Jinsong .recordlen = sizeof(struct xen_mce), 64cef12ee5SLiu, Jinsong }; 65cef12ee5SLiu, Jinsong 66cef12ee5SLiu, Jinsong static DEFINE_SPINLOCK(xen_mce_chrdev_state_lock); 67cef12ee5SLiu, Jinsong static int xen_mce_chrdev_open_count; /* #times opened */ 68cef12ee5SLiu, Jinsong static int xen_mce_chrdev_open_exclu; /* already open exclusive? */ 69cef12ee5SLiu, Jinsong 70cef12ee5SLiu, Jinsong static int xen_mce_chrdev_open(struct inode *inode, struct file *file) 71cef12ee5SLiu, Jinsong { 72cef12ee5SLiu, Jinsong spin_lock(&xen_mce_chrdev_state_lock); 73cef12ee5SLiu, Jinsong 74cef12ee5SLiu, Jinsong if (xen_mce_chrdev_open_exclu || 75cef12ee5SLiu, Jinsong (xen_mce_chrdev_open_count && (file->f_flags & O_EXCL))) { 76cef12ee5SLiu, Jinsong spin_unlock(&xen_mce_chrdev_state_lock); 77cef12ee5SLiu, Jinsong 78cef12ee5SLiu, Jinsong return -EBUSY; 79cef12ee5SLiu, Jinsong } 80cef12ee5SLiu, Jinsong 81cef12ee5SLiu, Jinsong if (file->f_flags & O_EXCL) 82cef12ee5SLiu, Jinsong xen_mce_chrdev_open_exclu = 1; 83cef12ee5SLiu, Jinsong xen_mce_chrdev_open_count++; 84cef12ee5SLiu, Jinsong 85cef12ee5SLiu, Jinsong spin_unlock(&xen_mce_chrdev_state_lock); 86cef12ee5SLiu, Jinsong 87cef12ee5SLiu, Jinsong return nonseekable_open(inode, file); 88cef12ee5SLiu, Jinsong } 89cef12ee5SLiu, Jinsong 90cef12ee5SLiu, Jinsong static int xen_mce_chrdev_release(struct inode *inode, struct file *file) 91cef12ee5SLiu, Jinsong { 92cef12ee5SLiu, Jinsong spin_lock(&xen_mce_chrdev_state_lock); 93cef12ee5SLiu, Jinsong 94cef12ee5SLiu, Jinsong xen_mce_chrdev_open_count--; 95cef12ee5SLiu, Jinsong xen_mce_chrdev_open_exclu = 0; 96cef12ee5SLiu, Jinsong 97cef12ee5SLiu, Jinsong spin_unlock(&xen_mce_chrdev_state_lock); 98cef12ee5SLiu, Jinsong 99cef12ee5SLiu, Jinsong return 0; 100cef12ee5SLiu, Jinsong } 101cef12ee5SLiu, Jinsong 102cef12ee5SLiu, Jinsong static ssize_t xen_mce_chrdev_read(struct file *filp, char __user *ubuf, 103cef12ee5SLiu, Jinsong size_t usize, loff_t *off) 104cef12ee5SLiu, Jinsong { 105cef12ee5SLiu, Jinsong char __user *buf = ubuf; 106cef12ee5SLiu, Jinsong unsigned num; 107cef12ee5SLiu, Jinsong int i, err; 108cef12ee5SLiu, Jinsong 109*1b2a0551SLiu, Jinsong mutex_lock(&mcelog_lock); 110cef12ee5SLiu, Jinsong 111cef12ee5SLiu, Jinsong num = xen_mcelog.next; 112cef12ee5SLiu, Jinsong 113cef12ee5SLiu, Jinsong /* Only supports full reads right now */ 114cef12ee5SLiu, Jinsong err = -EINVAL; 115cef12ee5SLiu, Jinsong if (*off != 0 || usize < XEN_MCE_LOG_LEN*sizeof(struct xen_mce)) 116cef12ee5SLiu, Jinsong goto out; 117cef12ee5SLiu, Jinsong 118cef12ee5SLiu, Jinsong err = 0; 119cef12ee5SLiu, Jinsong for (i = 0; i < num; i++) { 120cef12ee5SLiu, Jinsong struct xen_mce *m = &xen_mcelog.entry[i]; 121cef12ee5SLiu, Jinsong 122cef12ee5SLiu, Jinsong err |= copy_to_user(buf, m, sizeof(*m)); 123cef12ee5SLiu, Jinsong buf += sizeof(*m); 124cef12ee5SLiu, Jinsong } 125cef12ee5SLiu, Jinsong 126cef12ee5SLiu, Jinsong memset(xen_mcelog.entry, 0, num * sizeof(struct xen_mce)); 127cef12ee5SLiu, Jinsong xen_mcelog.next = 0; 128cef12ee5SLiu, Jinsong 129cef12ee5SLiu, Jinsong if (err) 130cef12ee5SLiu, Jinsong err = -EFAULT; 131cef12ee5SLiu, Jinsong 132cef12ee5SLiu, Jinsong out: 133*1b2a0551SLiu, Jinsong mutex_unlock(&mcelog_lock); 134cef12ee5SLiu, Jinsong 135cef12ee5SLiu, Jinsong return err ? err : buf - ubuf; 136cef12ee5SLiu, Jinsong } 137cef12ee5SLiu, Jinsong 138cef12ee5SLiu, Jinsong static long xen_mce_chrdev_ioctl(struct file *f, unsigned int cmd, 139cef12ee5SLiu, Jinsong unsigned long arg) 140cef12ee5SLiu, Jinsong { 141cef12ee5SLiu, Jinsong int __user *p = (int __user *)arg; 142cef12ee5SLiu, Jinsong 143cef12ee5SLiu, Jinsong if (!capable(CAP_SYS_ADMIN)) 144cef12ee5SLiu, Jinsong return -EPERM; 145cef12ee5SLiu, Jinsong 146cef12ee5SLiu, Jinsong switch (cmd) { 147cef12ee5SLiu, Jinsong case MCE_GET_RECORD_LEN: 148cef12ee5SLiu, Jinsong return put_user(sizeof(struct xen_mce), p); 149cef12ee5SLiu, Jinsong case MCE_GET_LOG_LEN: 150cef12ee5SLiu, Jinsong return put_user(XEN_MCE_LOG_LEN, p); 151cef12ee5SLiu, Jinsong case MCE_GETCLEAR_FLAGS: { 152cef12ee5SLiu, Jinsong unsigned flags; 153cef12ee5SLiu, Jinsong 154cef12ee5SLiu, Jinsong do { 155cef12ee5SLiu, Jinsong flags = xen_mcelog.flags; 156cef12ee5SLiu, Jinsong } while (cmpxchg(&xen_mcelog.flags, flags, 0) != flags); 157cef12ee5SLiu, Jinsong 158cef12ee5SLiu, Jinsong return put_user(flags, p); 159cef12ee5SLiu, Jinsong } 160cef12ee5SLiu, Jinsong default: 161cef12ee5SLiu, Jinsong return -ENOTTY; 162cef12ee5SLiu, Jinsong } 163cef12ee5SLiu, Jinsong } 164cef12ee5SLiu, Jinsong 165cef12ee5SLiu, Jinsong static const struct file_operations xen_mce_chrdev_ops = { 166cef12ee5SLiu, Jinsong .open = xen_mce_chrdev_open, 167cef12ee5SLiu, Jinsong .release = xen_mce_chrdev_release, 168cef12ee5SLiu, Jinsong .read = xen_mce_chrdev_read, 169cef12ee5SLiu, Jinsong .unlocked_ioctl = xen_mce_chrdev_ioctl, 170cef12ee5SLiu, Jinsong .llseek = no_llseek, 171cef12ee5SLiu, Jinsong }; 172cef12ee5SLiu, Jinsong 173cef12ee5SLiu, Jinsong static struct miscdevice xen_mce_chrdev_device = { 174cef12ee5SLiu, Jinsong MISC_MCELOG_MINOR, 175cef12ee5SLiu, Jinsong "mcelog", 176cef12ee5SLiu, Jinsong &xen_mce_chrdev_ops, 177cef12ee5SLiu, Jinsong }; 178cef12ee5SLiu, Jinsong 179cef12ee5SLiu, Jinsong /* 180cef12ee5SLiu, Jinsong * Caller should hold the mcelog_lock 181cef12ee5SLiu, Jinsong */ 182cef12ee5SLiu, Jinsong static void xen_mce_log(struct xen_mce *mce) 183cef12ee5SLiu, Jinsong { 184cef12ee5SLiu, Jinsong unsigned entry; 185cef12ee5SLiu, Jinsong 186cef12ee5SLiu, Jinsong entry = xen_mcelog.next; 187cef12ee5SLiu, Jinsong 188cef12ee5SLiu, Jinsong /* 189cef12ee5SLiu, Jinsong * When the buffer fills up discard new entries. 190cef12ee5SLiu, Jinsong * Assume that the earlier errors are the more 191cef12ee5SLiu, Jinsong * interesting ones: 192cef12ee5SLiu, Jinsong */ 193cef12ee5SLiu, Jinsong if (entry >= XEN_MCE_LOG_LEN) { 194cef12ee5SLiu, Jinsong set_bit(XEN_MCE_OVERFLOW, 195cef12ee5SLiu, Jinsong (unsigned long *)&xen_mcelog.flags); 196cef12ee5SLiu, Jinsong return; 197cef12ee5SLiu, Jinsong } 198cef12ee5SLiu, Jinsong 199cef12ee5SLiu, Jinsong memcpy(xen_mcelog.entry + entry, mce, sizeof(struct xen_mce)); 200cef12ee5SLiu, Jinsong 201cef12ee5SLiu, Jinsong xen_mcelog.next++; 202cef12ee5SLiu, Jinsong } 203cef12ee5SLiu, Jinsong 204cef12ee5SLiu, Jinsong static int convert_log(struct mc_info *mi) 205cef12ee5SLiu, Jinsong { 206cef12ee5SLiu, Jinsong struct mcinfo_common *mic; 207cef12ee5SLiu, Jinsong struct mcinfo_global *mc_global; 208cef12ee5SLiu, Jinsong struct mcinfo_bank *mc_bank; 209cef12ee5SLiu, Jinsong struct xen_mce m; 210cef12ee5SLiu, Jinsong uint32_t i; 211cef12ee5SLiu, Jinsong 212cef12ee5SLiu, Jinsong mic = NULL; 213cef12ee5SLiu, Jinsong x86_mcinfo_lookup(&mic, mi, MC_TYPE_GLOBAL); 214cef12ee5SLiu, Jinsong if (unlikely(!mic)) { 215cef12ee5SLiu, Jinsong pr_warning(XEN_MCELOG "Failed to find global error info\n"); 216cef12ee5SLiu, Jinsong return -ENODEV; 217cef12ee5SLiu, Jinsong } 218cef12ee5SLiu, Jinsong 219cef12ee5SLiu, Jinsong memset(&m, 0, sizeof(struct xen_mce)); 220cef12ee5SLiu, Jinsong 221cef12ee5SLiu, Jinsong mc_global = (struct mcinfo_global *)mic; 222cef12ee5SLiu, Jinsong m.mcgstatus = mc_global->mc_gstatus; 223cef12ee5SLiu, Jinsong m.apicid = mc_global->mc_apicid; 224cef12ee5SLiu, Jinsong 225cef12ee5SLiu, Jinsong for (i = 0; i < ncpus; i++) 226cef12ee5SLiu, Jinsong if (g_physinfo[i].mc_apicid == m.apicid) 227cef12ee5SLiu, Jinsong break; 228cef12ee5SLiu, Jinsong if (unlikely(i == ncpus)) { 229cef12ee5SLiu, Jinsong pr_warning(XEN_MCELOG "Failed to match cpu with apicid %d\n", 230cef12ee5SLiu, Jinsong m.apicid); 231cef12ee5SLiu, Jinsong return -ENODEV; 232cef12ee5SLiu, Jinsong } 233cef12ee5SLiu, Jinsong 234cef12ee5SLiu, Jinsong m.socketid = g_physinfo[i].mc_chipid; 235cef12ee5SLiu, Jinsong m.cpu = m.extcpu = g_physinfo[i].mc_cpunr; 236cef12ee5SLiu, Jinsong m.cpuvendor = (__u8)g_physinfo[i].mc_vendor; 237cef12ee5SLiu, Jinsong m.mcgcap = g_physinfo[i].mc_msrvalues[__MC_MSR_MCGCAP].value; 238cef12ee5SLiu, Jinsong 239cef12ee5SLiu, Jinsong mic = NULL; 240cef12ee5SLiu, Jinsong x86_mcinfo_lookup(&mic, mi, MC_TYPE_BANK); 241cef12ee5SLiu, Jinsong if (unlikely(!mic)) { 242cef12ee5SLiu, Jinsong pr_warning(XEN_MCELOG "Fail to find bank error info\n"); 243cef12ee5SLiu, Jinsong return -ENODEV; 244cef12ee5SLiu, Jinsong } 245cef12ee5SLiu, Jinsong 246cef12ee5SLiu, Jinsong do { 247cef12ee5SLiu, Jinsong if ((!mic) || (mic->size == 0) || 248cef12ee5SLiu, Jinsong (mic->type != MC_TYPE_GLOBAL && 249cef12ee5SLiu, Jinsong mic->type != MC_TYPE_BANK && 250cef12ee5SLiu, Jinsong mic->type != MC_TYPE_EXTENDED && 251cef12ee5SLiu, Jinsong mic->type != MC_TYPE_RECOVERY)) 252cef12ee5SLiu, Jinsong break; 253cef12ee5SLiu, Jinsong 254cef12ee5SLiu, Jinsong if (mic->type == MC_TYPE_BANK) { 255cef12ee5SLiu, Jinsong mc_bank = (struct mcinfo_bank *)mic; 256cef12ee5SLiu, Jinsong m.misc = mc_bank->mc_misc; 257cef12ee5SLiu, Jinsong m.status = mc_bank->mc_status; 258cef12ee5SLiu, Jinsong m.addr = mc_bank->mc_addr; 259cef12ee5SLiu, Jinsong m.tsc = mc_bank->mc_tsc; 260cef12ee5SLiu, Jinsong m.bank = mc_bank->mc_bank; 261cef12ee5SLiu, Jinsong m.finished = 1; 262cef12ee5SLiu, Jinsong /*log this record*/ 263cef12ee5SLiu, Jinsong xen_mce_log(&m); 264cef12ee5SLiu, Jinsong } 265cef12ee5SLiu, Jinsong mic = x86_mcinfo_next(mic); 266cef12ee5SLiu, Jinsong } while (1); 267cef12ee5SLiu, Jinsong 268cef12ee5SLiu, Jinsong return 0; 269cef12ee5SLiu, Jinsong } 270cef12ee5SLiu, Jinsong 271cef12ee5SLiu, Jinsong static int mc_queue_handle(uint32_t flags) 272cef12ee5SLiu, Jinsong { 273cef12ee5SLiu, Jinsong struct xen_mc mc_op; 274cef12ee5SLiu, Jinsong int ret = 0; 275cef12ee5SLiu, Jinsong 276cef12ee5SLiu, Jinsong mc_op.cmd = XEN_MC_fetch; 277cef12ee5SLiu, Jinsong mc_op.interface_version = XEN_MCA_INTERFACE_VERSION; 278cef12ee5SLiu, Jinsong set_xen_guest_handle(mc_op.u.mc_fetch.data, &g_mi); 279cef12ee5SLiu, Jinsong do { 280cef12ee5SLiu, Jinsong mc_op.u.mc_fetch.flags = flags; 281cef12ee5SLiu, Jinsong ret = HYPERVISOR_mca(&mc_op); 282cef12ee5SLiu, Jinsong if (ret) { 283cef12ee5SLiu, Jinsong pr_err(XEN_MCELOG "Failed to fetch %s error log\n", 284cef12ee5SLiu, Jinsong (flags == XEN_MC_URGENT) ? 285cef12ee5SLiu, Jinsong "urgnet" : "nonurgent"); 286cef12ee5SLiu, Jinsong break; 287cef12ee5SLiu, Jinsong } 288cef12ee5SLiu, Jinsong 289cef12ee5SLiu, Jinsong if (mc_op.u.mc_fetch.flags & XEN_MC_NODATA || 290cef12ee5SLiu, Jinsong mc_op.u.mc_fetch.flags & XEN_MC_FETCHFAILED) 291cef12ee5SLiu, Jinsong break; 292cef12ee5SLiu, Jinsong else { 293cef12ee5SLiu, Jinsong ret = convert_log(&g_mi); 294cef12ee5SLiu, Jinsong if (ret) 295cef12ee5SLiu, Jinsong pr_warning(XEN_MCELOG 296cef12ee5SLiu, Jinsong "Failed to convert this error log, " 297cef12ee5SLiu, Jinsong "continue acking it anyway\n"); 298cef12ee5SLiu, Jinsong 299cef12ee5SLiu, Jinsong mc_op.u.mc_fetch.flags = flags | XEN_MC_ACK; 300cef12ee5SLiu, Jinsong ret = HYPERVISOR_mca(&mc_op); 301cef12ee5SLiu, Jinsong if (ret) { 302cef12ee5SLiu, Jinsong pr_err(XEN_MCELOG 303cef12ee5SLiu, Jinsong "Failed to ack previous error log\n"); 304cef12ee5SLiu, Jinsong break; 305cef12ee5SLiu, Jinsong } 306cef12ee5SLiu, Jinsong } 307cef12ee5SLiu, Jinsong } while (1); 308cef12ee5SLiu, Jinsong 309cef12ee5SLiu, Jinsong return ret; 310cef12ee5SLiu, Jinsong } 311cef12ee5SLiu, Jinsong 312cef12ee5SLiu, Jinsong /* virq handler for machine check error info*/ 313*1b2a0551SLiu, Jinsong static void xen_mce_work_fn(struct work_struct *work) 314cef12ee5SLiu, Jinsong { 315cef12ee5SLiu, Jinsong int err; 316cef12ee5SLiu, Jinsong 317*1b2a0551SLiu, Jinsong mutex_lock(&mcelog_lock); 318cef12ee5SLiu, Jinsong 319cef12ee5SLiu, Jinsong /* urgent mc_info */ 320cef12ee5SLiu, Jinsong err = mc_queue_handle(XEN_MC_URGENT); 321cef12ee5SLiu, Jinsong if (err) 322cef12ee5SLiu, Jinsong pr_err(XEN_MCELOG 323cef12ee5SLiu, Jinsong "Failed to handle urgent mc_info queue, " 324cef12ee5SLiu, Jinsong "continue handling nonurgent mc_info queue anyway.\n"); 325cef12ee5SLiu, Jinsong 326cef12ee5SLiu, Jinsong /* nonurgent mc_info */ 327cef12ee5SLiu, Jinsong err = mc_queue_handle(XEN_MC_NONURGENT); 328cef12ee5SLiu, Jinsong if (err) 329cef12ee5SLiu, Jinsong pr_err(XEN_MCELOG 330cef12ee5SLiu, Jinsong "Failed to handle nonurgent mc_info queue.\n"); 331cef12ee5SLiu, Jinsong 332*1b2a0551SLiu, Jinsong mutex_unlock(&mcelog_lock); 333*1b2a0551SLiu, Jinsong } 334*1b2a0551SLiu, Jinsong static DECLARE_WORK(xen_mce_work, xen_mce_work_fn); 335cef12ee5SLiu, Jinsong 336*1b2a0551SLiu, Jinsong static irqreturn_t xen_mce_interrupt(int irq, void *dev_id) 337*1b2a0551SLiu, Jinsong { 338*1b2a0551SLiu, Jinsong schedule_work(&xen_mce_work); 339cef12ee5SLiu, Jinsong return IRQ_HANDLED; 340cef12ee5SLiu, Jinsong } 341cef12ee5SLiu, Jinsong 342cef12ee5SLiu, Jinsong static int bind_virq_for_mce(void) 343cef12ee5SLiu, Jinsong { 344cef12ee5SLiu, Jinsong int ret; 345cef12ee5SLiu, Jinsong struct xen_mc mc_op; 346cef12ee5SLiu, Jinsong 347cef12ee5SLiu, Jinsong memset(&mc_op, 0, sizeof(struct xen_mc)); 348cef12ee5SLiu, Jinsong 349cef12ee5SLiu, Jinsong /* Fetch physical CPU Numbers */ 350cef12ee5SLiu, Jinsong mc_op.cmd = XEN_MC_physcpuinfo; 351cef12ee5SLiu, Jinsong mc_op.interface_version = XEN_MCA_INTERFACE_VERSION; 352cef12ee5SLiu, Jinsong set_xen_guest_handle(mc_op.u.mc_physcpuinfo.info, g_physinfo); 353cef12ee5SLiu, Jinsong ret = HYPERVISOR_mca(&mc_op); 354cef12ee5SLiu, Jinsong if (ret) { 355cef12ee5SLiu, Jinsong pr_err(XEN_MCELOG "Failed to get CPU numbers\n"); 356cef12ee5SLiu, Jinsong return ret; 357cef12ee5SLiu, Jinsong } 358cef12ee5SLiu, Jinsong 359cef12ee5SLiu, Jinsong /* Fetch each CPU Physical Info for later reference*/ 360cef12ee5SLiu, Jinsong ncpus = mc_op.u.mc_physcpuinfo.ncpus; 361cef12ee5SLiu, Jinsong g_physinfo = kcalloc(ncpus, sizeof(struct mcinfo_logical_cpu), 362cef12ee5SLiu, Jinsong GFP_KERNEL); 363cef12ee5SLiu, Jinsong if (!g_physinfo) 364cef12ee5SLiu, Jinsong return -ENOMEM; 365cef12ee5SLiu, Jinsong set_xen_guest_handle(mc_op.u.mc_physcpuinfo.info, g_physinfo); 366cef12ee5SLiu, Jinsong ret = HYPERVISOR_mca(&mc_op); 367cef12ee5SLiu, Jinsong if (ret) { 368cef12ee5SLiu, Jinsong pr_err(XEN_MCELOG "Failed to get CPU info\n"); 369cef12ee5SLiu, Jinsong kfree(g_physinfo); 370cef12ee5SLiu, Jinsong return ret; 371cef12ee5SLiu, Jinsong } 372cef12ee5SLiu, Jinsong 373cef12ee5SLiu, Jinsong ret = bind_virq_to_irqhandler(VIRQ_MCA, 0, 374cef12ee5SLiu, Jinsong xen_mce_interrupt, 0, "mce", NULL); 375cef12ee5SLiu, Jinsong if (ret < 0) { 376cef12ee5SLiu, Jinsong pr_err(XEN_MCELOG "Failed to bind virq\n"); 377cef12ee5SLiu, Jinsong kfree(g_physinfo); 378cef12ee5SLiu, Jinsong return ret; 379cef12ee5SLiu, Jinsong } 380cef12ee5SLiu, Jinsong 381cef12ee5SLiu, Jinsong return 0; 382cef12ee5SLiu, Jinsong } 383cef12ee5SLiu, Jinsong 384cef12ee5SLiu, Jinsong static int __init xen_late_init_mcelog(void) 385cef12ee5SLiu, Jinsong { 386cef12ee5SLiu, Jinsong /* Only DOM0 is responsible for MCE logging */ 387cef12ee5SLiu, Jinsong if (xen_initial_domain()) { 388cef12ee5SLiu, Jinsong /* register character device /dev/mcelog for xen mcelog */ 389cef12ee5SLiu, Jinsong if (misc_register(&xen_mce_chrdev_device)) 390cef12ee5SLiu, Jinsong return -ENODEV; 391cef12ee5SLiu, Jinsong return bind_virq_for_mce(); 392cef12ee5SLiu, Jinsong } 393cef12ee5SLiu, Jinsong 394cef12ee5SLiu, Jinsong return -ENODEV; 395cef12ee5SLiu, Jinsong } 396cef12ee5SLiu, Jinsong device_initcall(xen_late_init_mcelog); 397