[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH] xen/arm: implement GICD_ICACTIVER read/write




On 2015/11/26 0:40, Stefano Stabellini wrote:
> Implement GICD_ICACTIVER and GICD_ISACTIVER reads by looking for the
> GIC_IRQ_GUEST_ACTIVE bit in the relevant struct pending_irq. However
> given that the pending to active transaction for irqs in LRs in done in
> hardware, the GIC_IRQ_GUEST_ACTIVE bit might be out of date. We'll have
> to live with that.
> 
> Implement GICD_ICACTIVER writes by checking the state of the irq in our
> queues: if the irq is present in an LR, remove the hardware ACTIVE bit.
> If the irq is present in an LR of another vcpu, send an IPI. Set the
> GIC_IRQ_GUEST_DEACTIVATE bit to tell the receiving vcpu that the active
> bit needs to be deactivated.
> 
> Signed-off-by: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>

Tested-by: Shannon Zhao <shannon.zhao@xxxxxxxxxx>

> ---
>  xen/arch/arm/gic.c         |   40 +++++++++++++++++++++++++++++++++++++++
>  xen/arch/arm/vgic-v2.c     |   45 
> ++++++++++++++++++++++++++++++++++++++------
>  xen/arch/arm/vgic-v3.c     |   44 ++++++++++++++++++++++++++++++++++++++-----
>  xen/include/asm-arm/gic.h  |    1 +
>  xen/include/asm-arm/vgic.h |    4 ++++
>  5 files changed, 123 insertions(+), 11 deletions(-)
> 
> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> index 1e1e5ba..75c1f52 100644
> --- a/xen/arch/arm/gic.c
> +++ b/xen/arch/arm/gic.c
> @@ -414,6 +414,15 @@ static void gic_update_one_lr(struct vcpu *v, int i)
>      gic_hw_ops->read_lr(i, &lr_val);
>      irq = lr_val.virq;
>      p = irq_to_pending(v, irq);
> +
> +    if ( test_and_clear_bit(GIC_IRQ_GUEST_DEACTIVATE, &p->status) &&
> +         (lr_val.state & GICH_LR_ACTIVE) )
> +    {
> +        clear_bit(GIC_IRQ_GUEST_ACTIVE, &p->status);
> +        lr_val.state &= ~GICH_LR_ACTIVE;
> +        gic_hw_ops->write_lr(i, &lr_val);
> +    }
> +
>      if ( lr_val.state & GICH_LR_ACTIVE )
>      {
>          set_bit(GIC_IRQ_GUEST_ACTIVE, &p->status);
> @@ -489,6 +498,37 @@ void gic_clear_lrs(struct vcpu *v)
>      spin_unlock_irqrestore(&v->arch.vgic.lock, flags);
>  }
>  
> +/* called with rank lock held */
> +void gic_deactivate_irq(struct vcpu *v, unsigned int irq)
> +{
> +    unsigned long flags;
> +    struct pending_irq *p;
> +    struct vcpu *v_target = v->domain->arch.vgic.handler->get_target_vcpu(v, 
> irq);
> +
> +    spin_lock_irqsave(&v_target->arch.vgic.lock, flags);
> +
> +    p = irq_to_pending(v_target, irq);
> +    /* the interrupt is not even in an LR */
> +    if ( list_empty(&p->inflight) || !list_empty(&p->lr_queue) )
> +    {
> +        spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags);
> +        return;
> +    }
> +
> +    /* it is in an LR, let's check */
> +    set_bit(GIC_IRQ_GUEST_DEACTIVATE, &p->status);
> +    if ( v_target == current )
> +    {
> +        gic_update_one_lr(v_target, p->lr);
> +        spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags);
> +    } else {
> +        spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags);
> +        vcpu_unblock(v_target);
> +        if (v_target->is_running )
> +            smp_send_event_check_mask(cpumask_of(v_target->processor));
> +    }
> +}
> +
>  static void gic_restore_pending_irqs(struct vcpu *v)
>  {
>      int lr = 0;
> diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
> index f7d784b..9042062 100644
> --- a/xen/arch/arm/vgic-v2.c
> +++ b/xen/arch/arm/vgic-v2.c
> @@ -126,8 +126,31 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, 
> mmio_info_t *info,
>      /* Read the active status of an IRQ via GICD is not supported */
>      case GICD_ISACTIVER ... GICD_ISACTIVERN:
>      case GICD_ICACTIVER ... GICD_ICACTIVERN:
> -        goto read_as_zero;
> -
> +    {
> +        unsigned int i = 0, irq = 0;
> +        struct pending_irq *p;
> +        if ( dabt.size != DABT_WORD ) goto bad_width;
> +        rank = vgic_rank_offset(v, 1, gicd_reg - GICD_ICACTIVER, DABT_WORD);
> +        if ( rank == NULL) goto read_as_zero;
> +        vgic_lock_rank(v, rank, flags);
> +        *r = 0;
> +        irq = (gicd_reg - GICD_ICACTIVER) << 3;
> +        for (i = 0; i < 32; i++)
> +        {
> +            p = irq_to_pending(v, i + irq);
> +            /*
> +             * This information is likely out of date because we don't
> +             * actually know which interrupts have become ACTIVE from
> +             * PENDING in the LRs of other processors at it happens
> +             * transparently in hardware.  We would have to interrupt
> +             * all other running vcpus to get an accurate snapshot.
> +             * Let's not do that.
> +             */
> +            *r |= test_bit(GIC_IRQ_GUEST_ACTIVE, &p->status) ? (1 << i) : 0;
> +        }
> +        vgic_unlock_rank(v, rank, flags);
> +        return 1;
> +    }
>      case GICD_ITARGETSR ... GICD_ITARGETSRN:
>          if ( dabt.size != DABT_BYTE && dabt.size != DABT_WORD ) goto 
> bad_width;
>          rank = vgic_rank_offset(v, 8, gicd_reg - GICD_ITARGETSR, DABT_WORD);
> @@ -332,11 +355,21 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, 
> mmio_info_t *info,
>          return 0;
>  
>      case GICD_ICACTIVER ... GICD_ICACTIVERN:
> +    {
> +        unsigned int i = 0, irq;
>          if ( dabt.size != DABT_WORD ) goto bad_width;
> -        printk(XENLOG_G_ERR
> -               "%pv: vGICD: unhandled word write %#"PRIregister" to 
> ICACTIVER%d\n",
> -               v, r, gicd_reg - GICD_ICACTIVER);
> -        return 0;
> +        rank = vgic_rank_offset(v, 1, gicd_reg - GICD_ICACTIVER, DABT_WORD);
> +        if ( rank == NULL) goto write_ignore;
> +        vgic_lock_rank(v, rank, flags);
> +        irq = (gicd_reg - GICD_ICACTIVER) << 3;
> +        while ( (i = find_next_bit(&r, 32, i)) < 32 )
> +        {
> +            gic_deactivate_irq(v, i + irq);
> +            i++;
> +        }
> +        vgic_unlock_rank(v, rank, flags);
> +        return 1;
> +    }
>  
>      case GICD_ITARGETSR ... GICD_ITARGETSR + 7:
>          /* SGI/PPI target is read only */
> diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
> index b5249ff..c779f75 100644
> --- a/xen/arch/arm/vgic-v3.c
> +++ b/xen/arch/arm/vgic-v3.c
> @@ -325,7 +325,31 @@ static int __vgic_v3_distr_common_mmio_read(const char 
> *name, struct vcpu *v,
>      /* Read the active status of an IRQ via GICD/GICR is not supported */
>      case GICD_ISACTIVER ... GICD_ISACTIVERN:
>      case GICD_ICACTIVER ... GICD_ICACTIVERN:
> -        goto read_as_zero;
> +    {
> +        unsigned int i = 0, irq = 0;
> +        struct pending_irq *p;
> +        if ( dabt.size != DABT_WORD ) goto bad_width;
> +        rank = vgic_rank_offset(v, 1, reg - GICD_ICACTIVER, DABT_WORD);
> +        if ( rank == NULL) goto read_as_zero;
> +        vgic_lock_rank(v, rank, flags);
> +        *r = 0;
> +        irq = (reg - GICD_ICACTIVER) << 3;
> +        for (i = 0; i < 32; i++)
> +        {
> +            p = irq_to_pending(v, i + irq);
> +            /*
> +             * This information is likely out of date because we don't
> +             * actually know which interrupts have become ACTIVE from
> +             * PENDING in the LRs of other processors at it happens
> +             * transparently in hardware.  We would have to interrupt
> +             * all other running vcpus to get an accurate snapshot.
> +             * Let's not do that.
> +             */
> +            *r |= test_bit(GIC_IRQ_GUEST_ACTIVE, &p->status) ? (1 << i) : 0;
> +        }
> +        vgic_unlock_rank(v, rank, flags);
> +        return 1;
> +    }
>  
>      case GICD_IPRIORITYR ... GICD_IPRIORITYRN:
>          if ( dabt.size != DABT_BYTE && dabt.size != DABT_WORD ) goto 
> bad_width;
> @@ -421,11 +445,21 @@ static int __vgic_v3_distr_common_mmio_write(const char 
> *name, struct vcpu *v,
>          return 0;
>  
>      case GICD_ICACTIVER ... GICD_ICACTIVERN:
> +    {
> +        unsigned int i = 0, irq;
>          if ( dabt.size != DABT_WORD ) goto bad_width;
> -        printk(XENLOG_G_ERR
> -               "%pv: %s: unhandled word write %#"PRIregister" to 
> ICACTIVER%d\n",
> -               v, name, r, reg - GICD_ICACTIVER);
> -        return 0;
> +        rank = vgic_rank_offset(v, 1, reg - GICD_ICACTIVER, DABT_WORD);
> +        if ( rank == NULL) goto write_ignore;
> +        vgic_lock_rank(v, rank, flags);
> +        irq = (reg - GICD_ICACTIVER) << 3;
> +        while ( (i = find_next_bit(&r, 32, i)) < 32 )
> +        {
> +            gic_deactivate_irq(v, i + irq);
> +            i++;
> +        }
> +        vgic_unlock_rank(v, rank, flags);
> +        return 1;
> +    }
>  
>      case GICD_IPRIORITYR ... GICD_IPRIORITYRN:
>          if ( dabt.size != DABT_BYTE && dabt.size != DABT_WORD ) goto 
> bad_width;
> diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
> index 0116481..0061368 100644
> --- a/xen/include/asm-arm/gic.h
> +++ b/xen/include/asm-arm/gic.h
> @@ -287,6 +287,7 @@ extern unsigned int gic_number_lines(void);
>  int gic_irq_xlate(const u32 *intspec, unsigned int intsize,
>                    unsigned int *out_hwirq, unsigned int *out_type);
>  void gic_clear_lrs(struct vcpu *v);
> +void gic_deactivate_irq(struct vcpu *v, unsigned int irq);
>  
>  struct gic_info {
>      /* GIC version */
> diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
> index cb51a9e..9845c13 100644
> --- a/xen/include/asm-arm/vgic.h
> +++ b/xen/include/asm-arm/vgic.h
> @@ -59,12 +59,16 @@ struct pending_irq
>       * vcpu while it is still inflight and on an GICH_LR register on the
>       * old vcpu.
>       *
> +     * GIC_IRQ_GUEST_DEACTIVATE: an explicit deactivation request has
> +     * been made by the guest (for example writing to GICD_ICACTIVER).
> +     *
>       */
>  #define GIC_IRQ_GUEST_QUEUED   0
>  #define GIC_IRQ_GUEST_ACTIVE   1
>  #define GIC_IRQ_GUEST_VISIBLE  2
>  #define GIC_IRQ_GUEST_ENABLED  3
>  #define GIC_IRQ_GUEST_MIGRATING   4
> +#define GIC_IRQ_GUEST_DEACTIVATE  5
>      unsigned long status;
>      struct irq_desc *desc; /* only set it the irq corresponds to a physical 
> irq */
>      unsigned int irq;
> 

-- 
Shannon


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.