ia64/xen-unstable

changeset 9597:8f7aad20b4a5

Backtrack on the new interface for reserved event-channel
ports, as binding them in user space via the evtchn driver
would be a pain. Instead extend VIRQs so they can be
classified as 'global' or 'per vcpu'. The former can only
be allocated once per guest, but can be re-bound to
an arbitrary VCPU.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed Apr 05 19:30:02 2006 +0100 (2006-04-05)
parents e1152d55ea31
children ece9b5710b29
files xen/arch/ia64/xen/xentime.c xen/arch/x86/time.c xen/common/domain.c xen/common/event_channel.c xen/common/keyhandler.c xen/drivers/char/console.c xen/include/public/event_channel.h xen/include/public/xen.h xen/include/xen/event.h
line diff
     1.1 --- a/xen/arch/ia64/xen/xentime.c	Wed Apr 05 17:41:51 2006 +0100
     1.2 +++ b/xen/arch/ia64/xen/xentime.c	Wed Apr 05 19:30:02 2006 +0100
     1.3 @@ -274,6 +274,6 @@ int reprogram_timer(s_time_t timeout)
     1.4  
     1.5  void send_timer_event(struct vcpu *v)
     1.6  {
     1.7 -	send_guest_virq(v, VIRQ_TIMER);
     1.8 +	send_guest_vcpu_virq(v, VIRQ_TIMER);
     1.9  }
    1.10  
     2.1 --- a/xen/arch/x86/time.c	Wed Apr 05 17:41:51 2006 +0100
     2.2 +++ b/xen/arch/x86/time.c	Wed Apr 05 19:30:02 2006 +0100
     2.3 @@ -916,7 +916,7 @@ void __init early_time_init(void)
     2.4  
     2.5  void send_timer_event(struct vcpu *v)
     2.6  {
     2.7 -    send_guest_virq(v, VIRQ_TIMER);
     2.8 +    send_guest_vcpu_virq(v, VIRQ_TIMER);
     2.9  }
    2.10  
    2.11  /*
     3.1 --- a/xen/common/domain.c	Wed Apr 05 17:41:51 2006 +0100
     3.2 +++ b/xen/common/domain.c	Wed Apr 05 19:30:02 2006 +0100
     3.3 @@ -137,7 +137,7 @@ void domain_kill(struct domain *d)
     3.4          domain_relinquish_resources(d);
     3.5          put_domain(d);
     3.6  
     3.7 -        send_guest_virq(dom0->vcpu[0], VIRQ_DOM_EXC);
     3.8 +        send_guest_global_virq(dom0, VIRQ_DOM_EXC);
     3.9      }
    3.10  }
    3.11  
    3.12 @@ -192,7 +192,7 @@ static void domain_shutdown_finalise(voi
    3.13  
    3.14      /* Don't set DOMF_shutdown until execution contexts are sync'ed. */
    3.15      if ( !test_and_set_bit(_DOMF_shutdown, &d->domain_flags) )
    3.16 -        send_guest_virq(dom0->vcpu[0], VIRQ_DOM_EXC);
    3.17 +        send_guest_global_virq(dom0, VIRQ_DOM_EXC);
    3.18  
    3.19      UNLOCK_BIGLOCK(d);
    3.20  
    3.21 @@ -267,7 +267,7 @@ void domain_pause_for_debugger(void)
    3.22      for_each_vcpu ( d, v )
    3.23          vcpu_sleep_nosync(v);
    3.24  
    3.25 -    send_guest_virq(dom0->vcpu[0], VIRQ_DEBUGGER);
    3.26 +    send_guest_global_virq(dom0, VIRQ_DEBUGGER);
    3.27  }
    3.28  
    3.29  
    3.30 @@ -307,7 +307,7 @@ void domain_destroy(struct domain *d)
    3.31  
    3.32      free_domain(d);
    3.33  
    3.34 -    send_guest_virq(dom0->vcpu[0], VIRQ_DOM_EXC);
    3.35 +    send_guest_global_virq(dom0, VIRQ_DOM_EXC);
    3.36  }
    3.37  
    3.38  void vcpu_pause(struct vcpu *v)
     4.1 --- a/xen/common/event_channel.c	Wed Apr 05 17:41:51 2006 +0100
     4.2 +++ b/xen/common/event_channel.c	Wed Apr 05 19:30:02 2006 +0100
     4.3 @@ -3,7 +3,7 @@
     4.4   * 
     4.5   * Event notifications from VIRQs, PIRQs, and other domains.
     4.6   * 
     4.7 - * Copyright (c) 2003-2005, K A Fraser.
     4.8 + * Copyright (c) 2003-2006, K A Fraser.
     4.9   * 
    4.10   * This program is distributed in the hope that it will be useful,
    4.11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.12 @@ -47,6 +47,27 @@
    4.13      } while ( 0 )
    4.14  
    4.15  
    4.16 +static int virq_is_global(int virq)
    4.17 +{
    4.18 +    int rc;
    4.19 +
    4.20 +    ASSERT((virq >= 0) && (virq < NR_VIRQS));
    4.21 +
    4.22 +    switch ( virq )
    4.23 +    {
    4.24 +    case VIRQ_TIMER:
    4.25 +    case VIRQ_DEBUG:
    4.26 +        rc = 0;
    4.27 +        break;
    4.28 +    default:
    4.29 +        rc = 1;
    4.30 +        break;
    4.31 +    }
    4.32 +
    4.33 +    return rc;
    4.34 +}
    4.35 +
    4.36 +
    4.37  static int get_free_port(struct domain *d)
    4.38  {
    4.39      struct evtchn *chn;
    4.40 @@ -182,6 +203,9 @@ static long evtchn_bind_virq(evtchn_bind
    4.41      if ( virq >= ARRAY_SIZE(v->virq_to_evtchn) )
    4.42          return -EINVAL;
    4.43  
    4.44 +    if ( virq_is_global(virq) && (vcpu != 0) )
    4.45 +        return -EINVAL;
    4.46 +
    4.47      if ( (vcpu >= ARRAY_SIZE(d->vcpu)) || ((v = d->vcpu[vcpu]) == NULL) )
    4.48          return -ENOENT;
    4.49  
    4.50 @@ -474,19 +498,43 @@ void evtchn_set_pending(struct vcpu *v, 
    4.51  }
    4.52  
    4.53  
    4.54 -void send_guest_virq(struct vcpu *v, int virq)
    4.55 +void send_guest_vcpu_virq(struct vcpu *v, int virq)
    4.56  {
    4.57 -    int port = v->virq_to_evtchn[virq];
    4.58 +    int port;
    4.59 +
    4.60 +    ASSERT(!virq_is_global(virq));
    4.61 +
    4.62 +    port = v->virq_to_evtchn[virq];
    4.63 +    if ( unlikely(port == 0) )
    4.64 +        return;
    4.65 +
    4.66 +    evtchn_set_pending(v, port);
    4.67 +}
    4.68  
    4.69 -    if ( likely(port != 0) )
    4.70 -        evtchn_set_pending(v, port);
    4.71 +void send_guest_global_virq(struct domain *d, int virq)
    4.72 +{
    4.73 +    int port;
    4.74 +    struct evtchn *chn;
    4.75 +
    4.76 +    ASSERT(virq_is_global(virq));
    4.77 +
    4.78 +    port = d->vcpu[0]->virq_to_evtchn[virq];
    4.79 +    if ( unlikely(port == 0) )
    4.80 +        return;
    4.81 +
    4.82 +    chn = evtchn_from_port(d, port);
    4.83 +    evtchn_set_pending(d->vcpu[chn->notify_vcpu_id], port);
    4.84  }
    4.85  
    4.86  
    4.87  void send_guest_pirq(struct domain *d, int pirq)
    4.88  {
    4.89      int port = d->pirq_to_evtchn[pirq];
    4.90 -    struct evtchn *chn = evtchn_from_port(d, port);
    4.91 +    struct evtchn *chn;
    4.92 +
    4.93 +    ASSERT(port != 0);
    4.94 +
    4.95 +    chn = evtchn_from_port(d, port);
    4.96      evtchn_set_pending(d->vcpu[chn->notify_vcpu_id], port);
    4.97  }
    4.98  
    4.99 @@ -576,6 +624,12 @@ long evtchn_bind_vcpu(unsigned int port,
   4.100      chn = evtchn_from_port(d, port);
   4.101      switch ( chn->state )
   4.102      {
   4.103 +    case ECS_VIRQ:
   4.104 +        if ( virq_is_global(chn->u.virq) )
   4.105 +            chn->notify_vcpu_id = vcpu_id;
   4.106 +        else
   4.107 +            rc = -EINVAL;
   4.108 +        break;
   4.109      case ECS_UNBOUND:
   4.110      case ECS_INTERDOMAIN:
   4.111      case ECS_PIRQ:
   4.112 @@ -702,41 +756,6 @@ long do_event_channel_op(GUEST_HANDLE(ev
   4.113  }
   4.114  
   4.115  
   4.116 -int evtchn_open_reserved_port(struct domain *d)
   4.117 -{
   4.118 -    struct evtchn *chn;
   4.119 -    int            port;
   4.120 -
   4.121 -    spin_lock(&d->evtchn_lock);
   4.122 -
   4.123 -    if ( (port = get_free_port(d)) >= 0 )
   4.124 -    {
   4.125 -        chn = evtchn_from_port(d, port);
   4.126 -        chn->state = ECS_RESERVED;
   4.127 -    }
   4.128 -
   4.129 -    spin_unlock(&d->evtchn_lock);
   4.130 -
   4.131 -    return port;
   4.132 -}
   4.133 -
   4.134 -
   4.135 -void evtchn_close_reserved_port(struct domain *d, int port)
   4.136 -{
   4.137 -    struct evtchn *chn;
   4.138 -
   4.139 -    spin_lock(&d->evtchn_lock);
   4.140 -
   4.141 -    BUG_ON(!port_is_valid(d, port));
   4.142 -
   4.143 -    chn = evtchn_from_port(d, port);
   4.144 -    chn->state          = ECS_FREE;
   4.145 -    chn->notify_vcpu_id = 0;
   4.146 -
   4.147 -    spin_unlock(&d->evtchn_lock);
   4.148 -}
   4.149 -
   4.150 -
   4.151  void evtchn_notify_reserved_port(struct domain *d, int port)
   4.152  {
   4.153      struct evtchn *chn = evtchn_from_port(d, port);
     5.1 --- a/xen/common/keyhandler.c	Wed Apr 05 17:41:51 2006 +0100
     5.2 +++ b/xen/common/keyhandler.c	Wed Apr 05 19:30:02 2006 +0100
     5.3 @@ -162,7 +162,7 @@ static void dump_domains(unsigned char k
     5.4                              &d->shared_info->evtchn_mask[0]),
     5.5                     test_bit(v->virq_to_evtchn[VIRQ_DEBUG]/BITS_PER_LONG, 
     5.6                              &v->vcpu_info->evtchn_pending_sel));
     5.7 -            send_guest_virq(v, VIRQ_DEBUG);
     5.8 +            send_guest_vcpu_virq(v, VIRQ_DEBUG);
     5.9          }
    5.10      }
    5.11  
     6.1 --- a/xen/drivers/char/console.c	Wed Apr 05 17:41:51 2006 +0100
     6.2 +++ b/xen/drivers/char/console.c	Wed Apr 05 19:30:02 2006 +0100
     6.3 @@ -294,7 +294,7 @@ static void __serial_rx(char c, struct c
     6.4      if ( (serial_rx_prod-serial_rx_cons) != SERIAL_RX_SIZE )
     6.5          serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod++)] = c;
     6.6      /* Always notify the guest: prevents receive path from getting stuck. */
     6.7 -    send_guest_virq(dom0->vcpu[0], VIRQ_CONSOLE);
     6.8 +    send_guest_global_virq(dom0, VIRQ_CONSOLE);
     6.9  }
    6.10  
    6.11  static void serial_rx(char c, struct cpu_user_regs *regs)
     7.1 --- a/xen/include/public/event_channel.h	Wed Apr 05 17:41:51 2006 +0100
     7.2 +++ b/xen/include/public/event_channel.h	Wed Apr 05 19:30:02 2006 +0100
     7.3 @@ -50,9 +50,13 @@ typedef struct evtchn_bind_interdomain {
     7.4   * EVTCHNOP_bind_virq: Bind a local event channel to VIRQ <irq> on specified
     7.5   * vcpu.
     7.6   * NOTES:
     7.7 - *  1. A virtual IRQ may be bound to at most one event channel per vcpu.
     7.8 - *  2. The allocated event channel is bound to the specified vcpu. The binding
     7.9 - *     may not be changed.
    7.10 + *  1. Virtual IRQs are classified as per-vcpu or global. See the VIRQ list
    7.11 + *     in xen.h for the classification of each VIRQ.
    7.12 + *  2. Global VIRQs must be allocated on VCPU0 but can subsequently be
    7.13 + *     re-bound via EVTCHNOP_bind_vcpu.
    7.14 + *  3. Per-vcpu VIRQs may be bound to at most one event channel per vcpu.
    7.15 + *     The allocated event channel is bound to the specified vcpu and the
    7.16 + *     binding cannot be changed.
    7.17   */
    7.18  #define EVTCHNOP_bind_virq        1
    7.19  typedef struct evtchn_bind_virq {
    7.20 @@ -152,9 +156,11 @@ typedef struct evtchn_status {
    7.21   * EVTCHNOP_bind_vcpu: Specify which vcpu a channel should notify when an
    7.22   * event is pending.
    7.23   * NOTES:
    7.24 - *  1. IPI- and VIRQ-bound channels always notify the vcpu that initialised
    7.25 - *     the binding. This binding cannot be changed.
    7.26 - *  2. All other channels notify vcpu0 by default. This default is set when
    7.27 + *  1. IPI-bound channels always notify the vcpu specified at bind time.
    7.28 + *     This binding cannot be changed.
    7.29 + *  2. Per-VCPU VIRQ channels always notify the vcpu specified at bind time.
    7.30 + *     This binding cannot be changed.
    7.31 + *  3. All other channels notify vcpu0 by default. This default is set when
    7.32   *     the channel is allocated (a port that is freed and subsequently reused
    7.33   *     has its binding reset to vcpu0).
    7.34   */
     8.1 --- a/xen/include/public/xen.h	Wed Apr 05 17:41:51 2006 +0100
     8.2 +++ b/xen/include/public/xen.h	Wed Apr 05 19:30:02 2006 +0100
     8.3 @@ -65,12 +65,17 @@
     8.4   * VIRTUAL INTERRUPTS
     8.5   * 
     8.6   * Virtual interrupts that a guest OS may receive from Xen.
     8.7 + * 
     8.8 + * In the side comments, 'V.' denotes a per-VCPU VIRQ while 'G.' denotes a
     8.9 + * global VIRQ. The former can be bound once per VCPU and cannot be re-bound.
    8.10 + * The latter can be allocated only once per guest: they must initially be
    8.11 + * allocated to VCPU0 but can subsequently be re-bound.
    8.12   */
    8.13 -#define VIRQ_TIMER      0  /* Timebase update, and/or requested timeout.  */
    8.14 -#define VIRQ_DEBUG      1  /* Request guest to dump debug info.           */
    8.15 -#define VIRQ_CONSOLE    2  /* (DOM0) Bytes received on emergency console. */
    8.16 -#define VIRQ_DOM_EXC    3  /* (DOM0) Exceptional event for some domain.   */
    8.17 -#define VIRQ_DEBUGGER   6  /* (DOM0) A domain has paused for debugging.   */
    8.18 +#define VIRQ_TIMER      0  /* V. Timebase update, and/or requested timeout.  */
    8.19 +#define VIRQ_DEBUG      1  /* V. Request guest to dump debug info.           */
    8.20 +#define VIRQ_CONSOLE    2  /* G. (DOM0) Bytes received on emergency console. */
    8.21 +#define VIRQ_DOM_EXC    3  /* G. (DOM0) Exceptional event for some domain.   */
    8.22 +#define VIRQ_DEBUGGER   6  /* G. (DOM0) A domain has paused for debugging.   */
    8.23  #define NR_VIRQS        8
    8.24  
    8.25  /*
     9.1 --- a/xen/include/xen/event.h	Wed Apr 05 17:41:51 2006 +0100
     9.2 +++ b/xen/include/xen/event.h	Wed Apr 05 19:30:02 2006 +0100
     9.3 @@ -3,7 +3,7 @@
     9.4   * 
     9.5   * A nice interface for passing asynchronous events to guest OSes.
     9.6   * 
     9.7 - * Copyright (c) 2002-2005, K A Fraser
     9.8 + * Copyright (c) 2002-2006, K A Fraser
     9.9   */
    9.10  
    9.11  #ifndef __XEN_EVENT_H__
    9.12 @@ -18,11 +18,18 @@
    9.13  extern void evtchn_set_pending(struct vcpu *v, int port);
    9.14  
    9.15  /*
    9.16 - * send_guest_virq:
    9.17 + * send_guest_vcpu_virq: Notify guest via a per-VCPU VIRQ.
    9.18   *  @v:        VCPU to which virtual IRQ should be sent
    9.19   *  @virq:     Virtual IRQ number (VIRQ_*)
    9.20   */
    9.21 -extern void send_guest_virq(struct vcpu *v, int virq);
    9.22 +extern void send_guest_vcpu_virq(struct vcpu *v, int virq);
    9.23 +
    9.24 +/*
    9.25 + * send_guest_global_virq: Notify guest via a global VIRQ.
    9.26 + *  @d:        Domain to which virtual IRQ should be sent
    9.27 + *  @virq:     Virtual IRQ number (VIRQ_*)
    9.28 + */
    9.29 +extern void send_guest_global_virq(struct domain *d, int virq);
    9.30  
    9.31  /*
    9.32   * send_guest_pirq:
    9.33 @@ -45,9 +52,4 @@ extern long evtchn_send(unsigned int lpo
    9.34  /* Bind a local event-channel port to the specified VCPU. */
    9.35  extern long evtchn_bind_vcpu(unsigned int port, unsigned int vcpu_id);
    9.36  
    9.37 -/* Reserved event-channel ports for other Xen subsystems. */
    9.38 -int evtchn_open_reserved_port(struct domain *d);
    9.39 -void evtchn_close_reserved_port(struct domain *d, int port);
    9.40 -void evtchn_notify_reserved_port(struct domain *d, int port);
    9.41 -
    9.42  #endif /* __XEN_EVENT_H__ */