diff options
-rw-r--r-- | include/linux/kvm.h | 9 | ||||
-rw-r--r-- | include/linux/kvm_host.h | 2 | ||||
-rw-r--r-- | virt/kvm/irq_comm.c | 78 | ||||
-rw-r--r-- | virt/kvm/kvm_main.c | 70 |
4 files changed, 86 insertions, 73 deletions
diff --git a/include/linux/kvm.h b/include/linux/kvm.h index 869462ca7625..2163b3dd36e7 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h | |||
@@ -410,8 +410,16 @@ struct kvm_irq_routing_irqchip { | |||
410 | __u32 pin; | 410 | __u32 pin; |
411 | }; | 411 | }; |
412 | 412 | ||
413 | struct kvm_irq_routing_msi { | ||
414 | __u32 address_lo; | ||
415 | __u32 address_hi; | ||
416 | __u32 data; | ||
417 | __u32 pad; | ||
418 | }; | ||
419 | |||
413 | /* gsi routing entry types */ | 420 | /* gsi routing entry types */ |
414 | #define KVM_IRQ_ROUTING_IRQCHIP 1 | 421 | #define KVM_IRQ_ROUTING_IRQCHIP 1 |
422 | #define KVM_IRQ_ROUTING_MSI 2 | ||
415 | 423 | ||
416 | struct kvm_irq_routing_entry { | 424 | struct kvm_irq_routing_entry { |
417 | __u32 gsi; | 425 | __u32 gsi; |
@@ -420,6 +428,7 @@ struct kvm_irq_routing_entry { | |||
420 | __u32 pad; | 428 | __u32 pad; |
421 | union { | 429 | union { |
422 | struct kvm_irq_routing_irqchip irqchip; | 430 | struct kvm_irq_routing_irqchip irqchip; |
431 | struct kvm_irq_routing_msi msi; | ||
423 | __u32 pad[8]; | 432 | __u32 pad[8]; |
424 | } u; | 433 | } u; |
425 | }; | 434 | }; |
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index c03a0a9a8584..339eda3ca6ee 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h | |||
@@ -116,6 +116,7 @@ struct kvm_kernel_irq_routing_entry { | |||
116 | unsigned irqchip; | 116 | unsigned irqchip; |
117 | unsigned pin; | 117 | unsigned pin; |
118 | } irqchip; | 118 | } irqchip; |
119 | struct msi_msg msi; | ||
119 | }; | 120 | }; |
120 | struct list_head link; | 121 | struct list_head link; |
121 | }; | 122 | }; |
@@ -327,7 +328,6 @@ struct kvm_assigned_dev_kernel { | |||
327 | int host_irq; | 328 | int host_irq; |
328 | bool host_irq_disabled; | 329 | bool host_irq_disabled; |
329 | int guest_irq; | 330 | int guest_irq; |
330 | struct msi_msg guest_msi; | ||
331 | #define KVM_ASSIGNED_DEV_GUEST_INTX (1 << 0) | 331 | #define KVM_ASSIGNED_DEV_GUEST_INTX (1 << 0) |
332 | #define KVM_ASSIGNED_DEV_GUEST_MSI (1 << 1) | 332 | #define KVM_ASSIGNED_DEV_GUEST_MSI (1 << 1) |
333 | #define KVM_ASSIGNED_DEV_HOST_INTX (1 << 8) | 333 | #define KVM_ASSIGNED_DEV_HOST_INTX (1 << 8) |
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 | /* |