
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. Signed-off-by: Xiang Chen <chenxiang66@hisilicon.com> Signed-off-by: Nianyao Tang <tangnianyao@huawei.com> Signed-off-by: Jinqian Yang <yangjinqian1@huawei.com> --- drivers/irqchip/irq-gic-v3-its.c | 58 ++++++++++++++++++++++++------ drivers/irqchip/irq-gic-v3.c | 9 ++++- include/linux/irqchip/arm-gic-v3.h | 14 ++++++++ 3 files changed, 69 insertions(+), 12 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 8ec6fd61b59d..1bf16c1f9a92 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -4572,18 +4572,44 @@ static void its_vpe_4_1_schedule(struct its_vpe *vpe, struct its_vm *vm = vpe->its_vm; unsigned long vpe_addr; u64 val = 0; - - if (static_branch_unlikely(&ipiv_enable) && - !static_branch_unlikely(&ipiv_direct)) { - vpe_addr = virt_to_phys(page_address(vm->vpe_page)); - writeq_relaxed(vpe_addr & 0xffffffff, + u32 nr_vpes; + + if (static_branch_unlikely(&ipiv_enable)) { + /* 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)); + if (!static_branch_unlikely(&ipiv_direct)) { + /* setup vm table */ + vpe_addr = virt_to_phys(page_address(vm->vpe_page)); + writel_relaxed(vpe_addr & 0xffffffff, vlpi_base + GICR_VM_TABLE_BAR_L); - writeq_relaxed((vpe_addr >> 32) & 0xffffffff, + 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); + } + + /* disable guest access ICC_SGI1R_EL1 trap */ + asm volatile("mrs %0, s3_4_c15_c7_2" : "=r" (val)); + val |= 1ULL; + asm volatile("msr s3_4_c15_c7_2, %0" : : "r" (val)); + asm volatile("mrs %0, s3_4_c15_c7_2" : "=r" (val)); + } /* 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); @@ -4627,10 +4653,20 @@ static void its_vpe_4_1_deschedule(struct its_vpe *vpe, vpe->pending_last = true; } - if (static_branch_unlikely(&ipiv_enable) && - !static_branch_unlikely(&ipiv_direct)) { - writeq_relaxed(0, vlpi_base + GICR_VM_TABLE_BAR_L); - writeq_relaxed(0, vlpi_base + GICR_VM_TABLE_BAR_H); + if (static_branch_unlikely(&ipiv_enable)) { + 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); + } + /* enable guest access ICC_SGI1R_EL1 trap, disable ipiv */ + asm volatile("mrs %0, s3_4_c15_c7_2" : "=r" (val)); + val &= ~1UL; + asm volatile("msr s3_4_c15_c7_2, %0" : : "r" (val)); + asm volatile("mrs %0, s3_4_c15_c7_2" : "=r" (val)); } } diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index a24160eabc1a..d5c4d0993436 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -1534,9 +1534,16 @@ bool gic_dist_enable_ipiv(bool direct) if (direct) { val |= GICD_IPIV_CTRL_AFF_DIRECT_VPEID; 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 */ + writel_relaxed(0x4880, gic_data.dist_base + GICD_IPIV_ITS_TA_BASE); return true; } EXPORT_SYMBOL(gic_dist_enable_ipiv); diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index bc96a5b66ee9..dbdaf5457a5f 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -118,7 +118,13 @@ #define GICD_IPIV_CTRL 0xc05c #define GICD_IPIV_CTRL_AFF_DIRECT_VPEID (1U << 4) +#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 */ @@ -371,6 +377,14 @@ #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 */ -- 2.33.0