aboutsummaryrefslogtreecommitdiffstats
path: root/virt/kvm
diff options
context:
space:
mode:
authorSheng Yang <sheng@linux.intel.com>2008-11-24 01:32:56 -0500
committerAvi Kivity <avi@redhat.com>2008-12-31 09:55:02 -0500
commit6b9cc7fd469869bed38831c5adac3f59dc25eaf5 (patch)
tree63d526ff94b891116c37bf9705e42a45479271f0 /virt/kvm
parentf64769eb05565c74d7fce6fa75d65924f9cdaf79 (diff)
KVM: Enable MSI for device assignment
We enable guest MSI and host MSI support in this patch. The userspace want to enable MSI should set KVM_DEV_IRQ_ASSIGN_ENABLE_MSI in the assigned_irq's flag. Function would return -ENOTTY if can't enable MSI, userspace shouldn't set MSI Enable bit when KVM_ASSIGN_IRQ return -ENOTTY with KVM_DEV_IRQ_ASSIGN_ENABLE_MSI. Userspace can tell the support of MSI device from #ifdef KVM_CAP_DEVICE_MSI. 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/kvm_main.c81
1 files changed, 75 insertions, 6 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 228c1d18a614..bf36ae9ae7df 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -159,9 +159,15 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
159 * finer-grained lock, update this 159 * finer-grained lock, update this
160 */ 160 */
161 mutex_lock(&assigned_dev->kvm->lock); 161 mutex_lock(&assigned_dev->kvm->lock);
162 kvm_set_irq(assigned_dev->kvm, 162 if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_GUEST_INTX)
163 assigned_dev->irq_source_id, 163 kvm_set_irq(assigned_dev->kvm,
164 assigned_dev->guest_irq, 1); 164 assigned_dev->irq_source_id,
165 assigned_dev->guest_irq, 1);
166 else if (assigned_dev->irq_requested_type &
167 KVM_ASSIGNED_DEV_GUEST_MSI) {
168 assigned_device_msi_dispatch(assigned_dev);
169 enable_irq(assigned_dev->host_irq);
170 }
165 mutex_unlock(&assigned_dev->kvm->lock); 171 mutex_unlock(&assigned_dev->kvm->lock);
166 kvm_put_kvm(assigned_dev->kvm); 172 kvm_put_kvm(assigned_dev->kvm);
167} 173}
@@ -197,6 +203,8 @@ static void kvm_free_assigned_device(struct kvm *kvm,
197{ 203{
198 if (irqchip_in_kernel(kvm) && assigned_dev->irq_requested_type) 204 if (irqchip_in_kernel(kvm) && assigned_dev->irq_requested_type)
199 free_irq(assigned_dev->host_irq, (void *)assigned_dev); 205 free_irq(assigned_dev->host_irq, (void *)assigned_dev);
206 if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI)
207 pci_disable_msi(assigned_dev->dev);
200 208
201 kvm_unregister_irq_ack_notifier(&assigned_dev->ack_notifier); 209 kvm_unregister_irq_ack_notifier(&assigned_dev->ack_notifier);
202 kvm_free_irq_source_id(kvm, assigned_dev->irq_source_id); 210 kvm_free_irq_source_id(kvm, assigned_dev->irq_source_id);
@@ -242,6 +250,11 @@ static int assigned_device_update_intx(struct kvm *kvm,
242 return 0; 250 return 0;
243 251
244 if (irqchip_in_kernel(kvm)) { 252 if (irqchip_in_kernel(kvm)) {
253 if (adev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI) {
254 free_irq(adev->host_irq, (void *)kvm);
255 pci_disable_msi(adev->dev);
256 }
257
245 if (!capable(CAP_SYS_RAWIO)) 258 if (!capable(CAP_SYS_RAWIO))
246 return -EPERM; 259 return -EPERM;
247 260
@@ -265,6 +278,41 @@ static int assigned_device_update_intx(struct kvm *kvm,
265 return 0; 278 return 0;
266} 279}
267 280
281#ifdef CONFIG_X86
282static int assigned_device_update_msi(struct kvm *kvm,
283 struct kvm_assigned_dev_kernel *adev,
284 struct kvm_assigned_irq *airq)
285{
286 int r;
287
288 /* x86 don't care upper address of guest msi message addr */
289 adev->guest_msi.address_lo = airq->guest_msi.addr_lo;
290 adev->guest_msi.data = airq->guest_msi.data;
291 adev->ack_notifier.gsi = -1;
292
293 if (adev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI)
294 return 0;
295
296 if (irqchip_in_kernel(kvm)) {
297 if (adev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_INTX)
298 free_irq(adev->host_irq, (void *)adev);
299
300 r = pci_enable_msi(adev->dev);
301 if (r)
302 return r;
303
304 adev->host_irq = adev->dev->irq;
305 if (request_irq(adev->host_irq, kvm_assigned_dev_intr, 0,
306 "kvm_assigned_msi_device", (void *)adev))
307 return -EIO;
308 }
309
310 adev->irq_requested_type = KVM_ASSIGNED_DEV_GUEST_MSI |
311 KVM_ASSIGNED_DEV_HOST_MSI;
312 return 0;
313}
314#endif
315
268static int kvm_vm_ioctl_assign_irq(struct kvm *kvm, 316static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
269 struct kvm_assigned_irq 317 struct kvm_assigned_irq
270 *assigned_irq) 318 *assigned_irq)
@@ -301,9 +349,30 @@ static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
301 } 349 }
302 } 350 }
303 351
304 r = assigned_device_update_intx(kvm, match, assigned_irq); 352 if (assigned_irq->flags & KVM_DEV_IRQ_ASSIGN_ENABLE_MSI) {
305 if (r) 353#ifdef CONFIG_X86
306 goto out_release; 354 r = assigned_device_update_msi(kvm, match, assigned_irq);
355 if (r) {
356 printk(KERN_WARNING "kvm: failed to enable "
357 "MSI device!\n");
358 goto out_release;
359 }
360#else
361 r = -ENOTTY;
362#endif
363 } else if (assigned_irq->host_irq == 0 && match->dev->irq == 0) {
364 /* Host device IRQ 0 means don't support INTx */
365 printk(KERN_WARNING "kvm: wait device to enable MSI!\n");
366 r = 0;
367 } else {
368 /* Non-sharing INTx mode */
369 r = assigned_device_update_intx(kvm, match, assigned_irq);
370 if (r) {
371 printk(KERN_WARNING "kvm: failed to enable "
372 "INTx device!\n");
373 goto out_release;
374 }
375 }
307 376
308 mutex_unlock(&kvm->lock); 377 mutex_unlock(&kvm->lock);
309 return r; 378 return r;