:p
atchew
Login
Up until now QEMU marked any zPCI device as "unmigratable." This patch series adds support for migrating emulated devices, which are simpler to migrate. It leaves VFIO devices still unmigratable. To enable migration, the device state needs to be saved/restored to/from the migration stream. There are 2 kinds of emulated devices - those that use the zPCI IOMMU page table emulation in QEMU (e.g., Intel IGB NIC), and those that don't (virtio). This is important to note for testing purposes. This change was tested on IGB, virtio-net and virtio-blk devices by running I/O on them while performing "virsh managedsave, virsh start". Konstantin Shkolnyy (14): s390x/pci: Create function to contain translation status check s390x/pci: Move iommu_mr from S390PCIIOMMU to S390PCIBusDevice s390x/pci: Move dm_mr from S390PCIIOMMU to S390PCIBusDevice s390x/pci: Move iotlb from S390PCIIOMMU to S390PCIBusDevice s390x/pci: Remove a ptr to S390PCIBusDevice from S390PCIIOMMU s390x/pci: Move/rename enabled from S390PCIIOMMU to S390PCIBusDevice s390x/pci: Move dma_limit from S390PCIIOMMU to S390PCIBusDevice s390x/pci: Move g_iota from S390PCIIOMMU to S390PCIBusDevice s390x/pci: Move pba from S390PCIIOMMU to S390PCIBusDevice s390x/pci: Move pal from S390PCIIOMMU to S390PCIBusDevice s390x/pci: Move max_dma_limit from S390PCIIOMMU to S390PCIBusDevice s390x/pci: Add a comment explaining S390PCIIOMMU purpose s390x/pci: Implement migration for emulated devices s390x/pci: Create function to contain fmb_timer start Matthew Rosato (1): s390x/pci: implement IOMMU replay hw/s390x/s390-pci-bus.c | 251 ++++++++++++++++++++++++------- hw/s390x/s390-pci-inst.c | 116 +++++++------- hw/s390x/s390-pci-vfio.c | 4 +- include/hw/s390x/s390-pci-bus.h | 37 +++-- include/hw/s390x/s390-pci-inst.h | 3 +- 5 files changed, 286 insertions(+), 125 deletions(-) -- 2.34.1
From: Matthew Rosato <mjrosato@linux.ibm.com> There are a few scenarios where IOMMU replay can potentially be needed for zPCI device, namely VFIO device reset scenarios where the guest continues running and expects the contents of its IOMMU to be replayed upon IOAT re-registration and migration scenarios where the destination must reconstruct the IOMMU on the destination. zPCI migration is not supported yet, but the IOMMU replay function is implemented so that it can be called both from IOMMUMemoryRegionClass now and migration post_load later. Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 50 ++++++++++++++++++++++++++++---- hw/s390x/s390-pci-inst.c | 4 +-- include/hw/s390x/s390-pci-inst.h | 1 + 3 files changed, 47 insertions(+), 8 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ err: return ret; } -static void s390_pci_iommu_replay(IOMMUMemoryRegion *iommu, +static void s390_pci_ioat_replay(S390PCIIOMMU *iommu) +{ + S390IOTLBEntry entry; + uint16_t error = 0; + uint32_t dma_avail; + hwaddr curr, end; + + curr = iommu->pba; + end = iommu->pal; + + if (iommu->dm_mr) { + /* If direct mapping is used, there are no guest tables to replay */ + return; + } + + if (iommu->dma_limit) { + dma_avail = iommu->dma_limit->avail; + } else { + dma_avail = 1; + } + + while (curr < end) { + error = s390_guest_io_table_walk(iommu->g_iota, curr, &entry); + if (error) { + error_report("Failure to walk table during iommu remap"); + return; + } + + if (entry.perm != IOMMU_NONE) { + if (dma_avail > 0) { + dma_avail = s390_pci_update_iotlb(iommu, &entry); + } else { + error_report("DMA mappings exhausted: iommu remap failed"); + return; + } + } + curr += entry.len; + } +} + +static void s390_pci_iommu_replay(IOMMUMemoryRegion *mr, IOMMUNotifier *notifier) { - /* It's impossible to plug a pci device on s390x that already has iommu - * mappings which need to be replayed, that is due to the "one iommu per - * zpci device" construct. But when we support migration of vfio-pci - * devices in future, we need to revisit this. - */ + S390PCIIOMMU *iommu = container_of(mr, S390PCIIOMMU, iommu_mr); + + s390_pci_ioat_replay(iommu); } static S390PCIIOMMU *s390_pci_get_iommu(S390pciState *s, PCIBus *bus, diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) return 0; } -static uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu, - S390IOTLBEntry *entry) +uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu, + S390IOTLBEntry *entry) { S390IOTLBEntry *cache = g_hash_table_lookup(iommu->iotlb, &entry->iova); IOMMUTLBEvent event = { diff --git a/include/hw/s390x/s390-pci-inst.h b/include/hw/s390x/s390-pci-inst.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-inst.h +++ b/include/hw/s390x/s390-pci-inst.h @@ -XXX,XX +XXX,XX @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, uintptr_t ra); void fmb_timer_free(S390PCIBusDevice *pbdev); +uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu, S390IOTLBEntry *entry); #define ZPCI_IO_BAR_MIN 0 #define ZPCI_IO_BAR_MAX 5 -- 2.34.1
Make it more clear what the bit means, and the new function will be called from yet another place in the future. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-inst.c | 7 ++++++- include/hw/s390x/s390-pci-bus.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ int pci_dereg_irqs(S390PCIBusDevice *pbdev) return 0; } +bool s390_pci_is_translation_enabled(uint64_t g_iota) +{ + return ((g_iota >> 11) & 0x1) != 0; /* "T" bit */ +} + static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib, uintptr_t ra) { @@ -XXX,XX +XXX,XX @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib, uint64_t pal = ldq_be_p(&fib.pal); uint64_t g_iota = ldq_be_p(&fib.iota); uint8_t dt = (g_iota >> 2) & 0x7; - uint8_t t = (g_iota >> 11) & 0x1; + bool t = s390_pci_is_translation_enabled(g_iota); pba &= ~0xfff; pal |= 0xfff; diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ int pci_chsc_sei_nt2_get_event(void *res); int pci_chsc_sei_nt2_have_event(void); void s390_pci_sclp_configure(SCCB *sccb); void s390_pci_sclp_deconfigure(SCCB *sccb); +bool s390_pci_is_translation_enabled(uint64_t g_iota); void s390_pci_iommu_enable(S390PCIIOMMU *iommu); void s390_pci_iommu_direct_map_enable(S390PCIIOMMU *iommu); void s390_pci_iommu_disable(S390PCIIOMMU *iommu); -- 2.34.1
This field is only used when S390PCIBusDevice exists, so it can be moved there to simplify S390PCIIOMMU which purpose is just to store the "root" AddressSpace. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 32 ++++++++++++++++++-------------- hw/s390x/s390-pci-inst.c | 28 +++++++++++++++------------- include/hw/s390x/s390-pci-bus.h | 6 +++--- include/hw/s390x/s390-pci-inst.h | 4 ++-- 4 files changed, 38 insertions(+), 32 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ void s390_pci_sclp_deconfigure(SCCB *sccb) pci_dereg_irqs(pbdev); } if (pbdev->iommu->enabled) { - pci_dereg_ioat(pbdev->iommu); + pci_dereg_ioat(pbdev); } pbdev->state = ZPCI_FS_STANDBY; rc = SCLP_RC_NORMAL_COMPLETION; @@ -XXX,XX +XXX,XX @@ uint16_t s390_guest_io_table_walk(uint64_t g_iota, hwaddr addr, static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr, IOMMUAccessFlags flag, int iommu_idx) { - S390PCIIOMMU *iommu = container_of(mr, S390PCIIOMMU, iommu_mr); + S390PCIBusDevice *pbdev = container_of(mr, S390PCIBusDevice, iommu_mr); + S390PCIIOMMU *iommu = pbdev->iommu; S390IOTLBEntry *entry; uint64_t iova = addr & TARGET_PAGE_MASK; uint16_t error = 0; @@ -XXX,XX +XXX,XX @@ err: return ret; } -static void s390_pci_ioat_replay(S390PCIIOMMU *iommu) +static void s390_pci_ioat_replay(S390PCIBusDevice *pbdev) { S390IOTLBEntry entry; uint16_t error = 0; uint32_t dma_avail; hwaddr curr, end; + S390PCIIOMMU *iommu = pbdev->iommu; curr = iommu->pba; end = iommu->pal; @@ -XXX,XX +XXX,XX @@ static void s390_pci_ioat_replay(S390PCIIOMMU *iommu) if (entry.perm != IOMMU_NONE) { if (dma_avail > 0) { - dma_avail = s390_pci_update_iotlb(iommu, &entry); + dma_avail = s390_pci_update_iotlb(pbdev, &entry); } else { error_report("DMA mappings exhausted: iommu remap failed"); return; @@ -XXX,XX +XXX,XX @@ static void s390_pci_ioat_replay(S390PCIIOMMU *iommu) static void s390_pci_iommu_replay(IOMMUMemoryRegion *mr, IOMMUNotifier *notifier) { - S390PCIIOMMU *iommu = container_of(mr, S390PCIIOMMU, iommu_mr); + S390PCIBusDevice *pbdev = container_of(mr, S390PCIBusDevice, iommu_mr); - s390_pci_ioat_replay(iommu); + s390_pci_ioat_replay(pbdev); } static S390PCIIOMMU *s390_pci_get_iommu(S390pciState *s, PCIBus *bus, @@ -XXX,XX +XXX,XX @@ static const MemoryRegionOps s390_msi_ctrl_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -void s390_pci_iommu_enable(S390PCIIOMMU *iommu) +void s390_pci_iommu_enable(S390PCIBusDevice *pbdev) { + S390PCIIOMMU *iommu = pbdev->iommu; /* * The iommu region is initialized against a 0-mapped address space, * so the smallest IOMMU region we can define runs from 0 to the end * of the PCI address space. */ char *name = g_strdup_printf("iommu-s390-%04x", iommu->pbdev->uid); - memory_region_init_iommu(&iommu->iommu_mr, sizeof(iommu->iommu_mr), + memory_region_init_iommu(&pbdev->iommu_mr, sizeof(pbdev->iommu_mr), TYPE_S390_IOMMU_MEMORY_REGION, OBJECT(&iommu->mr), name, iommu->pal + 1); iommu->enabled = true; - memory_region_add_subregion(&iommu->mr, 0, MEMORY_REGION(&iommu->iommu_mr)); + memory_region_add_subregion(&iommu->mr, 0, MEMORY_REGION(&pbdev->iommu_mr)); g_free(name); } @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_direct_map_enable(S390PCIIOMMU *iommu) iommu->dm_mr); } -void s390_pci_iommu_disable(S390PCIIOMMU *iommu) +void s390_pci_iommu_disable(S390PCIBusDevice *pbdev) { + S390PCIIOMMU *iommu = pbdev->iommu; iommu->enabled = false; g_hash_table_remove_all(iommu->iotlb); if (iommu->dm_mr) { @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_disable(S390PCIIOMMU *iommu) iommu->dm_mr = NULL; } else { memory_region_del_subregion(&iommu->mr, - MEMORY_REGION(&iommu->iommu_mr)); - object_unparent(OBJECT(&iommu->iommu_mr)); + MEMORY_REGION(&pbdev->iommu_mr)); + object_unparent(OBJECT(&pbdev->iommu_mr)); } } @@ -XXX,XX +XXX,XX @@ static void s390_pcihost_reset(DeviceState *dev) pci_dereg_irqs(pbdev); } if (pbdev->iommu->enabled) { - pci_dereg_ioat(pbdev->iommu); + pci_dereg_ioat(pbdev); } pbdev->state = ZPCI_FS_STANDBY; s390_pci_perform_unplug(pbdev); @@ -XXX,XX +XXX,XX @@ static void s390_pci_device_reset(DeviceState *dev) pci_dereg_irqs(pbdev); } if (pbdev->iommu->enabled) { - pci_dereg_ioat(pbdev->iommu); + pci_dereg_ioat(pbdev); } fmb_timer_free(pbdev); diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) return 0; } -uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu, +uint32_t s390_pci_update_iotlb(S390PCIBusDevice *pbdev, S390IOTLBEntry *entry) { + S390PCIIOMMU *iommu = pbdev->iommu; S390IOTLBEntry *cache = g_hash_table_lookup(iommu->iotlb, &entry->iova); IOMMUTLBEvent event = { .type = entry->perm ? IOMMU_NOTIFIER_MAP : IOMMU_NOTIFIER_UNMAP, @@ -XXX,XX +XXX,XX @@ uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu, event.type = IOMMU_NOTIFIER_UNMAP; event.entry.perm = IOMMU_NONE; - memory_region_notify_iommu(&iommu->iommu_mr, 0, event); + memory_region_notify_iommu(&pbdev->iommu_mr, 0, event); event.type = IOMMU_NOTIFIER_MAP; event.entry.perm = entry->perm; } @@ -XXX,XX +XXX,XX @@ uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu, * All associated iotlb entries have already been cleared, trigger the * unmaps. */ - memory_region_notify_iommu(&iommu->iommu_mr, 0, event); + memory_region_notify_iommu(&pbdev->iommu_mr, 0, event); out: return iommu->dma_limit ? iommu->dma_limit->avail : 1; } -static void s390_pci_batch_unmap(S390PCIIOMMU *iommu, uint64_t iova, +static void s390_pci_batch_unmap(S390PCIBusDevice *pbdev, uint64_t iova, uint64_t len) { uint64_t remain = len, start = iova, end = start + len - 1, mask, size; @@ -XXX,XX +XXX,XX @@ static void s390_pci_batch_unmap(S390PCIIOMMU *iommu, uint64_t iova, size = mask + 1; event.entry.iova = start; event.entry.addr_mask = mask; - memory_region_notify_iommu(&iommu->iommu_mr, 0, event); + memory_region_notify_iommu(&pbdev->iommu_mr, 0, event); start += size; remain -= size; } @@ -XXX,XX +XXX,XX @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) coalesce += entry.len; } else if (coalesce > 0) { /* Unleash the coalesced unmap before processing a new map */ - s390_pci_batch_unmap(iommu, iova, coalesce); + s390_pci_batch_unmap(pbdev, iova, coalesce); coalesce = 0; } start += entry.len; while (entry.iova < start && entry.iova < end) { if (dma_avail > 0 || entry.perm == IOMMU_NONE) { - dma_avail = s390_pci_update_iotlb(iommu, &entry); + dma_avail = s390_pci_update_iotlb(pbdev, &entry); entry.iova += TARGET_PAGE_SIZE; entry.translated_addr += TARGET_PAGE_SIZE; } else { @@ -XXX,XX +XXX,XX @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) } if (coalesce) { /* Unleash the coalesced unmap before finishing rpcit */ - s390_pci_batch_unmap(iommu, iova, coalesce); + s390_pci_batch_unmap(pbdev, iova, coalesce); coalesce = 0; } if (again && dma_avail > 0) @@ -XXX,XX +XXX,XX @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib, iommu->g_iota = g_iota; if (t) { - s390_pci_iommu_enable(iommu); + s390_pci_iommu_enable(pbdev); } else { s390_pci_iommu_direct_map_enable(iommu); } @@ -XXX,XX +XXX,XX @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib, return 0; } -void pci_dereg_ioat(S390PCIIOMMU *iommu) +void pci_dereg_ioat(S390PCIBusDevice *pbdev) { - s390_pci_iommu_disable(iommu); + S390PCIIOMMU *iommu = pbdev->iommu; + s390_pci_iommu_disable(pbdev); iommu->pba = 0; iommu->pal = 0; iommu->g_iota = 0; @@ -XXX,XX +XXX,XX @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); } else { - pci_dereg_ioat(pbdev->iommu); + pci_dereg_ioat(pbdev); } break; case ZPCI_MOD_FC_REREG_IOAT: @@ -XXX,XX +XXX,XX @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); } else { - pci_dereg_ioat(pbdev->iommu); + pci_dereg_ioat(pbdev); if (reg_ioat(env, pbdev, fib, ra)) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES); diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ struct S390PCIIOMMU { S390PCIBusDevice *pbdev; AddressSpace as; MemoryRegion mr; - IOMMUMemoryRegion iommu_mr; MemoryRegion *dm_mr; bool enabled; uint64_t g_iota; @@ -XXX,XX +XXX,XX @@ struct S390PCIBusDevice { S390MsixInfo msix; AdapterRoutes routes; S390PCIIOMMU *iommu; + IOMMUMemoryRegion iommu_mr; MemoryRegion msix_notify_mr; IndAddr *summary_ind; IndAddr *indicator; @@ -XXX,XX +XXX,XX @@ int pci_chsc_sei_nt2_have_event(void); void s390_pci_sclp_configure(SCCB *sccb); void s390_pci_sclp_deconfigure(SCCB *sccb); bool s390_pci_is_translation_enabled(uint64_t g_iota); -void s390_pci_iommu_enable(S390PCIIOMMU *iommu); +void s390_pci_iommu_enable(S390PCIBusDevice *pbdev); void s390_pci_iommu_direct_map_enable(S390PCIIOMMU *iommu); -void s390_pci_iommu_disable(S390PCIIOMMU *iommu); +void s390_pci_iommu_disable(S390PCIBusDevice *pbdev); void s390_pci_generate_error_event(uint16_t pec, uint32_t fh, uint32_t fid, uint64_t faddr, uint32_t e); uint16_t s390_guest_io_table_walk(uint64_t g_iota, hwaddr addr, diff --git a/include/hw/s390x/s390-pci-inst.h b/include/hw/s390x/s390-pci-inst.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-inst.h +++ b/include/hw/s390x/s390-pci-inst.h @@ -XXX,XX +XXX,XX @@ typedef struct ZpciFib { } QEMU_PACKED ZpciFib; int pci_dereg_irqs(S390PCIBusDevice *pbdev); -void pci_dereg_ioat(S390PCIIOMMU *iommu); +void pci_dereg_ioat(S390PCIBusDevice *pbdev); int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra); int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra); int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra); @@ -XXX,XX +XXX,XX @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, uintptr_t ra); void fmb_timer_free(S390PCIBusDevice *pbdev); -uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu, S390IOTLBEntry *entry); +uint32_t s390_pci_update_iotlb(S390PCIBusDevice *pbdev, S390IOTLBEntry *entry); #define ZPCI_IO_BAR_MIN 0 #define ZPCI_IO_BAR_MAX 5 -- 2.34.1
This field is only used when S390PCIBusDevice exists, so it can be moved there to simplify S390PCIIOMMU which purpose is just to store the "root" AddressSpace. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 21 +++++++++++---------- hw/s390x/s390-pci-inst.c | 2 +- include/hw/s390x/s390-pci-bus.h | 4 ++-- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ static void s390_pci_ioat_replay(S390PCIBusDevice *pbdev) curr = iommu->pba; end = iommu->pal; - if (iommu->dm_mr) { + if (pbdev->dm_mr) { /* If direct mapping is used, there are no guest tables to replay */ return; } @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_enable(S390PCIBusDevice *pbdev) g_free(name); } -void s390_pci_iommu_direct_map_enable(S390PCIIOMMU *iommu) +void s390_pci_iommu_direct_map_enable(S390PCIBusDevice *pbdev) { + S390PCIIOMMU *iommu = pbdev->iommu; MachineState *ms = MACHINE(qdev_get_machine()); S390CcwMachineState *s390ms = S390_CCW_MACHINE(ms); @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_direct_map_enable(S390PCIIOMMU *iommu) g_autofree char *name = g_strdup_printf("iommu-dm-s390-%04x", iommu->pbdev->uid); - iommu->dm_mr = g_malloc0(sizeof(*iommu->dm_mr)); - memory_region_init_alias(iommu->dm_mr, OBJECT(&iommu->mr), name, + pbdev->dm_mr = g_malloc0(sizeof(*pbdev->dm_mr)); + memory_region_init_alias(pbdev->dm_mr, OBJECT(&iommu->mr), name, get_system_memory(), 0, s390_get_memory_limit(s390ms)); iommu->enabled = true; memory_region_add_subregion(&iommu->mr, iommu->pbdev->zpci_fn.sdma, - iommu->dm_mr); + pbdev->dm_mr); } void s390_pci_iommu_disable(S390PCIBusDevice *pbdev) @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_disable(S390PCIBusDevice *pbdev) S390PCIIOMMU *iommu = pbdev->iommu; iommu->enabled = false; g_hash_table_remove_all(iommu->iotlb); - if (iommu->dm_mr) { - memory_region_del_subregion(&iommu->mr, iommu->dm_mr); - object_unparent(OBJECT(iommu->dm_mr)); - g_free(iommu->dm_mr); - iommu->dm_mr = NULL; + if (pbdev->dm_mr) { + memory_region_del_subregion(&iommu->mr, pbdev->dm_mr); + object_unparent(OBJECT(pbdev->dm_mr)); + g_free(pbdev->dm_mr); + pbdev->dm_mr = NULL; } else { memory_region_del_subregion(&iommu->mr, MEMORY_REGION(&pbdev->iommu_mr)); diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib, if (t) { s390_pci_iommu_enable(pbdev); } else { - s390_pci_iommu_direct_map_enable(iommu); + s390_pci_iommu_direct_map_enable(pbdev); } return 0; diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ struct S390PCIIOMMU { S390PCIBusDevice *pbdev; AddressSpace as; MemoryRegion mr; - MemoryRegion *dm_mr; bool enabled; uint64_t g_iota; uint64_t pba; @@ -XXX,XX +XXX,XX @@ struct S390PCIBusDevice { AdapterRoutes routes; S390PCIIOMMU *iommu; IOMMUMemoryRegion iommu_mr; + MemoryRegion *dm_mr; MemoryRegion msix_notify_mr; IndAddr *summary_ind; IndAddr *indicator; @@ -XXX,XX +XXX,XX @@ void s390_pci_sclp_configure(SCCB *sccb); void s390_pci_sclp_deconfigure(SCCB *sccb); bool s390_pci_is_translation_enabled(uint64_t g_iota); void s390_pci_iommu_enable(S390PCIBusDevice *pbdev); -void s390_pci_iommu_direct_map_enable(S390PCIIOMMU *iommu); +void s390_pci_iommu_direct_map_enable(S390PCIBusDevice *pbdev); void s390_pci_iommu_disable(S390PCIBusDevice *pbdev); void s390_pci_generate_error_event(uint16_t pec, uint32_t fh, uint32_t fid, uint64_t faddr, uint32_t e); -- 2.34.1
This field is only used when S390PCIBusDevice exists, so it can be moved there to simplify S390PCIIOMMU which purpose is just to store the "root" AddressSpace. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 10 +++++----- hw/s390x/s390-pci-inst.c | 6 +++--- include/hw/s390x/s390-pci-bus.h | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr, goto err; } - entry = g_hash_table_lookup(iommu->iotlb, &iova); + entry = g_hash_table_lookup(pbdev->iotlb, &iova); if (entry) { ret.iova = entry->iova; ret.translated_addr = entry->translated_addr; @@ -XXX,XX +XXX,XX @@ static S390PCIIOMMU *s390_pci_get_iommu(S390pciState *s, PCIBus *bus, PCI_FUNC(devfn)); memory_region_init(&iommu->mr, OBJECT(iommu), mr_name, UINT64_MAX); address_space_init(&iommu->as, &iommu->mr, as_name); - iommu->iotlb = g_hash_table_new_full(g_int64_hash, g_int64_equal, - NULL, g_free); table->iommu[PCI_SLOT(devfn)] = iommu; g_free(mr_name); @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_disable(S390PCIBusDevice *pbdev) { S390PCIIOMMU *iommu = pbdev->iommu; iommu->enabled = false; - g_hash_table_remove_all(iommu->iotlb); + g_hash_table_remove_all(pbdev->iotlb); if (pbdev->dm_mr) { memory_region_del_subregion(&iommu->mr, pbdev->dm_mr); object_unparent(OBJECT(pbdev->dm_mr)); @@ -XXX,XX +XXX,XX @@ static void s390_pci_iommu_free(S390pciState *s, PCIBus *bus, int32_t devfn) } table->iommu[PCI_SLOT(devfn)] = NULL; - g_hash_table_destroy(iommu->iotlb); /* * An attached PCI device may have memory listeners, eg. VFIO PCI. * The associated subregion will already have been unmapped in @@ -XXX,XX +XXX,XX @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev, /* the allocated idx is actually getting used */ s->next_idx = (pbdev->idx + 1) & FH_MASK_INDEX; pbdev->fh = pbdev->idx; + pbdev->iotlb = g_hash_table_new_full(g_int64_hash, g_int64_equal, + NULL, g_free); QTAILQ_INSERT_TAIL(&s->zpci_devs, pbdev, link); g_hash_table_insert(s->zpci_table, &pbdev->idx, pbdev); } else { @@ -XXX,XX +XXX,XX @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, if (pbdev->iommu && pbdev->iommu->dma_limit) { s390_pci_end_dma_count(s, pbdev->iommu->dma_limit); } + g_hash_table_destroy(pbdev->iotlb); qdev_unrealize(dev); } } diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ uint32_t s390_pci_update_iotlb(S390PCIBusDevice *pbdev, S390IOTLBEntry *entry) { S390PCIIOMMU *iommu = pbdev->iommu; - S390IOTLBEntry *cache = g_hash_table_lookup(iommu->iotlb, &entry->iova); + S390IOTLBEntry *cache = g_hash_table_lookup(pbdev->iotlb, &entry->iova); IOMMUTLBEvent event = { .type = entry->perm ? IOMMU_NOTIFIER_MAP : IOMMU_NOTIFIER_UNMAP, .entry = { @@ -XXX,XX +XXX,XX @@ uint32_t s390_pci_update_iotlb(S390PCIBusDevice *pbdev, if (!cache) { goto out; } - g_hash_table_remove(iommu->iotlb, &entry->iova); + g_hash_table_remove(pbdev->iotlb, &entry->iova); inc_dma_avail(iommu); /* Don't notify the iommu yet, maybe we can bundle contiguous unmaps */ goto out; @@ -XXX,XX +XXX,XX @@ uint32_t s390_pci_update_iotlb(S390PCIBusDevice *pbdev, cache->translated_addr = entry->translated_addr; cache->len = TARGET_PAGE_SIZE; cache->perm = entry->perm; - g_hash_table_replace(iommu->iotlb, &cache->iova, cache); + g_hash_table_replace(pbdev->iotlb, &cache->iova, cache); dec_dma_avail(iommu); } diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ struct S390PCIIOMMU { uint64_t pba; uint64_t pal; uint64_t max_dma_limit; - GHashTable *iotlb; S390PCIDMACount *dma_limit; }; @@ -XXX,XX +XXX,XX @@ struct S390PCIBusDevice { S390PCIIOMMU *iommu; IOMMUMemoryRegion iommu_mr; MemoryRegion *dm_mr; + GHashTable *iotlb; MemoryRegion msix_notify_mr; IndAddr *summary_ind; IndAddr *indicator; -- 2.34.1
This pointer is no longer used, after fields were moved from S390PCIIOMMU to S390PCIBusDevice. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 15 +++++++-------- include/hw/s390x/s390-pci-bus.h | 1 - 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr, .perm = IOMMU_NONE, }; - switch (iommu->pbdev->state) { + switch (pbdev->state) { case ZPCI_FS_ENABLED: case ZPCI_FS_BLOCKED: if (!iommu->enabled) { @@ -XXX,XX +XXX,XX @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr, } err: if (error) { - iommu->pbdev->state = ZPCI_FS_ERROR; - s390_pci_generate_error_event(error, iommu->pbdev->fh, - iommu->pbdev->fid, addr, 0); + pbdev->state = ZPCI_FS_ERROR; + s390_pci_generate_error_event(error, pbdev->fh, + pbdev->fid, addr, 0); } return ret; } @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_enable(S390PCIBusDevice *pbdev) * so the smallest IOMMU region we can define runs from 0 to the end * of the PCI address space. */ - char *name = g_strdup_printf("iommu-s390-%04x", iommu->pbdev->uid); + char *name = g_strdup_printf("iommu-s390-%04x", pbdev->uid); memory_region_init_iommu(&pbdev->iommu_mr, sizeof(pbdev->iommu_mr), TYPE_S390_IOMMU_MEMORY_REGION, OBJECT(&iommu->mr), name, iommu->pal + 1); @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_direct_map_enable(S390PCIBusDevice *pbdev) * IOVA X + SDMA. VFIO will handle pinning via its memory listener. */ g_autofree char *name = g_strdup_printf("iommu-dm-s390-%04x", - iommu->pbdev->uid); + pbdev->uid); pbdev->dm_mr = g_malloc0(sizeof(*pbdev->dm_mr)); memory_region_init_alias(pbdev->dm_mr, OBJECT(&iommu->mr), name, get_system_memory(), 0, s390_get_memory_limit(s390ms)); iommu->enabled = true; - memory_region_add_subregion(&iommu->mr, iommu->pbdev->zpci_fn.sdma, + memory_region_add_subregion(&iommu->mr, pbdev->zpci_fn.sdma, pbdev->dm_mr); } @@ -XXX,XX +XXX,XX @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev, pbdev->pdev = pdev; pbdev->iommu = s390_pci_get_iommu(s, pci_get_bus(pdev), pdev->devfn); - pbdev->iommu->pbdev = pbdev; pbdev->state = ZPCI_FS_DISABLED; set_pbdev_info(pbdev); diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ typedef struct S390PCIDMACount { struct S390PCIIOMMU { Object parent_obj; - S390PCIBusDevice *pbdev; AddressSpace as; MemoryRegion mr; bool enabled; -- 2.34.1
This field is only used when S390PCIBusDevice exists, so it can be moved there to simplify S390PCIIOMMU which purpose is just to store the "root" AddressSpace. This also allows to save/restore this field during migration. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 14 +++++++------- hw/s390x/s390-pci-inst.c | 8 ++++---- include/hw/s390x/s390-pci-bus.h | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ void s390_pci_sclp_deconfigure(SCCB *sccb) } else if (pbdev->summary_ind) { pci_dereg_irqs(pbdev); } - if (pbdev->iommu->enabled) { + if (pbdev->iommu_enabled) { pci_dereg_ioat(pbdev); } pbdev->state = ZPCI_FS_STANDBY; @@ -XXX,XX +XXX,XX @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr, switch (pbdev->state) { case ZPCI_FS_ENABLED: case ZPCI_FS_BLOCKED: - if (!iommu->enabled) { + if (!pbdev->iommu_enabled) { return ret; } break; @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_enable(S390PCIBusDevice *pbdev) memory_region_init_iommu(&pbdev->iommu_mr, sizeof(pbdev->iommu_mr), TYPE_S390_IOMMU_MEMORY_REGION, OBJECT(&iommu->mr), name, iommu->pal + 1); - iommu->enabled = true; + pbdev->iommu_enabled = true; memory_region_add_subregion(&iommu->mr, 0, MEMORY_REGION(&pbdev->iommu_mr)); g_free(name); } @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_direct_map_enable(S390PCIBusDevice *pbdev) memory_region_init_alias(pbdev->dm_mr, OBJECT(&iommu->mr), name, get_system_memory(), 0, s390_get_memory_limit(s390ms)); - iommu->enabled = true; + pbdev->iommu_enabled = true; memory_region_add_subregion(&iommu->mr, pbdev->zpci_fn.sdma, pbdev->dm_mr); } @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_direct_map_enable(S390PCIBusDevice *pbdev) void s390_pci_iommu_disable(S390PCIBusDevice *pbdev) { S390PCIIOMMU *iommu = pbdev->iommu; - iommu->enabled = false; + pbdev->iommu_enabled = false; g_hash_table_remove_all(pbdev->iotlb); if (pbdev->dm_mr) { memory_region_del_subregion(&iommu->mr, pbdev->dm_mr); @@ -XXX,XX +XXX,XX @@ static void s390_pcihost_reset(DeviceState *dev) } else if (pbdev->summary_ind) { pci_dereg_irqs(pbdev); } - if (pbdev->iommu->enabled) { + if (pbdev->iommu_enabled) { pci_dereg_ioat(pbdev); } pbdev->state = ZPCI_FS_STANDBY; @@ -XXX,XX +XXX,XX @@ static void s390_pci_device_reset(DeviceState *dev) } else if (pbdev->summary_ind) { pci_dereg_irqs(pbdev); } - if (pbdev->iommu->enabled) { + if (pbdev->iommu_enabled) { pci_dereg_ioat(pbdev); } diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, if (dmaas != 0) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL); - } else if (pbdev->iommu->enabled) { + } else if (pbdev->iommu_enabled) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); } else if (reg_ioat(env, pbdev, fib, ra)) { @@ -XXX,XX +XXX,XX @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, if (dmaas != 0) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL); - } else if (!pbdev->iommu->enabled) { + } else if (!pbdev->iommu_enabled) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); } else { @@ -XXX,XX +XXX,XX @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, if (dmaas != 0) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL); - } else if (!pbdev->iommu->enabled) { + } else if (!pbdev->iommu_enabled) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); } else { @@ -XXX,XX +XXX,XX @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, /* fallthrough */ case ZPCI_FS_ENABLED: fib.fc |= 0x80; - if (pbdev->iommu->enabled) { + if (pbdev->iommu_enabled) { fib.fc |= 0x10; } if (!(fh & FH_MASK_ENABLE)) { diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ struct S390PCIIOMMU { Object parent_obj; AddressSpace as; MemoryRegion mr; - bool enabled; uint64_t g_iota; uint64_t pba; uint64_t pal; @@ -XXX,XX +XXX,XX @@ struct S390PCIBusDevice { S390MsixInfo msix; AdapterRoutes routes; S390PCIIOMMU *iommu; + bool iommu_enabled; IOMMUMemoryRegion iommu_mr; MemoryRegion *dm_mr; GHashTable *iotlb; -- 2.34.1
This field is only used when S390PCIBusDevice exists, so it can be moved there to simplify S390PCIIOMMU which purpose is just to store the "root" AddressSpace. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 10 +++++----- hw/s390x/s390-pci-inst.c | 23 +++++++++++------------ include/hw/s390x/s390-pci-bus.h | 2 +- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ static void s390_pci_ioat_replay(S390PCIBusDevice *pbdev) return; } - if (iommu->dma_limit) { - dma_avail = iommu->dma_limit->avail; + if (pbdev->dma_limit) { + dma_avail = pbdev->dma_limit->avail; } else { dma_avail = 1; } @@ -XXX,XX +XXX,XX @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev, pbdev->forwarding_assist = false; } } - pbdev->iommu->dma_limit = s390_pci_start_dma_count(s, pbdev); + pbdev->dma_limit = s390_pci_start_dma_count(s, pbdev); /* Fill in CLP information passed via the vfio region */ s390_pci_get_clp_info(pbdev); if (!pbdev->interp) { @@ -XXX,XX +XXX,XX @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, pbdev->fid = 0; QTAILQ_REMOVE(&s->zpci_devs, pbdev, link); g_hash_table_remove(s->zpci_table, &pbdev->idx); - if (pbdev->iommu && pbdev->iommu->dma_limit) { - s390_pci_end_dma_count(s, pbdev->iommu->dma_limit); + if (pbdev->dma_limit) { + s390_pci_end_dma_count(s, pbdev->dma_limit); } g_hash_table_destroy(pbdev->iotlb); qdev_unrealize(dev); diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ #include "trace.h" -static inline void inc_dma_avail(S390PCIIOMMU *iommu) +static inline void inc_dma_avail(S390PCIBusDevice *pbdev) { - if (iommu->dma_limit) { - iommu->dma_limit->avail++; + if (pbdev->dma_limit) { + pbdev->dma_limit->avail++; } } -static inline void dec_dma_avail(S390PCIIOMMU *iommu) +static inline void dec_dma_avail(S390PCIBusDevice *pbdev) { - if (iommu->dma_limit) { - iommu->dma_limit->avail--; + if (pbdev->dma_limit) { + pbdev->dma_limit->avail--; } } @@ -XXX,XX +XXX,XX @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) uint32_t s390_pci_update_iotlb(S390PCIBusDevice *pbdev, S390IOTLBEntry *entry) { - S390PCIIOMMU *iommu = pbdev->iommu; S390IOTLBEntry *cache = g_hash_table_lookup(pbdev->iotlb, &entry->iova); IOMMUTLBEvent event = { .type = entry->perm ? IOMMU_NOTIFIER_MAP : IOMMU_NOTIFIER_UNMAP, @@ -XXX,XX +XXX,XX @@ uint32_t s390_pci_update_iotlb(S390PCIBusDevice *pbdev, goto out; } g_hash_table_remove(pbdev->iotlb, &entry->iova); - inc_dma_avail(iommu); + inc_dma_avail(pbdev); /* Don't notify the iommu yet, maybe we can bundle contiguous unmaps */ goto out; } else { @@ -XXX,XX +XXX,XX @@ uint32_t s390_pci_update_iotlb(S390PCIBusDevice *pbdev, cache->len = TARGET_PAGE_SIZE; cache->perm = entry->perm; g_hash_table_replace(pbdev->iotlb, &cache->iova, cache); - dec_dma_avail(iommu); + dec_dma_avail(pbdev); } /* @@ -XXX,XX +XXX,XX @@ uint32_t s390_pci_update_iotlb(S390PCIBusDevice *pbdev, memory_region_notify_iommu(&pbdev->iommu_mr, 0, event); out: - return iommu->dma_limit ? iommu->dma_limit->avail : 1; + return pbdev->dma_limit ? pbdev->dma_limit->avail : 1; } static void s390_pci_batch_unmap(S390PCIBusDevice *pbdev, uint64_t iova, @@ -XXX,XX +XXX,XX @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) } iommu = pbdev->iommu; - if (iommu->dma_limit) { - dma_avail = iommu->dma_limit->avail; + if (pbdev->dma_limit) { + dma_avail = pbdev->dma_limit->avail; } else { dma_avail = 1; } diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ struct S390PCIIOMMU { uint64_t pba; uint64_t pal; uint64_t max_dma_limit; - S390PCIDMACount *dma_limit; }; typedef struct S390PCIIOMMUTable { @@ -XXX,XX +XXX,XX @@ struct S390PCIBusDevice { IOMMUMemoryRegion iommu_mr; MemoryRegion *dm_mr; GHashTable *iotlb; + S390PCIDMACount *dma_limit; MemoryRegion msix_notify_mr; IndAddr *summary_ind; IndAddr *indicator; -- 2.34.1
This field is only used when S390PCIBusDevice exists, so it can be moved there to simplify S390PCIIOMMU which purpose is just to store the "root" AddressSpace. This also allows to save/restore this field during migration. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 2 +- hw/s390x/s390-pci-inst.c | 10 +++++----- include/hw/s390x/s390-pci-bus.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ static void s390_pci_ioat_replay(S390PCIBusDevice *pbdev) } while (curr < end) { - error = s390_guest_io_table_walk(iommu->g_iota, curr, &entry); + error = s390_guest_io_table_walk(pbdev->g_iota, curr, &entry); if (error) { error_report("Failure to walk table during iommu remap"); return; diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) } else { dma_avail = 1; } - if (!iommu->g_iota) { + if (!pbdev->g_iota) { error = ERR_EVENT_INVALAS; goto err; } @@ -XXX,XX +XXX,XX @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) start = sstart; again = false; while (start < end) { - error = s390_guest_io_table_walk(iommu->g_iota, start, &entry); + error = s390_guest_io_table_walk(pbdev->g_iota, start, &entry); if (error) { break; } @@ -XXX,XX +XXX,XX @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib, iommu->pba = pba; iommu->pal = pal; - iommu->g_iota = g_iota; + pbdev->g_iota = g_iota; if (t) { s390_pci_iommu_enable(pbdev); @@ -XXX,XX +XXX,XX @@ void pci_dereg_ioat(S390PCIBusDevice *pbdev) s390_pci_iommu_disable(pbdev); iommu->pba = 0; iommu->pal = 0; - iommu->g_iota = 0; + pbdev->g_iota = 0; } void fmb_timer_free(S390PCIBusDevice *pbdev) @@ -XXX,XX +XXX,XX @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, stq_be_p(&fib.pba, pbdev->iommu->pba); stq_be_p(&fib.pal, pbdev->iommu->pal); - stq_be_p(&fib.iota, pbdev->iommu->g_iota); + stq_be_p(&fib.iota, pbdev->g_iota); stq_be_p(&fib.aibv, pbdev->routes.adapter.ind_addr); stq_be_p(&fib.aisb, pbdev->routes.adapter.summary_addr); stq_be_p(&fib.fmb_addr, pbdev->fmb_addr); diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ struct S390PCIIOMMU { Object parent_obj; AddressSpace as; MemoryRegion mr; - uint64_t g_iota; uint64_t pba; uint64_t pal; uint64_t max_dma_limit; @@ -XXX,XX +XXX,XX @@ struct S390PCIBusDevice { IOMMUMemoryRegion iommu_mr; MemoryRegion *dm_mr; GHashTable *iotlb; + uint64_t g_iota; S390PCIDMACount *dma_limit; MemoryRegion msix_notify_mr; IndAddr *summary_ind; -- 2.34.1
This field is only used when S390PCIBusDevice exists, so it can be moved there to simplify S390PCIIOMMU which purpose is just to store the "root" AddressSpace. This also allows to save/restore this field during migration. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 4 ++-- hw/s390x/s390-pci-inst.c | 8 ++++---- include/hw/s390x/s390-pci-bus.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr, trace_s390_pci_iommu_xlate(addr); - if (addr < iommu->pba || addr > iommu->pal) { + if (addr < pbdev->pba || addr > iommu->pal) { error = ERR_EVENT_OORANGE; goto err; } @@ -XXX,XX +XXX,XX @@ static void s390_pci_ioat_replay(S390PCIBusDevice *pbdev) hwaddr curr, end; S390PCIIOMMU *iommu = pbdev->iommu; - curr = iommu->pba; + curr = pbdev->pba; end = iommu->pal; if (pbdev->dm_mr) { diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) goto err; } - if (end < iommu->pba || start > iommu->pal) { + if (end < pbdev->pba || start > iommu->pal) { error = ERR_EVENT_OORANGE; goto err; } @@ -XXX,XX +XXX,XX @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib, return -EINVAL; } - iommu->pba = pba; + pbdev->pba = pba; iommu->pal = pal; pbdev->g_iota = g_iota; @@ -XXX,XX +XXX,XX @@ void pci_dereg_ioat(S390PCIBusDevice *pbdev) { S390PCIIOMMU *iommu = pbdev->iommu; s390_pci_iommu_disable(pbdev); - iommu->pba = 0; + pbdev->pba = 0; iommu->pal = 0; pbdev->g_iota = 0; } @@ -XXX,XX +XXX,XX @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, return 0; } - stq_be_p(&fib.pba, pbdev->iommu->pba); + stq_be_p(&fib.pba, pbdev->pba); stq_be_p(&fib.pal, pbdev->iommu->pal); stq_be_p(&fib.iota, pbdev->g_iota); stq_be_p(&fib.aibv, pbdev->routes.adapter.ind_addr); diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ struct S390PCIIOMMU { Object parent_obj; AddressSpace as; MemoryRegion mr; - uint64_t pba; uint64_t pal; uint64_t max_dma_limit; }; @@ -XXX,XX +XXX,XX @@ struct S390PCIBusDevice { MemoryRegion *dm_mr; GHashTable *iotlb; uint64_t g_iota; + uint64_t pba; S390PCIDMACount *dma_limit; MemoryRegion msix_notify_mr; IndAddr *summary_ind; -- 2.34.1
This field is only used when S390PCIBusDevice exists, so it can be moved there to simplify S390PCIIOMMU which purpose is just to store the "root" AddressSpace. This also allows to save/restore this field during migration. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 8 +++----- hw/s390x/s390-pci-inst.c | 12 ++++-------- include/hw/s390x/s390-pci-bus.h | 2 +- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr, IOMMUAccessFlags flag, int iommu_idx) { S390PCIBusDevice *pbdev = container_of(mr, S390PCIBusDevice, iommu_mr); - S390PCIIOMMU *iommu = pbdev->iommu; S390IOTLBEntry *entry; uint64_t iova = addr & TARGET_PAGE_MASK; uint16_t error = 0; @@ -XXX,XX +XXX,XX @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr, trace_s390_pci_iommu_xlate(addr); - if (addr < pbdev->pba || addr > iommu->pal) { + if (addr < pbdev->pba || addr > pbdev->pal) { error = ERR_EVENT_OORANGE; goto err; } @@ -XXX,XX +XXX,XX @@ static void s390_pci_ioat_replay(S390PCIBusDevice *pbdev) uint16_t error = 0; uint32_t dma_avail; hwaddr curr, end; - S390PCIIOMMU *iommu = pbdev->iommu; curr = pbdev->pba; - end = iommu->pal; + end = pbdev->pal; if (pbdev->dm_mr) { /* If direct mapping is used, there are no guest tables to replay */ @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_enable(S390PCIBusDevice *pbdev) char *name = g_strdup_printf("iommu-s390-%04x", pbdev->uid); memory_region_init_iommu(&pbdev->iommu_mr, sizeof(pbdev->iommu_mr), TYPE_S390_IOMMU_MEMORY_REGION, OBJECT(&iommu->mr), - name, iommu->pal + 1); + name, pbdev->pal + 1); pbdev->iommu_enabled = true; memory_region_add_subregion(&iommu->mr, 0, MEMORY_REGION(&pbdev->iommu_mr)); g_free(name); diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) uint32_t fh; uint16_t error = 0; S390PCIBusDevice *pbdev; - S390PCIIOMMU *iommu; S390IOTLBEntry entry; hwaddr start, end, sstart; uint32_t dma_avail; @@ -XXX,XX +XXX,XX @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) break; } - iommu = pbdev->iommu; if (pbdev->dma_limit) { dma_avail = pbdev->dma_limit->avail; } else { @@ -XXX,XX +XXX,XX @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) goto err; } - if (end < pbdev->pba || start > iommu->pal) { + if (end < pbdev->pba || start > pbdev->pal) { error = ERR_EVENT_OORANGE; goto err; } @@ -XXX,XX +XXX,XX @@ bool s390_pci_is_translation_enabled(uint64_t g_iota) static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib, uintptr_t ra) { - S390PCIIOMMU *iommu = pbdev->iommu; uint64_t pba = ldq_be_p(&fib.pba); uint64_t pal = ldq_be_p(&fib.pal); uint64_t g_iota = ldq_be_p(&fib.iota); @@ -XXX,XX +XXX,XX @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib, } pbdev->pba = pba; - iommu->pal = pal; + pbdev->pal = pal; pbdev->g_iota = g_iota; if (t) { @@ -XXX,XX +XXX,XX @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib, void pci_dereg_ioat(S390PCIBusDevice *pbdev) { - S390PCIIOMMU *iommu = pbdev->iommu; s390_pci_iommu_disable(pbdev); pbdev->pba = 0; - iommu->pal = 0; + pbdev->pal = 0; pbdev->g_iota = 0; } @@ -XXX,XX +XXX,XX @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, } stq_be_p(&fib.pba, pbdev->pba); - stq_be_p(&fib.pal, pbdev->iommu->pal); + stq_be_p(&fib.pal, pbdev->pal); stq_be_p(&fib.iota, pbdev->g_iota); stq_be_p(&fib.aibv, pbdev->routes.adapter.ind_addr); stq_be_p(&fib.aisb, pbdev->routes.adapter.summary_addr); diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ struct S390PCIIOMMU { Object parent_obj; AddressSpace as; MemoryRegion mr; - uint64_t pal; uint64_t max_dma_limit; }; @@ -XXX,XX +XXX,XX @@ struct S390PCIBusDevice { GHashTable *iotlb; uint64_t g_iota; uint64_t pba; + uint64_t pal; S390PCIDMACount *dma_limit; MemoryRegion msix_notify_mr; IndAddr *summary_ind; -- 2.34.1
This field is only used when S390PCIBusDevice exists, so it can be moved there to simplify S390PCIIOMMU which purpose is just to store the "root" AddressSpace. This also allows to save/restore this field during migration. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-vfio.c | 4 ++-- include/hw/s390x/s390-pci-bus.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/s390x/s390-pci-vfio.c b/hw/s390x/s390-pci-vfio.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-vfio.c +++ b/hw/s390x/s390-pci-vfio.c @@ -XXX,XX +XXX,XX @@ S390PCIDMACount *s390_pci_start_dma_count(S390pciState *s, cnt->users = 1; cnt->avail = avail; QTAILQ_INSERT_TAIL(&s->zpci_dma_limit, cnt, link); - pbdev->iommu->max_dma_limit = avail; + pbdev->max_dma_limit = avail; return cnt; } @@ -XXX,XX +XXX,XX @@ static void s390_pci_read_base(S390PCIBusDevice *pbdev, * to request that the guest free DMA mappings as necessary. */ if (!pbdev->rtr_avail) { - vfio_size = pbdev->iommu->max_dma_limit << qemu_target_page_bits(); + vfio_size = pbdev->max_dma_limit << qemu_target_page_bits(); if (vfio_size > 0 && vfio_size < cap->end_dma - cap->start_dma + 1) { pbdev->zpci_fn.edma = cap->start_dma + vfio_size - 1; } diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ struct S390PCIIOMMU { Object parent_obj; AddressSpace as; MemoryRegion mr; - uint64_t max_dma_limit; }; typedef struct S390PCIIOMMUTable { @@ -XXX,XX +XXX,XX @@ struct S390PCIBusDevice { uint64_t g_iota; uint64_t pba; uint64_t pal; + uint64_t max_dma_limit; S390PCIDMACount *dma_limit; MemoryRegion msix_notify_mr; IndAddr *summary_ind; -- 2.34.1
Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- include/hw/s390x/s390-pci-bus.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ typedef struct S390PCIDMACount { QTAILQ_ENTRY(S390PCIDMACount) link; } S390PCIDMACount; +/* + * This structure holds the PCI device AddressSpace that QEMU needs to link + * into its internal structures before the zPCI and PCI devices are fully + * initialized. It's a QEMU requirement to provide this "root" AddressSpace + * early. The AddressSpace is only actually used for I/O while the PCI + * device is plugged in and configured by the guest, at which time it gets + * additional memory subregions from zPCI device, that can do real work. + */ struct S390PCIIOMMU { Object parent_obj; AddressSpace as; -- 2.34.1
Implement zPCI device state migration, consequently enabling migration of VMs that have emulated PCI devices, whether virtio or not. Migration is allowed for devices whose function handle has the FH_SHM_EMUL bit set. For these devices QEMU will save and restore the state of its zPCI emulator. Passthrough devices will continue to block migration. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 112 ++++++++++++++++++++++++++++++-- hw/s390x/s390-pci-inst.c | 2 +- include/hw/s390x/s390-pci-bus.h | 2 + 3 files changed, 110 insertions(+), 6 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ #include "hw/pci/pci_bridge.h" #include "hw/pci/msi.h" #include "exec/cpu-common.h" +#include "migration/blocker.h" #include "qemu/error-report.h" #include "qemu/module.h" #include "system/reset.h" @@ -XXX,XX +XXX,XX @@ static int s390_pci_interp_plug(S390pciState *s, S390PCIBusDevice *pbdev) return 0; } +static int s390_set_passthrough_migration_blocker(S390PCIBusDevice *pbdev, + Error **errp) +{ + pbdev->passthrough_migr_blocker = NULL; + + if (pbdev->fh & FH_SHM_EMUL) { + return 0; + } + error_setg(&pbdev->passthrough_migr_blocker, + "Migration blocked by passthrough zPCI device " + "fh 0x%x uid %d fid %d", pbdev->fh, pbdev->uid, pbdev->fid); + + return migrate_add_blocker(&pbdev->passthrough_migr_blocker, errp); +} + +static void s390_clear_passthrough_migration_blocker(S390PCIBusDevice *pbdev) +{ + if (pbdev->passthrough_migr_blocker) { + migrate_del_blocker(&pbdev->passthrough_migr_blocker); + } +} + static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { @@ -XXX,XX +XXX,XX @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev, return; } + if (s390_set_passthrough_migration_blocker(pbdev, errp)) { + s390_pci_msix_free(pbdev); + return; + } + if (dev->hotplugged) { s390_pci_generate_plug_event(HP_EVENT_TO_CONFIGURED , pbdev->fh, pbdev->fid); @@ -XXX,XX +XXX,XX @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, return; } + s390_clear_passthrough_migration_blocker(pbdev); + s390_pci_generate_plug_event(HP_EVENT_STANDBY_TO_RESERVED, pbdev->fh, pbdev->fid); bus = pci_get_bus(pci_dev); @@ -XXX,XX +XXX,XX @@ static const Property s390_pci_device_properties[] = { true), }; -static const VMStateDescription s390_pci_device_vmstate = { - .name = TYPE_S390_PCI_DEVICE, +static int s390_pci_device_post_load(void *opaque, int version_id) +{ + S390PCIBusDevice *pbdev = S390_PCI_DEVICE(opaque); + + /* + * Now that S390PCIBusDevice fields have been restored, regenerate IOMMU + * state - that includes IOTLB contents and QEMU memory regions. + */ + if (pbdev->iommu_enabled) { + assert(pbdev->iommu); + if (s390_pci_is_translation_enabled(pbdev->g_iota)) { + s390_pci_iommu_enable(pbdev); + s390_pci_ioat_replay(pbdev); + } else { + s390_pci_iommu_direct_map_enable(pbdev); + } + } + /* - * TODO: add state handling here, so migration works at least with - * emulated pci devices on s390x + * Guest sets fmb_addr by mpcifc.ZPCI_MOD_FC_SET_MEASURE instruction. + * The handler consequently starts fmb_timer. Now that fmb_addr has been + * restored, we may need to restart fmb_timer. */ - .unmigratable = 1, + if (pbdev->fmb_addr) { + assert(!pbdev->fmb_timer); + assert(pbdev->pci_group); + pbdev->fmb_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, + fmb_update, pbdev); + timer_mod(pbdev->fmb_timer, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + + pbdev->pci_group->zpci_group.mui); + } + return 0; +} + +static const VMStateDescription s390_pci_device_vmstate = { + .name = TYPE_S390_PCI_DEVICE, + .version_id = 1, + .minimum_version_id = 1, + .post_load = s390_pci_device_post_load, + .fields = (const VMStateField[]) { + VMSTATE_UINT32(state, S390PCIBusDevice), + VMSTATE_UINT16(uid, S390PCIBusDevice), + VMSTATE_UINT32(idx, S390PCIBusDevice), + VMSTATE_UINT32(fh, S390PCIBusDevice), + VMSTATE_UINT32(fid, S390PCIBusDevice), + VMSTATE_BOOL(fid_defined, S390PCIBusDevice), + VMSTATE_UINT64(fmb_addr, S390PCIBusDevice), + VMSTATE_UINT32(fmb.format, S390PCIBusDevice), + VMSTATE_UINT32(fmb.sample, S390PCIBusDevice), + VMSTATE_UINT64(fmb.last_update, S390PCIBusDevice), + VMSTATE_UINT64_ARRAY(fmb.counter, S390PCIBusDevice, + ARRAY_SIZE(((S390PCIBusDevice *)0)->fmb.counter)), + VMSTATE_UINT64(fmb.fmt0.dma_rbytes, S390PCIBusDevice), + VMSTATE_UINT64(fmb.fmt0.dma_wbytes, S390PCIBusDevice), + VMSTATE_UINT8(isc, S390PCIBusDevice), + VMSTATE_UINT16(noi, S390PCIBusDevice), + VMSTATE_UINT8(sum, S390PCIBusDevice), + VMSTATE_UINT8(pft, S390PCIBusDevice), + VMSTATE_UINT64(routes.adapter.ind_addr, S390PCIBusDevice), + VMSTATE_UINT64(routes.adapter.summary_addr, S390PCIBusDevice), + VMSTATE_UINT64(routes.adapter.ind_offset, S390PCIBusDevice), + VMSTATE_UINT32(routes.adapter.summary_offset, S390PCIBusDevice), + VMSTATE_UINT32(routes.adapter.adapter_id, S390PCIBusDevice), + VMSTATE_BOOL(iommu_enabled, S390PCIBusDevice), + VMSTATE_UINT64(g_iota, S390PCIBusDevice), + VMSTATE_UINT64(pba, S390PCIBusDevice), + VMSTATE_UINT64(pal, S390PCIBusDevice), + VMSTATE_UINT64(max_dma_limit, S390PCIBusDevice), + VMSTATE_PTR_TO_IND_ADDR(summary_ind, S390PCIBusDevice), + VMSTATE_PTR_TO_IND_ADDR(indicator, S390PCIBusDevice), + VMSTATE_BOOL(pci_unplug_request_processed, S390PCIBusDevice), + VMSTATE_BOOL(unplug_requested, S390PCIBusDevice), + VMSTATE_BOOL(interp, S390PCIBusDevice), + VMSTATE_BOOL(forwarding_assist, S390PCIBusDevice), + VMSTATE_BOOL(aif, S390PCIBusDevice), + VMSTATE_BOOL(rtr_avail, S390PCIBusDevice), + VMSTATE_END_OF_LIST() + } }; static void s390_pci_device_class_init(ObjectClass *klass, const void *data) diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ static int fmb_do_update(S390PCIBusDevice *pbdev, int offset, uint64_t val, return ret; } -static void fmb_update(void *opaque) +void fmb_update(void *opaque) { S390PCIBusDevice *pbdev = opaque; int64_t t = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ struct S390PCIBusDevice { uint16_t uid; uint32_t idx; uint32_t fh; + Error *passthrough_migr_blocker; uint32_t fid; bool fid_defined; uint64_t fmb_addr; @@ -XXX,XX +XXX,XX @@ S390PCIBusDevice *s390_pci_find_dev_by_pci(S390pciState *s, S390PCIBusDevice *s390_pci_find_next_avail_dev(S390pciState *s, S390PCIBusDevice *pbdev); void s390_pci_ism_reset(void); +void fmb_update(void *opaque); #endif -- 2.34.1
fmb_timer is now started in 3 different places. The new function will encapsulate that to make sure mui is added in all cases. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 5 ++--- hw/s390x/s390-pci-inst.c | 14 ++++++++++---- include/hw/s390x/s390-pci-bus.h | 1 + 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ static int s390_pci_device_post_load(void *opaque, int version_id) assert(pbdev->pci_group); pbdev->fmb_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, fmb_update, pbdev); - timer_mod(pbdev->fmb_timer, - qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + - pbdev->pci_group->zpci_group.mui); + s390_pci_schedule_fmb_timer(pbdev, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)); } return 0; } diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ static int fmb_do_update(S390PCIBusDevice *pbdev, int offset, uint64_t val, return ret; } +void s390_pci_schedule_fmb_timer(S390PCIBusDevice *pbdev, uint64_t start) +{ + timer_mod(pbdev->fmb_timer, start + pbdev->pci_group->zpci_group.mui); +} + void fmb_update(void *opaque) { S390PCIBusDevice *pbdev = opaque; + + /* Must be read before updating U bit */ int64_t t = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); int i; @@ -XXX,XX +XXX,XX @@ void fmb_update(void *opaque) sizeof(pbdev->fmb.last_update))) { return; } - timer_mod(pbdev->fmb_timer, t + pbdev->pci_group->zpci_group.mui); + s390_pci_schedule_fmb_timer(pbdev, t); } static int mpcifc_reg_int_interp(S390PCIBusDevice *pbdev, ZpciFib *fib) @@ -XXX,XX +XXX,XX @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, timer_del(pbdev->fmb_timer); } pbdev->fmb_addr = fmb_addr; - timer_mod(pbdev->fmb_timer, - qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + - pbdev->pci_group->zpci_group.mui); + s390_pci_schedule_fmb_timer(pbdev, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)); break; } default: diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ S390PCIBusDevice *s390_pci_find_next_avail_dev(S390pciState *s, S390PCIBusDevice *pbdev); void s390_pci_ism_reset(void); void fmb_update(void *opaque); +void s390_pci_schedule_fmb_timer(S390PCIBusDevice *pbdev, uint64_t start); #endif -- 2.34.1
Up until now QEMU marked any zPCI device as "unmigratable." This patch series adds support for migrating emulated devices, which are simpler to migrate. It leaves VFIO devices still unmigratable. To enable migration, the device state needs to be saved/restored to/from the migration stream. There are 2 kinds of emulated devices - those that use the zPCI IOMMU page table emulation in QEMU (e.g., Intel IGB NIC), and those that don't (virtio). This is important to note for testing purposes. This change was tested on IGB, virtio-net and virtio-blk devices by running I/O on them while performing "virsh managedsave, virsh start" and also live migration to another host and back. Changes in v3: - patch 1: provided proper error handling. - patch 14: Fixed zpci_table corruption during migration that occurred if devices were hot-unplugged and plugged before migration. - patch 14: Provided UID-based migration stream IDs for zpci devices to avoid unstable auto-generated IDs that caused migration problems if devices were hot-unplugged and plugged before migration. Konstantin Shkolnyy (14): s390x/pci: Create function to contain translation status check s390x/pci: Move iommu_mr from S390PCIIOMMU to S390PCIBusDevice s390x/pci: Move dm_mr from S390PCIIOMMU to S390PCIBusDevice s390x/pci: Move iotlb from S390PCIIOMMU to S390PCIBusDevice s390x/pci: Remove a ptr to S390PCIBusDevice from S390PCIIOMMU s390x/pci: Move/rename enabled from S390PCIIOMMU to S390PCIBusDevice s390x/pci: Move dma_limit from S390PCIIOMMU to S390PCIBusDevice s390x/pci: Move g_iota from S390PCIIOMMU to S390PCIBusDevice s390x/pci: Move pba from S390PCIIOMMU to S390PCIBusDevice s390x/pci: Move pal from S390PCIIOMMU to S390PCIBusDevice s390x/pci: Move max_dma_limit from S390PCIIOMMU to S390PCIBusDevice s390x/pci: Add a comment explaining S390PCIIOMMU purpose s390x/pci: Implement migration for emulated devices s390x/pci: Create function to contain fmb_timer start Matthew Rosato (1): s390x/pci: implement IOMMU replay hw/s390x/s390-pci-bus.c | 338 ++++++++++++++++++++++++++----- hw/s390x/s390-pci-inst.c | 116 ++++++----- hw/s390x/s390-pci-vfio.c | 4 +- hw/s390x/s390-virtio-ccw.c | 5 + include/hw/s390x/s390-pci-bus.h | 39 ++-- include/hw/s390x/s390-pci-inst.h | 3 +- 6 files changed, 380 insertions(+), 125 deletions(-) -- 2.34.1
From: Matthew Rosato <mjrosato@linux.ibm.com> There are a few scenarios where IOMMU replay can potentially be needed for zPCI device, namely VFIO device reset scenarios where the guest continues running and expects the contents of its IOMMU to be replayed upon IOAT re-registration and migration scenarios where the destination must reconstruct the IOMMU on the destination. zPCI migration is not supported yet, but the IOMMU replay function is implemented so that it can be called both from IOMMUMemoryRegionClass now and migration post_load later. Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com> Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 62 ++++++++++++++++++++++++++++---- hw/s390x/s390-pci-inst.c | 4 +-- include/hw/s390x/s390-pci-inst.h | 1 + 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ err: return ret; } -static void s390_pci_iommu_replay(IOMMUMemoryRegion *iommu, +static void s390_pci_ioat_replay(S390PCIIOMMU *iommu) +{ + S390IOTLBEntry entry; + uint16_t error = 0; + uint32_t dma_avail; + hwaddr curr, end; + + curr = iommu->pba; + end = iommu->pal; + + if (iommu->dm_mr) { + /* If direct mapping is used, there are no guest tables to replay */ + return; + } + + if (iommu->dma_limit) { + dma_avail = iommu->dma_limit->avail; + } else { + dma_avail = 1; + } + + while (curr < end) { + error = s390_guest_io_table_walk(iommu->g_iota, curr, &entry); + if (error) { + pbdev->state = ZPCI_FS_ERROR; + s390_pci_generate_error_event(error, pbdev->fh, pbdev->fid, curr, + 0); + error_report("Failure to walk table during iommu remap"); + return; + } + + if (entry.perm != IOMMU_NONE) { + if (dma_avail > 0) { + dma_avail = s390_pci_update_iotlb(iommu, &entry); + } else { + /* + * There is no reliable method to request the guest to release + * mappings other than in response to a RPCIT instruction; + * generate a permanent error condition and require the device + * to be completely re-initialized from the guest side. + */ + pbdev->state = ZPCI_FS_ERROR; + s390_pci_generate_error_event(ERR_EVENT_PERMERR, pbdev->fh, + pbdev->fid, 0, 0); + error_report("DMA mappings exhausted: iommu remap failed"); + return; + } + } + curr += entry.len; + } +} + +static void s390_pci_iommu_replay(IOMMUMemoryRegion *mr, IOMMUNotifier *notifier) { - /* It's impossible to plug a pci device on s390x that already has iommu - * mappings which need to be replayed, that is due to the "one iommu per - * zpci device" construct. But when we support migration of vfio-pci - * devices in future, we need to revisit this. - */ + S390PCIIOMMU *iommu = container_of(mr, S390PCIIOMMU, iommu_mr); + + s390_pci_ioat_replay(iommu); } static S390PCIIOMMU *s390_pci_get_iommu(S390pciState *s, PCIBus *bus, diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) return 0; } -static uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu, - S390IOTLBEntry *entry) +uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu, + S390IOTLBEntry *entry) { S390IOTLBEntry *cache = g_hash_table_lookup(iommu->iotlb, &entry->iova); IOMMUTLBEvent event = { diff --git a/include/hw/s390x/s390-pci-inst.h b/include/hw/s390x/s390-pci-inst.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-inst.h +++ b/include/hw/s390x/s390-pci-inst.h @@ -XXX,XX +XXX,XX @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, uintptr_t ra); void fmb_timer_free(S390PCIBusDevice *pbdev); +uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu, S390IOTLBEntry *entry); #define ZPCI_IO_BAR_MIN 0 #define ZPCI_IO_BAR_MAX 5 -- 2.34.1
Make it more clear what the bit means, and the new function will be called from yet another place in the future. Reviewed-by: Christian Borntraeger <borntraeger@linux.ibm.com> Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com> Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-inst.c | 7 ++++++- include/hw/s390x/s390-pci-bus.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ int pci_dereg_irqs(S390PCIBusDevice *pbdev) return 0; } +bool s390_pci_is_translation_enabled(uint64_t g_iota) +{ + return ((g_iota >> 11) & 0x1) != 0; /* "T" bit */ +} + static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib, uintptr_t ra) { @@ -XXX,XX +XXX,XX @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib, uint64_t pal = ldq_be_p(&fib.pal); uint64_t g_iota = ldq_be_p(&fib.iota); uint8_t dt = (g_iota >> 2) & 0x7; - uint8_t t = (g_iota >> 11) & 0x1; + bool t = s390_pci_is_translation_enabled(g_iota); pba &= ~0xfff; pal |= 0xfff; diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ int pci_chsc_sei_nt2_get_event(void *res); int pci_chsc_sei_nt2_have_event(void); void s390_pci_sclp_configure(SCCB *sccb); void s390_pci_sclp_deconfigure(SCCB *sccb); +bool s390_pci_is_translation_enabled(uint64_t g_iota); void s390_pci_iommu_enable(S390PCIIOMMU *iommu); void s390_pci_iommu_direct_map_enable(S390PCIIOMMU *iommu); void s390_pci_iommu_disable(S390PCIIOMMU *iommu); -- 2.34.1
This field is only used when S390PCIBusDevice exists, so it can be moved there to simplify S390PCIIOMMU which purpose is just to store the "root" AddressSpace. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 32 ++++++++++++++++++-------------- hw/s390x/s390-pci-inst.c | 28 +++++++++++++++------------- include/hw/s390x/s390-pci-bus.h | 6 +++--- include/hw/s390x/s390-pci-inst.h | 4 ++-- 4 files changed, 38 insertions(+), 32 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ void s390_pci_sclp_deconfigure(SCCB *sccb) pci_dereg_irqs(pbdev); } if (pbdev->iommu->enabled) { - pci_dereg_ioat(pbdev->iommu); + pci_dereg_ioat(pbdev); } pbdev->state = ZPCI_FS_STANDBY; rc = SCLP_RC_NORMAL_COMPLETION; @@ -XXX,XX +XXX,XX @@ uint16_t s390_guest_io_table_walk(uint64_t g_iota, hwaddr addr, static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr, IOMMUAccessFlags flag, int iommu_idx) { - S390PCIIOMMU *iommu = container_of(mr, S390PCIIOMMU, iommu_mr); + S390PCIBusDevice *pbdev = container_of(mr, S390PCIBusDevice, iommu_mr); + S390PCIIOMMU *iommu = pbdev->iommu; S390IOTLBEntry *entry; uint64_t iova = addr & TARGET_PAGE_MASK; uint16_t error = 0; @@ -XXX,XX +XXX,XX @@ err: return ret; } -static void s390_pci_ioat_replay(S390PCIIOMMU *iommu) +static void s390_pci_ioat_replay(S390PCIBusDevice *pbdev) { S390IOTLBEntry entry; uint16_t error = 0; uint32_t dma_avail; hwaddr curr, end; + S390PCIIOMMU *iommu = pbdev->iommu; curr = iommu->pba; end = iommu->pal; @@ -XXX,XX +XXX,XX @@ static void s390_pci_ioat_replay(S390PCIIOMMU *iommu) if (entry.perm != IOMMU_NONE) { if (dma_avail > 0) { - dma_avail = s390_pci_update_iotlb(iommu, &entry); + dma_avail = s390_pci_update_iotlb(pbdev, &entry); } else { /* * There is no reliable method to request the guest to release @@ -XXX,XX +XXX,XX @@ static void s390_pci_ioat_replay(S390PCIIOMMU *iommu) static void s390_pci_iommu_replay(IOMMUMemoryRegion *mr, IOMMUNotifier *notifier) { - S390PCIIOMMU *iommu = container_of(mr, S390PCIIOMMU, iommu_mr); + S390PCIBusDevice *pbdev = container_of(mr, S390PCIBusDevice, iommu_mr); - s390_pci_ioat_replay(iommu); + s390_pci_ioat_replay(pbdev); } static S390PCIIOMMU *s390_pci_get_iommu(S390pciState *s, PCIBus *bus, @@ -XXX,XX +XXX,XX @@ static const MemoryRegionOps s390_msi_ctrl_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -void s390_pci_iommu_enable(S390PCIIOMMU *iommu) +void s390_pci_iommu_enable(S390PCIBusDevice *pbdev) { + S390PCIIOMMU *iommu = pbdev->iommu; /* * The iommu region is initialized against a 0-mapped address space, * so the smallest IOMMU region we can define runs from 0 to the end * of the PCI address space. */ char *name = g_strdup_printf("iommu-s390-%04x", iommu->pbdev->uid); - memory_region_init_iommu(&iommu->iommu_mr, sizeof(iommu->iommu_mr), + memory_region_init_iommu(&pbdev->iommu_mr, sizeof(pbdev->iommu_mr), TYPE_S390_IOMMU_MEMORY_REGION, OBJECT(&iommu->mr), name, iommu->pal + 1); iommu->enabled = true; - memory_region_add_subregion(&iommu->mr, 0, MEMORY_REGION(&iommu->iommu_mr)); + memory_region_add_subregion(&iommu->mr, 0, MEMORY_REGION(&pbdev->iommu_mr)); g_free(name); } @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_direct_map_enable(S390PCIIOMMU *iommu) iommu->dm_mr); } -void s390_pci_iommu_disable(S390PCIIOMMU *iommu) +void s390_pci_iommu_disable(S390PCIBusDevice *pbdev) { + S390PCIIOMMU *iommu = pbdev->iommu; iommu->enabled = false; g_hash_table_remove_all(iommu->iotlb); if (iommu->dm_mr) { @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_disable(S390PCIIOMMU *iommu) iommu->dm_mr = NULL; } else { memory_region_del_subregion(&iommu->mr, - MEMORY_REGION(&iommu->iommu_mr)); - object_unparent(OBJECT(&iommu->iommu_mr)); + MEMORY_REGION(&pbdev->iommu_mr)); + object_unparent(OBJECT(&pbdev->iommu_mr)); } } @@ -XXX,XX +XXX,XX @@ static void s390_pcihost_reset(DeviceState *dev) pci_dereg_irqs(pbdev); } if (pbdev->iommu->enabled) { - pci_dereg_ioat(pbdev->iommu); + pci_dereg_ioat(pbdev); } pbdev->state = ZPCI_FS_STANDBY; s390_pci_perform_unplug(pbdev); @@ -XXX,XX +XXX,XX @@ static void s390_pci_device_reset(DeviceState *dev) pci_dereg_irqs(pbdev); } if (pbdev->iommu->enabled) { - pci_dereg_ioat(pbdev->iommu); + pci_dereg_ioat(pbdev); } fmb_timer_free(pbdev); diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) return 0; } -uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu, +uint32_t s390_pci_update_iotlb(S390PCIBusDevice *pbdev, S390IOTLBEntry *entry) { + S390PCIIOMMU *iommu = pbdev->iommu; S390IOTLBEntry *cache = g_hash_table_lookup(iommu->iotlb, &entry->iova); IOMMUTLBEvent event = { .type = entry->perm ? IOMMU_NOTIFIER_MAP : IOMMU_NOTIFIER_UNMAP, @@ -XXX,XX +XXX,XX @@ uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu, event.type = IOMMU_NOTIFIER_UNMAP; event.entry.perm = IOMMU_NONE; - memory_region_notify_iommu(&iommu->iommu_mr, 0, event); + memory_region_notify_iommu(&pbdev->iommu_mr, 0, event); event.type = IOMMU_NOTIFIER_MAP; event.entry.perm = entry->perm; } @@ -XXX,XX +XXX,XX @@ uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu, * All associated iotlb entries have already been cleared, trigger the * unmaps. */ - memory_region_notify_iommu(&iommu->iommu_mr, 0, event); + memory_region_notify_iommu(&pbdev->iommu_mr, 0, event); out: return iommu->dma_limit ? iommu->dma_limit->avail : 1; } -static void s390_pci_batch_unmap(S390PCIIOMMU *iommu, uint64_t iova, +static void s390_pci_batch_unmap(S390PCIBusDevice *pbdev, uint64_t iova, uint64_t len) { uint64_t remain = len, start = iova, end = start + len - 1, mask, size; @@ -XXX,XX +XXX,XX @@ static void s390_pci_batch_unmap(S390PCIIOMMU *iommu, uint64_t iova, size = mask + 1; event.entry.iova = start; event.entry.addr_mask = mask; - memory_region_notify_iommu(&iommu->iommu_mr, 0, event); + memory_region_notify_iommu(&pbdev->iommu_mr, 0, event); start += size; remain -= size; } @@ -XXX,XX +XXX,XX @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) coalesce += entry.len; } else if (coalesce > 0) { /* Unleash the coalesced unmap before processing a new map */ - s390_pci_batch_unmap(iommu, iova, coalesce); + s390_pci_batch_unmap(pbdev, iova, coalesce); coalesce = 0; } start += entry.len; while (entry.iova < start && entry.iova < end) { if (dma_avail > 0 || entry.perm == IOMMU_NONE) { - dma_avail = s390_pci_update_iotlb(iommu, &entry); + dma_avail = s390_pci_update_iotlb(pbdev, &entry); entry.iova += TARGET_PAGE_SIZE; entry.translated_addr += TARGET_PAGE_SIZE; } else { @@ -XXX,XX +XXX,XX @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) } if (coalesce) { /* Unleash the coalesced unmap before finishing rpcit */ - s390_pci_batch_unmap(iommu, iova, coalesce); + s390_pci_batch_unmap(pbdev, iova, coalesce); coalesce = 0; } if (again && dma_avail > 0) @@ -XXX,XX +XXX,XX @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib, iommu->g_iota = g_iota; if (t) { - s390_pci_iommu_enable(iommu); + s390_pci_iommu_enable(pbdev); } else { s390_pci_iommu_direct_map_enable(iommu); } @@ -XXX,XX +XXX,XX @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib, return 0; } -void pci_dereg_ioat(S390PCIIOMMU *iommu) +void pci_dereg_ioat(S390PCIBusDevice *pbdev) { - s390_pci_iommu_disable(iommu); + S390PCIIOMMU *iommu = pbdev->iommu; + s390_pci_iommu_disable(pbdev); iommu->pba = 0; iommu->pal = 0; iommu->g_iota = 0; @@ -XXX,XX +XXX,XX @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); } else { - pci_dereg_ioat(pbdev->iommu); + pci_dereg_ioat(pbdev); } break; case ZPCI_MOD_FC_REREG_IOAT: @@ -XXX,XX +XXX,XX @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); } else { - pci_dereg_ioat(pbdev->iommu); + pci_dereg_ioat(pbdev); if (reg_ioat(env, pbdev, fib, ra)) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES); diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ struct S390PCIIOMMU { S390PCIBusDevice *pbdev; AddressSpace as; MemoryRegion mr; - IOMMUMemoryRegion iommu_mr; MemoryRegion *dm_mr; bool enabled; uint64_t g_iota; @@ -XXX,XX +XXX,XX @@ struct S390PCIBusDevice { S390MsixInfo msix; AdapterRoutes routes; S390PCIIOMMU *iommu; + IOMMUMemoryRegion iommu_mr; MemoryRegion msix_notify_mr; IndAddr *summary_ind; IndAddr *indicator; @@ -XXX,XX +XXX,XX @@ int pci_chsc_sei_nt2_have_event(void); void s390_pci_sclp_configure(SCCB *sccb); void s390_pci_sclp_deconfigure(SCCB *sccb); bool s390_pci_is_translation_enabled(uint64_t g_iota); -void s390_pci_iommu_enable(S390PCIIOMMU *iommu); +void s390_pci_iommu_enable(S390PCIBusDevice *pbdev); void s390_pci_iommu_direct_map_enable(S390PCIIOMMU *iommu); -void s390_pci_iommu_disable(S390PCIIOMMU *iommu); +void s390_pci_iommu_disable(S390PCIBusDevice *pbdev); void s390_pci_generate_error_event(uint16_t pec, uint32_t fh, uint32_t fid, uint64_t faddr, uint32_t e); uint16_t s390_guest_io_table_walk(uint64_t g_iota, hwaddr addr, diff --git a/include/hw/s390x/s390-pci-inst.h b/include/hw/s390x/s390-pci-inst.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-inst.h +++ b/include/hw/s390x/s390-pci-inst.h @@ -XXX,XX +XXX,XX @@ typedef struct ZpciFib { } QEMU_PACKED ZpciFib; int pci_dereg_irqs(S390PCIBusDevice *pbdev); -void pci_dereg_ioat(S390PCIIOMMU *iommu); +void pci_dereg_ioat(S390PCIBusDevice *pbdev); int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra); int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra); int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra); @@ -XXX,XX +XXX,XX @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, uintptr_t ra); void fmb_timer_free(S390PCIBusDevice *pbdev); -uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu, S390IOTLBEntry *entry); +uint32_t s390_pci_update_iotlb(S390PCIBusDevice *pbdev, S390IOTLBEntry *entry); #define ZPCI_IO_BAR_MIN 0 #define ZPCI_IO_BAR_MAX 5 -- 2.34.1
This field is only used when S390PCIBusDevice exists, so it can be moved there to simplify S390PCIIOMMU which purpose is just to store the "root" AddressSpace. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 21 +++++++++++---------- hw/s390x/s390-pci-inst.c | 2 +- include/hw/s390x/s390-pci-bus.h | 4 ++-- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ static void s390_pci_ioat_replay(S390PCIBusDevice *pbdev) curr = iommu->pba; end = iommu->pal; - if (iommu->dm_mr) { + if (pbdev->dm_mr) { /* If direct mapping is used, there are no guest tables to replay */ return; } @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_enable(S390PCIBusDevice *pbdev) g_free(name); } -void s390_pci_iommu_direct_map_enable(S390PCIIOMMU *iommu) +void s390_pci_iommu_direct_map_enable(S390PCIBusDevice *pbdev) { + S390PCIIOMMU *iommu = pbdev->iommu; MachineState *ms = MACHINE(qdev_get_machine()); S390CcwMachineState *s390ms = S390_CCW_MACHINE(ms); @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_direct_map_enable(S390PCIIOMMU *iommu) g_autofree char *name = g_strdup_printf("iommu-dm-s390-%04x", iommu->pbdev->uid); - iommu->dm_mr = g_malloc0(sizeof(*iommu->dm_mr)); - memory_region_init_alias(iommu->dm_mr, OBJECT(&iommu->mr), name, + pbdev->dm_mr = g_malloc0(sizeof(*pbdev->dm_mr)); + memory_region_init_alias(pbdev->dm_mr, OBJECT(&iommu->mr), name, get_system_memory(), 0, s390_get_memory_limit(s390ms)); iommu->enabled = true; memory_region_add_subregion(&iommu->mr, iommu->pbdev->zpci_fn.sdma, - iommu->dm_mr); + pbdev->dm_mr); } void s390_pci_iommu_disable(S390PCIBusDevice *pbdev) @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_disable(S390PCIBusDevice *pbdev) S390PCIIOMMU *iommu = pbdev->iommu; iommu->enabled = false; g_hash_table_remove_all(iommu->iotlb); - if (iommu->dm_mr) { - memory_region_del_subregion(&iommu->mr, iommu->dm_mr); - object_unparent(OBJECT(iommu->dm_mr)); - g_free(iommu->dm_mr); - iommu->dm_mr = NULL; + if (pbdev->dm_mr) { + memory_region_del_subregion(&iommu->mr, pbdev->dm_mr); + object_unparent(OBJECT(pbdev->dm_mr)); + g_free(pbdev->dm_mr); + pbdev->dm_mr = NULL; } else { memory_region_del_subregion(&iommu->mr, MEMORY_REGION(&pbdev->iommu_mr)); diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib, if (t) { s390_pci_iommu_enable(pbdev); } else { - s390_pci_iommu_direct_map_enable(iommu); + s390_pci_iommu_direct_map_enable(pbdev); } return 0; diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ struct S390PCIIOMMU { S390PCIBusDevice *pbdev; AddressSpace as; MemoryRegion mr; - MemoryRegion *dm_mr; bool enabled; uint64_t g_iota; uint64_t pba; @@ -XXX,XX +XXX,XX @@ struct S390PCIBusDevice { AdapterRoutes routes; S390PCIIOMMU *iommu; IOMMUMemoryRegion iommu_mr; + MemoryRegion *dm_mr; MemoryRegion msix_notify_mr; IndAddr *summary_ind; IndAddr *indicator; @@ -XXX,XX +XXX,XX @@ void s390_pci_sclp_configure(SCCB *sccb); void s390_pci_sclp_deconfigure(SCCB *sccb); bool s390_pci_is_translation_enabled(uint64_t g_iota); void s390_pci_iommu_enable(S390PCIBusDevice *pbdev); -void s390_pci_iommu_direct_map_enable(S390PCIIOMMU *iommu); +void s390_pci_iommu_direct_map_enable(S390PCIBusDevice *pbdev); void s390_pci_iommu_disable(S390PCIBusDevice *pbdev); void s390_pci_generate_error_event(uint16_t pec, uint32_t fh, uint32_t fid, uint64_t faddr, uint32_t e); -- 2.34.1
This field is only used when S390PCIBusDevice exists, so it can be moved there to simplify S390PCIIOMMU which purpose is just to store the "root" AddressSpace. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 10 +++++----- hw/s390x/s390-pci-inst.c | 6 +++--- include/hw/s390x/s390-pci-bus.h | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr, goto err; } - entry = g_hash_table_lookup(iommu->iotlb, &iova); + entry = g_hash_table_lookup(pbdev->iotlb, &iova); if (entry) { ret.iova = entry->iova; ret.translated_addr = entry->translated_addr; @@ -XXX,XX +XXX,XX @@ static S390PCIIOMMU *s390_pci_get_iommu(S390pciState *s, PCIBus *bus, PCI_FUNC(devfn)); memory_region_init(&iommu->mr, OBJECT(iommu), mr_name, UINT64_MAX); address_space_init(&iommu->as, &iommu->mr, as_name); - iommu->iotlb = g_hash_table_new_full(g_int64_hash, g_int64_equal, - NULL, g_free); table->iommu[PCI_SLOT(devfn)] = iommu; g_free(mr_name); @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_disable(S390PCIBusDevice *pbdev) { S390PCIIOMMU *iommu = pbdev->iommu; iommu->enabled = false; - g_hash_table_remove_all(iommu->iotlb); + g_hash_table_remove_all(pbdev->iotlb); if (pbdev->dm_mr) { memory_region_del_subregion(&iommu->mr, pbdev->dm_mr); object_unparent(OBJECT(pbdev->dm_mr)); @@ -XXX,XX +XXX,XX @@ static void s390_pci_iommu_free(S390pciState *s, PCIBus *bus, int32_t devfn) } table->iommu[PCI_SLOT(devfn)] = NULL; - g_hash_table_destroy(iommu->iotlb); /* * An attached PCI device may have memory listeners, eg. VFIO PCI. * The associated subregion will already have been unmapped in @@ -XXX,XX +XXX,XX @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev, /* the allocated idx is actually getting used */ s->next_idx = (pbdev->idx + 1) & FH_MASK_INDEX; pbdev->fh = pbdev->idx; + pbdev->iotlb = g_hash_table_new_full(g_int64_hash, g_int64_equal, + NULL, g_free); QTAILQ_INSERT_TAIL(&s->zpci_devs, pbdev, link); g_hash_table_insert(s->zpci_table, &pbdev->idx, pbdev); } else { @@ -XXX,XX +XXX,XX @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, if (pbdev->iommu && pbdev->iommu->dma_limit) { s390_pci_end_dma_count(s, pbdev->iommu->dma_limit); } + g_hash_table_destroy(pbdev->iotlb); qdev_unrealize(dev); } } diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ uint32_t s390_pci_update_iotlb(S390PCIBusDevice *pbdev, S390IOTLBEntry *entry) { S390PCIIOMMU *iommu = pbdev->iommu; - S390IOTLBEntry *cache = g_hash_table_lookup(iommu->iotlb, &entry->iova); + S390IOTLBEntry *cache = g_hash_table_lookup(pbdev->iotlb, &entry->iova); IOMMUTLBEvent event = { .type = entry->perm ? IOMMU_NOTIFIER_MAP : IOMMU_NOTIFIER_UNMAP, .entry = { @@ -XXX,XX +XXX,XX @@ uint32_t s390_pci_update_iotlb(S390PCIBusDevice *pbdev, if (!cache) { goto out; } - g_hash_table_remove(iommu->iotlb, &entry->iova); + g_hash_table_remove(pbdev->iotlb, &entry->iova); inc_dma_avail(iommu); /* Don't notify the iommu yet, maybe we can bundle contiguous unmaps */ goto out; @@ -XXX,XX +XXX,XX @@ uint32_t s390_pci_update_iotlb(S390PCIBusDevice *pbdev, cache->translated_addr = entry->translated_addr; cache->len = TARGET_PAGE_SIZE; cache->perm = entry->perm; - g_hash_table_replace(iommu->iotlb, &cache->iova, cache); + g_hash_table_replace(pbdev->iotlb, &cache->iova, cache); dec_dma_avail(iommu); } diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ struct S390PCIIOMMU { uint64_t pba; uint64_t pal; uint64_t max_dma_limit; - GHashTable *iotlb; S390PCIDMACount *dma_limit; }; @@ -XXX,XX +XXX,XX @@ struct S390PCIBusDevice { S390PCIIOMMU *iommu; IOMMUMemoryRegion iommu_mr; MemoryRegion *dm_mr; + GHashTable *iotlb; MemoryRegion msix_notify_mr; IndAddr *summary_ind; IndAddr *indicator; -- 2.34.1
This pointer is no longer used, after fields were moved from S390PCIIOMMU to S390PCIBusDevice. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 15 +++++++-------- include/hw/s390x/s390-pci-bus.h | 1 - 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr, .perm = IOMMU_NONE, }; - switch (iommu->pbdev->state) { + switch (pbdev->state) { case ZPCI_FS_ENABLED: case ZPCI_FS_BLOCKED: if (!iommu->enabled) { @@ -XXX,XX +XXX,XX @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr, } err: if (error) { - iommu->pbdev->state = ZPCI_FS_ERROR; - s390_pci_generate_error_event(error, iommu->pbdev->fh, - iommu->pbdev->fid, addr, 0); + pbdev->state = ZPCI_FS_ERROR; + s390_pci_generate_error_event(error, pbdev->fh, + pbdev->fid, addr, 0); } return ret; } @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_enable(S390PCIBusDevice *pbdev) * so the smallest IOMMU region we can define runs from 0 to the end * of the PCI address space. */ - char *name = g_strdup_printf("iommu-s390-%04x", iommu->pbdev->uid); + char *name = g_strdup_printf("iommu-s390-%04x", pbdev->uid); memory_region_init_iommu(&pbdev->iommu_mr, sizeof(pbdev->iommu_mr), TYPE_S390_IOMMU_MEMORY_REGION, OBJECT(&iommu->mr), name, iommu->pal + 1); @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_direct_map_enable(S390PCIBusDevice *pbdev) * IOVA X + SDMA. VFIO will handle pinning via its memory listener. */ g_autofree char *name = g_strdup_printf("iommu-dm-s390-%04x", - iommu->pbdev->uid); + pbdev->uid); pbdev->dm_mr = g_malloc0(sizeof(*pbdev->dm_mr)); memory_region_init_alias(pbdev->dm_mr, OBJECT(&iommu->mr), name, get_system_memory(), 0, s390_get_memory_limit(s390ms)); iommu->enabled = true; - memory_region_add_subregion(&iommu->mr, iommu->pbdev->zpci_fn.sdma, + memory_region_add_subregion(&iommu->mr, pbdev->zpci_fn.sdma, pbdev->dm_mr); } @@ -XXX,XX +XXX,XX @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev, pbdev->pdev = pdev; pbdev->iommu = s390_pci_get_iommu(s, pci_get_bus(pdev), pdev->devfn); - pbdev->iommu->pbdev = pbdev; pbdev->state = ZPCI_FS_DISABLED; set_pbdev_info(pbdev); diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ typedef struct S390PCIDMACount { struct S390PCIIOMMU { Object parent_obj; - S390PCIBusDevice *pbdev; AddressSpace as; MemoryRegion mr; bool enabled; -- 2.34.1
This field is only used when S390PCIBusDevice exists, so it can be moved there to simplify S390PCIIOMMU which purpose is just to store the "root" AddressSpace. This also allows to save/restore this field during migration. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 14 +++++++------- hw/s390x/s390-pci-inst.c | 8 ++++---- include/hw/s390x/s390-pci-bus.h | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ void s390_pci_sclp_deconfigure(SCCB *sccb) } else if (pbdev->summary_ind) { pci_dereg_irqs(pbdev); } - if (pbdev->iommu->enabled) { + if (pbdev->iommu_enabled) { pci_dereg_ioat(pbdev); } pbdev->state = ZPCI_FS_STANDBY; @@ -XXX,XX +XXX,XX @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr, switch (pbdev->state) { case ZPCI_FS_ENABLED: case ZPCI_FS_BLOCKED: - if (!iommu->enabled) { + if (!pbdev->iommu_enabled) { return ret; } break; @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_enable(S390PCIBusDevice *pbdev) memory_region_init_iommu(&pbdev->iommu_mr, sizeof(pbdev->iommu_mr), TYPE_S390_IOMMU_MEMORY_REGION, OBJECT(&iommu->mr), name, iommu->pal + 1); - iommu->enabled = true; + pbdev->iommu_enabled = true; memory_region_add_subregion(&iommu->mr, 0, MEMORY_REGION(&pbdev->iommu_mr)); g_free(name); } @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_direct_map_enable(S390PCIBusDevice *pbdev) memory_region_init_alias(pbdev->dm_mr, OBJECT(&iommu->mr), name, get_system_memory(), 0, s390_get_memory_limit(s390ms)); - iommu->enabled = true; + pbdev->iommu_enabled = true; memory_region_add_subregion(&iommu->mr, pbdev->zpci_fn.sdma, pbdev->dm_mr); } @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_direct_map_enable(S390PCIBusDevice *pbdev) void s390_pci_iommu_disable(S390PCIBusDevice *pbdev) { S390PCIIOMMU *iommu = pbdev->iommu; - iommu->enabled = false; + pbdev->iommu_enabled = false; g_hash_table_remove_all(pbdev->iotlb); if (pbdev->dm_mr) { memory_region_del_subregion(&iommu->mr, pbdev->dm_mr); @@ -XXX,XX +XXX,XX @@ static void s390_pcihost_reset(DeviceState *dev) } else if (pbdev->summary_ind) { pci_dereg_irqs(pbdev); } - if (pbdev->iommu->enabled) { + if (pbdev->iommu_enabled) { pci_dereg_ioat(pbdev); } pbdev->state = ZPCI_FS_STANDBY; @@ -XXX,XX +XXX,XX @@ static void s390_pci_device_reset(DeviceState *dev) } else if (pbdev->summary_ind) { pci_dereg_irqs(pbdev); } - if (pbdev->iommu->enabled) { + if (pbdev->iommu_enabled) { pci_dereg_ioat(pbdev); } diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, if (dmaas != 0) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL); - } else if (pbdev->iommu->enabled) { + } else if (pbdev->iommu_enabled) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); } else if (reg_ioat(env, pbdev, fib, ra)) { @@ -XXX,XX +XXX,XX @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, if (dmaas != 0) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL); - } else if (!pbdev->iommu->enabled) { + } else if (!pbdev->iommu_enabled) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); } else { @@ -XXX,XX +XXX,XX @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, if (dmaas != 0) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL); - } else if (!pbdev->iommu->enabled) { + } else if (!pbdev->iommu_enabled) { cc = ZPCI_PCI_LS_ERR; s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE); } else { @@ -XXX,XX +XXX,XX @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, /* fallthrough */ case ZPCI_FS_ENABLED: fib.fc |= 0x80; - if (pbdev->iommu->enabled) { + if (pbdev->iommu_enabled) { fib.fc |= 0x10; } if (!(fh & FH_MASK_ENABLE)) { diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ struct S390PCIIOMMU { Object parent_obj; AddressSpace as; MemoryRegion mr; - bool enabled; uint64_t g_iota; uint64_t pba; uint64_t pal; @@ -XXX,XX +XXX,XX @@ struct S390PCIBusDevice { S390MsixInfo msix; AdapterRoutes routes; S390PCIIOMMU *iommu; + bool iommu_enabled; IOMMUMemoryRegion iommu_mr; MemoryRegion *dm_mr; GHashTable *iotlb; -- 2.34.1
This field is only used when S390PCIBusDevice exists, so it can be moved there to simplify S390PCIIOMMU which purpose is just to store the "root" AddressSpace. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 10 +++++----- hw/s390x/s390-pci-inst.c | 23 +++++++++++------------ include/hw/s390x/s390-pci-bus.h | 2 +- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ static void s390_pci_ioat_replay(S390PCIBusDevice *pbdev) return; } - if (iommu->dma_limit) { - dma_avail = iommu->dma_limit->avail; + if (pbdev->dma_limit) { + dma_avail = pbdev->dma_limit->avail; } else { dma_avail = 1; } @@ -XXX,XX +XXX,XX @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev, pbdev->forwarding_assist = false; } } - pbdev->iommu->dma_limit = s390_pci_start_dma_count(s, pbdev); + pbdev->dma_limit = s390_pci_start_dma_count(s, pbdev); /* Fill in CLP information passed via the vfio region */ s390_pci_get_clp_info(pbdev); if (!pbdev->interp) { @@ -XXX,XX +XXX,XX @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, pbdev->fid = 0; QTAILQ_REMOVE(&s->zpci_devs, pbdev, link); g_hash_table_remove(s->zpci_table, &pbdev->idx); - if (pbdev->iommu && pbdev->iommu->dma_limit) { - s390_pci_end_dma_count(s, pbdev->iommu->dma_limit); + if (pbdev->dma_limit) { + s390_pci_end_dma_count(s, pbdev->dma_limit); } g_hash_table_destroy(pbdev->iotlb); qdev_unrealize(dev); diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ #include "trace.h" -static inline void inc_dma_avail(S390PCIIOMMU *iommu) +static inline void inc_dma_avail(S390PCIBusDevice *pbdev) { - if (iommu->dma_limit) { - iommu->dma_limit->avail++; + if (pbdev->dma_limit) { + pbdev->dma_limit->avail++; } } -static inline void dec_dma_avail(S390PCIIOMMU *iommu) +static inline void dec_dma_avail(S390PCIBusDevice *pbdev) { - if (iommu->dma_limit) { - iommu->dma_limit->avail--; + if (pbdev->dma_limit) { + pbdev->dma_limit->avail--; } } @@ -XXX,XX +XXX,XX @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) uint32_t s390_pci_update_iotlb(S390PCIBusDevice *pbdev, S390IOTLBEntry *entry) { - S390PCIIOMMU *iommu = pbdev->iommu; S390IOTLBEntry *cache = g_hash_table_lookup(pbdev->iotlb, &entry->iova); IOMMUTLBEvent event = { .type = entry->perm ? IOMMU_NOTIFIER_MAP : IOMMU_NOTIFIER_UNMAP, @@ -XXX,XX +XXX,XX @@ uint32_t s390_pci_update_iotlb(S390PCIBusDevice *pbdev, goto out; } g_hash_table_remove(pbdev->iotlb, &entry->iova); - inc_dma_avail(iommu); + inc_dma_avail(pbdev); /* Don't notify the iommu yet, maybe we can bundle contiguous unmaps */ goto out; } else { @@ -XXX,XX +XXX,XX @@ uint32_t s390_pci_update_iotlb(S390PCIBusDevice *pbdev, cache->len = TARGET_PAGE_SIZE; cache->perm = entry->perm; g_hash_table_replace(pbdev->iotlb, &cache->iova, cache); - dec_dma_avail(iommu); + dec_dma_avail(pbdev); } /* @@ -XXX,XX +XXX,XX @@ uint32_t s390_pci_update_iotlb(S390PCIBusDevice *pbdev, memory_region_notify_iommu(&pbdev->iommu_mr, 0, event); out: - return iommu->dma_limit ? iommu->dma_limit->avail : 1; + return pbdev->dma_limit ? pbdev->dma_limit->avail : 1; } static void s390_pci_batch_unmap(S390PCIBusDevice *pbdev, uint64_t iova, @@ -XXX,XX +XXX,XX @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) } iommu = pbdev->iommu; - if (iommu->dma_limit) { - dma_avail = iommu->dma_limit->avail; + if (pbdev->dma_limit) { + dma_avail = pbdev->dma_limit->avail; } else { dma_avail = 1; } diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ struct S390PCIIOMMU { uint64_t pba; uint64_t pal; uint64_t max_dma_limit; - S390PCIDMACount *dma_limit; }; typedef struct S390PCIIOMMUTable { @@ -XXX,XX +XXX,XX @@ struct S390PCIBusDevice { IOMMUMemoryRegion iommu_mr; MemoryRegion *dm_mr; GHashTable *iotlb; + S390PCIDMACount *dma_limit; MemoryRegion msix_notify_mr; IndAddr *summary_ind; IndAddr *indicator; -- 2.34.1
This field is only used when S390PCIBusDevice exists, so it can be moved there to simplify S390PCIIOMMU which purpose is just to store the "root" AddressSpace. This also allows to save/restore this field during migration. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 2 +- hw/s390x/s390-pci-inst.c | 10 +++++----- include/hw/s390x/s390-pci-bus.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ static void s390_pci_ioat_replay(S390PCIBusDevice *pbdev) } while (curr < end) { - error = s390_guest_io_table_walk(iommu->g_iota, curr, &entry); + error = s390_guest_io_table_walk(pbdev->g_iota, curr, &entry); if (error) { pbdev->state = ZPCI_FS_ERROR; s390_pci_generate_error_event(error, pbdev->fh, pbdev->fid, curr, diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) } else { dma_avail = 1; } - if (!iommu->g_iota) { + if (!pbdev->g_iota) { error = ERR_EVENT_INVALAS; goto err; } @@ -XXX,XX +XXX,XX @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) start = sstart; again = false; while (start < end) { - error = s390_guest_io_table_walk(iommu->g_iota, start, &entry); + error = s390_guest_io_table_walk(pbdev->g_iota, start, &entry); if (error) { break; } @@ -XXX,XX +XXX,XX @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib, iommu->pba = pba; iommu->pal = pal; - iommu->g_iota = g_iota; + pbdev->g_iota = g_iota; if (t) { s390_pci_iommu_enable(pbdev); @@ -XXX,XX +XXX,XX @@ void pci_dereg_ioat(S390PCIBusDevice *pbdev) s390_pci_iommu_disable(pbdev); iommu->pba = 0; iommu->pal = 0; - iommu->g_iota = 0; + pbdev->g_iota = 0; } void fmb_timer_free(S390PCIBusDevice *pbdev) @@ -XXX,XX +XXX,XX @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, stq_be_p(&fib.pba, pbdev->iommu->pba); stq_be_p(&fib.pal, pbdev->iommu->pal); - stq_be_p(&fib.iota, pbdev->iommu->g_iota); + stq_be_p(&fib.iota, pbdev->g_iota); stq_be_p(&fib.aibv, pbdev->routes.adapter.ind_addr); stq_be_p(&fib.aisb, pbdev->routes.adapter.summary_addr); stq_be_p(&fib.fmb_addr, pbdev->fmb_addr); diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ struct S390PCIIOMMU { Object parent_obj; AddressSpace as; MemoryRegion mr; - uint64_t g_iota; uint64_t pba; uint64_t pal; uint64_t max_dma_limit; @@ -XXX,XX +XXX,XX @@ struct S390PCIBusDevice { IOMMUMemoryRegion iommu_mr; MemoryRegion *dm_mr; GHashTable *iotlb; + uint64_t g_iota; S390PCIDMACount *dma_limit; MemoryRegion msix_notify_mr; IndAddr *summary_ind; -- 2.34.1
This field is only used when S390PCIBusDevice exists, so it can be moved there to simplify S390PCIIOMMU which purpose is just to store the "root" AddressSpace. This also allows to save/restore this field during migration. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 4 ++-- hw/s390x/s390-pci-inst.c | 8 ++++---- include/hw/s390x/s390-pci-bus.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr, trace_s390_pci_iommu_xlate(addr); - if (addr < iommu->pba || addr > iommu->pal) { + if (addr < pbdev->pba || addr > iommu->pal) { error = ERR_EVENT_OORANGE; goto err; } @@ -XXX,XX +XXX,XX @@ static void s390_pci_ioat_replay(S390PCIBusDevice *pbdev) hwaddr curr, end; S390PCIIOMMU *iommu = pbdev->iommu; - curr = iommu->pba; + curr = pbdev->pba; end = iommu->pal; if (pbdev->dm_mr) { diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) goto err; } - if (end < iommu->pba || start > iommu->pal) { + if (end < pbdev->pba || start > iommu->pal) { error = ERR_EVENT_OORANGE; goto err; } @@ -XXX,XX +XXX,XX @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib, return -EINVAL; } - iommu->pba = pba; + pbdev->pba = pba; iommu->pal = pal; pbdev->g_iota = g_iota; @@ -XXX,XX +XXX,XX @@ void pci_dereg_ioat(S390PCIBusDevice *pbdev) { S390PCIIOMMU *iommu = pbdev->iommu; s390_pci_iommu_disable(pbdev); - iommu->pba = 0; + pbdev->pba = 0; iommu->pal = 0; pbdev->g_iota = 0; } @@ -XXX,XX +XXX,XX @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, return 0; } - stq_be_p(&fib.pba, pbdev->iommu->pba); + stq_be_p(&fib.pba, pbdev->pba); stq_be_p(&fib.pal, pbdev->iommu->pal); stq_be_p(&fib.iota, pbdev->g_iota); stq_be_p(&fib.aibv, pbdev->routes.adapter.ind_addr); diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ struct S390PCIIOMMU { Object parent_obj; AddressSpace as; MemoryRegion mr; - uint64_t pba; uint64_t pal; uint64_t max_dma_limit; }; @@ -XXX,XX +XXX,XX @@ struct S390PCIBusDevice { MemoryRegion *dm_mr; GHashTable *iotlb; uint64_t g_iota; + uint64_t pba; S390PCIDMACount *dma_limit; MemoryRegion msix_notify_mr; IndAddr *summary_ind; -- 2.34.1
This field is only used when S390PCIBusDevice exists, so it can be moved there to simplify S390PCIIOMMU which purpose is just to store the "root" AddressSpace. This also allows to save/restore this field during migration. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 8 +++----- hw/s390x/s390-pci-inst.c | 12 ++++-------- include/hw/s390x/s390-pci-bus.h | 2 +- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr, IOMMUAccessFlags flag, int iommu_idx) { S390PCIBusDevice *pbdev = container_of(mr, S390PCIBusDevice, iommu_mr); - S390PCIIOMMU *iommu = pbdev->iommu; S390IOTLBEntry *entry; uint64_t iova = addr & TARGET_PAGE_MASK; uint16_t error = 0; @@ -XXX,XX +XXX,XX @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr, trace_s390_pci_iommu_xlate(addr); - if (addr < pbdev->pba || addr > iommu->pal) { + if (addr < pbdev->pba || addr > pbdev->pal) { error = ERR_EVENT_OORANGE; goto err; } @@ -XXX,XX +XXX,XX @@ static void s390_pci_ioat_replay(S390PCIBusDevice *pbdev) uint16_t error = 0; uint32_t dma_avail; hwaddr curr, end; - S390PCIIOMMU *iommu = pbdev->iommu; curr = pbdev->pba; - end = iommu->pal; + end = pbdev->pal; if (pbdev->dm_mr) { /* If direct mapping is used, there are no guest tables to replay */ @@ -XXX,XX +XXX,XX @@ void s390_pci_iommu_enable(S390PCIBusDevice *pbdev) char *name = g_strdup_printf("iommu-s390-%04x", pbdev->uid); memory_region_init_iommu(&pbdev->iommu_mr, sizeof(pbdev->iommu_mr), TYPE_S390_IOMMU_MEMORY_REGION, OBJECT(&iommu->mr), - name, iommu->pal + 1); + name, pbdev->pal + 1); pbdev->iommu_enabled = true; memory_region_add_subregion(&iommu->mr, 0, MEMORY_REGION(&pbdev->iommu_mr)); g_free(name); diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) uint32_t fh; uint16_t error = 0; S390PCIBusDevice *pbdev; - S390PCIIOMMU *iommu; S390IOTLBEntry entry; hwaddr start, end, sstart; uint32_t dma_avail; @@ -XXX,XX +XXX,XX @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) break; } - iommu = pbdev->iommu; if (pbdev->dma_limit) { dma_avail = pbdev->dma_limit->avail; } else { @@ -XXX,XX +XXX,XX @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra) goto err; } - if (end < pbdev->pba || start > iommu->pal) { + if (end < pbdev->pba || start > pbdev->pal) { error = ERR_EVENT_OORANGE; goto err; } @@ -XXX,XX +XXX,XX @@ bool s390_pci_is_translation_enabled(uint64_t g_iota) static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib, uintptr_t ra) { - S390PCIIOMMU *iommu = pbdev->iommu; uint64_t pba = ldq_be_p(&fib.pba); uint64_t pal = ldq_be_p(&fib.pal); uint64_t g_iota = ldq_be_p(&fib.iota); @@ -XXX,XX +XXX,XX @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib, } pbdev->pba = pba; - iommu->pal = pal; + pbdev->pal = pal; pbdev->g_iota = g_iota; if (t) { @@ -XXX,XX +XXX,XX @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib, void pci_dereg_ioat(S390PCIBusDevice *pbdev) { - S390PCIIOMMU *iommu = pbdev->iommu; s390_pci_iommu_disable(pbdev); pbdev->pba = 0; - iommu->pal = 0; + pbdev->pal = 0; pbdev->g_iota = 0; } @@ -XXX,XX +XXX,XX @@ int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, } stq_be_p(&fib.pba, pbdev->pba); - stq_be_p(&fib.pal, pbdev->iommu->pal); + stq_be_p(&fib.pal, pbdev->pal); stq_be_p(&fib.iota, pbdev->g_iota); stq_be_p(&fib.aibv, pbdev->routes.adapter.ind_addr); stq_be_p(&fib.aisb, pbdev->routes.adapter.summary_addr); diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ struct S390PCIIOMMU { Object parent_obj; AddressSpace as; MemoryRegion mr; - uint64_t pal; uint64_t max_dma_limit; }; @@ -XXX,XX +XXX,XX @@ struct S390PCIBusDevice { GHashTable *iotlb; uint64_t g_iota; uint64_t pba; + uint64_t pal; S390PCIDMACount *dma_limit; MemoryRegion msix_notify_mr; IndAddr *summary_ind; -- 2.34.1
This field is only used when S390PCIBusDevice exists, so it can be moved there to simplify S390PCIIOMMU which purpose is just to store the "root" AddressSpace. This also allows to save/restore this field during migration. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-vfio.c | 4 ++-- include/hw/s390x/s390-pci-bus.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/s390x/s390-pci-vfio.c b/hw/s390x/s390-pci-vfio.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-vfio.c +++ b/hw/s390x/s390-pci-vfio.c @@ -XXX,XX +XXX,XX @@ S390PCIDMACount *s390_pci_start_dma_count(S390pciState *s, cnt->users = 1; cnt->avail = avail; QTAILQ_INSERT_TAIL(&s->zpci_dma_limit, cnt, link); - pbdev->iommu->max_dma_limit = avail; + pbdev->max_dma_limit = avail; return cnt; } @@ -XXX,XX +XXX,XX @@ static void s390_pci_read_base(S390PCIBusDevice *pbdev, * to request that the guest free DMA mappings as necessary. */ if (!pbdev->rtr_avail) { - vfio_size = pbdev->iommu->max_dma_limit << qemu_target_page_bits(); + vfio_size = pbdev->max_dma_limit << qemu_target_page_bits(); if (vfio_size > 0 && vfio_size < cap->end_dma - cap->start_dma + 1) { pbdev->zpci_fn.edma = cap->start_dma + vfio_size - 1; } diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ struct S390PCIIOMMU { Object parent_obj; AddressSpace as; MemoryRegion mr; - uint64_t max_dma_limit; }; typedef struct S390PCIIOMMUTable { @@ -XXX,XX +XXX,XX @@ struct S390PCIBusDevice { uint64_t g_iota; uint64_t pba; uint64_t pal; + uint64_t max_dma_limit; S390PCIDMACount *dma_limit; MemoryRegion msix_notify_mr; IndAddr *summary_ind; -- 2.34.1
Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- include/hw/s390x/s390-pci-bus.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ typedef struct S390PCIDMACount { QTAILQ_ENTRY(S390PCIDMACount) link; } S390PCIDMACount; +/* + * This structure holds the PCI device AddressSpace that QEMU needs to link + * into its internal structures before the zPCI and PCI devices are fully + * initialized. It's a QEMU requirement to provide this "root" AddressSpace + * early. The AddressSpace is only actually used for I/O while the PCI + * device is plugged in and configured by the guest, at which time it gets + * additional memory subregions from zPCI device, that can do real work. + */ struct S390PCIIOMMU { Object parent_obj; AddressSpace as; -- 2.34.1
Implement zPCI device state migration, consequently enabling migration of VMs that have emulated PCI devices, whether virtio or not. Migration is allowed for devices whose function handle has the FH_SHM_EMUL bit set. For these devices QEMU will save and restore the state of its zPCI emulator. This will enable emulated PCI migration starting with s390-ccw-virtio-11.1. Passthrough devices will continue to block migration. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 187 +++++++++++++++++++++++++++++++- hw/s390x/s390-pci-inst.c | 2 +- hw/s390x/s390-virtio-ccw.c | 5 + include/hw/s390x/s390-pci-bus.h | 4 + 4 files changed, 192 insertions(+), 6 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ #include "hw/pci/pci_bridge.h" #include "hw/pci/msi.h" #include "exec/cpu-common.h" +#include "migration/blocker.h" #include "qemu/error-report.h" #include "qemu/module.h" #include "system/reset.h" @@ -XXX,XX +XXX,XX @@ #include "trace.h" +static const Property phb_props[] = { + DEFINE_PROP_BOOL("x-zpci-emul-dev-migr-enabled", S390pciState, + emul_dev_migr_enabled, true), +}; + S390pciState *s390_get_phb(void) { static S390pciState *phb; @@ -XXX,XX +XXX,XX @@ static void set_pbdev_info(S390PCIBusDevice *pbdev) pbdev->pci_group = s390_group_find(ZPCI_DEFAULT_FN_GRP); } +static int s390_set_emul_dev_migration_blocker(S390pciState *s, Error **errp) +{ + if (s->emul_dev_migr_enabled) { + return 0; + } + error_setg(&s->emul_dev_migr_blocker, + "Migration disabled for emulated zPCI devices on this machine type"); + return migrate_add_blocker(&s->emul_dev_migr_blocker, errp); +} + +static void s390_clear_emul_dev_migration_blocker(S390pciState *s) +{ + if (s->emul_dev_migr_blocker) { + migrate_del_blocker(&s->emul_dev_migr_blocker); + } +} + static void s390_pcihost_realize(DeviceState *dev, Error **errp) { PCIBus *b; @@ -XXX,XX +XXX,XX @@ static void s390_pcihost_realize(DeviceState *dev, Error **errp) css_register_io_adapters(CSS_IO_ADAPTER_PCI, true, false, S390_ADAPTER_SUPPRESSIBLE, errp); s390_pcihost_kvm_realize(); + s390_set_emul_dev_migration_blocker(s, errp); } static void s390_pcihost_unrealize(DeviceState *dev) @@ -XXX,XX +XXX,XX @@ static void s390_pcihost_unrealize(DeviceState *dev) S390PCIGroup *group; S390pciState *s = S390_PCI_HOST_BRIDGE(dev); + s390_clear_emul_dev_migration_blocker(s); + while (!QTAILQ_EMPTY(&s->zpci_groups)) { group = QTAILQ_FIRST(&s->zpci_groups); QTAILQ_REMOVE(&s->zpci_groups, group, link); @@ -XXX,XX +XXX,XX @@ static int s390_pci_interp_plug(S390pciState *s, S390PCIBusDevice *pbdev) return 0; } +static int s390_set_passthrough_migration_blocker(S390PCIBusDevice *pbdev, + Error **errp) +{ + pbdev->passthrough_migr_blocker = NULL; + + if (pbdev->fh & FH_SHM_EMUL) { + return 0; + } + error_setg(&pbdev->passthrough_migr_blocker, + "Migration blocked by passthrough zPCI device " + "fh 0x%x uid %d fid %d", pbdev->fh, pbdev->uid, pbdev->fid); + return migrate_add_blocker(&pbdev->passthrough_migr_blocker, errp); +} + +static void s390_clear_passthrough_migration_blocker(S390PCIBusDevice *pbdev) +{ + if (pbdev->passthrough_migr_blocker) { + migrate_del_blocker(&pbdev->passthrough_migr_blocker); + } +} + static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { @@ -XXX,XX +XXX,XX @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev, return; } + if (s390_set_passthrough_migration_blocker(pbdev, errp)) { + s390_pci_msix_free(pbdev); + return; + } + if (dev->hotplugged) { s390_pci_generate_plug_event(HP_EVENT_TO_CONFIGURED , pbdev->fh, pbdev->fid); @@ -XXX,XX +XXX,XX @@ static void s390_pcihost_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, return; } + s390_clear_passthrough_migration_blocker(pbdev); + s390_pci_generate_plug_event(HP_EVENT_STANDBY_TO_RESERVED, pbdev->fh, pbdev->fid); bus = pci_get_bus(pci_dev); @@ -XXX,XX +XXX,XX @@ static void s390_pcihost_class_init(ObjectClass *klass, const void *data) hc->unplug_request = s390_pcihost_unplug_request; hc->unplug = s390_pcihost_unplug; msi_nonbroken = true; + device_class_set_props(dc, phb_props); } static const TypeInfo s390_pcihost_info = { @@ -XXX,XX +XXX,XX @@ static const TypeInfo s390_pcihost_info = { } }; +/* Return a unique bus "path" for zpci device */ +static char *s390_pci_bus_get_dev_path(DeviceState *dev) +{ + S390PCIBusDevice *pbdev = S390_PCI_DEVICE(dev); + return g_strdup_printf("uid-%04x", pbdev->uid); +} + +static void s390_pcibus_class_init(ObjectClass *oc, const void *data) +{ + BusClass *bc = BUS_CLASS(oc); + bc->get_dev_path = s390_pci_bus_get_dev_path; +} + static const TypeInfo s390_pcibus_info = { .name = TYPE_S390_PCI_BUS, .parent = TYPE_BUS, .instance_size = sizeof(S390PCIBus), + /* + * Implement get_dev_path() to provide each zpci device with a unique + * stable UID-based bus "path". The "path" is used as part of idstr in the + ^ migration stream, making idstr unique and instance_id always 0. + * For migration to succeed, (idstr+instance_id) must match those generated + * during QEMU start. Without unique idstr, QEMU will generate variable + * instance_id to distinquish devices, and that instance_id can change + * if a device is unplugged and plugged back, preventing migration. + */ + .class_init = s390_pcibus_class_init, }; static uint16_t s390_pci_generate_uid(S390pciState *s) @@ -XXX,XX +XXX,XX @@ static const Property s390_pci_device_properties[] = { true), }; -static const VMStateDescription s390_pci_device_vmstate = { - .name = TYPE_S390_PCI_DEVICE, +static int s390_pci_device_pre_load(void *opaque) +{ + S390PCIBusDevice *pbdev = S390_PCI_DEVICE(opaque); + S390PCIBusDevice *found_pbdev; + + /* + * Make sure pbdev is removed from the table before state load. The change + * of pbdev->idx means it needs to be moved to a different position anyway, + * and is illegal while in the table. But be careful to not remove + * instead another pbdev whose state might have been loaded earlier and + * that has then replaced our pbdev. (post_load() will put our pbdev back.) + */ + found_pbdev = g_hash_table_lookup(s390_get_phb()->zpci_table, &pbdev->idx); + assert(found_pbdev); + if (found_pbdev == pbdev) { + g_hash_table_remove(s390_get_phb()->zpci_table, &pbdev->idx); + } + + return 0; +} + +static int s390_pci_device_post_load(void *opaque, int version_id) +{ + S390PCIBusDevice *pbdev = S390_PCI_DEVICE(opaque); + /* - * TODO: add state handling here, so migration works at least with - * emulated pci devices on s390x + * Now that pbdev->idx has been loaded, use it to place pbdev back into + * the table. This may replace a different not-yet-state-loaded pbdev, + * but pre_load() handles this case. */ - .unmigratable = 1, + g_hash_table_replace(s390_get_phb()->zpci_table, &pbdev->idx, pbdev); + + /* + * Regenerate IOMMU state, including IOTLB contents and QEMU memory regions. + */ + if (pbdev->iommu_enabled) { + assert(pbdev->iommu); + if (s390_pci_is_translation_enabled(pbdev->g_iota)) { + s390_pci_iommu_enable(pbdev); + s390_pci_ioat_replay(pbdev); + } else { + s390_pci_iommu_direct_map_enable(pbdev); + } + } + + /* + * Guest sets fmb_addr by mpcifc.ZPCI_MOD_FC_SET_MEASURE instruction, + * whose handler consequently starts fmb_timer. We may need to restart it. + */ + if (pbdev->fmb_addr) { + assert(!pbdev->fmb_timer); + assert(pbdev->pci_group); + pbdev->fmb_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, + fmb_update, pbdev); + timer_mod(pbdev->fmb_timer, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + + pbdev->pci_group->zpci_group.mui); + } + return 0; +} + +static const VMStateDescription s390_pci_device_vmstate = { + .name = TYPE_S390_PCI_DEVICE, + .version_id = 1, + .minimum_version_id = 1, + .pre_load = s390_pci_device_pre_load, + .post_load = s390_pci_device_post_load, + .fields = (const VMStateField[]) { + VMSTATE_UINT32(state, S390PCIBusDevice), + VMSTATE_UINT16(uid, S390PCIBusDevice), + VMSTATE_UINT32(idx, S390PCIBusDevice), + VMSTATE_UINT32(fh, S390PCIBusDevice), + VMSTATE_UINT32(fid, S390PCIBusDevice), + VMSTATE_BOOL(fid_defined, S390PCIBusDevice), + VMSTATE_UINT64(fmb_addr, S390PCIBusDevice), + VMSTATE_UINT32(fmb.format, S390PCIBusDevice), + VMSTATE_UINT32(fmb.sample, S390PCIBusDevice), + VMSTATE_UINT64(fmb.last_update, S390PCIBusDevice), + VMSTATE_UINT64_ARRAY(fmb.counter, S390PCIBusDevice, + ARRAY_SIZE(((S390PCIBusDevice *)0)->fmb.counter)), + VMSTATE_UINT64(fmb.fmt0.dma_rbytes, S390PCIBusDevice), + VMSTATE_UINT64(fmb.fmt0.dma_wbytes, S390PCIBusDevice), + VMSTATE_UINT8(isc, S390PCIBusDevice), + VMSTATE_UINT16(noi, S390PCIBusDevice), + VMSTATE_UINT8(sum, S390PCIBusDevice), + VMSTATE_UINT8(pft, S390PCIBusDevice), + VMSTATE_UINT64(routes.adapter.ind_addr, S390PCIBusDevice), + VMSTATE_UINT64(routes.adapter.summary_addr, S390PCIBusDevice), + VMSTATE_UINT64(routes.adapter.ind_offset, S390PCIBusDevice), + VMSTATE_UINT32(routes.adapter.summary_offset, S390PCIBusDevice), + VMSTATE_UINT32(routes.adapter.adapter_id, S390PCIBusDevice), + VMSTATE_BOOL(iommu_enabled, S390PCIBusDevice), + VMSTATE_UINT64(g_iota, S390PCIBusDevice), + VMSTATE_UINT64(pba, S390PCIBusDevice), + VMSTATE_UINT64(pal, S390PCIBusDevice), + VMSTATE_UINT64(max_dma_limit, S390PCIBusDevice), + VMSTATE_PTR_TO_IND_ADDR(summary_ind, S390PCIBusDevice), + VMSTATE_PTR_TO_IND_ADDR(indicator, S390PCIBusDevice), + VMSTATE_BOOL(pci_unplug_request_processed, S390PCIBusDevice), + VMSTATE_BOOL(unplug_requested, S390PCIBusDevice), + VMSTATE_BOOL(interp, S390PCIBusDevice), + VMSTATE_BOOL(forwarding_assist, S390PCIBusDevice), + VMSTATE_BOOL(aif, S390PCIBusDevice), + VMSTATE_BOOL(rtr_avail, S390PCIBusDevice), + VMSTATE_END_OF_LIST() + } }; static void s390_pci_device_class_init(ObjectClass *klass, const void *data) diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ static int fmb_do_update(S390PCIBusDevice *pbdev, int offset, uint64_t val, return ret; } -static void fmb_update(void *opaque) +void fmb_update(void *opaque) { S390PCIBusDevice *pbdev = opaque; int64_t t = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -XXX,XX +XXX,XX @@ static void ccw_machine_11_0_instance_options(MachineState *machine) static void ccw_machine_11_0_class_options(MachineClass *mc) { + static GlobalProperty compat[] = { + { TYPE_S390_PCI_HOST_BRIDGE, "x-zpci-emul-dev-migr-enabled", "off" }, + }; + ccw_machine_11_1_class_options(mc); compat_props_add(mc->compat_props, hw_compat_11_0, hw_compat_11_0_len); + compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); } DEFINE_CCW_MACHINE(11, 0); diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ struct S390PCIBusDevice { uint16_t uid; uint32_t idx; uint32_t fh; + Error *passthrough_migr_blocker; uint32_t fid; bool fid_defined; uint64_t fmb_addr; @@ -XXX,XX +XXX,XX @@ struct S390pciState { QTAILQ_HEAD(, S390PCIDMACount) zpci_dma_limit; QTAILQ_HEAD(, S390PCIGroup) zpci_groups; uint8_t next_sim_grp; + bool emul_dev_migr_enabled; + Error *emul_dev_migr_blocker; }; S390pciState *s390_get_phb(void); @@ -XXX,XX +XXX,XX @@ S390PCIBusDevice *s390_pci_find_dev_by_pci(S390pciState *s, S390PCIBusDevice *s390_pci_find_next_avail_dev(S390pciState *s, S390PCIBusDevice *pbdev); void s390_pci_ism_reset(void); +void fmb_update(void *opaque); #endif -- 2.34.1
fmb_timer is now started in 3 different places. The new function will encapsulate that to make sure mui is added in all cases. Signed-off-by: Konstantin Shkolnyy <kshk@linux.ibm.com> --- hw/s390x/s390-pci-bus.c | 5 ++--- hw/s390x/s390-pci-inst.c | 14 ++++++++++---- include/hw/s390x/s390-pci-bus.h | 1 + 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -XXX,XX +XXX,XX @@ static int s390_pci_device_post_load(void *opaque, int version_id) assert(pbdev->pci_group); pbdev->fmb_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, fmb_update, pbdev); - timer_mod(pbdev->fmb_timer, - qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + - pbdev->pci_group->zpci_group.mui); + s390_pci_schedule_fmb_timer(pbdev, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)); } return 0; } diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index XXXXXXX..XXXXXXX 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -XXX,XX +XXX,XX @@ static int fmb_do_update(S390PCIBusDevice *pbdev, int offset, uint64_t val, return ret; } +void s390_pci_schedule_fmb_timer(S390PCIBusDevice *pbdev, uint64_t start) +{ + timer_mod(pbdev->fmb_timer, start + pbdev->pci_group->zpci_group.mui); +} + void fmb_update(void *opaque) { S390PCIBusDevice *pbdev = opaque; + + /* Must be read before updating U bit */ int64_t t = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); int i; @@ -XXX,XX +XXX,XX @@ void fmb_update(void *opaque) sizeof(pbdev->fmb.last_update))) { return; } - timer_mod(pbdev->fmb_timer, t + pbdev->pci_group->zpci_group.mui); + s390_pci_schedule_fmb_timer(pbdev, t); } static int mpcifc_reg_int_interp(S390PCIBusDevice *pbdev, ZpciFib *fib) @@ -XXX,XX +XXX,XX @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar, timer_del(pbdev->fmb_timer); } pbdev->fmb_addr = fmb_addr; - timer_mod(pbdev->fmb_timer, - qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + - pbdev->pci_group->zpci_group.mui); + s390_pci_schedule_fmb_timer(pbdev, + qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)); break; } default: diff --git a/include/hw/s390x/s390-pci-bus.h b/include/hw/s390x/s390-pci-bus.h index XXXXXXX..XXXXXXX 100644 --- a/include/hw/s390x/s390-pci-bus.h +++ b/include/hw/s390x/s390-pci-bus.h @@ -XXX,XX +XXX,XX @@ S390PCIBusDevice *s390_pci_find_next_avail_dev(S390pciState *s, S390PCIBusDevice *pbdev); void s390_pci_ism_reset(void); void fmb_update(void *opaque); +void s390_pci_schedule_fmb_timer(S390PCIBusDevice *pbdev, uint64_t start); #endif -- 2.34.1