[PATCH OLK-6.6 v3 00/11] IPIV-BUGFIX for HIP12

Compared with the previous IPIV, the IPIV-BUGFIX has the following changes: 1. Use Kconfig to Control whether to enable IPIV. 2. Users use ioctl to control whether to enable IPIV. 3. Use the SMCCC interface for Guest OS to control whether to enable IPIV. 4. ensure that enable_ipiv_from_guest are the same before and after live migration 5. make sure vcpu_id == vcpu_idx. 6. the MPIDR cannot be changed When IPIV is enabled. 7. fix bug that ipiv enable is displayed on the host when "kvm-arm.vgic_v4_enable=0 kvm-arm.ipiv_enabled=1" is configured. 8. Add Exception Printing Jinqian Yang (5): arm64/config: add config to control whether enable IPIV feature KVM: arm64: fix live migration bug of IPIv KVM: arm64: using kvm_vgic_global_state for ipiv kvm: hisi: print error for IPIV arm64/kabi: use KABI_EXTEND to skip KABI check Zhou Wang (6): KVM: arm64: Introduce ipiv enable ioctl KVM: arm64: Document PV-sgi interface KVM: arm64: Implement PV_SGI related calls irqchip/gic: Add HiSilicon PV SGI support kvm: hisi: make sure vcpu_id and vcpu_idx have same value in IPIv kvm: hisi: Don't allow to change mpidr in IPIv Documentation/virt/kvm/arm/hypercalls.rst | 4 ++ Documentation/virt/kvm/arm/pvsgi.rst | 33 ++++++++++++++ arch/arm64/Kconfig | 13 ++++++ arch/arm64/configs/openeuler_defconfig | 1 + arch/arm64/include/asm/kvm_host.h | 3 ++ arch/arm64/include/uapi/asm/kvm.h | 5 +++ arch/arm64/kvm/arm.c | 36 +++++++++++---- arch/arm64/kvm/hisilicon/hisi_virt.c | 32 ++++++++++++- arch/arm64/kvm/hisilicon/hisi_virt.h | 20 +++++++-- arch/arm64/kvm/hypercalls.c | 26 +++++++++++ arch/arm64/kvm/sys_regs.c | 34 +++++++++----- arch/arm64/kvm/vgic/vgic-init.c | 42 ++++++++++++++--- arch/arm64/kvm/vgic/vgic-its.c | 19 ++++++++ arch/arm64/kvm/vgic/vgic-mmio-v3.c | 1 - drivers/irqchip/irq-gic-v3-its.c | 50 ++++++++++++++------- drivers/irqchip/irq-gic-v3.c | 55 ++++++++++++++++++----- include/linux/arm-smccc.h | 15 +++++++ include/linux/irqchip/arm-gic-v3.h | 10 +++++ include/linux/irqchip/arm-gic-v4.h | 5 ++- include/uapi/linux/kvm.h | 2 +- 20 files changed, 348 insertions(+), 58 deletions(-) create mode 100644 Documentation/virt/kvm/arm/pvsgi.rst -- 2.33.0

virt inclusion category: feature 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

From: Zhou Wang <wangzhou1@hisilicon.com> virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IC7KH5 ------------------------------------------------------------------------ IPIV uses ioctl to be enabled. Users (such as qemu) can invoke the ioctl to enable IPIV. Otherwise, other VMMs will enable the IPIV without knowing it. As a result, multicast and broadcast cannot be supported. Signed-off-by: Zhou Wang <wangzhou1@hisilicon.com> Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- arch/arm64/kvm/arm.c | 15 ++++++++++++++- include/linux/irqchip/arm-gic-v4.h | 1 + include/uapi/linux/kvm.h | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 38ce562586f9..51c257588d4a 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -200,6 +200,14 @@ static int kvm_cap_arm_enable_hdbss(struct kvm *kvm, } #endif +#ifdef CONFIG_ARM64_HISI_IPIV +static int kvm_hisi_ipiv_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap) +{ + kvm->arch.vgic.its_vm.enable_ipiv_from_vmm = true; + return 0; +} +#endif + int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap) { @@ -258,6 +266,11 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm, case KVM_CAP_ARM_HW_DIRTY_STATE_TRACK: r = kvm_cap_arm_enable_hdbss(kvm, cap); break; +#endif +#ifdef CONFIG_ARM64_HISI_IPIV + case KVM_CAP_ARM_HISI_IPIV: + r = kvm_hisi_ipiv_enable_cap(kvm, cap); + break; #endif default: r = -EINVAL; @@ -522,7 +535,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) break; #endif #ifdef CONFIG_ARM64_HISI_IPIV - case KVM_CAP_ARM_IPIV_MODE: + case KVM_CAP_ARM_HISI_IPIV: if (static_branch_unlikely(&ipiv_enable)) r = 1; else diff --git a/include/linux/irqchip/arm-gic-v4.h b/include/linux/irqchip/arm-gic-v4.h index e16a89aeed72..8743741e7a52 100644 --- a/include/linux/irqchip/arm-gic-v4.h +++ b/include/linux/irqchip/arm-gic-v4.h @@ -37,6 +37,7 @@ struct its_vm { #ifdef CONFIG_ARM64_HISI_IPIV KABI_EXTEND(struct page *vpeid_page) KABI_EXTEND(bool nassgireq) + bool enable_ipiv_from_vmm; #endif }; diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 938613c25553..fd9991b243cd 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1211,7 +1211,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_HYGON_COCO_EXT_CSV3_INJ_SECRET (1 << 2) #define KVM_CAP_ARM_HW_DIRTY_STATE_TRACK 502 -#define KVM_CAP_ARM_IPIV_MODE 503 +#define KVM_CAP_ARM_HISI_IPIV 503 #define KVM_CAP_ARM_VIRT_MSI_BYPASS 799 -- 2.33.0

