From mboxrd@z Thu Jan 1 00:00:00 1970 From: vijay.kilari@gmail.com Subject: [PATCH v5 16/22] xen/arm: ITS: Route LPIs Date: Mon, 27 Jul 2015 16:41:58 +0530 Message-ID: <1437995524-19772-17-git-send-email-vijay.kilari@gmail.com> References: <1437995524-19772-1-git-send-email-vijay.kilari@gmail.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1437995524-19772-1-git-send-email-vijay.kilari@gmail.com> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: Ian.Campbell@citrix.com, julien.grall@citrix.com, stefano.stabellini@eu.citrix.com, stefano.stabellini@citrix.com, tim@xen.org, xen-devel@lists.xen.org Cc: Prasun.Kapoor@caviumnetworks.com, manish.jaggi@caviumnetworks.com, Vijaya Kumar K , vijay.kilari@gmail.com List-Id: xen-devel@lists.xenproject.org From: Vijaya Kumar K Allocate and initialize irq descriptor for LPIs and route LPIs to guest Signed-off-by: Vijaya Kumar K --- xen/arch/arm/gic-v3-its.c | 20 +++++++ xen/arch/arm/gic-v3.c | 17 +++++- xen/arch/arm/gic.c | 38 ++++++++++++- xen/arch/arm/irq.c | 126 ++++++++++++++++++++++++++++++++++++++--- xen/arch/arm/vgic-v2.c | 5 +- xen/arch/arm/vgic-v3-its.c | 22 ++++++- xen/arch/arm/vgic-v3.c | 17 ++++-- xen/arch/arm/vgic.c | 72 ++++++++++++++++++++++- xen/include/asm-arm/gic-its.h | 10 ++++ xen/include/asm-arm/gic.h | 11 +++- xen/include/asm-arm/irq.h | 2 + xen/include/asm-arm/vgic.h | 2 + 12 files changed, 319 insertions(+), 23 deletions(-) diff --git a/xen/arch/arm/gic-v3-its.c b/xen/arch/arm/gic-v3-its.c index 5ffd52f..0d8582a 100644 --- a/xen/arch/arm/gic-v3-its.c +++ b/xen/arch/arm/gic-v3-its.c @@ -110,6 +110,11 @@ void dump_cmd(its_cmd_block *cmd) void dump_cmd(its_cmd_block *cmd) { do {} while ( 0 ); } #endif +u32 its_get_nr_event_ids(void) +{ + return (1 << its_data.eventid_bits); +} + /* RB-tree helpers for its_device */ struct its_device *its_find_device(u32 devid) { @@ -415,6 +420,21 @@ static void its_flush_and_invalidate_prop(struct irq_desc *desc, u8 *cfg) its_send_inv(its_dev, col, vid); } +void its_set_lpi_properties(struct irq_desc *desc, + const cpumask_t *cpu_mask, + unsigned int priority) +{ + unsigned long flags; + u8 *cfg; + + spin_lock_irqsave(&its_lock, flags); + cfg = gic_rdists->prop_page + desc->irq - FIRST_GIC_LPI; + *cfg = (*cfg & 3) | (priority & LPI_PRIORITY_MASK) ; + + its_flush_and_invalidate_prop(desc, cfg); + spin_unlock_irqrestore(&its_lock, flags); +} + static void its_set_lpi_state(struct irq_desc *desc, int enable) { u8 *cfg; diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c index 58e878e..8c7c5cf 100644 --- a/xen/arch/arm/gic-v3.c +++ b/xen/arch/arm/gic-v3.c @@ -535,6 +535,16 @@ static void gicv3_set_irq_properties(struct irq_desc *desc, spin_unlock(&gicv3.lock); } +static void gicv3_set_properties(struct irq_desc *desc, + const cpumask_t *cpu_mask, + unsigned int priority) +{ + if ( gic_is_lpi(desc->irq) ) + its_set_lpi_properties(desc, cpu_mask, priority); + else + gicv3_set_irq_properties(desc, cpu_mask, priority); +} + static void __init gicv3_dist_init(void) { uint32_t type; @@ -912,7 +922,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 && !(gic_is_lpi(p->irq)) ) val |= GICH_LR_HW | (((uint64_t)p->desc->irq & GICH_LR_PHYSICAL_MASK) << GICH_LR_PHYSICAL_SHIFT); @@ -1312,7 +1322,10 @@ static int __init gicv3_init(void) spin_lock(&gicv3.lock); if ( gicv3_dist_supports_lpis() ) + { gicv3_info.lpi_supported = 1; + gicv3_info.nr_event_ids = its_get_nr_event_ids(); + } else gicv3_info.lpi_supported = 0; @@ -1336,7 +1349,7 @@ static const struct gic_hw_operations gicv3_ops = { .eoi_irq = gicv3_eoi_irq, .deactivate_irq = gicv3_dir_irq, .read_irq = gicv3_read_irq, - .set_irq_properties = gicv3_set_irq_properties, + .set_irq_properties = gicv3_set_properties, .send_SGI = gicv3_send_sgi, .disable_interface = gicv3_disable_interface, .update_lr = gicv3_update_lr, diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index 092087d..f6be0e9 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -33,6 +33,7 @@ #include #include #include +#include #include static void gic_restore_pending_irqs(struct vcpu *v); @@ -67,11 +68,23 @@ bool_t gic_is_lpi(unsigned int irq) return gic_hw_ops->is_lpi(irq); } +/* Returns number of 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) || gic_is_lpi(irq)); +} + +unsigned int gic_nr_event_ids(void) +{ + return gic_hw_ops->info->nr_event_ids; +} + bool_t gic_lpi_supported(void) { return gic_hw_ops->info->lpi_supported; @@ -134,7 +147,8 @@ 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(gic_is_valid_irq(desc->irq)); ASSERT(test_bit(_IRQ_DISABLED, &desc->status)); ASSERT(spin_is_locked(&desc->lock)); @@ -183,6 +197,24 @@ out: return res; } +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)); + ASSERT(virq < gic_nr_event_ids()); + + desc->handler = get_guest_hw_irq_controller(desc->irq); + set_bit(_IRQ_GUEST, &desc->status); + + /* Set cpumask to current processor */ + gic_set_irq_properties(desc, cpumask_of(smp_processor_id()), priority); + + /* Enable LPI by default? */ + desc->handler->enable(desc); + + return 0; +} + /* This function only works with SPIs for now */ int gic_remove_irq_from_guest(struct domain *d, unsigned int virq, struct irq_desc *desc) @@ -440,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 || gic_is_lpi(irq) ) { lr_val.state |= GICH_LR_PENDING; gic_hw_ops->write_lr(i, &lr_val); @@ -663,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)) || likely(gic_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 ccbe088..ae301a4 100644 --- a/xen/arch/arm/irq.c +++ b/xen/arch/arm/irq.c @@ -26,6 +26,7 @@ #include #include +#include #include static unsigned int local_irqs_type[NR_LOCAL_IRQS]; @@ -221,7 +222,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 ( !gic_is_valid_irq(irq) ) return -EINVAL; if ( !handler ) return -EINVAL; @@ -279,11 +280,28 @@ void do_IRQ(struct cpu_user_regs *regs, unsigned int irq, int is_fiq) set_bit(_IRQ_INPROGRESS, &desc->status); - /* - * The irq cannot be a PPI, we only support delivery of SPIs to - * guests. - */ - vgic_vcpu_inject_spi(info->d, info->virq); +#ifdef HAS_GICV3 + if ( gic_is_lpi(irq) ) + { + struct its_device *dev = get_irq_its_device(desc); + unsigned int vdevid = dev->virt_device_id; + unsigned int eventID = irq_to_vid(desc); + + if ( info->d->domain_id != dev->domain_id) + { + printk("LPI %"PRId32" not assigned to domain.. dropping \n", + irq); + goto out_no_end; + } + vgic_vcpu_inject_lpi(info->d, vdevid, eventID); + } + else +#endif + /* + * The irq cannot be a PPI, we only support delivery of SPIs to + * guests + */ + vgic_vcpu_inject_spi(info->d, info->virq); goto out_no_end; } @@ -449,10 +467,102 @@ 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())); + /* For now, we can only route SPI/LPIs to the guest */ + return (((irq >= NR_LOCAL_IRQS) && (irq < gic_number_lines())) || + gic_is_lpi(irq)); } +#ifdef HAS_GICV3 +/* + * Route an LPI to a specific guest. + */ +int route_lpi_to_guest(struct domain *d, unsigned int vid, + unsigned int irq, const char *devname) +{ + struct irqaction *action; + struct irq_guest *info; + struct irq_desc *desc; + unsigned long flags; + int retval = 0; + + if ( !gic_is_lpi(irq) ) + { + printk(XENLOG_G_ERR "Only LPI can be routed \n"); + return -EINVAL; + } + + action = xmalloc(struct irqaction); + if ( !action ) + return -ENOMEM; + + info = xmalloc(struct irq_guest); + if ( !info ) + { + xfree(action); + return -ENOMEM; + } + info->d = d; + + action->dev_id = info; + action->name = devname; + action->free_on_release = 1; + + desc = irq_to_desc(irq); + spin_lock_irqsave(&desc->lock, flags); + + ASSERT(desc->msi_desc != NULL); + desc->msi_desc->eventID = vid; + if ( desc->arch.type == DT_IRQ_TYPE_INVALID ) + { + printk(XENLOG_G_ERR "LPI %u has not been configured\n", irq); + retval = -EIO; + goto out; + } + + /* + * If the IRQ is already used by by same domain + */ + if ( desc->action != NULL ) + { + struct domain *ad = irq_get_domain(desc); + + if ( test_bit(_IRQ_GUEST, &desc->status) && d == ad ) + { + printk(XENLOG_G_ERR + "d%u: vID %u is already assigned to domain %u\n", + d->domain_id, irq, d->domain_id); + retval = -EBUSY; + goto out; + } + } + + retval = __setup_irq(desc, 0, action); + if ( retval ) + goto out; + + retval = gic_route_lpi_to_guest(d, vid, desc, GIC_PRI_IRQ); + + spin_unlock_irqrestore(&desc->lock, flags); + + if ( retval ) + { + /* TODO: for LPI */ + release_irq(desc->irq, info); + goto free_info; + } + + return 0; + +out: + spin_unlock_irqrestore(&desc->lock, flags); + xfree(action); +free_info: + xfree(info); + + return retval; +} +#endif + /* * Route an IRQ to a specific guest. * For now only SPIs are assignable to the guest. diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c index 524787b..4517a62 100644 --- a/xen/arch/arm/vgic-v2.c +++ b/xen/arch/arm/vgic-v2.c @@ -520,11 +520,14 @@ static int vgic_v2_get_irq_priority(struct vcpu *v, unsigned int irq) { int priority; struct vgic_irq_rank *rank = vgic_rank_irq(v, irq); + unsigned long flags; - ASSERT(spin_is_locked(&rank->lock)); + vgic_lock_rank(v, rank, flags); priority = vgic_byte_read(rank->ipriority[REG_RANK_INDEX(8, irq, DABT_WORD)], 0, irq & 0x3); + vgic_lock_rank(v, rank, flags); + return priority; } diff --git a/xen/arch/arm/vgic-v3-its.c b/xen/arch/arm/vgic-v3-its.c index b8f32ed..5323192 100644 --- a/xen/arch/arm/vgic-v3-its.c +++ b/xen/arch/arm/vgic-v3-its.c @@ -75,6 +75,11 @@ bool_t is_domain_lpi(struct domain *d, unsigned int lpi) (lpi < (d->arch.vgic.nr_lpis + FIRST_GIC_LPI))); } +bool_t is_valid_collection(struct domain *d, uint32_t col) +{ + return (col <= (d->max_vcpus + 1)); +} + static inline uint32_t vits_get_max_collections(struct domain *d) { /* Collection ID is only 16 bit */ @@ -371,7 +376,7 @@ static int vits_process_int(struct vcpu *v, struct vgic_its *vits, DPRINTK("%pv: vITS: INT: Device 0x%"PRIx32" id %"PRId32"\n", v, dev_id, event); - /* TODO: Inject LPI */ + vgic_vcpu_inject_lpi(v->domain, dev_id, event); return 0; } @@ -586,6 +591,21 @@ static inline uint32_t vits_get_word(uint32_t reg_offset, uint64_t val) return (u32)(val >> 32); } +uint8_t vits_get_priority(struct vcpu *v, uint32_t vlpi) +{ + struct vgic_its *vits = v->domain->arch.vgic.vits; + uint8_t priority; + + ASSERT(vlpi < vits->prop_size); + + spin_lock(&vits->prop_lock); + priority = *((u8*)vits->prop_page + vlpi); + priority &= LPI_PRIORITY_MASK; + spin_unlock(&vits->prop_lock); + + 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 a466a8f..9e6e3ff 100644 --- a/xen/arch/arm/vgic-v3.c +++ b/xen/arch/arm/vgic-v3.c @@ -1140,12 +1140,21 @@ 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; + unsigned long flags; - ASSERT(spin_is_locked(&rank->lock)); - priority = vgic_byte_read(rank->ipriority[REG_RANK_INDEX(8, + if ( !gic_is_lpi(irq) ) + { + rank = vgic_rank_irq(v, irq); + + vgic_lock_rank(v, rank, flags); + priority = vgic_byte_read(rank->ipriority[REG_RANK_INDEX(8, irq, DABT_WORD)], 0, irq & 0x3); + vgic_unlock_rank(v, rank, flags); + } + else if ( gic_lpi_supported() && is_domain_lpi(v->domain, irq) ) + priority = vits_get_priority(v, irq); return priority; } diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index ab5e81b..57c0f52 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -33,6 +33,12 @@ #include #include +static inline bool_t is_domains_lpi(struct domain *d, unsigned int irq) +{ + return ((irq > FIRST_GIC_LPI) && + (irq < (d->arch.vgic.nr_lpis + FIRST_GIC_LPI))); +} + static inline struct vgic_irq_rank *vgic_get_rank(struct vcpu *v, int rank) { if ( rank == 0 ) @@ -414,14 +420,11 @@ 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 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); spin_lock_irqsave(&v->arch.vgic.lock, flags); @@ -478,6 +481,69 @@ void vgic_vcpu_inject_spi(struct domain *d, unsigned int virq) vgic_vcpu_inject_irq(v, virq); } +#ifdef HAS_GICV3 +void vgic_vcpu_inject_lpi(struct domain *d, unsigned int vdevid, + unsigned int eventID) +{ + struct vdevice_table dt_entry; + struct vitt vitt_entry; + uint32_t col_id, target; + + if ( eventID > gic_nr_event_ids() ) + { + dprintk(XENLOG_WARNING, + "Invalid eventID %"PRId32" ..dropping\n", vdevid); + return; + } + + if ( vits_get_vdevice_entry(d, vdevid, &dt_entry) ) + { + dprintk(XENLOG_WARNING, + "Failed to read dt entry for dev 0x%"PRIx32" ..dropping\n", + vdevid); + return; + } + + if ( dt_entry.vitt_ipa == INVALID_PADDR ) + { + dprintk(XENLOG_WARNING, + "Event %"PRId32" of dev 0x%"PRIx32" is invalid..dropping\n", + eventID, vdevid); + return; + } + + if ( vits_get_vitt_entry(d, vdevid, eventID, &vitt_entry) ) + { + dprintk(XENLOG_WARNING, + "Event %"PRId32" of dev 0x%"PRIx32" is invalid..dropping\n", + eventID, vdevid); + return; + } + + col_id = vitt_entry.vcollection; + + if ( !vitt_entry.valid || !is_valid_collection(d, col_id) || + !is_domain_lpi(d, vitt_entry.vlpi) ) + { + dprintk(XENLOG_WARNING, + "vlpi %"PRId32" for dev 0x%"PRIx32" is not valid..dropping\n", + vitt_entry.vlpi, vdevid); + return; + } + + target = d->arch.vgic.vits->collections[col_id].target_address; + if ( target > d->max_vcpus ) + { + dprintk(XENLOG_WARNING, + "vlpi %"PRId32" got invalid target %"PRId32" dev 0x%"PRIx32"\n", + vitt_entry.vlpi, target, vdevid); + return; + } + + vgic_vcpu_inject_irq(d->vcpu[target], 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/gic-its.h b/xen/include/asm-arm/gic-its.h index 110516a..870c9a8 100644 --- a/xen/include/asm-arm/gic-its.h +++ b/xen/include/asm-arm/gic-its.h @@ -315,6 +315,10 @@ struct its_device { u32 nr_lpis; /* Physical Device id */ u32 device_id; + /* Virtual Device id */ + u32 virt_device_id; + /* Domain id */ + int domain_id; /* RB-tree entry */ struct rb_node node; }; @@ -353,17 +357,23 @@ struct gic_its_info { struct its_node_info *its_hw; }; +bool_t is_valid_collection(struct domain *d, uint32_t col); bool_t is_domain_lpi(struct domain *d, unsigned int lpi); hw_irq_controller *its_get_host_lpi_type(void); hw_irq_controller *its_get_guest_lpi_type(void); +u32 its_get_nr_event_ids(void); int its_init(struct rdist_prop *rdists); int its_cpu_init(void); +void its_set_lpi_properties(struct irq_desc *desc, + const cpumask_t *cpu_mask, + unsigned int priority); 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); void vits_setup_hw(struct gic_its_info *info); int vits_map_lpi_prop(struct domain *d); +uint8_t vits_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 2edf9de..15bd6eb 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,12 @@ 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 (PPIs + SGIs + SPIs)*/ extern unsigned int gic_number_lines(void); +/* Check if irq is valid */ +bool_t gic_is_valid_irq(unsigned int irq); +/* Number of event ids supported */ +extern unsigned int gic_nr_event_ids(void); /* LPI support info */ bool_t gic_lpi_supported(void); @@ -307,6 +314,8 @@ struct gic_info { const struct dt_device_node *node; /* Number of IRQ ID bits supported */ uint32_t nr_id_bits; + /* Number of Event IDs supported */ + uint32_t nr_event_ids; /* LPIs are support information */ bool_t lpi_supported; }; diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h index 5923127..00d5345 100644 --- a/xen/include/asm-arm/irq.h +++ b/xen/include/asm-arm/irq.h @@ -49,6 +49,8 @@ bool_t is_assignable_irq(unsigned int irq); void init_IRQ(void); void init_secondary_IRQ(void); +int route_lpi_to_guest(struct domain *d, unsigned int vid, + unsigned int irq, const char *devname); int route_irq_to_guest(struct domain *d, unsigned int virq, unsigned int irq, const char *devname); int release_guest_irq(struct domain *d, unsigned int irq); diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index 41cadb1..b11faa0 100644 --- a/xen/include/asm-arm/vgic.h +++ b/xen/include/asm-arm/vgic.h @@ -196,6 +196,8 @@ 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 devid, + unsigned int eventID); 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