xref: /qemu/hw/vfio/cpr.c (revision 5a1f614d0cd0bcc8e84e0b7ab6af63d56bd348a2)
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 
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 
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 
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  */
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