|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC PATCH v3 13/18] xen/arm: ITS: Add irq descriptors for LPIs
From: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
Add irq descriptors for LPIs and route
Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
---
xen/arch/arm/gic-v3.c | 8 +++-
xen/arch/arm/gic.c | 17 +++++++-
xen/arch/arm/irq.c | 38 +++++++++++++----
xen/arch/arm/vgic-v3-its.c | 9 +++++
xen/arch/arm/vgic.c | 90 ++++++++++++++++++++++++++++++++++++++---
xen/include/asm-arm/domain.h | 2 +
xen/include/asm-arm/gic-its.h | 6 +++
xen/include/asm-arm/gic.h | 3 ++
xen/include/asm-arm/vgic.h | 1 +
9 files changed, 157 insertions(+), 17 deletions(-)
diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
index 737646c..793f2f0 100644
--- a/xen/arch/arm/gic-v3.c
+++ b/xen/arch/arm/gic-v3.c
@@ -899,9 +899,13 @@ static void gicv3_update_lr(int lr, const struct
pending_irq *p,
val = (((uint64_t)state & 0x3) << GICH_LR_STATE_SHIFT) | grp;
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 ( is_lpi(p->irq) )
+ val |= ((uint64_t)p->irq & GICH_LR_VIRTUAL_MASK) <<
GICH_LR_VIRTUAL_SHIFT;
+ else
+ val |= ((uint64_t)p->irq & GICH_LR_VIRTUAL_MASK) <<
GICH_LR_VIRTUAL_SHIFT;
+
+ 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 cfc9c42..091f7e5 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -124,18 +124,31 @@ void gic_route_irq_to_xen(struct irq_desc *desc, const
cpumask_t *cpu_mask,
unsigned int priority)
{
ASSERT(priority <= 0xff); /* Only 8 bits of priority */
- ASSERT(desc->irq < gic_number_lines());/* Can't route interrupts that
don't exist */
+ /* Can't route interrupts that don't exist */
+ ASSERT(desc->irq < gic_number_lines() && is_lpi(desc->irq));
ASSERT(test_bit(_IRQ_DISABLED, &desc->status));
ASSERT(spin_is_locked(&desc->lock));
desc->handler = gic_hw_ops->gic_host_irq_type;
- gic_set_irq_properties(desc, cpu_mask, priority);
+ if ( !is_lpi(desc->irq) )
+ gic_set_irq_properties(desc, cpu_mask, priority);
}
/* 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 = gic_hw_ops->gic_guest_irq_type;
+ 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)
{
diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index 9dbdf7d..105ef85 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -57,12 +57,22 @@ hw_irq_controller no_irq_type = {
};
static irq_desc_t irq_desc[NR_IRQS];
+static irq_desc_t irq_desc_lpi[MAX_NR_LPIS];
static DEFINE_PER_CPU(irq_desc_t[NR_LOCAL_IRQS], local_irq_desc);
irq_desc_t *__irq_to_desc(int irq)
{
+ struct irq_desc *desc = NULL;
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];
+ else
+ {
+ if ( is_lpi(irq) )
+ return &irq_desc_lpi[irq - NR_GIC_LPI];
+ }
+
+ return desc;
}
int __init arch_init_one_irq_desc(struct irq_desc *desc)
@@ -83,6 +93,13 @@ static int __init init_irq_data(void)
desc->action = NULL;
}
+ 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;
+ }
return 0;
}
@@ -178,7 +195,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;
@@ -237,9 +254,12 @@ 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();
+ if ( is_lpi(irq) )
+ vgic_vcpu_inject_lpi(info->d, irq);
+ else
/* 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;
}
@@ -405,6 +425,8 @@ err:
bool_t is_assignable_irq(unsigned int irq)
{
+ if ( is_lpi(irq) )
+ return 1;
/* For now, we can only route SPIs to the guest */
return ((irq >= NR_LOCAL_IRQS) && (irq < gic_number_lines()));
}
@@ -422,7 +444,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",
@@ -431,7 +453,7 @@ int route_irq_to_guest(struct domain *d, unsigned int virq,
}
/* Only routing to virtual SPIs is supported */
- if ( virq < NR_LOCAL_IRQS )
+ if ( virq < NR_LOCAL_IRQS && !is_lpi(irq) )
{
printk(XENLOG_G_ERR "IRQ can only be routed to an SPI\n");
return -EINVAL;
@@ -507,8 +529,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 fa9dccc..543db91 100644
--- a/xen/arch/arm/vgic-v3-its.c
+++ b/xen/arch/arm/vgic-v3-its.c
@@ -689,6 +689,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 &= 0xfc;
+
+ 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.c b/xen/arch/arm/vgic.c
index 73a6f7e..6074431 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,13 @@ 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);
+ d->arch.vgic.pending_lpis = xzalloc_array(struct pending_irq, MAX_NR_LPIS);
+ if ( d->arch.vgic.pending_lpis == NULL )
+ return -ENOMEM;
+
+ for ( i = 0; i < MAX_NR_LPIS; i++ )
+ vgic_init_pending_irq(&d->arch.vgic.pending_lpis[i], i);
+
for (i=0; i<DOMAIN_NR_RANKS(d); i++)
spin_lock_init(&d->arch.vgic.shared_irqs[i].lock);
@@ -377,13 +385,18 @@ 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];
+ else
+ {
+ if ( is_lpi(irq) )
+ n = &v->domain->arch.vgic.pending_lpis[irq - 8192];
+ }
return n;
}
@@ -409,14 +422,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 = vgic_its_get_priority(v, virq);
spin_lock_irqsave(&v->arch.vgic.lock, flags);
@@ -473,6 +492,65 @@ void vgic_vcpu_inject_spi(struct domain *d, unsigned int
virq)
vgic_vcpu_inject_irq(v, virq);
}
+void vgic_vcpu_inject_lpi(struct domain *d, unsigned int irq)
+{
+ struct irq_desc *desc;
+ struct pending_irq *p;
+ struct its_device *dev;
+ struct vitt vitt_entry;
+ struct vdevice_table dt_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->device_id;
+ event = irq - dev->lpi_base;
+ if ( event < 0 && event > dev->nr_lpis)
+ {
+ dprintk(XENLOG_WARNING,
+ "LPI %d received for dev 0x%x is not valid..dropping \n",
+ irq, devid);
+ return;
+ }
+
+ /* validity of device is checheck on vitt entry request */
+ vits_get_vdevice_entry(d, devid, &dt_entry);
+ 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 which is disabled..dropping \n",
+ irq, devid);
+ return;
+ }
+ if ( !vitt_entry.valid )
+ {
+ dprintk(XENLOG_WARNING,
+ "LPI %d received for dev 0x%x which is not valid..dropping \n",
+ irq, devid);
+ return;
+ }
+ p = irq_to_pending(d->vcpu[0], vitt_entry.vlpi);
+ col_id = vitt_entry.vcollection;
+
+ ASSERT(col_id < d->max_vcpus);
+
+ p->desc = desc;
+
+ vgic_vcpu_inject_irq(d->vcpu[col_id], vitt_entry.vlpi);
+}
+
+
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 db1d1db..06105cc 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -98,6 +98,8 @@ struct arch_domain
* struct arch_vcpu.
*/
struct pending_irq *pending_irqs;
+ struct pending_irq *pending_lpis;
+
/* 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 1de57a7..f34a207 100644
--- a/xen/include/asm-arm/gic-its.h
+++ b/xen/include/asm-arm/gic-its.h
@@ -276,11 +276,17 @@ static inline uint32_t its_decode_devid(struct domain *d,
its_cmd_block *cmd)
void its_set_affinity(struct irq_desc *desc, int cpu);
void lpi_set_config(struct irq_desc *desc, int enable);
+uint8_t vgic_its_get_priority(struct vcpu *v, uint32_t pid);
+
uint32_t its_get_nr_events(void);
int vgic_its_unmap_lpi_prop(struct vcpu *v);
struct vits_device * find_vits_device(struct rb_root *root, uint32_t devid);
int insert_vits_device(struct rb_root *root, struct vits_device *dev);
int remove_vits_device(struct rb_root *root, struct vits_device *dev);
+int vits_get_vitt_entry(struct domain *d, uint32_t devid,
+ uint32_t event, struct vitt *entry);
+int vits_get_vdevice_entry(struct domain *d, uint32_t devid,
+ struct vdevice_table *entry);
#endif /* __ASM_ARM_GIC_ITS_H__ */
/*
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index ee612de..9e94d65 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -225,6 +225,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,
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 |