[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v4 12/17] xen/arm: ITS: Initialize LPI irq descriptors and route
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)); +} + 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); @@ -477,6 +498,83 @@ void vgic_vcpu_inject_spi(struct domain *d, unsigned int virq) vgic_vcpu_inject_irq(v, virq); } +#ifdef CONFIG_ARM_64 +void vgic_vcpu_inject_lpi(struct domain *d, unsigned int irq) +{ + struct irq_desc *desc; + struct pending_irq *p; + struct its_device *dev; + struct vits_device *vdev; + struct vdevice_table dt_entry; + struct vitt vitt_entry; + uint32_t devid, col_id; + int event; + + desc = irq_to_desc(irq); + event = irq_to_virq(desc); + + dev = get_irq_device(desc); + devid = dev->virt_device_id; + event = irq - dev->lpi_base; + if ( (event < 0 && event > dev->nr_lpis) || + (dev->domain_id != d->domain_id) ) + { + dprintk(XENLOG_WARNING, + "LPI %d received for dev 0x%x is not assigned..dropping\n", + irq, devid); + return; + } + + vdev = vits_find_device(&d->arch.vits->dev_root, devid); + if ( !vdev ) + { + dprintk(XENLOG_WARNING, + "LPI %d received for dev 0x%x not assigned..dropping\n", + irq, devid); + return; + } + + if ( vits_get_vdevice_entry(d, devid, &dt_entry) ) + { + dprintk(XENLOG_WARNING, + "Failed to read device table entry for dev 0x%x ..dropping\n", + devid); + return; + } + if ( dt_entry.vitt_ipa == INVALID_PADDR ) + { + dprintk(XENLOG_WARNING, + "LPI %d received for dev 0x%x which is disabled..dropping\n", + irq, devid); + return; + } + + if ( vits_get_vitt_entry(d, devid, event, &vitt_entry) ) + { + dprintk(XENLOG_WARNING, + "LPI %d received for dev 0x%x with invalid entry..dropping\n", + irq, devid); + return; + } + + col_id = vitt_entry.vcollection; + + if ( !vitt_entry.valid || col_id > d->max_vcpus || + vitt_entry.vlpi > its_get_nr_events() ) + { + dprintk(XENLOG_WARNING, + "LPI %d received for dev 0x%x is not valid..dropping\n", + irq, devid); + return; + } + + p = irq_to_pending(d->vcpu[0], vitt_entry.vlpi); + p->desc = desc; + + vgic_vcpu_inject_irq(d->vcpu[col_id], vitt_entry.vlpi); +} +#endif + void arch_evtchn_inject(struct vcpu *v) { vgic_vcpu_inject_irq(v, v->domain->arch.evtchn_irq); diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h index 49db7f0..a4bf8f6 100644 --- a/xen/include/asm-arm/domain.h +++ b/xen/include/asm-arm/domain.h @@ -98,6 +98,9 @@ struct arch_domain * struct arch_vcpu. */ struct pending_irq *pending_irqs; +#ifdef CONFIG_ARM_64 + struct pending_irq *pending_lpis; +#endif /* Base address for guest GIC */ paddr_t dbase; /* Distributor base address */ paddr_t cbase; /* CPU base address */ diff --git a/xen/include/asm-arm/gic-its.h b/xen/include/asm-arm/gic-its.h index a79b70f..fbed905 100644 --- a/xen/include/asm-arm/gic-its.h +++ b/xen/include/asm-arm/gic-its.h @@ -277,6 +277,7 @@ struct vits_device *vits_find_device(struct rb_root *root, uint32_t devid); int vits_insert_device(struct rb_root *root, struct vits_device *dev); void vits_remove_device(struct rb_root *root, struct vits_device *dev); int vits_unmap_lpi_prop(struct vcpu *v); +uint8_t vgic_its_get_priority(struct vcpu *v, uint32_t pid); #endif /* __ASM_ARM_GIC_ITS_H__ */ /* diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h index 69bf1ff..537ed3d 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -226,6 +226,9 @@ extern void gic_route_irq_to_xen(struct irq_desc *desc, const cpumask_t *cpu_mas extern int gic_route_irq_to_guest(struct domain *, unsigned int virq, struct irq_desc *desc, unsigned int priority); +extern int gic_route_lpi_to_guest(struct domain *d, unsigned int virq, + struct irq_desc *desc, + unsigned int priority); /* Remove an IRQ passthrough to a guest */ int gic_remove_irq_from_guest(struct domain *d, unsigned int virq, @@ -282,8 +285,10 @@ extern void send_SGI_allbutself(enum gic_sgi sgi); /* print useful debug info */ extern void gic_dump_info(struct vcpu *v); -/* Number of interrupt lines */ +/* Number of interrupt lines (SPIs)*/ extern unsigned int gic_number_lines(void); +/* Check if irq is valid SPI or LPI */ +bool_t gic_is_valid_irq(unsigned int irq); /* Number of interrupt id bits supported */ extern unsigned int gic_nr_id_bits(void); /* LPI support info */ diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index 8d22532..f8928ab 100644 --- a/xen/include/asm-arm/vgic.h +++ b/xen/include/asm-arm/vgic.h @@ -183,6 +183,7 @@ extern int vcpu_vgic_init(struct vcpu *v); extern struct vcpu *vgic_get_target_vcpu(struct vcpu *v, unsigned int irq); extern void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int virq); extern void vgic_vcpu_inject_spi(struct domain *d, unsigned int virq); +extern void vgic_vcpu_inject_lpi(struct domain *d, unsigned int virq); extern void vgic_clear_pending_irqs(struct vcpu *v); extern struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq); extern struct pending_irq *spi_to_pending(struct domain *d, unsigned int irq); -- 1.7.9.5 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |