diff options
Diffstat (limited to 'arch/x86/kvm/i8259.c')
-rw-r--r-- | arch/x86/kvm/i8259.c | 87 |
1 files changed, 54 insertions, 33 deletions
diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c index 01f151682802..a790fa128a9f 100644 --- a/arch/x86/kvm/i8259.c +++ b/arch/x86/kvm/i8259.c | |||
@@ -26,6 +26,7 @@ | |||
26 | * Port from Qemu. | 26 | * Port from Qemu. |
27 | */ | 27 | */ |
28 | #include <linux/mm.h> | 28 | #include <linux/mm.h> |
29 | #include <linux/slab.h> | ||
29 | #include <linux/bitops.h> | 30 | #include <linux/bitops.h> |
30 | #include "irq.h" | 31 | #include "irq.h" |
31 | 32 | ||
@@ -38,16 +39,25 @@ static void pic_clear_isr(struct kvm_kpic_state *s, int irq) | |||
38 | s->isr_ack |= (1 << irq); | 39 | s->isr_ack |= (1 << irq); |
39 | if (s != &s->pics_state->pics[0]) | 40 | if (s != &s->pics_state->pics[0]) |
40 | irq += 8; | 41 | irq += 8; |
42 | /* | ||
43 | * We are dropping lock while calling ack notifiers since ack | ||
44 | * notifier callbacks for assigned devices call into PIC recursively. | ||
45 | * Other interrupt may be delivered to PIC while lock is dropped but | ||
46 | * it should be safe since PIC state is already updated at this stage. | ||
47 | */ | ||
48 | raw_spin_unlock(&s->pics_state->lock); | ||
41 | kvm_notify_acked_irq(s->pics_state->kvm, SELECT_PIC(irq), irq); | 49 | kvm_notify_acked_irq(s->pics_state->kvm, SELECT_PIC(irq), irq); |
50 | raw_spin_lock(&s->pics_state->lock); | ||
42 | } | 51 | } |
43 | 52 | ||
44 | void kvm_pic_clear_isr_ack(struct kvm *kvm) | 53 | void kvm_pic_clear_isr_ack(struct kvm *kvm) |
45 | { | 54 | { |
46 | struct kvm_pic *s = pic_irqchip(kvm); | 55 | struct kvm_pic *s = pic_irqchip(kvm); |
47 | spin_lock(&s->lock); | 56 | |
57 | raw_spin_lock(&s->lock); | ||
48 | s->pics[0].isr_ack = 0xff; | 58 | s->pics[0].isr_ack = 0xff; |
49 | s->pics[1].isr_ack = 0xff; | 59 | s->pics[1].isr_ack = 0xff; |
50 | spin_unlock(&s->lock); | 60 | raw_spin_unlock(&s->lock); |
51 | } | 61 | } |
52 | 62 | ||
53 | /* | 63 | /* |
@@ -148,9 +158,9 @@ static void pic_update_irq(struct kvm_pic *s) | |||
148 | 158 | ||
149 | void kvm_pic_update_irq(struct kvm_pic *s) | 159 | void kvm_pic_update_irq(struct kvm_pic *s) |
150 | { | 160 | { |
151 | spin_lock(&s->lock); | 161 | raw_spin_lock(&s->lock); |
152 | pic_update_irq(s); | 162 | pic_update_irq(s); |
153 | spin_unlock(&s->lock); | 163 | raw_spin_unlock(&s->lock); |
154 | } | 164 | } |
155 | 165 | ||
156 | int kvm_pic_set_irq(void *opaque, int irq, int level) | 166 | int kvm_pic_set_irq(void *opaque, int irq, int level) |
@@ -158,14 +168,14 @@ int kvm_pic_set_irq(void *opaque, int irq, int level) | |||
158 | struct kvm_pic *s = opaque; | 168 | struct kvm_pic *s = opaque; |
159 | int ret = -1; | 169 | int ret = -1; |
160 | 170 | ||
161 | spin_lock(&s->lock); | 171 | raw_spin_lock(&s->lock); |
162 | if (irq >= 0 && irq < PIC_NUM_PINS) { | 172 | if (irq >= 0 && irq < PIC_NUM_PINS) { |
163 | ret = pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); | 173 | ret = pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); |
164 | pic_update_irq(s); | 174 | pic_update_irq(s); |
165 | trace_kvm_pic_set_irq(irq >> 3, irq & 7, s->pics[irq >> 3].elcr, | 175 | trace_kvm_pic_set_irq(irq >> 3, irq & 7, s->pics[irq >> 3].elcr, |
166 | s->pics[irq >> 3].imr, ret == 0); | 176 | s->pics[irq >> 3].imr, ret == 0); |
167 | } | 177 | } |
168 | spin_unlock(&s->lock); | 178 | raw_spin_unlock(&s->lock); |
169 | 179 | ||
170 | return ret; | 180 | return ret; |
171 | } | 181 | } |
@@ -176,16 +186,18 @@ int kvm_pic_set_irq(void *opaque, int irq, int level) | |||
176 | static inline void pic_intack(struct kvm_kpic_state *s, int irq) | 186 | static inline void pic_intack(struct kvm_kpic_state *s, int irq) |
177 | { | 187 | { |
178 | s->isr |= 1 << irq; | 188 | s->isr |= 1 << irq; |
179 | if (s->auto_eoi) { | ||
180 | if (s->rotate_on_auto_eoi) | ||
181 | s->priority_add = (irq + 1) & 7; | ||
182 | pic_clear_isr(s, irq); | ||
183 | } | ||
184 | /* | 189 | /* |
185 | * We don't clear a level sensitive interrupt here | 190 | * We don't clear a level sensitive interrupt here |
186 | */ | 191 | */ |
187 | if (!(s->elcr & (1 << irq))) | 192 | if (!(s->elcr & (1 << irq))) |
188 | s->irr &= ~(1 << irq); | 193 | s->irr &= ~(1 << irq); |
194 | |||
195 | if (s->auto_eoi) { | ||
196 | if (s->rotate_on_auto_eoi) | ||
197 | s->priority_add = (irq + 1) & 7; | ||
198 | pic_clear_isr(s, irq); | ||
199 | } | ||
200 | |||
189 | } | 201 | } |
190 | 202 | ||
191 | int kvm_pic_read_irq(struct kvm *kvm) | 203 | int kvm_pic_read_irq(struct kvm *kvm) |
@@ -193,7 +205,7 @@ int kvm_pic_read_irq(struct kvm *kvm) | |||
193 | int irq, irq2, intno; | 205 | int irq, irq2, intno; |
194 | struct kvm_pic *s = pic_irqchip(kvm); | 206 | struct kvm_pic *s = pic_irqchip(kvm); |
195 | 207 | ||
196 | spin_lock(&s->lock); | 208 | raw_spin_lock(&s->lock); |
197 | irq = pic_get_irq(&s->pics[0]); | 209 | irq = pic_get_irq(&s->pics[0]); |
198 | if (irq >= 0) { | 210 | if (irq >= 0) { |
199 | pic_intack(&s->pics[0], irq); | 211 | pic_intack(&s->pics[0], irq); |
@@ -218,29 +230,18 @@ int kvm_pic_read_irq(struct kvm *kvm) | |||
218 | intno = s->pics[0].irq_base + irq; | 230 | intno = s->pics[0].irq_base + irq; |
219 | } | 231 | } |
220 | pic_update_irq(s); | 232 | pic_update_irq(s); |
221 | spin_unlock(&s->lock); | 233 | raw_spin_unlock(&s->lock); |
222 | 234 | ||
223 | return intno; | 235 | return intno; |
224 | } | 236 | } |
225 | 237 | ||
226 | void kvm_pic_reset(struct kvm_kpic_state *s) | 238 | void kvm_pic_reset(struct kvm_kpic_state *s) |
227 | { | 239 | { |
228 | int irq, irqbase, n; | 240 | int irq; |
229 | struct kvm *kvm = s->pics_state->irq_request_opaque; | 241 | struct kvm *kvm = s->pics_state->irq_request_opaque; |
230 | struct kvm_vcpu *vcpu0 = kvm->bsp_vcpu; | 242 | struct kvm_vcpu *vcpu0 = kvm->bsp_vcpu; |
243 | u8 irr = s->irr, isr = s->imr; | ||
231 | 244 | ||
232 | if (s == &s->pics_state->pics[0]) | ||
233 | irqbase = 0; | ||
234 | else | ||
235 | irqbase = 8; | ||
236 | |||
237 | for (irq = 0; irq < PIC_NUM_PINS/2; irq++) { | ||
238 | if (vcpu0 && kvm_apic_accept_pic_intr(vcpu0)) | ||
239 | if (s->irr & (1 << irq) || s->isr & (1 << irq)) { | ||
240 | n = irq + irqbase; | ||
241 | kvm_notify_acked_irq(kvm, SELECT_PIC(n), n); | ||
242 | } | ||
243 | } | ||
244 | s->last_irr = 0; | 245 | s->last_irr = 0; |
245 | s->irr = 0; | 246 | s->irr = 0; |
246 | s->imr = 0; | 247 | s->imr = 0; |
@@ -256,6 +257,13 @@ void kvm_pic_reset(struct kvm_kpic_state *s) | |||
256 | s->rotate_on_auto_eoi = 0; | 257 | s->rotate_on_auto_eoi = 0; |
257 | s->special_fully_nested_mode = 0; | 258 | s->special_fully_nested_mode = 0; |
258 | s->init4 = 0; | 259 | s->init4 = 0; |
260 | |||
261 | for (irq = 0; irq < PIC_NUM_PINS/2; irq++) { | ||
262 | if (vcpu0 && kvm_apic_accept_pic_intr(vcpu0)) | ||
263 | if (irr & (1 << irq) || isr & (1 << irq)) { | ||
264 | pic_clear_isr(s, irq); | ||
265 | } | ||
266 | } | ||
259 | } | 267 | } |
260 | 268 | ||
261 | static void pic_ioport_write(void *opaque, u32 addr, u32 val) | 269 | static void pic_ioport_write(void *opaque, u32 addr, u32 val) |
@@ -298,9 +306,9 @@ static void pic_ioport_write(void *opaque, u32 addr, u32 val) | |||
298 | priority = get_priority(s, s->isr); | 306 | priority = get_priority(s, s->isr); |
299 | if (priority != 8) { | 307 | if (priority != 8) { |
300 | irq = (priority + s->priority_add) & 7; | 308 | irq = (priority + s->priority_add) & 7; |
301 | pic_clear_isr(s, irq); | ||
302 | if (cmd == 5) | 309 | if (cmd == 5) |
303 | s->priority_add = (irq + 1) & 7; | 310 | s->priority_add = (irq + 1) & 7; |
311 | pic_clear_isr(s, irq); | ||
304 | pic_update_irq(s->pics_state); | 312 | pic_update_irq(s->pics_state); |
305 | } | 313 | } |
306 | break; | 314 | break; |
@@ -436,7 +444,7 @@ static int picdev_write(struct kvm_io_device *this, | |||
436 | printk(KERN_ERR "PIC: non byte write\n"); | 444 | printk(KERN_ERR "PIC: non byte write\n"); |
437 | return 0; | 445 | return 0; |
438 | } | 446 | } |
439 | spin_lock(&s->lock); | 447 | raw_spin_lock(&s->lock); |
440 | switch (addr) { | 448 | switch (addr) { |
441 | case 0x20: | 449 | case 0x20: |
442 | case 0x21: | 450 | case 0x21: |
@@ -449,7 +457,7 @@ static int picdev_write(struct kvm_io_device *this, | |||
449 | elcr_ioport_write(&s->pics[addr & 1], addr, data); | 457 | elcr_ioport_write(&s->pics[addr & 1], addr, data); |
450 | break; | 458 | break; |
451 | } | 459 | } |
452 | spin_unlock(&s->lock); | 460 | raw_spin_unlock(&s->lock); |
453 | return 0; | 461 | return 0; |
454 | } | 462 | } |
455 | 463 | ||
@@ -466,7 +474,7 @@ static int picdev_read(struct kvm_io_device *this, | |||
466 | printk(KERN_ERR "PIC: non byte read\n"); | 474 | printk(KERN_ERR "PIC: non byte read\n"); |
467 | return 0; | 475 | return 0; |
468 | } | 476 | } |
469 | spin_lock(&s->lock); | 477 | raw_spin_lock(&s->lock); |
470 | switch (addr) { | 478 | switch (addr) { |
471 | case 0x20: | 479 | case 0x20: |
472 | case 0x21: | 480 | case 0x21: |
@@ -480,7 +488,7 @@ static int picdev_read(struct kvm_io_device *this, | |||
480 | break; | 488 | break; |
481 | } | 489 | } |
482 | *(unsigned char *)val = data; | 490 | *(unsigned char *)val = data; |
483 | spin_unlock(&s->lock); | 491 | raw_spin_unlock(&s->lock); |
484 | return 0; | 492 | return 0; |
485 | } | 493 | } |
486 | 494 | ||
@@ -514,7 +522,7 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm) | |||
514 | s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL); | 522 | s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL); |
515 | if (!s) | 523 | if (!s) |
516 | return NULL; | 524 | return NULL; |
517 | spin_lock_init(&s->lock); | 525 | raw_spin_lock_init(&s->lock); |
518 | s->kvm = kvm; | 526 | s->kvm = kvm; |
519 | s->pics[0].elcr_mask = 0xf8; | 527 | s->pics[0].elcr_mask = 0xf8; |
520 | s->pics[1].elcr_mask = 0xde; | 528 | s->pics[1].elcr_mask = 0xde; |
@@ -527,7 +535,9 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm) | |||
527 | * Initialize PIO device | 535 | * Initialize PIO device |
528 | */ | 536 | */ |
529 | kvm_iodevice_init(&s->dev, &picdev_ops); | 537 | kvm_iodevice_init(&s->dev, &picdev_ops); |
530 | ret = kvm_io_bus_register_dev(kvm, &kvm->pio_bus, &s->dev); | 538 | mutex_lock(&kvm->slots_lock); |
539 | ret = kvm_io_bus_register_dev(kvm, KVM_PIO_BUS, &s->dev); | ||
540 | mutex_unlock(&kvm->slots_lock); | ||
531 | if (ret < 0) { | 541 | if (ret < 0) { |
532 | kfree(s); | 542 | kfree(s); |
533 | return NULL; | 543 | return NULL; |
@@ -535,3 +545,14 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm) | |||
535 | 545 | ||
536 | return s; | 546 | return s; |
537 | } | 547 | } |
548 | |||
549 | void kvm_destroy_pic(struct kvm *kvm) | ||
550 | { | ||
551 | struct kvm_pic *vpic = kvm->arch.vpic; | ||
552 | |||
553 | if (vpic) { | ||
554 | kvm_io_bus_unregister_dev(kvm, KVM_PIO_BUS, &vpic->dev); | ||
555 | kvm->arch.vpic = NULL; | ||
556 | kfree(vpic); | ||
557 | } | ||
558 | } | ||