cregit-Linux how code gets into the kernel

Release 4.14 arch/powerpc/kvm/book3s_hv.c

Directory: arch/powerpc/kvm
/*
 * Copyright 2011 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
 * Copyright (C) 2009. SUSE Linux Products GmbH. All rights reserved.
 *
 * Authors:
 *    Paul Mackerras <paulus@au1.ibm.com>
 *    Alexander Graf <agraf@suse.de>
 *    Kevin Wolf <mail@kevin-wolf.de>
 *
 * Description: KVM functions specific to running on Book 3S
 * processors in hypervisor mode (specifically POWER7 and later).
 *
 * This file is derived from arch/powerpc/kvm/book3s.c,
 * by Alexander Graf <agraf@suse.de>.
 *
 * 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.
 */

#include <linux/kvm_host.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/preempt.h>
#include <linux/sched/signal.h>
#include <linux/sched/stat.h>
#include <linux/delay.h>
#include <linux/export.h>
#include <linux/fs.h>
#include <linux/anon_inodes.h>
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/spinlock.h>
#include <linux/page-flags.h>
#include <linux/srcu.h>
#include <linux/miscdevice.h>
#include <linux/debugfs.h>
#include <linux/gfp.h>
#include <linux/vmalloc.h>
#include <linux/highmem.h>
#include <linux/hugetlb.h>
#include <linux/kvm_irqfd.h>
#include <linux/irqbypass.h>
#include <linux/module.h>
#include <linux/compiler.h>
#include <linux/of.h>

#include <asm/reg.h>
#include <asm/ppc-opcode.h>
#include <asm/disassemble.h>
#include <asm/cputable.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/kvm_ppc.h>
#include <asm/kvm_book3s.h>
#include <asm/mmu_context.h>
#include <asm/lppaca.h>
#include <asm/processor.h>
#include <asm/cputhreads.h>
#include <asm/page.h>
#include <asm/hvcall.h>
#include <asm/switch_to.h>
#include <asm/smp.h>
#include <asm/dbell.h>
#include <asm/hmi.h>
#include <asm/pnv-pci.h>
#include <asm/mmu.h>
#include <asm/opal.h>
#include <asm/xics.h>
#include <asm/xive.h>

#include "book3s.h"


#define CREATE_TRACE_POINTS
#include "trace_hv.h"

/* #define EXIT_DEBUG */
/* #define EXIT_DEBUG_SIMPLE */
/* #define EXIT_DEBUG_INT */

/* Used to indicate that a guest page fault needs to be handled */

#define RESUME_PAGE_FAULT	(RESUME_GUEST | RESUME_FLAG_ARCH1)
/* Used to indicate that a guest passthrough interrupt needs to be handled */

#define RESUME_PASSTHROUGH	(RESUME_GUEST | RESUME_FLAG_ARCH2)

/* Used as a "null" value for timebase values */

#define TB_NIL	(~(u64)0)

static DECLARE_BITMAP(default_enabled_hcalls, MAX_HCALL_OPCODE/4 + 1);


