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:
commit
4a3eceb403
@ -622,14 +622,6 @@ static void vfio_listener_region_add(MemoryListener *listener,
|
|||||||
int128_get64(llend),
|
int128_get64(llend),
|
||||||
iommu_idx);
|
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,
|
ret = memory_region_register_iommu_notifier(section->mr, &giommu->n,
|
||||||
&err);
|
&err);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -83,6 +83,21 @@ int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
|
|||||||
errp);
|
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)
|
static void vfio_container_instance_finalize(Object *obj)
|
||||||
{
|
{
|
||||||
VFIOContainerBase *bcontainer = VFIO_IOMMU(obj);
|
VFIOContainerBase *bcontainer = VFIO_IOMMU(obj);
|
||||||
|
@ -1165,18 +1165,21 @@ static int hiod_legacy_vfio_get_cap(HostIOMMUDevice *hiod, int cap,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static GList *
|
static GList *
|
||||||
hiod_legacy_vfio_get_iova_ranges(HostIOMMUDevice *hiod, Error **errp)
|
hiod_legacy_vfio_get_iova_ranges(HostIOMMUDevice *hiod)
|
||||||
{
|
{
|
||||||
VFIODevice *vdev = hiod->agent;
|
VFIODevice *vdev = hiod->agent;
|
||||||
GList *l = NULL;
|
|
||||||
|
|
||||||
g_assert(vdev);
|
g_assert(vdev);
|
||||||
|
return vfio_container_get_iova_ranges(vdev->bcontainer);
|
||||||
|
}
|
||||||
|
|
||||||
if (vdev->bcontainer) {
|
static uint64_t
|
||||||
l = g_list_copy(vdev->bcontainer->iova_ranges);
|
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)
|
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->realize = hiod_legacy_vfio_realize;
|
||||||
hioc->get_cap = hiod_legacy_vfio_get_cap;
|
hioc->get_cap = hiod_legacy_vfio_get_cap;
|
||||||
hioc->get_iova_ranges = hiod_legacy_vfio_get_iova_ranges;
|
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[] = {
|
static const TypeInfo types[] = {
|
||||||
|
@ -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;
|
VFIODisplay *dpy = vdev->dpy;
|
||||||
int fd = vdev->vbasedev.fd;
|
int fd = vdev->vbasedev.fd;
|
||||||
@ -135,7 +135,8 @@ static void vfio_display_edid_init(VFIOPCIDevice *vdev)
|
|||||||
VFIO_REGION_SUBTYPE_GFX_EDID,
|
VFIO_REGION_SUBTYPE_GFX_EDID,
|
||||||
&dpy->edid_info);
|
&dpy->edid_info);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
return;
|
/* Failed to get GFX edid info, allow to go through without edid. */
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
trace_vfio_display_edid_available();
|
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_link_up, vdev);
|
||||||
|
|
||||||
vfio_display_edid_update(vdev, true, 0, 0);
|
vfio_display_edid_update(vdev, true, 0, 0);
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
error_setg(errp, "vfio: failed to read GFX edid field");
|
||||||
trace_vfio_display_edid_write_error();
|
trace_vfio_display_edid_write_error();
|
||||||
|
g_free(dpy->edid_info);
|
||||||
g_free(dpy->edid_regs);
|
g_free(dpy->edid_regs);
|
||||||
|
dpy->edid_info = NULL;
|
||||||
dpy->edid_regs = NULL;
|
dpy->edid_regs = NULL;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vfio_display_edid_exit(VFIODisplay *dpy)
|
static void vfio_display_edid_exit(VFIODisplay *dpy)
|
||||||
@ -182,6 +186,7 @@ static void vfio_display_edid_exit(VFIODisplay *dpy)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_free(dpy->edid_info);
|
||||||
g_free(dpy->edid_regs);
|
g_free(dpy->edid_regs);
|
||||||
g_free(dpy->edid_blob);
|
g_free(dpy->edid_blob);
|
||||||
timer_free(dpy->edid_link_timer);
|
timer_free(dpy->edid_link_timer);
|
||||||
@ -365,8 +370,7 @@ static bool vfio_display_dmabuf_init(VFIOPCIDevice *vdev, Error **errp)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vfio_display_edid_init(vdev);
|
return vfio_display_edid_init(vdev, errp);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vfio_display_dmabuf_exit(VFIODisplay *dpy)
|
static void vfio_display_dmabuf_exit(VFIODisplay *dpy)
|
||||||
|
@ -644,26 +644,31 @@ static bool hiod_iommufd_vfio_realize(HostIOMMUDevice *hiod, void *opaque,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static GList *
|
static GList *
|
||||||
hiod_iommufd_vfio_get_iova_ranges(HostIOMMUDevice *hiod, Error **errp)
|
hiod_iommufd_vfio_get_iova_ranges(HostIOMMUDevice *hiod)
|
||||||
{
|
{
|
||||||
VFIODevice *vdev = hiod->agent;
|
VFIODevice *vdev = hiod->agent;
|
||||||
GList *l = NULL;
|
|
||||||
|
|
||||||
g_assert(vdev);
|
g_assert(vdev);
|
||||||
|
return vfio_container_get_iova_ranges(vdev->bcontainer);
|
||||||
if (vdev->bcontainer) {
|
|
||||||
l = g_list_copy(vdev->bcontainer->iova_ranges);
|
|
||||||
}
|
|
||||||
|
|
||||||
return l;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
static void hiod_iommufd_vfio_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
HostIOMMUDeviceClass *hiodc = HOST_IOMMU_DEVICE_CLASS(oc);
|
HostIOMMUDeviceClass *hiodc = HOST_IOMMU_DEVICE_CLASS(oc);
|
||||||
|
|
||||||
hiodc->realize = hiod_iommufd_vfio_realize;
|
hiodc->realize = hiod_iommufd_vfio_realize;
|
||||||
hiodc->get_iova_ranges = hiod_iommufd_vfio_get_iova_ranges;
|
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[] = {
|
static const TypeInfo types[] = {
|
||||||
|
@ -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_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_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_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_add(const char *name) "add notifier to mr %s"
|
||||||
virtio_iommu_notify_flag_del(const char *name) "del notifier from 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)"
|
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)"
|
||||||
|
@ -563,10 +563,15 @@ static int virtio_iommu_set_host_iova_ranges(VirtIOIOMMU *s, PCIBus *bus,
|
|||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
if (!sbus) {
|
if (!sbus) {
|
||||||
error_report("%s no sbus", __func__);
|
error_setg(errp, "%s: no IOMMUPciBus found!", __func__);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
sdev = sbus->pbdev[devfn];
|
sdev = sbus->pbdev[devfn];
|
||||||
|
if (!sdev) {
|
||||||
|
error_setg(errp, "%s: no IOMMUDevice found!", __func__);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
current_ranges = sdev->host_resv_ranges;
|
current_ranges = sdev->host_resv_ranges;
|
||||||
|
|
||||||
@ -613,9 +618,39 @@ out:
|
|||||||
return ret;
|
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,
|
static bool virtio_iommu_set_iommu_device(PCIBus *bus, void *opaque, int devfn,
|
||||||
HostIOMMUDevice *hiod, Error **errp)
|
HostIOMMUDevice *hiod, Error **errp)
|
||||||
{
|
{
|
||||||
|
ERRP_GUARD();
|
||||||
VirtIOIOMMU *viommu = opaque;
|
VirtIOIOMMU *viommu = opaque;
|
||||||
HostIOMMUDeviceClass *hiodc = HOST_IOMMU_DEVICE_GET_CLASS(hiod);
|
HostIOMMUDeviceClass *hiodc = HOST_IOMMU_DEVICE_GET_CLASS(hiod);
|
||||||
struct hiod_key *new_key;
|
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) {
|
if (hiodc->get_iova_ranges) {
|
||||||
int ret;
|
int ret;
|
||||||
host_iova_ranges = hiodc->get_iova_ranges(hiod, errp);
|
host_iova_ranges = hiodc->get_iova_ranges(hiod);
|
||||||
if (!host_iova_ranges) {
|
if (!host_iova_ranges) {
|
||||||
return true; /* some old kernels may not support that capability */
|
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,
|
hiod->aliased_devfn,
|
||||||
host_iova_ranges, errp);
|
host_iova_ranges, errp);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
g_list_free_full(host_iova_ranges, g_free);
|
goto error;
|
||||||
return false;
|
}
|
||||||
|
}
|
||||||
|
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);
|
g_list_free_full(host_iova_ranges, g_free);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
error:
|
||||||
|
g_list_free_full(host_iova_ranges, g_free);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1350,50 +1408,6 @@ static int virtio_iommu_notify_flag_changed(IOMMUMemoryRegion *iommu_mr,
|
|||||||
return 0;
|
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)
|
static void virtio_iommu_system_reset(void *opaque)
|
||||||
{
|
{
|
||||||
VirtIOIOMMU *s = 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);
|
VirtIOIOMMU *s = container_of(notifier, VirtIOIOMMU, machine_done);
|
||||||
int granule;
|
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;
|
s->granule_frozen = true;
|
||||||
granule = ctz64(s->config.page_size_mask);
|
granule = ctz64(s->config.page_size_mask);
|
||||||
trace_virtio_iommu_freeze_granule(BIT_ULL(granule));
|
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->translate = virtio_iommu_translate;
|
||||||
imrc->replay = virtio_iommu_replay;
|
imrc->replay = virtio_iommu_replay;
|
||||||
imrc->notify_flag_changed = virtio_iommu_notify_flag_changed;
|
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 = {
|
static const TypeInfo virtio_iommu_info = {
|
||||||
|
@ -504,32 +504,6 @@ struct IOMMUMemoryRegionClass {
|
|||||||
* @iommu: the IOMMUMemoryRegion
|
* @iommu: the IOMMUMemoryRegion
|
||||||
*/
|
*/
|
||||||
int (*num_indexes)(IOMMUMemoryRegion *iommu);
|
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;
|
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);
|
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
|
* memory_region_name: get a memory region's name
|
||||||
*
|
*
|
||||||
|
@ -86,6 +86,15 @@ int vfio_container_set_dirty_page_tracking(VFIOContainerBase *bcontainer,
|
|||||||
int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
|
int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer,
|
||||||
VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp);
|
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 "vfio-iommu"
|
||||||
#define TYPE_VFIO_IOMMU_LEGACY TYPE_VFIO_IOMMU "-legacy"
|
#define TYPE_VFIO_IOMMU_LEGACY TYPE_VFIO_IOMMU "-legacy"
|
||||||
#define TYPE_VFIO_IOMMU_SPAPR TYPE_VFIO_IOMMU "-spapr"
|
#define TYPE_VFIO_IOMMU_SPAPR TYPE_VFIO_IOMMU "-spapr"
|
||||||
|
@ -87,9 +87,16 @@ struct HostIOMMUDeviceClass {
|
|||||||
* @hiod Host IOMMU device
|
* @hiod Host IOMMU device
|
||||||
*
|
*
|
||||||
* @hiod: handle to the 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);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1901,19 +1901,6 @@ static int memory_region_update_iommu_notify_flags(IOMMUMemoryRegion *iommu_mr,
|
|||||||
return ret;
|
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,
|
int memory_region_register_iommu_notifier(MemoryRegion *mr,
|
||||||
IOMMUNotifier *n, Error **errp)
|
IOMMUNotifier *n, Error **errp)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user