The source guest could have reallocated the default TCE table and migrate bigger/smaller table. This adds reallocation in post_load() if the default table size is different on source and destination.
Signed-off-by: Alexey Kardashevskiy <[email protected]> --- Changes: v14: * new to the series --- hw/ppc/spapr_iommu.c | 36 ++++++++++++++++++++++++++++++++++-- include/hw/ppc/spapr.h | 2 ++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index 9bcd3f6..549cd94 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -137,6 +137,16 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr, return ret; } +static void spapr_tce_table_pre_save(void *opaque) +{ + sPAPRTCETable *tcet = SPAPR_TCE_TABLE(opaque); + + tcet->mig_table = tcet->table; +} + +static void spapr_tce_table_do_enable(sPAPRTCETable *tcet); +static void spapr_tce_table_do_disable(sPAPRTCETable *tcet); + static int spapr_tce_table_post_load(void *opaque, int version_id) { sPAPRTCETable *tcet = SPAPR_TCE_TABLE(opaque); @@ -145,6 +155,26 @@ static int spapr_tce_table_post_load(void *opaque, int version_id) spapr_vio_set_bypass(tcet->vdev, tcet->bypass); } + if (tcet->enabled) { + if (tcet->nb_table != tcet->mig_nb_table) { + if (tcet->nb_table) { + spapr_tce_table_do_disable(tcet); + } + tcet->nb_table = tcet->mig_nb_table; + spapr_tce_table_do_enable(tcet); + } + + memcpy(tcet->table, tcet->mig_table, + tcet->nb_table * sizeof(tcet->table[0])); + + free(tcet->mig_table); + tcet->mig_table = NULL; + + } else if (tcet->table) { + /* Destination guest has a default table but source does not -> free */ + spapr_tce_table_do_disable(tcet); + } + return 0; } @@ -152,15 +182,17 @@ static const VMStateDescription vmstate_spapr_tce_table = { .name = "spapr_iommu", .version_id = 2, .minimum_version_id = 2, + .pre_save = spapr_tce_table_pre_save, .post_load = spapr_tce_table_post_load, .fields = (VMStateField []) { /* Sanity check */ VMSTATE_UINT32_EQUAL(liobn, sPAPRTCETable), - VMSTATE_UINT32_EQUAL(nb_table, sPAPRTCETable), /* IOMMU state */ + VMSTATE_UINT32(mig_nb_table, sPAPRTCETable), VMSTATE_BOOL(bypass, sPAPRTCETable), - VMSTATE_VARRAY_UINT32(table, sPAPRTCETable, nb_table, 0, vmstate_info_uint64, uint64_t), + VMSTATE_VARRAY_UINT32_ALLOC(mig_table, sPAPRTCETable, nb_table, 0, + vmstate_info_uint64, uint64_t), VMSTATE_END_OF_LIST() }, diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 75b0b55..c1ea49c 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -545,6 +545,8 @@ struct sPAPRTCETable { uint64_t bus_offset; uint32_t page_shift; uint64_t *table; + uint32_t mig_nb_table; + uint64_t *mig_table; bool bypass; bool need_vfio; int fd; -- 2.5.0.rc3
