aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/lapic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kvm/lapic.c')
-rw-r--r--arch/x86/kvm/lapic.c69
1 files changed, 26 insertions, 43 deletions
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index a42f968a23e1..998862a3c267 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -260,7 +260,7 @@ static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr)
260 260
261int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest) 261int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest)
262{ 262{
263 return kvm_apic_id(apic) == dest; 263 return dest == 0xff || kvm_apic_id(apic) == dest;
264} 264}
265 265
266int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda) 266int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
@@ -289,37 +289,34 @@ int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
289 return result; 289 return result;
290} 290}
291 291
292static int apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, 292int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
293 int short_hand, int dest, int dest_mode) 293 int short_hand, int dest, int dest_mode)
294{ 294{
295 int result = 0; 295 int result = 0;
296 struct kvm_lapic *target = vcpu->arch.apic; 296 struct kvm_lapic *target = vcpu->arch.apic;
297 297
298 apic_debug("target %p, source %p, dest 0x%x, " 298 apic_debug("target %p, source %p, dest 0x%x, "
299 "dest_mode 0x%x, short_hand 0x%x", 299 "dest_mode 0x%x, short_hand 0x%x\n",
300 target, source, dest, dest_mode, short_hand); 300 target, source, dest, dest_mode, short_hand);
301 301
302 ASSERT(!target); 302 ASSERT(!target);
303 switch (short_hand) { 303 switch (short_hand) {
304 case APIC_DEST_NOSHORT: 304 case APIC_DEST_NOSHORT:
305 if (dest_mode == 0) { 305 if (dest_mode == 0)
306 /* Physical mode. */ 306 /* Physical mode. */
307 if ((dest == 0xFF) || (dest == kvm_apic_id(target))) 307 result = kvm_apic_match_physical_addr(target, dest);
308 result = 1; 308 else
309 } else
310 /* Logical mode. */ 309 /* Logical mode. */
311 result = kvm_apic_match_logical_addr(target, dest); 310 result = kvm_apic_match_logical_addr(target, dest);
312 break; 311 break;
313 case APIC_DEST_SELF: 312 case APIC_DEST_SELF:
314 if (target == source) 313 result = (target == source);
315 result = 1;
316 break; 314 break;
317 case APIC_DEST_ALLINC: 315 case APIC_DEST_ALLINC:
318 result = 1; 316 result = 1;
319 break; 317 break;
320 case APIC_DEST_ALLBUT: 318 case APIC_DEST_ALLBUT:
321 if (target != source) 319 result = (target != source);
322 result = 1;
323 break; 320 break;
324 default: 321 default:
325 printk(KERN_WARNING "Bad dest shorthand value %x\n", 322 printk(KERN_WARNING "Bad dest shorthand value %x\n",
@@ -492,38 +489,26 @@ static void apic_send_ipi(struct kvm_lapic *apic)
492 unsigned int delivery_mode = icr_low & APIC_MODE_MASK; 489 unsigned int delivery_mode = icr_low & APIC_MODE_MASK;
493 unsigned int vector = icr_low & APIC_VECTOR_MASK; 490 unsigned int vector = icr_low & APIC_VECTOR_MASK;
494 491
495 struct kvm_vcpu *target; 492 DECLARE_BITMAP(deliver_bitmask, KVM_MAX_VCPUS);
496 struct kvm_vcpu *vcpu;
497 DECLARE_BITMAP(lpr_map, KVM_MAX_VCPUS);
498 int i; 493 int i;
499 494
500 bitmap_zero(lpr_map, KVM_MAX_VCPUS);
501 apic_debug("icr_high 0x%x, icr_low 0x%x, " 495 apic_debug("icr_high 0x%x, icr_low 0x%x, "
502 "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, " 496 "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
503 "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n", 497 "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n",
504 icr_high, icr_low, short_hand, dest, 498 icr_high, icr_low, short_hand, dest,
505 trig_mode, level, dest_mode, delivery_mode, vector); 499 trig_mode, level, dest_mode, delivery_mode, vector);
506 500
507 for (i = 0; i < KVM_MAX_VCPUS; i++) { 501 kvm_get_intr_delivery_bitmask(apic->vcpu->kvm, apic, dest, dest_mode,
508 vcpu = apic->vcpu->kvm->vcpus[i]; 502 delivery_mode == APIC_DM_LOWEST, short_hand,
509 if (!vcpu) 503 deliver_bitmask);
510 continue; 504
511 505 while ((i = find_first_bit(deliver_bitmask, KVM_MAX_VCPUS))
512 if (vcpu->arch.apic && 506 < KVM_MAX_VCPUS) {
513 apic_match_dest(vcpu, apic, short_hand, dest, dest_mode)) { 507 struct kvm_vcpu *vcpu = apic->vcpu->kvm->vcpus[i];
514 if (delivery_mode == APIC_DM_LOWEST) 508 __clear_bit(i, deliver_bitmask);
515 __set_bit(vcpu->vcpu_id, lpr_map); 509 if (vcpu)
516 else 510 __apic_accept_irq(vcpu->arch.apic, delivery_mode,
517 __apic_accept_irq(vcpu->arch.apic, delivery_mode, 511 vector, level, trig_mode);
518 vector, level, trig_mode);
519 }
520 }
521
522 if (delivery_mode == APIC_DM_LOWEST) {
523 target = kvm_get_lowest_prio_vcpu(vcpu->kvm, vector, lpr_map);
524 if (target != NULL)
525 __apic_accept_irq(target->arch.apic, delivery_mode,
526 vector, level, trig_mode);
527 } 512 }
528} 513}
529 514
@@ -930,16 +915,14 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
930} 915}
931EXPORT_SYMBOL_GPL(kvm_lapic_reset); 916EXPORT_SYMBOL_GPL(kvm_lapic_reset);
932 917
933int kvm_lapic_enabled(struct kvm_vcpu *vcpu) 918bool kvm_apic_present(struct kvm_vcpu *vcpu)
934{ 919{
935 struct kvm_lapic *apic = vcpu->arch.apic; 920 return vcpu->arch.apic && apic_hw_enabled(vcpu->arch.apic);
936 int ret = 0; 921}
937
938 if (!apic)
939 return 0;
940 ret = apic_enabled(apic);
941 922
942 return ret; 923int kvm_lapic_enabled(struct kvm_vcpu *vcpu)
924{
925 return kvm_apic_present(vcpu) && apic_sw_enabled(vcpu->arch.apic);
943} 926}
944EXPORT_SYMBOL_GPL(kvm_lapic_enabled); 927EXPORT_SYMBOL_GPL(kvm_lapic_enabled);
945 928