diff options
Diffstat (limited to 'virt/kvm/ioapic.c')
-rw-r--r-- | virt/kvm/ioapic.c | 39 |
1 files changed, 27 insertions, 12 deletions
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index 23b81cf242af..c3b99def9cbc 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c | |||
@@ -83,24 +83,28 @@ static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic, | |||
83 | return result; | 83 | return result; |
84 | } | 84 | } |
85 | 85 | ||
86 | static void ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx) | 86 | static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx) |
87 | { | 87 | { |
88 | union ioapic_redir_entry *pent; | 88 | union ioapic_redir_entry *pent; |
89 | int injected = -1; | ||
89 | 90 | ||
90 | pent = &ioapic->redirtbl[idx]; | 91 | pent = &ioapic->redirtbl[idx]; |
91 | 92 | ||
92 | if (!pent->fields.mask) { | 93 | if (!pent->fields.mask) { |
93 | int injected = ioapic_deliver(ioapic, idx); | 94 | injected = ioapic_deliver(ioapic, idx); |
94 | if (injected && pent->fields.trig_mode == IOAPIC_LEVEL_TRIG) | 95 | if (injected && pent->fields.trig_mode == IOAPIC_LEVEL_TRIG) |
95 | pent->fields.remote_irr = 1; | 96 | pent->fields.remote_irr = 1; |
96 | } | 97 | } |
97 | if (!pent->fields.trig_mode) | 98 | if (!pent->fields.trig_mode) |
98 | ioapic->irr &= ~(1 << idx); | 99 | ioapic->irr &= ~(1 << idx); |
100 | |||
101 | return injected; | ||
99 | } | 102 | } |
100 | 103 | ||
101 | static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) | 104 | static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) |
102 | { | 105 | { |
103 | unsigned index; | 106 | unsigned index; |
107 | bool mask_before, mask_after; | ||
104 | 108 | ||
105 | switch (ioapic->ioregsel) { | 109 | switch (ioapic->ioregsel) { |
106 | case IOAPIC_REG_VERSION: | 110 | case IOAPIC_REG_VERSION: |
@@ -120,6 +124,7 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) | |||
120 | ioapic_debug("change redir index %x val %x\n", index, val); | 124 | ioapic_debug("change redir index %x val %x\n", index, val); |
121 | if (index >= IOAPIC_NUM_PINS) | 125 | if (index >= IOAPIC_NUM_PINS) |
122 | return; | 126 | return; |
127 | mask_before = ioapic->redirtbl[index].fields.mask; | ||
123 | if (ioapic->ioregsel & 1) { | 128 | if (ioapic->ioregsel & 1) { |
124 | ioapic->redirtbl[index].bits &= 0xffffffff; | 129 | ioapic->redirtbl[index].bits &= 0xffffffff; |
125 | ioapic->redirtbl[index].bits |= (u64) val << 32; | 130 | ioapic->redirtbl[index].bits |= (u64) val << 32; |
@@ -128,6 +133,9 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) | |||
128 | ioapic->redirtbl[index].bits |= (u32) val; | 133 | ioapic->redirtbl[index].bits |= (u32) val; |
129 | ioapic->redirtbl[index].fields.remote_irr = 0; | 134 | ioapic->redirtbl[index].fields.remote_irr = 0; |
130 | } | 135 | } |
136 | mask_after = ioapic->redirtbl[index].fields.mask; | ||
137 | if (mask_before != mask_after) | ||
138 | kvm_fire_mask_notifiers(ioapic->kvm, index, mask_after); | ||
131 | if (ioapic->irr & (1 << index)) | 139 | if (ioapic->irr & (1 << index)) |
132 | ioapic_service(ioapic, index); | 140 | ioapic_service(ioapic, index); |
133 | break; | 141 | break; |
@@ -202,7 +210,7 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq) | |||
202 | u8 trig_mode = ioapic->redirtbl[irq].fields.trig_mode; | 210 | u8 trig_mode = ioapic->redirtbl[irq].fields.trig_mode; |
203 | u32 deliver_bitmask; | 211 | u32 deliver_bitmask; |
204 | struct kvm_vcpu *vcpu; | 212 | struct kvm_vcpu *vcpu; |
205 | int vcpu_id, r = 0; | 213 | int vcpu_id, r = -1; |
206 | 214 | ||
207 | ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x " | 215 | ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x " |
208 | "vector=%x trig_mode=%x\n", | 216 | "vector=%x trig_mode=%x\n", |
@@ -242,7 +250,9 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq) | |||
242 | deliver_bitmask &= ~(1 << vcpu_id); | 250 | deliver_bitmask &= ~(1 << vcpu_id); |
243 | vcpu = ioapic->kvm->vcpus[vcpu_id]; | 251 | vcpu = ioapic->kvm->vcpus[vcpu_id]; |
244 | if (vcpu) { | 252 | if (vcpu) { |
245 | r = ioapic_inj_irq(ioapic, vcpu, vector, | 253 | if (r < 0) |
254 | r = 0; | ||
255 | r += ioapic_inj_irq(ioapic, vcpu, vector, | ||
246 | trig_mode, delivery_mode); | 256 | trig_mode, delivery_mode); |
247 | } | 257 | } |
248 | } | 258 | } |
@@ -253,8 +263,10 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq) | |||
253 | continue; | 263 | continue; |
254 | deliver_bitmask &= ~(1 << vcpu_id); | 264 | deliver_bitmask &= ~(1 << vcpu_id); |
255 | vcpu = ioapic->kvm->vcpus[vcpu_id]; | 265 | vcpu = ioapic->kvm->vcpus[vcpu_id]; |
256 | if (vcpu) | 266 | if (vcpu) { |
257 | ioapic_inj_nmi(vcpu); | 267 | ioapic_inj_nmi(vcpu); |
268 | r = 1; | ||
269 | } | ||
258 | else | 270 | else |
259 | ioapic_debug("NMI to vcpu %d failed\n", | 271 | ioapic_debug("NMI to vcpu %d failed\n", |
260 | vcpu->vcpu_id); | 272 | vcpu->vcpu_id); |
@@ -268,11 +280,12 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq) | |||
268 | return r; | 280 | return r; |
269 | } | 281 | } |
270 | 282 | ||
271 | void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) | 283 | int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) |
272 | { | 284 | { |
273 | u32 old_irr = ioapic->irr; | 285 | u32 old_irr = ioapic->irr; |
274 | u32 mask = 1 << irq; | 286 | u32 mask = 1 << irq; |
275 | union ioapic_redir_entry entry; | 287 | union ioapic_redir_entry entry; |
288 | int ret = 1; | ||
276 | 289 | ||
277 | if (irq >= 0 && irq < IOAPIC_NUM_PINS) { | 290 | if (irq >= 0 && irq < IOAPIC_NUM_PINS) { |
278 | entry = ioapic->redirtbl[irq]; | 291 | entry = ioapic->redirtbl[irq]; |
@@ -283,25 +296,26 @@ void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) | |||
283 | ioapic->irr |= mask; | 296 | ioapic->irr |= mask; |
284 | if ((!entry.fields.trig_mode && old_irr != ioapic->irr) | 297 | if ((!entry.fields.trig_mode && old_irr != ioapic->irr) |
285 | || !entry.fields.remote_irr) | 298 | || !entry.fields.remote_irr) |
286 | ioapic_service(ioapic, irq); | 299 | ret = ioapic_service(ioapic, irq); |
287 | } | 300 | } |
288 | } | 301 | } |
302 | return ret; | ||
289 | } | 303 | } |
290 | 304 | ||
291 | static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int gsi, | 305 | static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int pin, |
292 | int trigger_mode) | 306 | int trigger_mode) |
293 | { | 307 | { |
294 | union ioapic_redir_entry *ent; | 308 | union ioapic_redir_entry *ent; |
295 | 309 | ||
296 | ent = &ioapic->redirtbl[gsi]; | 310 | ent = &ioapic->redirtbl[pin]; |
297 | 311 | ||
298 | kvm_notify_acked_irq(ioapic->kvm, gsi); | 312 | kvm_notify_acked_irq(ioapic->kvm, KVM_IRQCHIP_IOAPIC, pin); |
299 | 313 | ||
300 | if (trigger_mode == IOAPIC_LEVEL_TRIG) { | 314 | if (trigger_mode == IOAPIC_LEVEL_TRIG) { |
301 | ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); | 315 | ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG); |
302 | ent->fields.remote_irr = 0; | 316 | ent->fields.remote_irr = 0; |
303 | if (!ent->fields.mask && (ioapic->irr & (1 << gsi))) | 317 | if (!ent->fields.mask && (ioapic->irr & (1 << pin))) |
304 | ioapic_service(ioapic, gsi); | 318 | ioapic_service(ioapic, pin); |
305 | } | 319 | } |
306 | } | 320 | } |
307 | 321 | ||
@@ -426,3 +440,4 @@ int kvm_ioapic_init(struct kvm *kvm) | |||
426 | kvm_io_bus_register_dev(&kvm->mmio_bus, &ioapic->dev); | 440 | kvm_io_bus_register_dev(&kvm->mmio_bus, &ioapic->dev); |
427 | return 0; | 441 | return 0; |
428 | } | 442 | } |
443 | |||