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

Re: [Xen-devel] [PATCH v4 12/17] xen/arm: ITS: Initialize LPI irq descriptors and route



On Fri, 10 Jul 2015, vijay.kilari@xxxxxxxxx wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
> 
> Allocate and initialize irq descriptor for LPIs and
> route LPIs to guest
> 
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
> ---
> v4: - Merge patch #16
>     - Changed commit message
> ---
>  xen/arch/arm/gic-v3.c         |    2 +-
>  xen/arch/arm/gic.c            |   24 +++++++--
>  xen/arch/arm/irq.c            |   44 +++++++++++++----
>  xen/arch/arm/vgic-v3-its.c    |    9 ++++
>  xen/arch/arm/vgic-v3.c        |   15 ++++--
>  xen/arch/arm/vgic.c           |  110 
> ++++++++++++++++++++++++++++++++++++++---
>  xen/include/asm-arm/domain.h  |    3 ++
>  xen/include/asm-arm/gic-its.h |    1 +
>  xen/include/asm-arm/gic.h     |    7 ++-
>  xen/include/asm-arm/vgic.h    |    1 +
>  10 files changed, 192 insertions(+), 24 deletions(-)
> 
> diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
> index e6004d2..53554e6 100644
> --- a/xen/arch/arm/gic-v3.c
> +++ b/xen/arch/arm/gic-v3.c
> @@ -895,7 +895,7 @@ static void gicv3_update_lr(int lr, const struct 
> pending_irq *p,
>      val |= ((uint64_t)p->priority & 0xff) << GICH_LR_PRIORITY_SHIFT;
>      val |= ((uint64_t)p->irq & GICH_LR_VIRTUAL_MASK) << 
> GICH_LR_VIRTUAL_SHIFT;
>  
> -   if ( p->desc != NULL )
> +   if ( p->desc != NULL && !(is_lpi(p->irq)) )
>         val |= GICH_LR_HW | (((uint64_t)p->desc->irq & GICH_LR_PHYSICAL_MASK)
>                             << GICH_LR_PHYSICAL_SHIFT);
>  
> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
> index 3ebadcf..92d2be9 100644
> --- a/xen/arch/arm/gic.c
> +++ b/xen/arch/arm/gic.c
> @@ -68,11 +68,18 @@ enum gic_version gic_hw_version(void)
>     return gic_hw_ops->info->hw_version;
>  }
>  
> +/* Only validates PPIs/SGIs/SPIs supported */
>  unsigned int gic_number_lines(void)
>  {
>      return gic_hw_ops->info->nr_lines;
>  }
>  
> +/* Validates PPIs/SGIs/SPIs/LPIs supported */
> +bool_t gic_is_valid_irq(unsigned int irq)
> +{
> +    return ((irq < gic_hw_ops->info->nr_lines) && is_lpi(irq));
> +}

shouldn't it be ((irq < gic_hw_ops->info->nr_lines) || is_lpi(irq)) ?


