Skip to content

Commit

Permalink
KVM: arm64: Delay the polling of the GICR_VPENDBASER.Dirty bit
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Shenming Lu <[email protected]>
Signed-off-by: Marc Zyngier <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
  • Loading branch information
Shenming Lu authored and Marc Zyngier committed Nov 30, 2020
1 parent bf118a5 commit 57e3ceb
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 4 deletions.
12 changes: 12 additions & 0 deletions arch/arm64/kvm/vgic/vgic-v4.c
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,18 @@ int vgic_v4_load(struct kvm_vcpu *vcpu)
return err;
}

void vgic_v4_commit(struct kvm_vcpu *vcpu)
{
struct its_vpe *vpe = &vcpu->arch.vgic_cpu.vgic_v3.its_vpe;

/*
* No need to wait for the vPE to be ready across a shallow guest
* exit, as only a vcpu_put will invalidate it.
*/
if (!vpe->ready)
its_commit_vpe(vpe);
}

static struct vgic_its *vgic_get_its(struct kvm *kvm,
struct kvm_kernel_irq_routing_entry *irq_entry)
{
Expand Down
3 changes: 3 additions & 0 deletions arch/arm64/kvm/vgic/vgic.c
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,9 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)

if (can_access_vgic_from_kernel())
vgic_restore_state(vcpu);

if (vgic_supports_direct_msis(vcpu->kvm))
vgic_v4_commit(vcpu);
}

void kvm_vgic_load(struct kvm_vcpu *vcpu)
Expand Down
12 changes: 8 additions & 4 deletions drivers/irqchip/irq-gic-v3-its.c
Original file line number Diff line number Diff line change
Expand Up @@ -3842,8 +3842,6 @@ static void its_vpe_schedule(struct its_vpe *vpe)
val |= vpe->idai ? GICR_VPENDBASER_IDAI : 0;
val |= GICR_VPENDBASER_Valid;
gicr_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER);

its_wait_vpt_parse_complete();
}

static void its_vpe_deschedule(struct its_vpe *vpe)
Expand Down Expand Up @@ -3891,6 +3889,10 @@ static int its_vpe_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)
its_vpe_deschedule(vpe);
return 0;

case COMMIT_VPE:
its_wait_vpt_parse_complete();
return 0;

case INVALL_VPE:
its_vpe_invall(vpe);
return 0;
Expand Down Expand Up @@ -4052,8 +4054,6 @@ static void its_vpe_4_1_schedule(struct its_vpe *vpe,
val |= FIELD_PREP(GICR_VPENDBASER_4_1_VPEID, vpe->vpe_id);

gicr_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER);

its_wait_vpt_parse_complete();
}

static void its_vpe_4_1_deschedule(struct its_vpe *vpe,
Expand Down Expand Up @@ -4128,6 +4128,10 @@ static int its_vpe_4_1_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)
its_vpe_4_1_deschedule(vpe, info);
return 0;

case COMMIT_VPE:
its_wait_vpt_parse_complete();
return 0;

case INVALL_VPE:
its_vpe_4_1_invall(vpe);
return 0;
Expand Down
19 changes: 19 additions & 0 deletions drivers/irqchip/irq-gic-v4.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ int its_make_vpe_non_resident(struct its_vpe *vpe, bool db)
if (!ret)
vpe->resident = false;

vpe->ready = false;

return ret;
}

Expand All @@ -258,6 +260,23 @@ int its_make_vpe_resident(struct its_vpe *vpe, bool g0en, bool g1en)
return ret;
}

int its_commit_vpe(struct its_vpe *vpe)
{
struct its_cmd_info info = {
.cmd_type = COMMIT_VPE,
};
int ret;

WARN_ON(preemptible());

ret = its_send_vpe_cmd(vpe, &info);
if (!ret)
vpe->ready = true;

return ret;
}


int its_invall_vpe(struct its_vpe *vpe)
{
struct its_cmd_info info = {
Expand Down
1 change: 1 addition & 0 deletions include/kvm/arm_vgic.h
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ int kvm_vgic_v4_unset_forwarding(struct kvm *kvm, int irq,
struct kvm_kernel_irq_routing_entry *irq_entry);

int vgic_v4_load(struct kvm_vcpu *vcpu);
void vgic_v4_commit(struct kvm_vcpu *vcpu);
int vgic_v4_put(struct kvm_vcpu *vcpu, bool need_db);

#endif /* __KVM_ARM_VGIC_H */
4 changes: 4 additions & 0 deletions include/linux/irqchip/arm-gic-v4.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ struct its_vpe {
irq_hw_number_t vpe_db_lpi;
/* VPE resident */
bool resident;
/* VPT parse complete */
bool ready;
union {
/* GICv4.0 implementations */
struct {
Expand Down Expand Up @@ -104,6 +106,7 @@ enum its_vcpu_info_cmd_type {
PROP_UPDATE_AND_INV_VLPI,
SCHEDULE_VPE,
DESCHEDULE_VPE,
COMMIT_VPE,
INVALL_VPE,
PROP_UPDATE_VSGI,
};
Expand All @@ -129,6 +132,7 @@ int its_alloc_vcpu_irqs(struct its_vm *vm);
void its_free_vcpu_irqs(struct its_vm *vm);
int its_make_vpe_resident(struct its_vpe *vpe, bool g0en, bool g1en);
int its_make_vpe_non_resident(struct its_vpe *vpe, bool db);
int its_commit_vpe(struct its_vpe *vpe);
int its_invall_vpe(struct its_vpe *vpe);
int its_map_vlpi(int irq, struct its_vlpi_map *map);
int its_get_vlpi(int irq, struct its_vlpi_map *map);
Expand Down

0 comments on commit 57e3ceb

Please sign in to comment.