vfio queue:

* Fixes on VFIO display
 * VIRTIO-IOMMU/HostIOMMUDevice: Fixes and page size mask rework
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmaNI6MACgkQUaNDx8/7
 7KHMCQ//VrdayFV9psHCCkrku3MQL6VWsiTOf6bgOFz4zp716HQrnZlI6A7L1qFz
 p2OH6bQu9IDa8T65TVyQ/u6LL3VkZGAcji++YQQHYD1uNZryURq7IosxmoLnb5L/
 FcBp22rmYx7/0nBF8VW6SttVXAlVAmxe1dwEdmQNL+YJDmhayS7lTiUgx3mWjgUZ
 0lSvz5w+LWZIuHKLK/o0Fo8Lr4y63nCUxPukl46mjntciEd16zpaCv4ySCf/y83q
 MtRiBhD1+zuV9Kzla1CpwwRKPGccimksXGpmdAVGTUmzfK/ElA8sMB5KDFVDEhdD
 6iqWcdP7MdZIsCC9qXaOqLPyeqSYZ58LgqUOt4tTW9eiGf6eORqHNRqtStR98pDl
 W+SfCj6AY8wRktKSldb+BKE+XJ/7AD24Lxz2iD6RI7hWwWnalu9z6XpZD1QMqUvw
 h+XjIycp1bNgm7i5indA2B1zotT9ebI8AEEAUMbQOMrtMWqZzGORfI8rhS1s4A+B
 Kh37ll6jAVtYgaifercDQa/PFYyp4dIFZDbWt4WiFYxX51YkpnI3GJKDmIT2or7u
 X2o43rk9sp4xHlsge4pT7epoDzgmuv6fIygfxSPKOp9znrWlAVMX7DniN92SnRke
 xyvCxE2Jps9p0Y7cfaM4VZsWIgHk+IB3hr4wrlRwRKa3sPH4fwU=
 =glZK
 -----END PGP SIGNATURE-----

Merge tag 'pull-vfio-20240709' of https://github.com/legoater/qemu into staging

vfio queue:

* Fixes on VFIO display
* VIRTIO-IOMMU/HostIOMMUDevice: Fixes and page size mask rework

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmaNI6MACgkQUaNDx8/7
# 7KHMCQ//VrdayFV9psHCCkrku3MQL6VWsiTOf6bgOFz4zp716HQrnZlI6A7L1qFz
# p2OH6bQu9IDa8T65TVyQ/u6LL3VkZGAcji++YQQHYD1uNZryURq7IosxmoLnb5L/
# FcBp22rmYx7/0nBF8VW6SttVXAlVAmxe1dwEdmQNL+YJDmhayS7lTiUgx3mWjgUZ
# 0lSvz5w+LWZIuHKLK/o0Fo8Lr4y63nCUxPukl46mjntciEd16zpaCv4ySCf/y83q
# MtRiBhD1+zuV9Kzla1CpwwRKPGccimksXGpmdAVGTUmzfK/ElA8sMB5KDFVDEhdD
# 6iqWcdP7MdZIsCC9qXaOqLPyeqSYZ58LgqUOt4tTW9eiGf6eORqHNRqtStR98pDl
# W+SfCj6AY8wRktKSldb+BKE+XJ/7AD24Lxz2iD6RI7hWwWnalu9z6XpZD1QMqUvw
# h+XjIycp1bNgm7i5indA2B1zotT9ebI8AEEAUMbQOMrtMWqZzGORfI8rhS1s4A+B
# Kh37ll6jAVtYgaifercDQa/PFYyp4dIFZDbWt4WiFYxX51YkpnI3GJKDmIT2or7u
# X2o43rk9sp4xHlsge4pT7epoDzgmuv6fIygfxSPKOp9znrWlAVMX7DniN92SnRke
# xyvCxE2Jps9p0Y7cfaM4VZsWIgHk+IB3hr4wrlRwRKa3sPH4fwU=
# =glZK
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 09 Jul 2024 04:48:51 AM PDT
# gpg:                using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1
# gpg: Good signature from "Cédric Le Goater <clg@kaod.org>" [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: A0F6 6548 F048 95EB FE6B  0B60 51A3 43C7 CFFB ECA1

* tag 'pull-vfio-20240709' of https://github.com/legoater/qemu:
  vfio/display: Fix vfio_display_edid_init() error path
  vfio/display: Fix potential memleak of edid info
  virtio-iommu: Revert transient enablement of IOMMU MR in bypass mode
  memory: remove IOMMU MR iommu_set_page_size_mask() callback
  virtio-iommu : Retrieve page size mask on virtio_iommu_set_iommu_device()
  HostIOMMUDevice: Introduce get_page_size_mask() callback
  HostIOMMUDevice : remove Error handle from get_iova_ranges callback
  vfio-container-base: Introduce vfio_container_get_iova_ranges() helper
  virtio-iommu: Fix error handling in virtio_iommu_set_host_iova_ranges()

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2024-07-09 07:13:14 -07:00
commit 4a3eceb403
11 changed files with 129 additions and 143 deletions

View File

@ -622,14 +622,6 @@ static void vfio_listener_region_add(MemoryListener *listener,
int128_get64(llend),
iommu_idx);
ret = memory_region_iommu_set_page_size_mask(giommu->iommu_mr,
bcontainer->pgsizes,
&err);
if (ret) {
g_free(giommu);
goto fail;
}
ret = memory_region_register_iommu_notifier(section->mr, &giommu->n,
&err);
if (ret) {

View File

@ -83,6 +83,21 @@ int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
errp);
}
static gpointer copy_iova_range(gconstpointer src, gpointer data)
{
Range *source = (Range *)src;
Range *dest = g_new(Range, 1);
range_set_bounds(dest, range_lob(source), range_upb(source));
return dest;
}
GList *vfio_container_get_iova_ranges(const VFIOContainerBase *bcontainer)
{
assert(bcontainer);
return g_list_copy_deep(bcontainer->iova_ranges, copy_iova_range, NULL);
}
static void vfio_container_instance_finalize(Object *obj)
{
VFIOContainerBase *bcontainer = VFIO_IOMMU(obj);

View File

@ -1165,18 +1165,21 @@ static int hiod_legacy_vfio_get_cap(HostIOMMUDevice *hiod, int cap,
}
static GList *
hiod_legacy_vfio_get_iova_ranges(HostIOMMUDevice *hiod, Error **errp)
hiod_legacy_vfio_get_iova_ranges(HostIOMMUDevice *hiod)
{
VFIODevice *vdev = hiod->agent;
GList *l = NULL;
g_assert(vdev);
return vfio_container_get_iova_ranges(vdev->bcontainer);
}
if (vdev->bcontainer) {
l = g_list_copy(vdev->bcontainer->iova_ranges);
}
static uint64_t
hiod_legacy_vfio_get_page_size_mask(HostIOMMUDevice *hiod)
{
VFIODevice *vdev = hiod->agent;
return l;
g_assert(vdev);
return vfio_container_get_page_size_mask(vdev->bcontainer);
}
static void vfio_iommu_legacy_instance_init(Object *obj)
@ -1193,6 +1196,7 @@ static void hiod_legacy_vfio_class_init(ObjectClass *oc, void *data)
hioc->realize = hiod_legacy_vfio_realize;
hioc->get_cap = hiod_legacy_vfio_get_cap;
hioc->get_iova_ranges = hiod_legacy_vfio_get_iova_ranges;
hioc->get_page_size_mask = hiod_legacy_vfio_get_page_size_mask;
};
static const TypeInfo types[] = {

View File

@ -124,7 +124,7 @@ static void vfio_display_edid_ui_info(void *opaque, uint32_t idx,
}
}
static void vfio_display_edid_init(VFIOPCIDevice *vdev)
static bool vfio_display_edid_init(VFIOPCIDevice *vdev, Error **errp)
{
VFIODisplay *dpy = vdev->dpy;
int fd = vdev->vbasedev.fd;
@ -135,7 +135,8 @@ static void vfio_display_edid_init(VFIOPCIDevice *vdev)
VFIO_REGION_SUBTYPE_GFX_EDID,
&dpy->edid_info);
if (ret) {
return;
/* Failed to get GFX edid info, allow to go through without edid. */
return true;
}
trace_vfio_display_edid_available();
@ -167,13 +168,16 @@ static void vfio_display_edid_init(VFIOPCIDevice *vdev)
vfio_display_edid_link_up, vdev);
vfio_display_edid_update(vdev, true, 0, 0);
return;
return true;
err:
error_setg(errp, "vfio: failed to read GFX edid field");
trace_vfio_display_edid_write_error();
g_free(dpy->edid_info);
g_free(dpy->edid_regs);
dpy->edid_info = NULL;
dpy->edid_regs = NULL;
return;
return false;
}
static void vfio_display_edid_exit(VFIODisplay *dpy)
@ -182,6 +186,7 @@ static void vfio_display_edid_exit(VFIODisplay *dpy)
return;
}
g_free(dpy->edid_info);
g_free(dpy->edid_regs);
g_free(dpy->edid_blob);
timer_free(dpy->edid_link_timer);
@ -365,8 +370,7 @@ static bool vfio_display_dmabuf_init(VFIOPCIDevice *vdev, Error **errp)
return false;
}
}
vfio_display_edid_init(vdev);
return true;
return vfio_display_edid_init(vdev, errp);
}
static void vfio_display_dmabuf_exit(VFIODisplay *dpy)

