mirror of https://github.com/xemu-project/xemu.git
VFIO updates 2022-05-06
* Defer IRQ routing commits to improve setup and resume latency (Longpeng) * Fix trace sparse mmap boundary condition (Xiang Chen) * Quiet misalignment warning from TPM device mapping (Eric Auger) * Misc cleanups (Yi Liu, Eric Auger) -----BEGIN PGP SIGNATURE----- iQJPBAABCAA5FiEEQvbATlQL0amee4qQI5ubbjuwiyIFAmJ1hm8bHGFsZXgud2ls bGlhbXNvbkByZWRoYXQuY29tAAoJECObm247sIsi8cIP+wfOMh9YLAm6NC70Gd9q 7Z6Z3ql/5SYUF8AmsLZf3UPa1+bVQ4TcsjqN5tiaCx36iDXF39jkHM/w9Cd4sPuB 7ETmWndj6FwOI9PNpFmVoUrpONyLI3VuCNZqwhV1mlmTEnmCsE1PAvjjjPz51HDd +dnkIJsjoKqpzja9zotQnpWtx7O4iKGGAUx3oi4BbF47sG2az2GQnI/5L/Zj8dBO G3h+FCavSO6ODmIxX865ndZifN3BV1asazNDjFp7beUNFVrNCpzZkIkFGzhtx8yS npxw/27m2s/O+dJZIlWPMCH0H0ItIHpqntBziMopxCG3ELsnhJjAccg5aWi2okXM M0rmNu+BH9WKPJoqy8u89gZvebyhvtTuMQ1gDzZWkEe80LLfoB9Re/qvMuw2LBnv BSu8hUHCoX3Whnc7PoP11Y97uBW/uaH/LTagrqzIJIBWSniUCZaZUep6Ihg1wFFQ oTNKKiaer/jtzmCTFtGKC7dj/gGuKNvAO8l/yqWj3k7ssstllaOLOzjDmoD5bmZD jVaaAedOhFme5sGtgqcmFmNXA+r01PoKmopkHku74meCk+RCxV4i8xkVZGlREHpS YB7CsA8B8jcLQS9QfguFWreImhstaC0fOKRDXDGMGm9ikPThdtIE5oWt2c4fKz5Y Hi6FjfEsDoZNLs64lc4cyMEq =ShHn -----END PGP SIGNATURE----- Merge tag 'vfio-updates-20220506.1' of https://gitlab.com/alex.williamson/qemu into staging VFIO updates 2022-05-06 * Defer IRQ routing commits to improve setup and resume latency (Longpeng) * Fix trace sparse mmap boundary condition (Xiang Chen) * Quiet misalignment warning from TPM device mapping (Eric Auger) * Misc cleanups (Yi Liu, Eric Auger) # -----BEGIN PGP SIGNATURE----- # # iQJPBAABCAA5FiEEQvbATlQL0amee4qQI5ubbjuwiyIFAmJ1hm8bHGFsZXgud2ls # bGlhbXNvbkByZWRoYXQuY29tAAoJECObm247sIsi8cIP+wfOMh9YLAm6NC70Gd9q # 7Z6Z3ql/5SYUF8AmsLZf3UPa1+bVQ4TcsjqN5tiaCx36iDXF39jkHM/w9Cd4sPuB # 7ETmWndj6FwOI9PNpFmVoUrpONyLI3VuCNZqwhV1mlmTEnmCsE1PAvjjjPz51HDd # +dnkIJsjoKqpzja9zotQnpWtx7O4iKGGAUx3oi4BbF47sG2az2GQnI/5L/Zj8dBO # G3h+FCavSO6ODmIxX865ndZifN3BV1asazNDjFp7beUNFVrNCpzZkIkFGzhtx8yS # npxw/27m2s/O+dJZIlWPMCH0H0ItIHpqntBziMopxCG3ELsnhJjAccg5aWi2okXM # M0rmNu+BH9WKPJoqy8u89gZvebyhvtTuMQ1gDzZWkEe80LLfoB9Re/qvMuw2LBnv # BSu8hUHCoX3Whnc7PoP11Y97uBW/uaH/LTagrqzIJIBWSniUCZaZUep6Ihg1wFFQ # oTNKKiaer/jtzmCTFtGKC7dj/gGuKNvAO8l/yqWj3k7ssstllaOLOzjDmoD5bmZD # jVaaAedOhFme5sGtgqcmFmNXA+r01PoKmopkHku74meCk+RCxV4i8xkVZGlREHpS # YB7CsA8B8jcLQS9QfguFWreImhstaC0fOKRDXDGMGm9ikPThdtIE5oWt2c4fKz5Y # Hi6FjfEsDoZNLs64lc4cyMEq # =ShHn # -----END PGP SIGNATURE----- # gpg: Signature made Fri 06 May 2022 03:34:55 PM CDT # gpg: using RSA key 42F6C04E540BD1A99E7B8A90239B9B6E3BB08B22 # gpg: issuer "alex.williamson@redhat.com" # gpg: Good signature from "Alex Williamson <alex.williamson@redhat.com>" [undefined] # gpg: aka "Alex Williamson <alex@shazbot.org>" [undefined] # gpg: aka "Alex Williamson <alwillia@redhat.com>" [undefined] # gpg: aka "Alex Williamson <alex.l.williamson@gmail.com>" [undefined] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 42F6 C04E 540B D1A9 9E7B 8A90 239B 9B6E 3BB0 8B22 * tag 'vfio-updates-20220506.1' of https://gitlab.com/alex.williamson/qemu: vfio/common: Rename VFIOGuestIOMMU::iommu into ::iommu_mr vfio/pci: Use vbasedev local variable in vfio_realize() hw/vfio/pci: fix vfio_pci_hot_reset_result trace point vfio/common: remove spurious tpm-crb-cmd misalignment warning sysemu: tpm: Add a stub function for TPM_IS_CRB vfio/common: Fix a small boundary issue of a trace vfio: defer to commit kvm irq routing when enable msi/msix Revert "vfio: Avoid disabling and enabling vectors repeatedly in VFIO migration" vfio: simplify the failure path in vfio_msi_enable vfio: move re-enabling INTX out of the common helper vfio: simplify the conditional statements in vfio_msi_enable Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
13220a46e2
|
@ -40,6 +40,7 @@
|
|||
#include "trace.h"
|
||||
#include "qapi/error.h"
|
||||
#include "migration/migration.h"
|
||||
#include "sysemu/tpm.h"
|
||||
|
||||
VFIOGroupList vfio_group_list =
|
||||
QLIST_HEAD_INITIALIZER(vfio_group_list);
|
||||
|
@ -861,6 +862,22 @@ static void vfio_unregister_ram_discard_listener(VFIOContainer *container,
|
|||
g_free(vrdl);
|
||||
}
|
||||
|
||||
static bool vfio_known_safe_misalignment(MemoryRegionSection *section)
|
||||
{
|
||||
MemoryRegion *mr = section->mr;
|
||||
|
||||
if (!TPM_IS_CRB(mr->owner)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* this is a known safe misaligned region, just trace for debug purpose */
|
||||
trace_vfio_known_safe_misalignment(memory_region_name(mr),
|
||||
section->offset_within_address_space,
|
||||
section->offset_within_region,
|
||||
qemu_real_host_page_size());
|
||||
return true;
|
||||
}
|
||||
|
||||
static void vfio_listener_region_add(MemoryListener *listener,
|
||||
MemoryRegionSection *section)
|
||||
{
|
||||
|
@ -884,7 +901,15 @@ static void vfio_listener_region_add(MemoryListener *listener,
|
|||
if (unlikely((section->offset_within_address_space &
|
||||
~qemu_real_host_page_mask()) !=
|
||||
(section->offset_within_region & ~qemu_real_host_page_mask()))) {
|
||||
error_report("%s received unaligned region", __func__);
|
||||
if (!vfio_known_safe_misalignment(section)) {
|
||||
error_report("%s received unaligned region %s iova=0x%"PRIx64
|
||||
" offset_within_region=0x%"PRIx64
|
||||
" qemu_real_host_page_size=0x%"PRIxPTR,
|
||||
__func__, memory_region_name(section->mr),
|
||||
section->offset_within_address_space,
|
||||
section->offset_within_region,
|
||||
qemu_real_host_page_size());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -992,7 +1017,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
|
|||
* device emulation the VFIO iommu handles to use).
|
||||
*/
|
||||
giommu = g_malloc0(sizeof(*giommu));
|
||||
giommu->iommu = iommu_mr;
|
||||
giommu->iommu_mr = iommu_mr;
|
||||
giommu->iommu_offset = section->offset_within_address_space -
|
||||
section->offset_within_region;
|
||||
giommu->container = container;
|
||||
|
@ -1007,7 +1032,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
|
|||
int128_get64(llend),
|
||||
iommu_idx);
|
||||
|
||||
ret = memory_region_iommu_set_page_size_mask(giommu->iommu,
|
||||
ret = memory_region_iommu_set_page_size_mask(giommu->iommu_mr,
|
||||
container->pgsizes,
|
||||
&err);
|
||||
if (ret) {
|
||||
|
@ -1022,7 +1047,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
|
|||
goto fail;
|
||||
}
|
||||
QLIST_INSERT_HEAD(&container->giommu_list, giommu, giommu_next);
|
||||
memory_region_iommu_replay(giommu->iommu, &giommu->n);
|
||||
memory_region_iommu_replay(giommu->iommu_mr, &giommu->n);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -1128,7 +1153,7 @@ static void vfio_listener_region_del(MemoryListener *listener,
|
|||
VFIOGuestIOMMU *giommu;
|
||||
|
||||
QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) {
|
||||
if (MEMORY_REGION(giommu->iommu) == section->mr &&
|
||||
if (MEMORY_REGION(giommu->iommu_mr) == section->mr &&
|
||||
giommu->n.start == section->offset_within_region) {
|
||||
memory_region_unregister_iommu_notifier(section->mr,
|
||||
&giommu->n);
|
||||
|
@ -1393,11 +1418,11 @@ static int vfio_sync_dirty_bitmap(VFIOContainer *container,
|
|||
VFIOGuestIOMMU *giommu;
|
||||
|
||||
QLIST_FOREACH(giommu, &container->giommu_list, giommu_next) {
|
||||
if (MEMORY_REGION(giommu->iommu) == section->mr &&
|
||||
if (MEMORY_REGION(giommu->iommu_mr) == section->mr &&
|
||||
giommu->n.start == section->offset_within_region) {
|
||||
Int128 llend;
|
||||
vfio_giommu_dirty_notifier gdn = { .giommu = giommu };
|
||||
int idx = memory_region_iommu_attrs_to_index(giommu->iommu,
|
||||
int idx = memory_region_iommu_attrs_to_index(giommu->iommu_mr,
|
||||
MEMTXATTRS_UNSPECIFIED);
|
||||
|
||||
llend = int128_add(int128_make64(section->offset_within_region),
|
||||
|
@ -1410,7 +1435,7 @@ static int vfio_sync_dirty_bitmap(VFIOContainer *container,
|
|||
section->offset_within_region,
|
||||
int128_get64(llend),
|
||||
idx);
|
||||
memory_region_iommu_replay(giommu->iommu, &gdn.n);
|
||||
memory_region_iommu_replay(giommu->iommu_mr, &gdn.n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1544,11 +1569,10 @@ static int vfio_setup_region_sparse_mmaps(VFIORegion *region,
|
|||
region->mmaps = g_new0(VFIOMmap, sparse->nr_areas);
|
||||
|
||||
for (i = 0, j = 0; i < sparse->nr_areas; i++) {
|
||||
trace_vfio_region_sparse_mmap_entry(i, sparse->areas[i].offset,
|
||||
sparse->areas[i].offset +
|
||||
sparse->areas[i].size);
|
||||
|
||||
if (sparse->areas[i].size) {
|
||||
trace_vfio_region_sparse_mmap_entry(i, sparse->areas[i].offset,
|
||||
sparse->areas[i].offset +
|
||||
sparse->areas[i].size - 1);
|
||||
region->mmaps[j].offset = sparse->areas[i].offset;
|
||||
region->mmaps[j].size = sparse->areas[i].size;
|
||||
j++;
|
||||
|
@ -2246,7 +2270,7 @@ static void vfio_disconnect_container(VFIOGroup *group)
|
|||
|
||||
QLIST_FOREACH_SAFE(giommu, &container->giommu_list, giommu_next, tmp) {
|
||||
memory_region_unregister_iommu_notifier(
|
||||
MEMORY_REGION(giommu->iommu), &giommu->n);
|
||||
MEMORY_REGION(giommu->iommu_mr), &giommu->n);
|
||||
QLIST_REMOVE(giommu, giommu_next);
|
||||
g_free(giommu);
|
||||
}
|
||||
|
|
234
hw/vfio/pci.c
234
hw/vfio/pci.c
|
@ -45,8 +45,12 @@
|
|||
|
||||
#define TYPE_VFIO_PCI_NOHOTPLUG "vfio-pci-nohotplug"
|
||||
|
||||
/* Protected by BQL */
|
||||
static KVMRouteChange vfio_route_change;
|
||||
|
||||
static void vfio_disable_interrupts(VFIOPCIDevice *vdev);
|
||||
static void vfio_mmap_set_enabled(VFIOPCIDevice *vdev, bool enabled);
|
||||
static void vfio_msi_disable_common(VFIOPCIDevice *vdev);
|
||||
|
||||
/*
|
||||
* Disabling BAR mmaping can be slow, but toggling it around INTx can
|
||||
|
@ -412,33 +416,36 @@ static int vfio_enable_vectors(VFIOPCIDevice *vdev, bool msix)
|
|||
static void vfio_add_kvm_msi_virq(VFIOPCIDevice *vdev, VFIOMSIVector *vector,
|
||||
int vector_n, bool msix)
|
||||
{
|
||||
KVMRouteChange c;
|
||||
int virq;
|
||||
|
||||
if ((msix && vdev->no_kvm_msix) || (!msix && vdev->no_kvm_msi)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event_notifier_init(&vector->kvm_interrupt, 0)) {
|
||||
vector->virq = kvm_irqchip_add_msi_route(&vfio_route_change,
|
||||
vector_n, &vdev->pdev);
|
||||
}
|
||||
|
||||
static void vfio_connect_kvm_msi_virq(VFIOMSIVector *vector)
|
||||
{
|
||||
if (vector->virq < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
c = kvm_irqchip_begin_route_changes(kvm_state);
|
||||
virq = kvm_irqchip_add_msi_route(&c, vector_n, &vdev->pdev);
|
||||
if (virq < 0) {
|
||||
event_notifier_cleanup(&vector->kvm_interrupt);
|
||||
return;
|
||||
if (event_notifier_init(&vector->kvm_interrupt, 0)) {
|
||||
goto fail_notifier;
|
||||
}
|
||||
kvm_irqchip_commit_route_changes(&c);
|
||||
|
||||
if (kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, &vector->kvm_interrupt,
|
||||
NULL, virq) < 0) {
|
||||
kvm_irqchip_release_virq(kvm_state, virq);
|
||||
event_notifier_cleanup(&vector->kvm_interrupt);
|
||||
return;
|
||||
NULL, vector->virq) < 0) {
|
||||
goto fail_kvm;
|
||||
}
|
||||
|
||||
vector->virq = virq;
|
||||
return;
|
||||
|
||||
fail_kvm:
|
||||
event_notifier_cleanup(&vector->kvm_interrupt);
|
||||
fail_notifier:
|
||||
kvm_irqchip_release_virq(kvm_state, vector->virq);
|
||||
vector->virq = -1;
|
||||
}
|
||||
|
||||
static void vfio_remove_kvm_msi_virq(VFIOMSIVector *vector)
|
||||
|
@ -493,7 +500,14 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
|
|||
}
|
||||
} else {
|
||||
if (msg) {
|
||||
vfio_add_kvm_msi_virq(vdev, vector, nr, true);
|
||||
if (vdev->defer_kvm_irq_routing) {
|
||||
vfio_add_kvm_msi_virq(vdev, vector, nr, true);
|
||||
} else {
|
||||
vfio_route_change = kvm_irqchip_begin_route_changes(kvm_state);
|
||||
vfio_add_kvm_msi_virq(vdev, vector, nr, true);
|
||||
kvm_irqchip_commit_route_changes(&vfio_route_change);
|
||||
vfio_connect_kvm_msi_virq(vector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -503,11 +517,13 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
|
|||
* increase them as needed.
|
||||
*/
|
||||
if (vdev->nr_vectors < nr + 1) {
|
||||
vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX);
|
||||
vdev->nr_vectors = nr + 1;
|
||||
ret = vfio_enable_vectors(vdev, true);
|
||||
if (ret) {
|
||||
error_report("vfio: failed to enable vectors, %d", ret);
|
||||
if (!vdev->defer_kvm_irq_routing) {
|
||||
vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX);
|
||||
ret = vfio_enable_vectors(vdev, true);
|
||||
if (ret) {
|
||||
error_report("vfio: failed to enable vectors, %d", ret);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Error *err = NULL;
|
||||
|
@ -569,11 +585,29 @@ static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr)
|
|||
}
|
||||
}
|
||||
|
||||
static void vfio_prepare_kvm_msi_virq_batch(VFIOPCIDevice *vdev)
|
||||
{
|
||||
assert(!vdev->defer_kvm_irq_routing);
|
||||
vdev->defer_kvm_irq_routing = true;
|
||||
vfio_route_change = kvm_irqchip_begin_route_changes(kvm_state);
|
||||
}
|
||||
|
||||
static void vfio_commit_kvm_msi_virq_batch(VFIOPCIDevice *vdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
assert(vdev->defer_kvm_irq_routing);
|
||||
vdev->defer_kvm_irq_routing = false;
|
||||
|
||||
kvm_irqchip_commit_route_changes(&vfio_route_change);
|
||||
|
||||
for (i = 0; i < vdev->nr_vectors; i++) {
|
||||
vfio_connect_kvm_msi_virq(&vdev->msi_vectors[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void vfio_msix_enable(VFIOPCIDevice *vdev)
|
||||
{
|
||||
PCIDevice *pdev = &vdev->pdev;
|
||||
unsigned int nr, max_vec = 0;
|
||||
|
||||
vfio_disable_interrupts(vdev);
|
||||
|
||||
vdev->msi_vectors = g_new0(VFIOMSIVector, vdev->msix->entries);
|
||||
|
@ -581,37 +615,45 @@ static void vfio_msix_enable(VFIOPCIDevice *vdev)
|
|||
vdev->interrupt = VFIO_INT_MSIX;
|
||||
|
||||
/*
|
||||
* Some communication channels between VF & PF or PF & fw rely on the
|
||||
* physical state of the device and expect that enabling MSI-X from the
|
||||
* guest enables the same on the host. When our guest is Linux, the
|
||||
* guest driver call to pci_enable_msix() sets the enabling bit in the
|
||||
* MSI-X capability, but leaves the vector table masked. We therefore
|
||||
* can't rely on a vector_use callback (from request_irq() in the guest)
|
||||
* to switch the physical device into MSI-X mode because that may come a
|
||||
* long time after pci_enable_msix(). This code enables vector 0 with
|
||||
* triggering to userspace, then immediately release the vector, leaving
|
||||
* the physical device with no vectors enabled, but MSI-X enabled, just
|
||||
* like the guest view.
|
||||
* If there are already unmasked vectors (in migration resume phase and
|
||||
* some guest startups) which will be enabled soon, we can allocate all
|
||||
* of them here to avoid inefficiently disabling and enabling vectors
|
||||
* repeatedly later.
|
||||
* Setting vector notifiers triggers synchronous vector-use
|
||||
* callbacks for each active vector. Deferring to commit the KVM
|
||||
* routes once rather than per vector provides a substantial
|
||||
* performance improvement.
|
||||
*/
|
||||
if (!pdev->msix_function_masked) {
|
||||
for (nr = 0; nr < msix_nr_vectors_allocated(pdev); nr++) {
|
||||
if (!msix_is_masked(pdev, nr)) {
|
||||
max_vec = nr;
|
||||
}
|
||||
}
|
||||
}
|
||||
vfio_msix_vector_do_use(pdev, max_vec, NULL, NULL);
|
||||
vfio_msix_vector_release(pdev, max_vec);
|
||||
vfio_prepare_kvm_msi_virq_batch(vdev);
|
||||
|
||||
if (msix_set_vector_notifiers(pdev, vfio_msix_vector_use,
|
||||
if (msix_set_vector_notifiers(&vdev->pdev, vfio_msix_vector_use,
|
||||
vfio_msix_vector_release, NULL)) {
|
||||
error_report("vfio: msix_set_vector_notifiers failed");
|
||||
}
|
||||
|
||||
vfio_commit_kvm_msi_virq_batch(vdev);
|
||||
|
||||
if (vdev->nr_vectors) {
|
||||
int ret;
|
||||
|
||||
ret = vfio_enable_vectors(vdev, true);
|
||||
if (ret) {
|
||||
error_report("vfio: failed to enable vectors, %d", ret);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Some communication channels between VF & PF or PF & fw rely on the
|
||||
* physical state of the device and expect that enabling MSI-X from the
|
||||
* guest enables the same on the host. When our guest is Linux, the
|
||||
* guest driver call to pci_enable_msix() sets the enabling bit in the
|
||||
* MSI-X capability, but leaves the vector table masked. We therefore
|
||||
* can't rely on a vector_use callback (from request_irq() in the guest)
|
||||
* to switch the physical device into MSI-X mode because that may come a
|
||||
* long time after pci_enable_msix(). This code enables vector 0 with
|
||||
* triggering to userspace, then immediately release the vector, leaving
|
||||
* the physical device with no vectors enabled, but MSI-X enabled, just
|
||||
* like the guest view.
|
||||
*/
|
||||
vfio_msix_vector_do_use(&vdev->pdev, 0, NULL, NULL);
|
||||
vfio_msix_vector_release(&vdev->pdev, 0);
|
||||
}
|
||||
|
||||
trace_vfio_msix_enable(vdev->vbasedev.name);
|
||||
}
|
||||
|
||||
|
@ -621,6 +663,13 @@ static void vfio_msi_enable(VFIOPCIDevice *vdev)
|
|||
|
||||
vfio_disable_interrupts(vdev);
|
||||
|
||||
/*
|
||||
* Setting vector notifiers needs to enable route for each vector.
|
||||
* Deferring to commit the KVM routes once rather than per vector
|
||||
* provides a substantial performance improvement.
|
||||
*/
|
||||
vfio_prepare_kvm_msi_virq_batch(vdev);
|
||||
|
||||
vdev->nr_vectors = msi_nr_vectors_allocated(&vdev->pdev);
|
||||
retry:
|
||||
vdev->msi_vectors = g_new0(VFIOMSIVector, vdev->nr_vectors);
|
||||
|
@ -646,6 +695,8 @@ retry:
|
|||
vfio_add_kvm_msi_virq(vdev, vector, i, false);
|
||||
}
|
||||
|
||||
vfio_commit_kvm_msi_virq_batch(vdev);
|
||||
|
||||
/* Set interrupt type prior to possible interrupts */
|
||||
vdev->interrupt = VFIO_INT_MSI;
|
||||
|
||||
|
@ -653,29 +704,17 @@ retry:
|
|||
if (ret) {
|
||||
if (ret < 0) {
|
||||
error_report("vfio: Error: Failed to setup MSI fds: %m");
|
||||
} else if (ret != vdev->nr_vectors) {
|
||||
} else {
|
||||
error_report("vfio: Error: Failed to enable %d "
|
||||
"MSI vectors, retry with %d", vdev->nr_vectors, ret);
|
||||
}
|
||||
|
||||
for (i = 0; i < vdev->nr_vectors; i++) {
|
||||
VFIOMSIVector *vector = &vdev->msi_vectors[i];
|
||||
if (vector->virq >= 0) {
|
||||
vfio_remove_kvm_msi_virq(vector);
|
||||
}
|
||||
qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt),
|
||||
NULL, NULL, NULL);
|
||||
event_notifier_cleanup(&vector->interrupt);
|
||||
}
|
||||
vfio_msi_disable_common(vdev);
|
||||
|
||||
g_free(vdev->msi_vectors);
|
||||
vdev->msi_vectors = NULL;
|
||||
|
||||
if (ret > 0 && ret != vdev->nr_vectors) {
|
||||
if (ret > 0) {
|
||||
vdev->nr_vectors = ret;
|
||||
goto retry;
|
||||
}
|
||||
vdev->nr_vectors = 0;
|
||||
|
||||
/*
|
||||
* Failing to setup MSI doesn't really fall within any specification.
|
||||
|
@ -683,7 +722,6 @@ retry:
|
|||
* out to fall back to INTx for this device.
|
||||
*/
|
||||
error_report("vfio: Error: Failed to enable MSI");
|
||||
vdev->interrupt = VFIO_INT_NONE;
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -693,7 +731,6 @@ retry:
|
|||
|
||||
static void vfio_msi_disable_common(VFIOPCIDevice *vdev)
|
||||
{
|
||||
Error *err = NULL;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < vdev->nr_vectors; i++) {
|
||||
|
@ -712,15 +749,11 @@ static void vfio_msi_disable_common(VFIOPCIDevice *vdev)
|
|||
vdev->msi_vectors = NULL;
|
||||
vdev->nr_vectors = 0;
|
||||
vdev->interrupt = VFIO_INT_NONE;
|
||||
|
||||
vfio_intx_enable(vdev, &err);
|
||||
if (err) {
|
||||
error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
|
||||
}
|
||||
}
|
||||
|
||||
static void vfio_msix_disable(VFIOPCIDevice *vdev)
|
||||
{
|
||||
Error *err = NULL;
|
||||
int i;
|
||||
|
||||
msix_unset_vector_notifiers(&vdev->pdev);
|
||||
|
@ -741,6 +774,10 @@ static void vfio_msix_disable(VFIOPCIDevice *vdev)
|
|||
}
|
||||
|
||||
vfio_msi_disable_common(vdev);
|
||||
vfio_intx_enable(vdev, &err);
|
||||
if (err) {
|
||||
error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
|
||||
}
|
||||
|
||||
memset(vdev->msix->pending, 0,
|
||||
BITS_TO_LONGS(vdev->msix->entries) * sizeof(unsigned long));
|
||||
|
@ -750,8 +787,14 @@ static void vfio_msix_disable(VFIOPCIDevice *vdev)
|
|||
|
||||
static void vfio_msi_disable(VFIOPCIDevice *vdev)
|
||||
{
|
||||
Error *err = NULL;
|
||||
|
||||
vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSI_IRQ_INDEX);
|
||||
vfio_msi_disable_common(vdev);
|
||||
vfio_intx_enable(vdev, &err);
|
||||
if (err) {
|
||||
error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name);
|
||||
}
|
||||
|
||||
trace_vfio_msi_disable(vdev->vbasedev.name);
|
||||
}
|
||||
|
@ -2337,7 +2380,7 @@ static int vfio_pci_hot_reset(VFIOPCIDevice *vdev, bool single)
|
|||
g_free(reset);
|
||||
|
||||
trace_vfio_pci_hot_reset_result(vdev->vbasedev.name,
|
||||
ret ? "%m" : "Success");
|
||||
ret ? strerror(errno) : "Success");
|
||||
|
||||
out:
|
||||
/* Re-enable INTx on affected devices */
|
||||
|
@ -2803,6 +2846,7 @@ static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev)
|
|||
static void vfio_realize(PCIDevice *pdev, Error **errp)
|
||||
{
|
||||
VFIOPCIDevice *vdev = VFIO_PCI(pdev);
|
||||
VFIODevice *vbasedev = &vdev->vbasedev;
|
||||
VFIODevice *vbasedev_iter;
|
||||
VFIOGroup *group;
|
||||
char *tmp, *subsys, group_path[PATH_MAX], *group_name;
|
||||
|
@ -2813,7 +2857,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
|
|||
int i, ret;
|
||||
bool is_mdev;
|
||||
|
||||
if (!vdev->vbasedev.sysfsdev) {
|
||||
if (!vbasedev->sysfsdev) {
|
||||
if (!(~vdev->host.domain || ~vdev->host.bus ||
|
||||
~vdev->host.slot || ~vdev->host.function)) {
|
||||
error_setg(errp, "No provided host device");
|
||||
|
@ -2821,24 +2865,24 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
|
|||
"or -device vfio-pci,sysfsdev=PATH_TO_DEVICE\n");
|
||||
return;
|
||||
}
|
||||
vdev->vbasedev.sysfsdev =
|
||||
vbasedev->sysfsdev =
|
||||
g_strdup_printf("/sys/bus/pci/devices/%04x:%02x:%02x.%01x",
|
||||
vdev->host.domain, vdev->host.bus,
|
||||
vdev->host.slot, vdev->host.function);
|
||||
}
|
||||
|
||||
if (stat(vdev->vbasedev.sysfsdev, &st) < 0) {
|
||||
if (stat(vbasedev->sysfsdev, &st) < 0) {
|
||||
error_setg_errno(errp, errno, "no such host device");
|
||||
error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.sysfsdev);
|
||||
error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->sysfsdev);
|
||||
return;
|
||||
}
|
||||
|
||||
vdev->vbasedev.name = g_path_get_basename(vdev->vbasedev.sysfsdev);
|
||||
vdev->vbasedev.ops = &vfio_pci_ops;
|
||||
vdev->vbasedev.type = VFIO_DEVICE_TYPE_PCI;
|
||||
vdev->vbasedev.dev = DEVICE(vdev);
|
||||
vbasedev->name = g_path_get_basename(vbasedev->sysfsdev);
|
||||
vbasedev->ops = &vfio_pci_ops;
|
||||
vbasedev->type = VFIO_DEVICE_TYPE_PCI;
|
||||
vbasedev->dev = DEVICE(vdev);
|
||||
|
||||
tmp = g_strdup_printf("%s/iommu_group", vdev->vbasedev.sysfsdev);
|
||||
tmp = g_strdup_printf("%s/iommu_group", vbasedev->sysfsdev);
|
||||
len = readlink(tmp, group_path, sizeof(group_path));
|
||||
g_free(tmp);
|
||||
|
||||
|
@ -2856,7 +2900,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
|
|||
goto error;
|
||||
}
|
||||
|
||||
trace_vfio_realize(vdev->vbasedev.name, groupid);
|
||||
trace_vfio_realize(vbasedev->name, groupid);
|
||||
|
||||
group = vfio_get_group(groupid, pci_device_iommu_address_space(pdev), errp);
|
||||
if (!group) {
|
||||
|
@ -2864,7 +2908,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
|
|||
}
|
||||
|
||||
QLIST_FOREACH(vbasedev_iter, &group->device_list, next) {
|
||||
if (strcmp(vbasedev_iter->name, vdev->vbasedev.name) == 0) {
|
||||
if (strcmp(vbasedev_iter->name, vbasedev->name) == 0) {
|
||||
error_setg(errp, "device is already attached");
|
||||
vfio_put_group(group);
|
||||
goto error;
|
||||
|
@ -2877,22 +2921,22 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
|
|||
* stays in sync with the active working set of the guest driver. Prevent
|
||||
* the x-balloon-allowed option unless this is minimally an mdev device.
|
||||
*/
|
||||
tmp = g_strdup_printf("%s/subsystem", vdev->vbasedev.sysfsdev);
|
||||
tmp = g_strdup_printf("%s/subsystem", vbasedev->sysfsdev);
|
||||
subsys = realpath(tmp, NULL);
|
||||
g_free(tmp);
|
||||
is_mdev = subsys && (strcmp(subsys, "/sys/bus/mdev") == 0);
|
||||
free(subsys);
|
||||
|
||||
trace_vfio_mdev(vdev->vbasedev.name, is_mdev);
|
||||
trace_vfio_mdev(vbasedev->name, is_mdev);
|
||||
|
||||
if (vdev->vbasedev.ram_block_discard_allowed && !is_mdev) {
|
||||
if (vbasedev->ram_block_discard_allowed && !is_mdev) {
|
||||
error_setg(errp, "x-balloon-allowed only potentially compatible "
|
||||
"with mdev devices");
|
||||
vfio_put_group(group);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = vfio_get_device(group, vdev->vbasedev.name, &vdev->vbasedev, errp);
|
||||
ret = vfio_get_device(group, vbasedev->name, vbasedev, errp);
|
||||
if (ret) {
|
||||
vfio_put_group(group);
|
||||
goto error;
|
||||
|
@ -2905,7 +2949,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
|
|||
}
|
||||
|
||||
/* Get a copy of config space */
|
||||
ret = pread(vdev->vbasedev.fd, vdev->pdev.config,
|
||||
ret = pread(vbasedev->fd, vdev->pdev.config,
|
||||
MIN(pci_config_size(&vdev->pdev), vdev->config_size),
|
||||
vdev->config_offset);
|
||||
if (ret < (int)MIN(pci_config_size(&vdev->pdev), vdev->config_size)) {
|
||||
|
@ -2933,7 +2977,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
|
|||
goto error;
|
||||
}
|
||||
vfio_add_emulated_word(vdev, PCI_VENDOR_ID, vdev->vendor_id, ~0);
|
||||
trace_vfio_pci_emulated_vendor_id(vdev->vbasedev.name, vdev->vendor_id);
|
||||
trace_vfio_pci_emulated_vendor_id(vbasedev->name, vdev->vendor_id);
|
||||
} else {
|
||||
vdev->vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID);
|
||||
}
|
||||
|
@ -2944,7 +2988,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
|
|||
goto error;
|
||||
}
|
||||
vfio_add_emulated_word(vdev, PCI_DEVICE_ID, vdev->device_id, ~0);
|
||||
trace_vfio_pci_emulated_device_id(vdev->vbasedev.name, vdev->device_id);
|
||||
trace_vfio_pci_emulated_device_id(vbasedev->name, vdev->device_id);
|
||||
} else {
|
||||
vdev->device_id = pci_get_word(pdev->config + PCI_DEVICE_ID);
|
||||
}
|
||||
|
@ -2956,7 +3000,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
|
|||
}
|
||||
vfio_add_emulated_word(vdev, PCI_SUBSYSTEM_VENDOR_ID,
|
||||
vdev->sub_vendor_id, ~0);
|
||||
trace_vfio_pci_emulated_sub_vendor_id(vdev->vbasedev.name,
|
||||
trace_vfio_pci_emulated_sub_vendor_id(vbasedev->name,
|
||||
vdev->sub_vendor_id);
|
||||
}
|
||||
|
||||
|
@ -2966,7 +3010,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
|
|||
goto error;
|
||||
}
|
||||
vfio_add_emulated_word(vdev, PCI_SUBSYSTEM_ID, vdev->sub_device_id, ~0);
|
||||
trace_vfio_pci_emulated_sub_device_id(vdev->vbasedev.name,
|
||||
trace_vfio_pci_emulated_sub_device_id(vbasedev->name,
|
||||
vdev->sub_device_id);
|
||||
}
|
||||
|
||||
|
@ -3025,7 +3069,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
|
|||
goto out_teardown;
|
||||
}
|
||||
|
||||
ret = vfio_get_dev_region_info(&vdev->vbasedev,
|
||||
ret = vfio_get_dev_region_info(vbasedev,
|
||||
VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL,
|
||||
VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION, &opregion);
|
||||
if (ret) {
|
||||
|
@ -3101,9 +3145,9 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
|
|||
}
|
||||
|
||||
if (!pdev->failover_pair_id) {
|
||||
ret = vfio_migration_probe(&vdev->vbasedev, errp);
|
||||
ret = vfio_migration_probe(vbasedev, errp);
|
||||
if (ret) {
|
||||
error_report("%s: Migration disabled", vdev->vbasedev.name);
|
||||
error_report("%s: Migration disabled", vbasedev->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3120,7 +3164,7 @@ out_teardown:
|
|||
vfio_teardown_msi(vdev);
|
||||
vfio_bars_exit(vdev);
|
||||
error:
|
||||
error_prepend(errp, VFIO_MSG_PREFIX, vdev->vbasedev.name);
|
||||
error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->name);
|
||||
}
|
||||
|
||||
static void vfio_instance_finalize(Object *obj)
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "qemu/queue.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qom/object.h"
|
||||
#include "sysemu/kvm.h"
|
||||
|
||||
#define PCI_ANY_ID (~0)
|
||||
|
||||
|
@ -171,6 +172,7 @@ struct VFIOPCIDevice {
|
|||
bool no_kvm_ioeventfd;
|
||||
bool no_vfio_ioeventfd;
|
||||
bool enable_ramfb;
|
||||
bool defer_kvm_irq_routing;
|
||||
VFIODisplay *dpy;
|
||||
Notifier irqchip_change_notifier;
|
||||
};
|
||||
|
|
|
@ -100,6 +100,7 @@ vfio_listener_region_add_skip(uint64_t start, uint64_t end) "SKIPPING region_add
|
|||
vfio_spapr_group_attach(int groupfd, int tablefd) "Attached groupfd %d to liobn fd %d"
|
||||
vfio_listener_region_add_iommu(uint64_t start, uint64_t end) "region_add [iommu] 0x%"PRIx64" - 0x%"PRIx64
|
||||
vfio_listener_region_add_ram(uint64_t iova_start, uint64_t iova_end, void *vaddr) "region_add [ram] 0x%"PRIx64" - 0x%"PRIx64" [%p]"
|
||||
vfio_known_safe_misalignment(const char *name, uint64_t iova, uint64_t offset_within_region, uintptr_t page_size) "Region \"%s\" iova=0x%"PRIx64" offset_within_region=0x%"PRIx64" qemu_real_host_page_size=0x%"PRIxPTR ": cannot be mapped for DMA"
|
||||
vfio_listener_region_add_no_dma_map(const char *name, uint64_t iova, uint64_t size, uint64_t page_size) "Region \"%s\" 0x%"PRIx64" size=0x%"PRIx64" is not aligned to 0x%"PRIx64" and cannot be mapped for DMA"
|
||||
vfio_listener_region_del_skip(uint64_t start, uint64_t end) "SKIPPING region_del 0x%"PRIx64" - 0x%"PRIx64
|
||||
vfio_listener_region_del(uint64_t start, uint64_t end) "region_del 0x%"PRIx64" - 0x%"PRIx64
|
||||
|
|
|
@ -98,7 +98,7 @@ typedef struct VFIOContainer {
|
|||
|
||||
typedef struct VFIOGuestIOMMU {
|
||||
VFIOContainer *container;
|
||||
IOMMUMemoryRegion *iommu;
|
||||
IOMMUMemoryRegion *iommu_mr;
|
||||
hwaddr iommu_offset;
|
||||
IOMMUNotifier n;
|
||||
QLIST_ENTRY(VFIOGuestIOMMU) giommu_next;
|
||||
|
|
|
@ -80,6 +80,12 @@ static inline TPMVersion tpm_get_version(TPMIf *ti)
|
|||
#define tpm_init() (0)
|
||||
#define tpm_cleanup()
|
||||
|
||||
/* needed for an alignment check in non-tpm code */
|
||||
static inline Object *TPM_IS_CRB(Object *obj)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_TPM */
|
||||
|
||||
#endif /* QEMU_TPM_H */
|
||||
|
|
Loading…
Reference in New Issue