diff mbox

[v4,1/6] hw/msi: Allow platform devices to use explicit SID

Message ID 1473674889-2727-2-git-send-email-davidkiarie4@gmail.com
State New
Headers show

Commit Message

David Kiarie Sept. 12, 2016, 10:08 a.m. UTC
When using IOMMU platform devices like IOAPIC are required to make
interrupt remapping requests using explicit SID.We affiliate an MSI
route with a requester ID and a PCI device if present which ensures
that platform devices can call IOMMU interrupt remapping code with
explicit SID while maintaining compatility with the original code
which mainly dealt with PCI devices.

Signed-off-by: David Kiarie <davidkiarie4@gmail.com>
---
 hw/i386/intel_iommu.c             |  3 +++
 hw/i386/kvm/pci-assign.c          | 12 ++++++++----
 hw/intc/ioapic.c                  | 31 ++++++++++++++++++++++++++-----
 hw/misc/ivshmem.c                 |  6 ++++--
 hw/vfio/pci.c                     |  6 ++++--
 hw/virtio/virtio-pci.c            |  7 +++++--
 include/hw/i386/ioapic_internal.h |  1 +
 include/hw/i386/x86-iommu.h       |  1 +
 include/sysemu/kvm.h              | 25 ++++++++++++++-----------
 kvm-all.c                         | 10 ++++++----
 kvm-stub.c                        |  5 +++--
 qemu-version.h                    |  1 +
 target-i386/kvm.c                 | 15 +++++++++------
 13 files changed, 85 insertions(+), 38 deletions(-)
 create mode 100644 qemu-version.h

Comments

Peter Xu Sept. 12, 2016, 11:02 a.m. UTC | #1
On Mon, Sep 12, 2016 at 01:08:04PM +0300, David Kiarie wrote:
> When using IOMMU platform devices like IOAPIC are required to make
> interrupt remapping requests using explicit SID.We affiliate an MSI
> route with a requester ID and a PCI device if present which ensures
> that platform devices can call IOMMU interrupt remapping code with
> explicit SID while maintaining compatility with the original code
> which mainly dealt with PCI devices.

Nit: IMHO it'll be cooler and easier to understand if we can avoid
using very long sentences like above...

[...]

> diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
> index 31791b0..f2d4c15 100644
> --- a/hw/intc/ioapic.c
> +++ b/hw/intc/ioapic.c
> @@ -95,9 +95,17 @@ static void ioapic_entry_parse(uint64_t entry, struct ioapic_entry_info *info)
>          (info->delivery_mode << MSI_DATA_DELIVERY_MODE_SHIFT);
>  }
>  
> -static void ioapic_service(IOAPICCommonState *s)
> +static void ioapic_as_write(IOAPICCommonState *s, uint32_t data, uint64_t addr)
>  {
>      AddressSpace *ioapic_as = PC_MACHINE(qdev_get_machine())->ioapic_as;
> +    MemTxAttrs attrs;

Need to zero it first?

[...]

> @@ -383,14 +391,28 @@ static void ioapic_machine_done_notify(Notifier *notifier, void *data)
>      IOAPICCommonState *s = container_of(notifier, IOAPICCommonState,
>                                          machine_done);
>  
> +    X86IOMMUState *iommu = x86_iommu_get_default();
> +    /* kernel_irqchip=off */
> +    if (iommu) {
> +        s->devid = iommu->ioapic_bdf;
> +    }

Move out of "#ifdef CONFIG_KVM"?

[...]

> @@ -407,7 +429,6 @@ static void ioapic_realize(DeviceState *dev, Error **errp)
>  
>      memory_region_init_io(&s->io_memory, OBJECT(s), &ioapic_io_ops, s,
>                            "ioapic", 0x1000);
> -

Useless change.

[...]

> -int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
> +int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev, uint16_t requester_id)
>  {
>      struct kvm_irq_routing_entry kroute = {};
>      int virq;
> @@ -1275,7 +1275,8 @@ int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
>      kroute.u.msi.address_lo = (uint32_t)msg.address;
>      kroute.u.msi.address_hi = msg.address >> 32;
>      kroute.u.msi.data = le32_to_cpu(msg.data);
> -    if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data, dev)) {
> +    if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data,
> +                                 requester_id)) {

Can we just remove the PCIDevice parameter directly? I didn't go
deeper, but it seems to be explicitly introduced here:

    commit dc9f06ca81e6e16d062ec382701142a3a2ab3f7d
    Author: Pavel Fedin <p.fedin@samsung.com>
    Date:   Thu Oct 15 16:44:52 2015 +0300

        kvm: Pass PCI device pointer to MSI routing functions

And we'd better make sure we really wanted to remove it.

Also, I think we need to modify all target-*/kvm.c for this interface
change?

[...]

Btw, could you explain a bit about what kind of tests have you carried
out for this series (maybe also the AMD IOMMU general one)?

Thanks,

-- peterx
David Kiarie Sept. 12, 2016, 11:26 a.m. UTC | #2
On Mon, Sep 12, 2016 at 2:02 PM, Peter Xu <peterx@redhat.com> wrote:

> On Mon, Sep 12, 2016 at 01:08:04PM +0300, David Kiarie wrote:
> > When using IOMMU platform devices like IOAPIC are required to make
> > interrupt remapping requests using explicit SID.We affiliate an MSI
> > route with a requester ID and a PCI device if present which ensures
> > that platform devices can call IOMMU interrupt remapping code with
> > explicit SID while maintaining compatility with the original code
> > which mainly dealt with PCI devices.
>
> Nit: IMHO it'll be cooler and easier to understand if we can avoid
> using very long sentences like above...
>
> [...]
>
> > diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
> > index 31791b0..f2d4c15 100644
> > --- a/hw/intc/ioapic.c
> > +++ b/hw/intc/ioapic.c
> > @@ -95,9 +95,17 @@ static void ioapic_entry_parse(uint64_t entry, struct
> ioapic_entry_info *info)
> >          (info->delivery_mode << MSI_DATA_DELIVERY_MODE_SHIFT);
> >  }
> >
> > -static void ioapic_service(IOAPICCommonState *s)
> > +static void ioapic_as_write(IOAPICCommonState *s, uint32_t data,
> uint64_t addr)
> >  {
> >      AddressSpace *ioapic_as = PC_MACHINE(qdev_get_machine())
> ->ioapic_as;
> > +    MemTxAttrs attrs;
>
> Need to zero it first?
>
> [...]
>
> > @@ -383,14 +391,28 @@ static void ioapic_machine_done_notify(Notifier
> *notifier, void *data)
> >      IOAPICCommonState *s = container_of(notifier, IOAPICCommonState,
> >                                          machine_done);
> >
> > +    X86IOMMUState *iommu = x86_iommu_get_default();
> > +    /* kernel_irqchip=off */
> > +    if (iommu) {
> > +        s->devid = iommu->ioapic_bdf;
> > +    }
>
> Move out of "#ifdef CONFIG_KVM"?
>

Right, will move this out.


>
> [...]
>
> > @@ -407,7 +429,6 @@ static void ioapic_realize(DeviceState *dev, Error
> **errp)
> >
> >      memory_region_init_io(&s->io_memory, OBJECT(s), &ioapic_io_ops, s,
> >                            "ioapic", 0x1000);
> > -
>
> Useless change.
>
> [...]
>
> > -int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
> > +int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev,
> uint16_t requester_id)
> >  {
> >      struct kvm_irq_routing_entry kroute = {};
> >      int virq;
> > @@ -1275,7 +1275,8 @@ int kvm_irqchip_add_msi_route(KVMState *s, int
> vector, PCIDevice *dev)
> >      kroute.u.msi.address_lo = (uint32_t)msg.address;
> >      kroute.u.msi.address_hi = msg.address >> 32;
> >      kroute.u.msi.data = le32_to_cpu(msg.data);
> > -    if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data, dev))
> {
> > +    if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data,
> > +                                 requester_id)) {
>
> Can we just remove the PCIDevice parameter directly? I didn't go
> deeper, but it seems to be explicitly introduced here:
>
>     commit dc9f06ca81e6e16d062ec382701142a3a2ab3f7d
>     Author: Pavel Fedin <p.fedin@samsung.com>
>     Date:   Thu Oct 15 16:44:52 2015 +0300
>
>         kvm: Pass PCI device pointer to MSI routing functions
>
> And we'd better make sure we really wanted to remove it.
>
> Also, I think we need to modify all target-*/kvm.c for this interface
> change?
>

The current code keeps track of PCI devices for purposes of easily
constructing MSI messages

e.g in kvm_update_msi_routes_all which means to get rid of PCI device
pointer means we need another way to keep track of PCI devices.


>
> [...]
>
> Btw, could you explain a bit about what kind of tests have you carried
> out for this series (maybe also the AMD IOMMU general one)?
>

The tests done are pretty basic and manual. For DMA the related device
addresses are pretty static which means I can spot incorrect translations
in the logs. IR has also mainly been tested by watching the logs.


> Thanks,
>
> -- peterx
>
Peter Xu Sept. 12, 2016, 11:54 a.m. UTC | #3
On Mon, Sep 12, 2016 at 02:26:14PM +0300, David Kiarie wrote:

[...]

> > > -int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
> > > +int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev,
> > uint16_t requester_id)
> > >  {
> > >      struct kvm_irq_routing_entry kroute = {};
> > >      int virq;
> > > @@ -1275,7 +1275,8 @@ int kvm_irqchip_add_msi_route(KVMState *s, int
> > vector, PCIDevice *dev)
> > >      kroute.u.msi.address_lo = (uint32_t)msg.address;
> > >      kroute.u.msi.address_hi = msg.address >> 32;
> > >      kroute.u.msi.data = le32_to_cpu(msg.data);
> > > -    if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data, dev))
> > {
> > > +    if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data,
> > > +                                 requester_id)) {
> >
> > Can we just remove the PCIDevice parameter directly? I didn't go
> > deeper, but it seems to be explicitly introduced here:
> >
> >     commit dc9f06ca81e6e16d062ec382701142a3a2ab3f7d
> >     Author: Pavel Fedin <p.fedin@samsung.com>
> >     Date:   Thu Oct 15 16:44:52 2015 +0300
> >
> >         kvm: Pass PCI device pointer to MSI routing functions
> >
> > And we'd better make sure we really wanted to remove it.
> >
> > Also, I think we need to modify all target-*/kvm.c for this interface
> > change?
> >
> 
> The current code keeps track of PCI devices for purposes of easily
> constructing MSI messages
> 
> e.g in kvm_update_msi_routes_all which means to get rid of PCI device
> pointer means we need another way to keep track of PCI devices.

Actually I mean kvm_arch_fixup_msi_route(), not
kvm_{add|update}_msi_routes_all().

It looks like above commit (dc9f06ca81e) was preparing to pass in SID
in the future for ARM (though still haven't implemented on QEMU side).
So maybe removing PCIDevice is okay in this one since you are passing
in the SID directly. However I think possibly Paolo is the best one to
know the truth...

No matter what, you may still need to change the interface for other
platforms. Just try to grep kvm_arch_fixup_msi_route() in target-*/
directories. 

Thanks,

-- peterx
diff mbox

Patch

diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index d6e02c8..496d836 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -2466,6 +2466,9 @@  static void vtd_realize(DeviceState *dev, Error **errp)
     vtd_init(s);
     sysbus_mmio_map(SYS_BUS_DEVICE(s), 0, Q35_HOST_BRIDGE_IOMMU_ADDR);
     pci_setup_iommu(bus, vtd_host_dma_iommu, dev);
+    /* IOMMU expected IOAPIC SID */
+    x86_iommu->ioapic_bdf = PCI_BUILD_BDF(Q35_PSEUDO_DEVFN_IOAPIC,
+                            Q35_PSEUDO_DEVFN_IOAPIC);
     /* Pseudo address space under root PCI bus. */
     pcms->ioapic_as = vtd_host_dma_iommu(bus, s, Q35_PSEUDO_DEVFN_IOAPIC);
 
diff --git a/hw/i386/kvm/pci-assign.c b/hw/i386/kvm/pci-assign.c
index 8238fbc..3f26be1 100644
--- a/hw/i386/kvm/pci-assign.c
+++ b/hw/i386/kvm/pci-assign.c
@@ -976,7 +976,8 @@  static void assigned_dev_update_msi(PCIDevice *pci_dev)
     if (ctrl_byte & PCI_MSI_FLAGS_ENABLE) {
         int virq;
 
-        virq = kvm_irqchip_add_msi_route(kvm_state, 0, pci_dev);
+        virq = kvm_irqchip_add_msi_route(kvm_state, 0, pci_dev,
+                                         pci_requester_id(pci_dev));
         if (virq < 0) {
             perror("assigned_dev_update_msi: kvm_irqchip_add_msi_route");
             return;
@@ -1014,7 +1015,8 @@  static void assigned_dev_update_msi_msg(PCIDevice *pci_dev)
     }
 
     kvm_irqchip_update_msi_route(kvm_state, assigned_dev->msi_virq[0],
-                                 msi_get_message(pci_dev, 0), pci_dev);
+                                 msi_get_message(pci_dev, 0), pci_dev,
+                                 pci_requester_id(pci_dev));
     kvm_irqchip_commit_routes(kvm_state);
 }
 
@@ -1078,7 +1080,8 @@  static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev)
             continue;
         }
 
