pci-assign: Use PCI-2.3-based shared legacy interrupts
PATCH 1/1 pci-assign: Use PCI-2.3-based shared legacy interrupts
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".
--- 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(-)
hw/device-assignment.c +30 -7
@@ -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(), },
hw/device-assignment.h +3 -0
@@ -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;
qemu-kvm.c +8 -0
@@ -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
qemu-kvm.h +3 -0
@@ -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 ;
Signature · 1 line
1.7.1
Quoted 19 lines · Jan Kiszka
hw/device-assignment.c +11
-0@@ -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 */ }
hw/device-assignment.c do_log: · line 514
Quoted 4 lines
hw/device-assignment.c +1
-0@@ -494,6 +511,10 @@ do_log:else if (address ==6 ) val &= ~0x10 ; } +if (address ==PCI_COMMAND ) {
Could also be a single-byte write into the high byte of this word.
Quoted 7 lines
hw/device-assignment.c +3
-0+ val &= ~PCI_COMMAND_INTX_DISABLE ; + val |= pci_dev->intx_masked; + }return val; }@@ -824,11 +845,6 @@ static void free_assigned_device(AssignedDevice *dev)
Quoted 19 lines · Michael S. Tsirkin
Quoted 18 lines · Jan Kiszka
hw/device-assignment.c +11
-0@@ -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 */ }
Quoted 8 lines
hw/device-assignment.c do_log: · line 514
Quoted 5 lines
hw/device-assignment.c +1
-0@@ -494,6 +511,10 @@ do_log:else if (address ==6 ) val &= ~0x10 ; } +if (address ==PCI_COMMAND ) {Could also be a single-byte write into the high byte of this word.
Yes, will fix.
Jan
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux
Quoted 29 lines · Jan Kiszka
Quoted 19 lines · Michael S. Tsirkin
Quoted 18 lines · Jan Kiszka
hw/device-assignment.c +11
-0@@ -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 */ }Quoted 8 lines
hw/device-assignment.c do_log: · line 514
Quoted 5 lines
hw/device-assignment.c +1
-0@@ -494,6 +511,10 @@ do_log:else if (address ==6 ) val &= ~0x10 ; } +if (address ==PCI_COMMAND ) {Could also be a single-byte write into the high byte of this word.
Quoted 3 lines
Yes, will fix.
Jan
I think assigned devices call default write config, don't they? If yes you can just check
pci_get_word(d->config + PCI_COMMAND) & PCI_COMMAND_INTX_DISABLE
Quoted 3 lines
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux