From: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
To: xen-devel@lists.xensource.com
Cc: Tim.Deegan@citrix.com,
Stefano Stabellini <stefano.stabellini@eu.citrix.com>,
Ian.Campbell@citrix.com, david.vrabel@citrix.com
Subject: [PATCH v3 03/11] arm: support fewer LR registers than virtual irqs
Date: Fri, 2 Mar 2012 14:27:29 +0000 [thread overview]
Message-ID: <1330698457-8622-3-git-send-email-stefano.stabellini@eu.citrix.com> (raw)
In-Reply-To: <alpine.DEB.2.00.1203021415060.923@kaball-desktop>
If the vgic needs to inject a virtual irq into the guest, but no free
LR registers are available, add the irq to a list and return.
Whenever an LR register becomes available we add the queued irq to it
and remove it from the list.
We use the gic lock to protect the list and the bitmask.
Changes in this version:
- added some comments;
- rename lr_link to lr_queue;
- fix list handling in gic_set_guest_irq;
- use nr_lrs instead of sizeof(uint64_t) as argument to
find_first_zero_bit.
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
xen/arch/arm/gic.c | 101 ++++++++++++++++++++++++++++++++---------
xen/include/asm-arm/domain.h | 10 ++++
2 files changed, 89 insertions(+), 22 deletions(-)
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index 120ec82..72b122e 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -25,6 +25,7 @@
#include <xen/sched.h>
#include <xen/errno.h>
#include <xen/softirq.h>
+#include <xen/list.h>
#include <asm/p2m.h>
#include <asm/domain.h>
@@ -45,6 +46,14 @@ static struct {
unsigned int lines;
unsigned int cpus;
spinlock_t lock;
+ uint64_t lr_mask;
+ /* lr_pending is used to queue IRQs (struct pending_irq) that the
+ * vgic tried to inject in the guest (calling gic_set_guest_irq) but
+ * no LRs were available at the time.
+ * As soon as an LR is freed we remove the first IRQ from this
+ * list and write it to the LR register.
+ * lr_pending is a subset of vgic.inflight_irqs. */
+ struct list_head lr_pending;
} gic;
irq_desc_t irq_desc[NR_IRQS];
@@ -247,6 +256,8 @@ static void __cpuinit gic_hyp_init(void)
GICH[GICH_HCR] = GICH_HCR_EN;
GICH[GICH_MISR] = GICH_MISR_EOI;
+ gic.lr_mask = 0ULL;
+ INIT_LIST_HEAD(&gic.lr_pending);
}
/* Set up the GIC */
@@ -345,16 +356,50 @@ int __init setup_irq(unsigned int irq, struct irqaction *new)
return rc;
}
-void gic_set_guest_irq(unsigned int virtual_irq,
+static inline void gic_set_lr(int lr, unsigned int virtual_irq,
unsigned int state, unsigned int priority)
{
- BUG_ON(virtual_irq > nr_lrs);
- GICH[GICH_LR + virtual_irq] = state |
+ BUG_ON(lr > nr_lrs);
+ GICH[GICH_LR + lr] = state |
GICH_LR_MAINTENANCE_IRQ |
((priority >> 3) << GICH_LR_PRIORITY_SHIFT) |
((virtual_irq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT);
}
+void gic_set_guest_irq(unsigned int virtual_irq,
+ unsigned int state, unsigned int priority)
+{
+ int i;
+ struct pending_irq *iter, *n;
+
+ spin_lock(&gic.lock);
+
+ if ( list_empty(&gic.lr_pending) )
+ {
+ i = find_first_zero_bit(&gic.lr_mask, nr_lrs);
+ if (i < nr_lrs) {
+ set_bit(i, &gic.lr_mask);
+ gic_set_lr(i, virtual_irq, state, priority);
+ goto out;
+ }
+ }
+
+ n = irq_to_pending(current, virtual_irq);
+ list_for_each_entry ( iter, &gic.lr_pending, lr_queue )
+ {
+ if ( iter->priority > priority )
+ {
+ list_add_tail(&n->lr_queue, &iter->lr_queue);
+ goto out;
+ }
+ }
+ list_add_tail(&n->lr_queue, &gic.lr_pending);
+
+out:
+ spin_unlock(&gic.lock);
+ return;
+}
+
void gic_inject_irq_start(void)
{
uint32_t hcr;
@@ -431,30 +476,42 @@ void gicv_setup(struct domain *d)
static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs)
{
- int i, virq;
+ int i = 0, virq;
uint32_t lr;
uint64_t eisr = GICH[GICH_EISR0] | (((uint64_t) GICH[GICH_EISR1]) << 32);
- for ( i = 0; i < 64; i++ ) {
- if ( eisr & ((uint64_t)1 << i) ) {
- struct pending_irq *p;
-
- lr = GICH[GICH_LR + i];
- virq = lr & GICH_LR_VIRTUAL_MASK;
- GICH[GICH_LR + i] = 0;
-
- spin_lock(¤t->arch.vgic.lock);
- p = irq_to_pending(current, virq);
- if ( p->desc != NULL ) {
- p->desc->status &= ~IRQ_INPROGRESS;
- GICC[GICC_DIR] = virq;
- }
+ while ((i = find_next_bit((const long unsigned int *) &eisr,
+ sizeof(eisr), i)) < sizeof(eisr)) {
+ struct pending_irq *p;
+
+ spin_lock(&gic.lock);
+ lr = GICH[GICH_LR + i];
+ virq = lr & GICH_LR_VIRTUAL_MASK;
+ GICH[GICH_LR + i] = 0;
+ clear_bit(i, &gic.lr_mask);
+
+ if ( !list_empty(&gic.lr_pending) ) {
+ p = list_entry(gic.lr_pending.next, typeof(*p), lr_queue);
+ gic_set_lr(i, p->irq, GICH_LR_PENDING, p->priority);
+ list_del_init(&p->lr_queue);
+ set_bit(i, &gic.lr_mask);
+ } else {
gic_inject_irq_stop();
- list_del(&p->inflight);
- INIT_LIST_HEAD(&p->inflight);
- cpu_raise_softirq(current->processor, VGIC_SOFTIRQ);
- spin_unlock(¤t->arch.vgic.lock);
}
+ spin_unlock(&gic.lock);
+
+ spin_lock(¤t->arch.vgic.lock);
+ p = irq_to_pending(current, virq);
+ if ( p->desc != NULL ) {
+ p->desc->status &= ~IRQ_INPROGRESS;
+ GICC[GICC_DIR] = virq;
+ }
+ list_del(&p->inflight);
+ INIT_LIST_HEAD(&p->inflight);
+ cpu_raise_softirq(current->processor, VGIC_SOFTIRQ);
+ spin_unlock(¤t->arch.vgic.lock);
+
+ i++;
}
}
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 9851220..3aa7a8a 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -23,6 +23,9 @@ struct pending_irq
/* inflight is used to append instances of pending_irq to
* vgic.inflight_irqs */
struct list_head inflight;
+ /* lr_queue is used to append instances of pending_irq to
+ * gic.lr_pending */
+ struct list_head lr_queue;
};
struct arch_domain
@@ -56,6 +59,13 @@ struct arch_vcpu
struct {
struct vgic_irq_rank private_irqs;
+ /* This list is ordered by IRQ priority and it is used to keep
+ * track of the IRQs that the VGIC injected into the guest.
+ * Depending on the availability of LR registers, the IRQs might
+ * actually be in an LR, and therefore injected into the guest,
+ * or queued in gic.lr_pending.
+ * As soon as an IRQ is EOI'd by the guest and removed from the
+ * corresponding LR it is also removed from this list. */
struct list_head inflight_irqs;
spinlock_t lock;
} vgic;
--
1.7.2.5
next prev parent reply other threads:[~2012-03-02 14:27 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-03-02 14:27 [PATCH v3 0/11] xen/arm: event channels and shared_info page Stefano Stabellini
2012-03-02 14:27 ` [PATCH v3 01/11] arm: rename link to inflight Stefano Stabellini
2012-03-14 9:48 ` Ian Campbell
2012-03-02 14:27 ` [PATCH v3 02/11] arm: fix inflight_irqs list priority ordering Stefano Stabellini
2012-03-14 9:48 ` Ian Campbell
2012-03-02 14:27 ` Stefano Stabellini [this message]
2012-03-13 14:30 ` [PATCH v3 03/11] arm: support fewer LR registers than virtual irqs Ian Campbell
2012-03-13 17:31 ` Stefano Stabellini
2012-03-13 17:24 ` Ian Campbell
2012-03-14 9:26 ` Ian Campbell
2012-05-25 13:38 ` Stefano Stabellini
2012-03-02 14:27 ` [PATCH v3 04/11] arm: replace list_del and INIT_LIST_HEAD with list_del_init Stefano Stabellini
2012-03-14 9:49 ` Ian Campbell
2012-03-02 14:27 ` [PATCH v3 05/11] arm: shared_info page allocation and mapping Stefano Stabellini
2012-03-13 17:06 ` Ian Campbell
2012-05-25 13:44 ` Stefano Stabellini
2012-03-14 9:38 ` Ian Campbell
2012-05-25 13:54 ` Stefano Stabellini
2012-05-25 13:58 ` Ian Campbell
2012-03-02 14:27 ` [PATCH v3 06/11] arm: handle dom0_max_vcpus=0 case properly Stefano Stabellini
2012-03-14 9:49 ` Ian Campbell
2012-03-02 14:27 ` [PATCH v3 07/11] arm: use r12 to pass the hypercall number Stefano Stabellini
2012-03-13 15:28 ` Ian Campbell
2012-03-13 16:09 ` Ian Campbell
2012-03-13 16:17 ` WARNING: Xen ARMv7 with Virtualization Extensions Guest ABI has changed Ian Campbell
2012-03-02 14:27 ` [PATCH v3 08/11] arm: introduce more hypercalls Stefano Stabellini
2012-03-14 9:49 ` Ian Campbell
2012-03-02 14:27 ` [PATCH v3 09/11] arm: implement flush_tlb_all_local and flush_tlb_local Stefano Stabellini
2012-03-14 9:49 ` Ian Campbell
2012-03-02 14:27 ` [PATCH v3 10/11] arm: remove VGIC_SOFTIRQ Stefano Stabellini
2012-03-02 14:27 ` [PATCH v3 11/11] arm: implement event injection Stefano Stabellini
2012-03-14 9:50 ` [PATCH v3 0/11] xen/arm: event channels and shared_info page Ian Campbell
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=1330698457-8622-3-git-send-email-stefano.stabellini@eu.citrix.com \
--to=stefano.stabellini@eu.citrix.com \
--cc=Ian.Campbell@citrix.com \
--cc=Tim.Deegan@citrix.com \
--cc=david.vrabel@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).