The read emulation of the register IROUTER contains lots of uncessary code as irouter is already valid and doesn't need any processing before setting the value in a register.
Also take the opportunity to factorize the code to find a vCPU from the affinity in a single place. It will be easier to change the way to do it later. Signed-off-by: Julien Grall <julien.gr...@citrix.com> Cc: Chen Baozi <c...@baozis.org> --- xen/arch/arm/vgic-v3.c | 100 ++++++++++++++++++------------------------------- 1 file changed, 36 insertions(+), 64 deletions(-) diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c index 45a46c3..4af5a84 100644 --- a/xen/arch/arm/vgic-v3.c +++ b/xen/arch/arm/vgic-v3.c @@ -50,42 +50,36 @@ */ #define VGICD_CTLR_DEFAULT (GICD_CTLR_ARE_NS) -static struct vcpu *vgic_v3_irouter_to_vcpu(struct vcpu *v, uint64_t irouter) +static struct vcpu *vgic_v3_irouter_to_vcpu(struct domain *d, uint64_t irouter) { - irouter &= ~(GICD_IROUTER_SPI_MODE_ANY); - irouter = irouter & MPIDR_AFF0_MASK; - - return v->domain->vcpu[irouter]; -} + unsigned int vcpu_id; -static uint64_t vgic_v3_vcpu_to_irouter(struct vcpu *v, - unsigned int vcpu_id) -{ - uint64_t irq_affinity; - struct vcpu *v_target; + /* + * When the Interrupt Route Mode is set, the IRQ targets any vCPUs. + * For simplicity, the IRQ is always routed to vCPU0. + */ + if ( irouter & GICD_IROUTER_SPI_MODE_ANY ) + return d->vcpu[0]; - v_target = v->domain->vcpu[vcpu_id]; - irq_affinity = (MPIDR_AFFINITY_LEVEL(v_target->arch.vmpidr, 3) << 32 | - MPIDR_AFFINITY_LEVEL(v_target->arch.vmpidr, 2) << 16 | - MPIDR_AFFINITY_LEVEL(v_target->arch.vmpidr, 1) << 8 | - MPIDR_AFFINITY_LEVEL(v_target->arch.vmpidr, 0)); + vcpu_id = irouter & MPIDR_AFF0_MASK; + if ( vcpu_id >= d->max_vcpus ) + return NULL; - return irq_affinity; + return d->vcpu[vcpu_id]; } static struct vcpu *vgic_v3_get_target_vcpu(struct vcpu *v, unsigned int irq) { - uint64_t target; + struct vcpu *v_target; struct vgic_irq_rank *rank = vgic_rank_irq(v, irq); ASSERT(spin_is_locked(&rank->lock)); - target = rank->v3.irouter[irq % 32]; - target &= ~(GICD_IROUTER_SPI_MODE_ANY); - target &= MPIDR_AFF0_MASK; - ASSERT(target >= 0 && target < v->domain->max_vcpus); + v_target = vgic_v3_irouter_to_vcpu(v->domain, rank->v3.irouter[irq % 32]); - return v->domain->vcpu[target]; + ASSERT(v_target != NULL); + + return v_target; } static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info, @@ -670,8 +664,6 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info) register_t *r = select_user_reg(regs, dabt.reg); struct vgic_irq_rank *rank; unsigned long flags; - uint64_t irouter; - unsigned int vcpu_id; int gicd_reg = (int)(info->gpa - v->domain->arch.vgic.dbase); perfc_incr(vgicd_reads); @@ -742,17 +734,8 @@ static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info) DABT_DOUBLE_WORD); if ( rank == NULL ) goto read_as_zero; vgic_lock_rank(v, rank, flags); - irouter = rank->v3.irouter[REG_RANK_INDEX(64, - (gicd_reg - GICD_IROUTER), DABT_DOUBLE_WORD)]; - /* XXX: bit[31] stores IRQ mode. Just return */ - if ( irouter & GICD_IROUTER_SPI_MODE_ANY ) - { - *r = GICD_IROUTER_SPI_MODE_ANY; - vgic_unlock_rank(v, rank, flags); - return 1; - } - vcpu_id = irouter; - *r = vgic_v3_vcpu_to_irouter(v, vcpu_id); + *r = rank->v3.irouter[REG_RANK_INDEX(64, + (gicd_reg - GICD_IROUTER), DABT_DOUBLE_WORD)]; vgic_unlock_rank(v, rank, flags); return 1; case GICD_NSACR ... GICD_NSACRN: @@ -838,7 +821,7 @@ static int vgic_v3_distr_mmio_write(struct vcpu *v, mmio_info_t *info) register_t *r = select_user_reg(regs, dabt.reg); struct vgic_irq_rank *rank; unsigned long flags; - uint64_t new_irouter, new_target, old_target; + uint64_t new_irouter, old_irouter; struct vcpu *old_vcpu, *new_vcpu; int gicd_reg = (int)(info->gpa - v->domain->arch.vgic.dbase); @@ -910,40 +893,29 @@ static int vgic_v3_distr_mmio_write(struct vcpu *v, mmio_info_t *info) new_irouter = *r; vgic_lock_rank(v, rank, flags); - old_target = rank->v3.irouter[REG_RANK_INDEX(64, - (gicd_reg - GICD_IROUTER), DABT_DOUBLE_WORD)]; - old_target &= ~(GICD_IROUTER_SPI_MODE_ANY); - if ( new_irouter & GICD_IROUTER_SPI_MODE_ANY ) + old_irouter = rank->v3.irouter[REG_RANK_INDEX(64, + (gicd_reg - GICD_IROUTER), + DABT_DOUBLE_WORD)]; + old_vcpu = vgic_v3_irouter_to_vcpu(v->domain, old_irouter); + new_vcpu = vgic_v3_irouter_to_vcpu(v->domain, new_irouter); + + if ( !new_vcpu ) { + printk(XENLOG_G_DEBUG + "%pv: vGICD: wrong irouter at offset %#08x val %#"PRIregister, + v, gicd_reg, *r); + vgic_unlock_rank(v, rank, flags); /* - * IRQ routing mode set. Route any one processor in the entire - * system. We chose vcpu 0 and set IRQ mode bit[31] in irouter. + * TODO: Don't inject a fault to the guest when the MPIDR is + * not valid. From the spec, the interrupt should be + * ignored. */ - new_target = 0; - new_vcpu = v->domain->vcpu[0]; - new_irouter = GICD_IROUTER_SPI_MODE_ANY; - } - else - { - new_target = new_irouter & MPIDR_AFF0_MASK; - if ( new_target >= v->domain->max_vcpus ) - { - printk(XENLOG_G_DEBUG - "%pv: vGICD: wrong irouter at offset %#08x\n val 0x%lx vcpu %x", - v, gicd_reg, new_target, v->domain->max_vcpus); - vgic_unlock_rank(v, rank, flags); - return 0; - } - new_vcpu = vgic_v3_irouter_to_vcpu(v, new_irouter); + return 0; } - rank->v3.irouter[REG_RANK_INDEX(64, (gicd_reg - GICD_IROUTER), DABT_DOUBLE_WORD)] = new_irouter; - if ( old_target != new_target ) - { - old_vcpu = v->domain->vcpu[old_target]; + if ( old_vcpu != new_vcpu ) vgic_migrate_irq(old_vcpu, new_vcpu, (gicd_reg - GICD_IROUTER)/8); - } vgic_unlock_rank(v, rank, flags); return 1; case GICD_NSACR ... GICD_NSACRN: -- 2.1.4 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel