int __init bind_virq_for_mce(void) { int ret; xen_mc_t mc_op; g_mi = kmalloc(sizeof(*g_mi), GFP_KERNEL); if (!g_mi) return -ENOMEM; /* fetch physical CPU count */ mc_op.cmd = XEN_MC_physcpuinfo; mc_op.interface_version = XEN_MCA_INTERFACE_VERSION; set_xen_guest_handle(mc_op.u.mc_physcpuinfo.info, NULL); ret = HYPERVISOR_mca(&mc_op); if (ret) { printk(KERN_ERR "MCE: Failed to get physical CPU count\n"); kfree(g_mi); return ret; } /* fetch CPU physical info for later reference */ ncpus = mc_op.u.mc_physcpuinfo.ncpus; g_physinfo = kmalloc(sizeof(*g_physinfo) * ncpus, GFP_KERNEL); if (!g_physinfo) { kfree(g_mi); return -ENOMEM; } set_xen_guest_handle(mc_op.u.mc_physcpuinfo.info, g_physinfo); ret = HYPERVISOR_mca(&mc_op); if (ret) { printk(KERN_ERR "MCE: Failed to get physical CPUs' info\n"); kfree(g_mi); kfree(g_physinfo); return ret; } ret = bind_virq_to_irqhandler(VIRQ_MCA, 0, mce_dom0_interrupt, 0, "mce", NULL); if (ret < 0) { printk(KERN_ERR "MCE: Failed to bind vIRQ for Dom0\n"); kfree(g_mi); kfree(g_physinfo); return ret; } /* Log the machine checks left over from the previous reset. */ mce_dom0_interrupt(VIRQ_MCA, NULL); return 0; }
static int 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; mc_op.interface_version = XEN_MCA_INTERFACE_VERSION; 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; }
static int mc_queue_handle(uint32_t flags) { struct xen_mc mc_op; int ret = 0; mc_op.cmd = XEN_MC_fetch; mc_op.interface_version = XEN_MCA_INTERFACE_VERSION; 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; }
int xen_get_mc_physcpuinfo(xen_mc_logical_cpu_t *log_cpus, uint_t *ncpus) { xen_mc_t xmc; struct xen_mc_physcpuinfo *cpi = &xmc.u.mc_physcpuinfo; cpi->ncpus = *ncpus; /*LINTED: constant in conditional context*/ set_xen_guest_handle(cpi->info, log_cpus); if (HYPERVISOR_mca(XEN_MC_physcpuinfo, &xmc) != 0) return (-1); *ncpus = cpi->ncpus; return (0); }
static irqreturn_t mce_dom0_interrupt(int irq, void *dev_id) { xen_mc_t mc_op; int result = 0; printk(KERN_DEBUG "MCE_DOM0_LOG: enter dom0 mce vIRQ handler\n"); mc_op.cmd = XEN_MC_fetch; mc_op.interface_version = XEN_MCA_INTERFACE_VERSION; set_xen_guest_handle(mc_op.u.mc_fetch.data, g_mi); urgent: mc_op.u.mc_fetch.flags = XEN_MC_URGENT; result = HYPERVISOR_mca(&mc_op); if (result || mc_op.u.mc_fetch.flags & XEN_MC_NODATA || mc_op.u.mc_fetch.flags & XEN_MC_FETCHFAILED) { printk(KERN_DEBUG "MCE_DOM0_LOG: No more urgent data\n"); goto nonurgent; } else { result = convert_log(g_mi); if (result) { printk(KERN_ERR "MCE_DOM0_LOG: Log conversion failed\n"); goto end; } /* After fetching the telem from DOM0, we need to dec the telem's * refcnt and release the entry. The telem is reserved and inc * refcnt when filling the telem. */ mc_op.u.mc_fetch.flags = XEN_MC_URGENT | XEN_MC_ACK; result = HYPERVISOR_mca(&mc_op); goto urgent; } nonurgent: mc_op.u.mc_fetch.flags = XEN_MC_NONURGENT; result = HYPERVISOR_mca(&mc_op); if (result || mc_op.u.mc_fetch.flags & XEN_MC_NODATA || mc_op.u.mc_fetch.flags & XEN_MC_FETCHFAILED) { printk(KERN_DEBUG "MCE_DOM0_LOG: No more nonurgent data\n"); goto end; } else { result = convert_log(g_mi); if (result) { printk(KERN_ERR "MCE_DOM0_LOG: Log conversion failed\n"); goto end; } /* After fetching the telem from DOM0, we need to dec the telem's * refcnt and release the entry. The telem is reserved and inc * refcnt when filling the telem. */ mc_op.u.mc_fetch.flags = XEN_MC_NONURGENT | XEN_MC_ACK; result = HYPERVISOR_mca(&mc_op); goto nonurgent; } end: return IRQ_HANDLED; }