Expose MSI-X capabilty to guest if the assigned device got it.

Signed-off-by: Sheng Yang <[email protected]>
---
 qemu/hw/device-assignment.c |   82 +++++++++++++++++++++++++++++++++++++++++--
 qemu/hw/device-assignment.h |    3 ++
 2 files changed, 82 insertions(+), 3 deletions(-)

diff --git a/qemu/hw/device-assignment.c b/qemu/hw/device-assignment.c
index 61d3f66..2d0c8a5 100644
--- a/qemu/hw/device-assignment.c
+++ b/qemu/hw/device-assignment.c
@@ -570,7 +570,9 @@ void assigned_dev_update_irq(PCIDevice *d)
     }
 }
 
-#if defined(KVM_CAP_DEVICE_MSI) && defined (KVM_CAP_GSI_MSG)
+#ifdef KVM_CAP_GSI_MSG
+
+#ifdef KVM_CAP_DEVICE_MSI
 static void assigned_dev_update_msi(PCIDevice *pci_dev, unsigned int ctrl_pos)
 {
     struct kvm_assigned_irq assigned_irq_data;
@@ -610,6 +612,45 @@ static void assigned_dev_update_msi(PCIDevice *pci_dev, 
unsigned int ctrl_pos)
 }
 #endif
 
+#ifdef KVM_CAP_DEVICE_MSIX
+static void assigned_dev_update_msix(PCIDevice *pci_dev, unsigned int ctrl_pos)
+{
+    struct kvm_assigned_irq assigned_irq_data;
+    AssignedDevice *assigned_dev = container_of(pci_dev, AssignedDevice, dev);
+    uint16_t *ctrl_word = (uint16_t *)(pci_dev->cap.config + ctrl_pos);
+
+    memset(&assigned_irq_data, 0, sizeof assigned_irq_data);
+    assigned_irq_data.assigned_dev_id  =
+            calc_assigned_dev_id(assigned_dev->h_busnr,
+                    (uint8_t)assigned_dev->h_devfn);
+
+    assigned_irq_data.flags = KVM_DEV_IRQ_ASSIGN_MSIX_ACTION;
+    if (*ctrl_word & PCI_MSIX_ENABLE)
+        assigned_irq_data.flags |= KVM_DEV_IRQ_ASSIGN_ENABLE_MSIX;
+    if (*ctrl_word & PCI_MSIX_MASK)
+        assigned_irq_data.flags |= KVM_DEV_IRQ_ASSIGN_MASK_MSIX;
+
+    if (kvm_assign_irq(kvm_context, &assigned_irq_data) < 0)
+        perror("assigned_dev_enable_msi");
+
+    if (assigned_irq_data.flags & KVM_DEV_IRQ_ASSIGN_ENABLE_MSIX) {
+        assigned_dev->cap.state |= ASSIGNED_DEVICE_MSIX_ENABLED;
+        *ctrl_word |= PCI_MSIX_ENABLE;
+    } else {
+        assigned_dev->cap.state &= ~ASSIGNED_DEVICE_MSIX_ENABLED;
+        *ctrl_word &= ~PCI_MSIX_ENABLE;
+    }
+    if (assigned_irq_data.flags & KVM_DEV_IRQ_ASSIGN_MASK_MSIX) {
+        assigned_dev->cap.state |= ASSIGNED_DEVICE_MSIX_MASKED;
+        *ctrl_word |= PCI_MSIX_MASK;
+    } else {
+        assigned_dev->cap.state &= ~ASSIGNED_DEVICE_MSIX_MASKED;
+        *ctrl_word &= ~PCI_MSIX_MASK;
+    }
+}
+#endif
+#endif
+
 void assigned_device_pci_cap_write_config(PCIDevice *pci_dev, uint32_t address,
                                           uint32_t val, int len)
 {
@@ -617,7 +658,8 @@ void assigned_device_pci_cap_write_config(PCIDevice 
*pci_dev, uint32_t address,
     unsigned int pos = pci_dev->cap.start, ctrl_pos;
 
     pci_default_cap_write_config(pci_dev, address, val, len);
-#if defined(KVM_CAP_DEVICE_MSI) && defined (KVM_CAP_GSI_MSG)
+#ifdef KVM_CAP_GSI_MSG
+#ifdef KVM_CAP_DEVICE_MSI
     if (assigned_dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) {
         ctrl_pos = pos + PCI_MSI_FLAGS;
         if (address <= ctrl_pos && address + len > ctrl_pos)
@@ -625,6 +667,17 @@ void assigned_device_pci_cap_write_config(PCIDevice 
*pci_dev, uint32_t address,
         pos += PCI_CAPABILITY_CONFIG_MSI_LENGTH;
     }
 #endif
+#ifdef KVM_CAP_DEVICE_MSIX
+    if (assigned_dev->cap.available & ASSIGNED_DEVICE_CAP_MSI) {
+        ctrl_pos = pos + 3;
+        if (address <= ctrl_pos && address + len > ctrl_pos) {
+            ctrl_pos--; /* control is word long */
+            assigned_dev_update_msix(pci_dev, ctrl_pos - pci_dev->cap.start);
+       }
+        pos += PCI_CAPABILITY_CONFIG_MSIX_LENGTH;
+    }
+#endif
+#endif
     return;
 }
 
@@ -643,7 +696,8 @@ void assigned_device_pci_cap_init(PCIDevice *pci_dev)
     pci_init(pacc);
     dev->pdev = pci_get_dev(pacc, 0, h_bus, h_dev, h_func);
     pci_cleanup(pacc);
-#if defined(KVM_CAP_DEVICE_MSI) && defined (KVM_CAP_GSI_MSG)
+#ifdef KVM_CAP_GSI_MSG
+#ifdef KVM_CAP_DEVICE_MSI
     /* Expose MSI capability
      * MSI capability is the 1st capability in cap.config */
     if (pci_find_cap_offset(dev->pdev, PCI_CAP_ID_MSI)) {
@@ -653,6 +707,28 @@ void assigned_device_pci_cap_init(PCIDevice *pci_dev)
         next_cap_pt = 1;
     }
 #endif
+#ifdef KVM_CAP_DEVICE_MSIX
+    /* Expose MSI-X capability */
+    if (pci_find_cap_offset(dev->pdev, PCI_CAP_ID_MSIX)) {
+        int pos, entry_nr;
+        dev->cap.available |= ASSIGNED_DEVICE_CAP_MSIX;
+       pos = pci_find_cap_offset(dev->pdev, PCI_CAP_ID_MSIX);
+        entry_nr = pci_read_word(dev->pdev, pos + 2) & PCI_MSIX_TABSIZE;
+        pci_dev->cap.config[pci_dev->cap.length] = 0x11;
+        pci_dev->cap.config[pci_dev->cap.length + 2] = entry_nr;
+        *(uint32_t *)(pci_dev->cap.config +
+                      pci_dev->cap.length + PCI_MSIX_TABLE) =
+                    pci_read_long(dev->pdev, pos + PCI_MSIX_TABLE);
+        *(uint32_t *)(pci_dev->cap.config +
+                      pci_dev->cap.length + PCI_MSIX_PBA) =
+                    pci_read_long(dev->pdev, pos + PCI_MSIX_PBA);
+        pci_dev->cap.config[next_cap_pt] =
+                pci_dev->cap.start + pci_dev->cap.length;
+        pci_dev->cap.length += PCI_CAPABILITY_CONFIG_MSIX_LENGTH;
+        next_cap_pt += PCI_CAPABILITY_CONFIG_MSIX_LENGTH;
+    }
+#endif
+#endif
 }
 
 struct PCIDevice *init_assigned_device(AssignedDevInfo *adev, PCIBus *bus)
diff --git a/qemu/hw/device-assignment.h b/qemu/hw/device-assignment.h
index ea26de5..9348e2c 100644
--- a/qemu/hw/device-assignment.h
+++ b/qemu/hw/device-assignment.h
@@ -84,8 +84,11 @@ typedef struct {
     struct pci_dev *pdev;
     struct {
 #define ASSIGNED_DEVICE_CAP_MSI (1 << 0)
+#define ASSIGNED_DEVICE_CAP_MSIX (1 << 1)
         uint32_t available;
 #define ASSIGNED_DEVICE_MSI_ENABLED (1 << 0)
+#define ASSIGNED_DEVICE_MSIX_ENABLED (1 << 1)
+#define ASSIGNED_DEVICE_MSIX_MASKED (1 << 2)
         uint32_t state;
     } cap;
 } AssignedDevice;
-- 
1.5.4.5

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to