
From: Xiang Chen <chenxiang66@hisilicon.com> virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBPH85 ------------------------------------------------------------------------ There are two modes for IPIV feature: - indirect mode, access vm table to retrieve vpeid; - direct mode, directly calcute vpeid according to mpidr; Add support for ipiv direct mode. Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com> Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- .../admin-guide/kernel-parameters.txt | 5 ++++ arch/arm64/kvm/hisilicon/hisi_virt.c | 11 ++++++- arch/arm64/kvm/hisilicon/hisi_virt.h | 2 +- arch/arm64/kvm/sys_regs.c | 30 ++++++++++++++----- drivers/irqchip/irq-gic-v3-its.c | 19 ++++++++---- drivers/irqchip/irq-gic-v3.c | 12 +++++++- include/linux/irqchip/arm-gic-v3.h | 3 ++ 7 files changed, 65 insertions(+), 17 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 459323983fa9..000b990876fe 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2712,6 +2712,11 @@ kvm-arm.ipiv_enabled= [KVM,ARM] Allow use of HiSilicon ipiv on GICv4.1 + kvm-arm.ipiv_direct= + [KVM,ARM] Use different modes of ipiv if ipiv enabled + Default is 0 which using vmtable in memory to retrieve aff-vpeid + Directly calculate vpeid according to aff if set 1 + kvm-arm.dvmbm_enabled= [KVM,ARM] Allow use of HiSilicon DVMBM capability. Default: 0 diff --git a/arch/arm64/kvm/hisilicon/hisi_virt.c b/arch/arm64/kvm/hisilicon/hisi_virt.c index 642aff5ff7d8..89f488d4cbc6 100644 --- a/arch/arm64/kvm/hisilicon/hisi_virt.c +++ b/arch/arm64/kvm/hisilicon/hisi_virt.c @@ -13,6 +13,7 @@ static enum hisi_cpu_type cpu_type = UNKNOWN_HI_TYPE; static bool dvmbm_enabled; static bool ipiv_enabled; +static bool ipiv_direct; static const char * const hisi_cpu_type_str[] = { "Hisi1612", @@ -164,6 +165,12 @@ static int __init early_ipiv_enable(char *buf) } early_param("kvm-arm.ipiv_enabled", early_ipiv_enable); +static int __init early_ipiv_direct(char *buf) +{ + return kstrtobool(buf, &ipiv_direct); +} +early_param("kvm-arm.ipiv_direct", early_ipiv_direct); + bool hisi_ipiv_supported(void) { /* Determine whether IPIV is supported by the hardware */ @@ -178,10 +185,12 @@ bool hisi_ipiv_supported(void) return false; /* Enable IPIV feature if necessary */ - if (!gic_dist_enable_ipiv()) { + if (!gic_dist_enable_ipiv(ipiv_direct)) { kvm_info("Need to enable GICv4p1!\n"); return false; } + + kvm_info("Enable Hisi ipiv with %s mode\n", ipiv_direct ? "direct" : "indirect"); return true; } diff --git a/arch/arm64/kvm/hisilicon/hisi_virt.h b/arch/arm64/kvm/hisilicon/hisi_virt.h index ca37cc163cc7..c99a6fbe1412 100644 --- a/arch/arm64/kvm/hisilicon/hisi_virt.h +++ b/arch/arm64/kvm/hisilicon/hisi_virt.h @@ -111,5 +111,5 @@ static inline void kvm_tlbi_dvmbm_vcpu_put(struct kvm_vcpu *vcpu) {} static inline void kvm_hisi_reload_lsudvmbm(struct kvm *kvm) {} #endif /* CONFIG_KVM_HISI_VIRT */ -extern bool gic_dist_enable_ipiv(void); +extern bool gic_dist_enable_ipiv(bool direct); #endif /* __HISI_VIRT_H__ */ diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 0cfa8d93e2ee..69cbc11f5ff7 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -711,20 +711,34 @@ static u64 reset_actlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) return actlr; } +extern struct static_key_false ipiv_enable; +extern struct static_key_false ipiv_direct; + static u64 reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) { + struct its_vpe *vpe = &vcpu->arch.vgic_cpu.vgic_v3.its_vpe; u64 mpidr; /* - * Map the vcpu_id into the first three affinity level fields of - * the MPIDR. We limit the number of VCPUs in level 0 due to a - * limitation to 16 CPUs in that level in the ICC_SGIxR registers - * of the GICv3 to be able to address each CPU directly when - * sending IPIs. + * For direct ipiv mode, use vpeid as aff2/aff3 + * For indirect ipiv mode, use vcpu_id to index vpeid. To + * avoid sending multi-SGIs in guest OS, make aff1/aff2 unique */ - mpidr = (vcpu->vcpu_id & 0x0f) << MPIDR_LEVEL_SHIFT(0); - mpidr |= ((vcpu->vcpu_id >> 4) & 0xff) << MPIDR_LEVEL_SHIFT(1); - mpidr |= ((vcpu->vcpu_id >> 12) & 0xff) << MPIDR_LEVEL_SHIFT(2); + if (static_branch_unlikely(&ipiv_enable)) { + if (static_branch_unlikely(&ipiv_direct)) { + u64 vpe_id_aff3 = (vpe->vpe_id >> 8) & 0xff; + + mpidr |= ((vpe->vpe_id & 0xff) << MPIDR_LEVEL_SHIFT(2)); + mpidr |= vpe_id_aff3 << MPIDR_LEVEL_SHIFT(3); + } else { + mpidr = (vcpu->vcpu_id & 0x0f) << MPIDR_LEVEL_SHIFT(1); + mpidr |= ((vcpu->vcpu_id >> 4) & 0xff) << MPIDR_LEVEL_SHIFT(2); + } + } else { + mpidr = (vcpu->vcpu_id & 0x0f) << MPIDR_LEVEL_SHIFT(0); + mpidr |= ((vcpu->vcpu_id >> 4) & 0xff) << MPIDR_LEVEL_SHIFT(1); + mpidr |= ((vcpu->vcpu_id >> 12) & 0xff) << MPIDR_LEVEL_SHIFT(2); + } mpidr |= (1ULL << 31); vcpu_write_sys_reg(vcpu, mpidr, MPIDR_EL1); diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 9e318335b034..8ec6fd61b59d 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -389,6 +389,7 @@ static int alloc_devid_from_rsv_pools(struct rsv_devid_pool **devid_pool, #define gic_data_rdist_vlpi_base() (gic_data_rdist_rd_base() + SZ_128K) extern struct static_key_false ipiv_enable; +extern struct static_key_false ipiv_direct; #ifdef CONFIG_VIRT_PLAT_DEV /* @@ -4572,7 +4573,8 @@ static void its_vpe_4_1_schedule(struct its_vpe *vpe, unsigned long vpe_addr; u64 val = 0; - if (static_branch_unlikely(&ipiv_enable)) { + if (static_branch_unlikely(&ipiv_enable) && + !static_branch_unlikely(&ipiv_direct)) { vpe_addr = virt_to_phys(page_address(vm->vpe_page)); writeq_relaxed(vpe_addr & 0xffffffff, vlpi_base + GICR_VM_TABLE_BAR_L); @@ -4625,7 +4627,8 @@ static void its_vpe_4_1_deschedule(struct its_vpe *vpe, vpe->pending_last = true; } - if (static_branch_unlikely(&ipiv_enable)) { + if (static_branch_unlikely(&ipiv_enable) && + !static_branch_unlikely(&ipiv_direct)) { writeq_relaxed(0, vlpi_base + GICR_VM_TABLE_BAR_L); writeq_relaxed(0, vlpi_base + GICR_VM_TABLE_BAR_H); } @@ -5031,7 +5034,8 @@ static void its_vpe_irq_domain_free(struct irq_domain *domain, if (bitmap_empty(vm->db_bitmap, vm->nr_db_lpis)) { its_lpi_free(vm->db_bitmap, vm->db_lpi_base, vm->nr_db_lpis); its_free_prop_table(vm->vprop_page); - if (static_branch_unlikely(&ipiv_enable)) { + if (static_branch_unlikely(&ipiv_enable) && + !static_branch_unlikely(&ipiv_direct)) { free_pages((unsigned long)page_address(vm->vpe_page), get_order(nr_irqs * 2)); } @@ -5072,7 +5076,8 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virq if (gic_rdists->has_rvpeid) { irqchip = &its_vpe_4_1_irq_chip; - if (static_branch_unlikely(&ipiv_enable)) { + if (static_branch_unlikely(&ipiv_enable) && + !static_branch_unlikely(&ipiv_direct)) { vpe_page = alloc_pages(GFP_KERNEL, get_order(nr_irqs * 2)); if (!vpe_page) { its_lpi_free(vm->db_bitmap, vm->db_lpi_base, vm->nr_db_lpis); @@ -5089,7 +5094,8 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virq err = its_vpe_init(vm->vpes[i]); if (err) break; - if (static_branch_unlikely(&ipiv_enable)) { + if (static_branch_unlikely(&ipiv_enable) && + !static_branch_unlikely(&ipiv_direct)) { vpe_entry = (u16 *)vpe_table_va + i; *(u16 *)vpe_entry = vm->vpes[i]->vpe_id; } @@ -5105,7 +5111,8 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virq if (err) { its_vpe_irq_domain_free(domain, virq, i); - if (static_branch_unlikely(&ipiv_enable)) { + if (static_branch_unlikely(&ipiv_enable) & + !static_branch_unlikely(&ipiv_direct)) { free_pages((unsigned long)page_address(vm->vpe_page), get_order(nr_irqs * 2)); } diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index da44f67f8df7..a24160eabc1a 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -114,6 +114,9 @@ EXPORT_SYMBOL(gic_nonsecure_priorities); DEFINE_STATIC_KEY_FALSE(ipiv_enable); EXPORT_SYMBOL(ipiv_enable); +DEFINE_STATIC_KEY_FALSE(ipiv_direct); +EXPORT_SYMBOL(ipiv_direct); + /* * When the Non-secure world has access to group 0 interrupts (as a * consequence of SCR_EL3.FIQ == 0), reading the ICC_RPR_EL1 register will @@ -1514,7 +1517,7 @@ static int gic_dist_supports_lpis(void) !gicv3_nolpi); } -bool gic_dist_enable_ipiv(void) +bool gic_dist_enable_ipiv(bool direct) { u32 val; @@ -1527,6 +1530,13 @@ bool gic_dist_enable_ipiv(void) writel_relaxed(val, gic_data.dist_base + GICD_MISC_CTRL); static_branch_enable(&ipiv_enable); + val = readl_relaxed(gic_data.dist_base + GICD_IPIV_CTRL); + if (direct) { + val |= GICD_IPIV_CTRL_AFF_DIRECT_VPEID; + static_branch_enable(&ipiv_direct); + } + writel_relaxed(val, gic_data.dist_base + GICD_IPIV_CTRL); + return true; } EXPORT_SYMBOL(gic_dist_enable_ipiv); diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 904d788eed74..bc96a5b66ee9 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -116,6 +116,9 @@ #define GICD_MISC_CTRL 0x2084 #define GICD_MISC_CTRL_CFG_IPIV_EN (1U << 19) +#define GICD_IPIV_CTRL 0xc05c +#define GICD_IPIV_CTRL_AFF_DIRECT_VPEID (1U << 4) + /* * Re-Distributor registers, offsets from RD_base */ -- 2.33.0