-        r = kvm_irqchip_add_msi_route(kvm_state, i, pci_dev);
+        r = kvm_irqchip_add_msi_route(kvm_state, i, pci_dev,
+                                      pci_requester_id(pci_dev));
         if (r < 0) {
             return r;
         }
@@ -1599,7 +1602,8 @@  static void assigned_dev_msix_mmio_write(void *opaque, hwaddr addr,
 
                 ret = kvm_irqchip_update_msi_route(kvm_state,
                                                    adev->msi_virq[i], msg,
-                                                   pdev);
+                                                   pdev,
+                                                   pci_requester_id(pdev));
                 if (ret) {
                     error_report("Error updating irq routing entry (%d)", ret);
                 }
diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
index 31791b0..f2d4c15 100644
--- a/hw/intc/ioapic.c
+++ b/hw/intc/ioapic.c
@@ -95,9 +95,17 @@  static void ioapic_entry_parse(uint64_t entry, struct ioapic_entry_info *info)
         (info->delivery_mode << MSI_DATA_DELIVERY_MODE_SHIFT);
 }
 
-static void ioapic_service(IOAPICCommonState *s)
+static void ioapic_as_write(IOAPICCommonState *s, uint32_t data, uint64_t addr)
 {
     AddressSpace *ioapic_as = PC_MACHINE(qdev_get_machine())->ioapic_as;
+    MemTxAttrs attrs;
+
+    attrs.requester_id = s->devid;
+    address_space_stl_le(ioapic_as, addr, data, attrs, NULL);
+}
+
+static void ioapic_service(IOAPICCommonState *s)
+{
     struct ioapic_entry_info info;
     uint8_t i;
     uint32_t mask;
@@ -141,7 +149,7 @@  static void ioapic_service(IOAPICCommonState *s)
                  * the IOAPIC message into a MSI one, and its
                  * address space will decide whether we need a
                  * translation. */
-                stl_le_phys(ioapic_as, info.addr, info.data);
+                ioapic_as_write(s, info.data, info.addr);
             }
         }
     }
