/****************************************************************************** * mcelog.c * Driver for receiving and transferring machine check error infomation * * Copyright (c) 2012 Intel Corporation * Author: Liu, Jinsong <jinsong.liu@intel.com> * Author: Jiang, Yunhong <yunhong.jiang@intel.com> * Author: Ke, Liping <liping.ke@intel.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation; or, when distributed * separately from the Linux kernel or incorporated into other * software packages, subject to the following license: * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this source file (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, modify, * merge, publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE.
*/
/* * Caller should hold the mcelog_lock
*/ staticvoid xen_mce_log(struct xen_mce *mce)
{ unsigned entry;
entry = xen_mcelog.next;
/* * When the buffer fills up discard new entries. * Assume that the earlier errors are the more * interesting ones:
*/ if (entry >= XEN_MCE_LOG_LEN) {
set_bit(XEN_MCE_OVERFLOW,
(unsignedlong *)&xen_mcelog.flags); return;
}
for (i = 0; i < ncpus; i++) if (g_physinfo[i].mc_apicid == m.apicid) break; if (unlikely(i == ncpus)) {
pr_warn("Failed to match cpu with apicid %d\n", m.apicid); return -ENODEV;
}
if (mic->type == MC_TYPE_BANK) {
mc_bank = (struct mcinfo_bank *)mic;
m.misc = mc_bank->mc_misc;
m.status = mc_bank->mc_status;
m.addr = mc_bank->mc_addr;
m.tsc = mc_bank->mc_tsc;
m.bank = mc_bank->mc_bank;
m.finished = 1; /*log this record*/
xen_mce_log(&m);
}
mic = x86_mcinfo_next(mic);
} while (1);
return 0;
}
staticint mc_queue_handle(uint32_t flags)
{ struct xen_mc mc_op; int ret = 0;
mc_op.cmd = XEN_MC_fetch;
set_xen_guest_handle(mc_op.u.mc_fetch.data, &g_mi); do {
mc_op.u.mc_fetch.flags = flags;
ret = HYPERVISOR_mca(&mc_op); if (ret) {
pr_err("Failed to fetch %surgent error log\n",
flags == XEN_MC_URGENT ? "" : "non"); break;
}
if (mc_op.u.mc_fetch.flags & XEN_MC_NODATA ||
mc_op.u.mc_fetch.flags & XEN_MC_FETCHFAILED) break; else {
ret = convert_log(&g_mi); if (ret)
pr_warn("Failed to convert this error log, continue acking it anyway\n");
mc_op.u.mc_fetch.flags = flags | XEN_MC_ACK;
ret = HYPERVISOR_mca(&mc_op); if (ret) {
pr_err("Failed to ack previous error log\n"); break;
}
}
} while (1);
return ret;
}
/* virq handler for machine check error info*/ staticvoid xen_mce_work_fn(struct work_struct *work)
{ int err;
staticint bind_virq_for_mce(void)
{ int ret; struct xen_mc mc_op;
memset(&mc_op, 0, sizeof(struct xen_mc));
/* Fetch physical CPU Numbers */
mc_op.cmd = XEN_MC_physcpuinfo;
set_xen_guest_handle(mc_op.u.mc_physcpuinfo.info, g_physinfo);
ret = HYPERVISOR_mca(&mc_op); if (ret) {
pr_err("Failed to get CPU numbers\n"); return ret;
}
/* Fetch each CPU Physical Info for later reference*/
ncpus = mc_op.u.mc_physcpuinfo.ncpus;
g_physinfo = kcalloc(ncpus, sizeof(struct mcinfo_logical_cpu),
GFP_KERNEL); if (!g_physinfo) return -ENOMEM;
set_xen_guest_handle(mc_op.u.mc_physcpuinfo.info, g_physinfo);
ret = HYPERVISOR_mca(&mc_op); if (ret) {
pr_err("Failed to get CPU info\n");
kfree(g_physinfo); return ret;
}
ret = bind_virq_to_irqhandler(VIRQ_MCA, 0,
xen_mce_interrupt, 0, "mce", NULL); if (ret < 0) {
pr_err("Failed to bind virq\n");
kfree(g_physinfo); return ret;
}
return 0;
}
staticint __init xen_late_init_mcelog(void)
{ int ret;
/* Only DOM0 is responsible for MCE logging */ if (!xen_initial_domain()) return -ENODEV;
/* register character device /dev/mcelog for xen mcelog */
ret = misc_register(&xen_mce_chrdev_device); if (ret) return ret;
ret = bind_virq_for_mce(); if (ret) goto deregister;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.