diff options
Diffstat (limited to 'virt/kvm/irq_comm.c')
-rw-r--r-- | virt/kvm/irq_comm.c | 95 |
1 files changed, 58 insertions, 37 deletions
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c index 864ac5483baa..aec7a0d93a3f 100644 --- a/virt/kvm/irq_comm.c +++ b/virt/kvm/irq_comm.c | |||
@@ -43,53 +43,74 @@ static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e, | |||
43 | return kvm_ioapic_set_irq(kvm->arch.vioapic, e->irqchip.pin, level); | 43 | return kvm_ioapic_set_irq(kvm->arch.vioapic, e->irqchip.pin, level); |
44 | } | 44 | } |
45 | 45 | ||
46 | void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic, | ||
47 | union kvm_ioapic_redirect_entry *entry, | ||
48 | unsigned long *deliver_bitmask) | ||
49 | { | ||
50 | struct kvm_vcpu *vcpu; | ||
51 | |||
52 | *deliver_bitmask = kvm_ioapic_get_delivery_bitmask(ioapic, | ||
53 | entry->fields.dest_id, entry->fields.dest_mode); | ||
54 | switch (entry->fields.delivery_mode) { | ||
55 | case IOAPIC_LOWEST_PRIORITY: | ||
56 | vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm, | ||
57 | entry->fields.vector, *deliver_bitmask); | ||
58 | *deliver_bitmask = 1 << vcpu->vcpu_id; | ||
59 | break; | ||
60 | case IOAPIC_FIXED: | ||
61 | case IOAPIC_NMI: | ||
62 | break; | ||
63 | default: | ||
64 | if (printk_ratelimit()) | ||
65 | printk(KERN_INFO "kvm: unsupported delivery mode %d\n", | ||
66 | entry->fields.delivery_mode); | ||
67 | *deliver_bitmask = 0; | ||
68 | } | ||
69 | } | ||
70 | |||
46 | static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, | 71 | static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, |
47 | struct kvm *kvm, int level) | 72 | struct kvm *kvm, int level) |
48 | { | 73 | { |
49 | int vcpu_id, r = -1; | 74 | int vcpu_id, r = -1; |
50 | struct kvm_vcpu *vcpu; | 75 | struct kvm_vcpu *vcpu; |
51 | struct kvm_ioapic *ioapic = ioapic_irqchip(kvm); | 76 | struct kvm_ioapic *ioapic = ioapic_irqchip(kvm); |
52 | int dest_id = (e->msi.address_lo & MSI_ADDR_DEST_ID_MASK) | 77 | union kvm_ioapic_redirect_entry entry; |
53 | >> MSI_ADDR_DEST_ID_SHIFT; | 78 | unsigned long deliver_bitmask; |
54 | int vector = (e->msi.data & MSI_DATA_VECTOR_MASK) | ||
55 | >> MSI_DATA_VECTOR_SHIFT; | ||
56 | int dest_mode = test_bit(MSI_ADDR_DEST_MODE_SHIFT, | ||
57 | (unsigned long *)&e->msi.address_lo); | ||
58 | int trig_mode = test_bit(MSI_DATA_TRIGGER_SHIFT, | ||
59 | (unsigned long *)&e->msi.data); | ||
60 | int delivery_mode = test_bit(MSI_DATA_DELIVERY_MODE_SHIFT, | ||
61 | (unsigned long *)&e->msi.data); | ||
62 | u32 deliver_bitmask; | ||
63 | 79 | ||
64 | BUG_ON(!ioapic); | 80 | BUG_ON(!ioapic); |
65 | 81 | ||
66 | deliver_bitmask = kvm_ioapic_get_delivery_bitmask(ioapic, | 82 | entry.bits = 0; |
67 | dest_id, dest_mode); | 83 | entry.fields.dest_id = (e->msi.address_lo & |
68 | /* IOAPIC delivery mode value is the same as MSI here */ | 84 | MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT; |
69 | switch (delivery_mode) { | 85 | entry.fields.vector = (e->msi.data & |
70 | case IOAPIC_LOWEST_PRIORITY: | 86 | MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT; |
71 | vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm, vector, | 87 | entry.fields.dest_mode = test_bit(MSI_ADDR_DEST_MODE_SHIFT, |
72 | deliver_bitmask); | 88 | (unsigned long *)&e->msi.address_lo); |
73 | if (vcpu != NULL) | 89 | entry.fields.trig_mode = test_bit(MSI_DATA_TRIGGER_SHIFT, |
74 | r = kvm_apic_set_irq(vcpu, vector, trig_mode); | 90 | (unsigned long *)&e->msi.data); |
75 | else | 91 | entry.fields.delivery_mode = test_bit( |
76 | printk(KERN_INFO "kvm: null lowest priority vcpu!\n"); | 92 | MSI_DATA_DELIVERY_MODE_SHIFT, |
77 | break; | 93 | (unsigned long *)&e->msi.data); |
78 | case IOAPIC_FIXED: | 94 | |
79 | for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) { | 95 | /* TODO Deal with RH bit of MSI message address */ |
80 | if (!(deliver_bitmask & (1 << vcpu_id))) | 96 | |
81 | continue; | 97 | kvm_get_intr_delivery_bitmask(ioapic, &entry, &deliver_bitmask); |
82 | deliver_bitmask &= ~(1 << vcpu_id); | 98 | |
83 | vcpu = ioapic->kvm->vcpus[vcpu_id]; | 99 | if (!deliver_bitmask) { |
84 | if (vcpu) { | 100 | printk(KERN_WARNING "kvm: no destination for MSI delivery!"); |
85 | if (r < 0) | 101 | return -1; |
86 | r = 0; | 102 | } |
87 | r += kvm_apic_set_irq(vcpu, vector, trig_mode); | 103 | for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) { |
88 | } | 104 | if (!(deliver_bitmask & (1 << vcpu_id))) |
105 | continue; | ||
106 | deliver_bitmask &= ~(1 << vcpu_id); | ||
107 | vcpu = ioapic->kvm->vcpus[vcpu_id]; | ||
108 | if (vcpu) { | ||
109 | if (r < 0) | ||
110 | r = 0; | ||
111 | r += kvm_apic_set_irq(vcpu, entry.fields.vector, | ||
112 | entry.fields.trig_mode); | ||
89 | } | 113 | } |
90 | break; | ||
91 | default: | ||
92 | break; | ||
93 | } | 114 | } |
94 | return r; | 115 | return r; |
95 | } | 116 | } |