diff options
author | Sheng Yang <sheng@linux.intel.com> | 2009-02-10 00:57:06 -0500 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-03-24 05:03:09 -0400 |
commit | 79950e1073150909619b7c0f9a39a2fea83a42d8 (patch) | |
tree | 5dc96ee5d69029d61b90bc18d44cb42baaa925cd /virt/kvm | |
parent | 34c33d163fe509da8414a736c6328855f8c164e5 (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')
-rw-r--r-- | virt/kvm/irq_comm.c | 78 | ||||
-rw-r--r-- | virt/kvm/kvm_main.c | 70 |
2 files changed, 76 insertions, 72 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 | ||
46 | static 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 */ |
42 | void kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level) | 94 | void 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 | ||
62 | void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin) | 120 | void 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 | } |
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index c65484b471c6..266bdaf0ce44 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -47,10 +47,6 @@ | |||
47 | #include <asm/uaccess.h> | 47 | #include <asm/uaccess.h> |
48 | #include <asm/pgtable.h> | 48 | #include <asm/pgtable.h> |
49 | 49 | ||
50 | #ifdef CONFIG_X86 | ||
51 | #include <asm/msidef.h> | ||
52 | #endif | ||
53 | |||
54 | #ifdef KVM_COALESCED_MMIO_PAGE_OFFSET | 50 | #ifdef KVM_COALESCED_MMIO_PAGE_OFFSET |
55 | #include "coalesced_mmio.h" | 51 | #include "coalesced_mmio.h" |
56 | #endif | 52 | #endif |
@@ -85,57 +81,6 @@ static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl, | |||
85 | static bool kvm_rebooting; | 81 | static bool kvm_rebooting; |
86 | 82 | ||
87 | #ifdef KVM_CAP_DEVICE_ASSIGNMENT | 83 | #ifdef KVM_CAP_DEVICE_ASSIGNMENT |
88 | |||
89 | #ifdef CONFIG_X86 | ||
90 | static void assigned_device_msi_dispatch(struct kvm_assigned_dev_kernel *dev) | ||
91 | { | ||
92 | int vcpu_id; | ||
93 | struct kvm_vcpu *vcpu; | ||
94 | struct kvm_ioapic *ioapic = ioapic_irqchip(dev->kvm); | ||
95 | int dest_id = (dev->guest_msi.address_lo & MSI_ADDR_DEST_ID_MASK) | ||
96 | >> MSI_ADDR_DEST_ID_SHIFT; | ||
97 | int vector = (dev->guest_msi.data & MSI_DATA_VECTOR_MASK) | ||
98 | >> MSI_DATA_VECTOR_SHIFT; | ||
99 | int dest_mode = test_bit(MSI_ADDR_DEST_MODE_SHIFT, | ||
100 | (unsigned long *)&dev->guest_msi.address_lo); | ||
101 | int trig_mode = test_bit(MSI_DATA_TRIGGER_SHIFT, | ||
102 | (unsigned long *)&dev->guest_msi.data); | ||
103 | int delivery_mode = test_bit(MSI_DATA_DELIVERY_MODE_SHIFT, | ||
104 | (unsigned long *)&dev->guest_msi.data); | ||
105 | u32 deliver_bitmask; | ||
106 | |||
107 | BUG_ON(!ioapic); | ||
108 | |||
109 | deliver_bitmask = kvm_ioapic_get_delivery_bitmask(ioapic, | ||
110 | dest_id, dest_mode); | ||
111 | /* IOAPIC delivery mode value is the same as MSI here */ | ||
112 | switch (delivery_mode) { | ||
113 | case IOAPIC_LOWEST_PRIORITY: | ||
114 | vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm, vector, | ||
115 | deliver_bitmask); | ||
116 | if (vcpu != NULL) | ||
117 | kvm_apic_set_irq(vcpu, vector, trig_mode); | ||
118 | else | ||
119 | printk(KERN_INFO "kvm: null lowest priority vcpu!\n"); | ||
120 | break; | ||
121 | case IOAPIC_FIXED: | ||
122 | for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) { | ||
123 | if (!(deliver_bitmask & (1 << vcpu_id))) | ||
124 | continue; | ||
125 | deliver_bitmask &= ~(1 << vcpu_id); | ||
126 | vcpu = ioapic->kvm->vcpus[vcpu_id]; | ||
127 | if (vcpu) | ||
128 | kvm_apic_set_irq(vcpu, vector, trig_mode); | ||
129 | } | ||
130 | break; | ||
131 | default: | ||
132 | printk(KERN_INFO "kvm: unsupported MSI delivery mode\n"); | ||
133 | } | ||
134 | } | ||
135 | #else | ||
136 | static void assigned_device_msi_dispatch(struct kvm_assigned_dev_kernel *dev) {} | ||
137 | #endif | ||
138 | |||
139 | static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *head, | 84 | static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *head, |
140 | int assigned_dev_id) | 85 | int assigned_dev_id) |
141 | { | 86 | { |
@@ -162,13 +107,10 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) | |||
162 | * finer-grained lock, update this | 107 | * finer-grained lock, update this |
163 | */ | 108 | */ |
164 | mutex_lock(&assigned_dev->kvm->lock); | 109 | mutex_lock(&assigned_dev->kvm->lock); |
165 | if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_GUEST_INTX) | 110 | kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id, |
166 | kvm_set_irq(assigned_dev->kvm, | 111 | assigned_dev->guest_irq, 1); |
167 | assigned_dev->irq_source_id, | 112 | |
168 | assigned_dev->guest_irq, 1); | 113 | if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_GUEST_MSI) { |
169 | else if (assigned_dev->irq_requested_type & | ||
170 | KVM_ASSIGNED_DEV_GUEST_MSI) { | ||
171 | assigned_device_msi_dispatch(assigned_dev); | ||
172 | enable_irq(assigned_dev->host_irq); | 114 | enable_irq(assigned_dev->host_irq); |
173 | assigned_dev->host_irq_disabled = false; | 115 | assigned_dev->host_irq_disabled = false; |
174 | } | 116 | } |
@@ -331,17 +273,15 @@ static int assigned_device_update_msi(struct kvm *kvm, | |||
331 | { | 273 | { |
332 | int r; | 274 | int r; |
333 | 275 | ||
276 | adev->guest_irq = airq->guest_irq; | ||
334 | if (airq->flags & KVM_DEV_IRQ_ASSIGN_ENABLE_MSI) { | 277 | if (airq->flags & KVM_DEV_IRQ_ASSIGN_ENABLE_MSI) { |
335 | /* x86 don't care upper address of guest msi message addr */ | 278 | /* x86 don't care upper address of guest msi message addr */ |
336 | adev->irq_requested_type |= KVM_ASSIGNED_DEV_GUEST_MSI; | 279 | adev->irq_requested_type |= KVM_ASSIGNED_DEV_GUEST_MSI; |
337 | adev->irq_requested_type &= ~KVM_ASSIGNED_DEV_GUEST_INTX; | 280 | adev->irq_requested_type &= ~KVM_ASSIGNED_DEV_GUEST_INTX; |
338 | adev->guest_msi.address_lo = airq->guest_msi.addr_lo; | ||
339 | adev->guest_msi.data = airq->guest_msi.data; | ||
340 | adev->ack_notifier.gsi = -1; | 281 | adev->ack_notifier.gsi = -1; |
341 | } else if (msi2intx) { | 282 | } else if (msi2intx) { |
342 | adev->irq_requested_type |= KVM_ASSIGNED_DEV_GUEST_INTX; | 283 | adev->irq_requested_type |= KVM_ASSIGNED_DEV_GUEST_INTX; |
343 | adev->irq_requested_type &= ~KVM_ASSIGNED_DEV_GUEST_MSI; | 284 | adev->irq_requested_type &= ~KVM_ASSIGNED_DEV_GUEST_MSI; |
344 | adev->guest_irq = airq->guest_irq; | ||
345 | adev->ack_notifier.gsi = airq->guest_irq; | 285 | adev->ack_notifier.gsi = airq->guest_irq; |
346 | } else { | 286 | } else { |
347 | /* | 287 | /* |