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>
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  /*