[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] x86: add a shared page indicating the need for an EOI notification



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1227878852 0
# Node ID c820bf73a914f643ab48864629c0559e68ceede1
# Parent  8dbf23c89cc6a4fbd7b9063b14e706c065ba1678
x86: add a shared page indicating the need for an EOI notification

To simplify the interface for the guest, when a guest uses this new
(sub-)hypercall, PHYSDEVOP_eoi behavior changes to unmask the
corresponding event channel at once, avoiding the eventual need for a
second hypercall from the guest.

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx>
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
 xen/arch/x86/domain.c         |    7 ++++
 xen/arch/x86/irq.c            |   62 +++++++++++++++++++++++++++++++++++++-----
 xen/arch/x86/physdev.c        |   34 +++++++++++++++++++++++
 xen/arch/x86/x86_64/physdev.c |    3 ++
 xen/common/event_channel.c    |    5 +--
 xen/include/asm-x86/domain.h  |    4 ++
 xen/include/public/physdev.h  |   15 ++++++++++
 xen/include/xen/event.h       |    3 ++
 xen/include/xen/irq.h         |    1 
 9 files changed, 125 insertions(+), 9 deletions(-)

diff -r 8dbf23c89cc6 -r c820bf73a914 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c     Fri Nov 28 13:05:58 2008 +0000
+++ b/xen/arch/x86/domain.c     Fri Nov 28 13:27:32 2008 +0000
@@ -1814,6 +1814,13 @@ int domain_relinquish_resources(struct d
             unmap_vcpu_info(v);
         }
 
+        if ( d->arch.pirq_eoi_map != NULL )
+        {
+            unmap_domain_page_global(d->arch.pirq_eoi_map);
+            put_page_and_type(mfn_to_page(d->arch.pirq_eoi_map_mfn));
+            d->arch.pirq_eoi_map = NULL;
+        }
+
         d->arch.relmem = RELMEM_xen;
         /* fallthrough */
 
diff -r 8dbf23c89cc6 -r c820bf73a914 xen/arch/x86/irq.c
--- a/xen/arch/x86/irq.c        Fri Nov 28 13:05:58 2008 +0000
+++ b/xen/arch/x86/irq.c        Fri Nov 28 13:27:32 2008 +0000
@@ -18,6 +18,7 @@
 #include <xen/iommu.h>
 #include <asm/msi.h>
 #include <asm/current.h>
+#include <asm/flushtlb.h>
 #include <public/physdev.h>
 
 /* opt_noirqbalance: If true, software IRQ balancing/affinity is disabled. */
