提交 59f00ff9 编写于 作者: M Marc Zyngier

KVM: arm/arm64: vgic-v2: Avoid accessing GICH registers

GICv2 registers are *slow*. As in "terrifyingly slow". Which is bad.
But we're equaly bad, as we make a point in accessing them even if
we don't have any interrupt in flight.

A good solution is to first find out if we have anything useful to
write into the GIC, and if we don't, to simply not do it. This
involves tracking which LRs actually have something valid there.
Reviewed-by: NChristoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: NMarc Zyngier <marc.zyngier@arm.com>
上级 9b4a3004
...@@ -321,6 +321,8 @@ struct vgic_cpu { ...@@ -321,6 +321,8 @@ struct vgic_cpu {
/* Protected by the distributor's irq_phys_map_lock */ /* Protected by the distributor's irq_phys_map_lock */
struct list_head irq_phys_map_list; struct list_head irq_phys_map_list;
u64 live_lrs;
}; };
#define LR_EMPTY 0xff #define LR_EMPTY 0xff
......
...@@ -36,15 +36,20 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu) ...@@ -36,15 +36,20 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
nr_lr = vcpu->arch.vgic_cpu.nr_lr; nr_lr = vcpu->arch.vgic_cpu.nr_lr;
cpu_if->vgic_vmcr = readl_relaxed(base + GICH_VMCR); cpu_if->vgic_vmcr = readl_relaxed(base + GICH_VMCR);
cpu_if->vgic_misr = readl_relaxed(base + GICH_MISR);
if (vcpu->arch.vgic_cpu.live_lrs) {
eisr0 = readl_relaxed(base + GICH_EISR0); eisr0 = readl_relaxed(base + GICH_EISR0);
elrsr0 = readl_relaxed(base + GICH_ELRSR0); elrsr0 = readl_relaxed(base + GICH_ELRSR0);
cpu_if->vgic_misr = readl_relaxed(base + GICH_MISR);
cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
if (unlikely(nr_lr > 32)) { if (unlikely(nr_lr > 32)) {
eisr1 = readl_relaxed(base + GICH_EISR1); eisr1 = readl_relaxed(base + GICH_EISR1);
elrsr1 = readl_relaxed(base + GICH_ELRSR1); elrsr1 = readl_relaxed(base + GICH_ELRSR1);
} else { } else {
eisr1 = elrsr1 = 0; eisr1 = elrsr1 = 0;
} }
#ifdef CONFIG_CPU_BIG_ENDIAN #ifdef CONFIG_CPU_BIG_ENDIAN
cpu_if->vgic_eisr = ((u64)eisr0 << 32) | eisr1; cpu_if->vgic_eisr = ((u64)eisr0 << 32) | eisr1;
cpu_if->vgic_elrsr = ((u64)elrsr0 << 32) | elrsr1; cpu_if->vgic_elrsr = ((u64)elrsr0 << 32) | elrsr1;
...@@ -52,12 +57,20 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu) ...@@ -52,12 +57,20 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
cpu_if->vgic_eisr = ((u64)eisr1 << 32) | eisr0; cpu_if->vgic_eisr = ((u64)eisr1 << 32) | eisr0;
cpu_if->vgic_elrsr = ((u64)elrsr1 << 32) | elrsr0; cpu_if->vgic_elrsr = ((u64)elrsr1 << 32) | elrsr0;
#endif #endif
cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
writel_relaxed(0, base + GICH_HCR);
for (i = 0; i < nr_lr; i++) for (i = 0; i < nr_lr; i++)
if (vcpu->arch.vgic_cpu.live_lrs & (1UL << i))
cpu_if->vgic_lr[i] = readl_relaxed(base + GICH_LR0 + (i * 4)); cpu_if->vgic_lr[i] = readl_relaxed(base + GICH_LR0 + (i * 4));
writel_relaxed(0, base + GICH_HCR);
vcpu->arch.vgic_cpu.live_lrs = 0;
} else {
cpu_if->vgic_eisr = 0;
cpu_if->vgic_elrsr = ~0UL;
cpu_if->vgic_misr = 0;
cpu_if->vgic_apr = 0;
}
} }
/* vcpu is already in the HYP VA space */ /* vcpu is already in the HYP VA space */
...@@ -68,15 +81,30 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu) ...@@ -68,15 +81,30 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
struct vgic_dist *vgic = &kvm->arch.vgic; struct vgic_dist *vgic = &kvm->arch.vgic;
void __iomem *base = kern_hyp_va(vgic->vctrl_base); void __iomem *base = kern_hyp_va(vgic->vctrl_base);
int i, nr_lr; int i, nr_lr;
u64 live_lrs = 0;
if (!base) if (!base)
return; return;
nr_lr = vcpu->arch.vgic_cpu.nr_lr;
for (i = 0; i < nr_lr; i++)
if (cpu_if->vgic_lr[i] & GICH_LR_STATE)
live_lrs |= 1UL << i;
if (live_lrs) {
writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR); writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR);
writel_relaxed(cpu_if->vgic_vmcr, base + GICH_VMCR);
writel_relaxed(cpu_if->vgic_apr, base + GICH_APR); writel_relaxed(cpu_if->vgic_apr, base + GICH_APR);
for (i = 0; i < nr_lr; i++) {
u32 val = 0;
nr_lr = vcpu->arch.vgic_cpu.nr_lr; if (live_lrs & (1UL << i))
for (i = 0; i < nr_lr; i++) val = cpu_if->vgic_lr[i];
writel_relaxed(cpu_if->vgic_lr[i], base + GICH_LR0 + (i * 4));
writel_relaxed(val, base + GICH_LR0 + (i * 4));
}
}
writel_relaxed(cpu_if->vgic_vmcr, base + GICH_VMCR);
vcpu->arch.vgic_cpu.live_lrs = live_lrs;
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册