ia64/xen-unstable
changeset 18845:c820bf73a914
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@novell.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
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@novell.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author | Keir Fraser <keir.fraser@citrix.com> |
---|---|
date | Fri Nov 28 13:27:32 2008 +0000 (2008-11-28) |
parents | 8dbf23c89cc6 |
children | 4d52d3c53850 |
files | xen/arch/x86/domain.c xen/arch/x86/irq.c xen/arch/x86/physdev.c xen/arch/x86/x86_64/physdev.c xen/common/event_channel.c xen/include/asm-x86/domain.h xen/include/public/physdev.h xen/include/xen/event.h xen/include/xen/irq.h |
line diff
1.1 --- a/xen/arch/x86/domain.c Fri Nov 28 13:05:58 2008 +0000 1.2 +++ b/xen/arch/x86/domain.c Fri Nov 28 13:27:32 2008 +0000 1.3 @@ -1814,6 +1814,13 @@ int domain_relinquish_resources(struct d 1.4 unmap_vcpu_info(v); 1.5 } 1.6 1.7 + if ( d->arch.pirq_eoi_map != NULL ) 1.8 + { 1.9 + unmap_domain_page_global(d->arch.pirq_eoi_map); 1.10 + put_page_and_type(mfn_to_page(d->arch.pirq_eoi_map_mfn)); 1.11 + d->arch.pirq_eoi_map = NULL; 1.12 + } 1.13 + 1.14 d->arch.relmem = RELMEM_xen; 1.15 /* fallthrough */ 1.16
2.1 --- a/xen/arch/x86/irq.c Fri Nov 28 13:05:58 2008 +0000 2.2 +++ b/xen/arch/x86/irq.c Fri Nov 28 13:27:32 2008 +0000 2.3 @@ -18,6 +18,7 @@ 2.4 #include <xen/iommu.h> 2.5 #include <asm/msi.h> 2.6 #include <asm/current.h> 2.7 +#include <asm/flushtlb.h> 2.8 #include <public/physdev.h> 2.9 2.10 /* opt_noirqbalance: If true, software IRQ balancing/affinity is disabled. */ 2.11 @@ -206,16 +207,42 @@ struct pending_eoi { 2.12 static DEFINE_PER_CPU(struct pending_eoi, pending_eoi[NR_VECTORS]); 2.13 #define pending_eoi_sp(p) ((p)[NR_VECTORS-1].vector) 2.14 2.15 +static inline void set_pirq_eoi(struct domain *d, unsigned int irq) 2.16 +{ 2.17 + if ( d->arch.pirq_eoi_map ) 2.18 + set_bit(irq, d->arch.pirq_eoi_map); 2.19 +} 2.20 + 2.21 +static inline void clear_pirq_eoi(struct domain *d, unsigned int irq) 2.22 +{ 2.23 + if ( d->arch.pirq_eoi_map ) 2.24 + clear_bit(irq, d->arch.pirq_eoi_map); 2.25 +} 2.26 + 2.27 +static void _irq_guest_eoi(irq_desc_t *desc) 2.28 +{ 2.29 + irq_guest_action_t *action = (irq_guest_action_t *)desc->action; 2.30 + unsigned int i, vector = desc - irq_desc; 2.31 + 2.32 + if ( !(desc->status & IRQ_GUEST_EOI_PENDING) ) 2.33 + return; 2.34 + 2.35 + for ( i = 0; i < action->nr_guests; ++i ) 2.36 + clear_pirq_eoi(action->guest[i], 2.37 + domain_vector_to_irq(action->guest[i], vector)); 2.38 + 2.39 + desc->status &= ~(IRQ_INPROGRESS|IRQ_GUEST_EOI_PENDING); 2.40 + desc->handler->enable(vector); 2.41 +} 2.42 + 2.43 static struct timer irq_guest_eoi_timer[NR_VECTORS]; 2.44 static void irq_guest_eoi_timer_fn(void *data) 2.45 { 2.46 irq_desc_t *desc = data; 2.47 - unsigned vector = desc - irq_desc; 2.48 unsigned long flags; 2.49 2.50 spin_lock_irqsave(&desc->lock, flags); 2.51 - desc->status &= ~IRQ_INPROGRESS; 2.52 - desc->handler->enable(vector); 2.53 + _irq_guest_eoi(desc); 2.54 spin_unlock_irqrestore(&desc->lock, flags); 2.55 } 2.56 2.57 @@ -272,8 +299,22 @@ static void __do_IRQ_guest(int vector) 2.58 2.59 if ( already_pending == action->nr_guests ) 2.60 { 2.61 + stop_timer(&irq_guest_eoi_timer[vector]); 2.62 desc->handler->disable(vector); 2.63 - stop_timer(&irq_guest_eoi_timer[vector]); 2.64 + desc->status |= IRQ_GUEST_EOI_PENDING; 2.65 + for ( i = 0; i < already_pending; ++i ) 2.66 + { 2.67 + d = action->guest[i]; 2.68 + set_pirq_eoi(d, domain_vector_to_irq(d, vector)); 2.69 + /* 2.70 + * Could check here whether the guest unmasked the event by now 2.71 + * (or perhaps just re-issue the send_guest_pirq()), and if it 2.72 + * can now accept the event, 2.73 + * - clear all the pirq_eoi bits we already set, 2.74 + * - re-enable the vector, and 2.75 + * - skip the timer setup below. 2.76 + */ 2.77 + } 2.78 init_timer(&irq_guest_eoi_timer[vector], 2.79 irq_guest_eoi_timer_fn, desc, smp_processor_id()); 2.80 set_timer(&irq_guest_eoi_timer[vector], NOW() + MILLISECS(1)); 2.81 @@ -382,8 +423,12 @@ static void __pirq_guest_eoi(struct doma 2.82 action = (irq_guest_action_t *)desc->action; 2.83 vector = desc - irq_desc; 2.84 2.85 - ASSERT(!test_bit(irq, d->pirq_mask) || 2.86 - (action->ack_type != ACKTYPE_NONE)); 2.87 + if ( action->ack_type == ACKTYPE_NONE ) 2.88 + { 2.89 + ASSERT(!test_bit(irq, d->pirq_mask)); 2.90 + stop_timer(&irq_guest_eoi_timer[vector]); 2.91 + _irq_guest_eoi(desc); 2.92 + } 2.93 2.94 if ( unlikely(!test_and_clear_bit(irq, d->pirq_mask)) || 2.95 unlikely(--action->in_flight != 0) ) 2.96 @@ -607,6 +652,11 @@ int pirq_guest_bind(struct vcpu *v, int 2.97 2.98 action->guest[action->nr_guests++] = v->domain; 2.99 2.100 + if ( action->ack_type != ACKTYPE_NONE ) 2.101 + set_pirq_eoi(v->domain, irq); 2.102 + else 2.103 + clear_pirq_eoi(v->domain, irq); 2.104 + 2.105 unlock_out: 2.106 spin_unlock_irq(&desc->lock); 2.107 out:
3.1 --- a/xen/arch/x86/physdev.c Fri Nov 28 13:05:58 2008 +0000 3.2 +++ b/xen/arch/x86/physdev.c Fri Nov 28 13:27:32 2008 +0000 3.3 @@ -191,10 +191,44 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H 3.4 ret = -EFAULT; 3.5 if ( copy_from_guest(&eoi, arg, 1) != 0 ) 3.6 break; 3.7 + ret = -EINVAL; 3.8 + if ( eoi.irq < 0 || eoi.irq >= NR_IRQS ) 3.9 + break; 3.10 + if ( v->domain->arch.pirq_eoi_map ) 3.11 + evtchn_unmask(v->domain->pirq_to_evtchn[eoi.irq]); 3.12 ret = pirq_guest_eoi(v->domain, eoi.irq); 3.13 break; 3.14 } 3.15 3.16 + case PHYSDEVOP_pirq_eoi_mfn: { 3.17 + struct physdev_pirq_eoi_mfn info; 3.18 + unsigned long *p; 3.19 + 3.20 + BUILD_BUG_ON(NR_IRQS > (PAGE_SIZE * 8)); 3.21 + 3.22 + ret = -EFAULT; 3.23 + if ( copy_from_guest(&info, arg, 1) != 0 ) 3.24 + break; 3.25 + 3.26 + ret = -EINVAL; 3.27 + if ( !mfn_valid(info.mfn) || 3.28 + !get_page_and_type(mfn_to_page(info.mfn), v->domain, 3.29 + PGT_writable_page) ) 3.30 + break; 3.31 + 3.32 + ret = -ENOSPC; 3.33 + if ( (p = map_domain_page_global(info.mfn)) == NULL ) 3.34 + break; 3.35 + 3.36 + ret = -EBUSY; 3.37 + if ( cmpxchg(&v->domain->arch.pirq_eoi_map, NULL, p) != NULL ) 3.38 + unmap_domain_page_global(p); 3.39 + else 3.40 + v->domain->arch.pirq_eoi_map_mfn = info.mfn; 3.41 + 3.42 + break; 3.43 + } 3.44 + 3.45 /* Legacy since 0x00030202. */ 3.46 case PHYSDEVOP_IRQ_UNMASK_NOTIFY: { 3.47 ret = pirq_guest_unmask(v->domain);
4.1 --- a/xen/arch/x86/x86_64/physdev.c Fri Nov 28 13:05:58 2008 +0000 4.2 +++ b/xen/arch/x86/x86_64/physdev.c Fri Nov 28 13:27:32 2008 +0000 4.3 @@ -18,6 +18,9 @@ 4.4 #define physdev_eoi compat_physdev_eoi 4.5 #define physdev_eoi_t physdev_eoi_compat_t 4.6 4.7 +#define physdev_pirq_eoi_mfn compat_physdev_pirq_eoi_mfn 4.8 +#define physdev_pirq_eoi_mfn_t physdev_pirq_eoi_mfn_compat_t 4.9 + 4.10 #define physdev_set_iobitmap compat_physdev_set_iobitmap 4.11 #define physdev_set_iobitmap_t physdev_set_iobitmap_compat_t 4.12
5.1 --- a/xen/common/event_channel.c Fri Nov 28 13:05:58 2008 +0000 5.2 +++ b/xen/common/event_channel.c Fri Nov 28 13:27:32 2008 +0000 5.3 @@ -762,10 +762,9 @@ long evtchn_bind_vcpu(unsigned int port, 5.4 } 5.5 5.6 5.7 -static long evtchn_unmask(evtchn_unmask_t *unmask) 5.8 +int evtchn_unmask(unsigned int port) 5.9 { 5.10 struct domain *d = current->domain; 5.11 - int port = unmask->port; 5.12 struct vcpu *v; 5.13 5.14 spin_lock(&d->event_lock); 5.15 @@ -916,7 +915,7 @@ long do_event_channel_op(int cmd, XEN_GU 5.16 struct evtchn_unmask unmask; 5.17 if ( copy_from_guest(&unmask, arg, 1) != 0 ) 5.18 return -EFAULT; 5.19 - rc = evtchn_unmask(&unmask); 5.20 + rc = evtchn_unmask(unmask.port); 5.21 break; 5.22 } 5.23
6.1 --- a/xen/include/asm-x86/domain.h Fri Nov 28 13:05:58 2008 +0000 6.2 +++ b/xen/include/asm-x86/domain.h Fri Nov 28 13:27:32 2008 +0000 6.3 @@ -238,6 +238,10 @@ struct arch_domain 6.4 int vector_pirq[NR_VECTORS]; 6.5 s16 pirq_vector[NR_IRQS]; 6.6 6.7 + /* Shared page for notifying that explicit PIRQ EOI is required. */ 6.8 + unsigned long *pirq_eoi_map; 6.9 + unsigned long pirq_eoi_map_mfn; 6.10 + 6.11 /* Pseudophysical e820 map (XENMEM_memory_map). */ 6.12 struct e820entry e820[3]; 6.13 unsigned int nr_e820;
7.1 --- a/xen/include/public/physdev.h Fri Nov 28 13:05:58 2008 +0000 7.2 +++ b/xen/include/public/physdev.h Fri Nov 28 13:27:32 2008 +0000 7.3 @@ -41,6 +41,21 @@ typedef struct physdev_eoi physdev_eoi_t 7.4 DEFINE_XEN_GUEST_HANDLE(physdev_eoi_t); 7.5 7.6 /* 7.7 + * Register a shared page for the hypervisor to indicate whether the guest 7.8 + * must issue PHYSDEVOP_eoi. The semantics of PHYSDEVOP_eoi change slightly 7.9 + * once the guest used this function in that the associated event channel 7.10 + * will automatically get unmasked. The page registered is used as a bit 7.11 + * array indexed by Xen's PIRQ value. 7.12 + */ 7.13 +#define PHYSDEVOP_pirq_eoi_mfn 17 7.14 +struct physdev_pirq_eoi_mfn { 7.15 + /* IN */ 7.16 + xen_pfn_t mfn; 7.17 +}; 7.18 +typedef struct physdev_pirq_eoi_mfn physdev_pirq_eoi_mfn_t; 7.19 +DEFINE_XEN_GUEST_HANDLE(physdev_pirq_eoi_mfn_t); 7.20 + 7.21 +/* 7.22 * Query the status of an IRQ line. 7.23 * @arg == pointer to physdev_irq_status_query structure. 7.24 */
8.1 --- a/xen/include/xen/event.h Fri Nov 28 13:05:58 2008 +0000 8.2 +++ b/xen/include/xen/event.h Fri Nov 28 13:27:32 2008 +0000 8.3 @@ -44,6 +44,9 @@ int evtchn_send(struct domain *d, unsign 8.4 /* Bind a local event-channel port to the specified VCPU. */ 8.5 long evtchn_bind_vcpu(unsigned int port, unsigned int vcpu_id); 8.6 8.7 +/* Unmask a local event-channel port. */ 8.8 +int evtchn_unmask(unsigned int port); 8.9 + 8.10 /* Allocate/free a Xen-attached event channel port. */ 8.11 int alloc_unbound_xen_event_channel( 8.12 struct vcpu *local_vcpu, domid_t remote_domid);
9.1 --- a/xen/include/xen/irq.h Fri Nov 28 13:05:58 2008 +0000 9.2 +++ b/xen/include/xen/irq.h Fri Nov 28 13:27:32 2008 +0000 9.3 @@ -22,6 +22,7 @@ struct irqaction 9.4 #define IRQ_PENDING 4 /* IRQ pending - replay on enable */ 9.5 #define IRQ_REPLAY 8 /* IRQ has been replayed but not acked yet */ 9.6 #define IRQ_GUEST 16 /* IRQ is handled by guest OS(es) */ 9.7 +#define IRQ_GUEST_EOI_PENDING 32 /* IRQ was disabled, pending a guest EOI */ 9.8 #define IRQ_PER_CPU 256 /* IRQ is per CPU */ 9.9 9.10 /*