From: Julien Grall <julien.grall@citrix.com>
To: Stefano Stabellini <stefano.stabellini@eu.citrix.com>,
xen-devel@lists.xensource.com
Cc: ian.campbell@citrix.com
Subject: Re: [PATCH] xen/arm: implement GICD_ICACTIVER read/write
Date: Mon, 30 Nov 2015 12:35:16 +0000 [thread overview]
Message-ID: <565C4284.7090004@citrix.com> (raw)
In-Reply-To: <1448469640-27663-1-git-send-email-stefano.stabellini@eu.citrix.com>
Hi Stefano,
On 25/11/15 16: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.
Is it acceptable? The guest may rely on it to save the active state of
an IRQ.
> 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.
I would explain that the write bits of GICD_IACTIVER is left unimplemented.
> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> ---
> 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);
You also have to handle the deactivation of an hardware IRQ route to a
guest.
> + }
> +
> 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 */
Please add an ASSERT in the code to check this assumption.
> +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) )
I think this can be simplified by testing p->lr == GIC_INVALID_LR
> + {
> + 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);
Why do you need to unblock the vCPU?
> + 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;
> + }
Rather than duplicating the code twice (vgic-v2 and vgic-v3), could you
create a stub function to fetch the value. See vgic_fetch_itargetsr for
instance.
> + 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++;
> + }
Ditto.
> + 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;
Regards,
--
Julien Grall
next prev parent reply other threads:[~2015-11-30 12:35 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-11-25 16:40 [PATCH] xen/arm: implement GICD_ICACTIVER read/write Stefano Stabellini
2015-11-26 1:40 ` Shannon Zhao
2015-11-30 12:35 ` Julien Grall [this message]
2015-11-30 13:59 ` Julien Grall
2015-12-03 10:48 ` Stefano Stabellini
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=565C4284.7090004@citrix.com \
--to=julien.grall@citrix.com \
--cc=ian.campbell@citrix.com \
--cc=stefano.stabellini@eu.citrix.com \
--cc=xen-devel@lists.xensource.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.