From: Zhou Wang <wangzhou1@hisilicon.com> virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IC7KH5 ------------------------------------------------------------------------ Introduce a paravirtualization interface for KVM/arm64 to PV-sgi. A hypercall interface is provided for the guest to interrogate the hypervisor's support for IPIV. In the previous IPIV implementation, the MPIDR value of the vCPU needs to be changed to prevent guests from sending multicast and broadcast. This series of bugfix patches provide a method: Add the SMCCC interface to the kernel so that the guest OS can control the enabling of IPIV. When IPIV is enabled, the guest OS uses multiple unicast to implement multicast. (Broadcasting cannot be implemented due to hardware limitations. If a guest sends a broadcast, an exception message is displayed on the host.) In this way, do not need to modify the MPIDR. Signed-off-by: Zhou Wang <wangzhou1@hisilicon.com> Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- Documentation/virt/kvm/arm/hypercalls.rst | 4 +++ Documentation/virt/kvm/arm/pvsgi.rst | 33 +++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 Documentation/virt/kvm/arm/pvsgi.rst diff --git a/Documentation/virt/kvm/arm/hypercalls.rst b/Documentation/virt/kvm/arm/hypercalls.rst index 3e23084644ba..67bd102cf43b 100644 --- a/Documentation/virt/kvm/arm/hypercalls.rst +++ b/Documentation/virt/kvm/arm/hypercalls.rst @@ -127,6 +127,10 @@ The pseudo-firmware bitmap register are as follows: Bit-1: KVM_REG_ARM_VENDOR_HYP_BIT_PTP: The bit represents the Precision Time Protocol KVM service. + Bit-2: KVM_REG_ARM_VENDOR_HYP_BIT_IPIV: + The bit represents the ARM_SMCCC_VENDOR_PV_SGI_FEATURES and + ARM_SMCCC_VENDOR_PV_SGI_ENABLE function-ids. + Errors: ======= ============================================================= diff --git a/Documentation/virt/kvm/arm/pvsgi.rst b/Documentation/virt/kvm/arm/pvsgi.rst new file mode 100644 index 000000000000..5f12a3aaccd2 --- /dev/null +++ b/Documentation/virt/kvm/arm/pvsgi.rst @@ -0,0 +1,33 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Paravirtualized SGI support for HiSilicon +========================================== + +KVM/arm64 provides some hypervisor service calls to support a paravirtualized +SGI(software generated interrupt) in HiSilicon Hip12 SoC. + +Some SMCCC compatible hypercalls are defined: + +* PV_SGI_FEATURES: 0xC6000090 +* PV_SGI_ENABLE: 0xC6000091 + +The existence of the PV_SGI hypercall should be probed using the SMCCC 1.1 +ARCH_FEATURES mechanism before calling it. + +PV_SGI_FEATURES + + ============= ======== ========== + Function ID: (uint32) 0xC6000090 + PV_call_id: (uint32) The function to query for support. + Currently only PV_SGI_ENABLE is supported. + Return value: (int64) NOT_SUPPORTED (-1) or SUCCESS (0) if the relevant + PV-sgi feature is supported by the hypervisor. + ============= ======== ========== + +PV_SGI_ENABLE + + ============= ======== ========== + Function ID: (uint32) 0xC6000091 + Return value: (int64) NOT_SUPPORTED (-1) or SUCCESS (0) if this feature + has been enabled. + ============= ======== ========== -- 2.33.0

