direct-io.hg

changeset 10949:ffa5b2975dff

[XEN] Add Xen-attached event channels, which will be used
by HVM for the ioreq_packet port.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Fri Aug 04 20:34:44 2006 +0100 (2006-08-04)
parents 49dcd838b7df
children 353404fe850c
files xen/common/event_channel.c xen/include/xen/event.h xen/include/xen/sched.h
line diff
     1.1 --- a/xen/common/event_channel.c	Fri Aug 04 20:30:12 2006 +0100
     1.2 +++ b/xen/common/event_channel.c	Fri Aug 04 20:34:44 2006 +0100
     1.3 @@ -333,6 +333,14 @@ static long __evtchn_close(struct domain
     1.4      }
     1.5  
     1.6      chn1 = evtchn_from_port(d1, port1);
     1.7 +
     1.8 +    /* Guest cannot close a Xen-attached event channel. */
     1.9 +    if ( unlikely(chn1->consumer_is_xen) )
    1.10 +    {
    1.11 +        rc = -EINVAL;
    1.12 +        goto out;
    1.13 +    }
    1.14 +
    1.15      switch ( chn1->state )
    1.16      {
    1.17      case ECS_FREE:
    1.18 @@ -441,6 +449,7 @@ long evtchn_send(unsigned int lport)
    1.19  {
    1.20      struct evtchn *lchn, *rchn;
    1.21      struct domain *ld = current->domain, *rd;
    1.22 +    struct vcpu   *rvcpu;
    1.23      int            rport, ret = 0;
    1.24  
    1.25      spin_lock(&ld->evtchn_lock);
    1.26 @@ -452,13 +461,32 @@ long evtchn_send(unsigned int lport)
    1.27      }
    1.28  
    1.29      lchn = evtchn_from_port(ld, lport);
    1.30 +
    1.31 +    /* Guest cannot send via a Xen-attached event channel. */
    1.32 +    if ( unlikely(lchn->consumer_is_xen) )
    1.33 +    {
    1.34 +        spin_unlock(&ld->evtchn_lock);
    1.35 +        return -EINVAL;
    1.36 +    }
    1.37 +
    1.38      switch ( lchn->state )
    1.39      {
    1.40      case ECS_INTERDOMAIN:
    1.41          rd    = lchn->u.interdomain.remote_dom;
    1.42          rport = lchn->u.interdomain.remote_port;
    1.43          rchn  = evtchn_from_port(rd, rport);
    1.44 -        evtchn_set_pending(rd->vcpu[rchn->notify_vcpu_id], rport);
    1.45 +        rvcpu = rd->vcpu[rchn->notify_vcpu_id];
    1.46 +        if ( rchn->consumer_is_xen )
    1.47 +        {
    1.48 +            /* Xen consumers need notification only if they are blocked. */
    1.49 +            if ( test_and_clear_bit(_VCPUF_blocked_in_xen,
    1.50 +                                    &rvcpu->vcpu_flags) )
    1.51 +                vcpu_wake(rvcpu);
    1.52 +        }
    1.53 +        else
    1.54 +        {
    1.55 +            evtchn_set_pending(rvcpu, rport);
    1.56 +        }
    1.57          break;
    1.58      case ECS_IPI:
    1.59          evtchn_set_pending(ld->vcpu[lchn->notify_vcpu_id], lport);
    1.60 @@ -638,6 +666,14 @@ long evtchn_bind_vcpu(unsigned int port,
    1.61      }
    1.62  
    1.63      chn = evtchn_from_port(d, port);
    1.64 +
    1.65 +    /* Guest cannot re-bind a Xen-attached event channel. */
    1.66 +    if ( unlikely(chn->consumer_is_xen) )
    1.67 +    {
    1.68 +        rc = -EINVAL;
    1.69 +        goto out;
    1.70 +    }
    1.71 +
    1.72      switch ( chn->state )
    1.73      {
    1.74      case ECS_VIRQ:
    1.75 @@ -804,6 +840,71 @@ long do_event_channel_op(int cmd, XEN_GU
    1.76  }
    1.77  
    1.78  
    1.79 +int alloc_unbound_xen_event_channel(
    1.80 +    struct vcpu *local_vcpu, domid_t remote_domid)
    1.81 +{
    1.82 +    struct evtchn *chn;
    1.83 +    struct domain *d = local_vcpu->domain;
    1.84 +    int            port;
    1.85 +
    1.86 +    spin_lock(&d->evtchn_lock);
    1.87 +
    1.88 +    if ( (port = get_free_port(d)) < 0 )
    1.89 +        goto out;
    1.90 +    chn = evtchn_from_port(d, port);
    1.91 +
    1.92 +    chn->state = ECS_UNBOUND;
    1.93 +    chn->consumer_is_xen = 1;
    1.94 +    chn->notify_vcpu_id = local_vcpu->vcpu_id;
    1.95 +    chn->u.unbound.remote_domid = remote_domid;
    1.96 +
    1.97 + out:
    1.98 +    spin_unlock(&d->evtchn_lock);
    1.99 +
   1.100 +    return port;
   1.101 +}
   1.102 +
   1.103 +
   1.104 +void free_xen_event_channel(
   1.105 +    struct vcpu *local_vcpu, int port)
   1.106 +{
   1.107 +    struct evtchn *chn;
   1.108 +    struct domain *d = local_vcpu->domain;
   1.109 +
   1.110 +    spin_lock(&d->evtchn_lock);
   1.111 +    chn = evtchn_from_port(d, port);
   1.112 +    BUG_ON(!chn->consumer_is_xen);
   1.113 +    chn->consumer_is_xen = 0;
   1.114 +    spin_unlock(&d->evtchn_lock);
   1.115 +
   1.116 +    (void)__evtchn_close(d, port);
   1.117 +}
   1.118 +
   1.119 +
   1.120 +void notify_via_xen_event_channel(int lport)
   1.121 +{
   1.122 +    struct evtchn *lchn, *rchn;
   1.123 +    struct domain *ld = current->domain, *rd;
   1.124 +    int            rport;
   1.125 +
   1.126 +    spin_lock(&ld->evtchn_lock);
   1.127 +
   1.128 +    ASSERT(port_is_valid(ld, lport));
   1.129 +    lchn = evtchn_from_port(ld, lport);
   1.130 +    ASSERT(lchn->consumer_is_xen);
   1.131 +
   1.132 +    if ( likely(lchn->state == ECS_INTERDOMAIN) )
   1.133 +    {
   1.134 +        rd    = lchn->u.interdomain.remote_dom;
   1.135 +        rport = lchn->u.interdomain.remote_port;
   1.136 +        rchn  = evtchn_from_port(rd, rport);
   1.137 +        evtchn_set_pending(rd->vcpu[rchn->notify_vcpu_id], rport);
   1.138 +    }
   1.139 +
   1.140 +    spin_unlock(&ld->evtchn_lock);
   1.141 +}
   1.142 +
   1.143 +
   1.144  int evtchn_init(struct domain *d)
   1.145  {
   1.146      spin_lock_init(&d->evtchn_lock);
   1.147 @@ -819,7 +920,10 @@ void evtchn_destroy(struct domain *d)
   1.148      int i;
   1.149  
   1.150      for ( i = 0; port_is_valid(d, i); i++ )
   1.151 -            (void)__evtchn_close(d, i);
   1.152 +    {
   1.153 +        evtchn_from_port(d, i)->consumer_is_xen = 0;
   1.154 +        (void)__evtchn_close(d, i);
   1.155 +    }
   1.156  
   1.157      for ( i = 0; i < NR_EVTCHN_BUCKETS; i++ )
   1.158          xfree(d->evtchn[i]);
     2.1 --- a/xen/include/xen/event.h	Fri Aug 04 20:30:12 2006 +0100
     2.2 +++ b/xen/include/xen/event.h	Fri Aug 04 20:34:44 2006 +0100
     2.3 @@ -15,33 +15,58 @@
     2.4  #include <asm/bitops.h>
     2.5  #include <asm/event.h>
     2.6  
     2.7 -extern void evtchn_set_pending(struct vcpu *v, int port);
     2.8 +void evtchn_set_pending(struct vcpu *v, int port);
     2.9  
    2.10  /*
    2.11   * send_guest_vcpu_virq: Notify guest via a per-VCPU VIRQ.
    2.12   *  @v:        VCPU to which virtual IRQ should be sent
    2.13   *  @virq:     Virtual IRQ number (VIRQ_*)
    2.14   */
    2.15 -extern void send_guest_vcpu_virq(struct vcpu *v, int virq);
    2.16 +void send_guest_vcpu_virq(struct vcpu *v, int virq);
    2.17  
    2.18  /*
    2.19   * send_guest_global_virq: Notify guest via a global VIRQ.
    2.20   *  @d:        Domain to which virtual IRQ should be sent
    2.21   *  @virq:     Virtual IRQ number (VIRQ_*)
    2.22   */
    2.23 -extern void send_guest_global_virq(struct domain *d, int virq);
    2.24 +void send_guest_global_virq(struct domain *d, int virq);
    2.25  
    2.26  /*
    2.27   * send_guest_pirq:
    2.28   *  @d:        Domain to which physical IRQ should be sent
    2.29   *  @pirq:     Physical IRQ number
    2.30   */
    2.31 -extern void send_guest_pirq(struct domain *d, int pirq);
    2.32 +void send_guest_pirq(struct domain *d, int pirq);
    2.33  
    2.34  /* Send a notification from a local event-channel port. */
    2.35 -extern long evtchn_send(unsigned int lport);
    2.36 +long evtchn_send(unsigned int lport);
    2.37  
    2.38  /* Bind a local event-channel port to the specified VCPU. */
    2.39 -extern long evtchn_bind_vcpu(unsigned int port, unsigned int vcpu_id);
    2.40 +long evtchn_bind_vcpu(unsigned int port, unsigned int vcpu_id);
    2.41 +
    2.42 +/* Allocate/free a Xen-attached event channel port. */
    2.43 +int alloc_unbound_xen_event_channel(
    2.44 +    struct vcpu *local_vcpu, domid_t remote_domid);
    2.45 +void free_xen_event_channel(
    2.46 +    struct vcpu *local_vcpu, int port);
    2.47 +
    2.48 +/* Notify remote end of a Xen-attached event channel.*/
    2.49 +void notify_via_xen_event_channel(int lport);
    2.50 +
    2.51 +/* Wait on a Xen-attached event channel. */
    2.52 +#define wait_on_xen_event_channel(port, condition)                      \
    2.53 +    do {                                                                \
    2.54 +        if ( condition )                                                \
    2.55 +            break;                                                      \
    2.56 +        set_bit(_VCPUF_blocked_in_xen, &current->vcpu_flags);           \
    2.57 +        mb(); /* set blocked status /then/ re-evaluate condition */     \
    2.58 +        if ( condition )                                                \
    2.59 +        {                                                               \
    2.60 +            clear_bit(_VCPUF_blocked_in_xen, &current->vcpu_flags);     \
    2.61 +            break;                                                      \
    2.62 +        }                                                               \
    2.63 +        raise_softirq(SCHEDULE_SOFTIRQ);                                \
    2.64 +        do_softirq();                                                   \
    2.65 +    } while ( 0 )
    2.66  
    2.67  #endif /* __XEN_EVENT_H__ */
     3.1 --- a/xen/include/xen/sched.h	Fri Aug 04 20:30:12 2006 +0100
     3.2 +++ b/xen/include/xen/sched.h	Fri Aug 04 20:34:44 2006 +0100
     3.3 @@ -36,7 +36,8 @@ struct evtchn
     3.4  #define ECS_PIRQ         4 /* Channel is bound to a physical IRQ line.       */
     3.5  #define ECS_VIRQ         5 /* Channel is bound to a virtual IRQ line.        */
     3.6  #define ECS_IPI          6 /* Channel is bound to a virtual IPI line.        */
     3.7 -    u16 state;             /* ECS_* */
     3.8 +    u8  state;             /* ECS_* */
     3.9 +    u8  consumer_is_xen;   /* Consumed by Xen or by guest? */
    3.10      u16 notify_vcpu_id;    /* VCPU for local delivery notification */
    3.11      union {
    3.12          struct {
    3.13 @@ -375,6 +376,9 @@ extern struct domain *domain_list;
    3.14   /* VCPU is paused by the hypervisor? */
    3.15  #define _VCPUF_paused          11
    3.16  #define VCPUF_paused           (1UL<<_VCPUF_paused)
    3.17 + /* VCPU is blocked awaiting an event to be consumed by Xen. */
    3.18 +#define _VCPUF_blocked_in_xen  12
    3.19 +#define VCPUF_blocked_in_xen   (1UL<<_VCPUF_blocked_in_xen)
    3.20  
    3.21  /*
    3.22   * Per-domain flags (domain_flags).
    3.23 @@ -404,7 +408,7 @@ extern struct domain *domain_list;
    3.24  static inline int vcpu_runnable(struct vcpu *v)
    3.25  {
    3.26      return ( !(v->vcpu_flags &
    3.27 -               (VCPUF_blocked|VCPUF_down|VCPUF_paused)) &&
    3.28 +               (VCPUF_blocked|VCPUF_down|VCPUF_paused|VCPUF_blocked_in_xen)) &&
    3.29               !(v->domain->domain_flags &
    3.30                 (DOMF_shutdown|DOMF_ctrl_pause|DOMF_paused)) );
    3.31  }