diff options
| author | Sheng Yang <sheng@linux.intel.com> | 2009-02-25 04:22:26 -0500 |
|---|---|---|
| committer | Avi Kivity <avi@redhat.com> | 2009-06-10 04:48:23 -0400 |
| commit | c1e01514296e8a4a43ff0c88dcff635cb90feb5f (patch) | |
| tree | 299a54da71c4900fc3b71840e2c6eec98b35f8b4 | |
| parent | bfd349d073b2838a6a031f057d25e266619b7093 (diff) | |
KVM: Ioctls for init MSI-X entry
Introduce KVM_SET_MSIX_NR and KVM_SET_MSIX_ENTRY two ioctls.
This two ioctls are used by userspace to specific guest device MSI-X entry
number and correlate MSI-X entry with GSI during the initialization stage.
MSI-X should be well initialzed before enabling.
Don't support change MSI-X entry number for now.
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
| -rw-r--r-- | include/linux/kvm.h | 18 | ||||
| -rw-r--r-- | include/linux/kvm_host.h | 10 | ||||
| -rw-r--r-- | virt/kvm/kvm_main.c | 104 |
3 files changed, 132 insertions, 0 deletions
diff --git a/include/linux/kvm.h b/include/linux/kvm.h index 8cc137911b34..78cdee8c6355 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h | |||
| @@ -487,6 +487,10 @@ struct kvm_irq_routing { | |||
| 487 | #define KVM_REINJECT_CONTROL _IO(KVMIO, 0x71) | 487 | #define KVM_REINJECT_CONTROL _IO(KVMIO, 0x71) |
| 488 | #define KVM_DEASSIGN_PCI_DEVICE _IOW(KVMIO, 0x72, \ | 488 | #define KVM_DEASSIGN_PCI_DEVICE _IOW(KVMIO, 0x72, \ |
| 489 | struct kvm_assigned_pci_dev) | 489 | struct kvm_assigned_pci_dev) |
| 490 | #define KVM_ASSIGN_SET_MSIX_NR \ | ||
| 491 | _IOW(KVMIO, 0x73, struct kvm_assigned_msix_nr) | ||
| 492 | #define KVM_ASSIGN_SET_MSIX_ENTRY \ | ||
| 493 | _IOW(KVMIO, 0x74, struct kvm_assigned_msix_entry) | ||
| 490 | 494 | ||
| 491 | /* | 495 | /* |
| 492 | * ioctls for vcpu fds | 496 | * ioctls for vcpu fds |
| @@ -607,4 +611,18 @@ struct kvm_assigned_irq { | |||
| 607 | #define KVM_DEV_IRQ_ASSIGN_MSI_ACTION KVM_DEV_IRQ_ASSIGN_ENABLE_MSI | 611 | #define KVM_DEV_IRQ_ASSIGN_MSI_ACTION KVM_DEV_IRQ_ASSIGN_ENABLE_MSI |
| 608 | #define KVM_DEV_IRQ_ASSIGN_ENABLE_MSI (1 << 0) | 612 | #define KVM_DEV_IRQ_ASSIGN_ENABLE_MSI (1 << 0) |
| 609 | 613 | ||
| 614 | struct kvm_assigned_msix_nr { | ||
| 615 | __u32 assigned_dev_id; | ||
| 616 | __u16 entry_nr; | ||
| 617 | __u16 padding; | ||
| 618 | }; | ||
| 619 | |||
| 620 | #define KVM_MAX_MSIX_PER_DEV 512 | ||
| 621 | struct kvm_assigned_msix_entry { | ||
| 622 | __u32 assigned_dev_id; | ||
| 623 | __u32 gsi; | ||
| 624 | __u16 entry; /* The index of entry in the MSI-X table */ | ||
| 625 | __u16 padding[3]; | ||
| 626 | }; | ||
| 627 | |||
| 610 | #endif | 628 | #endif |
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 1a2f98fbecea..432edc27e82b 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h | |||
| @@ -319,6 +319,12 @@ struct kvm_irq_ack_notifier { | |||
| 319 | void (*irq_acked)(struct kvm_irq_ack_notifier *kian); | 319 | void (*irq_acked)(struct kvm_irq_ack_notifier *kian); |
| 320 | }; | 320 | }; |
| 321 | 321 | ||
| 322 | struct kvm_guest_msix_entry { | ||
| 323 | u32 vector; | ||
| 324 | u16 entry; | ||
| 325 | u16 flags; | ||
| 326 | }; | ||
| 327 | |||
| 322 | struct kvm_assigned_dev_kernel { | 328 | struct kvm_assigned_dev_kernel { |
| 323 | struct kvm_irq_ack_notifier ack_notifier; | 329 | struct kvm_irq_ack_notifier ack_notifier; |
| 324 | struct work_struct interrupt_work; | 330 | struct work_struct interrupt_work; |
| @@ -326,13 +332,17 @@ struct kvm_assigned_dev_kernel { | |||
| 326 | int assigned_dev_id; | 332 | int assigned_dev_id; |
| 327 | int host_busnr; | 333 | int host_busnr; |
| 328 | int host_devfn; | 334 | int host_devfn; |
| 335 | unsigned int entries_nr; | ||
| 329 | int host_irq; | 336 | int host_irq; |
| 330 | bool host_irq_disabled; | 337 | bool host_irq_disabled; |
| 338 | struct msix_entry *host_msix_entries; | ||
| 331 | int guest_irq; | 339 | int guest_irq; |
| 340 | struct kvm_guest_msix_entry *guest_msix_entries; | ||
| 332 | #define KVM_ASSIGNED_DEV_GUEST_INTX (1 << 0) | 341 | #define KVM_ASSIGNED_DEV_GUEST_INTX (1 << 0) |
| 333 | #define KVM_ASSIGNED_DEV_GUEST_MSI (1 << 1) | 342 | #define KVM_ASSIGNED_DEV_GUEST_MSI (1 << 1) |
| 334 | #define KVM_ASSIGNED_DEV_HOST_INTX (1 << 8) | 343 | #define KVM_ASSIGNED_DEV_HOST_INTX (1 << 8) |
| 335 | #define KVM_ASSIGNED_DEV_HOST_MSI (1 << 9) | 344 | #define KVM_ASSIGNED_DEV_HOST_MSI (1 << 9) |
| 345 | #define KVM_ASSIGNED_DEV_MSIX ((1 << 2) | (1 << 10)) | ||
| 336 | unsigned long irq_requested_type; | 346 | unsigned long irq_requested_type; |
| 337 | int irq_source_id; | 347 | int irq_source_id; |
| 338 | int flags; | 348 | int flags; |
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 4d0dd390aa50..1ceb96901f32 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
| @@ -1593,6 +1593,88 @@ static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset) | |||
| 1593 | return 0; | 1593 | return 0; |
| 1594 | } | 1594 | } |
| 1595 | 1595 | ||
| 1596 | #ifdef __KVM_HAVE_MSIX | ||
| 1597 | static int kvm_vm_ioctl_set_msix_nr(struct kvm *kvm, | ||
| 1598 | struct kvm_assigned_msix_nr *entry_nr) | ||
| 1599 | { | ||
| 1600 | int r = 0; | ||
| 1601 | struct kvm_assigned_dev_kernel *adev; | ||
| 1602 | |||
| 1603 | mutex_lock(&kvm->lock); | ||
| 1604 | |||
| 1605 | adev = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head, | ||
| 1606 | entry_nr->assigned_dev_id); | ||
| 1607 | if (!adev) { | ||
| 1608 | r = -EINVAL; | ||
| 1609 | goto msix_nr_out; | ||
| 1610 | } | ||
| 1611 | |||
| 1612 | if (adev->entries_nr == 0) { | ||
| 1613 | adev->entries_nr = entry_nr->entry_nr; | ||
| 1614 | if (adev->entries_nr == 0 || | ||
| 1615 | adev->entries_nr >= KVM_MAX_MSIX_PER_DEV) { | ||
| 1616 | r = -EINVAL; | ||
| 1617 | goto msix_nr_out; | ||
| 1618 | } | ||
| 1619 | |||
| 1620 | adev->host_msix_entries = kzalloc(sizeof(struct msix_entry) * | ||
| 1621 | entry_nr->entry_nr, | ||
| 1622 | GFP_KERNEL); | ||
| 1623 | if (!adev->host_msix_entries) { | ||
| 1624 | r = -ENOMEM; | ||
| 1625 | goto msix_nr_out; | ||
| 1626 | } | ||
| 1627 | adev->guest_msix_entries = kzalloc( | ||
| 1628 | sizeof(struct kvm_guest_msix_entry) * | ||
| 1629 | entry_nr->entry_nr, GFP_KERNEL); | ||
| 1630 | if (!adev->guest_msix_entries) { | ||
| 1631 | kfree(adev->host_msix_entries); | ||
| 1632 | r = -ENOMEM; | ||
| 1633 | goto msix_nr_out; | ||
| 1634 | } | ||
| 1635 | } else /* Not allowed set MSI-X number twice */ | ||
| 1636 | r = -EINVAL; | ||
| 1637 | msix_nr_out: | ||
| 1638 | mutex_unlock(&kvm->lock); | ||
| 1639 | return r; | ||
| 1640 | } | ||
| 1641 | |||
| 1642 | static int kvm_vm_ioctl_set_msix_entry(struct kvm *kvm, | ||
| 1643 | struct kvm_assigned_msix_entry *entry) | ||
| 1644 | { | ||
| 1645 | int r = 0, i; | ||
| 1646 | struct kvm_assigned_dev_kernel *adev; | ||
| 1647 | |||
| 1648 | mutex_lock(&kvm->lock); | ||
| 1649 | |||
| 1650 | adev = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head, | ||
| 1651 | entry->assigned_dev_id); | ||
| 1652 | |||
| 1653 | if (!adev) { | ||
| 1654 | r = -EINVAL; | ||
| 1655 | goto msix_entry_out; | ||
| 1656 | } | ||
| 1657 | |||
| 1658 | for (i = 0; i < adev->entries_nr; i++) | ||
| 1659 | if (adev->guest_msix_entries[i].vector == 0 || | ||
| 1660 | adev->guest_msix_entries[i].entry == entry->entry) { | ||
| 1661 | adev->guest_msix_entries[i].entry = entry->entry; | ||
| 1662 | adev->guest_msix_entries[i].vector = entry->gsi; | ||
| 1663 | adev->host_msix_entries[i].entry = entry->entry; | ||
| 1664 | break; | ||
| 1665 | } | ||
| 1666 | if (i == adev->entries_nr) { | ||
| 1667 | r = -ENOSPC; | ||
| 1668 | goto msix_entry_out; | ||
| 1669 | } | ||
| 1670 | |||
| 1671 | msix_entry_out: | ||
| 1672 | mutex_unlock(&kvm->lock); | ||
| 1673 | |||
| 1674 | return r; | ||
| 1675 | } | ||
| 1676 | #endif | ||
| 1677 | |||
| 1596 | static long kvm_vcpu_ioctl(struct file *filp, | 1678 | static long kvm_vcpu_ioctl(struct file *filp, |
| 1597 | unsigned int ioctl, unsigned long arg) | 1679 | unsigned int ioctl, unsigned long arg) |
| 1598 | { | 1680 | { |
| @@ -1917,7 +1999,29 @@ static long kvm_vm_ioctl(struct file *filp, | |||
| 1917 | vfree(entries); | 1999 | vfree(entries); |
| 1918 | break; | 2000 | break; |
| 1919 | } | 2001 | } |
| 2002 | #ifdef __KVM_HAVE_MSIX | ||
| 2003 | case KVM_ASSIGN_SET_MSIX_NR: { | ||
| 2004 | struct kvm_assigned_msix_nr entry_nr; | ||
| 2005 | r = -EFAULT; | ||
| 2006 | if (copy_from_user(&entry_nr, argp, sizeof entry_nr)) | ||
| 2007 | goto out; | ||
| 2008 | r = kvm_vm_ioctl_set_msix_nr(kvm, &entry_nr); | ||
| 2009 | if (r) | ||
| 2010 | goto out; | ||
| 2011 | break; | ||
| 2012 | } | ||
| 2013 | case KVM_ASSIGN_SET_MSIX_ENTRY: { | ||
| 2014 | struct kvm_assigned_msix_entry entry; | ||
| 2015 | r = -EFAULT; | ||
| 2016 | if (copy_from_user(&entry, argp, sizeof entry)) | ||
| 2017 | goto out; | ||
| 2018 | r = kvm_vm_ioctl_set_msix_entry(kvm, &entry); | ||
| 2019 | if (r) | ||
| 2020 | goto out; | ||
| 2021 | break; | ||
| 2022 | } | ||
| 1920 | #endif | 2023 | #endif |
| 2024 | #endif /* KVM_CAP_IRQ_ROUTING */ | ||
| 1921 | default: | 2025 | default: |
| 1922 | r = kvm_arch_vm_ioctl(filp, ioctl, arg); | 2026 | r = kvm_arch_vm_ioctl(filp, ioctl, arg); |
| 1923 | } | 2027 | } |
