Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: arm64: Delay the polling of the GICR_VPENDBASER.Dirty bit

In order to reduce the impact of the VPT parsing happening on the GIC,
we can split the vcpu reseidency in two phases:

- programming GICR_VPENDBASER: this still happens in vcpu_load()
- checking for the VPT parsing to be complete: this can happen
on vcpu entry (in kvm_vgic_flush_hwstate())

This allows the GIC and the CPU to work in parallel, rewmoving some
of the entry overhead.

Suggested-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Shenming Lu <lushenming@huawei.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20201128141857.983-3-lushenming@huawei.com

authored by

Shenming Lu and committed by
Marc Zyngier
57e3cebd bf118a5c

+47 -4
+12
arch/arm64/kvm/vgic/vgic-v4.c
··· 353 353 return err; 354 354 } 355 355 356 + void vgic_v4_commit(struct kvm_vcpu *vcpu) 357 + { 358 + struct its_vpe *vpe = &vcpu->arch.vgic_cpu.vgic_v3.its_vpe; 359 + 360 + /* 361 + * No need to wait for the vPE to be ready across a shallow guest 362 + * exit, as only a vcpu_put will invalidate it. 363 + */ 364 + if (!vpe->ready) 365 + its_commit_vpe(vpe); 366 + } 367 + 356 368 static struct vgic_its *vgic_get_its(struct kvm *kvm, 357 369 struct kvm_kernel_irq_routing_entry *irq_entry) 358 370 {
+3
arch/arm64/kvm/vgic/vgic.c
··· 915 915 916 916 if (can_access_vgic_from_kernel()) 917 917 vgic_restore_state(vcpu); 918 + 919 + if (vgic_supports_direct_msis(vcpu->kvm)) 920 + vgic_v4_commit(vcpu); 918 921 } 919 922 920 923 void kvm_vgic_load(struct kvm_vcpu *vcpu)
+8 -4
drivers/irqchip/irq-gic-v3-its.c
··· 3842 3842 val |= vpe->idai ? GICR_VPENDBASER_IDAI : 0; 3843 3843 val |= GICR_VPENDBASER_Valid; 3844 3844 gicr_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER); 3845 - 3846 - its_wait_vpt_parse_complete(); 3847 3845 } 3848 3846 3849 3847 static void its_vpe_deschedule(struct its_vpe *vpe) ··· 3887 3889 3888 3890 case DESCHEDULE_VPE: 3889 3891 its_vpe_deschedule(vpe); 3892 + return 0; 3893 + 3894 + case COMMIT_VPE: 3895 + its_wait_vpt_parse_complete(); 3890 3896 return 0; 3891 3897 3892 3898 case INVALL_VPE: ··· 4054 4052 val |= FIELD_PREP(GICR_VPENDBASER_4_1_VPEID, vpe->vpe_id); 4055 4053 4056 4054 gicr_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER); 4057 - 4058 - its_wait_vpt_parse_complete(); 4059 4055 } 4060 4056 4061 4057 static void its_vpe_4_1_deschedule(struct its_vpe *vpe, ··· 4126 4126 4127 4127 case DESCHEDULE_VPE: 4128 4128 its_vpe_4_1_deschedule(vpe, info); 4129 + return 0; 4130 + 4131 + case COMMIT_VPE: 4132 + its_wait_vpt_parse_complete(); 4129 4133 return 0; 4130 4134 4131 4135 case INVALL_VPE:
+19
drivers/irqchip/irq-gic-v4.c
··· 232 232 if (!ret) 233 233 vpe->resident = false; 234 234 235 + vpe->ready = false; 236 + 235 237 return ret; 236 238 } 237 239 ··· 259 257 260 258 return ret; 261 259 } 260 + 261 + int its_commit_vpe(struct its_vpe *vpe) 262 + { 263 + struct its_cmd_info info = { 264 + .cmd_type = COMMIT_VPE, 265 + }; 266 + int ret; 267 + 268 + WARN_ON(preemptible()); 269 + 270 + ret = its_send_vpe_cmd(vpe, &info); 271 + if (!ret) 272 + vpe->ready = true; 273 + 274 + return ret; 275 + } 276 + 262 277 263 278 int its_invall_vpe(struct its_vpe *vpe) 264 279 {
+1
include/kvm/arm_vgic.h
··· 402 402 struct kvm_kernel_irq_routing_entry *irq_entry); 403 403 404 404 int vgic_v4_load(struct kvm_vcpu *vcpu); 405 + void vgic_v4_commit(struct kvm_vcpu *vcpu); 405 406 int vgic_v4_put(struct kvm_vcpu *vcpu, bool need_db); 406 407 407 408 #endif /* __KVM_ARM_VGIC_H */
+4
include/linux/irqchip/arm-gic-v4.h
··· 39 39 irq_hw_number_t vpe_db_lpi; 40 40 /* VPE resident */ 41 41 bool resident; 42 + /* VPT parse complete */ 43 + bool ready; 42 44 union { 43 45 /* GICv4.0 implementations */ 44 46 struct { ··· 106 104 PROP_UPDATE_AND_INV_VLPI, 107 105 SCHEDULE_VPE, 108 106 DESCHEDULE_VPE, 107 + COMMIT_VPE, 109 108 INVALL_VPE, 110 109 PROP_UPDATE_VSGI, 111 110 }; ··· 132 129 void its_free_vcpu_irqs(struct its_vm *vm); 133 130 int its_make_vpe_resident(struct its_vpe *vpe, bool g0en, bool g1en); 134 131 int its_make_vpe_non_resident(struct its_vpe *vpe, bool db); 132 + int its_commit_vpe(struct its_vpe *vpe); 135 133 int its_invall_vpe(struct its_vpe *vpe); 136 134 int its_map_vlpi(int irq, struct its_vlpi_map *map); 137 135 int its_get_vlpi(int irq, struct its_vlpi_map *map);