@@ -197,7 +205,7 @@  static void ioapic_update_kvm_routes(IOAPICCommonState *s)
             ioapic_entry_parse(s->ioredtbl[i], &info);
             msg.address = info.addr;
             msg.data = info.data;
-            kvm_irqchip_update_msi_route(kvm_state, i, msg, NULL);
+            kvm_irqchip_update_msi_route(kvm_state, i, msg, NULL, s->devid);
         }
         kvm_irqchip_commit_routes(kvm_state);
     }
@@ -383,14 +391,28 @@  static void ioapic_machine_done_notify(Notifier *notifier, void *data)
     IOAPICCommonState *s = container_of(notifier, IOAPICCommonState,
                                         machine_done);
 
+    X86IOMMUState *iommu = x86_iommu_get_default();
+    /* kernel_irqchip=off */
+    if (iommu) {
+        s->devid = iommu->ioapic_bdf;
+    }
+
     if (kvm_irqchip_is_split()) {
-        X86IOMMUState *iommu = x86_iommu_get_default();
+        MSIMessage msg = {0, 0};
+        int i;
+
         if (iommu) {
             /* Register this IOAPIC with IOMMU IEC notifier, so that
              * when there are IR invalidates, we can be notified to
              * update kernel IR cache. */
             x86_iommu_iec_register_notifier(iommu, ioapic_iec_notifier, s);
+            /* update IOAPIC routes to the right SID */
+            for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+                kvm_irqchip_update_msi_route(kvm_state, i, msg, NULL, s->devid);
+            }
+            kvm_irqchip_commit_routes(kvm_state);
         }
