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>
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);