|
[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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |