
virt inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IC7KH5 ------------------------------------------------------------------------ Add ARM64_HISI_IPIV config to control whether enable the IPIV feature. The IPIV feature optimizes vSGI performance based on GICv4.1 and is a feature of HIP12. Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- arch/arm64/Kconfig | 13 +++++++++++ arch/arm64/configs/openeuler_defconfig | 1 + arch/arm64/include/asm/kvm_host.h | 3 +++ arch/arm64/kvm/arm.c | 12 ++++++++++ arch/arm64/kvm/hisilicon/hisi_virt.c | 5 ++++ arch/arm64/kvm/hisilicon/hisi_virt.h | 12 ++++++++-- arch/arm64/kvm/sys_regs.c | 4 ++++ arch/arm64/kvm/vgic/vgic-init.c | 10 ++++---- arch/arm64/kvm/vgic/vgic-mmio-v3.c | 2 ++ drivers/irqchip/irq-gic-v3-its.c | 32 ++++++++++++++++++++------ drivers/irqchip/irq-gic-v3.c | 4 ++++ include/linux/irqchip/arm-gic-v3.h | 4 ++++ include/linux/irqchip/arm-gic-v4.h | 2 ++ 13 files changed, 90 insertions(+), 14 deletions(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 1eb959318ecf..3407cabacafc 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -2388,6 +2388,19 @@ config ARM64_HDBSS endmenu # "ARMv9.5 architectural features" +config ARM64_HISI_IPIV + bool "Enable support for IPIV" + default y + depends on ACPI + depends on ARM64 + help + IPIV optimizes vSGI on the basis of GICv4.1. The vCPU on the sending + side of vSGI needs to trap to Hypervisor. IPIv sends vSGI without + traping, improving performance. + + The feature will only be enabled if CPU in the system and Guest OS + support this feature. If unsure, say Y. + config ARM64_SVE bool "ARM Scalable Vector Extension support" default y diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig index 7481b12939e6..8c3adc6078da 100644 --- a/arch/arm64/configs/openeuler_defconfig +++ b/arch/arm64/configs/openeuler_defconfig @@ -573,6 +573,7 @@ CONFIG_ARM64_NMI=y CONFIG_ARM64_HDBSS=y # end of ARMv9.5 architectural features +CONFIG_ARM64_HISI_IPIV=y CONFIG_ARM64_SVE=y CONFIG_ARM64_SME=y CONFIG_ARM64_PSEUDO_NMI=y diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 80276f048aef..fd3dc6f8c366 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -1294,6 +1294,9 @@ bool kvm_arm_vcpu_stopped(struct kvm_vcpu *vcpu); extern bool force_wfi_trap; extern bool kvm_ncsnp_support; extern bool kvm_dvmbm_support; + +#ifdef CONFIG_ARM64_HISI_IPIV extern bool kvm_ipiv_support; +#endif #endif /* __ARM64_KVM_HOST_H__ */ diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 5bd31fc0e446..38ce562586f9 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -67,8 +67,10 @@ bool kvm_ncsnp_support; /* Capability of DVMBM */ bool kvm_dvmbm_support; +#ifdef CONFIG_ARM64_HISI_IPIV /* Capability of IPIV */ bool kvm_ipiv_support; +#endif /* CONFIG_ARM64_HISI_IPIV */ static DEFINE_PER_CPU(unsigned char, kvm_hyp_initialized); @@ -386,7 +388,9 @@ void kvm_arch_destroy_vm(struct kvm *kvm) #endif } +#ifdef CONFIG_ARM64_HISI_IPIV extern struct static_key_false ipiv_enable; +#endif int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) { @@ -517,12 +521,14 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) r = system_supports_hdbss(); break; #endif +#ifdef CONFIG_ARM64_HISI_IPIV case KVM_CAP_ARM_IPIV_MODE: if (static_branch_unlikely(&ipiv_enable)) r = 1; else r = 0; break; +#endif default: r = 0; } @@ -2792,16 +2798,22 @@ static __init int kvm_arm_init(void) probe_hisi_cpu_type(); kvm_ncsnp_support = hisi_ncsnp_supported(); kvm_dvmbm_support = hisi_dvmbm_supported(); +#ifdef CONFIG_ARM64_HISI_IPIV kvm_ipiv_support = hisi_ipiv_supported(); +#endif kvm_info("KVM ncsnp %s\n", kvm_ncsnp_support ? "enabled" : "disabled"); kvm_info("KVM dvmbm %s\n", kvm_dvmbm_support ? "enabled" : "disabled"); +#ifdef CONFIG_ARM64_HISI_IPIV kvm_info("KVM ipiv %s\n", kvm_ipiv_support ? "enabled" : "disabled"); +#endif if (kvm_dvmbm_support) kvm_get_pg_cfg(); +#ifdef CONFIG_ARM64_HISI_IPIV if (kvm_ipiv_support) ipiv_gicd_init(); +#endif in_hyp_mode = is_kernel_in_hyp_mode(); diff --git a/arch/arm64/kvm/hisilicon/hisi_virt.c b/arch/arm64/kvm/hisilicon/hisi_virt.c index a529c42b59c9..b527f2113599 100644 --- a/arch/arm64/kvm/hisilicon/hisi_virt.c +++ b/arch/arm64/kvm/hisilicon/hisi_virt.c @@ -12,7 +12,10 @@ static enum hisi_cpu_type cpu_type = UNKNOWN_HI_TYPE; static bool dvmbm_enabled; + +#ifdef CONFIG_ARM64_HISI_IPIV static bool ipiv_enabled; +#endif static const char * const hisi_cpu_type_str[] = { "Hisi1612", @@ -158,6 +161,7 @@ static void hardware_disable_dvmbm(void *data) write_sysreg_s(val, SYS_LSUDVM_CTRL_EL2); } +#ifdef CONFIG_ARM64_HISI_IPIV static int __init early_ipiv_enable(char *buf) { return strtobool(buf, &ipiv_enabled); @@ -193,6 +197,7 @@ void ipiv_gicd_init(void) { gic_dist_enable_ipiv(); } +#endif /* CONFIG_ARM64_HISI_IPIV */ bool hisi_dvmbm_supported(void) { diff --git a/arch/arm64/kvm/hisilicon/hisi_virt.h b/arch/arm64/kvm/hisilicon/hisi_virt.h index f0b47c020261..2101fc3023a8 100644 --- a/arch/arm64/kvm/hisilicon/hisi_virt.h +++ b/arch/arm64/kvm/hisilicon/hisi_virt.h @@ -19,7 +19,9 @@ enum hisi_cpu_type { }; /* HIP12 */ +#ifdef CONFIG_ARM64_HISI_IPIV #define AIDR_EL1_IPIV_MASK GENMASK_ULL(17, 16) +#endif /* HIP10 */ #define AIDR_EL1_DVMBM_MASK GENMASK_ULL(13, 12) #define SYS_LSUDVM_CTRL_EL2 sys_reg(3, 4, 15, 7, 4) @@ -77,9 +79,11 @@ enum hisi_cpu_type { void probe_hisi_cpu_type(void); bool hisi_ncsnp_supported(void); bool hisi_dvmbm_supported(void); +#ifdef CONFIG_ARM64_HISI_IPIV bool hisi_ipiv_supported(void); -void kvm_get_pg_cfg(void); void ipiv_gicd_init(void); +#endif /* CONFIG_ARM64_HISI_IPIV */ +void kvm_get_pg_cfg(void); int kvm_sched_affinity_vcpu_init(struct kvm_vcpu *vcpu); void kvm_sched_affinity_vcpu_destroy(struct kvm_vcpu *vcpu); @@ -98,12 +102,14 @@ static inline bool hisi_dvmbm_supported(void) { return false; } +#ifdef CONFIG_ARM64_HISI_IPIV static inline bool hisi_ipiv_supported(void) { return false; } -static inline void kvm_get_pg_cfg(void) {} static inline void ipiv_gicd_init(void) {} +#endif /* CONFIG_ARM64_HISI_IPIV */ +static inline void kvm_get_pg_cfg(void) {} static inline int kvm_sched_affinity_vcpu_init(struct kvm_vcpu *vcpu) { @@ -120,6 +126,8 @@ 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 */ +#ifdef CONFIG_ARM64_HISI_IPIV extern bool gic_dist_enable_ipiv(void); extern bool is_gicv4p1(void); +#endif /* CONFIG_ARM64_HISI_IPIV */ #endif /* __HISI_VIRT_H__ */ diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 6a3dddaddd94..4d087f18c5db 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -711,7 +711,9 @@ static u64 reset_actlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) return actlr; } +#ifdef CONFIG_ARM64_HISI_IPIV extern struct static_key_false ipiv_enable; +#endif static u64 reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) { @@ -728,6 +730,7 @@ static u64 reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) mpidr |= ((vcpu->vcpu_id >> 4) & 0xff) << MPIDR_LEVEL_SHIFT(1); mpidr |= ((vcpu->vcpu_id >> 12) & 0xff) << MPIDR_LEVEL_SHIFT(2); +#ifdef CONFIG_ARM64_HISI_IPIV if (static_branch_unlikely(&ipiv_enable)) { /* * To avoid sending multi-SGIs in guest OS, make aff1/aff2 unique @@ -735,6 +738,7 @@ static u64 reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) mpidr = (vcpu->vcpu_id & 0x0f) << MPIDR_LEVEL_SHIFT(1); mpidr |= ((vcpu->vcpu_id >> 4) & 0xff) << MPIDR_LEVEL_SHIFT(2); } +#endif mpidr |= (1ULL << 31); vcpu_write_sys_reg(vcpu, mpidr, MPIDR_EL1); diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c index 5579ca6b1d80..7a0c29c6e921 100644 --- a/arch/arm64/kvm/vgic/vgic-init.c +++ b/arch/arm64/kvm/vgic/vgic-init.c @@ -532,7 +532,7 @@ int kvm_vgic_map_resources(struct kvm *kvm) return ret; } -#ifdef CONFIG_ACPI +#ifdef CONFIG_ARM64_HISI_IPIV extern struct static_key_false ipiv_enable; static int ipiv_irq; #endif @@ -542,7 +542,7 @@ static int ipiv_irq; void kvm_vgic_cpu_up(void) { enable_percpu_irq(kvm_vgic_global_state.maint_irq, 0); -#ifdef CONFIG_ACPI +#ifdef CONFIG_ARM64_HISI_IPIV if (static_branch_unlikely(&ipiv_enable)) enable_percpu_irq(ipiv_irq, 0); #endif @@ -552,13 +552,13 @@ void kvm_vgic_cpu_up(void) void kvm_vgic_cpu_down(void) { disable_percpu_irq(kvm_vgic_global_state.maint_irq); -#ifdef CONFIG_ACPI +#ifdef CONFIG_ARM64_HISI_IPIV if (static_branch_unlikely(&ipiv_enable)) disable_percpu_irq(ipiv_irq); #endif } -#ifdef CONFIG_ACPI +#ifdef CONFIG_ARM64_HISI_IPIV static irqreturn_t vgic_ipiv_irq_handler(int irq, void *data) { kvm_info("IPIV irq handler!\n"); @@ -675,7 +675,7 @@ int kvm_vgic_hyp_init(void) kvm_info("vgic interrupt IRQ%d\n", kvm_vgic_global_state.maint_irq); -#ifdef CONFIG_ACPI +#ifdef CONFIG_ARM64_HISI_IPIV if (static_branch_unlikely(&ipiv_enable)) { ipiv_irq = acpi_register_gsi(NULL, 18, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_HIGH); diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c index d55607dcd226..ff28c0bae2d7 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c +++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c @@ -136,7 +136,9 @@ static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu, /* Switching HW SGIs? */ dist->nassgireq = val & GICD_CTLR_nASSGIreq; +#ifdef CONFIG_ARM64_HISI_IPIV dist->its_vm.nassgireq = dist->nassgireq; +#endif if (is_hwsgi != dist->nassgireq) vgic_v4_configure_vsgis(vcpu->kvm); diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 3121b9f4c710..21d4e990249e 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -388,7 +388,9 @@ static int alloc_devid_from_rsv_pools(struct rsv_devid_pool **devid_pool, #define gic_data_rdist_rd_base() (gic_data_rdist()->rd_base) #define gic_data_rdist_vlpi_base() (gic_data_rdist_rd_base() + SZ_128K) +#ifdef CONFIG_ARM64_HISI_IPIV extern struct static_key_false ipiv_enable; +#endif #ifdef CONFIG_VIRT_PLAT_DEV /* @@ -4564,6 +4566,7 @@ static void its_vpe_4_1_unmask_irq(struct irq_data *d) its_vpe_4_1_send_inv(d); } +#ifdef CONFIG_ARM64_HISI_IPIV /* IPIV private register */ #define CPU_SYS_TRAP_EL2 sys_reg(3, 4, 15, 7, 2) #define CPU_SYS_TRAP_EL2_IPIV_ENABLE_SHIFT 0 @@ -4576,36 +4579,35 @@ static void its_vpe_4_1_unmask_irq(struct irq_data *d) */ static void ipiv_disable_vsgi_trap(void) { -#ifdef CONFIG_ARM64 u64 val; /* disable guest access ICC_SGI1R_EL1 trap, enable ipiv */ val = read_sysreg_s(CPU_SYS_TRAP_EL2); val |= CPU_SYS_TRAP_EL2_IPIV_ENABLE; write_sysreg_s(val, CPU_SYS_TRAP_EL2); -#endif } static void ipiv_enable_vsgi_trap(void) { -#ifdef CONFIG_ARM64 u64 val; /* enable guest access ICC_SGI1R_EL1 trap, disable ipiv */ val = read_sysreg_s(CPU_SYS_TRAP_EL2); val &= ~CPU_SYS_TRAP_EL2_IPIV_ENABLE; write_sysreg_s(val, CPU_SYS_TRAP_EL2); -#endif } +#endif /* CONFIG_ARM64_HISI_IPIV */ static void its_vpe_4_1_schedule(struct its_vpe *vpe, struct its_cmd_info *info) { void __iomem *vlpi_base = gic_data_rdist_vlpi_base(); + u64 val = 0; + +#ifdef CONFIG_ARM64_HISI_IPIV struct its_vm *vm = vpe->its_vm; unsigned long vpeid_page_addr; u64 ipiv_val = 0; - u64 val = 0; u32 nr_vpes; if (static_branch_unlikely(&ipiv_enable) && @@ -4627,6 +4629,7 @@ static void its_vpe_4_1_schedule(struct its_vpe *vpe, ipiv_disable_vsgi_trap(); } +#endif /* CONFIG_ARM64_HISI_IPIV */ /* Schedule the VPE */ val |= GICR_VPENDBASER_Valid; @@ -4641,9 +4644,12 @@ static void its_vpe_4_1_deschedule(struct its_vpe *vpe, struct its_cmd_info *info) { void __iomem *vlpi_base = gic_data_rdist_vlpi_base(); - struct its_vm *vm = vpe->its_vm; u64 val; +#ifdef CONFIG_ARM64_HISI_IPIV + struct its_vm *vm = vpe->its_vm; +#endif + if (info->req_db) { unsigned long flags; @@ -4674,6 +4680,7 @@ static void its_vpe_4_1_deschedule(struct its_vpe *vpe, vpe->pending_last = true; } +#ifdef CONFIG_ARM64_HISI_IPIV if (static_branch_unlikely(&ipiv_enable) && vm->nassgireq) { /* wait gicr_ipiv_busy */ @@ -4684,6 +4691,7 @@ static void its_vpe_4_1_deschedule(struct its_vpe *vpe, ipiv_enable_vsgi_trap(); } +#endif } static void its_vpe_4_1_invall(struct its_vpe *vpe) @@ -5086,10 +5094,12 @@ 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); +#ifdef CONFIG_ARM64_HISI_IPIV if (static_branch_unlikely(&ipiv_enable)) { free_pages((unsigned long)page_address(vm->vpeid_page), get_order(nr_irqs * 2)); } +#endif } } @@ -5099,10 +5109,14 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virq struct irq_chip *irqchip = &its_vpe_irq_chip; struct its_vm *vm = args; unsigned long *bitmap; - struct page *vprop_page, *vpeid_page; + struct page *vprop_page; int base, nr_ids, i, err = 0; + +#ifdef CONFIG_ARM64_HISI_IPIV + struct page *vpeid_page; void *vpeid_table_va; u16 *vpeid_entry; +#endif bitmap = its_lpi_alloc(roundup_pow_of_two(nr_irqs), &base, &nr_ids); if (!bitmap) @@ -5127,6 +5141,7 @@ 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; +#ifdef CONFIG_ARM64_HISI_IPIV if (static_branch_unlikely(&ipiv_enable)) { /* * The vpeid's size is 2 bytes, so we need to allocate 2 * @@ -5141,6 +5156,7 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virq vm->vpeid_page = vpeid_page; vpeid_table_va = page_address(vpeid_page); } +#endif } for (i = 0; i < nr_irqs; i++) { @@ -5148,10 +5164,12 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virq err = its_vpe_init(vm->vpes[i]); if (err) break; +#ifdef CONFIG_ARM64_HISI_IPIV if (static_branch_unlikely(&ipiv_enable)) { vpeid_entry = (u16 *)vpeid_table_va + i; *vpeid_entry = vm->vpes[i]->vpe_id; } +#endif err = its_irq_gic_domain_alloc(domain, virq + i, vm->vpes[i]->vpe_db_lpi); if (err) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 7a64d77be181..2a458aa94af0 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -111,8 +111,10 @@ static DEFINE_STATIC_KEY_FALSE(supports_pseudo_nmis); DEFINE_STATIC_KEY_FALSE(gic_nonsecure_priorities); EXPORT_SYMBOL(gic_nonsecure_priorities); +#ifdef CONFIG_ARM64_HISI_IPIV DEFINE_STATIC_KEY_FALSE(ipiv_enable); EXPORT_SYMBOL(ipiv_enable); +#endif /* * When the Non-secure world has access to group 0 interrupts (as a @@ -1514,6 +1516,7 @@ static int gic_dist_supports_lpis(void) !gicv3_nolpi); } +#ifdef CONFIG_ARM64_HISI_IPIV bool is_gicv4p1(void) { if (!gic_data.rdists.has_rvpeid) @@ -1543,6 +1546,7 @@ void gic_dist_enable_ipiv(void) writel_relaxed(0x4880, gic_data.dist_base + GICD_IPIV_ITS_TA_BASE); } EXPORT_SYMBOL(gic_dist_enable_ipiv); +#endif /* CONFIG_ARM64_HISI_IPIV */ static void gic_cpu_init(void) { diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 01584f2abf90..ddfacc6dd8cd 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -113,6 +113,7 @@ #define GIC_PAGE_SIZE_64K 2ULL #define GIC_PAGE_SIZE_MASK 3ULL +#ifdef CONFIG_ARM64_HISI_IPIV #define GICD_MISC_CTRL 0x2084 #define GICD_MISC_CTRL_CFG_IPIV_EN (1U << 19) @@ -124,6 +125,7 @@ #define GICD_IPIV_CTRL_VM_TABLE_INNERCACHE_SHIFT 16 #define GICD_IPIV_CTRL_VM_TABLE_SHAREABILITY_SHIFT 19 #define GICD_IPIV_ITS_TA_BASE 0xc010 +#endif /* * Re-Distributor registers, offsets from RD_base @@ -374,6 +376,7 @@ #define GICR_VSGIPENDR_BUSY (1U << 31) #define GICR_VSGIPENDR_PENDING GENMASK(15, 0) +#ifdef CONFIG_ARM64_HISI_IPIV /* IPIV VM table address */ #define GICR_VM_TABLE_BAR_L 0x140 #define GICR_VM_TABLE_BAR_H 0x144 @@ -388,6 +391,7 @@ #define GICR_IPIV_ST 0x14c #define GICR_IPIV_ST_IPIV_BUSY_SHIFT 0 #define GICR_IPIV_ST_IPIV_BUSY (1 << GICR_IPIV_ST_IPIV_BUSY_SHIFT) +#endif /* CONFIG_ARM64_HISI_IPIV */ /* * ITS registers, offsets from ITS_base diff --git a/include/linux/irqchip/arm-gic-v4.h b/include/linux/irqchip/arm-gic-v4.h index 9109a841c8da..e16a89aeed72 100644 --- a/include/linux/irqchip/arm-gic-v4.h +++ b/include/linux/irqchip/arm-gic-v4.h @@ -34,8 +34,10 @@ struct its_vm { */ raw_spinlock_t vmapp_lock; u32 vlpi_count[GICv4_ITS_LIST_MAX]; +#ifdef CONFIG_ARM64_HISI_IPIV KABI_EXTEND(struct page *vpeid_page) KABI_EXTEND(bool nassgireq) +#endif }; /* Embedded in kvm_vcpu.arch */ -- 2.33.0