static int dynamic_mt_modes = 6;
module_param(dynamic_mt_modes, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(dynamic_mt_modes, "Set of allowed dynamic micro-threading modes: 0 (= none), 2, 4, or 6 (= 2 or 4)");

static int target_smt_mode;
module_param(target_smt_mode, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(target_smt_mode, "Target threads per core (0 = max)");

#ifdef CONFIG_KVM_XICS

static struct kernel_param_ops module_param_ops = {
	.set = param_set_int,
	.get = param_get_int,
};

module_param_cb(kvm_irq_bypass, &module_param_ops, &kvm_irq_bypass,
							S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(kvm_irq_bypass, "Bypass passthrough interrupt optimization");

module_param_cb(h_ipi_redirect, &module_param_ops, &h_ipi_redirect,
							S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(h_ipi_redirect, "Redirect H_IPI wakeup to a free host core");
#endif

static void kvmppc_end_cede(struct kvm_vcpu *vcpu);
static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu);


static inline struct kvm_vcpu *next_runnable_thread(struct kvmppc_vcore *vc, int *ip) { int i = *ip; struct kvm_vcpu *vcpu; while (++i < MAX_SMT_THREADS) { vcpu = READ_ONCE(vc->runnable_threads[i]); if (vcpu) { *ip = i; return vcpu; } } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Suraj Jitindar Singh67100.00%1100.00%
Total67100.00%1100.00%

/* Used to traverse the list of runnable threads for a given vcore */ #define for_each_runnable_thread(i, vcpu, vc) \ for (i = -1; (vcpu = next_runnable_thread(vc, &i)); )
static bool kvmppc_ipi_thread(int cpu) { unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER); /* On POWER9 we can use msgsnd to IPI any cpu */ if (cpu_has_feature(CPU_FTR_ARCH_300)) { msg |= get_hard_smp_processor_id(cpu); smp_mb(); __asm__ __volatile__ (PPC_MSGSND(%0) : : "r" (msg)); return true; } /* On POWER8 for IPIs to threads in the same core, use msgsnd */ if (cpu_has_feature(CPU_FTR_ARCH_207S)) { preempt_disable(); if (cpu_first_thread_sibling(cpu) == cpu_first_thread_sibling(smp_processor_id())) { msg |= cpu_thread_in_core(cpu); smp_mb(); __asm__ __volatile__ (PPC_MSGSND(%0) : : "r" (msg)); preempt_enable(); return true; } preempt_enable(); } #if defined(CONFIG_PPC_ICP_NATIVE) && defined(CONFIG_SMP) if (cpu >= 0 && cpu < nr_cpu_ids) { if (paca[cpu].kvm_hstate.xics_phys) { xics_wake_cpu(cpu); return true; } opal_int_set_mfrr(get_hard_smp_processor_id(cpu), IPI_PRIORITY); return true; } #endif return false; }

Contributors

PersonTokensPropCommitsCommitProp
Paul Mackerras156100.00%3100.00%
Total156100.00%3100.00%


static void kvmppc_fast_vcpu_kick_hv(struct kvm_vcpu *vcpu) { int cpu; struct swait_queue_head *wqp; wqp = kvm_arch_vcpu_wq(vcpu); if (swq_has_sleeper(wqp)) { swake_up(wqp); ++vcpu->stat.halt_wakeup; } cpu = READ_ONCE(vcpu->arch.thread_cpu); if (cpu >= 0 && kvmppc_ipi_thread(cpu)) return; /* CPU points to the first thread of the core */ cpu = vcpu->cpu; if (cpu >= 0 && cpu < nr_cpu_ids && cpu_online(cpu)) smp_send_reschedule(cpu); }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt5859.79%114.29%
Paul Mackerras3334.02%342.86%
Marcelo Tosatti33.09%114.29%
Aneesh Kumar K.V22.06%114.29%
Davidlohr Bueso A11.03%114.29%
Total97100.00%7100.00%

/* * We use the vcpu_load/put functions to measure stolen time. * Stolen time is counted as time when either the vcpu is able to * run as part of a virtual core, but the task running the vcore * is preempted or sleeping, or when the vcpu needs something done * in the kernel by the task running the vcpu, but that task is * preempted or sleeping. Those two things have to be counted * separately, since one of the vcpu tasks will take on the job * of running the core, and the other vcpu tasks in the vcore will * sleep waiting for it to do that, but that sleep shouldn't count * as stolen time. * * Hence we accumulate stolen time when the vcpu can run as part of * a vcore using vc->stolen_tb, and the stolen time when the vcpu * needs its task to do other things in the kernel (for example, * service a page fault) in busy_stolen. We don't accumulate * stolen time for a vcore when it is inactive, or for a vcpu * when it is in state RUNNING or NOTREADY. NOTREADY is a bit of * a misnomer; it means that the vcpu task is not executing in * the KVM_VCPU_RUN ioctl, i.e. it is in userspace or elsewhere in * the kernel. We don't have any way of dividing up that time * between time that the vcpu is genuinely stopped, time that * the task is actively working on behalf of the vcpu, and time * that the task is preempted, so we don't count any of it as * stolen. * * Updates to busy_stolen are protected by arch.tbacct_lock; * updates to vc->stolen_tb are protected by the vcore->stoltb_lock * lock. The stolen times are measured in units of timebase ticks. * (Note that the != TB_NIL checks below are purely defensive; * they should never fail.) */
static void kvmppc_core_start_stolen(struct kvmppc_vcore *vc) { unsigned long flags; spin_lock_irqsave(&vc->stoltb_lock, flags); vc->preempt_tb = mftb(); spin_unlock_irqrestore(&vc->stoltb_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Paul Mackerras4197.62%583.33%
Aneesh Kumar K.V12.38%116.67%
Total42100.00%6100.00%


static void kvmppc_core_end_stolen(struct kvmppc_vcore *vc) { unsigned long flags; spin_lock_irqsave(&vc->stoltb_lock, flags); if (vc->preempt_tb != TB_NIL) { vc->stolen_tb += mftb() - vc->preempt_tb; vc->preempt_tb = TB_NIL; } spin_unlock_irqrestore(&vc->stoltb_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Paul Mackerras62100.00%5100.00%
Total62100.00%5100.00%


static void kvmppc_core_vcpu_load_hv(struct kvm_vcpu *vcpu, int cpu) { struct kvmppc_vcore *vc = vcpu->arch.vcore; unsigned long flags; /* * We can test vc->runner without taking the vcore lock, * because only this task ever sets vc->runner to this * vcpu, and once it is set to this vcpu, only this task * ever sets it to NULL. */ if (vc->runner == vcpu && vc->vcore_state >= VCORE_SLEEPING) kvmppc_core_end_stolen(vc); spin_lock_irqsave(&vcpu->arch.tbacct_lock, flags); if (vcpu->arch.state == KVMPPC_VCPU_BUSY_IN_HOST && vcpu->arch.busy_preempt != TB_NIL) { vcpu->arch.busy_stolen += mftb() - vcpu->arch.busy_preempt; vcpu->arch.busy_preempt = TB_NIL; } spin_unlock_irqrestore(&vcpu->arch.tbacct_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Paul Mackerras116100.00%5100.00%
Total116100.00%5100.00%


static void kvmppc_core_vcpu_put_hv(struct kvm_vcpu *vcpu) { struct kvmppc_vcore *vc = vcpu->arch.vcore; unsigned long flags; if (vc->runner == vcpu && vc->vcore_state >= VCORE_SLEEPING) kvmppc_core_start_stolen(vc); spin_lock_irqsave(&vcpu->arch.tbacct_lock, flags); if (vcpu->arch.state == KVMPPC_VCPU_BUSY_IN_HOST) vcpu->arch.busy_preempt = mftb(); spin_unlock_irqrestore(&vcpu->arch.tbacct_lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Paul Mackerras8697.73%685.71%
Aneesh Kumar K.V22.27%114.29%
Total88100.00%7100.00%


static void kvmppc_set_msr_hv(struct kvm_vcpu *vcpu, u64 msr) { /* * Check for illegal transactional state bit combination * and if we find it, force the TS field to a safe state. */ if ((msr & MSR_TS_MASK) == MSR_TS_MASK) msr &= ~MSR_TS_MASK; vcpu->arch.shregs.msr = msr; kvmppc_end_cede(vcpu); }

Contributors

PersonTokensPropCommitsCommitProp
Paul Mackerras4395.56%375.00%
Aneesh Kumar K.V24.44%125.00%
Total45100.00%4100.00%


static void kvmppc_set_pvr_hv(struct kvm_vcpu *vcpu, u32 pvr) { vcpu->arch.pvr = pvr; }

Contributors

PersonTokensPropCommitsCommitProp
Paul Mackerras2090.91%133.33%
Thomas Huth14.55%133.33%
Aneesh Kumar K.V14.55%133.33%
Total22100.00%3100.00%

/* Dummy value used in computing PCR value below */ #define PCR_ARCH_300 (PCR_ARCH_207 << 1)
static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat) { unsigned long host_pcr_bit = 0, guest_pcr_bit = 0; struct kvmppc_vcore *vc = vcpu->arch.vcore; /* We can (emulate) our own architecture version and anything older */ if (cpu_has_feature(CPU_FTR_ARCH_300)) host_pcr_bit = PCR_ARCH_300; else if (cpu_has_feature(CPU_FTR_ARCH_207S)) host_pcr_bit = PCR_ARCH_207; else if (cpu_has_feature(CPU_FTR_ARCH_206)) host_pcr_bit = PCR_ARCH_206; else host_pcr_bit = PCR_ARCH_205; /* Determine lowest PCR bit needed to run guest in given PVR level */ guest_pcr_bit = host_pcr_bit; if (arch_compat) { switch (arch_compat) { case PVR_ARCH_205: guest_pcr_bit = PCR_ARCH_205; break; case PVR_ARCH_206: case PVR_ARCH_206p: guest_pcr_bit = PCR_ARCH_206; break; case PVR_ARCH_207: guest_pcr_bit = PCR_ARCH_207; break; case PVR_ARCH_300: guest_pcr_bit = PCR_ARCH_300; break; default: return -EINVAL; } } /* Check requested PCR bits don't exceed our capabilities */ if (guest_pcr_bit > host_pcr_bit) return -EINVAL; spin_lock(&vc->lock); vc->arch_compat = arch_compat; /* Set all PCR bits for which guest_pcr_bit <= bit < host_pcr_bit */ vc->pcr = host_pcr_bit - guest_pcr_bit; spin_unlock(&vc->lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Paul Mackerras10357.87%250.00%
Suraj Jitindar Singh7441.57%125.00%
Thomas Huth10.56%125.00%
Total178100.00%4100.00%


static void kvmppc_dump_regs(struct kvm_vcpu *vcpu) { int r; pr_err("vcpu %p (%d):\n", vcpu, vcpu->vcpu_id); pr_err("pc = %.16lx msr = %.16llx trap = %x\n", vcpu->arch.pc, vcpu->arch.shregs.msr, vcpu->arch.trap); for (r = 0; r < 16; ++r) pr_err("r%2d = %.16lx r%d = %.16lx\n", r, kvmppc_get_gpr(vcpu, r), r+16, kvmppc_get_gpr(vcpu, r+16)); pr_err("ctr = %.16lx lr = %.16lx\n", vcpu->arch.ctr, vcpu->arch.lr); pr_err("srr0 = %.16llx srr1 = %.16llx\n", vcpu->arch.shregs.srr0, vcpu->arch.shregs.srr1); pr_err("sprg0 = %.16llx sprg1 = %.16llx\n", vcpu->arch.shregs.sprg0, vcpu->arch.shregs.sprg1); pr_err("sprg2 = %.16llx sprg3 = %.16llx\n", vcpu->arch.shregs.sprg2, vcpu->arch.shregs.sprg3); pr_err("cr = %.8x xer = %.16lx dsisr = %.8x\n", vcpu->arch.cr, vcpu->arch.xer, vcpu->arch.shregs.dsisr); pr_err("dar = %.16llx\n", vcpu->arch.shregs.dar); pr_err("fault dar = %.16lx dsisr = %.8x\n", vcpu->arch.fault_dar, vcpu->arch.fault_dsisr); pr_err("SLB (%d entries):\n", vcpu->arch.slb_max); for (r = 0; r < vcpu->arch.slb_max; ++r) pr_err(" ESID = %.16llx VSID = %.16llx\n", vcpu->arch.slb[r].orige, vcpu->arch.slb[r].origv); pr_err("lpcr = %.16lx sdr1 = %.16lx last_inst = %.8x\n", vcpu->arch.vcore->lpcr, vcpu->kvm->arch.sdr1, vcpu->arch.last_inst); }

Contributors

PersonTokensPropCommitsCommitProp
Paul Mackerras30699.67%266.67%
Thomas Huth10.33%133.33%
Total307100.00%3100.00%


static struct kvm_vcpu *kvmppc_find_vcpu(struct kvm *kvm, int id) { struct kvm_vcpu *ret; mutex_lock(&kvm->lock); ret = kvm_get_vcpu_by_id(kvm, id); mutex_unlock(&kvm->lock); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Paul Mackerras4387.76%133.33%
David Hildenbrand510.20%133.33%
Thomas Huth12.04%133.33%
Total49100.00%3100.00%


static void init_vpa(struct kvm_vcpu *vcpu, struct lppaca *vpa) { vpa->__old_status |= LPPACA_OLD_SHARED_PROC; vpa->yield_count = cpu_to_be32(1); }

Contributors

PersonTokensPropCommitsCommitProp
Paul Mackerras2580.65%133.33%
Alexander Graf39.68%133.33%
Anton Blanchard39.68%133.33%
Total31100.00%3100.00%


static int set_vpa(struct kvm_vcpu *vcpu, struct kvmppc_vpa *v, unsigned long addr, unsigned long len) { /* check address is cacheline aligned */ if (addr & (L1_CACHE_BYTES - 1)) return -EINVAL; spin_lock(&vcpu->arch.vpa_update_lock); if (v->next_gpa != addr || v->len != len) { v->next_gpa = addr; v->len = addr ? len : 0; v->update_pending = 1; } spin_unlock(&vcpu->arch.vpa_update_lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Paul Mackerras100100.00%1100.00%
Total100100.00%1100.00%

/* Length for a per-processor buffer is passed in at offset 4 in the buffer */ struct reg_vpa { u32 dummy; union { __be16 hword; __be32 word; } length; };
static int vpa_is_registered(struct kvmppc_vpa *vpap) { if (vpap->update_pending) return vpap->next_gpa != 0; return vpap->pinned_addr != NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Paul Mackerras31100.00%1100.00%
Total31100.00%1100.00%


static unsigned long do_h_register_vpa(struct kvm_vcpu *vcpu, unsigned long flags, unsigned long vcpuid, unsigned long vpa) { struct kvm *kvm = vcpu->kvm; unsigned long len, nb; void *va; struct kvm_vcpu *tvcpu; int err; int subfunc; struct kvmppc_vpa *vpap; tvcpu = kvmppc_find_vcpu(kvm, vcpuid); if (!tvcpu) return H_PARAMETER; subfunc = (flags >> H_VPA_FUNC_SHIFT) & H_VPA_FUNC_MASK; if (subfunc == H_VPA_REG_VPA || subfunc == H_VPA_REG_DTL || subfunc == H_VPA_REG_SLB) { /* Registering new area - address must be cache-line aligned */ if ((vpa & (L1_CACHE_BYTES - 1)) || !vpa) return H_PARAMETER; /* convert logical addr to kernel addr and read length */ va = kvmppc_pin_guest_page(kvm, vpa, &nb); if (va == NULL) return H_PARAMETER; if (subfunc == H_VPA_REG_VPA) len = be16_to_cpu(((struct reg_vpa *)va)->length.hword); else len = be32_to_cpu(((struct reg_vpa *)va)->length.word); kvmppc_unpin_guest_page(kvm, va, vpa, false); /* Check length */ if (len > nb || len < sizeof(struct reg_vpa)) return H_PARAMETER; } else { vpa = 0; len = 0; } err = H_PARAMETER; vpap = NULL; spin_lock(&tvcpu->arch.vpa_update_lock); switch (subfunc) { case H_VPA_REG_VPA: /* register VPA */ /* * The size of our lppaca is 1kB because of the way we align * it for the guest to avoid crossing a 4kB boundary. We only * use 640 bytes of the structure though, so we should accept * clients that set a size of 640. */ if (len < 640) break; vpap = &tvcpu->arch.vpa; err = 0; break; case H_VPA_REG_DTL: /* register DTL */ if (len < sizeof(struct dtl_entry)) break; len -= len % sizeof(struct dtl_entry); /* Check that they have previously registered a VPA */ err = H_RESOURCE; if (!vpa_is_registered(&tvcpu->arch.vpa)) break; vpap = &tvcpu->arch.dtl; err = 0; break; case H_VPA_REG_SLB: /* register SLB shadow buffer */ /* Check that they have previously registered a VPA */ err = H_RESOURCE; if (!vpa_is_registered(&tvcpu->arch.vpa)) break; vpap = &tvcpu->arch.slb_shadow; err = 0; break; case H_VPA_DEREG_VPA: /* deregister VPA */ /* Check they don't still have a DTL or SLB buf registered */ err = H_RESOURCE; if (vpa_is_registered(&tvcpu->arch.dtl) || vpa_is_registered(&tvcpu->arch.slb_shadow)) break; vpap = &tvcpu->arch.vpa; err = 0; break; case H_VPA_DEREG_DTL: /* deregister DTL */ vpap = &tvcpu->arch.dtl; err = 0; break; case H_VPA_DEREG_SLB: /* deregister SLB shadow buffer */ vpap = &tvcpu->arch.slb_shadow; err = 0; break; } if (vpap) { vpap->next_gpa = vpa; vpap->len = len; vpap->update_pending = 1; } spin_unlock(&tvcpu->arch.vpa_update_lock); return err; }

Contributors

PersonTokensPropCommitsCommitProp
Paul Mackerras48298.37%571.43%
Alexander Graf61.22%114.29%
Nicholas Piggin20.41%114.29%
Total490100.00%7100.00%


static void kvmppc_update_vpa(struct kvm_vcpu *vcpu, struct kvmppc_vpa *vpap) { struct kvm *kvm = vcpu->kvm; void *va; unsigned long nb; unsigned long gpa; /* * We need to pin the page pointed to by vpap->next_gpa, * but we can't call kvmppc_pin_guest_page under the lock * as it does get_user_pages() and down_read(). So we * have to drop the lock, pin the page, then get the lock * again and check that a new area didn't get registered * in the meantime. */ for (;;) { gpa = vpap->next_gpa; spin_unlock(&vcpu->arch.vpa_update_lock); va = NULL; nb = 0; if (gpa) va = kvmppc_pin_guest_page(kvm, gpa, &nb); spin_lock(&vcpu->arch.vpa_update_lock); if (gpa == vpap->next_gpa) break; /* sigh... unpin that one and try again */ if (va) kvmppc_unpin_guest_page(kvm, va, gpa, false); } vpap->update_pending = 0; if (va && nb < vpap->len) { /* * If it's now too short, it must be that userspace * has changed the mappings underlying guest memory, * so unregister the region. */ kvmppc_unpin_guest_page(kvm, va, gpa, false); va = NULL; } if (vpap->pinned_addr) kvmppc_unpin_guest_page(kvm, vpap->pinned_addr, vpap->gpa, vpap->dirty); vpap->gpa = gpa; vpap->pinned_addr = va; vpap->dirty = false; if (va) vpap->pinned_end = va + vpap->len; }

Contributors

PersonTokensPropCommitsCommitProp
Paul Mackerras209100.00%6100.00%
Total209100.00%6100.00%


static void kvmppc_update_vpas(struct kvm_vcpu *vcpu) { if (!(vcpu->arch.vpa.update_pending || vcpu->arch.slb_shadow.update_pending || vcpu->arch.dtl.update_pending)) return; spin_lock(&vcpu->arch.vpa_update_lock); if (vcpu->arch.vpa.update_pending) { kvmppc_update_vpa(vcpu, &vcpu->arch.vpa); if (vcpu->arch.vpa.pinned_addr) init_vpa(vcpu, vcpu->arch.vpa.pinned_addr); } if (vcpu->arch.dtl.update_pending) { kvmppc_update_vpa(vcpu, &vcpu->arch.dtl); vcpu->arch.dtl_ptr = vcpu->arch.dtl.pinned_addr; vcpu->arch.dtl_index = 0; } if (vcpu->arch.slb_shadow.update_pending) kvmppc_update_vpa(vcpu, &vcpu->arch.slb_shadow); spin_unlock(&vcpu->arch.vpa_update_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Paul Mackerras176100.00%6100.00%
Total176100.00%6100.00%

/* * Return the accumulated stolen time for the vcore up until `now'. * The caller should hold the vcore lock. */
static u64 vcore_stolen_time(struct kvmppc_vcore *vc, u64 now) { u64 p; unsigned long flags; spin_lock_irqsave(&vc->stoltb_lock, flags); p = vc->stolen_tb; if (vc->vcore_state != VCORE_INACTIVE && vc->preempt_tb != TB_NIL) p += now - vc->preempt_tb; spin_unlock_irqrestore(&vc->stoltb_lock, flags); return p; }

Contributors

PersonTokensPropCommitsCommitProp
Paul Mackerras72100.00%2100.00%
Total72100.00%2100.00%


static void kvmppc_create_dtl_entry(struct kvm_vcpu *vcpu, struct kvmppc_vcore *vc) { struct dtl_entry *dt; struct lppaca *vpa; unsigned long stolen; unsigned long core_stolen; u64 now; unsigned long flags; dt = vcpu->arch.dtl_ptr; vpa = vcpu->arch.vpa.pinned_addr; now = mftb(); core_stolen = vcore_stolen_time(vc, now); stolen = core_stolen - vcpu->arch.stolen_logged; vcpu->arch.stolen_logged = core_stolen; spin_lock_irqsave(&vcpu->arch.tbacct_lock, flags); stolen += vcpu->arch.busy_stolen; vcpu->arch.busy_stolen = 0; spin_unlock_irqrestore(&vcpu->arch.tbacct_lock, flags); if (!dt || !vpa) return; memset(dt, 0, sizeof(struct dtl_entry)); dt->dispatch_re