@@ -206,16 +207,42 @@ static DEFINE_PER_CPU(struct pending_eoi
 static DEFINE_PER_CPU(struct pending_eoi, pending_eoi[NR_VECTORS]);
 #define pending_eoi_sp(p) ((p)[NR_VECTORS-1].vector)
 
+static inline void set_pirq_eoi(struct domain *d, unsigned int irq)
+{
+    if ( d->arch.pirq_eoi_map )
+        set_bit(irq, d->arch.pirq_eoi_map);
+}
+
+static inline void clear_pirq_eoi(struct domain *d, unsigned int irq)
+{
+    if ( d->arch.pirq_eoi_map )
+        clear_bit(irq, d->arch.pirq_eoi_map);
+}
+
+static void _irq_guest_eoi(irq_desc_t *desc)
+{
+    irq_guest_action_t *action = (irq_guest_action_t *)desc->action;
+    unsigned int i, vector = desc - irq_desc;
+
+    if ( !(desc->status & IRQ_GUEST_EOI_PENDING) )
+        return;
+
+    for ( i = 0; i < action->nr_guests; ++i )
+        clear_pirq_eoi(action->guest[i],
+                       domain_vector_to_irq(action->guest[i], vector));
+
+    desc->status &= ~(IRQ_INPROGRESS|IRQ_GUEST_EOI_PENDING);
+    desc->handler->enable(vector);
+}
+
 static struct timer irq_guest_eoi_timer[NR_VECTORS];
 static void irq_guest_eoi_timer_fn(void *data)
 {
     irq_desc_t *desc = data;
-    unsigned vector = desc - irq_desc;
     unsigned long flags;
 
     spin_lock_irqsave(&desc->lock, flags);
-    desc->status &= ~IRQ_INPROGRESS;
-    desc->handler->enable(vector);
+    _irq_guest_eoi(desc);
     spin_unlock_irqrestore(&desc->lock, flags);
 }
 
@@ -272,8 +299,22 @@ static void __do_IRQ_guest(int vector)
 
     if ( already_pending == action->nr_guests )
     {
+        stop_timer(&irq_guest_eoi_timer[vector]);
         desc->handler->disable(vector);
-        stop_timer(&irq_guest_eoi_timer[vector]);
+        desc->status |= IRQ_GUEST_EOI_PENDING;
+        for ( i = 0; i < already_pending; ++i )
+        {
+            d = action->guest[i];
+            set_pirq_eoi(d, domain_vector_to_irq(d, vector));
+            /*
+             * Could check here whether the guest unmasked the event by now
+             * (or perhaps just re-issue the send_guest_pirq()), and if it
+             * can now accept the event,
+             * - clear all the pirq_eoi bits we already set,
+             * - re-enable the vector, and
+             * - skip the timer setup below.
+             */
+        }
         init_timer(&irq_guest_eoi_timer[vector],
                    irq_guest_eoi_timer_fn, desc, smp_processor_id());
         set_timer(&irq_guest_eoi_timer[vector], NOW() + MILLISECS(1));
@@ -382,8 +423,12 @@ static void __pirq_guest_eoi(struct doma
     action = (irq_guest_action_t *)desc->action;
     vector = desc - irq_desc;
 
-    ASSERT(!test_bit(irq, d->pirq_mask) ||
-           (action->ack_type != ACKTYPE_NONE));
+    if ( action->ack_type == ACKTYPE_NONE )
+    {
+        ASSERT(!test_bit(irq, d->pirq_mask));
+        stop_timer(&irq_guest_eoi_timer[vector]);
+        _irq_guest_eoi(desc);
+    }
 
     if ( unlikely(!test_and_clear_bit(irq, d->pirq_mask)) ||
          unlikely(--action->in_flight != 0) )
@@ -606,6 +651,11 @@ int pirq_guest_bind(struct vcpu *v, int 
     }
 
     action->guest[action->nr_guests++] = v->domain;
+
+    if ( action->ack_type != ACKTYPE_NONE )
+        set_pirq_eoi(v->domain, irq);
+    else
+        clear_pirq_eoi(v->domain, irq);
 
  unlock_out:
     spin_unlock_irq(&desc->lock);
diff -r 8dbf23c89cc6 -r c820bf73a914 xen/arch/x86/physdev.c
--- a/xen/arch/x86/physdev.c    Fri Nov 28 13:05:58 2008 +0000
+++ b/xen/arch/x86/physdev.c    Fri Nov 28 13:27:32 2008 +0000
@@ -191,7 +191,41 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H
         ret = -EFAULT;
         if ( copy_from_guest(&eoi, arg, 1) != 0 )
             break;
+        ret = -EINVAL;
+        if ( eoi.irq < 0 || eoi.irq >= NR_IRQS )
+            break;
+        if ( v->domain->arch.pirq_eoi_map )
+            evtchn_unmask(v->domain->pirq_to_evtchn[eoi.irq]);
         ret = pirq_guest_eoi(v->domain, eoi.irq);
+        break;
+    }
+
+    case PHYSDEVOP_pirq_eoi_mfn: {
+        struct physdev_pirq_eoi_mfn info;
+        unsigned long *p;
+
+        BUILD_BUG_ON(NR_IRQS > (PAGE_SIZE * 8));
+
+        ret = -EFAULT;
+        if ( copy_from_guest(&info, arg, 1) != 0 )
+            break;
+
+        ret = -EINVAL;
+        if ( !mfn_valid(info.mfn) ||
+             !get_page_and_type(mfn_to_page(info.mfn), v->domain,
+                                PGT_writable_page) )
+            break;
+
+        ret = -ENOSPC;
+        if ( (p = map_domain_page_global(info.mfn)) == NULL )
+            break;
+
+        ret = -EBUSY;
+        if ( cmpxchg(&v->domain->arch.pirq_eoi_map, NULL, p) != NULL )
+            unmap_domain_page_global(p);
+        else
+            v->domain->arch.pirq_eoi_map_mfn = info.mfn;
+
         break;
     }
 
diff -r 8dbf23c89cc6 -r c820bf73a914 xen/arch/x86/x86_64/physdev.c
--- a/xen/arch/x86/x86_64/physdev.c     Fri Nov 28 13:05:58 2008 +0000
+++ b/xen/arch/x86/x86_64/physdev.c     Fri Nov 28 13:27:32 2008 +0000
@@ -17,6 +17,9 @@
 
 #define physdev_eoi                compat_physdev_eoi
 #define physdev_eoi_t              physdev_eoi_compat_t
+
+#define physdev_pirq_eoi_mfn       compat_physdev_pirq_eoi_mfn
+#define physdev_pirq_eoi_mfn_t     physdev_pirq_eoi_mfn_compat_t
 
 #define physdev_set_iobitmap       compat_physdev_set_iobitmap
 #define physdev_set_iobitmap_t     physdev_set_iobitmap_compat_t
diff -r 8dbf23c89cc6 -r c820bf73a914 xen/common/event_channel.c
--- a/xen/common/event_channel.c        Fri Nov 28 13:05:58 2008 +0000
+++ b/xen/common/event_channel.c        Fri Nov 28 13:27:32 2008 +0000
@@ -762,10 +762,9 @@ long evtchn_bind_vcpu(unsigned int port,
 }
 
 
-static long evtchn_unmask(evtchn_unmask_t *unmask)
+int evtchn_unmask(unsigned int port)
 {
     struct domain *d = current->domain;
-    int            port = unmask->port;
     struct vcpu   *v;
 
     spin_lock(&d->event_lock);
@@ -916,7 +915,7 @@ long do_event_channel_op(int cmd, XEN_GU
         struct evtchn_unmask unmask;
         if ( copy_from_guest(&unmask, arg, 1) != 0 )
             return -EFAULT;
-        rc = evtchn_unmask(&unmask);
+        rc = evtchn_unmask(unmask.port);
         break;
     }
 
diff -r 8dbf23c89cc6 -r c820bf73a914 xen/include/asm-x86/domain.h
--- a/xen/include/asm-x86/domain.h      Fri Nov 28 13:05:58 2008 +0000
+++ b/xen/include/asm-x86/domain.h      Fri Nov 28 13:27:32 2008 +0000
@@ -237,6 +237,10 @@ struct arch_domain
     /* NB. protected by d->event_lock and by irq_desc[vector].lock */
     int vector_pirq[NR_VECTORS];
     s16 pirq_vector[NR_IRQS];
+
+    /* Shared page for notifying that explicit PIRQ EOI is required. */
+    unsigned long *pirq_eoi_map;
+    unsigned long pirq_eoi_map_mfn;
 
     /* Pseudophysical e820 map (XENMEM_memory_map).  */
     struct e820entry e820[3];
diff -r 8dbf23c89cc6 -r c820bf73a914 xen/include/public/physdev.h
--- a/xen/include/public/physdev.h      Fri Nov 28 13:05:58 2008 +0000
+++ b/xen/include/public/physdev.h      Fri Nov 28 13:27:32 2008 +0000
@@ -41,6 +41,21 @@ DEFINE_XEN_GUEST_HANDLE(physdev_eoi_t);
 DEFINE_XEN_GUEST_HANDLE(physdev_eoi_t);
 
 /*
+ * Register a shared page for the hypervisor to indicate whether the guest
+ * must issue PHYSDEVOP_eoi. The semantics of PHYSDEVOP_eoi change slightly
+ * once the guest used this function in that the associated event channel
+ * will automatically get unmasked. The page registered is used as a bit
+ * array indexed by Xen's PIRQ value.
+ */
+#define PHYSDEVOP_pirq_eoi_mfn          17
+struct physdev_pirq_eoi_mfn {
+    /* IN */
+    xen_pfn_t mfn;
+};
+typedef struct physdev_pirq_eoi_mfn physdev_pirq_eoi_mfn_t;
+DEFINE_XEN_GUEST_HANDLE(physdev_pirq_eoi_mfn_t);
+
+/*
  * Query the status of an IRQ line.
  * @arg == pointer to physdev_irq_status_query structure.
  */
diff -r 8dbf23c89cc6 -r c820bf73a914 xen/include/xen/event.h
--- a/xen/include/xen/event.h   Fri Nov 28 13:05:58 2008 +0000
+++ b/xen/include/xen/event.h   Fri Nov 28 13:27:32 2008 +0000
@@ -44,6 +44,9 @@ int evtchn_send(struct domain *d, unsign
 /* Bind a local event-channel port to the specified VCPU. */
 long evtchn_bind_vcpu(unsigned int port, unsigned int vcpu_id);
 
+/* Unmask a local event-channel port. */
+int evtchn_unmask(unsigned int port);
+
 /* Allocate/free a Xen-attached event channel port. */
 int alloc_unbound_xen_event_channel(
     struct vcpu *local_vcpu, domid_t remote_domid);
diff -r 8dbf23c89cc6 -r c820bf73a914 xen/include/xen/irq.h
--- a/xen/include/xen/irq.h     Fri Nov 28 13:05:58 2008 +0000
+++ b/xen/include/xen/irq.h     Fri Nov 28 13:27:32 2008 +0000
@@ -22,6 +22,7 @@ struct irqaction
 #define IRQ_PENDING    4       /* IRQ pending - replay on enable */
 #define IRQ_REPLAY     8       /* IRQ has been replayed but not acked yet */
 #define IRQ_GUEST       16      /* IRQ is handled by guest OS(es) */
+#define IRQ_GUEST_EOI_PENDING 32 /* IRQ was disabled, pending a guest EOI */
 #define IRQ_PER_CPU     256     /* IRQ is per CPU */
 
 /*

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.