+
     }
 #endif
 }
@@ -407,7 +429,6 @@  static void ioapic_realize(DeviceState *dev, Error **errp)
 
     memory_region_init_io(&s->io_memory, OBJECT(s), &ioapic_io_ops, s,
                           "ioapic", 0x1000);
-
     qdev_init_gpio_in(dev, ioapic_set_irq, IOAPIC_NUM_PINS);
 
     ioapics[ioapic_no] = s;
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 40a2ebc..9d5133f 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -318,7 +318,8 @@  static int ivshmem_vector_unmask(PCIDevice *dev, unsigned vector,
 
     IVSHMEM_DPRINTF("vector unmask %p %d\n", dev, vector);
 
-    ret = kvm_irqchip_update_msi_route(kvm_state, v->virq, msg, dev);
+    ret = kvm_irqchip_update_msi_route(kvm_state, v->virq, msg, dev,
+                                       pci_requester_id(dev));
     if (ret < 0) {
         return ret;
     }
@@ -447,7 +448,8 @@  static void ivshmem_add_kvm_msi_virq(IVShmemState *s, int vector,
     IVSHMEM_DPRINTF("ivshmem_add_kvm_msi_virq vector:%d\n", vector);
     assert(!s->msi_vectors[vector].pdev);
 
-    ret = kvm_irqchip_add_msi_route(kvm_state, vector, pdev);
+    ret = kvm_irqchip_add_msi_route(kvm_state, vector, pdev,
+                                    pci_requester_id(pdev));
     if (ret < 0) {
         error_setg(errp, "kvm_irqchip_add_msi_route failed");
         return;
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 7bfa17c..a745e07 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -429,7 +429,8 @@  static void vfio_add_kvm_msi_virq(VFIOPCIDevice *vdev, VFIOMSIVector *vector,
         return;
     }
 
-    virq = kvm_irqchip_add_msi_route(kvm_state, vector_n, &vdev->pdev);
+    virq = kvm_irqchip_add_msi_route(kvm_state, vector_n, &vdev->pdev,
+                                     pci_requester_id(&vdev->pdev));
     if (virq < 0) {
         event_notifier_cleanup(&vector->kvm_interrupt);
         return;
@@ -457,7 +458,8 @@  static void vfio_remove_kvm_msi_virq(VFIOMSIVector *vector)
 static void vfio_update_kvm_msi_virq(VFIOMSIVector *vector, MSIMessage msg,
                                      PCIDevice *pdev)
 {
-    kvm_irqchip_update_msi_route(kvm_state, vector->virq, msg, pdev);
+    kvm_irqchip_update_msi_route(kvm_state, vector->virq, msg, pdev,
+                                 pci_requester_id(pdev));
     kvm_irqchip_commit_routes(kvm_state);
 }
 
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 755f921..658d904 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -705,7 +705,8 @@  static int kvm_virtio_pci_vq_vector_use(VirtIOPCIProxy *proxy,
     int ret;
 
     if (irqfd->users == 0) {
-        ret = kvm_irqchip_add_msi_route(kvm_state, vector, &proxy->pci_dev);
+        ret = kvm_irqchip_add_msi_route(kvm_state, vector, &proxy->pci_dev,
+                                        pci_requester_id(&proxy->pci_dev));
         if (ret < 0) {
             return ret;
         }
@@ -833,12 +834,14 @@  static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy,
     EventNotifier *n = virtio_queue_get_guest_notifier(vq);
     VirtIOIRQFD *irqfd;
     int ret = 0;
+    uint16_t requester_id = pci_requester_id(&proxy->pci_dev);
 
     if (proxy->vector_irqfd) {
         irqfd = &proxy->vector_irqfd[vector];
         if (irqfd->msg.data != msg.data || irqfd->msg.address != msg.address) {
             ret = kvm_irqchip_update_msi_route(kvm_state, irqfd->virq, msg,
-                                               &proxy->pci_dev);
+                                               &proxy->pci_dev,
+                                               requester_id);
             if (ret < 0) {
                 return ret;
             }
diff --git a/include/hw/i386/ioapic_internal.h b/include/hw/i386/ioapic_internal.h
index a11d86d..d68a24f 100644
--- a/include/hw/i386/ioapic_internal.h
+++ b/include/hw/i386/ioapic_internal.h
@@ -103,6 +103,7 @@  typedef struct IOAPICCommonClass {
 struct IOAPICCommonState {
     SysBusDevice busdev;
     MemoryRegion io_memory;
+    uint16_t devid;
     uint8_t id;
     uint8_t ioregsel;
     uint32_t irr;
diff --git a/include/hw/i386/x86-iommu.h b/include/hw/i386/x86-iommu.h
index 0c89d98..5d05865 100644
--- a/include/hw/i386/x86-iommu.h
+++ b/include/hw/i386/x86-iommu.h
@@ -72,6 +72,7 @@  typedef struct IEC_Notifier IEC_Notifier;
 
 struct X86IOMMUState {
     SysBusDevice busdev;
+    uint16_t ioapic_bdf;        /* expected IOAPIC SID        */
     bool intr_supported;        /* Whether vIOMMU supports IR */
     IommuType type;             /* IOMMU type - AMD/Intel     */
     QLIST_HEAD(, IEC_Notifier) iec_notifiers; /* IEC notify list */
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index c9c2436..ae81f92 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -357,7 +357,8 @@  int kvm_arch_on_sigbus(int code, void *addr);
 void kvm_arch_init_irq_routing(KVMState *s);
 
 int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
-                             uint64_t address, uint32_t data, PCIDevice *dev);
+                             uint64_t address, uint32_t data,
+                             uint16_t requester_id);
 
 /* Notify arch about newly added MSI routes */
 int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route,
@@ -481,18 +482,20 @@  static inline void cpu_synchronize_post_init(CPUState *cpu)
 
 /**
  * kvm_irqchip_add_msi_route - Add MSI route for specific vector
- * @s:      KVM state
- * @vector: which vector to add. This can be either MSI/MSIX
- *          vector. The function will automatically detect whether
- *          MSI/MSIX is enabled, and fetch corresponding MSI
- *          message.
- * @dev:    Owner PCI device to add the route. If @dev is specified
- *          as @NULL, an empty MSI message will be inited.
- * @return: virq (>=0) when success, errno (<0) when failed.
+ * @s:            KVM state
+ * @vector:       which vector to add. This can be either MSI/MSIX
+ *                vector. The function will automatically detect whether
+ *                MSI/MSIX is enabled, and fetch corresponding MSI
+ *                message.
+ * @dev:          Owner PCI device to add the route. If @dev is specified
+ *                as @NULL, an empty MSI message will be inited.
+ * @requester_id: SID when calling IOMMU code
+ * @return:       virq (>=0) when success, errno (<0) when failed.
  */
-int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev);
+int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev,
+                              uint16_t requester_id);
 int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg,
-                                 PCIDevice *dev);
+                                 PCIDevice *dev, uint16_t requester_id);
 void kvm_irqchip_commit_routes(KVMState *s);
 void kvm_irqchip_release_virq(KVMState *s, int virq);
 
diff --git a/kvm-all.c b/kvm-all.c
index ebf35b0..9e888ab 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -1246,7 +1246,7 @@  int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg)
     return kvm_set_irq(s, route->kroute.gsi, 1);
 }
 
-int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
+int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev, uint16_t requester_id)
 {
     struct kvm_irq_routing_entry kroute = {};
     int virq;
@@ -1275,7 +1275,8 @@  int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
     kroute.u.msi.address_lo = (uint32_t)msg.address;
     kroute.u.msi.address_hi = msg.address >> 32;
     kroute.u.msi.data = le32_to_cpu(msg.data);
-    if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data, dev)) {
+    if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data,
+                                 requester_id)) {
         kvm_irqchip_release_virq(s, virq);
         return -EINVAL;
     }
