diff options
| author | Sheng Yang <sheng@linux.intel.com> | 2008-11-24 01:32:56 -0500 |
|---|---|---|
| committer | Avi Kivity <avi@redhat.com> | 2008-12-31 09:55:02 -0500 |
| commit | 6b9cc7fd469869bed38831c5adac3f59dc25eaf5 (patch) | |
| tree | 63d526ff94b891116c37bf9705e42a45479271f0 /virt | |
| parent | f64769eb05565c74d7fce6fa75d65924f9cdaf79 (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')
| -rw-r--r-- | virt/kvm/kvm_main.c | 81 |
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 | ||
| 282 | static 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 | |||
| 268 | static int kvm_vm_ioctl_assign_irq(struct kvm *kvm, | 316 | static 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; |
