This reuses the MSI routing infrastructure of the KVM core by folding both the routing setup and the IRQ assignment into a new function called kvm_device_msi_assign. It's also a good chance to clean up the IRQ deassignment before updates. Signed-off-by: Jan Kiszka <jan.kiszka@xxxxxxxxxxx> --- hw/device-assignment.c | 70 +++++++++++++---------------------------------- qemu-kvm.c | 16 +++++++++++ qemu-kvm.h | 2 + 3 files changed, 38 insertions(+), 50 deletions(-) diff --git a/hw/device-assignment.c b/hw/device-assignment.c index f145a84..7a8f702 100644 --- a/hw/device-assignment.c +++ b/hw/device-assignment.c @@ -40,6 +40,7 @@ #include "monitor.h" #include "range.h" #include "sysemu.h" +#include "msi.h" #define MSIX_PAGE_SIZE 0x1000 @@ -701,6 +702,11 @@ static void free_assigned_device(AssignedDevice *dev) } free_dev_irq_entries(dev); + + if (dev->dev.msi_cache) { + kvm_msi_cache_invalidate(&dev->dev.msi_cache[0]); + g_free(dev->dev.msi_cache); + } } static uint32_t calc_assigned_dev_id(AssignedDevice *dev) @@ -918,66 +924,28 @@ void assigned_dev_update_irqs(void) static void assigned_dev_update_msi(PCIDevice *pci_dev) { - struct kvm_assigned_irq assigned_irq_data; - AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, pci_dev); + AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev); uint8_t ctrl_byte = pci_get_byte(pci_dev->config + pci_dev->msi_cap + PCI_MSI_FLAGS); - uint32_t dev_id; - int r; - - dev_id = calc_assigned_dev_id(assigned_dev); - - /* Some guests gratuitously disable MSI even if they're not using it, - * try to catch this by only deassigning irqs if the guest is using - * MSI or intends to start. */ - if ((assigned_dev->irq_requested_type & KVM_DEV_IRQ_GUEST_MSI) || - (ctrl_byte & PCI_MSI_FLAGS_ENABLE)) { - free_dev_irq_entries(assigned_dev); - r = kvm_device_irq_deassign(kvm_state, dev_id, - assigned_dev->irq_requested_type); - /* -ENXIO means no assigned irq */ - if (r && r != -ENXIO) - perror("assigned_dev_update_msi: deassign irq"); - - assigned_dev->irq_requested_type = 0; - } if (ctrl_byte & PCI_MSI_FLAGS_ENABLE) { uint8_t *pos = pci_dev->config + pci_dev->msi_cap; + MSIMessage msg; - assigned_dev->entry = g_malloc0(sizeof(*(assigned_dev->entry))); - assigned_dev->entry->u.msi.address_lo = - pci_get_long(pos + PCI_MSI_ADDRESS_LO); - assigned_dev->entry->u.msi.address_hi = 0; - assigned_dev->entry->u.msi.data = pci_get_word(pos + PCI_MSI_DATA_32); - assigned_dev->entry->type = KVM_IRQ_ROUTING_MSI; - r = kvm_get_irq_route_gsi(); - if (r < 0) { - perror("assigned_dev_update_msi: kvm_get_irq_route_gsi"); - return; - } - assigned_dev->entry->gsi = r; + deassign_irq(dev); - kvm_add_routing_entry(assigned_dev->entry, NULL); - if (kvm_commit_irq_routes() < 0) { - perror("assigned_dev_update_msi: kvm_commit_irq_routes"); - assigned_dev->cap.state &= ~ASSIGNED_DEVICE_MSI_ENABLED; - return; - } - assigned_dev->irq_entries_nr = 1; + msg.address = pci_get_long(pos + PCI_MSI_ADDRESS_LO); + msg.data = pci_get_word(pos + PCI_MSI_DATA_32); - memset(&assigned_irq_data, 0, sizeof assigned_irq_data); - assigned_irq_data.assigned_dev_id = dev_id; - assigned_irq_data.guest_irq = assigned_dev->entry->gsi; - assigned_irq_data.flags = KVM_DEV_IRQ_HOST_MSI | KVM_DEV_IRQ_GUEST_MSI; - if (kvm_assign_irq(kvm_state, &assigned_irq_data) < 0) { - perror("assigned_dev_enable_msi: assign irq"); + if (kvm_device_msi_assign(kvm_state, calc_assigned_dev_id(dev), &msg, + &dev->dev.msi_cache[0]) < 0) { + perror("assigned_dev_update_msi: assign msi"); + return; } - - assigned_dev->girq = -1; - assigned_dev->irq_requested_type = assigned_irq_data.flags; + dev->irq_requested_type = KVM_DEV_IRQ_HOST_MSI | KVM_DEV_IRQ_GUEST_MSI; } else { - assign_intx(assigned_dev); + kvm_msi_cache_invalidate(&dev->dev.msi_cache[0]); + assign_intx(dev); } } @@ -1215,6 +1183,8 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev) PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); pci_set_long(pci_dev->wmask + pos + PCI_MSI_ADDRESS_LO, 0xfffffffc); pci_set_word(pci_dev->wmask + pos + PCI_MSI_DATA_32, 0xffff); + + dev->dev.msi_cache = g_malloc0(sizeof(MSIRoutingCache)); } /* Expose MSI-X capability */ pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_MSIX, 0); diff --git a/qemu-kvm.c b/qemu-kvm.c index 0086514..27723a6 100644 --- a/qemu-kvm.c +++ b/qemu-kvm.c @@ -600,6 +600,22 @@ int kvm_msi_irqfd_set(MSIMessage *msg, MSIRoutingCache *cache, int fd, return kvm_set_irqfd(cache->kvm_gsi, fd, assigned); } +int kvm_device_msi_assign(KVMState *s, uint32_t dev_id, MSIMessage *msg, + MSIRoutingCache *cache) +{ + struct kvm_assigned_irq assigned_irq; + int ret; + + ret = kvm_msi_message_update(msg, cache, MSI_ROUTE_STATIC); + if (ret < 0) { + return ret; + } + assigned_irq.assigned_dev_id = dev_id; + assigned_irq.guest_irq = cache->kvm_gsi; + assigned_irq.flags = KVM_DEV_IRQ_HOST_MSI | KVM_DEV_IRQ_GUEST_MSI; + return kvm_vm_ioctl(s, KVM_ASSIGN_DEV_IRQ, &assigned_irq); +} + #ifdef KVM_CAP_DEVICE_MSIX int kvm_assign_set_msix_nr(KVMState *s, struct kvm_assigned_msix_nr *msix_nr) { diff --git a/qemu-kvm.h b/qemu-kvm.h index 783df7f..d987d41 100644 --- a/qemu-kvm.h +++ b/qemu-kvm.h @@ -152,6 +152,8 @@ int kvm_assign_irq(KVMState *s, struct kvm_assigned_irq *assigned_irq); int kvm_device_intx_assign(KVMState *s, uint32_t dev_id, uint32_t host_irq_type, uint32_t guest_irq); +int kvm_device_msi_assign(KVMState *s, uint32_t dev_id, MSIMessage *msg, + MSIRoutingCache *cache); int kvm_device_irq_deassign(KVMState *s, uint32_t dev_id, uint32_t type); /*! -- 1.7.3.4 -- 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