|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v7 11/12] xen/arm: gic_events_need_delivery and irq priorities
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@xxxxxxxxxxxxx>
---
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
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |