106c6a658SSteve Sistare /* 206c6a658SSteve Sistare * Copyright (c) 2024-2025 Oracle and/or its affiliates. 306c6a658SSteve Sistare * 406c6a658SSteve Sistare * SPDX-License-Identifier: GPL-2.0-or-later 506c6a658SSteve Sistare */ 606c6a658SSteve Sistare 706c6a658SSteve Sistare #include "qemu/osdep.h" 806c6a658SSteve Sistare #include "qapi/error.h" 906c6a658SSteve Sistare #include "hw/vfio/vfio-cpr.h" 10*f2f3e466SSteve Sistare #include "hw/vfio/vfio-device.h" 1106c6a658SSteve Sistare #include "migration/blocker.h" 1206c6a658SSteve Sistare #include "migration/cpr.h" 1306c6a658SSteve Sistare #include "migration/migration.h" 1406c6a658SSteve Sistare #include "migration/vmstate.h" 1506c6a658SSteve Sistare #include "system/iommufd.h" 1606c6a658SSteve Sistare #include "vfio-iommufd.h" 17*f2f3e466SSteve Sistare #include "trace.h" 1806c6a658SSteve Sistare 19*f2f3e466SSteve Sistare typedef struct CprVFIODevice { 20*f2f3e466SSteve Sistare char *name; 21*f2f3e466SSteve Sistare unsigned int namelen; 22*f2f3e466SSteve Sistare uint32_t ioas_id; 23*f2f3e466SSteve Sistare int devid; 24*f2f3e466SSteve Sistare uint32_t hwpt_id; 25*f2f3e466SSteve Sistare QLIST_ENTRY(CprVFIODevice) next; 26*f2f3e466SSteve Sistare } CprVFIODevice; 27*f2f3e466SSteve Sistare 28*f2f3e466SSteve Sistare static const VMStateDescription vmstate_cpr_vfio_device = { 29*f2f3e466SSteve Sistare .name = "cpr vfio device", 30*f2f3e466SSteve Sistare .version_id = 1, 31*f2f3e466SSteve Sistare .minimum_version_id = 1, 32*f2f3e466SSteve Sistare .fields = (VMStateField[]) { 33*f2f3e466SSteve Sistare VMSTATE_UINT32(namelen, CprVFIODevice), 34*f2f3e466SSteve Sistare VMSTATE_VBUFFER_ALLOC_UINT32(name, CprVFIODevice, 0, NULL, namelen), 35*f2f3e466SSteve Sistare VMSTATE_INT32(devid, CprVFIODevice), 36*f2f3e466SSteve Sistare VMSTATE_UINT32(ioas_id, CprVFIODevice), 37*f2f3e466SSteve Sistare VMSTATE_UINT32(hwpt_id, CprVFIODevice), 38*f2f3e466SSteve Sistare VMSTATE_END_OF_LIST() 39*f2f3e466SSteve Sistare } 40*f2f3e466SSteve Sistare }; 41*f2f3e466SSteve Sistare 42*f2f3e466SSteve Sistare const VMStateDescription vmstate_cpr_vfio_devices = { 43*f2f3e466SSteve Sistare .name = CPR_STATE "/vfio devices", 44*f2f3e466SSteve Sistare .version_id = 1, 45*f2f3e466SSteve Sistare .minimum_version_id = 1, 46*f2f3e466SSteve Sistare .fields = (const VMStateField[]){ 47*f2f3e466SSteve Sistare VMSTATE_QLIST_V(vfio_devices, CprState, 1, vmstate_cpr_vfio_device, 48*f2f3e466SSteve Sistare CprVFIODevice, next), 49*f2f3e466SSteve Sistare VMSTATE_END_OF_LIST() 50*f2f3e466SSteve Sistare } 51*f2f3e466SSteve Sistare }; 52*f2f3e466SSteve Sistare 53*f2f3e466SSteve Sistare static void vfio_cpr_save_device(VFIODevice *vbasedev) 54*f2f3e466SSteve Sistare { 55*f2f3e466SSteve Sistare CprVFIODevice *elem = g_new0(CprVFIODevice, 1); 56*f2f3e466SSteve Sistare 57*f2f3e466SSteve Sistare elem->name = g_strdup(vbasedev->name); 58*f2f3e466SSteve Sistare elem->namelen = strlen(vbasedev->name) + 1; 59*f2f3e466SSteve Sistare elem->ioas_id = vbasedev->cpr.ioas_id; 60*f2f3e466SSteve Sistare elem->devid = vbasedev->devid; 61*f2f3e466SSteve Sistare elem->hwpt_id = vbasedev->cpr.hwpt_id; 62*f2f3e466SSteve Sistare QLIST_INSERT_HEAD(&cpr_state.vfio_devices, elem, next); 63*f2f3e466SSteve Sistare } 64*f2f3e466SSteve Sistare 65*f2f3e466SSteve Sistare static CprVFIODevice *find_device(const char *name) 66*f2f3e466SSteve Sistare { 67*f2f3e466SSteve Sistare CprVFIODeviceList *head = &cpr_state.vfio_devices; 68*f2f3e466SSteve Sistare CprVFIODevice *elem; 69*f2f3e466SSteve Sistare 70*f2f3e466SSteve Sistare QLIST_FOREACH(elem, head, next) { 71*f2f3e466SSteve Sistare if (!strcmp(elem->name, name)) { 72*f2f3e466SSteve Sistare return elem; 73*f2f3e466SSteve Sistare } 74*f2f3e466SSteve Sistare } 75*f2f3e466SSteve Sistare return NULL; 76*f2f3e466SSteve Sistare } 77*f2f3e466SSteve Sistare 78*f2f3e466SSteve Sistare static void vfio_cpr_delete_device(const char *name) 79*f2f3e466SSteve Sistare { 80*f2f3e466SSteve Sistare CprVFIODevice *elem = find_device(name); 81*f2f3e466SSteve Sistare 82*f2f3e466SSteve Sistare if (elem) { 83*f2f3e466SSteve Sistare QLIST_REMOVE(elem, next); 84*f2f3e466SSteve Sistare g_free(elem->name); 85*f2f3e466SSteve Sistare g_free(elem); 86*f2f3e466SSteve Sistare } 87*f2f3e466SSteve Sistare } 88*f2f3e466SSteve Sistare 89*f2f3e466SSteve Sistare static bool vfio_cpr_find_device(VFIODevice *vbasedev) 90*f2f3e466SSteve Sistare { 91*f2f3e466SSteve Sistare CprVFIODevice *elem = find_device(vbasedev->name); 92*f2f3e466SSteve Sistare 93*f2f3e466SSteve Sistare if (elem) { 94*f2f3e466SSteve Sistare vbasedev->cpr.ioas_id = elem->ioas_id; 95*f2f3e466SSteve Sistare vbasedev->devid = elem->devid; 96*f2f3e466SSteve Sistare vbasedev->cpr.hwpt_id = elem->hwpt_id; 97*f2f3e466SSteve Sistare trace_vfio_cpr_find_device(elem->ioas_id, elem->devid, elem->hwpt_id); 98*f2f3e466SSteve Sistare return true; 99*f2f3e466SSteve Sistare } 100*f2f3e466SSteve Sistare return false; 101*f2f3e466SSteve Sistare } 102a6f2f9c4SSteve Sistare 10306c6a658SSteve Sistare static bool vfio_cpr_supported(IOMMUFDBackend *be, Error **errp) 10406c6a658SSteve Sistare { 10506c6a658SSteve Sistare if (!iommufd_change_process_capable(be)) { 10606c6a658SSteve Sistare if (errp) { 10706c6a658SSteve Sistare error_setg(errp, "vfio iommufd backend does not support " 10806c6a658SSteve Sistare "IOMMU_IOAS_CHANGE_PROCESS"); 10906c6a658SSteve Sistare } 11006c6a658SSteve Sistare return false; 11106c6a658SSteve Sistare } 11206c6a658SSteve Sistare return true; 11306c6a658SSteve Sistare } 11406c6a658SSteve Sistare 11506c6a658SSteve Sistare static const VMStateDescription iommufd_cpr_vmstate = { 11606c6a658SSteve Sistare .name = "iommufd", 11706c6a658SSteve Sistare .version_id = 0, 11806c6a658SSteve Sistare .minimum_version_id = 0, 11906c6a658SSteve Sistare .needed = cpr_incoming_needed, 12006c6a658SSteve Sistare .fields = (VMStateField[]) { 12106c6a658SSteve Sistare VMSTATE_END_OF_LIST() 12206c6a658SSteve Sistare } 12306c6a658SSteve Sistare }; 12406c6a658SSteve Sistare 12506c6a658SSteve Sistare bool vfio_iommufd_cpr_register_iommufd(IOMMUFDBackend *be, Error **errp) 12606c6a658SSteve Sistare { 12706c6a658SSteve Sistare Error **cpr_blocker = &be->cpr_blocker; 12806c6a658SSteve Sistare 12906c6a658SSteve Sistare if (!vfio_cpr_supported(be, cpr_blocker)) { 13006c6a658SSteve Sistare return migrate_add_blocker_modes(cpr_blocker, errp, 13106c6a658SSteve Sistare MIG_MODE_CPR_TRANSFER, -1) == 0; 13206c6a658SSteve Sistare } 13306c6a658SSteve Sistare 13406c6a658SSteve Sistare vmstate_register(NULL, -1, &iommufd_cpr_vmstate, be); 13506c6a658SSteve Sistare 13606c6a658SSteve Sistare return true; 13706c6a658SSteve Sistare } 13806c6a658SSteve Sistare 13906c6a658SSteve Sistare void vfio_iommufd_cpr_unregister_iommufd(IOMMUFDBackend *be) 14006c6a658SSteve Sistare { 14106c6a658SSteve Sistare vmstate_unregister(NULL, &iommufd_cpr_vmstate, be); 14206c6a658SSteve Sistare migrate_del_blocker(&be->cpr_blocker); 14306c6a658SSteve Sistare } 14406c6a658SSteve Sistare 14506c6a658SSteve Sistare bool vfio_iommufd_cpr_register_container(VFIOIOMMUFDContainer *container, 14606c6a658SSteve Sistare Error **errp) 14706c6a658SSteve Sistare { 14806c6a658SSteve Sistare VFIOContainerBase *bcontainer = &container->bcontainer; 14906c6a658SSteve Sistare 15006c6a658SSteve Sistare migration_add_notifier_mode(&bcontainer->cpr_reboot_notifier, 15106c6a658SSteve Sistare vfio_cpr_reboot_notifier, 15206c6a658SSteve Sistare MIG_MODE_CPR_REBOOT); 15306c6a658SSteve Sistare 15406c6a658SSteve Sistare vfio_cpr_add_kvm_notifier(); 15506c6a658SSteve Sistare 15606c6a658SSteve Sistare return true; 15706c6a658SSteve Sistare } 15806c6a658SSteve Sistare 15906c6a658SSteve Sistare void vfio_iommufd_cpr_unregister_container(VFIOIOMMUFDContainer *container) 16006c6a658SSteve Sistare { 16106c6a658SSteve Sistare VFIOContainerBase *bcontainer = &container->bcontainer; 16206c6a658SSteve Sistare 16306c6a658SSteve Sistare migration_remove_notifier(&bcontainer->cpr_reboot_notifier); 16406c6a658SSteve Sistare } 16506c6a658SSteve Sistare 16606c6a658SSteve Sistare void vfio_iommufd_cpr_register_device(VFIODevice *vbasedev) 16706c6a658SSteve Sistare { 168*f2f3e466SSteve Sistare if (!cpr_is_incoming()) { 169*f2f3e466SSteve Sistare vfio_cpr_save_device(vbasedev); 170*f2f3e466SSteve Sistare } 17106c6a658SSteve Sistare } 17206c6a658SSteve Sistare 17306c6a658SSteve Sistare void vfio_iommufd_cpr_unregister_device(VFIODevice *vbasedev) 17406c6a658SSteve Sistare { 175*f2f3e466SSteve Sistare vfio_cpr_delete_device(vbasedev->name); 176*f2f3e466SSteve Sistare } 177*f2f3e466SSteve Sistare 178*f2f3e466SSteve Sistare void vfio_cpr_load_device(VFIODevice *vbasedev) 179*f2f3e466SSteve Sistare { 180*f2f3e466SSteve Sistare if (cpr_is_incoming()) { 181*f2f3e466SSteve Sistare bool ret = vfio_cpr_find_device(vbasedev); 182*f2f3e466SSteve Sistare g_assert(ret); 183*f2f3e466SSteve Sistare } 18406c6a658SSteve Sistare } 185