LoongArch KVM changes for v7.2

1. Enable FPU with max VM supported FPU type.
 2. Some enhancements about interrupt injection.
 3. Some bug fixes and other small changes.
 -----BEGIN PGP SIGNATURE-----
 
 iQJKBAABCAA0FiEEzOlt8mkP+tbeiYy5AoYrw/LiJnoFAmoryaoWHGNoZW5odWFj
 YWlAa2VybmVsLm9yZwAKCRAChivD8uImekd0D/4lhxwyxKlqKEBVDQFH5r6TgZFe
 TKGVNxSGF13bYQxTOOYt/zCnNJ9fQhQwk1hzK4KvlPlIMlFs6PKStxojYANxJqro
 21aYpDMXkyaVbaWt8CKck6ETbbyLBQSyfQmkZYu7YqZxzV1E4FUBMa1lwh1hGcVg
 uanNSTK0C7PdZ+rvRT3b/79Ib+6s7/NNtspSxiKoVPtd8lxCcXLBJSxZiw+XfSJY
 FzltGkKvU19PugATNXGyIU+9tfI5o96bBzW66EvjAYJbjJySIVKIBDFzlELwSTGF
 sQcikRMeSrHySdOMrvvihT1Abda5S2KQPcJlUp/3L5yNMejOoJ4yEe1PYwCtLg+M
 uVgRpoVcJzBc4G2l5mizpON0i3OvUF3ecbEda3OikvpvxfeUAdRyXSSHMEtu2l1X
 a2Z3Lkyc9vX7WjYiSeAm3fqqDrHmPXsUPhSijcKXTno9sgHy/vVHsZ5uixMQ3+oc
 QZV+3JaHXomN2Rk9Sj6VcbXSy/W6DVyUacQBSIt/rXSQx87Sz2C8jKqctODEy2Q5
 aeDZl8q3DId1+jT7E2eKKWGjBNPrDvlaQQByQWih0HCbQ8SUI/vDs641n7Ogi2dn
 nRtSxKMf4t9GlNILXUOBo+XxZUFNP3K6y5MY6k1J6Wfckzta5Ax+tDMWvR1g+gKD
 QCcYHUi+Yd4drsUOuQ==
 =WDcm
 -----END PGP SIGNATURE-----

Merge tag 'loongarch-kvm-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson into HEAD

LoongArch KVM changes for v7.2

1. Enable FPU with max VM supported FPU type.
2. Some enhancements about interrupt injection.
3. Some bug fixes and other small changes.
This commit is contained in:
Paolo Bonzini 2026-06-15 15:38:02 +02:00
commit 677d68682e
10 changed files with 131 additions and 180 deletions

View File

