Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Xen: Devel

[PATCH 3/5] xen/gic: support injecting IRQs even to VCPUs not currently running

 

 

Xen devel RSS feed   Index | Next | Previous | View Threaded


stefano.stabellini at eu

Jun 6, 2012, 4:22 AM

Post #1 of 5 (51 views)
Permalink
[PATCH 3/5] xen/gic: support injecting IRQs even to VCPUs not currently running

The lr_pending list belongs to the vgic rather than the gic, so move it
there.

gic_set_guest_irq should take into account whether the vcpu is currently
running and if it is not it should add the irq to the right lr_pending
list.

When restoring the gic state we need to go through the lr_pending list
because it is possible that some irqs have been "injected" while the
vcpu wasn't running.

Signed-off-by: Stefano Stabellini <stefano.stabellini [at] eu>
---
xen/arch/arm/gic.c | 66 +++++++++++++++++++++++++++++------------
xen/arch/arm/gic.h | 2 +-
xen/arch/arm/vgic.c | 3 +-
xen/include/asm-arm/domain.h | 7 ++++
4 files changed, 56 insertions(+), 22 deletions(-)

diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
index c73f274..2e41d75 100644
--- a/xen/arch/arm/gic.c
+++ b/xen/arch/arm/gic.c
@@ -38,6 +38,7 @@
#define GICH ((volatile uint32_t *) (FIXMAP_ADDR(FIXMAP_GICH) \
+ (GIC_HR_OFFSET & 0xfff)))
static void events_maintenance(struct vcpu *v);
+static void gic_restore_pending_irqs(struct vcpu *v);

/* Global state */
static struct {
@@ -49,13 +50,6 @@ static struct {
spinlock_t lock;
uint64_t event_mask;
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];
@@ -87,6 +81,8 @@ void gic_restore_state(struct vcpu *v)
GICH[GICH_LR + i] = v->arch.gic_lr[i];
GICH[GICH_HCR] = GICH_HCR_EN;
isb();
+
+ gic_restore_pending_irqs(v);
}

static unsigned int gic_irq_startup(struct irq_desc *desc)
@@ -323,7 +319,6 @@ int __init gic_init(void)

gic.lr_mask = 0ULL;
gic.event_mask = 0ULL;
- INIT_LIST_HEAD(&gic.lr_pending);

spin_unlock(&gic.lock);