From: Zhou Wang <wangzhou1@hisilicon.com> virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IC7KH5 ------------------------------------------------------------------------ This provides a mechanism for querying whether IPIV are available in this hypervisor. Add some SMCCC compatible hypercalls for PV SGI: PV_SGI_FEATURES: 0xC6000090 PV_SGI_ENABLE: 0xC6000091 ipiv_enable is a global variable, indicating whether the hardware supports IPIV. enable_ipiv_from_vmm indicates whether the VMM (such as QEMU) enables IPIV through ioctl. enable_ipiv_from_guest indicates whether the guest OS enables IPIV through the SMCCC interface. Signed-off-by: Zhou Wang <wangzhou1@hisilicon.com> Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- arch/arm64/include/uapi/asm/kvm.h | 5 +++++ arch/arm64/kvm/hisilicon/hisi_virt.c | 25 +++++++++++++++++++++++++ arch/arm64/kvm/hisilicon/hisi_virt.h | 7 +++++++ arch/arm64/kvm/hypercalls.c | 26 ++++++++++++++++++++++++++ arch/arm64/kvm/vgic/vgic-mmio-v3.c | 3 --- drivers/irqchip/irq-gic-v3-its.c | 16 +++++----------- include/linux/arm-smccc.h | 15 +++++++++++++++ include/linux/irqchip/arm-gic-v4.h | 2 +- 8 files changed, 84 insertions(+), 15 deletions(-) diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index 97941e582d83..196231712b10 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -377,6 +377,11 @@ enum { enum { KVM_REG_ARM_VENDOR_HYP_BIT_FUNC_FEAT = 0, KVM_REG_ARM_VENDOR_HYP_BIT_PTP = 1, + /* + * If the mainline conflicts, do not change the + * current sequence, add in sequence. + */ + KVM_REG_ARM_VENDOR_HYP_BIT_IPIV = 2, #ifdef __KERNEL__ KVM_REG_ARM_VENDOR_HYP_BMAP_BIT_COUNT, #endif diff --git a/arch/arm64/kvm/hisilicon/hisi_virt.c b/arch/arm64/kvm/hisilicon/hisi_virt.c index b527f2113599..6a7c3a7f7a69 100644 --- a/arch/arm64/kvm/hisilicon/hisi_virt.c +++ b/arch/arm64/kvm/hisilicon/hisi_virt.c @@ -193,6 +193,31 @@ bool hisi_ipiv_supported(void) return true; } +extern struct static_key_false ipiv_enable; + +bool hisi_ipiv_supported_per_vm(struct kvm_vcpu *vcpu) +{ + /* IPIV is supported by the hardware */ + if (!static_branch_unlikely(&ipiv_enable)) + return false; + + /* vSGI passthrough is configured */ + if (!vcpu->kvm->arch.vgic.nassgireq) + return false; + + /* IPIV is enabled by the user */ + if (!vcpu->kvm->arch.vgic.its_vm.enable_ipiv_from_vmm) + return false; + + return true; +} + +void hisi_ipiv_enable_per_vm(struct kvm_vcpu *vcpu) +{ + /* Enable IPIV feature */ + vcpu->kvm->arch.vgic.its_vm.enable_ipiv_from_guest = true; +} + void ipiv_gicd_init(void) { gic_dist_enable_ipiv(); diff --git a/arch/arm64/kvm/hisilicon/hisi_virt.h b/arch/arm64/kvm/hisilicon/hisi_virt.h index 2101fc3023a8..db4c8ef347f1 100644 --- a/arch/arm64/kvm/hisilicon/hisi_virt.h +++ b/arch/arm64/kvm/hisilicon/hisi_virt.h @@ -81,6 +81,8 @@ bool hisi_ncsnp_supported(void); bool hisi_dvmbm_supported(void); #ifdef CONFIG_ARM64_HISI_IPIV bool hisi_ipiv_supported(void); +bool hisi_ipiv_supported_per_vm(struct kvm_vcpu *vcpu); +void hisi_ipiv_enable_per_vm(struct kvm_vcpu *vcpu); void ipiv_gicd_init(void); #endif /* CONFIG_ARM64_HISI_IPIV */ void kvm_get_pg_cfg(void); @@ -107,6 +109,11 @@ static inline bool hisi_ipiv_supported(void) { return false; } +static bool hisi_ipiv_supported_per_vm(struct kvm_vcpu *vcpu) +{ + return false; +} +static void hisi_ipiv_enable_per_vm(struct kvm_vcpu *vcpu) {} static inline void ipiv_gicd_init(void) {} #endif /* CONFIG_ARM64_HISI_IPIV */ static inline void kvm_get_pg_cfg(void) {} diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c index 4c9fc5df5142..f02c7b53c922 100644 --- a/arch/arm64/kvm/hypercalls.c +++ b/arch/arm64/kvm/hypercalls.c @@ -9,6 +9,10 @@ #include <kvm/arm_hypercalls.h> #include <kvm/arm_psci.h> +#ifdef CONFIG_ARM64_HISI_IPIV +#include "hisilicon/hisi_virt.h" +#endif + #define KVM_ARM_SMCCC_STD_FEATURES \ GENMASK(KVM_REG_ARM_STD_BMAP_BIT_COUNT - 1, 0) #define KVM_ARM_SMCCC_STD_HYP_FEATURES \ @@ -116,6 +120,12 @@ static bool kvm_smccc_test_fw_bmap(struct kvm_vcpu *vcpu, u32 func_id) case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID: return test_bit(KVM_REG_ARM_VENDOR_HYP_BIT_PTP, &smccc_feat->vendor_hyp_bmap); +#ifdef CONFIG_ARM64_HISI_IPIV + case ARM_SMCCC_VENDOR_PV_SGI_FEATURES: + case ARM_SMCCC_VENDOR_PV_SGI_ENABLE: + return test_bit(KVM_REG_ARM_VENDOR_HYP_BIT_IPIV, + &smccc_feat->vendor_hyp_bmap); +#endif default: return false; } @@ -363,6 +373,22 @@ int kvm_smccc_call_handler(struct kvm_vcpu *vcpu) val[0] = SMCCC_RET_SUCCESS; break; #endif /* CONFIG_PARAVIRT_SCHED */ +#ifdef CONFIG_ARM64_HISI_IPIV + case ARM_SMCCC_VENDOR_PV_SGI_FEATURES: + if (hisi_ipiv_supported_per_vm(vcpu)) + val[0] = SMCCC_RET_SUCCESS; + else + val[0] = SMCCC_RET_NOT_SUPPORTED; + break; + case ARM_SMCCC_VENDOR_PV_SGI_ENABLE: + if (hisi_ipiv_supported_per_vm(vcpu)) { + hisi_ipiv_enable_per_vm(vcpu); + val[0] = SMCCC_RET_SUCCESS; + } else { + val[0] = SMCCC_RET_NOT_SUPPORTED; + } + break; +#endif case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID: val[0] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0; val[1] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1; diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c index ff28c0bae2d7..961c3a79f41d 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c +++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c @@ -136,9 +136,6 @@ 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 21d4e990249e..7bb02d3e72ec 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -388,10 +388,6 @@ 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 /* * Currently we only build *one* devid pool. @@ -4610,8 +4606,7 @@ static void its_vpe_4_1_schedule(struct its_vpe *vpe, u64 ipiv_val = 0; u32 nr_vpes; - if (static_branch_unlikely(&ipiv_enable) && - vm->nassgireq) { + if (vm->enable_ipiv_from_guest) { /* wait gicr_ipiv_busy */ WARN_ON_ONCE(readl_relaxed_poll_timeout_atomic(vlpi_base + GICR_IPIV_ST, ipiv_val, !(ipiv_val & GICR_IPIV_ST_IPIV_BUSY), 1, 500)); @@ -4681,8 +4676,7 @@ static void its_vpe_4_1_deschedule(struct its_vpe *vpe, } #ifdef CONFIG_ARM64_HISI_IPIV - if (static_branch_unlikely(&ipiv_enable) && - vm->nassgireq) { + if (vm->enable_ipiv_from_guest) { /* wait gicr_ipiv_busy */ WARN_ON_ONCE(readl_relaxed_poll_timeout_atomic(vlpi_base + GICR_IPIV_ST, val, !(val & GICR_IPIV_ST_IPIV_BUSY), 1, 500)); @@ -5095,7 +5089,7 @@ static void its_vpe_irq_domain_free(struct irq_domain *domain, 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)) { + if (vm->enable_ipiv_from_vmm) { free_pages((unsigned long)page_address(vm->vpeid_page), get_order(nr_irqs * 2)); } @@ -5142,7 +5136,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)) { + if (vm->enable_ipiv_from_vmm) { /* * The vpeid's size is 2 bytes, so we need to allocate 2 * * (num of vcpus). nr_irqs is equal to the number of vCPUs. @@ -5165,7 +5159,7 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virq if (err) break; #ifdef CONFIG_ARM64_HISI_IPIV - if (static_branch_unlikely(&ipiv_enable)) { + if (vm->enable_ipiv_from_vmm) { vpeid_entry = (u16 *)vpeid_table_va + i; *vpeid_entry = vm->vpes[i]->vpe_id; } diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h index 9aba48160352..26ca4fe621c9 100644 --- a/include/linux/arm-smccc.h +++ b/include/linux/arm-smccc.h @@ -572,5 +572,20 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1, 0x92) #endif /* CONFIG_PARAVIRT_SCHED */ +#ifdef CONFIG_ARM64_HISI_IPIV +/* HiSilicon paravirtualised sgi calls */ +#define ARM_SMCCC_VENDOR_PV_SGI_FEATURES \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_64, \ + ARM_SMCCC_OWNER_VENDOR_HYP, \ + 0x90) + +#define ARM_SMCCC_VENDOR_PV_SGI_ENABLE \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_64, \ + ARM_SMCCC_OWNER_VENDOR_HYP, \ + 0x91) +#endif /* CONFIG_ARM64_HISI_IPIV */ + #endif /*__ASSEMBLY__*/ #endif /*__LINUX_ARM_SMCCC_H*/ diff --git a/include/linux/irqchip/arm-gic-v4.h b/include/linux/irqchip/arm-gic-v4.h index 8743741e7a52..0838b75892b6 100644 --- a/include/linux/irqchip/arm-gic-v4.h +++ b/include/linux/irqchip/arm-gic-v4.h @@ -36,8 +36,8 @@ struct its_vm { u32 vlpi_count[GICv4_ITS_LIST_MAX]; #ifdef CONFIG_ARM64_HISI_IPIV KABI_EXTEND(struct page *vpeid_page) - KABI_EXTEND(bool nassgireq) bool enable_ipiv_from_vmm; + bool enable_ipiv_from_guest; #endif }; -- 2.33.0

From: Zhou Wang <wangzhou1@hisilicon.com> virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IC7KH5 ------------------------------------------------------------------------ Use the smccc interface to enable ipiv for the guest OS, modify the guest kernel, and use multiple unicasts to implement group boradcast. In this way, do not need to modify the MPIDR. In addition, the MPIDR modification is deleted, and the GICD configuration is modified. The hardware uses the mpidr to calculate the corresponding vCPU ID to lookup vpeid table. Signed-off-by: Zhou Wang <wangzhou1@hisilicon.com> Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- arch/arm64/kvm/sys_regs.c | 14 ------------ drivers/irqchip/irq-gic-v3.c | 42 ++++++++++++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 4d087f18c5db..33b0280024f8 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -711,10 +711,6 @@ 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) { u64 mpidr; @@ -730,16 +726,6 @@ 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 - */ - 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/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 2a458aa94af0..cad1d7f3406c 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -112,8 +112,12 @@ DEFINE_STATIC_KEY_FALSE(gic_nonsecure_priorities); EXPORT_SYMBOL(gic_nonsecure_priorities); #ifdef CONFIG_ARM64_HISI_IPIV +/* indicate if host supports IPIv */ DEFINE_STATIC_KEY_FALSE(ipiv_enable); EXPORT_SYMBOL(ipiv_enable); + +/* indicate if guest is using IPIv */ +static bool hisi_pv_sgi_enabled; #endif /* @@ -1536,8 +1540,8 @@ void gic_dist_enable_ipiv(void) static_branch_enable(&ipiv_enable); val = (0 << GICD_IPIV_CTRL_AFF_DIRECT_VPEID_SHIFT) | - (0 << GICD_IPIV_CTRL_AFF1_LEFT_SHIFT_SHIFT) | - (4 << GICD_IPIV_CTRL_AFF2_LEFT_SHIFT_SHIFT) | + (4 << GICD_IPIV_CTRL_AFF1_LEFT_SHIFT_SHIFT) | + (12 << GICD_IPIV_CTRL_AFF2_LEFT_SHIFT_SHIFT) | (7 << GICD_IPIV_CTRL_VM_TABLE_INNERCACHE_SHIFT) | (2 << GICD_IPIV_CTRL_VM_TABLE_SHAREABILITY_SHIFT); writel_relaxed(val, gic_data.dist_base + GICD_IPIV_CTRL); @@ -1656,7 +1660,15 @@ static void gic_ipi_send_mask(struct irq_data *d, const struct cpumask *mask) u64 cluster_id = MPIDR_TO_SGI_CLUSTER_ID(gic_cpu_to_affinity(cpu)); u16 tlist; +#ifdef CONFIG_ARM64_HISI_IPIV + if (!hisi_pv_sgi_enabled) + tlist = gic_compute_target_list(&cpu, mask, cluster_id); + else + tlist = 1 << (gic_cpu_to_affinity(cpu) & 0xf); +#else tlist = gic_compute_target_list(&cpu, mask, cluster_id); +#endif + gic_send_sgi(cluster_id, tlist, d->hwirq); } @@ -2941,6 +2953,28 @@ static struct fwnode_handle *gic_v3_get_gsi_domain_id(u32 gsi) return gsi_domain_handle; } +#ifdef CONFIG_ARM64_HISI_IPIV +static void hisi_pv_sgi_init(void) +{ + struct arm_smccc_res res; + + arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_PV_SGI_FEATURES, &res); + if (res.a0 != SMCCC_RET_SUCCESS) { + pr_info("Not Support HiSilicon PV SGI!\n"); + return; + } + + arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_PV_SGI_ENABLE, &res); + if (res.a0 != SMCCC_RET_SUCCESS) { + pr_info("Disable HiSilicon PV SGI!\n"); + return; + } + + hisi_pv_sgi_enabled = true; + pr_info("Enable HiSilicon PV SGI!\n"); +} +#endif + static int __init gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end) { @@ -2993,6 +3027,10 @@ gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end) if (static_branch_likely(&supports_deactivate_key)) gic_acpi_setup_kvm_info(); +#ifdef CONFIG_ARM64_HISI_IPIV + hisi_pv_sgi_init(); +#endif + return 0; out_fwhandle_free: -- 2.33.0

virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IC7KH5 ------------------------------------------------------------------------ GITS_IIDR bit7 is used to store whether IPIV is enabled for Guest OS to ensure that enable_ipiv_from_guest are the same before and after live migration. Signed-off-by: Zhou Wang <wangzhou1@hisilicon.com> Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- arch/arm64/kvm/vgic/vgic-its.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c index a22649011233..0fb64825b022 100644 --- a/arch/arm64/kvm/vgic/vgic-its.c +++ b/arch/arm64/kvm/vgic/vgic-its.c @@ -498,6 +498,14 @@ static unsigned long vgic_mmio_read_its_typer(struct kvm *kvm, return extract_bytes(reg, addr & 7, len); } +#ifdef CONFIG_ARM64_HISI_IPIV +/* + * Use bit7 not used by GITS_IIDR to indicate whether IPIV is + * enabled for guest OS. + */ +#define HISI_GUEST_ENABLE_IPIV_SHIFT 7 +#endif + static unsigned long vgic_mmio_read_its_iidr(struct kvm *kvm, struct vgic_its *its, gpa_t addr, unsigned int len) @@ -518,6 +526,12 @@ static int vgic_mmio_uaccess_write_its_iidr(struct kvm *kvm, if (rev >= NR_ITS_ABIS) return -EINVAL; + +#ifdef CONFIG_ARM64_HISI_IPIV + if (val & (1UL << HISI_GUEST_ENABLE_IPIV_SHIFT)) + kvm->arch.vgic.its_vm.enable_ipiv_from_guest = true; +#endif + return vgic_its_set_abi(its, rev); } @@ -2298,6 +2312,11 @@ static int vgic_its_attr_regs_access(struct kvm_device *dev, region->its_write(dev->kvm, its, addr, len, *reg); } else { *reg = region->its_read(dev->kvm, its, addr, len); +#ifdef CONFIG_ARM64_HISI_IPIV + if (dev->kvm->arch.vgic.its_vm.enable_ipiv_from_guest && + offset == GITS_IIDR) + *reg |= 1UL << HISI_GUEST_ENABLE_IPIV_SHIFT; +#endif } out: mutex_unlock(&dev->kvm->arch.config_lock); -- 2.33.0

From: Zhou Wang <wangzhou1@hisilicon.com> virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IC7KH5 ------------------------------------------------------------------------ When the VM's vgic is initialized, vpeids are written to vpeid table in the sequence of vcpu_idx. However, the actual hardware lookups vpeid_table in the sequence of vcpu_id. Therefore, ensure that vcpu_idx and vcpu_id are the same for IPIV. Signed-off-by: Zhou Wang <wangzhou1@hisilicon.com> Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- arch/arm64/kvm/arm.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 51c257588d4a..829c45d58045 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -1555,6 +1555,15 @@ static int kvm_vcpu_init_check_features(struct kvm_vcpu *vcpu, if (test_bit(KVM_ARM_VCPU_HAS_EL2, &features)) return -EINVAL; +#ifdef CONFIG_ARM64_HISI_IPIV + if (vcpu->kvm->arch.vgic.its_vm.enable_ipiv_from_guest && + vcpu->vcpu_id != vcpu->vcpu_idx) { + kvm_err("IPIV ERROR: vcpu_id %d != vcpu_idx %d\n", + vcpu->vcpu_id, vcpu->vcpu_idx); + return -EINVAL; + } +#endif + return 0; } -- 2.33.0

From: Zhou Wang <wangzhou1@hisilicon.com> virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IC7KH5 ------------------------------------------------------------------------ IPIV uses the MPIDR value to transmit vpeid to hardware, so don't allow to change it. Signed-off-by: Zhou Wang <wangzhou1@hisilicon.com> Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- arch/arm64/kvm/sys_regs.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 33b0280024f8..8cd4c95759a0 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1568,6 +1568,25 @@ static u64 read_sanitised_id_dfr0_el1(struct kvm_vcpu *vcpu, return val; } +#ifdef CONFIG_ARM64_HISI_IPIV +extern struct static_key_false ipiv_enable; +static int set_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, + u64 val) +{ + if (static_branch_unlikely(&ipiv_enable) && + vcpu->kvm->arch.vgic.its_vm.enable_ipiv_from_vmm) { + if (val != __vcpu_sys_reg(vcpu, rd->reg)) { + kvm_err("IPIV ERROR: MPIDR changed\n"); + return -EINVAL; + } + } + + __vcpu_sys_reg(vcpu, rd->reg) = val; + + return 0; +} +#endif + static int set_id_dfr0_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, u64 val) @@ -2073,7 +2092,12 @@ static const struct sys_reg_desc sys_reg_descs[] = { { SYS_DESC(SYS_DBGVCR32_EL2), NULL, reset_val, DBGVCR32_EL2, 0 }, +#ifdef CONFIG_ARM64_HISI_IPIV + { SYS_DESC(SYS_MPIDR_EL1), + .reset = reset_mpidr, .reg = MPIDR_EL1, .set_user = set_mpidr}, +#else { SYS_DESC(SYS_MPIDR_EL1), NULL, reset_mpidr, MPIDR_EL1 }, +#endif /* * ID regs: all ID_SANITISED() entries here must have corresponding -- 2.33.0

virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IC7KH5 ------------------------------------------------------------------------ when kvm-arm.vgic_v4_enable=0 kvm-arm.ipiv_enabled=1 is configured in the cmdline, the Host KVM displays "ipiv enabled", but ipiv is not enabled. gic_data.rdists.has_rvpeid is hardware-level information, which does not indicate that GICv4.1 is enabled for KVM. So whether the host supports IPIV depends on KVM enables GICv4.1m instead of hardware supports GICv4.1. Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- arch/arm64/kvm/arm.c | 16 ---------------- arch/arm64/kvm/hisilicon/hisi_virt.c | 2 +- arch/arm64/kvm/hisilicon/hisi_virt.h | 1 - arch/arm64/kvm/vgic/vgic-init.c | 11 +++++++++++ drivers/irqchip/irq-gic-v3.c | 9 --------- 5 files changed, 12 insertions(+), 27 deletions(-) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 829c45d58045..205f70516f78 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -67,11 +67,6 @@ 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); bool is_kvm_arm_initialised(void) @@ -2820,23 +2815,12 @@ 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(); #ifdef CONFIG_HISI_VIRTCCA_HOST diff --git a/arch/arm64/kvm/hisilicon/hisi_virt.c b/arch/arm64/kvm/hisilicon/hisi_virt.c index 6a7c3a7f7a69..d9029d612697 100644 --- a/arch/arm64/kvm/hisilicon/hisi_virt.c +++ b/arch/arm64/kvm/hisilicon/hisi_virt.c @@ -184,7 +184,7 @@ bool hisi_ipiv_supported(void) return false; /* Enable IPIV feature if necessary */ - if (!is_gicv4p1()) { + if (!kvm_vgic_global_state.has_gicv4_1) { kvm_info("Hisi ipiv needs to enable GICv4p1!\n"); return false; } diff --git a/arch/arm64/kvm/hisilicon/hisi_virt.h b/arch/arm64/kvm/hisilicon/hisi_virt.h index db4c8ef347f1..531a75227972 100644 --- a/arch/arm64/kvm/hisilicon/hisi_virt.h +++ b/arch/arm64/kvm/hisilicon/hisi_virt.h @@ -135,6 +135,5 @@ static inline void kvm_hisi_reload_lsudvmbm(struct kvm *kvm) {} #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/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c index 7a0c29c6e921..5157ce0e55e0 100644 --- a/arch/arm64/kvm/vgic/vgic-init.c +++ b/arch/arm64/kvm/vgic/vgic-init.c @@ -13,6 +13,10 @@ #include <asm/kvm_mmu.h> #include "vgic.h" +#ifdef CONFIG_ARM64_HISI_IPIV +#include "hisilicon/hisi_virt.h" +#endif + /* * Initialization rules: there are multiple stages to the vgic * initialization, both for the distributor and the CPU interfaces. The basic @@ -676,6 +680,13 @@ int kvm_vgic_hyp_init(void) kvm_info("vgic interrupt IRQ%d\n", kvm_vgic_global_state.maint_irq); #ifdef CONFIG_ARM64_HISI_IPIV + if (hisi_ipiv_supported()) { + ipiv_gicd_init(); + kvm_info("KVM ipiv enabled\n"); + } else { + kvm_info("KVM ipiv disabled\n"); + } + if (static_branch_unlikely(&ipiv_enable)) { ipiv_irq = acpi_register_gsi(NULL, 18, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_HIGH); diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index cad1d7f3406c..37eb995320a3 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -1521,15 +1521,6 @@ static int gic_dist_supports_lpis(void) } #ifdef CONFIG_ARM64_HISI_IPIV -bool is_gicv4p1(void) -{ - if (!gic_data.rdists.has_rvpeid) - return false; - - return true; -} -EXPORT_SYMBOL(is_gicv4p1); - void gic_dist_enable_ipiv(void) { u32 val; -- 2.33.0

virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IC7KH5 ------------------------------------------------------------------------ Displays detailed IPIV error causes based on hardware information. 1. Guest sends SGI with IRM=1. 2. Guest sends multicast. 3. The index of VM table exceeds the supported range. Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- arch/arm64/kvm/vgic/vgic-init.c | 21 ++++++++++++++++++++- drivers/irqchip/irq-gic-v3-its.c | 8 ++++++++ include/linux/irqchip/arm-gic-v3.h | 6 ++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c index 5157ce0e55e0..9ec452bcfb13 100644 --- a/arch/arm64/kvm/vgic/vgic-init.c +++ b/arch/arm64/kvm/vgic/vgic-init.c @@ -14,6 +14,7 @@ #include "vgic.h" #ifdef CONFIG_ARM64_HISI_IPIV +#include <linux/irqchip/arm-gic-v3.h> #include "hisilicon/hisi_virt.h" #endif @@ -563,9 +564,27 @@ void kvm_vgic_cpu_down(void) } #ifdef CONFIG_ARM64_HISI_IPIV +extern void __iomem *gic_data_rdist_get_vlpi_base(void); static irqreturn_t vgic_ipiv_irq_handler(int irq, void *data) { - kvm_info("IPIV irq handler!\n"); + void __iomem *vlpi_base = gic_data_rdist_get_vlpi_base(); + u32 gicr_ipiv_st; + bool broadcast_err, grpbrd_err, vcpuidx_err; + + gicr_ipiv_st = readl_relaxed(vlpi_base + GICR_IPIV_ST); + + broadcast_err = !!(gicr_ipiv_st & GICR_IPIV_ST_IRM_ERR); + if (broadcast_err) + kvm_err("IPIV error: IRM=1 Guest broadcast error\n"); + + grpbrd_err = !!(gicr_ipiv_st & GICR_IPIV_ST_BRPBRD_ERR); + if (grpbrd_err) + kvm_err("IPIV error: Guest group broadcast error\n"); + + vcpuidx_err = !!(gicr_ipiv_st & GICR_IPIV_ST_VCPUIDX_ERR); + if (vcpuidx_err) + kvm_err("IPIV error: The VCPU index is out of range\n"); + return IRQ_HANDLED; } #endif diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 7bb02d3e72ec..9b5103d0e6de 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -388,6 +388,14 @@ 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 +void __iomem *gic_data_rdist_get_vlpi_base(void) +{ + return gic_data_rdist_vlpi_base(); +} +EXPORT_SYMBOL(gic_data_rdist_get_vlpi_base); +#endif + #ifdef CONFIG_VIRT_PLAT_DEV /* * Currently we only build *one* devid pool. diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index ddfacc6dd8cd..8e97525a3afd 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -391,6 +391,12 @@ #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) +#define GICR_IPIV_ST_IRM_ERR_ST_SHIFT 1 +#define GICR_IPIV_ST_IRM_ERR (1 << GICR_IPIV_ST_IRM_ERR_ST_SHIFT) +#define GICR_IPIV_ST_BRPBRD_ERR_ST_SHIFT 2 +#define GICR_IPIV_ST_BRPBRD_ERR (1 << GICR_IPIV_ST_BRPBRD_ERR_ST_SHIFT) +#define GICR_IPIV_ST_VCPUIDX_ERR_ST_SHIFT 3 +#define GICR_IPIV_ST_VCPUIDX_ERR (1 << GICR_IPIV_ST_VCPUIDX_ERR_ST_SHIFT) #endif /* CONFIG_ARM64_HISI_IPIV */ /* -- 2.33.0

virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IC7KH5 ------------------------------------------------------------------------ Use KABI_EXTEND to skip KABI check of IPIV feature. Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- include/linux/irqchip/arm-gic-v4.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/irqchip/arm-gic-v4.h b/include/linux/irqchip/arm-gic-v4.h index 0838b75892b6..09477a8a9158 100644 --- a/include/linux/irqchip/arm-gic-v4.h +++ b/include/linux/irqchip/arm-gic-v4.h @@ -36,8 +36,8 @@ struct its_vm { u32 vlpi_count[GICv4_ITS_LIST_MAX]; #ifdef CONFIG_ARM64_HISI_IPIV KABI_EXTEND(struct page *vpeid_page) - bool enable_ipiv_from_vmm; - bool enable_ipiv_from_guest; + KABI_EXTEND(bool enable_ipiv_from_vmm) + KABI_EXTEND(bool enable_ipiv_from_guest) #endif }; -- 2.33.0

反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/16329 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/2T6... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/16329 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/2T6...
participants (2)
-
Jinqian Yang
-
patchwork bot