# 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
|