diff options
Diffstat (limited to 'arch/x86/kvm/i8259.c')
-rw-r--r-- | arch/x86/kvm/i8259.c | 52 |
1 files changed, 48 insertions, 4 deletions
diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c index 17e41e165f1a..179dcb0103fd 100644 --- a/arch/x86/kvm/i8259.c +++ b/arch/x86/kvm/i8259.c | |||
@@ -26,10 +26,40 @@ | |||
26 | * Port from Qemu. | 26 | * Port from Qemu. |
27 | */ | 27 | */ |
28 | #include <linux/mm.h> | 28 | #include <linux/mm.h> |
29 | #include <linux/bitops.h> | ||
29 | #include "irq.h" | 30 | #include "irq.h" |
30 | 31 | ||
31 | #include <linux/kvm_host.h> | 32 | #include <linux/kvm_host.h> |
32 | 33 | ||
34 | static void pic_lock(struct kvm_pic *s) | ||
35 | { | ||
36 | spin_lock(&s->lock); | ||
37 | } | ||
38 | |||
39 | static void pic_unlock(struct kvm_pic *s) | ||
40 | { | ||
41 | struct kvm *kvm = s->kvm; | ||
42 | unsigned acks = s->pending_acks; | ||
43 | bool wakeup = s->wakeup_needed; | ||
44 | struct kvm_vcpu *vcpu; | ||
45 | |||
46 | s->pending_acks = 0; | ||
47 | s->wakeup_needed = false; | ||
48 | |||
49 | spin_unlock(&s->lock); | ||
50 | |||
51 | while (acks) { | ||
52 | kvm_notify_acked_irq(kvm, __ffs(acks)); | ||
53 | acks &= acks - 1; | ||
54 | } | ||
55 | |||
56 | if (wakeup) { | ||
57 | vcpu = s->kvm->vcpus[0]; | ||
58 | if (vcpu) | ||
59 | kvm_vcpu_kick(vcpu); | ||
60 | } | ||
61 | } | ||
62 | |||
33 | static void pic_clear_isr(struct kvm_kpic_state *s, int irq) | 63 | static void pic_clear_isr(struct kvm_kpic_state *s, int irq) |
34 | { | 64 | { |
35 | s->isr &= ~(1 << irq); | 65 | s->isr &= ~(1 << irq); |
@@ -136,17 +166,21 @@ static void pic_update_irq(struct kvm_pic *s) | |||
136 | 166 | ||
137 | void kvm_pic_update_irq(struct kvm_pic *s) | 167 | void kvm_pic_update_irq(struct kvm_pic *s) |
138 | { | 168 | { |
169 | pic_lock(s); | ||
139 | pic_update_irq(s); | 170 | pic_update_irq(s); |
171 | pic_unlock(s); | ||
140 | } | 172 | } |
141 | 173 | ||
142 | void kvm_pic_set_irq(void *opaque, int irq, int level) | 174 | void kvm_pic_set_irq(void *opaque, int irq, int level) |
143 | { | 175 | { |
144 | struct kvm_pic *s = opaque; | 176 | struct kvm_pic *s = opaque; |
145 | 177 | ||
178 | pic_lock(s); | ||
146 | if (irq >= 0 && irq < PIC_NUM_PINS) { | 179 | if (irq >= 0 && irq < PIC_NUM_PINS) { |
147 | pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); | 180 | pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); |
148 | pic_update_irq(s); | 181 | pic_update_irq(s); |
149 | } | 182 | } |
183 | pic_unlock(s); | ||
150 | } | 184 | } |
151 | 185 | ||
152 | /* | 186 | /* |
@@ -172,6 +206,7 @@ int kvm_pic_read_irq(struct kvm *kvm) | |||
172 | int irq, irq2, intno; | 206 | int irq, irq2, intno; |
173 | struct kvm_pic *s = pic_irqchip(kvm); | 207 | struct kvm_pic *s = pic_irqchip(kvm); |
174 | 208 | ||
209 | pic_lock(s); | ||
175 | irq = pic_get_irq(&s->pics[0]); | 210 | irq = pic_get_irq(&s->pics[0]); |
176 | if (irq >= 0) { | 211 | if (irq >= 0) { |
177 | pic_intack(&s->pics[0], irq); | 212 | pic_intack(&s->pics[0], irq); |
@@ -196,6 +231,7 @@ int kvm_pic_read_irq(struct kvm *kvm) | |||
196 | intno = s->pics[0].irq_base + irq; | 231 | intno = s->pics[0].irq_base + irq; |
197 | } | 232 | } |
198 | pic_update_irq(s); | 233 | pic_update_irq(s); |
234 | pic_unlock(s); | ||
199 | kvm_notify_acked_irq(kvm, irq); | 235 | kvm_notify_acked_irq(kvm, irq); |
200 | 236 | ||
201 | return intno; | 237 | return intno; |
@@ -203,7 +239,7 @@ int kvm_pic_read_irq(struct kvm *kvm) | |||
203 | 239 | ||
204 | void kvm_pic_reset(struct kvm_kpic_state *s) | 240 | void kvm_pic_reset(struct kvm_kpic_state *s) |
205 | { | 241 | { |
206 | int irq, irqbase; | 242 | int irq, irqbase, n; |
207 | struct kvm *kvm = s->pics_state->irq_request_opaque; | 243 | struct kvm *kvm = s->pics_state->irq_request_opaque; |
208 | struct kvm_vcpu *vcpu0 = kvm->vcpus[0]; | 244 | struct kvm_vcpu *vcpu0 = kvm->vcpus[0]; |
209 | 245 | ||
@@ -214,8 +250,10 @@ void kvm_pic_reset(struct kvm_kpic_state *s) | |||
214 | 250 | ||
215 | for (irq = 0; irq < PIC_NUM_PINS/2; irq++) { | 251 | for (irq = 0; irq < PIC_NUM_PINS/2; irq++) { |
216 | if (vcpu0 && kvm_apic_accept_pic_intr(vcpu0)) | 252 | if (vcpu0 && kvm_apic_accept_pic_intr(vcpu0)) |
217 | if (s->irr & (1 << irq) || s->isr & (1 << irq)) | 253 | if (s->irr & (1 << irq) || s->isr & (1 << irq)) { |
218 | kvm_notify_acked_irq(kvm, irq+irqbase); | 254 | n = irq + irqbase; |
255 | s->pics_state->pending_acks |= 1 << n; | ||
256 | } | ||
219 | } | 257 | } |
220 | s->last_irr = 0; | 258 | s->last_irr = 0; |
221 | s->irr = 0; | 259 | s->irr = 0; |
@@ -406,6 +444,7 @@ static void picdev_write(struct kvm_io_device *this, | |||
406 | printk(KERN_ERR "PIC: non byte write\n"); | 444 | printk(KERN_ERR "PIC: non byte write\n"); |
407 | return; | 445 | return; |
408 | } | 446 | } |
447 | pic_lock(s); | ||
409 | switch (addr) { | 448 | switch (addr) { |
410 | case 0x20: | 449 | case 0x20: |
411 | case 0x21: | 450 | case 0x21: |
@@ -418,6 +457,7 @@ static void picdev_write(struct kvm_io_device *this, | |||
418 | elcr_ioport_write(&s->pics[addr & 1], addr, data); | 457 | elcr_ioport_write(&s->pics[addr & 1], addr, data); |
419 | break; | 458 | break; |
420 | } | 459 | } |
460 | pic_unlock(s); | ||
421 | } | 461 | } |
422 | 462 | ||
423 | static void picdev_read(struct kvm_io_device *this, | 463 | static void picdev_read(struct kvm_io_device *this, |
@@ -431,6 +471,7 @@ static void picdev_read(struct kvm_io_device *this, | |||
431 | printk(KERN_ERR "PIC: non byte read\n"); | 471 | printk(KERN_ERR "PIC: non byte read\n"); |
432 | return; | 472 | return; |
433 | } | 473 | } |
474 | pic_lock(s); | ||
434 | switch (addr) { | 475 | switch (addr) { |
435 | case 0x20: | 476 | case 0x20: |
436 | case 0x21: | 477 | case 0x21: |
@@ -444,6 +485,7 @@ static void picdev_read(struct kvm_io_device *this, | |||
444 | break; | 485 | break; |
445 | } | 486 | } |
446 | *(unsigned char *)val = data; | 487 | *(unsigned char *)val = data; |
488 | pic_unlock(s); | ||
447 | } | 489 | } |
448 | 490 | ||
449 | /* | 491 | /* |
@@ -459,7 +501,7 @@ static void pic_irq_request(void *opaque, int level) | |||
459 | s->output = level; | 501 | s->output = level; |
460 | if (vcpu && level && (s->pics[0].isr_ack & (1 << irq))) { | 502 | if (vcpu && level && (s->pics[0].isr_ack & (1 << irq))) { |
461 | s->pics[0].isr_ack &= ~(1 << irq); | 503 | s->pics[0].isr_ack &= ~(1 << irq); |
462 | kvm_vcpu_kick(vcpu); | 504 | s->wakeup_needed = true; |
463 | } | 505 | } |
464 | } | 506 | } |
465 | 507 | ||
@@ -469,6 +511,8 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm) | |||
469 | s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL); | 511 | s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL); |
470 | if (!s) | 512 | if (!s) |
471 | return NULL; | 513 | return NULL; |
514 | spin_lock_init(&s->lock); | ||
515 | s->kvm = kvm; | ||
472 | s->pics[0].elcr_mask = 0xf8; | 516 | s->pics[0].elcr_mask = 0xf8; |
473 | s->pics[1].elcr_mask = 0xde; | 517 | s->pics[1].elcr_mask = 0xde; |
474 | s->irq_request = pic_irq_request; | 518 | s->irq_request = pic_irq_request; |