diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst index ef58c86cd10beeebe58fcaf61383e0dc14d0fe3f..af8be06f11dff432439d81e9e49b7f6f22aa5cd2 100644 --- a/Documentation/arch/arm64/silicon-errata.rst +++ b/Documentation/arch/arm64/silicon-errata.rst @@ -213,9 +213,7 @@ stable kernels. +----------------+-----------------+-----------------+-----------------------------+ | Hisilicon | SMMUv3 | #162100602 | HISILICON_ERRATUM_162100602 | +----------------+-----------------+-----------------+-----------------------------+ -| Hisilicon | Hip09 | #162200803 | N/A | -+----------------+-----------------+-----------------+-----------------------------+ -| Hisilicon | Hip09 | #162200806 | N/A | +| Hisilicon | Hip{10,10C} | #162200803 | N/A | +----------------+-----------------+-----------------+-----------------------------+ | Qualcomm Tech. | Kryo/Falkor v1 | E1003 | QCOM_FALKOR_ERRATUM_1003 | +----------------+-----------------+-----------------+-----------------------------+ diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c index c29c0b5669a62a9965af6ea30817fa5e6f6af566..909584cd21c776cf5393a824b43b03dbee64d282 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c +++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c @@ -84,7 +84,7 @@ static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu, 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) + if (kvm_vgic_global_state.flags & FLAGS_WORKAROUND_HIP10_ERRATUM_162200803) value |= 11 << GICD_TYPER_NUM_LPIS_SHIFT; } else { diff --git a/arch/arm64/kvm/vgic/vgic-mmio.c b/arch/arm64/kvm/vgic/vgic-mmio.c index 56549ee4313c1d3a3ce3334594bc2fd3e754753d..dcd7388aa2443d2c7de8a77db210d36baae75d0f 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio.c +++ b/arch/arm64/kvm/vgic/vgic-mmio.c @@ -228,15 +228,33 @@ int vgic_uaccess_write_cenable(struct kvm_vcpu *vcpu, return 0; } +#define HIP10_MIDR 0x480fd030 #define VIRTUAL_SGI_PENDING_OFFSET 0x3F0 +static bool hip10_erratum_162200806_workaround(struct kvm_vcpu *vcpu, + struct vgic_irq *irq) +{ + struct its_vpe *vpe; + void *va; + u8 *ptr; + int mask; + + vpe = &vcpu->arch.vgic_cpu.vgic_v3.its_vpe; + WARN_ON(vpe->resident); + mask = BIT(irq->intid % BITS_PER_BYTE); + va = page_address(vpe->vpt_page); + ptr = va + VIRTUAL_SGI_PENDING_OFFSET + + irq->intid / BITS_PER_BYTE; + return *ptr & mask; +} + static unsigned long __read_pending(struct kvm_vcpu *vcpu, gpa_t addr, unsigned int len, bool is_user) { u32 intid = VGIC_ADDR_TO_INTID(addr, 1); + u32 midr = read_cpuid_id(); u32 value = 0; int i; - struct its_vpe *vpe = &vcpu->arch.vgic_cpu.vgic_v3.its_vpe; /* Loop over all IRQs affected by this read */ for (i = 0; i < len * 8; i++) { @@ -254,29 +272,20 @@ static unsigned long __read_pending(struct kvm_vcpu *vcpu, * for handling of ISPENDR and ICPENDR. */ raw_spin_lock_irqsave(&irq->irq_lock, flags); + /* direct ppi has not been commercial used */ if (vgic_direct_sgi_or_ppi(irq)) { - int err; - - if (irq->hw && vgic_irq_is_sgi(irq->intid) && - (kvm_vgic_global_state.flags & - FLAGS_WORKAROUND_HIP09_ERRATUM_162200806)) { - void *va; - u8 *ptr; - int mask; - bool is_pending; - - mask = BIT(irq->intid % BITS_PER_BYTE); - va = page_address(vpe->vpt_page); - ptr = va + VIRTUAL_SGI_PENDING_OFFSET + - irq->intid / BITS_PER_BYTE; - is_pending = *ptr & mask; - } - - val = false; - err = irq_get_irqchip_state(irq->host_irq, + if (midr == HIP10_MIDR) { + val = hip10_erratum_162200806_workaround(vcpu, + irq); + } else { + int err; + + val = false; + err = irq_get_irqchip_state(irq->host_irq, IRQCHIP_STATE_PENDING, &val); - WARN_RATELIMIT(err, "IRQ %d", irq->host_irq); + WARN_RATELIMIT(err, "IRQ %d", irq->host_irq); + } } else if (!is_user && vgic_irq_is_mapped_level(irq)) { val = vgic_get_phys_line_level(irq); } else { diff --git a/arch/arm64/kvm/vgic/vgic-mmio.h b/arch/arm64/kvm/vgic/vgic-mmio.h index 0477ec95e96cc979659368b6027995f5e2fd4d6a..47372c2ceb8d310d459138b905abb963a1b1bfdd 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio.h +++ b/arch/arm64/kvm/vgic/vgic-mmio.h @@ -5,8 +5,7 @@ #ifndef __KVM_ARM_VGIC_MMIO_H__ #define __KVM_ARM_VGIC_MMIO_H__ -#define FLAGS_WORKAROUND_HIP09_ERRATUM_162200803 (1ULL << 4) -#define FLAGS_WORKAROUND_HIP09_ERRATUM_162200806 (1ULL << 5) +#define FLAGS_WORKAROUND_HIP10_ERRATUM_162200803 (1ULL << 4) struct vgic_register_region { unsigned int reg_offset; diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index e4d148dde2b3f578c6d12cd5946fef1a5518c1d1..b6ba3d03a6fdacd368d5dba79a5dc88baad11ce3 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -3189,6 +3189,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; @@ -3223,10 +3224,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: @@ -3259,7 +3262,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; @@ -3270,7 +3273,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); diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index d287e7199cfe222467fe0217690ec2cee7b050c4..dba80bfc23f02dcc68203c04730c25cd61d88a54 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -41,8 +41,7 @@ #define FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539 (1ULL << 1) #define FLAGS_WORKAROUND_MTK_GICR_SAVE (1ULL << 2) #define FLAGS_WORKAROUND_ASR_ERRATUM_8601001 (1ULL << 3) -#define FLAGS_WORKAROUND_HIP09_ERRATUM_162200803 (1ULL << 4) -#define FLAGS_WORKAROUND_HIP09_ERRATUM_162200806 (1ULL << 5) +#define FLAGS_WORKAROUND_HIP10_ERRATUM_162200803 (1ULL << 4) #define GIC_IRQ_TYPE_PARTITION (GIC_IRQ_TYPE_LPI + 1) @@ -1993,20 +1992,11 @@ static bool rd_set_non_coherent(void *data) return true; } -static bool gic_enable_quirk_hip09_162200803(void *data) +static bool gic_enable_quirk_hip10_10C_162200803(void *data) { struct gic_chip_data *d = data; - d->flags |= FLAGS_WORKAROUND_HIP09_ERRATUM_162200803; - - 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; + d->flags |= FLAGS_WORKAROUND_HIP10_ERRATUM_162200803; return true; } @@ -2083,16 +2073,16 @@ static const struct gic_quirk gic_quirks[] = { .init = rd_set_non_coherent, }, { - .desc = "GICv3: HIP09 erratum 162200803", + .desc = "GICv3: HIP10 erratum 162200803", .iidr = 0x01050736, .mask = 0xffffffff, - .init = gic_enable_quirk_hip09_162200803, + .init = gic_enable_quirk_hip10_10C_162200803, }, { - .desc = "GICv3: HIP09 erratum 162200806", - .iidr = 0x01050736, + .desc = "GICv3: HIP10C erratum 162200803", + .iidr = 0x00061736, .mask = 0xffffffff, - .init = gic_enable_quirk_hip09_162200806, + .init = gic_enable_quirk_hip10_10C_162200803, }, { } @@ -2405,7 +2395,7 @@ static void __init gic_of_setup_kvm_info(struct device_node *node) #ifdef CONFIG_VIRT_VTIMER_IRQ_BYPASS gic_v3_kvm_info.has_vtimer = gic_data.rdists.has_vtimer; #endif - if (gic_v3_kvm_info.has_v4) + if (gic_v3_kvm_info.has_v4 && !gic_v3_kvm_info.has_v4_1) gic_v3_kvm_info.flags = gic_data.flags; vgic_set_kvm_info(&gic_v3_kvm_info); } @@ -2759,7 +2749,7 @@ static void __init gic_acpi_setup_kvm_info(void) #ifdef CONFIG_VIRT_VTIMER_IRQ_BYPASS gic_v3_kvm_info.has_vtimer = gic_data.rdists.has_vtimer; #endif - if (gic_v3_kvm_info.has_v4) + if (gic_v3_kvm_info.has_v4 && !gic_v3_kvm_info.has_v4_1) gic_v3_kvm_info.flags = gic_data.flags; vgic_set_kvm_info(&gic_v3_kvm_info); }