1 /*
2 * Copyright (c) 2021-2024 Oracle and/or its affiliates.
3 *
4 * This work is licensed under the terms of the GNU GPL, version 2 or later.
5 * See the COPYING file in the top-level directory.
6 */
7
8 #include "qemu/osdep.h"
9 #include "hw/vfio/vfio-device.h"
10 #include "hw/vfio/vfio-cpr.h"
11 #include "hw/vfio/pci.h"
12 #include "migration/cpr.h"
13 #include "qapi/error.h"
14 #include "system/runstate.h"
15
vfio_cpr_reboot_notifier(NotifierWithReturn * notifier,MigrationEvent * e,Error ** errp)16 int vfio_cpr_reboot_notifier(NotifierWithReturn *notifier,
17 MigrationEvent *e, Error **errp)
18 {
19 if (e->type == MIG_EVENT_PRECOPY_SETUP &&
20 !runstate_check(RUN_STATE_SUSPENDED) && !vm_get_suspended()) {
21
22 error_setg(errp,
23 "VFIO device only supports cpr-reboot for runstate suspended");
24
25 return -1;
26 }
27 return 0;
28 }
29
vfio_cpr_register_container(VFIOContainerBase * bcontainer,Error ** errp)30 bool vfio_cpr_register_container(VFIOContainerBase *bcontainer, Error **errp)
31 {
32 migration_add_notifier_mode(&bcontainer->cpr_reboot_notifier,
33 vfio_cpr_reboot_notifier,
34 MIG_MODE_CPR_REBOOT);
35 return true;
36 }
37
vfio_cpr_unregister_container(VFIOContainerBase * bcontainer)38 void vfio_cpr_unregister_container(VFIOContainerBase *bcontainer)
39 {
40 migration_remove_notifier(&bcontainer->cpr_reboot_notifier);
41 }
42
43 /*
44 * The kernel may change non-emulated config bits. Exclude them from the
45 * changed-bits check in get_pci_config_device.
46 */
vfio_cpr_pci_pre_load(void * opaque)47 static int vfio_cpr_pci_pre_load(void *opaque)
48 {
49 VFIOPCIDevice *vdev = opaque;
50 PCIDevice *pdev = &vdev->pdev;
51 int size = MIN(pci_config_size(pdev), vdev->config_size);
52 int i;
53
54 for (i = 0; i < size; i++) {
55 pdev->cmask[i] &= vdev->emulated_config_bits[i];
56 }
57
58 return 0;
59 }
60
61 const VMStateDescription vfio_cpr_pci_vmstate = {
62 .name = "vfio-cpr-pci",
63 .version_id = 0,
64 .minimum_version_id = 0,
65 .pre_load = vfio_cpr_pci_pre_load,
66 .needed = cpr_incoming_needed,
67 .fields = (VMStateField[]) {
68 VMSTATE_END_OF_LIST()
69 }
70 };
71