diff options
Diffstat (limited to 'virt/kvm/ioapic.c')
-rw-r--r-- | virt/kvm/ioapic.c | 38 |
1 files changed, 36 insertions, 2 deletions
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index 38a2d20b89de..3db15a807f80 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c | |||
@@ -100,6 +100,19 @@ static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx) | |||
100 | return injected; | 100 | return injected; |
101 | } | 101 | } |
102 | 102 | ||
103 | static void update_handled_vectors(struct kvm_ioapic *ioapic) | ||
104 | { | ||
105 | DECLARE_BITMAP(handled_vectors, 256); | ||
106 | int i; | ||
107 | |||
108 | memset(handled_vectors, 0, sizeof(handled_vectors)); | ||
109 | for (i = 0; i < IOAPIC_NUM_PINS; ++i) | ||
110 | __set_bit(ioapic->redirtbl[i].fields.vector, handled_vectors); | ||
111 | memcpy(ioapic->handled_vectors, handled_vectors, | ||
112 | sizeof(handled_vectors)); | ||
113 | smp_wmb(); | ||
114 | } | ||
115 | |||
103 | static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) | 116 | static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) |
104 | { | 117 | { |
105 | unsigned index; | 118 | unsigned index; |
@@ -134,6 +147,7 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) | |||
134 | e->bits |= (u32) val; | 147 | e->bits |= (u32) val; |
135 | e->fields.remote_irr = 0; | 148 | e->fields.remote_irr = 0; |
136 | } | 149 | } |
150 | update_handled_vectors(ioapic); | ||
137 | mask_after = e->fields.mask; | 151 | mask_after = e->fields.mask; |
138 | if (mask_before != mask_after) | 152 | if (mask_before != mask_after) |
139 | kvm_fire_mask_notifiers(ioapic->kvm, index, mask_after); | 153 | kvm_fire_mask_notifiers(ioapic->kvm, index, mask_after); |
@@ -241,6 +255,9 @@ void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode) | |||
241 | { | 255 | { |
242 | struct kvm_ioapic *ioapic = kvm->arch.vioapic; | 256 | struct kvm_ioapic *ioapic = kvm->arch.vioapic; |
243 | 257 | ||
258 | smp_rmb(); | ||
259 | if (!test_bit(vector, ioapic->handled_vectors)) | ||
260 | return; | ||
244 | mutex_lock(&ioapic->lock); | 261 | mutex_lock(&ioapic->lock); |
245 | __kvm_ioapic_update_eoi(ioapic, vector, trigger_mode); | 262 | __kvm_ioapic_update_eoi(ioapic, vector, trigger_mode); |
246 | mutex_unlock(&ioapic->lock); | 263 | mutex_unlock(&ioapic->lock); |
@@ -352,6 +369,7 @@ void kvm_ioapic_reset(struct kvm_ioapic *ioapic) | |||
352 | ioapic->ioregsel = 0; | 369 | ioapic->ioregsel = 0; |
353 | ioapic->irr = 0; | 370 | ioapic->irr = 0; |
354 | ioapic->id = 0; | 371 | ioapic->id = 0; |
372 | update_handled_vectors(ioapic); | ||
355 | } | 373 | } |
356 | 374 | ||
357 | static const struct kvm_io_device_ops ioapic_mmio_ops = { | 375 | static const struct kvm_io_device_ops ioapic_mmio_ops = { |
@@ -372,13 +390,28 @@ int kvm_ioapic_init(struct kvm *kvm) | |||
372 | kvm_ioapic_reset(ioapic); | 390 | kvm_ioapic_reset(ioapic); |
373 | kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops); | 391 | kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops); |
374 | ioapic->kvm = kvm; | 392 | ioapic->kvm = kvm; |
375 | ret = kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &ioapic->dev); | 393 | mutex_lock(&kvm->slots_lock); |
376 | if (ret < 0) | 394 | ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, &ioapic->dev); |
395 | mutex_unlock(&kvm->slots_lock); | ||
396 | if (ret < 0) { | ||
397 | kvm->arch.vioapic = NULL; | ||
377 | kfree(ioapic); | 398 | kfree(ioapic); |
399 | } | ||
378 | 400 | ||
379 | return ret; | 401 | return ret; |
380 | } | 402 | } |
381 | 403 | ||
404 | void kvm_ioapic_destroy(struct kvm *kvm) | ||
405 | { | ||
406 | struct kvm_ioapic *ioapic = kvm->arch.vioapic; | ||
407 | |||
408 | if (ioapic) { | ||
409 | kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &ioapic->dev); | ||
410 | kvm->arch.vioapic = NULL; | ||
411 | kfree(ioapic); | ||
412 | } | ||
413 | } | ||
414 | |||
382 | int kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state) | 415 | int kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state) |
383 | { | 416 | { |
384 | struct kvm_ioapic *ioapic = ioapic_irqchip(kvm); | 417 | struct kvm_ioapic *ioapic = ioapic_irqchip(kvm); |
@@ -399,6 +432,7 @@ int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state) | |||
399 | 432 | ||
400 | mutex_lock(&ioapic->lock); | 433 | mutex_lock(&ioapic->lock); |
401 | memcpy(ioapic, state, sizeof(struct kvm_ioapic_state)); | 434 | memcpy(ioapic, state, sizeof(struct kvm_ioapic_state)); |
435 | update_handled_vectors(ioapic); | ||
402 | mutex_unlock(&ioapic->lock); | 436 | mutex_unlock(&ioapic->lock); |
403 | return 0; | 437 | return 0; |
404 | } | 438 | } |