View File

@ -644,26 +644,31 @@ static bool hiod_iommufd_vfio_realize(HostIOMMUDevice *hiod, void *opaque,
}
static GList *
hiod_iommufd_vfio_get_iova_ranges(HostIOMMUDevice *hiod, Error **errp)
hiod_iommufd_vfio_get_iova_ranges(HostIOMMUDevice *hiod)
{
VFIODevice *vdev = hiod->agent;
GList *l = NULL;
g_assert(vdev);
if (vdev->bcontainer) {
l = g_list_copy(vdev->bcontainer->iova_ranges);
}
return l;
return vfio_container_get_iova_ranges(vdev->bcontainer);
}
static uint64_t
hiod_iommufd_vfio_get_page_size_mask(HostIOMMUDevice *hiod)
{
VFIODevice *vdev = hiod->agent;
g_assert(vdev);
return vfio_container_get_page_size_mask(vdev->bcontainer);
}
static void hiod_iommufd_vfio_class_init(ObjectClass *oc, void *data)
{
HostIOMMUDeviceClass *hiodc = HOST_IOMMU_DEVICE_CLASS(oc);
hiodc->realize = hiod_iommufd_vfio_realize;
hiodc->get_iova_ranges = hiod_iommufd_vfio_get_iova_ranges;
hiodc->get_page_size_mask = hiod_iommufd_vfio_get_page_size_mask;
};
static const TypeInfo types[] = {

View File

@ -131,7 +131,7 @@ virtio_iommu_fill_resv_property(uint32_t devid, uint8_t subtype, uint64_t start,
virtio_iommu_notify_map(const char *name, uint64_t virt_start, uint64_t virt_end, uint64_t phys_start, uint32_t flags) "mr=%s virt_start=0x%"PRIx64" virt_end=0x%"PRIx64" phys_start=0x%"PRIx64" flags=%d"
virtio_iommu_notify_unmap(const char *name, uint64_t virt_start, uint64_t virt_end) "mr=%s virt_start=0x%"PRIx64" virt_end=0x%"PRIx64
virtio_iommu_remap(const char *name, uint64_t virt_start, uint64_t virt_end, uint64_t phys_start) "mr=%s virt_start=0x%"PRIx64" virt_end=0x%"PRIx64" phys_start=0x%"PRIx64
virtio_iommu_set_page_size_mask(const char *name, uint64_t old, uint64_t new) "mr=%s old_mask=0x%"PRIx64" new_mask=0x%"PRIx64
virtio_iommu_update_page_size_mask(const char *name, uint64_t old, uint64_t new) "host iommu device=%s old_mask=0x%"PRIx64" new_mask=0x%"PRIx64
virtio_iommu_notify_flag_add(const char *name) "add notifier to mr %s"
virtio_iommu_notify_flag_del(const char *name) "del notifier from mr %s"
virtio_iommu_switch_address_space(uint8_t bus, uint8_t slot, uint8_t fn, bool on) "Device %02x:%02x.%x switching address space (iommu enabled=%d)"

View File

@ -563,10 +563,15 @@ static int virtio_iommu_set_host_iova_ranges(VirtIOIOMMU *s, PCIBus *bus,
int ret = -EINVAL;
if (!sbus) {
error_report("%s no sbus", __func__);
error_setg(errp, "%s: no IOMMUPciBus found!", __func__);
return ret;
}
sdev = sbus->pbdev[devfn];
if (!sdev) {
error_setg(errp, "%s: no IOMMUDevice found!", __func__);
return ret;
}
current_ranges = sdev->host_resv_ranges;
@ -613,9 +618,39 @@ out:
return ret;
}
static bool check_page_size_mask(VirtIOIOMMU *viommu, uint64_t new_mask,
Error **errp)
{
uint64_t cur_mask = viommu->config.page_size_mask;
if ((cur_mask & new_mask) == 0) {
error_setg(errp, "virtio-iommu reports a page size mask 0x%"PRIx64
" incompatible with currently supported mask 0x%"PRIx64,
new_mask, cur_mask);
return false;
}
/*
* Once the granule is frozen we can't change the mask anymore. If by
* chance the hotplugged device supports the same granule, we can still
* accept it.
*/
if (viommu->granule_frozen) {
int cur_granule = ctz64(cur_mask);
if (!(BIT_ULL(cur_granule) & new_mask)) {
error_setg(errp,
"virtio-iommu does not support frozen granule 0x%llx",
BIT_ULL(cur_granule));
return false;
}
}
return true;
}
static bool virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
HostIOMMUDevice *hiod, Error **errp)
{
ERRP_GUARD();
VirtIOIOMMU *viommu = opaque;
HostIOMMUDeviceClass *hiodc = HOST_IOMMU_DEVICE_GET_CLASS(hiod);
struct hiod_key *new_key;
@ -630,7 +665,7 @@ static bool virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
if (hiodc->get_iova_ranges) {
int ret;
host_iova_ranges = hiodc->get_iova_ranges(hiod, errp);
host_iova_ranges = hiodc->get_iova_ranges(hiod);
if (!host_iova_ranges) {
return true; /* some old kernels may not support that capability */
}
@ -638,8 +673,28 @@ static bool virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
hiod->aliased_devfn,
host_iova_ranges, errp);
if (ret) {
g_list_free_full(host_iova_ranges, g_free);
return false;
goto error;
}
}
if (hiodc->get_page_size_mask) {
uint64_t new_mask = hiodc->get_page_size_mask(hiod);
if (check_page_size_mask(viommu, new_mask, errp)) {
/*
* The default mask depends on the "granule" property. For example,
* with 4k granule, it is -(4 * KiB). When an assigned device has
* page size restrictions due to the hardware IOMMU configuration,
* apply this restriction to the mask.
*/
trace_virtio_iommu_update_page_size_mask(hiod->name,
viommu->config.page_size_mask,
new_mask);
if (!viommu->granule_frozen) {
viommu->config.page_size_mask &= new_mask;
}
} else {
error_prepend(errp, "%s: ", hiod->name);
goto error;
}
}
@ -652,6 +707,9 @@ static bool virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
g_list_free_full(host_iova_ranges, g_free);
return true;
error:
g_list_free_full(host_iova_ranges, g_free);
return false;
}
static void
@ -1350,50 +1408,6 @@ static int virtio_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu_mr,
return 0;
}
/*
* The default mask depends on the "granule" property. For example, with
* 4k granule, it is -(4 * KiB). When an assigned device has page size
* restrictions due to the hardware IOMMU configuration, apply this restriction
* to the mask.
*/
static int virtio_iommu_set_page_size_mask(IOMMUMemoryRegion *mr,
uint64_t new_mask,
Error **errp)
{
IOMMUDevice *sdev = container_of(mr, IOMMUDevice, iommu_mr);
VirtIOIOMMU *s = sdev->viommu;
uint64_t cur_mask = s->config.page_size_mask;
trace_virtio_iommu_set_page_size_mask(mr->parent_obj.name, cur_mask,
new_mask);
if ((cur_mask & new_mask) == 0) {
error_setg(errp, "virtio-iommu %s reports a page size mask 0x%"PRIx64
" incompatible with currently supported mask 0x%"PRIx64,
mr->parent_obj.name, new_mask, cur_mask);
return -1;
}
/*
* Once the granule is frozen we can't change the mask anymore. If by
* chance the hotplugged device supports the same granule, we can still
* accept it.
*/
if (s->granule_frozen) {
int cur_granule = ctz64(cur_mask);
if (!(BIT_ULL(cur_granule) & new_mask)) {
error_setg(errp, "virtio-iommu %s does not support frozen granule 0x%llx",
mr->parent_obj.name, BIT_ULL(cur_granule));
return -1;
}
return 0;
}
s->config.page_size_mask &= new_mask;
return 0;
}
static void virtio_iommu_system_reset(void *opaque)
{
VirtIOIOMMU *s = opaque;
@ -1416,18 +1430,6 @@ static void virtio_iommu_freeze_granule(Notifier *notifier, void *data)
VirtIOIOMMU *s = container_of(notifier, VirtIOIOMMU, machine_done);
int granule;
if (likely(s->config.bypass)) {
/*
* Transient IOMMU MR enable to collect page_size_mask requirements
* through memory_region_iommu_set_page_size_mask() called by
* VFIO region_add() callback
*/
s->config.bypass = false;
virtio_iommu_switch_address_space_all(s);
/* restore default */
s->config.bypass = true;
virtio_iommu_switch_address_space_all(s);
}
s->granule_frozen = true;
granule = ctz64(s->config.page_size_mask);
trace_virtio_iommu_freeze_granule(BIT_ULL(granule));
@ -1718,7 +1720,6 @@ static void virtio_iommu_memory_region_class_init(ObjectClass *klass,
imrc->translate = virtio_iommu_translate;
imrc->replay = virtio_iommu_replay;
imrc->notify_flag_changed = virtio_iommu_notify_flag_changed;
imrc->iommu_set_page_size_mask = virtio_iommu_set_page_size_mask;
}
static const TypeInfo virtio_iommu_info = {

View File

@ -504,32 +504,6 @@ struct IOMMUMemoryRegionClass {
* @iommu: the IOMMUMemoryRegion
*/
int (*num_indexes)(IOMMUMemoryRegion *iommu);
/**
* @iommu_set_page_size_mask:
*
* Restrict the page size mask that can be supported with a given IOMMU
* memory region. Used for example to propagate host physical IOMMU page
* size mask limitations to the virtual IOMMU.
*
* Optional method: if this method is not provided, then the default global
* page mask is used.
*
* @iommu: the IOMMUMemoryRegion
*
* @page_size_mask: a bitmask of supported page sizes. At least one bit,
* representing the smallest page size, must be set. Additional set bits
* represent supported block sizes. For example a host physical IOMMU that
* uses page tables with a page size of 4kB, and supports 2MB and 4GB
* blocks, will set mask 0x40201000. A granule of 4kB with indiscriminate
* block sizes is specified with mask 0xfffffffffffff000.
*
* Returns 0 on success, or a negative error. In case of failure, the error
* object must be created.
*/
int (*iommu_set_page_size_mask)(IOMMUMemoryRegion *iommu,
uint64_t page_size_mask,
Error **errp);
};
typedef struct RamDiscardListener RamDiscardListener;
@ -1919,18 +1893,6 @@ int memory_region_iommu_attrs_to_index(IOMMUMemoryRegion *iommu_mr,
*/
int memory_region_iommu_num_indexes(IOMMUMemoryRegion *iommu_mr);
/**
* memory_region_iommu_set_page_size_mask: set the supported page
* sizes for a given IOMMU memory region
*
* @iommu_mr: IOMMU memory region
* @page_size_mask: supported page size mask
* @errp: pointer to Error*, to store an error if it happens.
*/
int memory_region_iommu_set_page_size_mask(IOMMUMemoryRegion *iommu_mr,
uint64_t page_size_mask,
Error **errp);
/**
* memory_region_name: get a memory region's name
*

View File

@ -86,6 +86,15 @@ int vfio_container_set_dirty_page_tracking(VFIOContainerBase *bcontainer,
int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp);
GList *vfio_container_get_iova_ranges(const VFIOContainerBase *bcontainer);
static inline uint64_t
vfio_container_get_page_size_mask(const VFIOContainerBase *bcontainer)
{
assert(bcontainer);
return bcontainer->pgsizes;
}
#define TYPE_VFIO_IOMMU "vfio-iommu"
#define TYPE_VFIO_IOMMU_LEGACY TYPE_VFIO_IOMMU "-legacy"
#define TYPE_VFIO_IOMMU_SPAPR TYPE_VFIO_IOMMU "-spapr"

View File

@ -87,9 +87,16 @@ struct HostIOMMUDeviceClass {
* @hiod Host IOMMU device
*
* @hiod: handle to the host IOMMU device
* @errp: error handle
*/
GList* (*get_iova_ranges)(HostIOMMUDevice *hiod, Error **errp);
GList* (*get_iova_ranges)(HostIOMMUDevice *hiod);
/**
*
* @get_page_size_mask: Return the page size mask supported along this
* @hiod Host IOMMU device
*
* @hiod: handle to the host IOMMU device
*/
uint64_t (*get_page_size_mask)(HostIOMMUDevice *hiod);
};
/*

View File

@ -1901,19 +1901,6 @@ static int memory_region_update_iommu_notify_flags(IOMMUMemoryRegion *iommu_mr,
return ret;
}
int memory_region_iommu_set_page_size_mask(IOMMUMemoryRegion *iommu_mr,
uint64_t page_size_mask,
Error **errp)
{
IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
int ret = 0;
if (imrc->iommu_set_page_size_mask) {
ret = imrc->iommu_set_page_size_mask(iommu_mr, page_size_mask, errp);
}
return ret;
}
int memory_region_register_iommu_notifier(MemoryRegion *mr,
IOMMUNotifier *n, Error **errp)
{