
From: Xiang Chen <chenxiang66@hisilicon.com> virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBPH85 ------------------------------------------------------------------------ For direct mode, need to use vpe id, so need to pre-allocate vpe id before reset_mpidr. Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com> Signed-off-by: Nianyao Tang <tangnianyao@huawei.com> Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- arch/arm64/kvm/arm.c | 6 +++++ arch/arm64/kvm/sys_regs.c | 7 ++++-- arch/arm64/kvm/vgic/vgic-init.c | 40 ++++++++++++++++++++++++++++++ drivers/irqchip/irq-gic-v3-its.c | 18 ++++++++++---- include/kvm/arm_vgic.h | 2 ++ include/linux/irqchip/arm-gic-v4.h | 1 + 6 files changed, 67 insertions(+), 7 deletions(-) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 5115df307ab9..6bc313fcf1da 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -514,6 +514,10 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) if (err) return err; + err = kvm_vgic_vpe_id_alloc(vcpu); + if (err) + return err; + return kvm_share_hyp(vcpu, vcpu + 1); } @@ -530,6 +534,8 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) kvm_arm_vcpu_destroy(vcpu); kvm_sched_affinity_vcpu_destroy(vcpu); + + kvm_vgic_vpe_id_free(vcpu); } void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 69cbc11f5ff7..bc30ef0e1824 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -726,9 +726,12 @@ static u64 reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) */ if (static_branch_unlikely(&ipiv_enable)) { if (static_branch_unlikely(&ipiv_direct)) { - u64 vpe_id_aff3 = (vpe->vpe_id >> 8) & 0xff; + u64 vpe_id_aff3, vpe_id_aff2; - mpidr |= ((vpe->vpe_id & 0xff) << MPIDR_LEVEL_SHIFT(2)); + vpe_id_aff2 = (vpe->vpe_id >> 8) & 0xff; + vpe_id_aff3 = (vpe->vpe_id & 0xff); + + mpidr |= vpe_id_aff2 << MPIDR_LEVEL_SHIFT(2); mpidr |= vpe_id_aff3 << MPIDR_LEVEL_SHIFT(3); } else { mpidr = (vcpu->vcpu_id & 0x0f) << MPIDR_LEVEL_SHIFT(1); diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c index ec0965f26d70..ba944bef7235 100644 --- a/arch/arm64/kvm/vgic/vgic-init.c +++ b/arch/arm64/kvm/vgic/vgic-init.c @@ -695,3 +695,43 @@ int kvm_vgic_hyp_init(void) acpi_unregister_gsi(18); return ret; } + +extern int its_vpe_id_alloc(void); +extern void its_vpe_id_free(u16 id); +int kvm_vgic_vpe_id_alloc(struct kvm_vcpu *vcpu) +{ + struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; + int vpe_id; + + if (vgic_cpu->vgic_v3.its_vpe.vpe_id_allocated) { + kvm_err("[%s]vpe_id already allocated\n", __func__); + return -1; + } + + vpe_id = its_vpe_id_alloc(); + if (vpe_id < 0) { + kvm_err("[%s]alloc vpe id fail: vpe_id=%d\n", __func__, vpe_id); + return vpe_id; + } + + vgic_cpu->vgic_v3.its_vpe.vpe_id = vpe_id; + vgic_cpu->vgic_v3.its_vpe.vpe_id_allocated = true; + + return 0; +} + +int kvm_vgic_vpe_id_free(struct kvm_vcpu *vcpu) +{ + struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; + int vpe_id; + + vpe_id = vgic_cpu->vgic_v3.its_vpe.vpe_id; + + if (!vgic_cpu->vgic_v3.its_vpe.vpe_id_allocated) + return 0; + + its_vpe_id_free(vpe_id); + vgic_cpu->vgic_v3.its_vpe.vpe_id_allocated = false; + + return 0; +} diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 1bf16c1f9a92..72fe63f78952 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -4996,15 +4996,17 @@ static const struct irq_domain_ops its_sgi_domain_ops = { .deactivate = its_sgi_irq_domain_deactivate, }; -static int its_vpe_id_alloc(void) +int its_vpe_id_alloc(void) { return ida_simple_get(&its_vpeid_ida, 0, ITS_MAX_VPEID, GFP_KERNEL); } +EXPORT_SYMBOL(its_vpe_id_alloc); -static void its_vpe_id_free(u16 id) +void its_vpe_id_free(u16 id) { ida_simple_remove(&its_vpeid_ida, id); } +EXPORT_SYMBOL(its_vpe_id_free); static int its_vpe_init(struct its_vpe *vpe) { @@ -5012,9 +5014,13 @@ static int its_vpe_init(struct its_vpe *vpe) int vpe_id; /* Allocate vpe_id */ - vpe_id = its_vpe_id_alloc(); - if (vpe_id < 0) - return vpe_id; + if (!vpe->vpe_id_allocated) { + vpe_id = its_vpe_id_alloc(); + if (vpe_id < 0) + return vpe_id; + } else { + vpe_id = vpe->vpe_id; + } /* Allocate VPT */ vpt_page = its_allocate_pending_table(GFP_KERNEL); @@ -5031,6 +5037,7 @@ static int its_vpe_init(struct its_vpe *vpe) raw_spin_lock_init(&vpe->vpe_lock); vpe->vpe_id = vpe_id; + vpe->vpe_id_allocated = true; vpe->vpt_page = vpt_page; atomic_set(&vpe->vmapp_count, 0); if (!gic_rdists->has_rvpeid) @@ -5043,6 +5050,7 @@ static void its_vpe_teardown(struct its_vpe *vpe) { its_vpe_db_proxy_unmap(vpe); its_vpe_id_free(vpe->vpe_id); + vpe->vpe_id_allocated = false; its_free_pending_table(vpe->vpt_page); } diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 0b734d6f3d21..460d226450af 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -454,6 +454,8 @@ void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu); int kvm_vgic_map_resources(struct kvm *kvm); int kvm_vgic_hyp_init(void); void kvm_vgic_init_cpu_hardware(void); +int kvm_vgic_vpe_id_alloc(struct kvm_vcpu *vcpu); +int kvm_vgic_vpe_id_free(struct kvm_vcpu *vcpu); int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int intid, bool level, void *owner); diff --git a/include/linux/irqchip/arm-gic-v4.h b/include/linux/irqchip/arm-gic-v4.h index d3281506af9c..ea29e773d139 100644 --- a/include/linux/irqchip/arm-gic-v4.h +++ b/include/linux/irqchip/arm-gic-v4.h @@ -92,6 +92,7 @@ struct its_vpe { u16 col_idx; /* Unique (system-wide) VPE identifier */ u16 vpe_id; + bool vpe_id_allocated; /* Pending VLPIs on schedule out? */ bool pending_last; }; -- 2.33.0