[PATCH OLK-6.6 v5 0/7] Add support for IPIv

Patch#1 Allocate VM table and save vpeid in it Patch#2 avoid sending multi-SGIs in IPIV Patch#3 Set base address of vm table and targe ITS when vpe schedule and deschedule Patch#4 Register ipiv exception interrupt Patch#5 Add interface KVM_CAP_ARM_IPIV_MODE Patch#6 Probe and configure IPIV capacity on HIP12 Patch#7 Use KABI_EXTEND to perform kabi repair for IPIV Jinqian Yang (2): KVM: arm64: avoid sending multi-SGIs in IPIV kabi: Use KABI_EXTEND to perform kabi repair for IPIV Xiang Chen (5): kvm: hisi_virt: Allocate VM table and save vpeid in it irqchip: gicv3-its: Set base address of vm table and targe ITS when vpe schedule and deschedule kvm: hisi_virt: Register ipiv exception interrupt kvm: arm64: Add interface KVM_CAP_ARM_IPIV_MODE kvm: hisi_virt: Probe and configure IPIV capacity on HIP12 .../admin-guide/kernel-parameters.txt | 3 + arch/arm64/include/asm/kvm_host.h | 1 + arch/arm64/kvm/arm.c | 16 ++++ arch/arm64/kvm/hisilicon/hisi_virt.c | 35 ++++++++ arch/arm64/kvm/hisilicon/hisi_virt.h | 11 +++ arch/arm64/kvm/sys_regs.c | 30 ++++--- arch/arm64/kvm/vgic/vgic-init.c | 44 ++++++++- arch/arm64/kvm/vgic/vgic-mmio-v3.c | 2 + drivers/irqchip/irq-gic-v3-its.c | 89 ++++++++++++++++++- drivers/irqchip/irq-gic-v3.c | 33 +++++++ include/linux/irqchip/arm-gic-v3.h | 24 +++++ include/linux/irqchip/arm-gic-v4.h | 2 + include/uapi/linux/kvm.h | 2 + 13 files changed, 277 insertions(+), 15 deletions(-) -- 2.33.0

From: Xiang Chen <chenxiang66@hisilicon.com> virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBPH85 ------------------------------------------------------------------------ When guest access register ICC_SGI1R_EL1, GIC will access VM table to get the vpeid of vcpu for IPIV feature. So when IPIV feature is enabled, allocate VM table and save vpeid in it. The index of the entries in VM table is vcpu id. Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com> Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- drivers/irqchip/irq-gic-v3-its.c | 27 +++++++++++++++++++++++++-- drivers/irqchip/irq-gic-v3.c | 3 +++ include/linux/irqchip/arm-gic-v4.h | 1 + 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 49a60999f661..e41e1baeba6e 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -388,6 +388,8 @@ 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) +extern struct static_key_false ipiv_enable; + #ifdef CONFIG_VIRT_PLAT_DEV /* * Currently we only build *one* devid pool. @@ -5014,6 +5016,10 @@ static void its_vpe_irq_domain_free(struct irq_domain *domain, if (bitmap_empty(vm->db_bitmap, vm->nr_db_lpis)) { its_lpi_free(vm->db_bitmap, vm->db_lpi_base, vm->nr_db_lpis); its_free_prop_table(vm->vprop_page); + if (static_branch_unlikely(&ipiv_enable)) { + free_pages((unsigned long)page_address(vm->vpe_page), + get_order(nr_irqs * 2)); + } } } @@ -5023,8 +5029,10 @@ 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; + struct page *vprop_page, *vpe_page; int base, nr_ids, i, err = 0; + void *vpe_table_va; + u16 *vpe_entry; bitmap = its_lpi_alloc(roundup_pow_of_two(nr_irqs), &base, &nr_ids); if (!bitmap) @@ -5047,14 +5055,29 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virq vm->vprop_page = vprop_page; raw_spin_lock_init(&vm->vmapp_lock); - if (gic_rdists->has_rvpeid) + if (gic_rdists->has_rvpeid) { irqchip = &its_vpe_4_1_irq_chip; + if (static_branch_unlikely(&ipiv_enable)) { + vpe_page = alloc_pages(GFP_KERNEL, get_order(nr_irqs * 2)); + if (!vpe_page) { + its_lpi_free(vm->db_bitmap, vm->db_lpi_base, vm->nr_db_lpis); + its_free_prop_table(vm->vprop_page); + return -ENOMEM; + } + vm->vpe_page = vpe_page; + vpe_table_va = page_address(vm->vpe_page); + } + } for (i = 0; i < nr_irqs; i++) { vm->vpes[i]->vpe_db_lpi = base + i; err = its_vpe_init(vm->vpes[i]); if (err) break; + if (static_branch_unlikely(&ipiv_enable)) { + vpe_entry = (u16 *)vpe_table_va + i; + *(u16 *)vpe_entry = vm->vpes[i]->vpe_id; + } 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 0af1eed9ad35..8e80eed7513c 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -111,6 +111,9 @@ static DEFINE_STATIC_KEY_FALSE(supports_pseudo_nmis); DEFINE_STATIC_KEY_FALSE(gic_nonsecure_priorities); EXPORT_SYMBOL(gic_nonsecure_priorities); +DEFINE_STATIC_KEY_FALSE(ipiv_enable); +EXPORT_SYMBOL(ipiv_enable); + /* * When the Non-secure world has access to group 0 interrupts (as a * consequence of SCR_EL3.FIQ == 0), reading the ICC_RPR_EL1 register will diff --git a/include/linux/irqchip/arm-gic-v4.h b/include/linux/irqchip/arm-gic-v4.h index 2d6f41001a46..d3281506af9c 100644 --- a/include/linux/irqchip/arm-gic-v4.h +++ b/include/linux/irqchip/arm-gic-v4.h @@ -20,6 +20,7 @@ struct its_vm { struct fwnode_handle *fwnode; struct irq_domain *domain; struct page *vprop_page; + struct page *vpe_page; struct its_vpe **vpes; int nr_vpes; irq_hw_number_t db_lpi_base; -- 2.33.0

virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBPH85 ------------------------------------------------------------------------ IPIV optimizes unicast scenarios and does not support multicast or broadcast. Instead, it converts multicast and broadcast traffic into multiple unicast streams. To prevent Guest OSes from generating multicast and broadcast traffic, the MPIDR of vCPUs is modified to ensure that the [aff3, aff2, aff1] fields are uniquely assigned for each vCPU within a virtual machine, while all aff0 fields are set to zero. This configuration guarantees the uniqueness of vCPU affinity identifiers at the architecture level, thereby suppressing the generation of vSGI multicast and broadcast signals by the virtualized environment. Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- arch/arm64/kvm/sys_regs.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 0cfa8d93e2ee..4d9bf04c1023 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -711,20 +711,30 @@ static u64 reset_actlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) return actlr; } +extern struct static_key_false ipiv_enable; + static u64 reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) { u64 mpidr; - /* - * Map the vcpu_id into the first three affinity level fields of - * the MPIDR. We limit the number of VCPUs in level 0 due to a - * limitation to 16 CPUs in that level in the ICC_SGIxR registers - * of the GICv3 to be able to address each CPU directly when - * sending IPIs. - */ - mpidr = (vcpu->vcpu_id & 0x0f) << MPIDR_LEVEL_SHIFT(0); - mpidr |= ((vcpu->vcpu_id >> 4) & 0xff) << MPIDR_LEVEL_SHIFT(1); - mpidr |= ((vcpu->vcpu_id >> 12) & 0xff) << MPIDR_LEVEL_SHIFT(2); + if (static_branch_unlikely(&ipiv_enable)) { + /* + * 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); + } else { + /* + * Map the vcpu_id into the first three affinity level fields of + * the MPIDR. We limit the number of VCPUs in level 0 due to a + * limitation to 16 CPUs in that level in the ICC_SGIxR registers + * of the GICv3 to be able to address each CPU directly when + * sending IPIs. + */ + mpidr = (vcpu->vcpu_id & 0x0f) << MPIDR_LEVEL_SHIFT(0); + mpidr |= ((vcpu->vcpu_id >> 4) & 0xff) << MPIDR_LEVEL_SHIFT(1); + mpidr |= ((vcpu->vcpu_id >> 12) & 0xff) << MPIDR_LEVEL_SHIFT(2); + } mpidr |= (1ULL << 31); vcpu_write_sys_reg(vcpu, mpidr, MPIDR_EL1); -- 2.33.0

From: Xiang Chen <chenxiang66@hisilicon.com> virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBPH85 ------------------------------------------------------------------------ Set the base address of vm table and target ITS when vpe schedule and deschedule. Also need to make sure IPIV is not busy before setting them. Disable ICC_SGI1R_EL1 trap when vpe schedule, and enable the trap when vpe deschedule. Only disable ICC_SGI1R_EL1 trap when enabled ipiv and set GICD_CTLR_nASSGIreq for register GICD_CTLR of virtual machine. Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com> Signed-off-by: Nianyao Tang <tangnianyao@huawei.com> Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- arch/arm64/kvm/vgic/vgic-mmio-v3.c | 1 + drivers/irqchip/irq-gic-v3-its.c | 62 +++++++++++++++++++++++++++++- include/linux/irqchip/arm-gic-v3.h | 12 ++++++ include/linux/irqchip/arm-gic-v4.h | 1 + 4 files changed, 75 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c index 961c3a79f41d..d55607dcd226 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c +++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c @@ -136,6 +136,7 @@ static void vgic_mmio_write_v3_misc(struct kvm_vcpu *vcpu, /* Switching HW SGIs? */ dist->nassgireq = val & GICD_CTLR_nASSGIreq; + dist->its_vm.nassgireq = dist->nassgireq; 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 e41e1baeba6e..fde5227cb796 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -4564,14 +4564,62 @@ static void its_vpe_4_1_unmask_irq(struct irq_data *d) its_vpe_4_1_send_inv(d); } +/* IPIV register */ +#define CPU_SYS_TRAP_EL2 sys_reg(3, 4, 15, 7, 2) + +static void ipiv_disable_vsgi_trap(void) +{ + u64 val; + + /* disable guest access ICC_SGI1R_EL1 trap, enable ipiv */ + val = read_sysreg_s(CPU_SYS_TRAP_EL2); + val |= 1ULL; + write_sysreg_s(val, CPU_SYS_TRAP_EL2); +} + +static void ipiv_enable_vsgi_trap(void) +{ + u64 val; + + /* enable guest access ICC_SGI1R_EL1 trap, disable ipiv */ + val = read_sysreg_s(CPU_SYS_TRAP_EL2); + val &= ~1UL; + write_sysreg_s(val, CPU_SYS_TRAP_EL2); +} + 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(); + struct its_vm *vm = vpe->its_vm; + unsigned long vpe_addr; u64 val = 0; + u32 nr_vpes; + + if (static_branch_unlikely(&ipiv_enable) && + vm->nassgireq) { + /* 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)); + vpe_addr = virt_to_phys(page_address(vm->vpe_page)); + writel_relaxed(lower_32_bits(vpe_addr), + vlpi_base + GICR_VM_TABLE_BAR_L); + writel_relaxed(upper_32_bits(vpe_addr), + vlpi_base + GICR_VM_TABLE_BAR_H); + + /* setup gicr_vcpu_entry_num_max and gicr_ipiv_its_ta_sel */ + nr_vpes = vpe->its_vm->nr_vpes; + val = ((nr_vpes - 1) << GICR_IPIV_CTRL_VCPU_ENTRY_NUM_MAX_SHIFT) | + (0 << GICR_IPIV_CTRL_IPIV_ITS_TA_SEL_SHIFT); + writel_relaxed(val, vlpi_base + GICR_IPIV_CTRL); + + ipiv_disable_vsgi_trap(); + } else { + ipiv_enable_vsgi_trap(); + } /* Schedule the VPE */ - val |= GICR_VPENDBASER_Valid; + val = GICR_VPENDBASER_Valid; val |= info->g0en ? GICR_VPENDBASER_4_1_VGRP0EN : 0; val |= info->g1en ? GICR_VPENDBASER_4_1_VGRP1EN : 0; val |= FIELD_PREP(GICR_VPENDBASER_4_1_VPEID, vpe->vpe_id); @@ -4583,6 +4631,7 @@ 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; if (info->req_db) { @@ -4614,6 +4663,17 @@ static void its_vpe_4_1_deschedule(struct its_vpe *vpe, GICR_VPENDBASER_PendingLast); vpe->pending_last = true; } + + if (static_branch_unlikely(&ipiv_enable) && + vm->nassgireq) { + /* 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)); + writel_relaxed(0, vlpi_base + GICR_VM_TABLE_BAR_L); + writel_relaxed(0, vlpi_base + GICR_VM_TABLE_BAR_H); + + ipiv_enable_vsgi_trap(); + } } static void its_vpe_4_1_invall(struct its_vpe *vpe) diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 548b8a5c46cf..074b347e8fcc 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -362,6 +362,18 @@ #define GICR_VSGIPENDR_BUSY (1U << 31) #define GICR_VSGIPENDR_PENDING GENMASK(15, 0) +/* IPIV VM table address */ +#define GICR_VM_TABLE_BAR_L 0x140 +#define GICR_VM_TABLE_BAR_H 0x144 + +#define GICR_IPIV_CTRL 0x148 +#define GICR_IPIV_CTRL_VCPU_ENTRY_NUM_MAX_SHIFT 8 +#define GICR_IPIV_CTRL_IPIV_ITS_TA_SEL_SHIFT 4 + +#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) + /* * 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 d3281506af9c..e0473eab485a 100644 --- a/include/linux/irqchip/arm-gic-v4.h +++ b/include/linux/irqchip/arm-gic-v4.h @@ -35,6 +35,7 @@ struct its_vm { */ raw_spinlock_t vmapp_lock; u32 vlpi_count[GICv4_ITS_LIST_MAX]; + bool nassgireq; }; /* Embedded in kvm_vcpu.arch */ -- 2.33.0

From: Xiang Chen <chenxiang66@hisilicon.com> virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBPH85 ------------------------------------------------------------------------ When the index of VM table exceeds the supported range or guest sends SGI with IRM=1, it triggers a exception interrupt (PPI interrupt). Just printk exception info in interrupt handler. Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com> Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- arch/arm64/kvm/vgic/vgic-init.c | 44 +++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c index db5db9402c3a..113accd6cd0b 100644 --- a/arch/arm64/kvm/vgic/vgic-init.c +++ b/arch/arm64/kvm/vgic/vgic-init.c @@ -3,6 +3,7 @@ * Copyright (C) 2015, 2016 ARM Ltd. */ +#include <linux/acpi.h> #include <linux/uaccess.h> #include <linux/interrupt.h> #include <linux/cpu.h> @@ -531,17 +532,30 @@ int kvm_vgic_map_resources(struct kvm *kvm) return ret; } +extern struct static_key_false ipiv_enable; +static int ipiv_irq; + /* GENERIC PROBE */ void kvm_vgic_cpu_up(void) { enable_percpu_irq(kvm_vgic_global_state.maint_irq, 0); + if (static_branch_unlikely(&ipiv_enable)) + enable_percpu_irq(ipiv_irq, 0); } void kvm_vgic_cpu_down(void) { disable_percpu_irq(kvm_vgic_global_state.maint_irq); + if (static_branch_unlikely(&ipiv_enable)) + disable_percpu_irq(ipiv_irq); +} + +static irqreturn_t vgic_ipiv_irq_handler(int irq, void *data) +{ + kvm_info("IPIV irq handler!\n"); + return IRQ_HANDLED; } static irqreturn_t vgic_maintenance_handler(int irq, void *data) @@ -615,6 +629,15 @@ int kvm_vgic_hyp_init(void) kvm_vgic_global_state.no_hw_deactivation = true; } + if (static_branch_unlikely(&ipiv_enable)) { + ipiv_irq = acpi_register_gsi(NULL, 18, ACPI_EDGE_SENSITIVE, + ACPI_ACTIVE_HIGH); + if (ipiv_irq < 0) { + kvm_err("No ipiv exception irq\n"); + return -ENXIO; + } + } + kvm_vgic_global_state.flags = gic_kvm_info->flags; switch (gic_kvm_info->type) { case GIC_V2: @@ -637,7 +660,7 @@ int kvm_vgic_hyp_init(void) gic_kvm_info = NULL; if (ret) - return ret; + goto out_unregister_gsi; if (!has_mask && !kvm_vgic_global_state.maint_irq) return 0; @@ -648,9 +671,26 @@ int kvm_vgic_hyp_init(void) if (ret) { kvm_err("Cannot register interrupt %d\n", kvm_vgic_global_state.maint_irq); - return ret; + goto out_unregister_gsi; } kvm_info("vgic interrupt IRQ%d\n", kvm_vgic_global_state.maint_irq); + + if (static_branch_unlikely(&ipiv_enable)) { + ret = request_percpu_irq(ipiv_irq, vgic_ipiv_irq_handler, + "ipiv exception", kvm_get_running_vcpus()); + if (ret) { + kvm_err("Cannot register interrupt %d\n", ipiv_irq); + goto out_free_irq; + } + } + return 0; +out_free_irq: + free_percpu_irq(kvm_vgic_global_state.maint_irq, + kvm_get_running_vcpus()); +out_unregister_gsi: + if (static_branch_unlikely(&ipiv_enable)) + acpi_unregister_gsi(18); + return ret; } -- 2.33.0

From: Xiang Chen <chenxiang66@hisilicon.com> virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBPH85 ------------------------------------------------------------------------ Before IPIV feature, it gets mpidr from vcpu id, but after the feature, we need to know if IPIV mode is enabled. And new IPIV modes may be added later. Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com> Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- arch/arm64/kvm/arm.c | 8 ++++++++ include/uapi/linux/kvm.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 5ba336d1efad..996a7117d709 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -312,6 +312,8 @@ void kvm_arch_destroy_vm(struct kvm *kvm) #endif } +extern struct static_key_false ipiv_enable; + int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) { int r; @@ -436,6 +438,12 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) r = static_key_enabled(&virtcca_cvm_is_available); break; #endif + case KVM_CAP_ARM_IPIV_MODE: + if (static_branch_unlikely(&ipiv_enable)) + r = 1; + else + r = 0; + break; default: r = 0; } diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 1f67e4d6ff7b..870be8fcfacf 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1201,6 +1201,8 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE 228 #define KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES 229 +#define KVM_CAP_ARM_IPIV_MODE 301 /* ipiv mode */ + #define KVM_CAP_SEV_ES_GHCB 500 #define KVM_CAP_HYGON_COCO_EXT 501 /* support userspace to request firmware to build CSV3 guest's memory space */ -- 2.33.0

From: Xiang Chen <chenxiang66@hisilicon.com> virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBPH85 ------------------------------------------------------------------------ IPIV is an virtualization extension on HIP12, which allows IPIs on guest directly sending by hardware to other vcpu stead of trapping to EL2. It will bring IPI interrupt optimization on guest. Introduce the method to detect and enable the feature, and also add a kernel command parameter "kvm-arm.ipiv_enabled" (default is 0) so that users can disable or enable the feature. The feature is based on GICv4p1. Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com> Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- .../admin-guide/kernel-parameters.txt | 3 ++ arch/arm64/include/asm/kvm_host.h | 1 + arch/arm64/kvm/arm.c | 8 +++++ arch/arm64/kvm/hisilicon/hisi_virt.c | 35 +++++++++++++++++++ arch/arm64/kvm/hisilicon/hisi_virt.h | 11 ++++++ arch/arm64/kvm/vgic/vgic-mmio-v3.c | 1 + drivers/irqchip/irq-gic-v3.c | 30 ++++++++++++++++ include/linux/irqchip/arm-gic-v3.h | 12 +++++++ 8 files changed, 101 insertions(+) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 78a30d4453ad..6d8ad9c0e1fd 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2709,6 +2709,9 @@ [KVM,ARM] Allow use of GICv4 for direct injection of LPIs. + kvm-arm.ipiv_enabled= + [KVM,ARM] Allow use of HiSilicon ipiv on GICv4.1 + kvm-arm.dvmbm_enabled= [KVM,ARM] Allow use of HiSilicon DVMBM capability. Default: 0 diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index ac4e59256f8e..bf884f95e6e6 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -1286,5 +1286,6 @@ bool kvm_arm_vcpu_stopped(struct kvm_vcpu *vcpu); extern bool force_wfi_trap; extern bool kvm_ncsnp_support; extern bool kvm_dvmbm_support; +extern bool kvm_ipiv_support; #endif /* __ARM64_KVM_HOST_H__ */ diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 996a7117d709..f3fa3a74e041 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -67,6 +67,9 @@ bool kvm_ncsnp_support; /* Capability of DVMBM */ bool kvm_dvmbm_support; +/* Capability of IPIV */ +bool kvm_ipiv_support; + static DEFINE_PER_CPU(unsigned char, kvm_hyp_initialized); bool is_kvm_arm_initialised(void) @@ -2701,12 +2704,17 @@ static __init int kvm_arm_init(void) probe_hisi_cpu_type(); kvm_ncsnp_support = hisi_ncsnp_supported(); kvm_dvmbm_support = hisi_dvmbm_supported(); + kvm_ipiv_support = hisi_ipiv_supported(); kvm_info("KVM ncsnp %s\n", kvm_ncsnp_support ? "enabled" : "disabled"); kvm_info("KVM dvmbm %s\n", kvm_dvmbm_support ? "enabled" : "disabled"); + kvm_info("KVM ipiv %s\n", kvm_ipiv_support ? "enabled" : "disabled"); if (kvm_dvmbm_support) kvm_get_pg_cfg(); + if (kvm_ipiv_support) + ipiv_gicd_init(); + 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 d95b96ee7237..88b1c393c8be 100644 --- a/arch/arm64/kvm/hisilicon/hisi_virt.c +++ b/arch/arm64/kvm/hisilicon/hisi_virt.c @@ -12,6 +12,7 @@ static enum hisi_cpu_type cpu_type = UNKNOWN_HI_TYPE; static bool dvmbm_enabled; +static bool ipiv_enabled; static const char * const hisi_cpu_type_str[] = { "Hisi1612", @@ -157,6 +158,40 @@ static void hardware_disable_dvmbm(void *data) write_sysreg_s(val, SYS_LSUDVM_CTRL_EL2); } +static int __init early_ipiv_enable(char *buf) +{ + return strtobool(buf, &ipiv_enabled); +} +early_param("kvm-arm.ipiv_enabled", early_ipiv_enable); + +bool hisi_ipiv_supported(void) +{ + /* Determine whether IPIV is supported by the hardware */ + if (!(read_sysreg(aidr_el1) & AIDR_EL1_IPIV_MASK)) { + kvm_info("Hisi ipiv not supported by the hardware\n"); + return false; + } else + kvm_info("Hisi ipiv detected on the hardware\n"); + + /* User provided kernel command-line parameter */ + if (!ipiv_enabled || !is_kernel_in_hyp_mode()) + return false; + + /* Enable IPIV feature if necessary */ + if (!is_gicv4p1()) { + kvm_info("Need to enable GICv4p1!\n"); + return false; + } + + kvm_info("Enable Hisi ipiv, do not support SGI broadcast\n"); + return true; +} + +void ipiv_gicd_init(void) +{ + gic_dist_enable_ipiv(); +} + bool hisi_dvmbm_supported(void) { if (cpu_type != HI_IP10 && cpu_type != HI_IP10C && diff --git a/arch/arm64/kvm/hisilicon/hisi_virt.h b/arch/arm64/kvm/hisilicon/hisi_virt.h index c45d319e7b41..f0b47c020261 100644 --- a/arch/arm64/kvm/hisilicon/hisi_virt.h +++ b/arch/arm64/kvm/hisilicon/hisi_virt.h @@ -18,6 +18,8 @@ enum hisi_cpu_type { UNKNOWN_HI_TYPE }; +/* HIP12 */ +#define AIDR_EL1_IPIV_MASK GENMASK_ULL(17, 16) /* HIP10 */ #define AIDR_EL1_DVMBM_MASK GENMASK_ULL(13, 12) #define SYS_LSUDVM_CTRL_EL2 sys_reg(3, 4, 15, 7, 4) @@ -75,7 +77,9 @@ enum hisi_cpu_type { void probe_hisi_cpu_type(void); bool hisi_ncsnp_supported(void); bool hisi_dvmbm_supported(void); +bool hisi_ipiv_supported(void); void kvm_get_pg_cfg(void); +void ipiv_gicd_init(void); int kvm_sched_affinity_vcpu_init(struct kvm_vcpu *vcpu); void kvm_sched_affinity_vcpu_destroy(struct kvm_vcpu *vcpu); @@ -94,7 +98,12 @@ static inline bool hisi_dvmbm_supported(void) { return false; } +static inline bool hisi_ipiv_supported(void) +{ + return false; +} static inline void kvm_get_pg_cfg(void) {} +static inline void ipiv_gicd_init(void) {} static inline int kvm_sched_affinity_vcpu_init(struct kvm_vcpu *vcpu) { @@ -111,4 +120,6 @@ static inline void kvm_tlbi_dvmbm_vcpu_put(struct kvm_vcpu *vcpu) {} static inline void kvm_hisi_reload_lsudvmbm(struct kvm *kvm) {} #endif /* CONFIG_KVM_HISI_VIRT */ +extern bool gic_dist_enable_ipiv(void); +extern bool is_gicv4p1(void); #endif /* __HISI_VIRT_H__ */ diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c index d55607dcd226..0edea419baf3 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c +++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c @@ -342,6 +342,7 @@ static unsigned long vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu, u64 value; value = (u64)(mpidr & GENMASK(23, 0)) << 32; + value |= MPIDR_AFFINITY_LEVEL(mpidr, 3) << 56; value |= ((target_vcpu_id & 0xffff) << 8); if (vgic_has_its(vcpu->kvm)) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 8e80eed7513c..7a64d77be181 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -1514,6 +1514,36 @@ static int gic_dist_supports_lpis(void) !gicv3_nolpi); } +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; + + val = readl_relaxed(gic_data.dist_base + GICD_MISC_CTRL); + val |= GICD_MISC_CTRL_CFG_IPIV_EN; + writel_relaxed(val, gic_data.dist_base + GICD_MISC_CTRL); + 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) | + (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); + + /* Set target ITS address of IPIV feature */ + writel_relaxed(0x4880, gic_data.dist_base + GICD_IPIV_ITS_TA_BASE); +} +EXPORT_SYMBOL(gic_dist_enable_ipiv); + static void gic_cpu_init(void) { void __iomem *rbase; diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 074b347e8fcc..5fdc3ae4cd99 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -113,6 +113,18 @@ #define GIC_PAGE_SIZE_64K 2ULL #define GIC_PAGE_SIZE_MASK 3ULL +#define GICD_MISC_CTRL 0x2084 +#define GICD_MISC_CTRL_CFG_IPIV_EN (1U << 19) + +/* IPIV private register */ +#define GICD_IPIV_CTRL 0xc05c +#define GICD_IPIV_CTRL_AFF_DIRECT_VPEID_SHIFT 4 +#define GICD_IPIV_CTRL_AFF1_LEFT_SHIFT_SHIFT 8 +#define GICD_IPIV_CTRL_AFF2_LEFT_SHIFT_SHIFT 12 +#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 + /* * Re-Distributor registers, offsets from RD_base */ -- 2.33.0

virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBPH85 ------------------------------------------------------------------------ Follow the kabi repair method of openeuler and use KABI_EXTEND. Its essence is to use GENKSYMS shielding. 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 e0473eab485a..630b18f455c0 100644 --- a/include/linux/irqchip/arm-gic-v4.h +++ b/include/linux/irqchip/arm-gic-v4.h @@ -20,7 +20,6 @@ struct its_vm { struct fwnode_handle *fwnode; struct irq_domain *domain; struct page *vprop_page; - struct page *vpe_page; struct its_vpe **vpes; int nr_vpes; irq_hw_number_t db_lpi_base; @@ -35,7 +34,8 @@ struct its_vm { */ raw_spinlock_t vmapp_lock; u32 vlpi_count[GICv4_ITS_LIST_MAX]; - bool nassgireq; + KABI_EXTEND(struct page *vpe_page) + KABI_EXTEND(bool nassgireq) }; /* Embedded in kvm_vcpu.arch */ -- 2.33.0

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