On Tue, Sep 20, 2016 at 08:40:41PM +0300, David Kiarie wrote: > When using IOMMU platform devices like IOAPIC are required to make > interrupt remapping requests using explicit SID. We associate 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. This also ensures compatility with the original code > which mainly dealt with PCI devices. > > Signed-off-by: David Kiarie <davidkiar...@gmail.com>
Paolo, could you please ack the kvm changes? Thanks! > --- > hw/i386/intel_iommu.c | 3 +++ > hw/i386/kvm/pci-assign.c | 12 ++++++++---- > hw/intc/ioapic.c | 33 ++++++++++++++++++++++++++------- > 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 | 11 +++++++---- > kvm-stub.c | 5 +++-- > target-arm/kvm.c | 3 ++- > target-i386/kvm.c | 15 +++++++++------ > target-mips/kvm.c | 3 ++- > target-ppc/kvm.c | 3 ++- > target-s390x/kvm.c | 3 ++- > 16 files changed, 93 insertions(+), 44 deletions(-) > > 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..fa2b745 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); > } > @@ -379,18 +387,30 @@ static const MemoryRegionOps ioapic_io_ops = { > > static void ioapic_machine_done_notify(Notifier *notifier, void *data) > { > -#ifdef CONFIG_KVM > + X86IOMMUState *iommu = x86_iommu_get_default(); > IOAPICCommonState *s = container_of(notifier, IOAPICCommonState, > machine_done); > - > + /* kernel_irqchip=off */ > + if (iommu) { > + s->devid = iommu->ioapic_bdf; > + } > +#ifdef CONFIG_KVM > 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 +427,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 f803dfd..64995bf 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 a5a620a..1ab083a 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 2d60a00..6108f5b 100644 > --- a/hw/virtio/virtio-pci.c > +++ b/hw/virtio/virtio-pci.c > @@ -711,7 +711,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; > } > @@ -839,12 +840,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 3e17ba7..2348456 100644 > --- a/include/sysemu/kvm.h > +++ b/include/sysemu/kvm.h > @@ -354,7 +354,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, > @@ -477,18 +478,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 8a4382e..f9b2ff7 100644 > --- a/kvm-all.c > +++ b/kvm-all.c > @@ -1246,7 +1246,8 @@ 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 +1276,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 +1292,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 +1310,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 3227127..5f0bee5 100644 > --- a/kvm-stub.c > +++ b/kvm-stub.c > @@ -112,7 +112,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; > } > @@ -126,7 +127,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/target-arm/kvm.c b/target-arm/kvm.c > index dbe393c..a221e68 100644 > --- a/target-arm/kvm.c > +++ b/target-arm/kvm.c > @@ -617,7 +617,8 @@ int kvm_arm_vgic_probe(void) > } > > 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) > { > return 0; > } > diff --git a/target-i386/kvm.c b/target-i386/kvm.c > index f1ad805..2e223e0 100644 > --- a/target-i386/kvm.c > +++ b/target-i386/kvm.c > @@ -3226,7 +3226,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); > } > @@ -3394,7 +3394,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(); > > @@ -3408,9 +3409,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; > @@ -3428,6 +3428,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; > @@ -3448,7 +3449,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); > @@ -3469,6 +3471,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); > diff --git a/target-mips/kvm.c b/target-mips/kvm.c > index dcf5fbb..dbb5e59 100644 > --- a/target-mips/kvm.c > +++ b/target-mips/kvm.c > @@ -1038,7 +1038,8 @@ int kvm_arch_get_registers(CPUState *cs) > } > > 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) > { > return 0; > } > diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c > index dcb68b9..49d313a 100644 > --- a/target-ppc/kvm.c > +++ b/target-ppc/kvm.c > @@ -2620,7 +2620,8 @@ error_out: > } > > 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) > { > return 0; > } > diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c > index 4b847a3..93aeee4 100644 > --- a/target-s390x/kvm.c > +++ b/target-s390x/kvm.c > @@ -2282,7 +2282,8 @@ int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu) > } > > 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) > { > S390PCIBusDevice *pbdev; > uint32_t idx = data >> ZPCI_MSI_VEC_BITS; > -- > 2.1.4