diff options
| -rw-r--r-- | docs/devel/qapi-code-gen.rst | 19 | ||||
| -rw-r--r-- | docs/devel/qapi-domain.rst | 1 | ||||
| -rw-r--r-- | hw/vfio/cpr.c | 93 | ||||
| -rw-r--r-- | hw/vfio/pci.c | 18 | ||||
| -rw-r--r-- | hw/vfio/pci.h | 4 | ||||
| -rw-r--r-- | include/hw/vfio/vfio-cpr.h | 6 | ||||
| -rwxr-xr-x | tests/functional/test_aarch64_hotplug_pci.py | 4 |
7 files changed, 132 insertions, 13 deletions
diff --git a/docs/devel/qapi-code-gen.rst b/docs/devel/qapi-code-gen.rst index dfdbeac5a5..d97602f464 100644 --- a/docs/devel/qapi-code-gen.rst +++ b/docs/devel/qapi-code-gen.rst @@ -646,9 +646,9 @@ Member 'event' names the event. This is the event name used in the Client JSON Protocol. Member 'data' defines the event-specific data. It defaults to an -empty MEMBERS object. +empty MEMBERS_ object. -If 'data' is a MEMBERS object, then MEMBERS defines event-specific +If 'data' is a MEMBERS_ object, then MEMBERS defines event-specific data just like a struct type's 'data' defines struct type members. If 'data' is a STRING, then STRING names a complex type whose members @@ -786,8 +786,8 @@ Configuring the schema Syntax:: COND = STRING - | { 'all: [ COND, ... ] } - | { 'any: [ COND, ... ] } + | { 'all': [ COND, ... ] } + | { 'any': [ COND, ... ] } | { 'not': COND } All definitions take an optional 'if' member. Its value must be a @@ -943,9 +943,14 @@ The usual ****strong****, *\*emphasized\** and ````literal```` markup should be used. If you need a single literal ``*``, you will need to backslash-escape it. -Use ``@foo`` to reference a name in the schema. This is an rST -extension. It is rendered the same way as ````foo````, but carries -additional meaning. +Use ```foo``` to reference a definition in the schema. This generates +a link to the definition. In the event that such a cross-reference is +ambiguous, you can use `QAPI cross-reference roles +<QAPI-domain-cross-references>` to disambiguate. + +Use @foo to reference a member description within the current +definition. This is an rST extension. It is currently rendered the +same way as ````foo````, but carries additional meaning. Example:: diff --git a/docs/devel/qapi-domain.rst b/docs/devel/qapi-domain.rst index fe540d1e40..1924f12d42 100644 --- a/docs/devel/qapi-domain.rst +++ b/docs/devel/qapi-domain.rst @@ -375,6 +375,7 @@ Will allow you to add arbitrary field lists in QAPI directives:: :see also: Lorem ipsum, dolor sit amet ... +.. _QAPI-domain-cross-references: Cross-references ================ diff --git a/hw/vfio/cpr.c b/hw/vfio/cpr.c index 384b56c4c7..a831243e02 100644 --- a/hw/vfio/cpr.c +++ b/hw/vfio/cpr.c @@ -70,7 +70,7 @@ static void vfio_cpr_claim_vectors(VFIOPCIDevice *vdev, int nr_vectors, fd = vfio_cpr_load_vector_fd(vdev, "interrupt", i); if (fd >= 0) { vfio_pci_vector_init(vdev, i); - vfio_pci_msi_set_handler(vdev, i); + vfio_pci_msi_set_handler(vdev, i, true); } if (vfio_cpr_load_vector_fd(vdev, "kvm_interrupt", i) >= 0) { @@ -200,3 +200,94 @@ void vfio_cpr_add_kvm_notifier(void) MIG_MODE_CPR_TRANSFER); } } + +static int set_irqfd_notifier_gsi(KVMState *s, EventNotifier *n, + EventNotifier *rn, int virq, bool enable) +{ + if (enable) { + return kvm_irqchip_add_irqfd_notifier_gsi(s, n, rn, virq); + } else { + return kvm_irqchip_remove_irqfd_notifier_gsi(s, n, virq); + } +} + +static int vfio_cpr_set_msi_virq(VFIOPCIDevice *vdev, Error **errp, bool enable) +{ + const char *op = (enable ? "enable" : "disable"); + PCIDevice *pdev = &vdev->pdev; + int i, nr_vectors, ret = 0; + + if (msix_enabled(pdev)) { + nr_vectors = vdev->msix->entries; + + } else if (msi_enabled(pdev)) { + nr_vectors = msi_nr_vectors_allocated(pdev); + + } else if (vfio_pci_read_config(pdev, PCI_INTERRUPT_PIN, 1)) { + ret = set_irqfd_notifier_gsi(kvm_state, &vdev->intx.interrupt, + &vdev->intx.unmask, vdev->intx.route.irq, + enable); + if (ret) { + error_setg_errno(errp, -ret, "failed to %s INTx irq %d", + op, vdev->intx.route.irq); + return ret; + } + vfio_pci_intx_set_handler(vdev, enable); + return ret; + + } else { + return 0; + } + + for (i = 0; i < nr_vectors; i++) { + VFIOMSIVector *vector = &vdev->msi_vectors[i]; + if (vector->use) { + ret = set_irqfd_notifier_gsi(kvm_state, &vector->kvm_interrupt, + NULL, vector->virq, enable); + if (ret) { + error_setg_errno(errp, -ret, + "failed to %s msi vector %d virq %d", + op, i, vector->virq); + return ret; + } + vfio_pci_msi_set_handler(vdev, i, enable); + } + } + + return ret; +} + +/* + * When CPR starts, detach IRQs from the VFIO device so future interrupts + * are posted to kvm_interrupt, which is preserved in new QEMU. Interrupts + * that were already posted to the old KVM instance, but not delivered to the + * VCPU, are recovered via KVM_GET_LAPIC and pushed to the new KVM instance + * in new QEMU. + * + * If CPR fails, reattach the IRQs. + */ +static int vfio_cpr_pci_notifier(NotifierWithReturn *notifier, + MigrationEvent *e, Error **errp) +{ + VFIOPCIDevice *vdev = + container_of(notifier, VFIOPCIDevice, cpr.transfer_notifier); + + if (e->type == MIG_EVENT_PRECOPY_SETUP) { + return vfio_cpr_set_msi_virq(vdev, errp, false); + } else if (e->type == MIG_EVENT_PRECOPY_FAILED) { + return vfio_cpr_set_msi_virq(vdev, errp, true); + } + return 0; +} + +void vfio_cpr_pci_register_device(VFIOPCIDevice *vdev) +{ + migration_add_notifier_mode(&vdev->cpr.transfer_notifier, + vfio_cpr_pci_notifier, + MIG_MODE_CPR_TRANSFER); +} + +void vfio_cpr_pci_unregister_device(VFIOPCIDevice *vdev) +{ + migration_remove_notifier(&vdev->cpr.transfer_notifier); +} diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 4fa692c1a3..07257d0fa0 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -413,6 +413,14 @@ bool vfio_pci_intx_enable(VFIOPCIDevice *vdev, Error **errp) return vfio_intx_enable(vdev, errp); } +void vfio_pci_intx_set_handler(VFIOPCIDevice *vdev, bool enable) +{ + int fd = event_notifier_get_fd(&vdev->intx.interrupt); + IOHandler *handler = (enable ? vfio_intx_interrupt : NULL); + + qemu_set_fd_handler(fd, handler, NULL, vdev); +} + /* * MSI/X */ @@ -451,12 +459,13 @@ static void vfio_msi_interrupt(void *opaque) notify(&vdev->pdev, nr); } -void vfio_pci_msi_set_handler(VFIOPCIDevice *vdev, int nr) +void vfio_pci_msi_set_handler(VFIOPCIDevice *vdev, int nr, bool enable) { VFIOMSIVector *vector = &vdev->msi_vectors[nr]; int fd = event_notifier_get_fd(&vector->interrupt); + IOHandler *handler = (enable ? vfio_msi_interrupt : NULL); - qemu_set_fd_handler(fd, vfio_msi_interrupt, NULL, vector); + qemu_set_fd_handler(fd, handler, NULL, vector); } /* @@ -2992,6 +3001,7 @@ void vfio_pci_put_device(VFIOPCIDevice *vdev) { vfio_display_finalize(vdev); vfio_bars_finalize(vdev); + vfio_cpr_pci_unregister_device(vdev); g_free(vdev->emulated_config_bits); g_free(vdev->rom); /* @@ -3471,6 +3481,7 @@ static void vfio_pci_realize(PCIDevice *pdev, Error **errp) vfio_pci_register_err_notifier(vdev); vfio_pci_register_req_notifier(vdev); vfio_setup_resetfn_quirk(vdev); + vfio_cpr_pci_register_device(vdev); return; @@ -3890,6 +3901,9 @@ static void vfio_pci_nohotplug_dev_class_init(ObjectClass *klass, "x-ramfb-migrate", "Override default migration support for ramfb support " "(DEBUG)"); + object_class_property_set_description(klass, /* 10.1 */ + "use-legacy-x86-rom", + "Controls loading of a legacy VGA BIOS ROM"); } static const TypeInfo vfio_pci_nohotplug_dev_info = { diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h index 81465a8214..810a842f4a 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h @@ -188,6 +188,7 @@ struct VFIOPCIDevice { bool skip_vsc_check; VFIODisplay *dpy; Notifier irqchip_change_notifier; + VFIOPCICPR cpr; }; /* Use uin32_t for vendor & device so PCI_ANY_ID expands and cannot match hw */ @@ -209,8 +210,9 @@ void vfio_pci_add_kvm_msi_virq(VFIOPCIDevice *vdev, VFIOMSIVector *vector, void vfio_pci_prepare_kvm_msi_virq_batch(VFIOPCIDevice *vdev); void vfio_pci_commit_kvm_msi_virq_batch(VFIOPCIDevice *vdev); bool vfio_pci_intx_enable(VFIOPCIDevice *vdev, Error **errp); +void vfio_pci_intx_set_handler(VFIOPCIDevice *vdev, bool enable); void vfio_pci_msix_set_notifiers(VFIOPCIDevice *vdev); -void vfio_pci_msi_set_handler(VFIOPCIDevice *vdev, int nr); +void vfio_pci_msi_set_handler(VFIOPCIDevice *vdev, int nr, bool enable); uint32_t vfio_pci_read_config(PCIDevice *pdev, uint32_t addr, int len); void vfio_pci_write_config(PCIDevice *pdev, diff --git a/include/hw/vfio/vfio-cpr.h b/include/hw/vfio/vfio-cpr.h index 80ad20d216..d37daffbc5 100644 --- a/include/hw/vfio/vfio-cpr.h +++ b/include/hw/vfio/vfio-cpr.h @@ -38,6 +38,10 @@ typedef struct VFIODeviceCPR { uint32_t ioas_id; } VFIODeviceCPR; +typedef struct VFIOPCICPR { + NotifierWithReturn transfer_notifier; +} VFIOPCICPR; + bool vfio_legacy_cpr_register_container(struct VFIOContainer *container, Error **errp); void vfio_legacy_cpr_unregister_container(struct VFIOContainer *container); @@ -77,5 +81,7 @@ extern const VMStateDescription vfio_cpr_pci_vmstate; extern const VMStateDescription vmstate_cpr_vfio_devices; void vfio_cpr_add_kvm_notifier(void); +void vfio_cpr_pci_register_device(struct VFIOPCIDevice *vdev); +void vfio_cpr_pci_unregister_device(struct VFIOPCIDevice *vdev); #endif /* HW_VFIO_VFIO_CPR_H */ diff --git a/tests/functional/test_aarch64_hotplug_pci.py b/tests/functional/test_aarch64_hotplug_pci.py index c9bb7f1d97..0c67991b89 100755 --- a/tests/functional/test_aarch64_hotplug_pci.py +++ b/tests/functional/test_aarch64_hotplug_pci.py @@ -15,12 +15,12 @@ from qemu_test import BUILD_DIR class HotplugPCI(LinuxKernelTest): ASSET_KERNEL = Asset( - ('https://ftp.debian.org/debian/dists/stable/main/installer-arm64/' + ('https://ftp.debian.org/debian/dists/bookworm/main/installer-arm64/' '20230607+deb12u11/images/netboot/debian-installer/arm64/linux'), 'd92a60392ce1e379ca198a1a820899f8f0d39a62d047c41ab79492f81541a9d9') ASSET_INITRD = Asset( - ('https://ftp.debian.org/debian/dists/stable/main/installer-arm64/' + ('https://ftp.debian.org/debian/dists/bookworm/main/installer-arm64/' '20230607+deb12u11/images/netboot/debian-installer/arm64/initrd.gz'), '9f817f76951f3237bca8216bee35267bfb826815687f4b2fcdd5e6c2a917790c') |