Make use of the new KVM feature that allows legacy interrupt sharing for PCI-2.3-compliant devices. As exclusive mode (with IRQ masking at interrupt controller level) is generally faster, the new mode has to be enabled explicitly via the property "host_pci_2_3". Signed-off-by: Jan Kiszka <jan.kiszka@xxxxxxxxxxx> --- hw/device-assignment.c | 37 ++++++++++++++++++++++++++++++------- hw/device-assignment.h | 3 +++ qemu-kvm.c | 8 ++++++++ qemu-kvm.h | 3 +++ 4 files changed, 44 insertions(+), 7 deletions(-) diff --git a/hw/device-assignment.c b/hw/device-assignment.c index 5f5bde1..30e05f1 100644 --- a/hw/device-assignment.c +++ b/hw/device-assignment.c @@ -404,12 +404,18 @@ static uint8_t pci_find_cap_offset(PCIDevice *d, uint8_t cap) return 0; } +static uint32_t calc_assigned_dev_id(uint16_t seg, uint8_t bus, uint8_t devfn) +{ + return (uint32_t)seg << 16 | (uint32_t)bus << 8 | (uint32_t)devfn; +} + static void assigned_dev_pci_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { int fd; ssize_t ret; AssignedDevice *pci_dev = container_of(d, AssignedDevice, dev); + struct kvm_assigned_pci_dev assigned_dev_data; DEBUG("(%x.%x): address=%04x val=0x%08x len=%d\n", ((d->devfn >> 3) & 0x1F), (d->devfn & 0x7), @@ -417,6 +423,17 @@ static void assigned_dev_pci_write_config(PCIDevice *d, uint32_t address, if (address == 0x4) { pci_default_write_config(d, address, val, len); + pci_dev->intx_masked = val & PCI_COMMAND_INTX_DISABLE; +#ifdef KVM_CAP_PCI_2_3 + memset(&assigned_dev_data, 0, sizeof(assigned_dev_data)); + assigned_dev_data.assigned_dev_id = + calc_assigned_dev_id(pci_dev->h_segnr, pci_dev->h_busnr, + pci_dev->h_devfn); + if (pci_dev->intx_masked) { + assigned_dev_data.flags = KVM_DEV_ASSIGN_MASK_INTX; + } + kvm_assign_set_intx_mask(kvm_context, &assigned_dev_data); +#endif /* Continue to program the card */ } @@ -494,6 +511,10 @@ do_log: else if (address == 6) val &= ~0x10; } + if (address == PCI_COMMAND) { + val &= ~PCI_COMMAND_INTX_DISABLE; + val |= pci_dev->intx_masked; + } return val; } @@ -824,11 +845,6 @@ static void free_assigned_device(AssignedDevice *dev) } } -static uint32_t calc_assigned_dev_id(uint16_t seg, uint8_t bus, uint8_t devfn) -{ - return (uint32_t)seg << 16 | (uint32_t)bus << 8 | (uint32_t)devfn; -} - static void assign_failed_examine(AssignedDevice *dev) { char name[PATH_MAX], dir[PATH_MAX], driver[PATH_MAX] = {}, *ns; @@ -919,6 +935,11 @@ static int assign_device(AssignedDevice *dev) "cause host memory corruption if the device issues DMA write " "requests!\n"); } +#ifdef KVM_CAP_PCI_2_3 + if (dev->features & ASSIGNED_DEVICE_USE_PCI_2_3_MASK) { + assigned_dev_data.flags |= KVM_DEV_ASSIGN_PCI_2_3; + } +#endif /* KVM_CAP_PCI_2_3 */ r = kvm_assign_pci_device(kvm_context, &assigned_dev_data); if (r < 0) { @@ -981,8 +1002,8 @@ static int assign_irq(AssignedDevice *dev) if (r < 0) { fprintf(stderr, "Failed to assign irq for \"%s\": %s\n", dev->dev.qdev.id, strerror(-r)); - fprintf(stderr, "Perhaps you are assigning a device " - "that shares an IRQ with another device?\n"); + fprintf(stderr, "If the assigned device shares an IRQ with another " + "device, try host_pci_2_3=on.\n"); return r; } @@ -1554,6 +1575,8 @@ static PCIDeviceInfo assign_info = { ASSIGNED_DEVICE_USE_IOMMU_BIT, true), DEFINE_PROP_BIT("prefer_msi", AssignedDevice, features, ASSIGNED_DEVICE_PREFER_MSI_BIT, true), + DEFINE_PROP_BIT("host_pci_2_3", AssignedDevice, features, + ASSIGNED_DEVICE_USE_PCI_2_3_BIT, false), DEFINE_PROP_STRING("configfd", AssignedDevice, configfd_name), DEFINE_PROP_END_OF_LIST(), }, diff --git a/hw/device-assignment.h b/hw/device-assignment.h index c94a730..71ba94c 100644 --- a/hw/device-assignment.h +++ b/hw/device-assignment.h @@ -76,15 +76,18 @@ typedef struct { #define ASSIGNED_DEVICE_USE_IOMMU_BIT 0 #define ASSIGNED_DEVICE_PREFER_MSI_BIT 1 +#define ASSIGNED_DEVICE_USE_PCI_2_3_BIT 2 #define ASSIGNED_DEVICE_USE_IOMMU_MASK (1 << ASSIGNED_DEVICE_USE_IOMMU_BIT) #define ASSIGNED_DEVICE_PREFER_MSI_MASK (1 << ASSIGNED_DEVICE_PREFER_MSI_BIT) +#define ASSIGNED_DEVICE_USE_PCI_2_3_MASK (1 << ASSIGNED_DEVICE_USE_PCI_2_3_BIT) typedef struct AssignedDevice { PCIDevice dev; PCIHostDevice host; uint32_t features; int intpin; + uint32_t intx_masked; uint8_t debug_flags; AssignedDevRegion v_addrs[PCI_NUM_REGIONS - 1]; PCIDevRegions real_device; diff --git a/qemu-kvm.c b/qemu-kvm.c index 471306b..8157b4f 100644 --- a/qemu-kvm.c +++ b/qemu-kvm.c @@ -740,6 +740,14 @@ int kvm_deassign_pci_device(kvm_context_t kvm, } #endif +#ifdef KVM_CAP_PCI_2_3 +int kvm_assign_set_intx_mask(kvm_context_t kvm, + struct kvm_assigned_pci_dev *assigned_dev) +{ + return kvm_vm_ioctl(kvm_state, KVM_ASSIGN_SET_INTX_MASK, assigned_dev); +} +#endif + int kvm_reinject_control(kvm_context_t kvm, int pit_reinject) { #ifdef KVM_CAP_REINJECT_CONTROL diff --git a/qemu-kvm.h b/qemu-kvm.h index 0f3fb50..7f26f1a 100644 --- a/qemu-kvm.h +++ b/qemu-kvm.h @@ -631,6 +631,9 @@ int kvm_assign_set_msix_entry(kvm_context_t kvm, struct kvm_assigned_msix_entry *entry); #endif +int kvm_assign_set_intx_mask(kvm_context_t kvm, + struct kvm_assigned_pci_dev *assigned_dev); + #else /* !CONFIG_KVM */ typedef struct kvm_context *kvm_context_t; -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html