aboutsummaryrefslogtreecommitdiffstats
path: root/virt/kvm/irq_comm.c
diff options
context:
space:
mode:
authorSheng Yang <sheng@linux.intel.com>2009-02-10 00:57:06 -0500
committerAvi Kivity <avi@redhat.com>2009-03-24 05:03:09 -0400
commit79950e1073150909619b7c0f9a39a2fea83a42d8 (patch)
tree5dc96ee5d69029d61b90bc18d44cb42baaa925cd /virt/kvm/irq_comm.c
parent34c33d163fe509da8414a736c6328855f8c164e5 (diff)
KVM: Use irq routing API for MSI
Merge MSI userspace interface with IRQ routing table. Notice the API have been changed, and using IRQ routing table would be the only interface kvm-userspace supported. Signed-off-by: Sheng Yang <sheng@linux.intel.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'virt/kvm/irq_comm.c')
-rw-r--r--virt/kvm/irq_comm.c78
1 files changed, 71 insertions, 7 deletions
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
index 7aa5086c8622..6bc7439eff6e 100644
--- a/virt/kvm/irq_comm.c
+++ b/virt/kvm/irq_comm.c
@@ -20,6 +20,11 @@
20 */ 20 */
21 21
22#include <linux/kvm_host.h> 22#include <linux/kvm_host.h>
23
24#ifdef CONFIG_X86
25#include <asm/msidef.h>
26#endif
27
23#include "irq.h" 28#include "irq.h"
24 29
25#include "ioapic.h" 30#include "ioapic.h"
@@ -38,17 +43,70 @@ static void kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e,
38 kvm_ioapic_set_irq(kvm->arch.vioapic, e->irqchip.pin, level); 43 kvm_ioapic_set_irq(kvm->arch.vioapic, e->irqchip.pin, level);
39} 44}
40 45
46static void kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
47 struct kvm *kvm, int level)
48{
49 int vcpu_id;
50 struct kvm_vcpu *vcpu;
51 struct kvm_ioapic *ioapic = ioapic_irqchip(kvm);
52 int dest_id = (e->msi.address_lo & MSI_ADDR_DEST_ID_MASK)
53 >> MSI_ADDR_DEST_ID_SHIFT;
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
64 BUG_ON(!ioapic);
65
66 deliver_bitmask = kvm_ioapic_get_delivery_bitmask(ioapic,
67 dest_id, dest_mode);
68 /* IOAPIC delivery mode value is the same as MSI here */
69 switch (delivery_mode) {
70 case IOAPIC_LOWEST_PRIORITY:
71 vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm, vector,
72 deliver_bitmask);
73 if (vcpu != NULL)
74 kvm_apic_set_irq(vcpu, vector, trig_mode);
75 else
76 printk(KERN_INFO "kvm: null lowest priority vcpu!\n");
77 break;
78 case IOAPIC_FIXED:
79 for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) {
80 if (!(deliver_bitmask & (1 << vcpu_id)))
81 continue;
82 deliver_bitmask &= ~(1 << vcpu_id);
83 vcpu = ioapic->kvm->vcpus[vcpu_id];
84 if (vcpu)
85 kvm_apic_set_irq(vcpu, vector, trig_mode);
86 }
87 break;
88 default:
89 break;
90 }
91}
92
41/* This should be called with the kvm->lock mutex held */ 93/* This should be called with the kvm->lock mutex held */
42void kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level) 94void kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level)
43{ 95{
44 struct kvm_kernel_irq_routing_entry *e; 96 struct kvm_kernel_irq_routing_entry *e;
45 unsigned long *irq_state = (unsigned long *)&kvm->arch.irq_states[irq]; 97 unsigned long *irq_state, sig_level;
98
99 if (irq < KVM_IOAPIC_NUM_PINS) {
100 irq_state = (unsigned long *)&kvm->arch.irq_states[irq];
46 101
47 /* Logical OR for level trig interrupt */ 102 /* Logical OR for level trig interrupt */
48 if (level) 103 if (level)
49 set_bit(irq_source_id, irq_state); 104 set_bit(irq_source_id, irq_state);
50 else 105 else
51 clear_bit(irq_source_id, irq_state); 106 clear_bit(irq_source_id, irq_state);
107 sig_level = !!(*irq_state);
108 } else /* Deal with MSI/MSI-X */
109 sig_level = 1;
52 110
53 /* Not possible to detect if the guest uses the PIC or the 111 /* Not possible to detect if the guest uses the PIC or the
54 * IOAPIC. So set the bit in both. The guest will ignore 112 * IOAPIC. So set the bit in both. The guest will ignore
@@ -56,7 +114,7 @@ void kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level)
56 */ 114 */
57 list_for_each_entry(e, &kvm->irq_routing, link) 115 list_for_each_entry(e, &kvm->irq_routing, link)
58 if (e->gsi == irq) 116 if (e->gsi == irq)
59 e->set(e, kvm, !!(*irq_state)); 117 e->set(e, kvm, sig_level);
60} 118}
61 119
62void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin) 120void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin)
@@ -186,6 +244,12 @@ int setup_routing_entry(struct kvm_kernel_irq_routing_entry *e,
186 e->irqchip.irqchip = ue->u.irqchip.irqchip; 244 e->irqchip.irqchip = ue->u.irqchip.irqchip;
187 e->irqchip.pin = ue->u.irqchip.pin + delta; 245 e->irqchip.pin = ue->u.irqchip.pin + delta;
188 break; 246 break;
247 case KVM_IRQ_ROUTING_MSI:
248 e->set = kvm_set_msi;
249 e->msi.address_lo = ue->u.msi.address_lo;
250 e->msi.address_hi = ue->u.msi.address_hi;
251 e->msi.data = ue->u.msi.data;
252 break;
189 default: 253 default:
190 goto out; 254 goto out;
191 } 255 }