[PATCH OLK-6.6 00/10] 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. make sure vcpu_id == vcpu_idx. 5. the MPIDR cannot be changed When IPIV is enabled. 6. fix bug that ipiv enable is displayed on the host when "kvm-arm.vgic_v4_enable=0 kvm-arm.ipiv_enabled=1" is configured. 7. Add Exception Printing Patch#1 arm64/config: add config to control whether enable IPIV feature Patch#2 KVM: arm64: Introduce ipiv enable ioctl Patch#3 KVM: arm64: Document PV-sgi interface Patch#4 KVM: arm64: Implement PV_SGI related calls Patch#5 irqchip/gic: Add HiSilicon PV SGI support Patch#6 kvm: hisi: make sure vcpu_id and vcpu_idx have same value in IPIv Patch#7 kvm: hisi: Don't allow to change mpidr in IPIv Patch#8 KVM: arm64: using kvm_vgic_global_state for ipiv Patch#9 kvm: hisi: print error for IPIV Patch#10 arm64/kabi: use KABI_EXTEND to skip KABI check Jinqian Yang (4): arm64/config: add config to control whether enable IPIV feature 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/pvsgi.rst | 33 ++++++++++++++++ arch/arm64/Kconfig | 13 ++++++ arch/arm64/configs/openeuler_defconfig | 1 + arch/arm64/include/asm/kvm_host.h | 3 ++ arch/arm64/kvm/arm.c | 34 ++++++++++++---- arch/arm64/kvm/hisilicon/hisi_virt.c | 25 +++++++++++- arch/arm64/kvm/hisilicon/hisi_virt.h | 20 ++++++++-- arch/arm64/kvm/hypercalls.c | 24 +++++++++++ arch/arm64/kvm/sys_regs.c | 34 +++++++++++----- arch/arm64/kvm/vgic/vgic-init.c | 42 +++++++++++++++++--- arch/arm64/kvm/vgic/vgic-mmio-v3.c | 2 + 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 | 4 ++ 16 files changed, 311 insertions(+), 54 deletions(-) create mode 100644 Documentation/virt/kvm/arm/pvsgi.rst -- 2.33.0

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

From: Zhou Wang <wangzhou1@hisilicon.com> virt inclusion category: bugfix 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. Signed-off-by: Zhou Wang <wangzhou1@hisilicon.com> Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- arch/arm64/kvm/arm.c | 13 +++++++++++++ include/linux/irqchip/arm-gic-v4.h | 1 + 2 files changed, 14 insertions(+) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 38ce562586f9..259247bd8297 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_IPIV_MODE: + r = kvm_hisi_ipiv_enable_cap(kvm, cap); + break; #endif default: r = -EINVAL; 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 }; -- 2.33.0

From: Zhou Wang <wangzhou1@hisilicon.com> virt inclusion category: bugfix 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/pvsgi.rst | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Documentation/virt/kvm/arm/pvsgi.rst 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: bugfix 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/kvm/hisilicon/hisi_virt.c | 18 ++++++++++++++++++ arch/arm64/kvm/hisilicon/hisi_virt.h | 7 +++++++ arch/arm64/kvm/hypercalls.c | 24 ++++++++++++++++++++++++ drivers/irqchip/irq-gic-v3-its.c | 16 +++++----------- include/linux/arm-smccc.h | 15 +++++++++++++++ include/linux/irqchip/arm-gic-v4.h | 1 + 6 files changed, 70 insertions(+), 11 deletions(-) diff --git a/arch/arm64/kvm/hisilicon/hisi_virt.c b/arch/arm64/kvm/hisilicon/hisi_virt.c index b527f2113599..54e5ecf85697 100644 --- a/arch/arm64/kvm/hisilicon/hisi_virt.c +++ b/arch/arm64/kvm/hisilicon/hisi_virt.c @@ -193,6 +193,24 @@ bool hisi_ipiv_supported(void) return true; } +extern struct static_key_false ipiv_enable; + +bool hisi_ipiv_supported_per_vm(struct kvm_vcpu *vcpu) +{ + if (!static_branch_unlikely(&ipiv_enable)) + return false; + + 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) +{ + 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..58839f9391ed 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 \ @@ -75,6 +79,10 @@ static bool kvm_smccc_default_allowed(u32 func_id) */ case ARM_SMCCC_VERSION_FUNC_ID: case ARM_SMCCC_ARCH_FEATURES_FUNC_ID: +#ifdef CONFIG_ARM64_HISI_IPIV + case ARM_SMCCC_VENDOR_PV_SGI_FEATURES: + case ARM_SMCCC_VENDOR_PV_SGI_ENABLE: +#endif return true; default: /* PSCI 0.2 and up is in the 0:0x1f range */ @@ -363,6 +371,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/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 21d4e990249e..81a039b25989 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->nassgireq && 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->nassgireq && 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..93d629db519e 100644 --- a/include/linux/irqchip/arm-gic-v4.h +++ b/include/linux/irqchip/arm-gic-v4.h @@ -38,6 +38,7 @@ struct its_vm { 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: bugfix 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..bfc76cf92567 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) & 0xff); +#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

From: Zhou Wang <wangzhou1@hisilicon.com> virt inclusion category: bugfix 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 259247bd8297..0cac53df0a8b 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_info("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: bugfix 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..8b22469f43db 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_info("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: bugfix 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 0cac53df0a8b..33fd7c5ec1f8 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 54e5ecf85697..40d7ebe6dcef 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 bfc76cf92567..fa33aa1d1b8a 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: bugfix 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..be22c5035db4 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_info("IPIV error: IRM=1 Guest broadcast error\n"); + + grpbrd_err = !!(gicr_ipiv_st & GICR_IPIV_ST_BRPBRD_ERR); + if (grpbrd_err) + kvm_info("IPIV error: Guest group broadcast error\n"); + + vcpuidx_err = !!(gicr_ipiv_st & GICR_IPIV_ST_VCPUIDX_ERR); + if (vcpuidx_err) + kvm_info("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 81a039b25989..ba331269d114 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: bugfix 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 93d629db519e..214a5cd7d761 100644 --- a/include/linux/irqchip/arm-gic-v4.h +++ b/include/linux/irqchip/arm-gic-v4.h @@ -37,8 +37,8 @@ struct its_vm { #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; + KABI_EXTEND(bool enable_ipiv_from_vmm) + KABI_EXTEND(bool enable_ipiv_from_guest) #endif }; -- 2.33.0

反馈: 您发送到kernel@openeuler.org的补丁/补丁集,转换为PR失败! 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/OXW... 失败原因:同步源码仓代码到fork仓失败 建议解决方法:请稍等,机器人会在下一次任务重新执行 FeedBack: The patch(es) which you have sent to kernel@openeuler.org has been converted to PR failed! Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/OXW... Failed Reason: sync origin kernel's codes to the fork repository failed Suggest Solution: please wait, the bot will retry in the next interval

反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/16272 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/OXW... 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/16272 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/OXW...
participants (2)
-
Jinqian Yang
-
patchwork bot