
From: Xiang Chen <chenxiang66@hisilicon.com> virt inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/IBPH85 ------------------------------------------------------------------------ There are two modes for IPIV feature: - indirect mode, access vm table to retrieve vpeid; - direct mode, directly calcute vpeid according to mpidr; Add support for ipiv direct mode. Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com> Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- .../admin-guide/kernel-parameters.txt | 5 ++ arch/arm64/kvm/arm.c | 8 ++- arch/arm64/kvm/hisilicon/hisi_virt.c | 11 +++- arch/arm64/kvm/hisilicon/hisi_virt.h | 2 +- drivers/irqchip/irq-gic-v3-its.c | 50 ++++++++++++------- drivers/irqchip/irq-gic-v3.c | 18 ++++--- 6 files changed, 65 insertions(+), 29 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 6d8ad9c0e1fd..a5a76107d294 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2712,6 +2712,11 @@ kvm-arm.ipiv_enabled= [KVM,ARM] Allow use of HiSilicon ipiv on GICv4.1 + kvm-arm.ipiv_direct= + [KVM,ARM] Use different modes of ipiv if ipiv enabled + Default is 0 which using vmtable in memory to retrieve aff-vpeid + Directly calculate vpeid according to aff if set 1 + kvm-arm.dvmbm_enabled= [KVM,ARM] Allow use of HiSilicon DVMBM capability. Default: 0 diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index fcc0b4ae1ed5..43ef7742be82 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -316,6 +316,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm) } extern struct static_key_false ipiv_enable; +extern struct static_key_false ipiv_direct; int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) { @@ -443,9 +444,12 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) #endif case KVM_CAP_ARM_IPIV_MODE: if (static_branch_unlikely(&ipiv_enable)) { - r = 1; + if (static_branch_unlikely(&ipiv_direct)) + r = 2; /* direct mode */ + else + r = 1; /* indirect mode */ } else { - r = 0; + r = 0; /* don't enable IPIV */ } break; default: diff --git a/arch/arm64/kvm/hisilicon/hisi_virt.c b/arch/arm64/kvm/hisilicon/hisi_virt.c index 59814df372a2..07c0c76c1d09 100644 --- a/arch/arm64/kvm/hisilicon/hisi_virt.c +++ b/arch/arm64/kvm/hisilicon/hisi_virt.c @@ -13,6 +13,7 @@ static enum hisi_cpu_type cpu_type = UNKNOWN_HI_TYPE; static bool dvmbm_enabled; static bool ipiv_enabled; +static bool ipiv_direct; static const char * const hisi_cpu_type_str[] = { "Hisi1612", @@ -164,6 +165,12 @@ static int __init early_ipiv_enable(char *buf) } early_param("kvm-arm.ipiv_enabled", early_ipiv_enable); +static int __init early_ipiv_direct(char *buf) +{ + return kstrtobool(buf, &ipiv_direct); +} +early_param("kvm-arm.ipiv_direct", early_ipiv_direct); + bool hisi_ipiv_supported(void) { /* Determine whether IPIV is supported by the hardware */ @@ -182,12 +189,14 @@ bool hisi_ipiv_supported(void) kvm_info("Need to enable GICv4p1!\n"); return false; } + + kvm_info("Enable Hisi ipiv with %s mode\n", ipiv_direct ? "direct" : "indirect"); return true; } void ipiv_gicd_init() { - gic_dist_enable_ipiv(); + gic_dist_enable_ipiv(ipiv_direct); } 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..09f33f7cc18e 100644 --- a/arch/arm64/kvm/hisilicon/hisi_virt.h +++ b/arch/arm64/kvm/hisilicon/hisi_virt.h @@ -120,6 +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 gic_dist_enable_ipiv(bool direct); extern bool is_gicv4p1(void); #endif /* __HISI_VIRT_H__ */ diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index a607b6373c59..a8d07320c851 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -389,6 +389,7 @@ static int alloc_devid_from_rsv_pools(struct rsv_devid_pool **devid_pool, #define gic_data_rdist_vlpi_base() (gic_data_rdist_rd_base() + SZ_128K) extern struct static_key_false ipiv_enable; +extern struct static_key_false ipiv_direct; #ifdef CONFIG_VIRT_PLAT_DEV /* @@ -4596,17 +4597,23 @@ static void its_vpe_4_1_schedule(struct its_vpe *vpe, /* 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(vpe_addr & 0xffffffff, - vlpi_base + GICR_VM_TABLE_BAR_L); - writel_relaxed((vpe_addr >> 32) & 0xffffffff, - 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); + if (!static_branch_unlikely(&ipiv_direct)) { + vpe_addr = virt_to_phys(page_address(vm->vpe_page)); + writel_relaxed(vpe_addr & 0xffffffff, + vlpi_base + GICR_VM_TABLE_BAR_L); + writel_relaxed((vpe_addr >> 32) & 0xffffffff, + 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); + } else { + /* setup gicr_ipiv_its_ta_sel */ + val = (0 << GICR_IPIV_CTRL_IPIV_ITS_TA_SEL_SHIFT); + writel_relaxed(val, vlpi_base + GICR_IPIV_CTRL); + } ipiv_disable_vsgi_trap(val); } else { @@ -4661,11 +4668,13 @@ static void its_vpe_4_1_deschedule(struct its_vpe *vpe, 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); + if (!static_branch_unlikely(&ipiv_direct)) { + /* 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(val); } @@ -5079,7 +5088,8 @@ static void its_vpe_irq_domain_free(struct irq_domain *domain, if (bitmap_empty(vm->db_bitmap, vm->nr_db_lpis)) { its_lpi_free(vm->db_bitmap, vm->db_lpi_base, vm->nr_db_lpis); its_free_prop_table(vm->vprop_page); - if (static_branch_unlikely(&ipiv_enable)) { + if (static_branch_unlikely(&ipiv_enable) && + !static_branch_unlikely(&ipiv_direct)) { free_pages((unsigned long)page_address(vm->vpe_page), get_order(nr_irqs * 2)); } @@ -5120,7 +5130,8 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virq if (gic_rdists->has_rvpeid) { irqchip = &its_vpe_4_1_irq_chip; - if (static_branch_unlikely(&ipiv_enable)) { + if (static_branch_unlikely(&ipiv_enable) && + !static_branch_unlikely(&ipiv_direct)) { vpe_page = alloc_pages(GFP_KERNEL, get_order(nr_irqs * 2)); if (!vpe_page) { its_lpi_free(vm->db_bitmap, vm->db_lpi_base, vm->nr_db_lpis); @@ -5137,7 +5148,8 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virq err = its_vpe_init(vm->vpes[i]); if (err) break; - if (static_branch_unlikely(&ipiv_enable)) { + if (static_branch_unlikely(&ipiv_enable) && + !static_branch_unlikely(&ipiv_direct)) { vpe_entry = (u16 *)vpe_table_va + i; *(u16 *)vpe_entry = vm->vpes[i]->vpe_id; } diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index d1c2e2315e42..b1956e1c6273 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -1526,7 +1526,7 @@ bool is_gicv4p1(void) } EXPORT_SYMBOL(is_gicv4p1); -void gic_dist_enable_ipiv(void) +void gic_dist_enable_ipiv(bool direct) { u32 val; @@ -1535,11 +1535,17 @@ void gic_dist_enable_ipiv(void) 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); + val = readl_relaxed(gic_data.dist_base + GICD_IPIV_CTRL); + if (direct) { + val |= (1U << GICD_IPIV_CTRL_AFF_DIRECT_VPEID_SHIFT); + static_branch_enable(&ipiv_direct); + } else { + 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 */ -- 2.33.0