@@ -435,17 +430,20 @@ static inline void gic_set_lr(int lr, unsigned int virtual_irq,
((virtual_irq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT);
}

-void gic_set_guest_irq(unsigned int virtual_irq,
+void gic_set_guest_irq(struct vcpu *v, unsigned int virtual_irq,
unsigned int state, unsigned int priority)
{
int i;
struct pending_irq *iter, *n;

- events_maintenance(current);
+ if ( v->is_running )
+ {
+ events_maintenance(v);
+ }

spin_lock_irq(&gic.lock);

- if ( list_empty(&gic.lr_pending) )
+ if ( v->is_running && list_empty(&v->arch.vgic.lr_pending) )
{
i = find_first_zero_bit(&gic.lr_mask, nr_lrs);
if (i < nr_lrs) {
@@ -457,8 +455,8 @@ void gic_set_guest_irq(unsigned int virtual_irq,
}
}

- n = irq_to_pending(current, virtual_irq);
- list_for_each_entry ( iter, &gic.lr_pending, lr_queue )
+ n = irq_to_pending(v, virtual_irq);
+ list_for_each_entry ( iter, &v->arch.vgic.lr_pending, lr_queue )
{
if ( iter->priority > priority )
{
@@ -466,13 +464,40 @@ void gic_set_guest_irq(unsigned int virtual_irq,
goto out;
}
}
- list_add_tail(&n->lr_queue, &gic.lr_pending);
+ list_add_tail(&n->lr_queue, &v->arch.vgic.lr_pending);

out:
spin_unlock_irq(&gic.lock);
return;
}

+static void gic_restore_pending_irqs(struct vcpu *v)
+{
+ int i;
+ struct pending_irq *p;
+
+ /* check for new pending irqs */
+ if ( list_empty(&v->arch.vgic.lr_pending) )
+ return;
+
+ list_for_each_entry ( p, &v->arch.vgic.lr_pending, lr_queue )
+ {
+ i = find_first_zero_bit(&gic.lr_mask, nr_lrs);
+ if ( i < nr_lrs )
+ {
+ gic_set_lr(i, p->irq, GICH_LR_PENDING, p->priority);
+ list_del_init(&p->lr_queue);
+ set_bit(i, &gic.lr_mask);
+ if ( p->irq == VGIC_IRQ_EVTCHN_CALLBACK )
+ set_bit(i, &gic.event_mask);
+ } else
+ {
+ return;
+ }
+ }
+
+}
+
static void gic_inject_irq_start(void)
{
uint32_t hcr;
@@ -582,9 +607,10 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
{
int i = 0, virq;
uint32_t lr;
+ struct vcpu *v = current;
uint64_t eisr = GICH[GICH_EISR0] | (((uint64_t) GICH[GICH_EISR1]) << 32);

- events_maintenance(current);
+ events_maintenance(v);

while ((i = find_next_bit((const long unsigned int *) &eisr,
sizeof(eisr), i)) < sizeof(eisr)) {
@@ -596,8 +622,8 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
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);
+ if ( !list_empty(&v->arch.vgic.lr_pending) ) {
+ p = list_entry(v->arch.vgic.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);
@@ -608,14 +634,14 @@ static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *r
}
spin_unlock_irq(&gic.lock);

- spin_lock(&current->arch.vgic.lock);
- p = irq_to_pending(current, virq);
+ spin_lock(&v->arch.vgic.lock);
+ p = irq_to_pending(v, virq);
if ( p->desc != NULL ) {
p->desc->status &= ~IRQ_INPROGRESS;
GICC[GICC_DIR] = virq;
}
list_del_init(&p->inflight);
- spin_unlock(&current->arch.vgic.lock);
+ spin_unlock(&v->arch.vgic.lock);

i++;
}
diff --git a/xen/arch/arm/gic.h b/xen/arch/arm/gic.h
index ac9cf3a..a55e146 100644
--- a/xen/arch/arm/gic.h
+++ b/xen/arch/arm/gic.h
@@ -134,7 +134,7 @@ extern void gic_route_irqs(void);
extern void gic_inject(void);

extern void __cpuinit init_maintenance_interrupt(void);
-extern void gic_set_guest_irq(unsigned int irq,
+extern void gic_set_guest_irq(struct vcpu *v, unsigned int irq,
unsigned int state, unsigned int priority);
extern int gic_route_irq_to_guest(struct domain *d, unsigned int irq,
const char * devname);
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index 6eb6ec7..5a624bd 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -112,6 +112,7 @@ int vcpu_vgic_init(struct vcpu *v)
| (1<<(v->vcpu_id+16))
| (1<<(v->vcpu_id+24));
INIT_LIST_HEAD(&v->arch.vgic.inflight_irqs);
+ INIT_LIST_HEAD(&v->arch.vgic.lr_pending);
spin_lock_init(&v->arch.vgic.lock);

return 0;
@@ -568,7 +569,7 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq, int virtual)
else
n->desc = NULL;

- gic_set_guest_irq(irq, GICH_LR_PENDING, priority);
+ gic_set_guest_irq(v, irq, GICH_LR_PENDING, priority);

spin_lock_irqsave(&v->arch.vgic.lock, flags);
list_for_each_entry ( iter, &v->arch.vgic.inflight_irqs, inflight )
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 3576d50..2b14545 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -140,6 +140,13 @@ struct arch_vcpu
* 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;
+ /* 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;
spinlock_t lock;
} vgic;

--
1.7.2.5


_______________________________________________
Xen-devel mailing list
Xen-devel [at] lists
http://lists.xen.org/xen-devel


tim at xen

Jun 7, 2012, 5:46 AM

Post #2 of 5 (48 views)
Permalink
Re: [PATCH 3/5] xen/gic: support injecting IRQs even to VCPUs not currently running [In reply to]

At 12:22 +0100 on 06 Jun (1338985328), Stefano Stabellini wrote:
> +static void gic_restore_pending_irqs(struct vcpu *v)
> +{
> + int i;
> + struct pending_irq *p;
> +
> + /* check for new pending irqs */
> + if ( list_empty(&v->arch.vgic.lr_pending) )
> + return;
> +
> + list_for_each_entry ( p, &v->arch.vgic.lr_pending, lr_queue )
> + {
> + i = find_first_zero_bit(&gic.lr_mask, nr_lrs);
> + if ( i < nr_lrs )
> + {
> + gic_set_lr(i, p->irq, GICH_LR_PENDING, p->priority);
> + list_del_init(&p->lr_queue);
> + set_bit(i, &gic.lr_mask);
> + if ( p->irq == VGIC_IRQ_EVTCHN_CALLBACK )
> + set_bit(i, &gic.event_mask);
> + } else
> + {
> + return;
> + }

This is a bit ugly - maybe "if ( i >= nr_lrs ) return" above and don't
indent the block?


_______________________________________________
Xen-devel mailing list
Xen-devel [at] lists
http://lists.xen.org/xen-devel


stefano.stabellini at eu

Jun 7, 2012, 8:43 AM

Post #3 of 5 (47 views)
Permalink
Re: [PATCH 3/5] xen/gic: support injecting IRQs even to VCPUs not currently running [In reply to]

On Thu, 7 Jun 2012, Tim Deegan wrote:
> At 12:22 +0100 on 06 Jun (1338985328), Stefano Stabellini wrote:
> > +static void gic_restore_pending_irqs(struct vcpu *v)
> > +{
> > + int i;
> > + struct pending_irq *p;
> > +
> > + /* check for new pending irqs */
> > + if ( list_empty(&v->arch.vgic.lr_pending) )
> > + return;
> > +
> > + list_for_each_entry ( p, &v->arch.vgic.lr_pending, lr_queue )
> > + {
> > + i = find_first_zero_bit(&gic.lr_mask, nr_lrs);
> > + if ( i < nr_lrs )
> > + {
> > + gic_set_lr(i, p->irq, GICH_LR_PENDING, p->priority);
> > + list_del_init(&p->lr_queue);
> > + set_bit(i, &gic.lr_mask);
> > + if ( p->irq == VGIC_IRQ_EVTCHN_CALLBACK )
> > + set_bit(i, &gic.event_mask);
> > + } else
> > + {
> > + return;
> > + }
>
> This is a bit ugly - maybe "if ( i >= nr_lrs ) return" above and don't
> indent the block?
>

good idea

_______________________________________________
Xen-devel mailing list
Xen-devel [at] lists
http://lists.xen.org/xen-devel


Ian.Campbell at citrix

Jun 26, 2012, 7:07 AM

Post #4 of 5 (44 views)
Permalink
Re: [PATCH 3/5] xen/gic: support injecting IRQs even to VCPUs not currently running [In reply to]

On Thu, 2012-06-07 at 13:46 +0100, Tim Deegan wrote:
> At 12:22 +0100 on 06 Jun (1338985328), Stefano Stabellini wrote:
> > +static void gic_restore_pending_irqs(struct vcpu *v)
> > +{
> > + int i;
> > + struct pending_irq *p;
> > +
> > + /* check for new pending irqs */
> > + if ( list_empty(&v->arch.vgic.lr_pending) )
> > + return;
> > +
> > + list_for_each_entry ( p, &v->arch.vgic.lr_pending, lr_queue )

Is list_for_each_entry on an empty list somehow wrong/buggy/slow?

> > + {
> > + i = find_first_zero_bit(&gic.lr_mask, nr_lrs);
> > + if ( i < nr_lrs )
> > + {
> > + gic_set_lr(i, p->irq, GICH_LR_PENDING, p->priority);
> > + list_del_init(&p->lr_queue);
> > + set_bit(i, &gic.lr_mask);
> > + if ( p->irq == VGIC_IRQ_EVTCHN_CALLBACK )
> > + set_bit(i, &gic.event_mask);
> > + } else
> > + {
> > + return;
> > + }
>
> This is a bit ugly - maybe "if ( i >= nr_lrs ) return" above and don't
> indent the block?
>



_______________________________________________
Xen-devel mailing list
Xen-devel [at] lists
http://lists.xen.org/xen-devel


stefano.stabellini at eu

Jun 26, 2012, 10:28 AM

Post #5 of 5 (45 views)
Permalink
Re: [PATCH 3/5] xen/gic: support injecting IRQs even to VCPUs not currently running [In reply to]

On Tue, 26 Jun 2012, Ian Campbell wrote:
> On Thu, 2012-06-07 at 13:46 +0100, Tim Deegan wrote:
> > At 12:22 +0100 on 06 Jun (1338985328), Stefano Stabellini wrote:
> > > +static void gic_restore_pending_irqs(struct vcpu *v)
> > > +{
> > > + int i;
> > > + struct pending_irq *p;
> > > +
> > > + /* check for new pending irqs */
> > > + if ( list_empty(&v->arch.vgic.lr_pending) )
> > > + return;
> > > +
> > > + list_for_each_entry ( p, &v->arch.vgic.lr_pending, lr_queue )
>
> Is list_for_each_entry on an empty list somehow wrong/buggy/slow?

Not at all. I'll change it.


_______________________________________________
Xen-devel mailing list
Xen-devel [at] lists
http://lists.xen.org/xen-devel

Xen devel RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.