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 | } |