@ -38,7 +38,8 @@
#define KVM_REQ_TLB_FLUSH_GPA KVM_ARCH_REQ(0)
#define KVM_REQ_STEAL_UPDATE KVM_ARCH_REQ(1)
#define KVM_REQ_PMU KVM_ARCH_REQ(2)
#define KVM_REQ_AUX_LOAD KVM_ARCH_REQ(3)
#define KVM_REQ_FPU_LOAD KVM_ARCH_REQ(3)
#define KVM_REQ_LBT_LOAD KVM_ARCH_REQ(4)
#define KVM_GUESTDBG_SW_BP_MASK \
(KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP)
@ -157,12 +158,10 @@ enum emulation_result {
};
#define KVM_LARCH_FPU (0x1 << 0)
#define KVM_LARCH_LSX (0x1 << 1)
#define KVM_LARCH_LASX (0x1 << 2)
#define KVM_LARCH_LBT (0x1 << 3)
#define KVM_LARCH_PMU (0x1 << 4)
#define KVM_LARCH_SWCSR_LATEST (0x1 << 5)
#define KVM_LARCH_HWCSR_USABLE (0x1 << 6)
#define KVM_LARCH_LBT (0x1 << 1)
#define KVM_LARCH_PMU (0x1 << 2)
#define KVM_LARCH_SWCSR_LATEST (0x1 << 3)
#define KVM_LARCH_HWCSR_USABLE (0x1 << 4)
#define LOONGARCH_PV_FEAT_UPDATED BIT_ULL(63)
#define LOONGARCH_PV_FEAT_MASK (BIT(KVM_FEATURE_IPI) | \
@ -203,7 +202,6 @@ struct kvm_vcpu_arch {
/* Which auxiliary state is loaded (KVM_LARCH_*) */
unsigned int aux_inuse;
unsigned int aux_ldtype;
/* FPU state */
struct loongarch_fpu fpu FPU_ALIGN;

View File

@ -10,22 +10,37 @@
#include <asm/loongarch.h>
/* Controlled by 0x5 guest estat */
#define CPU_SIP0 (_ULCAST_(1))
#define CPU_SIP1 (_ULCAST_(1) << 1)
#define CPU_PMU (_ULCAST_(1) << 10)
#define CPU_TIMER (_ULCAST_(1) << 11)
#define CPU_IPI (_ULCAST_(1) << 12)
#define CPU_AVEC (_ULCAST_(1) << 14)
#define CPU_SIP0 BIT(INT_SWI0)
#define CPU_SIP1 BIT(INT_SWI1)
#define CPU_HWI0 BIT(INT_HWI0)
#define CPU_HWI1 BIT(INT_HWI1)
#define CPU_HWI2 BIT(INT_HWI2)
#define CPU_HWI3 BIT(INT_HWI3)
#define CPU_HWI4 BIT(INT_HWI4)
#define CPU_HWI5 BIT(INT_HWI5)
#define CPU_HWI6 BIT(INT_HWI6)
#define CPU_HWI7 BIT(INT_HWI7)
#define CPU_PMU BIT(INT_PCOV)
#define CPU_TIMER BIT(INT_TI)
#define CPU_IPI BIT(INT_IPI)
#define CPU_AVEC BIT(INT_AVEC)
#define KVM_ESTAT_INTI_MASK (CPU_SIP0 | CPU_SIP1 | CPU_PMU | CPU_TIMER \
| CPU_IPI | CPU_AVEC)
#define KVM_ESTAT_EXTI_MASK (CPU_HWI0 | CPU_HWI1 | CPU_HWI2 | CPU_HWI3 \
| CPU_HWI4 | CPU_HWI5 | CPU_HWI6 | CPU_HWI7)
/* Controlled by 0x52 guest exception VIP aligned to estat bit 5~12 */
#define CPU_IP0 (_ULCAST_(1))
#define CPU_IP1 (_ULCAST_(1) << 1)
#define CPU_IP2 (_ULCAST_(1) << 2)
#define CPU_IP3 (_ULCAST_(1) << 3)
#define CPU_IP4 (_ULCAST_(1) << 4)
#define CPU_IP5 (_ULCAST_(1) << 5)
#define CPU_IP6 (_ULCAST_(1) << 6)
#define CPU_IP7 (_ULCAST_(1) << 7)
#define VIP_DELTA (INT_HWI0 - CSR_GINTC_VIP_SHIFT)
#define CPU_IP0 BIT(INT_HWI0 - VIP_DELTA)
#define CPU_IP1 BIT(INT_HWI1 - VIP_DELTA)
#define CPU_IP2 BIT(INT_HWI2 - VIP_DELTA)
#define CPU_IP3 BIT(INT_HWI3 - VIP_DELTA)
#define CPU_IP4 BIT(INT_HWI4 - VIP_DELTA)
#define CPU_IP5 BIT(INT_HWI5 - VIP_DELTA)
#define CPU_IP6 BIT(INT_HWI6 - VIP_DELTA)
#define CPU_IP7 BIT(INT_HWI7 - VIP_DELTA)
#define KVM_GINTC_IRQ_MASK (CPU_IP0 | CPU_IP1 | CPU_IP2 | CPU_IP3 \
| CPU_IP4 | CPU_IP5 | CPU_IP6 | CPU_IP7)
#define MNSEC_PER_SEC (NSEC_PER_SEC >> 20)

