From: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
To: xen-devel@lists.xensource.com
Cc: julien.grall@citrix.com, Ian.Campbell@citrix.com,
stefano.stabellini@eu.citrix.com
Subject: [PATCH v7 11/12] xen/arm: gic_events_need_delivery and irq priorities
Date: Tue, 8 Apr 2014 16:12:48 +0100 [thread overview]
Message-ID: <1396969969-18973-11-git-send-email-stefano.stabellini@eu.citrix.com> (raw)
In-Reply-To: <alpine.DEB.2.02.1404071131100.9060@kaball.uk.xensource.com>
gic_events_need_delivery should only return positive if an outstanding
pending irq has an higher priority than the currently active irq and the
priority mask.
Introduce GIC_IRQ_GUEST_ACTIVE to track which one is the currently
active guest irq.
Rewrite the function by going through the priority ordered inflight and
lr_queue lists.
In gic_restore_pending_irqs replace lower priority pending (and not
active) irqs in GICH_LRs with higher priority irqs if no more GICH_LRs
are available.
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
Changes in v7:
- fix locking for the list_empty case in gic_restore_pending_irqs;
- add in code comment;
- gic_events_need_delivery: break out of the loop as soon as we find the
active irq as inflight_irqs is ordered by priority;
- gic_events_need_delivery: break out of the loop if p->priority is
lower than mask_priority as inflight_irqs is ordered by priority;
- use find_next_zero_bit instead of find_first_zero_bit;
- in gic_restore_pending_irqs remember the last position of the inner
loop search and continue from there;
- in gic_restore_pending_irqs use a priority check to get out of the
inner loop.
Changes in v5:
- improve in code comments;
- use list_for_each_entry_reverse instead of writing my own list walker.
Changes in v4:
- in gic_events_need_delivery go through inflight_irqs and only consider
enabled irqs.
---
xen/arch/arm/gic.c | 84 ++++++++++++++++++++++++++++++++++++++----
xen/include/asm-arm/domain.h | 5 ++-
xen/include/asm-arm/gic.h | 3 ++
3 files changed, 82 insertions(+), 10 deletions(-)
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index e6e6f1a..9295ccf 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -721,6 +721,7 @@ static void gic_update_one_lr(struct vcpu *v, int i)
p = irq_to_pending(v, irq);
if ( lr & GICH_LR_ACTIVE )
{
+ set_bit(GIC_IRQ_GUEST_ACTIVE, &p->status);
/* HW interrupts cannot be ACTIVE and PENDING */
if ( p->desc == NULL &&
test_bit(GIC_IRQ_GUEST_ENABLED, &p->status) &&
@@ -735,6 +736,7 @@ static void gic_update_one_lr(struct vcpu *v, int i)
if ( p->desc != NULL )
p->desc->status &= ~IRQ_INPROGRESS;
clear_bit(GIC_IRQ_GUEST_VISIBLE, &p->status);
+ clear_bit(GIC_IRQ_GUEST_ACTIVE, &p->status);
p->lr = GIC_INVALID_LR;
if ( test_bit(GIC_IRQ_GUEST_QUEUED, &p->status) &&
test_bit(GIC_IRQ_GUEST_ENABLED, &p->status))
@@ -763,22 +765,53 @@ void gic_clear_lrs(struct vcpu *v)
static void gic_restore_pending_irqs(struct vcpu *v)
{
- int i;
- struct pending_irq *p, *t;
+ int i = 0, lrs = nr_lrs;
+ struct pending_irq *p, *t, *p_r;
+ struct list_head *inflight_r;
unsigned long flags;
+ spin_lock_irqsave(&v->arch.vgic.lock, flags);
+
+ if ( list_empty(&v->arch.vgic.lr_pending) )
+ goto out;
+
+ inflight_r = &v->arch.vgic.inflight_irqs;
list_for_each_entry_safe ( p, t, &v->arch.vgic.lr_pending, lr_queue )
{
- i = find_first_zero_bit(&this_cpu(lr_mask), nr_lrs);
- if ( i >= nr_lrs ) return;
+ i = find_next_zero_bit(&this_cpu(lr_mask), nr_lrs, i);
+ if ( i >= nr_lrs )
+ {
+ /* No more free LRs: find a lower priority irq to evict */
+ list_for_each_entry_reverse( p_r, inflight_r, inflight )
+ {
+ inflight_r = &p_r->inflight;
+ if ( p_r->priority == p->priority )
+ goto out;
+ if ( test_bit(GIC_IRQ_GUEST_VISIBLE, &p_r->status) &&
+ !test_bit(GIC_IRQ_GUEST_ACTIVE, &p_r->status) )
+ goto found;
+ }
+ goto out;
+
+found:
+ i = p_r->lr;
+ p_r->lr = GIC_INVALID_LR;
+ set_bit(GIC_IRQ_GUEST_QUEUED, &p_r->status);
+ clear_bit(GIC_IRQ_GUEST_VISIBLE, &p_r->status);
+ gic_add_to_lr_pending(v, p_r);
+ }
- spin_lock_irqsave(&v->arch.vgic.lock, flags);
gic_set_lr(i, p, GICH_LR_PENDING);
list_del_init(&p->lr_queue);
set_bit(i, &this_cpu(lr_mask));
- spin_unlock_irqrestore(&v->arch.vgic.lock, flags);
+
+ lrs--;
+ if ( lrs == 0 )
+ break;
}
+out:
+ spin_unlock_irqrestore(&v->arch.vgic.lock, flags);
}
void gic_clear_pending_irqs(struct vcpu *v)
@@ -794,8 +827,43 @@ void gic_clear_pending_irqs(struct vcpu *v)
int gic_events_need_delivery(void)
{
- return (!list_empty(¤t->arch.vgic.lr_pending) ||
- this_cpu(lr_mask));
+ int mask_priority, lrs = nr_lrs;
+ int max_priority = 0xff, active_priority = 0xff;
+ struct vcpu *v = current;
+ struct pending_irq *p;
+ unsigned long flags;
+
+ mask_priority = (GICH[GICH_VMCR] >> GICH_VMCR_PRIORITY_SHIFT) & GICH_VMCR_PRIORITY_MASK;
+
+ spin_lock_irqsave(&v->arch.vgic.lock, flags);
+
+ /* TODO: We order the guest irqs by priority, but we don't change
+ * the priority of host irqs. */
+ list_for_each_entry( p, &v->arch.vgic.inflight_irqs, inflight )
+ {
+ if ( test_bit(GIC_IRQ_GUEST_ACTIVE, &p->status) )
+ {
+ if ( p->priority < active_priority )
+ active_priority = p->priority;
+ break;
+ } else if ( test_bit(GIC_IRQ_GUEST_ENABLED, &p->status) ) {
+ if ( p->priority < max_priority )
+ max_priority = p->priority;
+ }
+ if ( (p->priority >> 3) >= mask_priority )
+ break;
+ lrs--;
+ if ( lrs == 0 )
+ break;
+ }
+
+ spin_unlock_irqrestore(&v->arch.vgic.lock, flags);
+
+ if ( max_priority < active_priority &&
+ (max_priority >> 3) < mask_priority )
+ return 1;
+ else
+ return 0;
}
void gic_inject(void)
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 71f563f..75cc2f3 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -56,8 +56,9 @@ struct pending_irq
*
*/
#define GIC_IRQ_GUEST_QUEUED 0
-#define GIC_IRQ_GUEST_VISIBLE 1
-#define GIC_IRQ_GUEST_ENABLED 2
+#define GIC_IRQ_GUEST_ACTIVE 1
+#define GIC_IRQ_GUEST_VISIBLE 2
+#define GIC_IRQ_GUEST_ENABLED 3
unsigned long status;
struct irq_desc *desc; /* only set it the irq corresponds to a physical irq */
int irq;
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 5a9dc77..5d8f7f1 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -129,6 +129,9 @@
#define GICH_LR_CPUID_SHIFT 9
#define GICH_VTR_NRLRGS 0x3f
+#define GICH_VMCR_PRIORITY_MASK 0x1f
+#define GICH_VMCR_PRIORITY_SHIFT 27
+
/*
* The minimum GICC_BPR is required to be in the range 0-3. We set
* GICC_BPR to 0 but we must expect that it might be 3. This means we
--
1.7.10.4
next prev parent reply other threads:[~2014-04-08 15:12 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-04-08 15:11 [PATCH v7 0/12] remove maintenance interrupts Stefano Stabellini
2014-04-08 15:12 ` [PATCH v7 01/12] xen/arm: no need to set HCR_VI when using the vgic to inject irqs Stefano Stabellini
2014-04-08 15:12 ` [PATCH v7 02/12] xen/arm: remove unused virtual parameter from vgic_vcpu_inject_irq Stefano Stabellini
2014-04-08 15:12 ` [PATCH v7 03/12] xen/arm: set GICH_HCR_UIE if all the LRs are in use Stefano Stabellini
2014-04-08 15:12 ` [PATCH v7 04/12] xen/arm: support HW interrupts, do not request maintenance_interrupts Stefano Stabellini
2014-04-23 12:45 ` Ian Campbell
2014-04-23 12:54 ` Ian Campbell
2014-04-08 15:12 ` [PATCH v7 05/12] xen/arm: nr_lrs should be uint8_t Stefano Stabellini
2014-04-23 12:47 ` Ian Campbell
2014-04-23 12:53 ` Julien Grall
2014-04-23 13:07 ` Ian Campbell
2014-04-23 13:13 ` Julien Grall
2014-04-08 15:12 ` [PATCH v7 06/12] xen/arm: keep track of the GICH_LR used for the irq in struct pending_irq Stefano Stabellini
2014-04-08 15:12 ` [PATCH v7 07/12] xen/arm: s/gic_set_guest_irq/gic_raise_guest_irq Stefano Stabellini
2014-04-08 15:12 ` [PATCH v7 08/12] xen/arm: rename GIC_IRQ_GUEST_PENDING to GIC_IRQ_GUEST_QUEUED Stefano Stabellini
2014-04-23 12:52 ` Ian Campbell
2014-05-08 17:57 ` Stefano Stabellini
2014-05-09 8:33 ` Ian Campbell
2014-04-08 15:12 ` [PATCH v7 09/12] xen/arm: second irq injection while the first irq is still inflight Stefano Stabellini
2014-04-23 13:00 ` Ian Campbell
2014-04-08 15:12 ` [PATCH v7 10/12] xen/arm: don't protect GICH and lr_queue accesses with gic.lock Stefano Stabellini
2014-04-08 15:12 ` Stefano Stabellini [this message]
2014-04-23 13:31 ` [PATCH v7 11/12] xen/arm: gic_events_need_delivery and irq priorities Ian Campbell
2014-05-08 18:37 ` Stefano Stabellini
2014-05-09 8:37 ` Ian Campbell
2014-05-11 14:13 ` Stefano Stabellini
2014-05-11 16:50 ` Stefano Stabellini
2014-04-08 15:12 ` [PATCH v7 12/12] xen/arm: introduce GIC_PRI_TO_GUEST macro Stefano Stabellini
2014-04-23 13:32 ` Ian Campbell
2014-04-23 12:50 ` [PATCH v7 0/12] remove maintenance interrupts Julien Grall
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=1396969969-18973-11-git-send-email-stefano.stabellini@eu.citrix.com \
--to=stefano.stabellini@eu.citrix.com \
--cc=Ian.Campbell@citrix.com \
--cc=julien.grall@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).