@@ -1290,7 +1291,7 @@  int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
 }
 
 int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg,
-                                 PCIDevice *dev)
+                                 PCIDevice *dev, uint16_t requester_id)
 {
     struct kvm_irq_routing_entry kroute = {};
 
@@ -1308,7 +1309,8 @@  int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg,
     kroute.u.msi.address_lo = (uint32_t)msg.address;
     kroute.u.msi.address_hi = msg.address >> 32;
     kroute.u.msi.data = le32_to_cpu(msg.data);
-    if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data, dev)) {
+    if (kvm_arch_fixup_msi_route(&kroute, msg.address, msg.data,
+                                 requester_id)) {
         return -EINVAL;
     }
 
diff --git a/kvm-stub.c b/kvm-stub.c
index 64e23f6..9a49ce0 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -116,7 +116,8 @@  int kvm_on_sigbus(int code, void *addr)
 }
 
 #ifndef CONFIG_USER_ONLY
-int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev)
+int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev,
+                              uint16_t requester_id)
 {
     return -ENOSYS;
 }
@@ -130,7 +131,7 @@  void kvm_irqchip_release_virq(KVMState *s, int virq)
 }
 
 int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg,
-                                 PCIDevice *dev)
+                                 PCIDevice *dev, uint16_t requester_id)
 {
     return -ENOSYS;
 }
