ia64/xen-unstable

changeset 10072:7cbc1fc8dbea

Add some locking to the PIC device model. Improves SMP guest stability.
Signed-off-by: David Lively <dlively@virtualiron.com>
author kaf24@firebug.cl.cam.ac.uk
date Tue May 16 19:54:41 2006 +0100 (2006-05-16)
parents 7fdc4a8b782b
children 86d8246c6aff
files xen/arch/x86/hvm/hvm.c xen/arch/x86/hvm/i8259.c xen/include/asm-x86/hvm/vpic.h
line diff
     1.1 --- a/xen/arch/x86/hvm/hvm.c	Tue May 16 19:50:23 2006 +0100
     1.2 +++ b/xen/arch/x86/hvm/hvm.c	Tue May 16 19:54:41 2006 +0100
     1.3 @@ -240,15 +240,18 @@ int cpu_get_interrupt(struct vcpu *v, in
     1.4  {
     1.5      int intno;
     1.6      struct hvm_virpic *s = &v->domain->arch.hvm_domain.vpic;
     1.7 +    unsigned long flags;
     1.8  
     1.9      if ( (intno = cpu_get_apic_interrupt(v, type)) != -1 ) {
    1.10          /* set irq request if a PIC irq is still pending */
    1.11          /* XXX: improve that */
    1.12 +        spin_lock_irqsave(&s->lock, flags);
    1.13          pic_update_irq(s);
    1.14 +        spin_unlock_irqrestore(&s->lock, flags);
    1.15          return intno;
    1.16      }
    1.17      /* read the irq from the PIC */
    1.18 -    if ( (intno = cpu_get_pic_interrupt(v, type)) != -1 )
    1.19 +    if ( v->vcpu_id == 0 && (intno = cpu_get_pic_interrupt(v, type)) != -1 )
    1.20          return intno;
    1.21  
    1.22      return -1;
     2.1 --- a/xen/arch/x86/hvm/i8259.c	Tue May 16 19:50:23 2006 +0100
     2.2 +++ b/xen/arch/x86/hvm/i8259.c	Tue May 16 19:54:41 2006 +0100
     2.3 @@ -35,9 +35,13 @@
     2.4  #include <asm/current.h>
     2.5  
     2.6  /* set irq level. If an edge is detected, then the IRR is set to 1 */
     2.7 +/* Caller must hold vpic lock */
     2.8  static inline void pic_set_irq1(PicState *s, int irq, int level)
     2.9  {
    2.10      int mask;
    2.11 +
    2.12 +    BUG_ON(!spin_is_locked(&s->pics_state->lock));
    2.13 +
    2.14      mask = 1 << irq;
    2.15      if (s->elcr & mask) {
    2.16          /* level triggered */
    2.17 @@ -63,9 +67,13 @@ static inline void pic_set_irq1(PicState
    2.18  
    2.19  /* return the highest priority found in mask (highest = smallest
    2.20     number). Return 8 if no irq */
    2.21 +/* Caller must hold vpic lock */
    2.22  static inline int get_priority(PicState *s, int mask)
    2.23  {
    2.24      int priority;
    2.25 +
    2.26 +    BUG_ON(!spin_is_locked(&s->pics_state->lock));
    2.27 +
    2.28      if (mask == 0)
    2.29          return 8;
    2.30      priority = 0;
    2.31 @@ -75,10 +83,13 @@ static inline int get_priority(PicState 
    2.32  }
    2.33  
    2.34  /* return the pic wanted interrupt. return -1 if none */
    2.35 +/* Caller must hold vpic lock */
    2.36  static int pic_get_irq(PicState *s)
    2.37  {
    2.38      int mask, cur_priority, priority;
    2.39  
    2.40 +    BUG_ON(!spin_is_locked(&s->pics_state->lock));
    2.41 +
    2.42      mask = s->irr & ~s->imr;
    2.43      priority = get_priority(s, mask);
    2.44      if (priority == 8)
    2.45 @@ -101,10 +112,13 @@ static int pic_get_irq(PicState *s)
    2.46  /* raise irq to CPU if necessary. must be called every time the active
    2.47     irq may change */
    2.48  /* XXX: should not export it, but it is needed for an APIC kludge */
    2.49 +/* Caller must hold vpic lock */
    2.50  void pic_update_irq(struct hvm_virpic *s)
    2.51  {
    2.52      int irq2, irq;
    2.53  
    2.54 +    BUG_ON(!spin_is_locked(&s->lock));
    2.55 +
    2.56      /* first look at slave pic */
    2.57      irq2 = pic_get_irq(&s->pics[1]);
    2.58      if (irq2 >= 0) {
    2.59 @@ -122,29 +136,40 @@ void pic_update_irq(struct hvm_virpic *s
    2.60  void pic_set_irq_new(void *opaque, int irq, int level)
    2.61  {
    2.62      struct hvm_virpic *s = opaque;
    2.63 +    unsigned long flags;
    2.64  
    2.65 +    spin_lock_irqsave(&s->lock, flags);
    2.66      hvm_vioapic_set_irq(current->domain, irq, level);
    2.67      pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
    2.68      /* used for IOAPIC irqs */
    2.69      if (s->alt_irq_func)
    2.70          s->alt_irq_func(s->alt_irq_opaque, irq, level);
    2.71      pic_update_irq(s);
    2.72 +    spin_unlock_irqrestore(&s->lock, flags);
    2.73  }
    2.74  
    2.75  void do_pic_irqs (struct hvm_virpic *s, uint16_t irqs)
    2.76  {
    2.77 +    unsigned long flags;
    2.78 +
    2.79 +    spin_lock_irqsave(&s->lock, flags);
    2.80      s->pics[1].irr |= (uint8_t)(irqs >> 8);
    2.81      s->pics[0].irr |= (uint8_t) irqs;
    2.82      hvm_vioapic_do_irqs(current->domain, irqs);
    2.83      pic_update_irq(s);
    2.84 +    spin_unlock_irqrestore(&s->lock, flags);
    2.85  }
    2.86  
    2.87  void do_pic_irqs_clear (struct hvm_virpic *s, uint16_t irqs)
    2.88  {
    2.89 +    unsigned long flags;
    2.90 +
    2.91 +    spin_lock_irqsave(&s->lock, flags);
    2.92      s->pics[1].irr &= ~(uint8_t)(irqs >> 8);
    2.93      s->pics[0].irr &= ~(uint8_t) irqs;
    2.94      hvm_vioapic_do_irqs_clear(current->domain, irqs);
    2.95      pic_update_irq(s);
    2.96 +    spin_unlock_irqrestore(&s->lock, flags);
    2.97  }
    2.98  
    2.99  /* obsolete function */
   2.100 @@ -154,8 +179,11 @@ void pic_set_irq(struct hvm_virpic *isa_
   2.101  }
   2.102  
   2.103  /* acknowledge interrupt 'irq' */
   2.104 +/* Caller must hold vpic lock */
   2.105  static inline void pic_intack(PicState *s, int irq)
   2.106  {
   2.107 +    BUG_ON(!spin_is_locked(&s->pics_state->lock));
   2.108 +
   2.109      if (s->auto_eoi) {
   2.110          if (s->rotate_on_auto_eoi)
   2.111              s->priority_add = (irq + 1) & 7;
   2.112 @@ -170,7 +198,9 @@ static inline void pic_intack(PicState *
   2.113  int pic_read_irq(struct hvm_virpic *s)
   2.114  {
   2.115      int irq, irq2, intno;
   2.116 +    unsigned long flags;
   2.117  
   2.118 +    spin_lock_irqsave(&s->lock, flags);
   2.119      irq = pic_get_irq(&s->pics[0]);
   2.120      if (irq >= 0) {
   2.121          pic_intack(&s->pics[0], irq);
   2.122 @@ -194,14 +224,18 @@ int pic_read_irq(struct hvm_virpic *s)
   2.123          intno = s->pics[0].irq_base + irq;
   2.124      }
   2.125      pic_update_irq(s);
   2.126 +    spin_unlock_irqrestore(&s->lock, flags);
   2.127          
   2.128      return intno;
   2.129  }
   2.130  
   2.131 +/* Caller must hold vpic lock */
   2.132  static void update_shared_irr(struct hvm_virpic *s, PicState *c)
   2.133  {
   2.134      uint8_t *pl, *pe;
   2.135  
   2.136 +    BUG_ON(!spin_is_locked(&s->lock));
   2.137 +
   2.138      get_sp(current->domain)->sp_global.pic_elcr = 
   2.139  		s->pics[0].elcr | ((u16)s->pics[1].elcr << 8);
   2.140      pl =(uint8_t*)&get_sp(current->domain)->sp_global.pic_last_irr;
   2.141 @@ -216,10 +250,13 @@ static void update_shared_irr(struct hvm
   2.142      }
   2.143  }
   2.144  
   2.145 +/* Caller must hold vpic lock */
   2.146  static void pic_reset(void *opaque)
   2.147  {
   2.148      PicState *s = opaque;
   2.149  
   2.150 +    BUG_ON(!spin_is_locked(&s->pics_state->lock));
   2.151 +
   2.152      s->last_irr = 0;
   2.153      s->irr = 0;
   2.154      s->imr = 0;
   2.155 @@ -237,11 +274,14 @@ static void pic_reset(void *opaque)
   2.156      s->elcr = 0;
   2.157  }
   2.158  
   2.159 +/* Caller must hold vpic lock */
   2.160  static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
   2.161  {
   2.162      PicState *s = opaque;
   2.163      int priority, cmd, irq;
   2.164  
   2.165 +    BUG_ON(!spin_is_locked(&s->pics_state->lock));
   2.166 +
   2.167      addr &= 1;
   2.168      if (addr == 0) {
   2.169          if (val & 0x10) {
   2.170 @@ -328,10 +368,13 @@ static void pic_ioport_write(void *opaqu
   2.171      }
   2.172  }
   2.173  
   2.174 +/* Caller must hold vpic lock */
   2.175  static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
   2.176  {
   2.177      int ret;
   2.178  
   2.179 +    BUG_ON(!spin_is_locked(&s->pics_state->lock));
   2.180 +
   2.181      ret = pic_get_irq(s);
   2.182      if (ret >= 0) {
   2.183          if (addr1 >> 7) {
   2.184 @@ -350,12 +393,15 @@ static uint32_t pic_poll_read (PicState 
   2.185      return ret;
   2.186  }
   2.187  
   2.188 +/* Caller must hold vpic lock */
   2.189  static uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
   2.190  {
   2.191      PicState *s = opaque;
   2.192      unsigned int addr;
   2.193      int ret;
   2.194  
   2.195 +    BUG_ON(!spin_is_locked(&s->pics_state->lock));
   2.196 +
   2.197      addr = addr1;
   2.198      addr &= 1;
   2.199      if (s->poll) {
   2.200 @@ -375,23 +421,30 @@ static uint32_t pic_ioport_read(void *op
   2.201  }
   2.202  
   2.203  /* memory mapped interrupt status */
   2.204 -/* XXX: may be the same than pic_read_irq() */
   2.205 +/* XXX: may be the same than pic_read_rq() */
   2.206  uint32_t pic_intack_read(struct hvm_virpic *s)
   2.207  {
   2.208      int ret;
   2.209 +    unsigned long flags;
   2.210  
   2.211 +    spin_lock_irqsave(&s->lock, flags);
   2.212      ret = pic_poll_read(&s->pics[0], 0x00);
   2.213      if (ret == 2)
   2.214          ret = pic_poll_read(&s->pics[1], 0x80) + 8;
   2.215      /* Prepare for ISR read */
   2.216      s->pics[0].read_reg_select = 1;
   2.217 +    spin_unlock_irqrestore(&s->lock, flags);
   2.218      
   2.219      return ret;
   2.220  }
   2.221  
   2.222  static void elcr_ioport_write(void *opaque, uint32_t addr, uint32_t val)
   2.223 +/* Caller must hold vpic lock */
   2.224  {
   2.225      PicState *s = opaque;
   2.226 +
   2.227 +    BUG_ON(!spin_is_locked(&s->pics_state->lock));
   2.228 +
   2.229      s->elcr = val & s->elcr_mask;
   2.230  }
   2.231  
   2.232 @@ -402,23 +455,31 @@ static uint32_t elcr_ioport_read(void *o
   2.233  }
   2.234  
   2.235  /* XXX: add generic master/slave system */
   2.236 +/* Caller must hold vpic lock */
   2.237  static void pic_init1(int io_addr, int elcr_addr, PicState *s)
   2.238  {
   2.239 +    BUG_ON(!spin_is_locked(&s->pics_state->lock));
   2.240 +
   2.241      pic_reset(s);
   2.242  }
   2.243  
   2.244  void pic_init(struct hvm_virpic *s, void (*irq_request)(void *, int),
   2.245                void *irq_request_opaque)
   2.246  {
   2.247 +    unsigned long flags;
   2.248 +
   2.249      memset(s, 0, sizeof(*s));
   2.250 +    spin_lock_init(&s->lock);
   2.251 +    s->pics[0].pics_state = s;
   2.252 +    s->pics[1].pics_state = s;
   2.253 +    spin_lock_irqsave(&s->lock, flags);
   2.254      pic_init1(0x20, 0x4d0, &s->pics[0]);
   2.255      pic_init1(0xa0, 0x4d1, &s->pics[1]);
   2.256 +    spin_unlock_irqrestore(&s->lock, flags);
   2.257      s->pics[0].elcr_mask = 0xf8;
   2.258      s->pics[1].elcr_mask = 0xde;
   2.259      s->irq_request = irq_request;
   2.260      s->irq_request_opaque = irq_request_opaque;
   2.261 -    s->pics[0].pics_state = s;
   2.262 -    s->pics[1].pics_state = s;
   2.263      return; 
   2.264  }
   2.265  
   2.266 @@ -426,8 +487,12 @@ void pic_set_alt_irq_func(struct hvm_vir
   2.267                            void (*alt_irq_func)(void *, int, int),
   2.268                            void *alt_irq_opaque)
   2.269  {
   2.270 +    unsigned long flags;
   2.271 +
   2.272 +    spin_lock_irqsave(&s->lock, flags);
   2.273      s->alt_irq_func = alt_irq_func;
   2.274      s->alt_irq_opaque = alt_irq_opaque;
   2.275 +    spin_unlock_irqrestore(&s->lock, flags);
   2.276  }
   2.277  
   2.278  static int intercept_pic_io(ioreq_t *p)
   2.279 @@ -435,6 +500,7 @@ static int intercept_pic_io(ioreq_t *p)
   2.280      struct hvm_virpic  *pic;
   2.281      struct vcpu *v = current;
   2.282      uint32_t data;
   2.283 +    unsigned long flags;
   2.284      
   2.285      if ( p->size != 1 || p->count != 1) {
   2.286          printk("PIC_IO wrong access size %d!\n", (int)p->size);
   2.287 @@ -446,12 +512,16 @@ static int intercept_pic_io(ioreq_t *p)
   2.288              hvm_copy(&data, (unsigned long)p->u.pdata, p->size, HVM_COPY_IN);
   2.289          else
   2.290              data = p->u.data;
   2.291 +        spin_lock_irqsave(&pic->lock, flags);
   2.292          pic_ioport_write((void*)&pic->pics[p->addr>>7],
   2.293                  (uint32_t) p->addr, (uint32_t) (data & 0xff));
   2.294 +        spin_unlock_irqrestore(&pic->lock, flags);
   2.295      }
   2.296      else {
   2.297 +        spin_lock_irqsave(&pic->lock, flags);
   2.298          data = pic_ioport_read(
   2.299              (void*)&pic->pics[p->addr>>7], (uint32_t) p->addr);
   2.300 +        spin_unlock_irqrestore(&pic->lock, flags);
   2.301          if(p->pdata_valid) 
   2.302              hvm_copy(&data, (unsigned long)p->u.pdata, p->size, HVM_COPY_OUT);
   2.303          else 
   2.304 @@ -465,6 +535,7 @@ static int intercept_elcr_io(ioreq_t *p)
   2.305      struct hvm_virpic  *s;
   2.306      struct vcpu *v = current;
   2.307      uint32_t data;
   2.308 +    unsigned long flags;
   2.309      
   2.310      if ( p->size != 1 || p->count != 1 ) {
   2.311          printk("PIC_IO wrong access size %d!\n", (int)p->size);
   2.312 @@ -477,10 +548,12 @@ static int intercept_elcr_io(ioreq_t *p)
   2.313              hvm_copy(&data, (unsigned long)p->u.pdata, p->size, HVM_COPY_IN);
   2.314          else
   2.315              data = p->u.data;
   2.316 +        spin_lock_irqsave(&s->lock, flags);
   2.317          elcr_ioport_write((void*)&s->pics[p->addr&1],
   2.318                  (uint32_t) p->addr, (uint32_t)( data & 0xff));
   2.319      	get_sp(current->domain)->sp_global.pic_elcr = 
   2.320              s->pics[0].elcr | ((u16)s->pics[1].elcr << 8);
   2.321 +        spin_unlock_irqrestore(&s->lock, flags);
   2.322      }
   2.323      else {
   2.324          data = (u64) elcr_ioport_read(
   2.325 @@ -512,10 +585,9 @@ int cpu_get_pic_interrupt(struct vcpu *v
   2.326      if ( !vlapic_accept_pic_intr(v) )
   2.327          return -1;
   2.328  
   2.329 -    if ( !plat->interrupt_request )
   2.330 +    if (cmpxchg(&plat->interrupt_request, 1, 0) != 1)
   2.331          return -1;
   2.332  
   2.333 -    plat->interrupt_request = 0;
   2.334      /* read the irq from the PIC */
   2.335      intno = pic_read_irq(s);
   2.336      *type = VLAPIC_DELIV_MODE_EXT;
     3.1 --- a/xen/include/asm-x86/hvm/vpic.h	Tue May 16 19:50:23 2006 +0100
     3.2 +++ b/xen/include/asm-x86/hvm/vpic.h	Tue May 16 19:54:41 2006 +0100
     3.3 @@ -60,6 +60,7 @@ struct hvm_virpic {
     3.4      /* IOAPIC callback support */
     3.5      void (*alt_irq_func)(void *opaque, int irq_num, int level);
     3.6      void *alt_irq_opaque;
     3.7 +    spinlock_t lock;
     3.8  };
     3.9  
    3.10  
    3.11 @@ -72,7 +73,7 @@ void pic_set_alt_irq_func(struct hvm_vir
    3.12                            void (*alt_irq_func)(void *, int, int),
    3.13                            void *alt_irq_opaque);
    3.14  int pic_read_irq(struct hvm_virpic *s);
    3.15 -void pic_update_irq(struct hvm_virpic *s);
    3.16 +void pic_update_irq(struct hvm_virpic *s); /* Caller must hold s->lock */
    3.17  uint32_t pic_intack_read(struct hvm_virpic *s);
    3.18  void register_pic_io_hook (void);
    3.19  int cpu_get_pic_interrupt(struct vcpu *v, int *type);