diff options
| -rw-r--r-- | arch/x86/kvm/i8259.c | 52 | ||||
| -rw-r--r-- | arch/x86/kvm/irq.h | 5 |
2 files changed, 53 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; |
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h index b9e9051650ea..2bf32a03ceec 100644 --- a/arch/x86/kvm/irq.h +++ b/arch/x86/kvm/irq.h | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/mm_types.h> | 25 | #include <linux/mm_types.h> |
| 26 | #include <linux/hrtimer.h> | 26 | #include <linux/hrtimer.h> |
| 27 | #include <linux/kvm_host.h> | 27 | #include <linux/kvm_host.h> |
| 28 | #include <linux/spinlock.h> | ||
| 28 | 29 | ||
| 29 | #include "iodev.h" | 30 | #include "iodev.h" |
| 30 | #include "ioapic.h" | 31 | #include "ioapic.h" |
| @@ -59,6 +60,10 @@ struct kvm_kpic_state { | |||
| 59 | }; | 60 | }; |
| 60 | 61 | ||
| 61 | struct kvm_pic { | 62 | struct kvm_pic { |
| 63 | spinlock_t lock; | ||
| 64 | bool wakeup_needed; | ||
| 65 | unsigned pending_acks; | ||
| 66 | struct kvm *kvm; | ||
| 62 | struct kvm_kpic_state pics[2]; /* 0 is master pic, 1 is slave pic */ | 67 | struct kvm_kpic_state pics[2]; /* 0 is master pic, 1 is slave pic */ |
| 63 | irq_request_func *irq_request; | 68 | irq_request_func *irq_request; |
| 64 | void *irq_request_opaque; | 69 | void *irq_request_opaque; |