>  unsigned int gic_nr_id_bits(void)
>  {
>      return gic_hw_ops->info->nr_id_bits;
> @@ -148,7 +155,7 @@ void gic_route_irq_to_xen(struct irq_desc *desc, const 
> cpumask_t *cpu_mask,
>  {
>      ASSERT(priority <= 0xff);     /* Only 8 bits of priority */
>      /* Can't route interrupts that don't exist */
> -    ASSERT(desc->irq < gic_number_lines() || is_lpi(desc->irq));
> +    ASSERT(gic_is_valid_irq(desc->irq));
>      ASSERT(test_bit(_IRQ_DISABLED, &desc->status));
>      ASSERT(spin_is_locked(&desc->lock));
>  
> @@ -160,6 +167,17 @@ void gic_route_irq_to_xen(struct irq_desc *desc, const 
> cpumask_t *cpu_mask,
>  /* Program the GIC to route an interrupt to a guest
>   *   - desc.lock must be held
>   */
> +int gic_route_lpi_to_guest(struct domain *d, unsigned int virq,
> +                           struct irq_desc *desc, unsigned int priority)
> +{
> +    ASSERT(spin_is_locked(&desc->lock));
> +
> +    desc->handler = get_guest_hw_irq_controller(desc->irq);
> +    set_bit(_IRQ_GUEST, &desc->status);
> +
> +    return 0;
> +}
> +
>  int gic_route_irq_to_guest(struct domain *d, unsigned int virq,
>                             struct irq_desc *desc, unsigned int priority)
>  {
> @@ -454,7 +472,7 @@ static void gic_update_one_lr(struct vcpu *v, int i)
>          if ( test_bit(GIC_IRQ_GUEST_ENABLED, &p->status) &&
>               test_and_clear_bit(GIC_IRQ_GUEST_QUEUED, &p->status) )
>          {
> -            if ( p->desc == NULL )
> +            if ( p->desc == NULL  || is_lpi(irq) )
>              {
>                   lr_val.state |= GICH_LR_PENDING;
>                   gic_hw_ops->write_lr(i, &lr_val);
> @@ -677,7 +695,7 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq)
>          /* Reading IRQ will ACK it */
>          irq = gic_hw_ops->read_irq();
>  
> -        if ( likely(irq >= 16 && irq < 1020) )
> +        if ( (likely(irq >= 16 && irq < 1020)) || is_lpi(irq) )
>          {
>              local_irq_enable();
>              do_IRQ(regs, irq, is_fiq);
> diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
> index 3806d98..c8ea627 100644
> --- a/xen/arch/arm/irq.c
> +++ b/xen/arch/arm/irq.c
> @@ -62,12 +62,21 @@ hw_irq_controller no_irq_type = {
>  };
>  
>  static irq_desc_t irq_desc[NR_IRQS];
> +#ifdef CONFIG_ARM_64
> +static irq_desc_t irq_desc_lpi[NR_GIC_LPI];
> +#endif
>  static DEFINE_PER_CPU(irq_desc_t[NR_LOCAL_IRQS], local_irq_desc);
>  
>  irq_desc_t *__irq_to_desc(int irq)
>  {
>      if (irq < NR_LOCAL_IRQS) return &this_cpu(local_irq_desc)[irq];
> -    return &irq_desc[irq-NR_LOCAL_IRQS];
> +    else if ( irq >= NR_LOCAL_IRQS && irq < NR_IRQS)
> +        return &irq_desc[irq-NR_LOCAL_IRQS];
> +#ifdef CONFIG_ARM_64
> +    else if ( is_lpi(irq) )
> +        return &irq_desc_lpi[irq - NR_GIC_LPI];
> +#endif
> +    return NULL;
>  }
>  
>  int __init arch_init_one_irq_desc(struct irq_desc *desc)
> @@ -88,6 +97,15 @@ static int __init init_irq_data(void)
>          desc->action  = NULL;
>      }
>  
> +#ifdef CONFIG_ARM_64
> +    for ( irq = NR_GIC_LPI; irq < MAX_LPI; irq++ )
> +    {
> +        struct irq_desc *desc = irq_to_desc(irq);
> +        init_one_irq_desc(desc);
> +        desc->irq = irq;
> +        desc->action  = NULL;
> +    }
> +#endif
>      return 0;
>  }
>  
> @@ -208,7 +226,7 @@ int request_irq(unsigned int irq, unsigned int irqflags,
>       * which interrupt is which (messes up the interrupt freeing
>       * logic etc).
>       */
> -    if ( irq >= nr_irqs )
> +    if ( irq >= nr_irqs && !is_lpi(irq) )
>          return -EINVAL;
>      if ( !handler )
>          return -EINVAL;
> @@ -267,9 +285,14 @@ void do_IRQ(struct cpu_user_regs *regs, unsigned int 
> irq, int is_fiq)
>          set_bit(_IRQ_INPROGRESS, &desc->status);
>          desc->arch.eoi_cpu = smp_processor_id();
>  
> +#ifdef CONFIG_ARM_64
> +        if ( is_lpi(irq) )
> +            vgic_vcpu_inject_lpi(info->d, irq);
> +        else
> +#endif
>          /* the irq cannot be a PPI, we only support delivery of SPIs to
>           * guests */
> -        vgic_vcpu_inject_spi(info->d, info->virq);
> +            vgic_vcpu_inject_spi(info->d, info->virq);
>          goto out_no_end;
>      }
>  
> @@ -436,7 +459,8 @@ err:
>  bool_t is_assignable_irq(unsigned int irq)
>  {
>      /* For now, we can only route SPIs to the guest */
> -    return ((irq >= NR_LOCAL_IRQS) && (irq < gic_number_lines()));
> +    return (((irq >= NR_LOCAL_IRQS) && (irq < gic_number_lines())) ||
> +              is_lpi(irq));
>  }
>  
>  /*
> @@ -452,7 +476,7 @@ int route_irq_to_guest(struct domain *d, unsigned int 
> virq,
>      unsigned long flags;
>      int retval = 0;
>  
> -    if ( virq >= vgic_num_irqs(d) )
> +    if ( virq >= vgic_num_irqs(d) && !is_lpi(irq) )
>      {
>          printk(XENLOG_G_ERR
>                 "the vIRQ number %u is too high for domain %u (max = %u)\n",
> @@ -460,10 +484,10 @@ int route_irq_to_guest(struct domain *d, unsigned int 
> virq,
>          return -EINVAL;
>      }
>  
> -    /* Only routing to virtual SPIs is supported */
> +    /* Only routing to virtual SPIs/LPIs is supported */
>      if ( virq < NR_LOCAL_IRQS )
>      {
> -        printk(XENLOG_G_ERR "IRQ can only be routed to an SPI\n");
> +        printk(XENLOG_G_ERR "IRQ can only be routed to an SPI/LPI\n");
>          return -EINVAL;
>      }
>  
> @@ -537,8 +561,10 @@ int route_irq_to_guest(struct domain *d, unsigned int 
> virq,
>      retval = __setup_irq(desc, 0, action);
>      if ( retval )
>          goto out;
> -
> -    retval = gic_route_irq_to_guest(d, virq, desc, GIC_PRI_IRQ);
> +    if ( is_lpi(irq) )
> +        retval = gic_route_lpi_to_guest(d, virq, desc, GIC_PRI_IRQ);
> +    else
> +        retval = gic_route_irq_to_guest(d, virq, desc, GIC_PRI_IRQ);
>  
>      spin_unlock_irqrestore(&desc->lock, flags);
>  
> diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c
> index bbcc7bb..4649b07 100644
> --- a/xen/arch/arm/vgic-v3-its.c
> +++ b/xen/arch/arm/vgic-v3-its.c
> @@ -625,6 +625,15 @@ err:
>      return 0;
>  }
>  
> +uint8_t vgic_its_get_priority(struct vcpu *v, uint32_t pid)
> +{
> +    uint8_t priority;
> +
> +    priority =  readb_relaxed(v->domain->arch.vits->prop_page + pid);
> +    priority &= LPI_PRIORITY_MASK;
> +
> +    return priority;
> +}
>  static int vgic_v3_gits_lpi_mmio_read(struct vcpu *v, mmio_info_t *info)
>  {
>      uint32_t offset;
> diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
> index 25b69a0..4e14439 100644
> --- a/xen/arch/arm/vgic-v3.c
> +++ b/xen/arch/arm/vgic-v3.c
> @@ -1111,12 +1111,19 @@ static const struct mmio_handler_ops 
> vgic_distr_mmio_handler = {
>  
>  static int vgic_v3_get_irq_priority(struct vcpu *v, unsigned int irq)
>  {
> -    int priority;
> -    struct vgic_irq_rank *rank = vgic_rank_irq(v, irq);
> +    int priority = 0;
> +    struct vgic_irq_rank *rank;
>  
> -    ASSERT(spin_is_locked(&rank->lock));
> -    priority = vgic_byte_read(rank->ipriority[REG_RANK_INDEX(8,
> +    if ( !is_lpi(irq) )
> +    {
> +        rank = vgic_rank_irq(v, irq);
> +
> +        ASSERT(spin_is_locked(&rank->lock));
> +        priority = vgic_byte_read(rank->ipriority[REG_RANK_INDEX(8,
>                                                irq, DABT_WORD)], 0, irq & 
> 0x3);
> +    }
> +    if ( is_lpi(irq) && gic_lpi_supported() )
> +        priority = vgic_its_get_priority(v, irq);
>  
>      return priority;
>  }
> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> index a5f66f6..8190a46 100644
> --- a/xen/arch/arm/vgic.c
> +++ b/xen/arch/arm/vgic.c
> @@ -30,6 +30,7 @@
>  
>  #include <asm/mmio.h>
>  #include <asm/gic.h>
> +#include <asm/gic-its.h>
>  #include <asm/vgic.h>
>  
>  static inline struct vgic_irq_rank *vgic_get_rank(struct vcpu *v, int rank)
> @@ -111,6 +112,15 @@ int domain_vgic_init(struct domain *d, unsigned int 
> nr_spis)
>      for (i=0; i<d->arch.vgic.nr_spis; i++)
>          vgic_init_pending_irq(&d->arch.vgic.pending_irqs[i], i + 32);
>  
> +#ifdef CONFIG_ARM_64
> +    d->arch.vgic.pending_lpis = xzalloc_array(struct pending_irq, 
> NR_GIC_LPI);
> +    if ( d->arch.vgic.pending_lpis == NULL )
> +        return -ENOMEM;
> +
> +    for ( i = 0; i < NR_GIC_LPI; i++ )
> +        vgic_init_pending_irq(&d->arch.vgic.pending_lpis[i], i);
> +#endif
> +
>      for (i=0; i<DOMAIN_NR_RANKS(d); i++)
>          spin_lock_init(&d->arch.vgic.shared_irqs[i].lock);
>  
> @@ -157,6 +167,7 @@ void domain_vgic_free(struct domain *d)
>  #ifdef CONFIG_ARM_64
>      free_xenheap_pages(d->arch.vits->prop_page,
>                         get_order_from_bytes(d->arch.vits->prop_size));
> +    xfree(d->arch.vgic.pending_lpis);
>  #endif
>  }
>  
> @@ -381,13 +392,17 @@ int vgic_to_sgi(struct vcpu *v, register_t sgir, enum 
> gic_sgi_mode irqmode, int
>  
>  struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq)
>  {
> -    struct pending_irq *n;
> +    struct pending_irq *n = NULL;
>      /* Pending irqs allocation strategy: the first vgic.nr_spis irqs
>       * are used for SPIs; the rests are used for per cpu irqs */
>      if ( irq < 32 )
>          n = &v->arch.vgic.pending_irqs[irq];
> -    else
> +    else if ( irq < NR_IRQS )
>          n = &v->domain->arch.vgic.pending_irqs[irq - 32];
> +#ifdef CONFIG_ARM_64
> +    else if ( is_lpi(irq) )
> +        n = &v->domain->arch.vgic.pending_lpis[irq - FIRST_GIC_LPI];
> +#endif
>      return n;
>  }
>  
> @@ -413,14 +428,20 @@ void vgic_clear_pending_irqs(struct vcpu *v)
>  void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int virq)
>  {
>      uint8_t priority;
> -    struct vgic_irq_rank *rank = vgic_rank_irq(v, virq);
> +    struct vgic_irq_rank *rank;
>      struct pending_irq *iter, *n = irq_to_pending(v, virq);
>      unsigned long flags;
>      bool_t running;
>  
> -    vgic_lock_rank(v, rank, flags);
> -    priority = v->domain->arch.vgic.handler->get_irq_priority(v, virq);
> -    vgic_unlock_rank(v, rank, flags);
> +    if ( virq < NR_GIC_LPI )
> +    {
> +        rank = vgic_rank_irq(v, virq);
> +        vgic_lock_rank(v, rank, flags);
> +        priority = v->domain->arch.vgic.handler->get_irq_priority(v, virq);
> +        vgic_unlock_rank(v, rank, flags);
> +    }
> +    else
> +        priority = v->domain->arch.vgic.handler->get_irq_priority(v, virq);
>  
>      spin_lock_irqsave(&v->arch.vgic.lock, flags);
>  

_______________________________________________
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®.