From: Xiang Chen chenxiang66@hisilicon.com
virt inclusion category: other bugzilla: https://gitee.com/openeuler/kernel/issues/I9SGLA
------------------------------------------------------------------
For gicv4.0 of hip09, it has a soc bug with vPE schedule: when multiple vPEs are sending vpe schedule/deschedule commands concurrently and repeatly, some vPE schedule command may not be scheduled, and it will cause the command timeout. To avoid the issue, limit the number of vLPI to 4096 for virtual machine.
Signed-off-by: Xiang Chen chenxiang66@hisilicon.com Signed-off-by: caijian caijian11@h-partners.com --- arch/arm64/kvm/vgic/vgic-init.c | 1 + arch/arm64/kvm/vgic/vgic-mmio-v3.c | 5 +++++ arch/arm64/kvm/vgic/vgic-mmio.h | 2 ++ drivers/irqchip/irq-gic-v3.c | 20 ++++++++++++++++++++ include/kvm/arm_vgic.h | 1 + include/linux/irqchip/arm-gic-common.h | 1 + include/linux/irqchip/arm-gic-v3.h | 2 ++ 7 files changed, 32 insertions(+)
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c index e711c878e563..d38c1d513768 100644 --- a/arch/arm64/kvm/vgic/vgic-init.c +++ b/arch/arm64/kvm/vgic/vgic-init.c @@ -522,6 +522,7 @@ int kvm_vgic_hyp_init(void) return -ENXIO; }
+ kvm_vgic_global_state.flags = gic_kvm_info->flags; switch (gic_kvm_info->type) { case GIC_V2: ret = vgic_v2_probe(gic_kvm_info); diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c index 8b90e2cde9b9..bfaa3a452565 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c +++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c @@ -81,6 +81,11 @@ static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu, if (vgic_has_its(vcpu->kvm)) { value |= (INTERRUPT_ID_BITS_ITS - 1) << 19; value |= GICD_TYPER_LPIS; + /* Limit the number of vlpis to 4096 */ + if (kvm_vgic_global_state.flags & + FLAGS_WORKAROUND_HIP09_ERRATUM_162200803) + value |= 11 << GICD_TYPER_NUM_LPIS_SHIFT; + } else { value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19; } diff --git a/arch/arm64/kvm/vgic/vgic-mmio.h b/arch/arm64/kvm/vgic/vgic-mmio.h index dcea44015985..7de51e059698 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio.h +++ b/arch/arm64/kvm/vgic/vgic-mmio.h @@ -5,6 +5,8 @@ #ifndef __KVM_ARM_VGIC_MMIO_H__ #define __KVM_ARM_VGIC_MMIO_H__
+#define FLAGS_WORKAROUND_HIP09_ERRATUM_162200803 (1ULL << 4) + struct vgic_register_region { unsigned int reg_offset; unsigned int len; diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index ebb22a443f1d..5371a8d8e027 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -36,6 +36,7 @@ #define FLAGS_WORKAROUND_GICR_WAKER_MSM8996 (1ULL << 0) #define FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539 (1ULL << 1) #define FLAGS_WORKAROUND_MTK_GICR_SAVE (1ULL << 2) +#define FLAGS_WORKAROUND_HIP09_ERRATUM_162200803 (1ULL << 4)
#define GIC_IRQ_TYPE_PARTITION (GIC_IRQ_TYPE_LPI + 1)
@@ -1700,6 +1701,15 @@ static bool gic_enable_quirk_hip06_07(void *data) return false; }
+static bool gic_enable_quirk_hip09_162200803(void *data) +{ + struct gic_chip_data *d = data; + + d->flags |= FLAGS_WORKAROUND_HIP09_ERRATUM_162200803; + + return true; +} + static const struct gic_quirk gic_quirks[] = { { .desc = "GICv3: Qualcomm MSM8996 broken firmware", @@ -1736,6 +1746,12 @@ static const struct gic_quirk gic_quirks[] = { .mask = 0xe8f00fff, .init = gic_enable_quirk_cavium_38539, }, + { + .desc = "GICv3: HIP09 erratum 162200803", + .iidr = 0x01050736, + .mask = 0xffffffff, + .init = gic_enable_quirk_hip09_162200803, + }, { } }; @@ -2036,6 +2052,8 @@ static void __init gic_of_setup_kvm_info(struct device_node *node) gic_v3_kvm_info.has_v4 = gic_data.rdists.has_vlpis; gic_v3_kvm_info.has_v4_1 = gic_data.rdists.has_rvpeid; gic_v3_kvm_info.has_vtimer = gic_data.rdists.has_vtimer; + if (gic_v3_kvm_info.has_v4 && !gic_v3_kvm_info.has_v4_1) + gic_v3_kvm_info.flags = gic_data.flags; gic_set_kvm_info(&gic_v3_kvm_info); }
@@ -2353,6 +2371,8 @@ static void __init gic_acpi_setup_kvm_info(void) gic_v3_kvm_info.has_v4 = gic_data.rdists.has_vlpis; gic_v3_kvm_info.has_v4_1 = gic_data.rdists.has_rvpeid; gic_v3_kvm_info.has_vtimer = gic_data.rdists.has_vtimer; + if (gic_v3_kvm_info.has_v4 && !gic_v3_kvm_info.has_v4_1) + gic_v3_kvm_info.flags = gic_data.flags; gic_set_kvm_info(&gic_v3_kvm_info); }
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index b402e064ff3b..1d987bf1e70a 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -110,6 +110,7 @@ struct vgic_global { struct static_key_false gicv3_cpuif;
u32 ich_vtr_el2; + u64 flags; };
extern struct vgic_global kvm_vgic_global_state; diff --git a/include/linux/irqchip/arm-gic-common.h b/include/linux/irqchip/arm-gic-common.h index 9b2c86a09a47..9ace08bb15ba 100644 --- a/include/linux/irqchip/arm-gic-common.h +++ b/include/linux/irqchip/arm-gic-common.h @@ -37,6 +37,7 @@ struct gic_kvm_info { /* vtimer irqbypass support */ bool has_vtimer;
+ u64 flags; };
const struct gic_kvm_info *gic_get_kvm_info(void); diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index e5c5b05c9c5a..88b02e3b81da 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -79,6 +79,8 @@ #define GICD_CTLR_ENABLE_SS_G1 (1U << 1) #define GICD_CTLR_ENABLE_SS_G0 (1U << 0)
+#define GICD_TYPER_NUM_LPIS_SHIFT 11 + #define GICD_TYPER_RSS (1U << 26) #define GICD_TYPER_LPIS (1U << 17) #define GICD_TYPER_MBIS (1U << 16)
virt inclusion category: other bugzilla: https://gitee.com/openeuler/kernel/issues/I9SGLA
-------------------------------------------------------------
For gicv4.1 of hip09, it has a soc bug with the status of vpe pending is inaccurate, so read the pending status from memory to fix the issue.
Signed-off-by: Kunkun Jiang jiangkunkun@huawei.com Signed-off-by: Xiang Chen chenxiang66@hisilicon.com Signed-off-by: caijian caijian11@h-partners.com --- arch/arm64/kvm/vgic/vgic-mmio-v3.c | 24 ++++++++++++++++++++---- arch/arm64/kvm/vgic/vgic-mmio.h | 1 + drivers/irqchip/irq-gic-v3.c | 16 ++++++++++++++++ 3 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c index bfaa3a452565..b6bdf22abab1 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c +++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c @@ -313,6 +313,7 @@ static unsigned long vgic_mmio_read_v3_idregs(struct kvm_vcpu *vcpu, return 0; }
+#define VIRTUAL_SGI_PENDING_OFFSET 0x3F0 static unsigned long vgic_v3_uaccess_read_pending(struct kvm_vcpu *vcpu, gpa_t addr, unsigned int len) { @@ -332,12 +333,27 @@ static unsigned long vgic_v3_uaccess_read_pending(struct kvm_vcpu *vcpu, bool state = irq->pending_latch;
if (vgic_direct_sgi_or_ppi(irq)) { - int err; - - err = irq_get_irqchip_state(irq->host_irq, + if (vgic_irq_is_sgi(irq->intid) && + (kvm_vgic_global_state.flags & + FLAGS_WORKAROUND_HIP09_ERRATUM_162200806)) { + struct its_vpe *vpe; + void *va; + u8 *ptr; + int mask; + + vpe = &vcpu->arch.vgic_cpu.vgic_v3.its_vpe; + mask = BIT(irq->intid % BITS_PER_BYTE); + va = page_address(vpe->vpt_page); + ptr = va + VIRTUAL_SGI_PENDING_OFFSET + + irq->intid / BITS_PER_BYTE; + state = *ptr & mask; + } else { + int err; + err = irq_get_irqchip_state(irq->host_irq, IRQCHIP_STATE_PENDING, &state); - WARN_ON(err); + WARN_ON(err); + } }
if (state) diff --git a/arch/arm64/kvm/vgic/vgic-mmio.h b/arch/arm64/kvm/vgic/vgic-mmio.h index 7de51e059698..3c6bd9005acb 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio.h +++ b/arch/arm64/kvm/vgic/vgic-mmio.h @@ -6,6 +6,7 @@ #define __KVM_ARM_VGIC_MMIO_H__
#define FLAGS_WORKAROUND_HIP09_ERRATUM_162200803 (1ULL << 4) +#define FLAGS_WORKAROUND_HIP09_ERRATUM_162200806 (1ULL << 5)
struct vgic_register_region { unsigned int reg_offset; diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 5371a8d8e027..8b2a45fbc9f7 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -37,6 +37,7 @@ #define FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539 (1ULL << 1) #define FLAGS_WORKAROUND_MTK_GICR_SAVE (1ULL << 2) #define FLAGS_WORKAROUND_HIP09_ERRATUM_162200803 (1ULL << 4) +#define FLAGS_WORKAROUND_HIP09_ERRATUM_162200806 (1ULL << 5)
#define GIC_IRQ_TYPE_PARTITION (GIC_IRQ_TYPE_LPI + 1)
@@ -1710,6 +1711,15 @@ static bool gic_enable_quirk_hip09_162200803(void *data) return true; }
+static bool __maybe_unused gic_enable_quirk_hip09_162200806(void *data) +{ + struct gic_chip_data *d = data; + + d->flags |= FLAGS_WORKAROUND_HIP09_ERRATUM_162200806; + + return true; +} + static const struct gic_quirk gic_quirks[] = { { .desc = "GICv3: Qualcomm MSM8996 broken firmware", @@ -1752,6 +1762,12 @@ static const struct gic_quirk gic_quirks[] = { .mask = 0xffffffff, .init = gic_enable_quirk_hip09_162200803, }, + { + .desc = "GICv3: HIP09 erratum 162200806", + .iidr = 0x01050736, + .mask = 0xffffffff, + .init = gic_enable_quirk_hip09_162200806, + }, { } };
virt inclusion category: other bugzilla: https://gitee.com/openeuler/kernel/issues/I9SGLA
-------------------------------------------------------------
In allocate_vpe_l1_table, when we fail to inherit VPE table from other redistributors or ITSs, and we allocate a new vpe table for current common affinity field without checking whether indirect table is supported. Let's fix it.
Signed-off-by: Nianyao Tang tangnianyao@huawei.com Signed-off-by: Marc Zyngier maz@kernel.org Signed-off-by: Kunkun Jiang jiangkunkun@huawei.com --- drivers/irqchip/irq-gic-v3-its.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 8a716da480b0..2c2f23f35904 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -3208,6 +3208,7 @@ static int allocate_vpe_l1_table(void) unsigned int psz = SZ_64K; unsigned int np, epp, esz; struct page *page; + bool indirect;
if (!gic_rdists->has_rvpeid) return 0; @@ -3242,10 +3243,12 @@ static int allocate_vpe_l1_table(void)
/* First probe the page size */ val = FIELD_PREP(GICR_VPROPBASER_4_1_PAGE_SIZE, GIC_PAGE_SIZE_64K); + val |= GICR_VPROPBASER_4_1_INDIRECT; gicr_write_vpropbaser(val, vlpi_base + GICR_VPROPBASER); val = gicr_read_vpropbaser(vlpi_base + GICR_VPROPBASER); gpsz = FIELD_GET(GICR_VPROPBASER_4_1_PAGE_SIZE, val); esz = FIELD_GET(GICR_VPROPBASER_4_1_ENTRY_SIZE, val); + indirect = !!(val & GICR_VPROPBASER_4_1_INDIRECT);
switch (gpsz) { default: @@ -3278,7 +3281,7 @@ static int allocate_vpe_l1_table(void) * If we need more than just a single L1 page, flag the table * as indirect and compute the number of required L1 pages. */ - if (epp < ITS_MAX_VPEID) { + if (epp < ITS_MAX_VPEID && indirect) { int nl2;
val |= GICR_VPROPBASER_4_1_INDIRECT; @@ -3289,7 +3292,8 @@ static int allocate_vpe_l1_table(void) /* Number of L1 pages to point to the L2 pages */ npg = DIV_ROUND_UP(nl2 * SZ_8, psz); } else { - npg = 1; + npg = DIV_ROUND_UP(ITS_MAX_VPEID, epp); + npg = clamp_val(npg, 1, (GICR_VPROPBASER_4_1_SIZE + 1)); }
val |= FIELD_PREP(GICR_VPROPBASER_4_1_SIZE, npg - 1);