static void __init set_vsmp_pv_ops(void) { void __iomem *address; unsigned int cap, ctl, cfg; /* set vSMP magic bits to indicate vSMP capable kernel */ cfg = read_pci_config(0, 0x1f, 0, PCI_BASE_ADDRESS_0); address = early_ioremap(cfg, 8); cap = readl(address); ctl = readl(address + 4); printk(KERN_INFO "vSMP CTL: capabilities:0x%08x control:0x%08x\n", cap, ctl); if (cap & ctl & (1 << 4)) { /* Setup irq ops and turn on vSMP IRQ fastpath handling */ pv_irq_ops.irq_disable = PV_CALLEE_SAVE(vsmp_irq_disable); pv_irq_ops.irq_enable = PV_CALLEE_SAVE(vsmp_irq_enable); pv_irq_ops.save_fl = PV_CALLEE_SAVE(vsmp_save_fl); pv_irq_ops.restore_fl = PV_CALLEE_SAVE(vsmp_restore_fl); pv_init_ops.patch = vsmp_patch; ctl &= ~(1 << 4); writel(ctl, address + 4); ctl = readl(address + 4); printk(KERN_INFO "vSMP CTL: control set to:0x%08x\n", ctl); } early_iounmap(address, 8); }
/* * Our init of PV spinlocks is split in two init functions due to us * using paravirt patching and jump labels patching and having to do * all of this before SMP code is invoked. * * The paravirt patching needs to be done _before_ the alternative asm code * is started, otherwise we would not patch the core kernel code. */ void __init xen_init_spinlocks(void) { if (!xen_pvspin) { printk(KERN_DEBUG "xen: PV spinlocks disabled\n"); return; } printk(KERN_DEBUG "xen: PV spinlocks enabled\n"); __pv_init_lock_hash(); pv_lock_ops.queued_spin_lock_slowpath = __pv_queued_spin_lock_slowpath; pv_lock_ops.queued_spin_unlock = PV_CALLEE_SAVE(__pv_queued_spin_unlock); pv_lock_ops.wait = xen_qlock_wait; pv_lock_ops.kick = xen_qlock_kick; }
{ /* Blocking includes an implicit local_irq_enable(). */ if (HYPERVISOR_sched_op(SCHEDOP_block, NULL) != 0) BUG(); } static void xen_halt(void) { if (irqs_disabled()) HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL); else xen_safe_halt(); } static const struct pv_irq_ops xen_irq_ops __initconst = { .save_fl = PV_CALLEE_SAVE(xen_save_fl), .restore_fl = PV_CALLEE_SAVE(xen_restore_fl), .irq_disable = PV_CALLEE_SAVE(xen_irq_disable), .irq_enable = PV_CALLEE_SAVE(xen_irq_enable), .safe_halt = xen_safe_halt, .halt = xen_halt, #ifdef CONFIG_X86_64 .adjust_exception_frame = xen_adjust_exception_frame, #endif }; void __init xen_init_irq_ops(void) { pv_irq_ops = xen_irq_ops; x86_init.irqs.intr_init = xen_init_IRQ;
#include <linux/export.h> #include <linux/jump_label.h> #include <asm/paravirt.h> __visible void __native_queued_spin_unlock(struct qspinlock *lock) { native_queued_spin_unlock(lock); } PV_CALLEE_SAVE_REGS_THUNK(__native_queued_spin_unlock); bool pv_is_native_spin_unlock(void) { return pv_lock_ops.queued_spin_unlock.func == __raw_callee_save___native_queued_spin_unlock; } struct pv_lock_ops pv_lock_ops = { #ifdef CONFIG_SMP .queued_spin_lock_slowpath = native_queued_spin_lock_slowpath, .queued_spin_unlock = PV_CALLEE_SAVE(__native_queued_spin_unlock), .wait = paravirt_nop, .kick = paravirt_nop, #endif /* SMP */ }; EXPORT_SYMBOL(pv_lock_ops); struct static_key paravirt_ticketlocks_enabled = STATIC_KEY_INIT_FALSE; EXPORT_SYMBOL(paravirt_ticketlocks_enabled);