diff --git a/qemu-version.h b/qemu-version.h
new file mode 100644
index 0000000..0e06b3e
--- /dev/null
+++ b/qemu-version.h
@@ -0,0 +1 @@ 
+#define QEMU_PKGVERSION " (v2.3.0-9603-g33203eb-dirty)"
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index d1a25c5..723bd67 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -3243,7 +3243,7 @@  void kvm_arch_init_irq_routing(KVMState *s)
         /* If the ioapic is in QEMU and the lapics are in KVM, reserve
            MSI routes for signaling interrupts to the local apics. */
         for (i = 0; i < IOAPIC_NUM_PINS; i++) {
-            if (kvm_irqchip_add_msi_route(s, 0, NULL) < 0) {
+            if (kvm_irqchip_add_msi_route(s, 0, NULL, 0) < 0) {
                 error_report("Could not enable split IRQ mode.");
                 exit(1);
             }
@@ -3411,7 +3411,8 @@  int kvm_device_msix_deassign(KVMState *s, uint32_t dev_id)
 }
 
 int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
-                             uint64_t address, uint32_t data, PCIDevice *dev)
+                             uint64_t address, uint32_t data,
+                             uint16_t requester_id)
 {
     X86IOMMUState *iommu = x86_iommu_get_default();
 
@@ -3425,9 +3426,8 @@  int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
         src.address |= route->u.msi.address_lo;
         src.data = route->u.msi.data;
 
-        ret = class->int_remap(iommu, &src, &dst, dev ? \
-                               pci_requester_id(dev) : \
-                               X86_IOMMU_SID_INVALID);
+        ret = class->int_remap(iommu, &src, &dst, requester_id);
+
         if (ret) {
             trace_kvm_x86_fixup_msi_error(route->gsi);
             return 1;
@@ -3445,6 +3445,7 @@  typedef struct MSIRouteEntry MSIRouteEntry;
 
 struct MSIRouteEntry {
     PCIDevice *dev;             /* Device pointer */
+    uint16_t requester_id;      /* Requesting SID */
     int vector;                 /* MSI/MSIX vector index */
     int virq;                   /* Virtual IRQ index */
     QLIST_ENTRY(MSIRouteEntry) list;
@@ -3465,7 +3466,8 @@  static void kvm_update_msi_routes_all(void *private, bool global,
         cnt++;
         msg = pci_get_msi_message(entry->dev, entry->vector);
         kvm_irqchip_update_msi_route(kvm_state, entry->virq,
-                                     msg, entry->dev);
+                                     msg, entry->dev,
+                                     entry->requester_id);
     }
     kvm_irqchip_commit_routes(kvm_state);
     trace_kvm_x86_update_msi_routes(cnt);
@@ -3486,6 +3488,7 @@  int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route,
 
     entry = g_new0(MSIRouteEntry, 1);
     entry->dev = dev;
+    entry->requester_id = pci_requester_id(dev);
     entry->vector = vector;
     entry->virq = route->gsi;
     QLIST_INSERT_HEAD(&msi_route_list, entry, list);