View File

@ -103,7 +103,6 @@ static unsigned long kvm_emu_xchg_csr(struct kvm_vcpu *vcpu, int csrid,
old = kvm_read_sw_gcsr(csr, csrid);
val = (old & ~csr_mask) | (val & csr_mask);
kvm_write_sw_gcsr(csr, csrid, val);
old = old & csr_mask;
} else
pr_warn_once("Unsupported csrxchg 0x%x with pc %lx\n", csrid, vcpu->arch.pc);
@ -755,8 +754,7 @@ static int kvm_handle_fpu_disabled(struct kvm_vcpu *vcpu, int ecode)
return RESUME_HOST;
}
vcpu->arch.aux_ldtype = KVM_LARCH_FPU;
kvm_make_request(KVM_REQ_AUX_LOAD, vcpu);
kvm_make_request(KVM_REQ_FPU_LOAD, vcpu);
return RESUME_GUEST;
}
@ -796,10 +794,8 @@ static int kvm_handle_lsx_disabled(struct kvm_vcpu *vcpu, int ecode)
{
if (!kvm_guest_has_lsx(&vcpu->arch))
kvm_queue_exception(vcpu, EXCCODE_INE, 0);
else {
vcpu->arch.aux_ldtype = KVM_LARCH_LSX;
kvm_make_request(KVM_REQ_AUX_LOAD, vcpu);
}
else
kvm_make_request(KVM_REQ_FPU_LOAD, vcpu);
return RESUME_GUEST;
}
@ -816,10 +812,8 @@ static int kvm_handle_lasx_disabled(struct kvm_vcpu *vcpu, int ecode)
{
if (!kvm_guest_has_lasx(&vcpu->arch))
kvm_queue_exception(vcpu, EXCCODE_INE, 0);
else {
vcpu->arch.aux_ldtype = KVM_LARCH_LASX;
kvm_make_request(KVM_REQ_AUX_LOAD, vcpu);
}
else
kvm_make_request(KVM_REQ_FPU_LOAD, vcpu);
return RESUME_GUEST;
}
@ -828,10 +822,8 @@ static int kvm_handle_lbt_disabled(struct kvm_vcpu *vcpu, int ecode)
{
if (!kvm_guest_has_lbt(&vcpu->arch))
kvm_queue_exception(vcpu, EXCCODE_INE, 0);
else {
vcpu->arch.aux_ldtype = KVM_LARCH_LBT;
kvm_make_request(KVM_REQ_AUX_LOAD, vcpu);
}
else
kvm_make_request(KVM_REQ_LBT_LOAD, vcpu);
return RESUME_GUEST;
}

View File

@ -645,10 +645,14 @@ static int kvm_eiointc_create(struct kvm_device *dev, u32 type)
device = &s->device_vext;
kvm_iodevice_init(device, &kvm_eiointc_virt_ops);
mutex_lock(&kvm->slots_lock);
ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS,
EIOINTC_VIRT_BASE, EIOINTC_VIRT_SIZE, device);
mutex_unlock(&kvm->slots_lock);
if (ret < 0) {
mutex_lock(&kvm->slots_lock);
kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &s->device);
mutex_unlock(&kvm->slots_lock);
kfree(s);
return ret;
}
@ -667,8 +671,10 @@ static void kvm_eiointc_destroy(struct kvm_device *dev)
kvm = dev->kvm;
eiointc = kvm->arch.eiointc;
mutex_lock(&kvm->slots_lock);
kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device);
kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device_vext);
mutex_unlock(&kvm->slots_lock);
kfree(eiointc);
kfree(dev);
}

View File

@ -447,7 +447,9 @@ static void kvm_ipi_destroy(struct kvm_device *dev)
kvm = dev->kvm;
ipi = kvm->arch.ipi;
mutex_lock(&kvm->slots_lock);
kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &ipi->device);
mutex_unlock(&kvm->slots_lock);
kfree(ipi);
kfree(dev);
}

View File

