From ebb540ebeece2e934989c9f5944371cb5f0ae073 Mon Sep 17 00:00:00 2001 Message-Id: In-Reply-To: References: From: Alex Williamson Date: Thu, 23 May 2013 22:23:04 +0200 Subject: [PATCH 2/6] pci-assign: Add MSI affinity support RH-Author: Alex Williamson Message-id: <20130523222304.23855.86099.stgit@bling.home> Patchwork-id: 51615 O-Subject: [RHEL6.5 -E qemu-kvm PATCH] pci-assign: Add MSI affinity support Bugzilla: 919761 RH-Acked-by: Laszlo Ersek RH-Acked-by: Michael S. Tsirkin RH-Acked-by: Don Dutile Bugzilla: 919761 Upstream commit: 3459f01b2d9612070ec23221a4ccb60a41b775ae (qemu.git) Testing: Tested with e1000e 82578DM supporting MSI/INTx-only. Without this, RHEL5 guests do nothing on IRQ smp_affinity update because MSI enable isn't toggled. RHEL6 guests do toggle MSI enabled, but the sequence it uses causes smp_affinity to use the previous CPU targets, so two updates are required to get the desired targets. With patch both work as expected. Backport notes: Code is significantly different from upstream. Compare to assigned_dev_update_msi for creating routing entry and extracting address/data from the MSI capability and msix_mmio_writel for performing an update of a routing entry. Brew: https://brewweb.devel.redhat.com/taskinfo?taskID=5820217 To support guest MSI affinity changes update the MSI message any time the guest writes to the address or data fields. Signed-off-by: Alex Williamson Acked-by: Michael S. Tsirkin Message-id: 20130513201840.5430.86331.stgit@bling.home Signed-off-by: Anthony Liguori --- hw/device-assignment.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) Signed-off-by: Michal Novotny --- hw/device-assignment.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/hw/device-assignment.c b/hw/device-assignment.c index 9d8d39e..4cc27a2 100644 --- a/hw/device-assignment.c +++ b/hw/device-assignment.c @@ -1132,6 +1132,53 @@ static void assigned_dev_update_msi(PCIDevice *pci_dev, unsigned int ctrl_pos) assigned_dev->irq_requested_type = assigned_irq_data.flags; } } + +static void assigned_dev_update_msi_msg(PCIDevice *pci_dev, + unsigned int ctrl_pos) +{ + AssignedDevice *assigned_dev = container_of(pci_dev, AssignedDevice, dev); + uint8_t ctrl_byte = pci_dev->config[ctrl_pos]; + struct kvm_irq_routing_entry *orig; + int pos, ret; + + if (!(assigned_dev->irq_requested_type & KVM_DEV_IRQ_GUEST_MSI) || + !(ctrl_byte & PCI_MSI_FLAGS_ENABLE)) { + return; + } + + orig = assigned_dev->entry; + pos = ctrl_pos - PCI_MSI_FLAGS; + + assigned_dev->entry = calloc(1, sizeof(struct kvm_irq_routing_entry)); + if (!assigned_dev->entry) { + assigned_dev->entry = orig; + perror("assigned_dev_update_msi_msg: "); + return; + } + + assigned_dev->entry->u.msi.address_lo = + pci_get_long(pci_dev->config + pos + PCI_MSI_ADDRESS_LO); + assigned_dev->entry->u.msi.address_hi = 0; + assigned_dev->entry->u.msi.data = + pci_get_word(pci_dev->config + pos + PCI_MSI_DATA_32); + assigned_dev->entry->type = KVM_IRQ_ROUTING_MSI; + assigned_dev->entry->gsi = orig->gsi; + + ret = kvm_update_routing_entry(kvm_context, orig, assigned_dev->entry); + if (ret) { + fprintf(stderr, "Error updating MSI irq routing entry (%d)\n", ret); + free(assigned_dev->entry); + assigned_dev->entry = orig; + return; + } + + free(orig); + + ret = kvm_commit_irq_routes(kvm_context); + if (ret) { + fprintf(stderr, "Error committing MSI irq route (%d)\n", ret); + } +} #endif #ifdef KVM_CAP_DEVICE_MSIX @@ -1362,6 +1409,9 @@ static void assigned_device_pci_cap_write_config(PCIDevice *pci_dev, uint8_t cap = pci_find_capability(pci_dev, cap_id); if (ranges_overlap(address - cap, len, PCI_MSI_FLAGS, 1)) { assigned_dev_update_msi(pci_dev, cap + PCI_MSI_FLAGS); + } else if (ranges_overlap(address - cap, len, /* 32bit MSI only */ + PCI_MSI_ADDRESS_LO, 6)) { + assigned_dev_update_msi_msg(pci_dev, cap + PCI_MSI_FLAGS); } } #endif -- 1.7.11.7