diff options
author | shameer <shamiali2008@gmail.com> | 2017-05-20 19:45:10 +0100 |
---|---|---|
committer | Graeme Gregory <graeme.gregory@linaro.org> | 2017-06-06 10:00:44 +0100 |
commit | 37edf0f0978a06e825a1ef449183adf79d12deca (patch) | |
tree | 60fd3384814c8b615d90f44906834ebbd5e3b188 | |
parent | 0d2d2a67c95fd4304dd00b935a6695131e9ab12b (diff) | |
download | leg-kernel-37edf0f0978a06e825a1ef449183adf79d12deca.tar.gz |
KVM:arm/arm64: HiSilicon GIC quirk for kvm CPU stall issue
KVM uses virt-phys interrupt map feature while forwarding
the timer interrupt to Guest (ICH_LR HW bit=1). At present
GIC on HiSilicon platforms(D02/D03) has issues with this
feature and causes CPU stall.
This patch uses non mapped timer irq inject into the Guest.
When Guest deactivates the timer irq, a maintenance EOI irq
is generated and KVM handles the deactivation on phys distributor.
Signed-off-by: shameer <shamiali2008@gmail.com>
Remove dts and change matching to HIP05/HIP06
Disable pr_warn("Unexpected interrupt %d on vcpu %p\n", irq, vcpu);
There is a bug in D03 board that doesn't always clear interrupt,
but this doesn't impact the functionality, so disable the warning.
Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
-rw-r--r-- | drivers/irqchip/irq-gic-v3.c | 29 | ||||
-rw-r--r-- | include/kvm/arm_vgic.h | 5 | ||||
-rw-r--r-- | include/linux/irqchip/arm-gic-common.h | 2 | ||||
-rw-r--r-- | virt/kvm/arm/arch_timer.c | 15 | ||||
-rw-r--r-- | virt/kvm/arm/vgic/vgic-v3.c | 9 |
5 files changed, 55 insertions, 5 deletions
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index c132f29322cc..19b95834cc05 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -1100,6 +1100,10 @@ static void __init gic_of_setup_kvm_info(struct device_node *node) if (!gic_v3_kvm_info.maint_irq) return; + /* HiSilicon GIC quirk: virtual timer irq map not supported */ + gic_v3_kvm_info.hisi_vtimer_quirk = of_property_read_bool(node, + "hisi-kvm-vtimer-quirk"); + if (of_property_read_u32(node, "#redistributor-regions", &gicv_idx)) gicv_idx = 1; @@ -1378,6 +1382,29 @@ static bool __init gic_acpi_collect_virt_info(void) #define ACPI_GICV2_VCTRL_MEM_SIZE (SZ_4K) #define ACPI_GICV2_VCPU_MEM_SIZE (SZ_8K) +static void __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) +{ + /* + * Workaround for D02 and D03, disable virt timer interrupt + * mapping because GIC on D02 and D03 don't support that + */ + if (!strncmp(oem_id, "HISI", 4) && + (!strncmp(oem_table_id, "HIP05", 5) || + !strncmp(oem_table_id, "HIP06", 5))) + gic_v3_kvm_info.hisi_vtimer_quirk = true; +} + +static int __init acpi_parse_madt(struct acpi_table_header *table) +{ + struct acpi_table_madt *acpi_madt; + + acpi_madt = (struct acpi_table_madt *)table; + acpi_madt_oem_check(acpi_madt->header.oem_id, + acpi_madt->header.oem_table_id); + + return 0; +} + static void __init gic_acpi_setup_kvm_info(void) { int irq; @@ -1387,6 +1414,8 @@ static void __init gic_acpi_setup_kvm_info(void) return; } + acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt); + gic_v3_kvm_info.type = GIC_V3; irq = acpi_register_gsi(NULL, acpi_data.maint_irq, diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index ef718586321c..7d9af5cc00a1 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -77,6 +77,11 @@ struct vgic_global { extern struct vgic_global kvm_vgic_global_state; +/*HiSilicon quirk: vtimer irqmap not supported*/ +extern struct static_key_false hisi_vtimer_quirk_enabled; +#define needs_hisi_vtimer_quirk() \ + static_branch_unlikely(&hisi_vtimer_quirk_enabled) + #define VGIC_V2_MAX_LRS (1 << 6) #define VGIC_V3_MAX_LRS 16 #define VGIC_V3_LR_INDEX(lr) (VGIC_V3_MAX_LRS - 1 - lr) diff --git a/include/linux/irqchip/arm-gic-common.h b/include/linux/irqchip/arm-gic-common.h index c647b0547bcd..964f672854d9 100644 --- a/include/linux/irqchip/arm-gic-common.h +++ b/include/linux/irqchip/arm-gic-common.h @@ -27,6 +27,8 @@ struct gic_kvm_info { unsigned int maint_irq; /* Virtual control interface */ struct resource vctrl; + /* HiSilicon GIC quirk: virtual timer irq map not supported */ + bool hisi_vtimer_quirk; }; const struct gic_kvm_info *gic_get_kvm_info(void); diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c index 5976609ef27c..43159a238746 100644 --- a/virt/kvm/arm/arch_timer.c +++ b/virt/kvm/arm/arch_timer.c @@ -69,15 +69,17 @@ static void timer_disarm(struct arch_timer_cpu *timer) static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id) { - struct kvm_vcpu *vcpu = *(struct kvm_vcpu **)dev_id; /* + struct kvm_vcpu *vcpu = *(struct kvm_vcpu **)dev_id; + * We disable the timer in the world switch and let it be * handled by kvm_timer_sync_hwstate(). Getting a timer * interrupt at this point is a sure sign of some major * breakage. - */ pr_warn("Unexpected interrupt %d on vcpu %p\n", irq, vcpu); + + */ return IRQ_HANDLED; } @@ -650,10 +652,13 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu) /* * Tell the VGIC that the virtual interrupt is tied to a * physical interrupt. We do that once per VCPU. + * HiSilicon quirk: virtual timer irq map not supported. */ - ret = kvm_vgic_map_phys_irq(vcpu, vtimer->irq.irq, phys_irq); - if (ret) - return ret; + if (!needs_hisi_vtimer_quirk()) { + ret = kvm_vgic_map_phys_irq(vcpu, vtimer->irq.irq, phys_irq); + if (ret) + return ret; + } no_vgic: timer->enabled = 1; diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c index 6fe3f003636a..bc4f7cc6fd05 100644 --- a/virt/kvm/arm/vgic/vgic-v3.c +++ b/virt/kvm/arm/vgic/vgic-v3.c @@ -21,6 +21,9 @@ #include "vgic.h" +DEFINE_STATIC_KEY_FALSE(hisi_vtimer_quirk_enabled); +EXPORT_SYMBOL_GPL(hisi_vtimer_quirk_enabled); + void vgic_v3_set_underflow(struct kvm_vcpu *vcpu) { struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3; @@ -429,6 +432,12 @@ int vgic_v3_probe(const struct gic_kvm_info *info) kvm_vgic_global_state.can_emulate_gicv2 = false; kvm_vgic_global_state.ich_vtr_el2 = ich_vtr_el2; + /* HiSilicon Quirk: virt timer irqmap not supported */ + if (info->hisi_vtimer_quirk) { + static_branch_enable(&hisi_vtimer_quirk_enabled); + pr_info("kvm: Enabling HiSilicon GIC virt timer quirk\n"); + } + if (!info->vcpu.start) { kvm_info("GICv3: no GICV resource entry\n"); kvm_vgic_global_state.vcpu_base = 0; |