@ -481,7 +481,9 @@ static void kvm_pch_pic_destroy(struct kvm_device *dev)
kvm = dev->kvm;
s = kvm->arch.pch_pic;
/* unregister pch pic device and free it's memory */
mutex_lock(&kvm->slots_lock);
kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &s->device);
mutex_unlock(&kvm->slots_lock);
kfree(s);
kfree(dev);
}

View File

@ -9,41 +9,16 @@
#include <asm/kvm_vcpu.h>
#include <asm/kvm_dmsintc.h>
static unsigned int priority_to_irq[EXCCODE_INT_NUM] = {
[INT_TI] = CPU_TIMER,
[INT_IPI] = CPU_IPI,
[INT_SWI0] = CPU_SIP0,
[INT_SWI1] = CPU_SIP1,
[INT_HWI0] = CPU_IP0,
[INT_HWI1] = CPU_IP1,
[INT_HWI2] = CPU_IP2,
[INT_HWI3] = CPU_IP3,
[INT_HWI4] = CPU_IP4,
[INT_HWI5] = CPU_IP5,
[INT_HWI6] = CPU_IP6,
[INT_HWI7] = CPU_IP7,
[INT_AVEC] = CPU_AVEC,
};
static int kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
static void kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned long mask)
{
unsigned int irq = 0;
unsigned long irq;
unsigned long old, new;
clear_bit(priority, &vcpu->arch.irq_pending);
if (priority < EXCCODE_INT_NUM)
irq = priority_to_irq[priority];
switch (priority) {
case INT_AVEC:
if (!kvm_guest_has_msgint(&vcpu->arch))
break;
if (mask & CPU_AVEC)
dmsintc_inject_irq(vcpu);
fallthrough;
case INT_TI:
case INT_IPI:
case INT_SWI0:
case INT_SWI1:
irq = mask & KVM_ESTAT_INTI_MASK;
if (irq) {
old = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL);
set_gcsr_estat(irq);
new = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL);
@ -51,37 +26,20 @@ static int kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
/* Inject TI if TVAL inverted */
if (new > old)
set_gcsr_estat(CPU_TIMER);
break;
case INT_HWI0 ... INT_HWI7:
set_csr_gintc(irq);
break;
default:
break;
}
return 1;
irq = (mask >> VIP_DELTA) & KVM_GINTC_IRQ_MASK;
if (irq)
set_csr_gintc(irq);
}
static int kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned int priority)
static void kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned long mask)
{
unsigned int irq = 0;
unsigned long irq;
unsigned long old, new;
clear_bit(priority, &vcpu->arch.irq_clear);
if (priority < EXCCODE_INT_NUM)
irq = priority_to_irq[priority];
switch (priority) {
case INT_AVEC:
if (!kvm_guest_has_msgint(&vcpu->arch))
break;
fallthrough;
case INT_TI:
case INT_IPI:
case INT_SWI0:
case INT_SWI1:
irq = mask & KVM_ESTAT_INTI_MASK;
if (irq) {
old = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL);
clear_gcsr_estat(irq);
new = kvm_read_hw_gcsr(LOONGARCH_CSR_TVAL);
@ -89,30 +47,28 @@ static int kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned int priority)
/* Inject TI if TVAL inverted */
if (new > old)
set_gcsr_estat(CPU_TIMER);
break;
case INT_HWI0 ... INT_HWI7:
clear_csr_gintc(irq);
break;
default:
break;
}
return 1;
irq = (mask >> VIP_DELTA) & KVM_GINTC_IRQ_MASK;
if (irq)
clear_csr_gintc(irq);
}
void kvm_deliver_intr(struct kvm_vcpu *vcpu)
{
unsigned int priority;
unsigned long *pending = &vcpu->arch.irq_pending;
unsigned long *pending_clr = &vcpu->arch.irq_clear;
unsigned long mask;
for_each_set_bit(priority, pending_clr, EXCCODE_INT_NUM)
kvm_irq_clear(vcpu, priority);
mask = READ_ONCE(vcpu->arch.irq_clear);
if (mask) {
mask = xchg_relaxed(&vcpu->arch.irq_clear, 0);
kvm_irq_clear(vcpu, mask);
}
for_each_set_bit(priority, pending, EXCCODE_INT_NUM)
kvm_irq_deliver(vcpu, priority);
mask = READ_ONCE(vcpu->arch.irq_pending);
if (mask) {
mask = xchg_relaxed(&vcpu->arch.irq_pending, 0);
kvm_irq_deliver(vcpu, mask);
}
}
int kvm_pending_timer(struct kvm_vcpu *vcpu)

View File

@ -51,7 +51,8 @@ int kvm_set_routing_entry(struct kvm *kvm,
e->irqchip.irqchip = ue->u.irqchip.irqchip;
e->irqchip.pin = ue->u.irqchip.pin;
if (e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS)
if (e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS ||
e->irqchip.irqchip >= KVM_NR_IRQCHIPS)
return -EINVAL;
return 0;

View File

@ -30,8 +30,7 @@ enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer)
struct kvm_vcpu *vcpu;
vcpu = container_of(timer, struct kvm_vcpu, arch.swtimer);
kvm_queue_irq(vcpu, INT_TI);
rcuwait_wake_up(&vcpu->wait);
kvm_vcpu_wake_up(vcpu);
return HRTIMER_NORESTART;
}

View File

@ -239,26 +239,17 @@ static void kvm_late_check_requests(struct kvm_vcpu *vcpu)
vcpu->arch.flush_gpa = INVALID_GPA;
}
if (kvm_check_request(KVM_REQ_AUX_LOAD, vcpu)) {
switch (vcpu->arch.aux_ldtype) {
case KVM_LARCH_FPU:
kvm_own_fpu(vcpu);
break;
case KVM_LARCH_LSX:
kvm_own_lsx(vcpu);
break;
case KVM_LARCH_LASX:
if (kvm_check_request(KVM_REQ_FPU_LOAD, vcpu)) {
if (kvm_guest_has_lasx(&vcpu->arch))
kvm_own_lasx(vcpu);
break;
case KVM_LARCH_LBT:
kvm_own_lbt(vcpu);
break;
default:
break;
}
vcpu->arch.aux_ldtype = 0;
else if (kvm_guest_has_lsx(&vcpu->arch))
kvm_own_lsx(vcpu);
else if (kvm_guest_has_fpu(&vcpu->arch))
kvm_own_fpu(vcpu);
}
if (kvm_check_request(KVM_REQ_LBT_LOAD, vcpu))
kvm_own_lbt(vcpu);
}
/*
@ -308,10 +299,10 @@ static int kvm_pre_enter_guest(struct kvm_vcpu *vcpu)
* check vmid before vcpu enter guest
*/
local_irq_disable();
kvm_deliver_intr(vcpu);
kvm_deliver_exception(vcpu);
/* Make sure the vcpu mode has been written */
smp_store_mb(vcpu->mode, IN_GUEST_MODE);
kvm_deliver_intr(vcpu);
kvm_check_vpid(vcpu);
/*
@ -348,7 +339,7 @@ static int kvm_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
u32 intr = estat & CSR_ESTAT_IS;
u32 ecode = (estat & CSR_ESTAT_EXC) >> CSR_ESTAT_EXC_SHIFT;
vcpu->mode = OUTSIDE_GUEST_MODE;
smp_store_mb(vcpu->mode, OUTSIDE_GUEST_MODE);
/* Set a default exit reason */
run->exit_reason = KVM_EXIT_UNKNOWN;
@ -602,7 +593,7 @@ struct kvm_vcpu *kvm_get_vcpu_by_cpuid(struct kvm *kvm, int cpuid)
static int _kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *val)
{
unsigned long gintc;
unsigned long estat, gintc;
struct loongarch_csrs *csr = vcpu->arch.csr;
if (get_gcsr_flag(id) & INVALID_GCSR)
@ -621,8 +612,9 @@ static int _kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *val)
preempt_enable();
/* ESTAT IP0~IP7 get from GINTC */
gintc = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_GINTC) & 0xff;
*val = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_ESTAT) | (gintc << 2);
gintc = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_GINTC) & KVM_GINTC_IRQ_MASK;
estat = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_ESTAT) & ~KVM_ESTAT_EXTI_MASK;
*val = estat | (gintc << VIP_DELTA);
return 0;
}
@ -637,7 +629,8 @@ static int _kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *val)
static int _kvm_setcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 val)
{
int ret = 0, gintc;
int ret = 0;
unsigned long estat, gintc;
struct loongarch_csrs *csr = vcpu->arch.csr;
if (get_gcsr_flag(id) & INVALID_GCSR)
@ -648,11 +641,16 @@ static int _kvm_setcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 val)
if (id == LOONGARCH_CSR_ESTAT) {
/* ESTAT IP0~IP7 inject through GINTC */
gintc = (val >> 2) & 0xff;
kvm_set_sw_gcsr(csr, LOONGARCH_CSR_GINTC, gintc);
gintc = (val >> VIP_DELTA) & KVM_GINTC_IRQ_MASK;
gintc |= kvm_read_sw_gcsr(csr, LOONGARCH_CSR_GINTC) & ~KVM_GINTC_IRQ_MASK;
kvm_write_sw_gcsr(csr, LOONGARCH_CSR_GINTC, gintc);
gintc = val & ~(0xffUL << 2);
kvm_set_sw_gcsr(csr, LOONGARCH_CSR_ESTAT, gintc);
/* Only set valid ESTAT bits */
estat = val & ~KVM_ESTAT_EXTI_MASK;
estat &= CSR_ESTAT_IS | CSR_ESTAT_EXC | CSR_ESTAT_ESUBCODE;
if (!kvm_guest_has_msgint(&vcpu->arch))
estat &= ~CPU_AVEC;
kvm_write_sw_gcsr(csr, LOONGARCH_CSR_ESTAT, estat);
return ret;
}
@ -1108,7 +1106,8 @@ static int kvm_loongarch_cpucfg_get_attr(struct kvm_vcpu *vcpu,
return -ENXIO;
}
put_user(val, uaddr);
if (put_user(val, uaddr))
return -EFAULT;
return ret;
}
@ -1312,7 +1311,7 @@ int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
fpu->fcc = vcpu->arch.fpu.fcc;
fpu->fcsr = vcpu->arch.fpu.fcsr;
for (i = 0; i < NUM_FPU_REGS; i++)
memcpy(&fpu->fpr[i], &vcpu->arch.fpu.fpr[i], FPU_REG_WIDTH / 64);
memcpy(&fpu->fpr[i], &vcpu->arch.fpu.fpr[i], sizeof(union fpureg));
return 0;
}
@ -1324,7 +1323,7 @@ int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
vcpu->arch.fpu.fcc = fpu->fcc;
vcpu->arch.fpu.fcsr = fpu->fcsr;
for (i = 0; i < NUM_FPU_REGS; i++)
memcpy(&vcpu->arch.fpu.fpr[i], &fpu->fpr[i], FPU_REG_WIDTH / 64);
memcpy(&vcpu->arch.fpu.fpr[i], &fpu->fpr[i], sizeof(union fpureg));
return 0;
}
@ -1398,24 +1397,10 @@ int kvm_own_lsx(struct kvm_vcpu *vcpu)
/* Enable LSX for guest */
kvm_check_fcsr(vcpu, vcpu->arch.fpu.fcsr);
set_csr_euen(CSR_EUEN_LSXEN | CSR_EUEN_FPEN);
switch (vcpu->arch.aux_inuse & KVM_LARCH_FPU) {
case KVM_LARCH_FPU:
/*
* Guest FPU state already loaded,
* only restore upper LSX state
*/
_restore_lsx_upper(&vcpu->arch.fpu);
break;
default:
/* Neither FP or LSX already active,
* restore full LSX state
*/
kvm_restore_lsx(&vcpu->arch.fpu);
break;
}
kvm_restore_lsx(&vcpu->arch.fpu);
vcpu->arch.aux_inuse |= KVM_LARCH_FPU;
trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE, KVM_TRACE_AUX_LSX);
vcpu->arch.aux_inuse |= KVM_LARCH_LSX | KVM_LARCH_FPU;
return 0;
}
@ -1427,25 +1412,10 @@ int kvm_own_lasx(struct kvm_vcpu *vcpu)
{
kvm_check_fcsr(vcpu, vcpu->arch.fpu.fcsr);
set_csr_euen(CSR_EUEN_FPEN | CSR_EUEN_LSXEN | CSR_EUEN_LASXEN);
switch (vcpu->arch.aux_inuse & (KVM_LARCH_FPU | KVM_LARCH_LSX)) {
case KVM_LARCH_LSX:
case KVM_LARCH_LSX | KVM_LARCH_FPU:
/* Guest LSX state already loaded, only restore upper LASX state */
_restore_lasx_upper(&vcpu->arch.fpu);
break;
case KVM_LARCH_FPU:
/* Guest FP state already loaded, only restore upper LSX & LASX state */
_restore_lsx_upper(&vcpu->arch.fpu);
_restore_lasx_upper(&vcpu->arch.fpu);
break;
default:
/* Neither FP or LSX already active, restore full LASX state */
kvm_restore_lasx(&vcpu->arch.fpu);
break;
}
kvm_restore_lasx(&vcpu->arch.fpu);
vcpu->arch.aux_inuse |= KVM_LARCH_FPU;
trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE, KVM_TRACE_AUX_LASX);
vcpu->arch.aux_inuse |= KVM_LARCH_LASX | KVM_LARCH_LSX | KVM_LARCH_FPU;
return 0;
}
@ -1456,29 +1426,32 @@ void kvm_lose_fpu(struct kvm_vcpu *vcpu)
{
preempt_disable();
if (!(vcpu->arch.aux_inuse & KVM_LARCH_FPU))
goto done;
kvm_check_fcsr_alive(vcpu);
if (vcpu->arch.aux_inuse & KVM_LARCH_LASX) {
if (kvm_guest_has_lasx(&vcpu->arch)) {
kvm_save_lasx(&vcpu->arch.fpu);
vcpu->arch.aux_inuse &= ~(KVM_LARCH_LSX | KVM_LARCH_FPU | KVM_LARCH_LASX);
trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_LASX);
/* Disable LASX & LSX & FPU */
clear_csr_euen(CSR_EUEN_FPEN | CSR_EUEN_LSXEN | CSR_EUEN_LASXEN);
} else if (vcpu->arch.aux_inuse & KVM_LARCH_LSX) {
} else if (kvm_guest_has_lsx(&vcpu->arch)) {
kvm_save_lsx(&vcpu->arch.fpu);
vcpu->arch.aux_inuse &= ~(KVM_LARCH_LSX | KVM_LARCH_FPU);
trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_LSX);
/* Disable LSX & FPU */
clear_csr_euen(CSR_EUEN_FPEN | CSR_EUEN_LSXEN);
} else if (vcpu->arch.aux_inuse & KVM_LARCH_FPU) {
kvm_save_fpu(&vcpu->arch.fpu);
vcpu->arch.aux_inuse &= ~KVM_LARCH_FPU;
trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_FPU);
/* Disable FPU */
clear_csr_euen(CSR_EUEN_FPEN);
}
vcpu->arch.aux_inuse &= ~KVM_LARCH_FPU;
done:
kvm_lose_lbt(vcpu);
preempt_enable();
@ -1487,6 +1460,13 @@ void kvm_lose_fpu(struct kvm_vcpu *vcpu)
int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq)
{
int intr = (int)irq->irq;
unsigned int vector = abs(intr);
if (vector >= EXCCODE_INT_NUM)
return -EINVAL;
if (!kvm_guest_has_msgint(&vcpu->arch) && (vector == INT_AVEC))
return -EINVAL;
if (intr > 0)
kvm_queue_irq(vcpu, intr);