summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2026-04-13 11:46:11 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2026-04-13 11:46:11 +0200
commit05578316ca7246b45fb7d9eaf81308c0e0f3ee10 (patch)
tree04d0c6681e843ca032ff48a71413b04926d2d8bd /arch
parentd880d2a9c694b616ccd3ba4c966275fe52e27fc3 (diff)
parente47b8e1db9a9bbef6765e85b11e87f48e6b56846 (diff)
downloadlinux-next-05578316ca7246b45fb7d9eaf81308c0e0f3ee10.tar.gz
linux-next-05578316ca7246b45fb7d9eaf81308c0e0f3ee10.zip
Merge tag 'loongarch-kvm-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson into HEAD
LoongArch KVM changes for v7.1 1. Use CSR_CRMD_PLV in kvm_arch_vcpu_in_kernel(). 2. Let vcpu_is_preempted() a macro & some enhanments. 3. Add DMSINTC irqchip in kernel support. 4. Add KVM PMU test cases for tools/selftests.
Diffstat (limited to 'arch')
-rw-r--r--arch/loongarch/include/asm/kvm_dmsintc.h27
-rw-r--r--arch/loongarch/include/asm/kvm_host.h3
-rw-r--r--arch/loongarch/include/asm/kvm_pch_pic.h3
-rw-r--r--arch/loongarch/include/asm/qspinlock.h26
-rw-r--r--arch/loongarch/include/uapi/asm/kvm.h4
-rw-r--r--arch/loongarch/kernel/paravirt.c16
-rw-r--r--arch/loongarch/kvm/Makefile1
-rw-r--r--arch/loongarch/kvm/intc/dmsintc.c182
-rw-r--r--arch/loongarch/kvm/intc/pch_pic.c15
-rw-r--r--arch/loongarch/kvm/interrupt.c2
-rw-r--r--arch/loongarch/kvm/irqfd.c10
-rw-r--r--arch/loongarch/kvm/main.c14
-rw-r--r--arch/loongarch/kvm/vcpu.c29
13 files changed, 289 insertions, 43 deletions
diff --git a/arch/loongarch/include/asm/kvm_dmsintc.h b/arch/loongarch/include/asm/kvm_dmsintc.h
new file mode 100644
index 000000000000..5a71b9ccbe78
--- /dev/null
+++ b/arch/loongarch/include/asm/kvm_dmsintc.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2025 Loongson Technology Corporation Limited
+ */
+
+#ifndef __ASM_KVM_DMSINTC_H
+#define __ASM_KVM_DMSINTC_H
+
+#include <linux/kvm_types.h>
+
+struct loongarch_dmsintc {
+ struct kvm *kvm;
+ uint64_t msg_addr_base;
+ uint64_t msg_addr_size;
+ uint32_t cpu_mask;
+};
+
+struct dmsintc_state {
+ atomic64_t vector_map[4];
+};
+
+int kvm_loongarch_register_dmsintc_device(void);
+void dmsintc_inject_irq(struct kvm_vcpu *vcpu);
+int dmsintc_set_irq(struct kvm *kvm, u64 addr, int data, int level);
+int dmsintc_deliver_msi_to_vcpu(struct kvm *kvm, struct kvm_vcpu *vcpu, u32 vector, int level);
+
+#endif
diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
index 19eb5e5c3984..130cedbb6b39 100644
--- a/arch/loongarch/include/asm/kvm_host.h
+++ b/arch/loongarch/include/asm/kvm_host.h
@@ -20,6 +20,7 @@
#include <asm/inst.h>
#include <asm/kvm_mmu.h>
#include <asm/kvm_ipi.h>
+#include <asm/kvm_dmsintc.h>
#include <asm/kvm_eiointc.h>
#include <asm/kvm_pch_pic.h>
#include <asm/loongarch.h>
@@ -133,6 +134,7 @@ struct kvm_arch {
s64 time_offset;
struct kvm_context __percpu *vmcs;
struct loongarch_ipi *ipi;
+ struct loongarch_dmsintc *dmsintc;
struct loongarch_eiointc *eiointc;
struct loongarch_pch_pic *pch_pic;
};
@@ -247,6 +249,7 @@ struct kvm_vcpu_arch {
struct kvm_mp_state mp_state;
/* ipi state */
struct ipi_state ipi_state;
+ struct dmsintc_state dmsintc_state;
/* cpucfg */
u32 cpucfg[KVM_MAX_CPUCFG_REGS];
diff --git a/arch/loongarch/include/asm/kvm_pch_pic.h b/arch/loongarch/include/asm/kvm_pch_pic.h
index 7f33a3039272..e74b3b742634 100644
--- a/arch/loongarch/include/asm/kvm_pch_pic.h
+++ b/arch/loongarch/include/asm/kvm_pch_pic.h
@@ -68,8 +68,9 @@ struct loongarch_pch_pic {
uint64_t pch_pic_base;
};
+struct kvm_kernel_irq_routing_entry;
int kvm_loongarch_register_pch_pic_device(void);
void pch_pic_set_irq(struct loongarch_pch_pic *s, int irq, int level);
-void pch_msi_set_irq(struct kvm *kvm, int irq, int level);
+int pch_msi_set_irq(struct kvm *kvm, struct kvm_kernel_irq_routing_entry *e, int level);
#endif /* __ASM_KVM_PCH_PIC_H */
diff --git a/arch/loongarch/include/asm/qspinlock.h b/arch/loongarch/include/asm/qspinlock.h
index 66244801db67..0ee15b3b3937 100644
--- a/arch/loongarch/include/asm/qspinlock.h
+++ b/arch/loongarch/include/asm/qspinlock.h
@@ -2,11 +2,13 @@
#ifndef _ASM_LOONGARCH_QSPINLOCK_H
#define _ASM_LOONGARCH_QSPINLOCK_H
+#include <asm/kvm_para.h>
#include <linux/jump_label.h>
#ifdef CONFIG_PARAVIRT
-
+DECLARE_STATIC_KEY_FALSE(virt_preempt_key);
DECLARE_STATIC_KEY_FALSE(virt_spin_lock_key);
+DECLARE_PER_CPU(struct kvm_steal_time, steal_time);
#define virt_spin_lock virt_spin_lock
@@ -34,9 +36,25 @@ __retry:
return true;
}
-#define vcpu_is_preempted vcpu_is_preempted
-
-bool vcpu_is_preempted(int cpu);
+/*
+ * Macro is better than inline function here
+ * With macro, parameter cpu is parsed only when it is used.
+ * With inline function, parameter cpu is parsed even though it is not used.
+ * This may cause cache line thrashing across NUMA nodes.
+ */
+#define vcpu_is_preempted(cpu) \
+({ \
+ bool __val; \
+ \
+ if (!static_branch_unlikely(&virt_preempt_key)) \
+ __val = false; \
+ else { \
+ struct kvm_steal_time *src; \
+ src = &per_cpu(steal_time, cpu); \
+ __val = !!(READ_ONCE(src->preempted) & KVM_VCPU_PREEMPTED); \
+ } \
+ __val; \
+})
#endif /* CONFIG_PARAVIRT */
diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h
index 419647aacdf3..cd0b5c11ca9c 100644
--- a/arch/loongarch/include/uapi/asm/kvm.h
+++ b/arch/loongarch/include/uapi/asm/kvm.h
@@ -155,4 +155,8 @@ struct kvm_iocsr_entry {
#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL 0x40000006
#define KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT 0
+#define KVM_DEV_LOONGARCH_DMSINTC_GRP_CTRL 0x40000007
+#define KVM_DEV_LOONGARCH_DMSINTC_MSG_ADDR_BASE 0x0
+#define KVM_DEV_LOONGARCH_DMSINTC_MSG_ADDR_SIZE 0x1
+
#endif /* __UAPI_ASM_LOONGARCH_KVM_H */
diff --git a/arch/loongarch/kernel/paravirt.c b/arch/loongarch/kernel/paravirt.c
index b74fe6db49ab..10821cce554c 100644
--- a/arch/loongarch/kernel/paravirt.c
+++ b/arch/loongarch/kernel/paravirt.c
@@ -10,9 +10,9 @@
#include <asm/paravirt.h>
static int has_steal_clock;
-static DEFINE_PER_CPU(struct kvm_steal_time, steal_time) __aligned(64);
-static DEFINE_STATIC_KEY_FALSE(virt_preempt_key);
+DEFINE_STATIC_KEY_FALSE(virt_preempt_key);
DEFINE_STATIC_KEY_FALSE(virt_spin_lock_key);
+DEFINE_PER_CPU(struct kvm_steal_time, steal_time) __aligned(64);
static bool steal_acc = true;
@@ -260,18 +260,6 @@ static int pv_time_cpu_down_prepare(unsigned int cpu)
return 0;
}
-
-bool vcpu_is_preempted(int cpu)
-{
- struct kvm_steal_time *src;
-
- if (!static_branch_unlikely(&virt_preempt_key))
- return false;
-
- src = &per_cpu(steal_time, cpu);
- return !!(src->preempted & KVM_VCPU_PREEMPTED);
-}
-EXPORT_SYMBOL(vcpu_is_preempted);
#endif
static void pv_cpu_reboot(void *unused)
diff --git a/arch/loongarch/kvm/Makefile b/arch/loongarch/kvm/Makefile
index cb41d9265662..ae469edec99c 100644
--- a/arch/loongarch/kvm/Makefile
+++ b/arch/loongarch/kvm/Makefile
@@ -17,6 +17,7 @@ kvm-y += tlb.o
kvm-y += vcpu.o
kvm-y += vm.o
kvm-y += intc/ipi.o
+kvm-y += intc/dmsintc.o
kvm-y += intc/eiointc.o
kvm-y += intc/pch_pic.o
kvm-y += irqfd.o
diff --git a/arch/loongarch/kvm/intc/dmsintc.c b/arch/loongarch/kvm/intc/dmsintc.c
new file mode 100644
index 000000000000..de25735ce039
--- /dev/null
+++ b/arch/loongarch/kvm/intc/dmsintc.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 Loongson Technology Corporation Limited
+ */
+
+#include <linux/kvm_host.h>
+#include <asm/kvm_csr.h>
+#include <asm/kvm_dmsintc.h>
+#include <asm/kvm_vcpu.h>
+
+void dmsintc_inject_irq(struct kvm_vcpu *vcpu)
+{
+ unsigned int i;
+ unsigned long vector[4], old;
+ struct dmsintc_state *ds = &vcpu->arch.dmsintc_state;
+
+ if (!ds)
+ return;
+
+ for (i = 0; i < 4; i++) {
+ old = atomic64_read(&(ds->vector_map[i]));
+ if (old)
+ vector[i] = atomic64_xchg(&(ds->vector_map[i]), 0);
+ }
+
+ if (vector[0]) {
+ old = kvm_read_hw_gcsr(LOONGARCH_CSR_ISR0);
+ kvm_write_hw_gcsr(LOONGARCH_CSR_ISR0, vector[0] | old);
+ }
+
+ if (vector[1]) {
+ old = kvm_read_hw_gcsr(LOONGARCH_CSR_ISR1);
+ kvm_write_hw_gcsr(LOONGARCH_CSR_ISR1, vector[1] | old);
+ }
+
+ if (vector[2]) {
+ old = kvm_read_hw_gcsr(LOONGARCH_CSR_ISR2);
+ kvm_write_hw_gcsr(LOONGARCH_CSR_ISR2, vector[2] | old);
+ }
+
+ if (vector[3]) {
+ old = kvm_read_hw_gcsr(LOONGARCH_CSR_ISR3);
+ kvm_write_hw_gcsr(LOONGARCH_CSR_ISR3, vector[3] | old);
+ }
+}
+
+int dmsintc_deliver_msi_to_vcpu(struct kvm *kvm,
+ struct kvm_vcpu *vcpu, u32 vector, int level)
+{
+ struct kvm_interrupt vcpu_irq;
+ struct dmsintc_state *ds = &vcpu->arch.dmsintc_state;
+
+ if (!level)
+ return 0;
+ if (!vcpu || vector >= 256)
+ return -EINVAL;
+ if (!ds)
+ return -ENODEV;
+
+ vcpu_irq.irq = INT_AVEC;
+ set_bit(vector, (unsigned long *)&ds->vector_map);
+ kvm_vcpu_ioctl_interrupt(vcpu, &vcpu_irq);
+ kvm_vcpu_kick(vcpu);
+
+ return 0;
+}
+
+int dmsintc_set_irq(struct kvm *kvm, u64 addr, int data, int level)
+{
+ unsigned int irq, cpu;
+ struct kvm_vcpu *vcpu;
+
+ irq = (addr >> AVEC_IRQ_SHIFT) & AVEC_IRQ_MASK;
+ cpu = (addr >> AVEC_CPU_SHIFT) & kvm->arch.dmsintc->cpu_mask;
+ if (cpu >= KVM_MAX_VCPUS)
+ return -EINVAL;
+ vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu);
+ if (!vcpu)
+ return -EINVAL;
+
+ return dmsintc_deliver_msi_to_vcpu(kvm, vcpu, irq, level);
+}
+
+static int kvm_dmsintc_ctrl_access(struct kvm_device *dev,
+ struct kvm_device_attr *attr, bool is_write)
+{
+ int addr = attr->attr;
+ unsigned long cpu_bit, val;
+ void __user *data = (void __user *)attr->addr;
+ struct loongarch_dmsintc *s = dev->kvm->arch.dmsintc;
+
+ switch (addr) {
+ case KVM_DEV_LOONGARCH_DMSINTC_MSG_ADDR_BASE:
+ if (is_write) {
+ if (copy_from_user(&val, data, sizeof(s->msg_addr_base)))
+ return -EFAULT;
+ if (s->msg_addr_base)
+ return -EFAULT; /* Duplicate setting are not allowed. */
+ if ((val & (BIT(AVEC_CPU_SHIFT) - 1)) != 0)
+ return -EINVAL;
+ s->msg_addr_base = val;
+ cpu_bit = find_first_bit((unsigned long *)&(s->msg_addr_base), 64) - AVEC_CPU_SHIFT;
+ cpu_bit = min(cpu_bit, AVEC_CPU_BIT);
+ s->cpu_mask = GENMASK(cpu_bit - 1, 0) & AVEC_CPU_MASK;
+ }
+ break;
+ case KVM_DEV_LOONGARCH_DMSINTC_MSG_ADDR_SIZE:
+ if (is_write) {
+ if (copy_from_user(&val, data, sizeof(s->msg_addr_size)))
+ return -EFAULT;
+ if (s->msg_addr_size)
+ return -EFAULT; /*Duplicate setting are not allowed. */
+ s->msg_addr_size = val;
+ }
+ break;
+ default:
+ kvm_err("%s: unknown dmsintc register, addr = %d\n", __func__, addr);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int kvm_dmsintc_set_attr(struct kvm_device *dev,
+ struct kvm_device_attr *attr)
+{
+ switch (attr->group) {
+ case KVM_DEV_LOONGARCH_DMSINTC_GRP_CTRL:
+ return kvm_dmsintc_ctrl_access(dev, attr, true);
+ default:
+ kvm_err("%s: unknown group (%d)\n", __func__, attr->group);
+ return -EINVAL;
+ }
+}
+
+static int kvm_dmsintc_create(struct kvm_device *dev, u32 type)
+{
+ struct kvm *kvm;
+ struct loongarch_dmsintc *s;
+
+ if (!dev) {
+ kvm_err("%s: kvm_device ptr is invalid!\n", __func__);
+ return -EINVAL;
+ }
+
+ kvm = dev->kvm;
+ if (kvm->arch.dmsintc) {
+ kvm_err("%s: LoongArch DMSINTC has already been created!\n", __func__);
+ return -EINVAL;
+ }
+
+ s = kzalloc(sizeof(struct loongarch_dmsintc), GFP_KERNEL);
+ if (!s)
+ return -ENOMEM;
+
+ s->kvm = kvm;
+ kvm->arch.dmsintc = s;
+
+ return 0;
+}
+
+static void kvm_dmsintc_destroy(struct kvm_device *dev)
+{
+
+ if (!dev || !dev->kvm || !dev->kvm->arch.dmsintc)
+ return;
+
+ kfree(dev->kvm->arch.dmsintc);
+ kfree(dev);
+}
+
+static struct kvm_device_ops kvm_dmsintc_dev_ops = {
+ .name = "kvm-loongarch-dmsintc",
+ .create = kvm_dmsintc_create,
+ .destroy = kvm_dmsintc_destroy,
+ .set_attr = kvm_dmsintc_set_attr,
+};
+
+int kvm_loongarch_register_dmsintc_device(void)
+{
+ return kvm_register_device_ops(&kvm_dmsintc_dev_ops, KVM_DEV_TYPE_LOONGARCH_DMSINTC);
+}
diff --git a/arch/loongarch/kvm/intc/pch_pic.c b/arch/loongarch/kvm/intc/pch_pic.c
index dd7e7f8d53db..aa0ed59ae8cf 100644
--- a/arch/loongarch/kvm/intc/pch_pic.c
+++ b/arch/loongarch/kvm/intc/pch_pic.c
@@ -3,6 +3,7 @@
* Copyright (C) 2024 Loongson Technology Corporation Limited
*/
+#include <asm/kvm_dmsintc.h>
#include <asm/kvm_eiointc.h>
#include <asm/kvm_pch_pic.h>
#include <asm/kvm_vcpu.h>
@@ -67,9 +68,19 @@ void pch_pic_set_irq(struct loongarch_pch_pic *s, int irq, int level)
}
/* msi irq handler */
-void pch_msi_set_irq(struct kvm *kvm, int irq, int level)
+int pch_msi_set_irq(struct kvm *kvm, struct kvm_kernel_irq_routing_entry *e, int level)
{
- eiointc_set_irq(kvm->arch.eiointc, irq, level);
+ u64 msg_addr = (((u64)e->msi.address_hi) << 32) | e->msi.address_lo;
+
+ if (cpu_has_msgint && kvm->arch.dmsintc &&
+ msg_addr >= kvm->arch.dmsintc->msg_addr_base &&
+ msg_addr < (kvm->arch.dmsintc->msg_addr_base + kvm->arch.dmsintc->msg_addr_size)) {
+ return dmsintc_set_irq(kvm, msg_addr, e->msi.data, level);
+ }
+
+ eiointc_set_irq(kvm->arch.eiointc, e->msi.data, level);
+
+ return 0;
}
static int loongarch_pch_pic_read(struct loongarch_pch_pic *s, gpa_t addr, int len, void *val)
diff --git a/arch/loongarch/kvm/interrupt.c b/arch/loongarch/kvm/interrupt.c
index fb704f4c8ac5..32930959f7c2 100644
--- a/arch/loongarch/kvm/interrupt.c
+++ b/arch/loongarch/kvm/interrupt.c
@@ -7,6 +7,7 @@
#include <linux/errno.h>
#include <asm/kvm_csr.h>
#include <asm/kvm_vcpu.h>
+#include <asm/kvm_dmsintc.h>
static unsigned int priority_to_irq[EXCCODE_INT_NUM] = {
[INT_TI] = CPU_TIMER,
@@ -33,6 +34,7 @@ static int kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
irq = priority_to_irq[priority];
if (kvm_guest_has_msgint(&vcpu->arch) && (priority == INT_AVEC)) {
+ dmsintc_inject_irq(vcpu);
set_gcsr_estat(irq);
return 1;
}
diff --git a/arch/loongarch/kvm/irqfd.c b/arch/loongarch/kvm/irqfd.c
index 9a39627aecf0..f4f953b22419 100644
--- a/arch/loongarch/kvm/irqfd.c
+++ b/arch/loongarch/kvm/irqfd.c
@@ -29,9 +29,7 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
if (!level)
return -1;
- pch_msi_set_irq(kvm, e->msi.data, level);
-
- return 0;
+ return pch_msi_set_irq(kvm, e, level);
}
/*
@@ -71,13 +69,15 @@ int kvm_set_routing_entry(struct kvm *kvm,
int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int irq_source_id, int level, bool line_status)
{
+ if (!level)
+ return -EWOULDBLOCK;
+
switch (e->type) {
case KVM_IRQ_ROUTING_IRQCHIP:
pch_pic_set_irq(kvm->arch.pch_pic, e->irqchip.pin, level);
return 0;
case KVM_IRQ_ROUTING_MSI:
- pch_msi_set_irq(kvm, e->msi.data, level);
- return 0;
+ return pch_msi_set_irq(kvm, e, level);
default:
return -EWOULDBLOCK;
}
diff --git a/arch/loongarch/kvm/main.c b/arch/loongarch/kvm/main.c
index 2c593ac7892f..76ebff2faedd 100644
--- a/arch/loongarch/kvm/main.c
+++ b/arch/loongarch/kvm/main.c
@@ -271,11 +271,11 @@ void kvm_check_vpid(struct kvm_vcpu *vcpu)
* memory with new address is changed on other VCPUs.
*/
set_gcsr_llbctl(CSR_LLBCTL_WCLLB);
- }
- /* Restore GSTAT(0x50).vpid */
- vpid = (vcpu->arch.vpid & vpid_mask) << CSR_GSTAT_GID_SHIFT;
- change_csr_gstat(vpid_mask << CSR_GSTAT_GID_SHIFT, vpid);
+ /* Restore GSTAT(0x50).vpid */
+ vpid = (vcpu->arch.vpid & vpid_mask) << CSR_GSTAT_GID_SHIFT;
+ change_csr_gstat(vpid_mask << CSR_GSTAT_GID_SHIFT, vpid);
+ }
}
void kvm_init_vmcs(struct kvm *kvm)
@@ -416,6 +416,12 @@ static int kvm_loongarch_env_init(void)
/* Register LoongArch PCH-PIC interrupt controller interface. */
ret = kvm_loongarch_register_pch_pic_device();
+ if (ret)
+ return ret;
+
+ /* Register LoongArch DMSINTC interrupt contrroller interface */
+ if (cpu_has_msgint)
+ ret = kvm_loongarch_register_dmsintc_device();
return ret;
}
diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index 831f381a8fd1..e28084c49e68 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -149,14 +149,6 @@ static void kvm_lose_pmu(struct kvm_vcpu *vcpu)
kvm_restore_host_pmu(vcpu);
}
-static void kvm_check_pmu(struct kvm_vcpu *vcpu)
-{
- if (kvm_check_request(KVM_REQ_PMU, vcpu)) {
- kvm_own_pmu(vcpu);
- vcpu->arch.aux_inuse |= KVM_LARCH_PMU;
- }
-}
-
static void kvm_update_stolen_time(struct kvm_vcpu *vcpu)
{
u32 version;
@@ -232,6 +224,15 @@ static int kvm_check_requests(struct kvm_vcpu *vcpu)
static void kvm_late_check_requests(struct kvm_vcpu *vcpu)
{
lockdep_assert_irqs_disabled();
+
+ if (!kvm_request_pending(vcpu))
+ return;
+
+ if (kvm_check_request(KVM_REQ_PMU, vcpu)) {
+ kvm_own_pmu(vcpu);
+ vcpu->arch.aux_inuse |= KVM_LARCH_PMU;
+ }
+
if (kvm_check_request(KVM_REQ_TLB_FLUSH_GPA, vcpu))
if (vcpu->arch.flush_gpa != INVALID_GPA) {
kvm_flush_tlb_gpa(vcpu, vcpu->arch.flush_gpa);
@@ -312,7 +313,6 @@ static int kvm_pre_enter_guest(struct kvm_vcpu *vcpu)
/* Make sure the vcpu mode has been written */
smp_store_mb(vcpu->mode, IN_GUEST_MODE);
kvm_check_vpid(vcpu);
- kvm_check_pmu(vcpu);
/*
* Called after function kvm_check_vpid()
@@ -320,7 +320,6 @@ static int kvm_pre_enter_guest(struct kvm_vcpu *vcpu)
* and it may also clear KVM_REQ_TLB_FLUSH_GPA pending bit
*/
kvm_late_check_requests(vcpu);
- vcpu->arch.host_eentry = csr_read64(LOONGARCH_CSR_EENTRY);
/* Clear KVM_LARCH_SWCSR_LATEST as CSR will change when enter guest */
vcpu->arch.aux_inuse &= ~KVM_LARCH_SWCSR_LATEST;
@@ -402,7 +401,7 @@ bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu)
val = gcsr_read(LOONGARCH_CSR_CRMD);
preempt_enable();
- return (val & CSR_PRMD_PPLV) == PLV_KERN;
+ return (val & CSR_CRMD_PLV) == PLV_KERN;
}
#ifdef CONFIG_GUEST_PERF_EVENTS
@@ -1628,9 +1627,11 @@ static int _kvm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
* If not, any old guest state from this vCPU will have been clobbered.
*/
context = per_cpu_ptr(vcpu->kvm->arch.vmcs, cpu);
- if (migrated || (context->last_vcpu != vcpu))
+ if (migrated || (context->last_vcpu != vcpu)) {
+ context->last_vcpu = vcpu;
vcpu->arch.aux_inuse &= ~KVM_LARCH_HWCSR_USABLE;
- context->last_vcpu = vcpu;
+ vcpu->arch.host_eentry = csr_read64(LOONGARCH_CSR_EENTRY);
+ }
/* Restore timer state regardless */
kvm_restore_timer(vcpu);
@@ -1698,6 +1699,7 @@ static int _kvm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
/* Restore Root.GINTC from unused Guest.GINTC register */
write_csr_gintc(csr->csrs[LOONGARCH_CSR_GINTC]);
+ write_csr_gstat(csr->csrs[LOONGARCH_CSR_GSTAT]);
/*
* We should clear linked load bit to break interrupted atomics. This
@@ -1793,6 +1795,7 @@ static int _kvm_vcpu_put(struct kvm_vcpu *vcpu, int cpu)
kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ISR3);
}
+ csr->csrs[LOONGARCH_CSR_GSTAT] = read_csr_gstat();
vcpu->arch.aux_inuse |= KVM_LARCH_SWCSR_LATEST;
out: