diff options
Diffstat (limited to 'arch/x86/kvm/i8259.c')
-rw-r--r-- | arch/x86/kvm/i8259.c | 116 |
1 files changed, 55 insertions, 61 deletions
diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c index 1ccb50c74f18..01f151682802 100644 --- a/arch/x86/kvm/i8259.c +++ b/arch/x86/kvm/i8259.c | |||
@@ -30,50 +30,24 @@ | |||
30 | #include "irq.h" | 30 | #include "irq.h" |
31 | 31 | ||
32 | #include <linux/kvm_host.h> | 32 | #include <linux/kvm_host.h> |
33 | 33 | #include "trace.h" | |
34 | static void pic_lock(struct kvm_pic *s) | ||
35 | __acquires(&s->lock) | ||
36 | { | ||
37 | spin_lock(&s->lock); | ||
38 | } | ||
39 | |||
40 | static void pic_unlock(struct kvm_pic *s) | ||
41 | __releases(&s->lock) | ||
42 | { | ||
43 | struct kvm *kvm = s->kvm; | ||
44 | unsigned acks = s->pending_acks; | ||
45 | bool wakeup = s->wakeup_needed; | ||
46 | struct kvm_vcpu *vcpu; | ||
47 | |||
48 | s->pending_acks = 0; | ||
49 | s->wakeup_needed = false; | ||
50 | |||
51 | spin_unlock(&s->lock); | ||
52 | |||
53 | while (acks) { | ||
54 | kvm_notify_acked_irq(kvm, SELECT_PIC(__ffs(acks)), | ||
55 | __ffs(acks)); | ||
56 | acks &= acks - 1; | ||
57 | } | ||
58 | |||
59 | if (wakeup) { | ||
60 | vcpu = s->kvm->vcpus[0]; | ||
61 | if (vcpu) | ||
62 | kvm_vcpu_kick(vcpu); | ||
63 | } | ||
64 | } | ||
65 | 34 | ||
66 | static void pic_clear_isr(struct kvm_kpic_state *s, int irq) | 35 | static void pic_clear_isr(struct kvm_kpic_state *s, int irq) |
67 | { | 36 | { |
68 | s->isr &= ~(1 << irq); | 37 | s->isr &= ~(1 << irq); |
69 | s->isr_ack |= (1 << irq); | 38 | s->isr_ack |= (1 << irq); |
39 | if (s != &s->pics_state->pics[0]) | ||
40 | irq += 8; | ||
41 | kvm_notify_acked_irq(s->pics_state->kvm, SELECT_PIC(irq), irq); | ||
70 | } | 42 | } |
71 | 43 | ||
72 | void kvm_pic_clear_isr_ack(struct kvm *kvm) | 44 | void kvm_pic_clear_isr_ack(struct kvm *kvm) |
73 | { | 45 | { |
74 | struct kvm_pic *s = pic_irqchip(kvm); | 46 | struct kvm_pic *s = pic_irqchip(kvm); |
47 | spin_lock(&s->lock); | ||
75 | s->pics[0].isr_ack = 0xff; | 48 | s->pics[0].isr_ack = 0xff; |
76 | s->pics[1].isr_ack = 0xff; | 49 | s->pics[1].isr_ack = 0xff; |
50 | spin_unlock(&s->lock); | ||
77 | } | 51 | } |
78 | 52 | ||
79 | /* | 53 | /* |
@@ -174,9 +148,9 @@ static void pic_update_irq(struct kvm_pic *s) | |||
174 | 148 | ||
175 | void kvm_pic_update_irq(struct kvm_pic *s) | 149 | void kvm_pic_update_irq(struct kvm_pic *s) |
176 | { | 150 | { |
177 | pic_lock(s); | 151 | spin_lock(&s->lock); |
178 | pic_update_irq(s); | 152 | pic_update_irq(s); |
179 | pic_unlock(s); | 153 | spin_unlock(&s->lock); |
180 | } | 154 | } |
181 | 155 | ||
182 | int kvm_pic_set_irq(void *opaque, int irq, int level) | 156 | int kvm_pic_set_irq(void *opaque, int irq, int level) |
@@ -184,12 +158,14 @@ int kvm_pic_set_irq(void *opaque, int irq, int level) | |||
184 | struct kvm_pic *s = opaque; | 158 | struct kvm_pic *s = opaque; |
185 | int ret = -1; | 159 | int ret = -1; |
186 | 160 | ||
187 | pic_lock(s); | 161 | spin_lock(&s->lock); |
188 | if (irq >= 0 && irq < PIC_NUM_PINS) { | 162 | if (irq >= 0 && irq < PIC_NUM_PINS) { |
189 | ret = pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); | 163 | ret = pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); |
190 | pic_update_irq(s); | 164 | pic_update_irq(s); |
165 | trace_kvm_pic_set_irq(irq >> 3, irq & 7, s->pics[irq >> 3].elcr, | ||
166 | s->pics[irq >> 3].imr, ret == 0); | ||
191 | } | 167 | } |
192 | pic_unlock(s); | 168 | spin_unlock(&s->lock); |
193 | 169 | ||
194 | return ret; | 170 | return ret; |
195 | } | 171 | } |
@@ -217,7 +193,7 @@ int kvm_pic_read_irq(struct kvm *kvm) | |||
217 | int irq, irq2, intno; | 193 | int irq, irq2, intno; |
218 | struct kvm_pic *s = pic_irqchip(kvm); | 194 | struct kvm_pic *s = pic_irqchip(kvm); |
219 | 195 | ||
220 | pic_lock(s); | 196 | spin_lock(&s->lock); |
221 | irq = pic_get_irq(&s->pics[0]); | 197 | irq = pic_get_irq(&s->pics[0]); |
222 | if (irq >= 0) { | 198 | if (irq >= 0) { |
223 | pic_intack(&s->pics[0], irq); | 199 | pic_intack(&s->pics[0], irq); |
@@ -242,8 +218,7 @@ int kvm_pic_read_irq(struct kvm *kvm) | |||
242 | intno = s->pics[0].irq_base + irq; | 218 | intno = s->pics[0].irq_base + irq; |
243 | } | 219 | } |
244 | pic_update_irq(s); | 220 | pic_update_irq(s); |
245 | pic_unlock(s); | 221 | spin_unlock(&s->lock); |
246 | kvm_notify_acked_irq(kvm, SELECT_PIC(irq), irq); | ||
247 | 222 | ||
248 | return intno; | 223 | return intno; |
249 | } | 224 | } |
@@ -252,7 +227,7 @@ void kvm_pic_reset(struct kvm_kpic_state *s) | |||
252 | { | 227 | { |
253 | int irq, irqbase, n; | 228 | int irq, irqbase, n; |
254 | struct kvm *kvm = s->pics_state->irq_request_opaque; | 229 | struct kvm *kvm = s->pics_state->irq_request_opaque; |
255 | struct kvm_vcpu *vcpu0 = kvm->vcpus[0]; | 230 | struct kvm_vcpu *vcpu0 = kvm->bsp_vcpu; |
256 | 231 | ||
257 | if (s == &s->pics_state->pics[0]) | 232 | if (s == &s->pics_state->pics[0]) |
258 | irqbase = 0; | 233 | irqbase = 0; |
@@ -263,7 +238,7 @@ void kvm_pic_reset(struct kvm_kpic_state *s) | |||
263 | if (vcpu0 && kvm_apic_accept_pic_intr(vcpu0)) | 238 | if (vcpu0 && kvm_apic_accept_pic_intr(vcpu0)) |
264 | if (s->irr & (1 << irq) || s->isr & (1 << irq)) { | 239 | if (s->irr & (1 << irq) || s->isr & (1 << irq)) { |
265 | n = irq + irqbase; | 240 | n = irq + irqbase; |
266 | s->pics_state->pending_acks |= 1 << n; | 241 | kvm_notify_acked_irq(kvm, SELECT_PIC(n), n); |
267 | } | 242 | } |
268 | } | 243 | } |
269 | s->last_irr = 0; | 244 | s->last_irr = 0; |
@@ -428,8 +403,7 @@ static u32 elcr_ioport_read(void *opaque, u32 addr1) | |||
428 | return s->elcr; | 403 | return s->elcr; |
429 | } | 404 | } |
430 | 405 | ||
431 | static int picdev_in_range(struct kvm_io_device *this, gpa_t addr, | 406 | static int picdev_in_range(gpa_t addr) |
432 | int len, int is_write) | ||
433 | { | 407 | { |
434 | switch (addr) { | 408 | switch (addr) { |
435 | case 0x20: | 409 | case 0x20: |
@@ -444,18 +418,25 @@ static int picdev_in_range(struct kvm_io_device *this, gpa_t addr, | |||
444 | } | 418 | } |
445 | } | 419 | } |
446 | 420 | ||
447 | static void picdev_write(struct kvm_io_device *this, | 421 | static inline struct kvm_pic *to_pic(struct kvm_io_device *dev) |
422 | { | ||
423 | return container_of(dev, struct kvm_pic, dev); | ||
424 | } | ||
425 | |||
426 | static int picdev_write(struct kvm_io_device *this, | ||
448 | gpa_t addr, int len, const void *val) | 427 | gpa_t addr, int len, const void *val) |
449 | { | 428 | { |
450 | struct kvm_pic *s = this->private; | 429 | struct kvm_pic *s = to_pic(this); |
451 | unsigned char data = *(unsigned char *)val; | 430 | unsigned char data = *(unsigned char *)val; |
431 | if (!picdev_in_range(addr)) | ||
432 | return -EOPNOTSUPP; | ||
452 | 433 | ||
453 | if (len != 1) { | 434 | if (len != 1) { |
454 | if (printk_ratelimit()) | 435 | if (printk_ratelimit()) |
455 | printk(KERN_ERR "PIC: non byte write\n"); | 436 | printk(KERN_ERR "PIC: non byte write\n"); |
456 | return; | 437 | return 0; |
457 | } | 438 | } |
458 | pic_lock(s); | 439 | spin_lock(&s->lock); |
459 | switch (addr) { | 440 | switch (addr) { |
460 | case 0x20: | 441 | case 0x20: |
461 | case 0x21: | 442 | case 0x21: |
@@ -468,21 +449,24 @@ static void picdev_write(struct kvm_io_device *this, | |||
468 | elcr_ioport_write(&s->pics[addr & 1], addr, data); | 449 | elcr_ioport_write(&s->pics[addr & 1], addr, data); |
469 | break; | 450 | break; |
470 | } | 451 | } |
471 | pic_unlock(s); | 452 | spin_unlock(&s->lock); |
453 | return 0; | ||
472 | } | 454 | } |
473 | 455 | ||
474 | static void picdev_read(struct kvm_io_device *this, | 456 | static int picdev_read(struct kvm_io_device *this, |
475 | gpa_t addr, int len, void *val) | 457 | gpa_t addr, int len, void *val) |
476 | { | 458 | { |
477 | struct kvm_pic *s = this->private; | 459 | struct kvm_pic *s = to_pic(this); |
478 | unsigned char data = 0; | 460 | unsigned char data = 0; |
461 | if (!picdev_in_range(addr)) | ||
462 | return -EOPNOTSUPP; | ||
479 | 463 | ||
480 | if (len != 1) { | 464 | if (len != 1) { |
481 | if (printk_ratelimit()) | 465 | if (printk_ratelimit()) |
482 | printk(KERN_ERR "PIC: non byte read\n"); | 466 | printk(KERN_ERR "PIC: non byte read\n"); |
483 | return; | 467 | return 0; |
484 | } | 468 | } |
485 | pic_lock(s); | 469 | spin_lock(&s->lock); |
486 | switch (addr) { | 470 | switch (addr) { |
487 | case 0x20: | 471 | case 0x20: |
488 | case 0x21: | 472 | case 0x21: |
@@ -496,7 +480,8 @@ static void picdev_read(struct kvm_io_device *this, | |||
496 | break; | 480 | break; |
497 | } | 481 | } |
498 | *(unsigned char *)val = data; | 482 | *(unsigned char *)val = data; |
499 | pic_unlock(s); | 483 | spin_unlock(&s->lock); |
484 | return 0; | ||
500 | } | 485 | } |
501 | 486 | ||
502 | /* | 487 | /* |
@@ -505,20 +490,27 @@ static void picdev_read(struct kvm_io_device *this, | |||
505 | static void pic_irq_request(void *opaque, int level) | 490 | static void pic_irq_request(void *opaque, int level) |
506 | { | 491 | { |
507 | struct kvm *kvm = opaque; | 492 | struct kvm *kvm = opaque; |
508 | struct kvm_vcpu *vcpu = kvm->vcpus[0]; | 493 | struct kvm_vcpu *vcpu = kvm->bsp_vcpu; |
509 | struct kvm_pic *s = pic_irqchip(kvm); | 494 | struct kvm_pic *s = pic_irqchip(kvm); |
510 | int irq = pic_get_irq(&s->pics[0]); | 495 | int irq = pic_get_irq(&s->pics[0]); |
511 | 496 | ||
512 | s->output = level; | 497 | s->output = level; |
513 | if (vcpu && level && (s->pics[0].isr_ack & (1 << irq))) { | 498 | if (vcpu && level && (s->pics[0].isr_ack & (1 << irq))) { |
514 | s->pics[0].isr_ack &= ~(1 << irq); | 499 | s->pics[0].isr_ack &= ~(1 << irq); |
515 | s->wakeup_needed = true; | 500 | kvm_vcpu_kick(vcpu); |
516 | } | 501 | } |
517 | } | 502 | } |
518 | 503 | ||
504 | static const struct kvm_io_device_ops picdev_ops = { | ||
505 | .read = picdev_read, | ||
506 | .write = picdev_write, | ||
507 | }; | ||
508 | |||
519 | struct kvm_pic *kvm_create_pic(struct kvm *kvm) | 509 | struct kvm_pic *kvm_create_pic(struct kvm *kvm) |
520 | { | 510 | { |
521 | struct kvm_pic *s; | 511 | struct kvm_pic *s; |
512 | int ret; | ||
513 | |||
522 | s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL); | 514 | s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL); |
523 | if (!s) | 515 | if (!s) |
524 | return NULL; | 516 | return NULL; |
@@ -534,10 +526,12 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm) | |||
534 | /* | 526 | /* |
535 | * Initialize PIO device | 527 | * Initialize PIO device |
536 | */ | 528 | */ |
537 | s->dev.read = picdev_read; | 529 | kvm_iodevice_init(&s->dev, &picdev_ops); |
538 | s->dev.write = picdev_write; | 530 | ret = kvm_io_bus_register_dev(kvm, &kvm->pio_bus, &s->dev); |
539 | s->dev.in_range = picdev_in_range; | 531 | if (ret < 0) { |
540 | s->dev.private = s; | 532 | kfree(s); |
541 | kvm_io_bus_register_dev(&kvm->pio_bus, &s->dev); | 533 | return NULL; |
534 | } | ||
535 | |||
542 | return s; | 536 | return s; |
543 | } | 537 | } |