diff options
Diffstat (limited to 'arch/x86/kvm/lapic.c')
-rw-r--r-- | arch/x86/kvm/lapic.c | 47 |
1 files changed, 29 insertions, 18 deletions
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 27ca43e4e440..a42f968a23e1 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -196,20 +196,30 @@ int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu) | |||
196 | } | 196 | } |
197 | EXPORT_SYMBOL_GPL(kvm_lapic_find_highest_irr); | 197 | EXPORT_SYMBOL_GPL(kvm_lapic_find_highest_irr); |
198 | 198 | ||
199 | int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 trig) | 199 | static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, |
200 | int vector, int level, int trig_mode); | ||
201 | |||
202 | int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 dmode, u8 trig) | ||
200 | { | 203 | { |
201 | struct kvm_lapic *apic = vcpu->arch.apic; | 204 | struct kvm_lapic *apic = vcpu->arch.apic; |
205 | int lapic_dmode; | ||
202 | 206 | ||
203 | if (!apic_test_and_set_irr(vec, apic)) { | 207 | switch (dmode) { |
204 | /* a new pending irq is set in IRR */ | 208 | case IOAPIC_LOWEST_PRIORITY: |
205 | if (trig) | 209 | lapic_dmode = APIC_DM_LOWEST; |
206 | apic_set_vector(vec, apic->regs + APIC_TMR); | 210 | break; |
207 | else | 211 | case IOAPIC_FIXED: |
208 | apic_clear_vector(vec, apic->regs + APIC_TMR); | 212 | lapic_dmode = APIC_DM_FIXED; |
209 | kvm_vcpu_kick(apic->vcpu); | 213 | break; |
210 | return 1; | 214 | case IOAPIC_NMI: |
215 | lapic_dmode = APIC_DM_NMI; | ||
216 | break; | ||
217 | default: | ||
218 | printk(KERN_DEBUG"Ignoring delivery mode %d\n", dmode); | ||
219 | return 0; | ||
220 | break; | ||
211 | } | 221 | } |
212 | return 0; | 222 | return __apic_accept_irq(apic, lapic_dmode, vec, 1, trig); |
213 | } | 223 | } |
214 | 224 | ||
215 | static inline int apic_find_highest_isr(struct kvm_lapic *apic) | 225 | static inline int apic_find_highest_isr(struct kvm_lapic *apic) |
@@ -327,7 +337,7 @@ static int apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, | |||
327 | static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, | 337 | static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, |
328 | int vector, int level, int trig_mode) | 338 | int vector, int level, int trig_mode) |
329 | { | 339 | { |
330 | int orig_irr, result = 0; | 340 | int result = 0; |
331 | struct kvm_vcpu *vcpu = apic->vcpu; | 341 | struct kvm_vcpu *vcpu = apic->vcpu; |
332 | 342 | ||
333 | switch (delivery_mode) { | 343 | switch (delivery_mode) { |
@@ -337,10 +347,11 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, | |||
337 | if (unlikely(!apic_enabled(apic))) | 347 | if (unlikely(!apic_enabled(apic))) |
338 | break; | 348 | break; |
339 | 349 | ||
340 | orig_irr = apic_test_and_set_irr(vector, apic); | 350 | result = !apic_test_and_set_irr(vector, apic); |
341 | if (orig_irr && trig_mode) { | 351 | if (!result) { |
342 | apic_debug("level trig mode repeatedly for vector %d", | 352 | if (trig_mode) |
343 | vector); | 353 | apic_debug("level trig mode repeatedly for " |
354 | "vector %d", vector); | ||
344 | break; | 355 | break; |
345 | } | 356 | } |
346 | 357 | ||
@@ -349,10 +360,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, | |||
349 | apic_set_vector(vector, apic->regs + APIC_TMR); | 360 | apic_set_vector(vector, apic->regs + APIC_TMR); |
350 | } else | 361 | } else |
351 | apic_clear_vector(vector, apic->regs + APIC_TMR); | 362 | apic_clear_vector(vector, apic->regs + APIC_TMR); |
352 | |||
353 | kvm_vcpu_kick(vcpu); | 363 | kvm_vcpu_kick(vcpu); |
354 | |||
355 | result = (orig_irr == 0); | ||
356 | break; | 364 | break; |
357 | 365 | ||
358 | case APIC_DM_REMRD: | 366 | case APIC_DM_REMRD: |
@@ -364,12 +372,14 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, | |||
364 | break; | 372 | break; |
365 | 373 | ||
366 | case APIC_DM_NMI: | 374 | case APIC_DM_NMI: |
375 | result = 1; | ||
367 | kvm_inject_nmi(vcpu); | 376 | kvm_inject_nmi(vcpu); |
368 | kvm_vcpu_kick(vcpu); | 377 | kvm_vcpu_kick(vcpu); |
369 | break; | 378 | break; |
370 | 379 | ||
371 | case APIC_DM_INIT: | 380 | case APIC_DM_INIT: |
372 | if (level) { | 381 | if (level) { |
382 | result = 1; | ||
373 | if (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE) | 383 | if (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE) |
374 | printk(KERN_DEBUG | 384 | printk(KERN_DEBUG |
375 | "INIT on a runnable vcpu %d\n", | 385 | "INIT on a runnable vcpu %d\n", |
@@ -386,6 +396,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, | |||
386 | apic_debug("SIPI to vcpu %d vector 0x%02x\n", | 396 | apic_debug("SIPI to vcpu %d vector 0x%02x\n", |
387 | vcpu->vcpu_id, vector); | 397 | vcpu->vcpu_id, vector); |
388 | if (vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED) { | 398 | if (vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED) { |
399 | result = 1; | ||
389 | vcpu->arch.sipi_vector = vector; | 400 | vcpu->arch.sipi_vector = vector; |
390 | vcpu->arch.mp_state = KVM_MP_STATE_SIPI_RECEIVED; | 401 | vcpu->arch.mp_state = KVM_MP_STATE_SIPI_RECEIVED; |
391 | kvm_vcpu_kick(vcpu); | 402 | kvm_vcpu_kick(vcpu); |