When the vfio_iommu_type1 supports the VFIO_IOMMU_INFO_CAPABILITIES and the capability ID VFIO_IOMMU_INFO_CAP_DMA we can use an ioctl to retrieve this information from the real IOMMU device.
Let's use this information to add the host window associated with the container. Signed-off-by: Pierre Morel <pmo...@linux.ibm.com> --- hw/vfio/common.c | 73 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 17 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 7c185e5a..fd7e991 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1036,6 +1036,61 @@ static void vfio_put_address_space(VFIOAddressSpace *space) } } +static void vfio_iommu_type1_get_info(int fd, VFIOContainer *container) +{ + struct vfio_iommu_type1_info *info; + size_t argsz = sizeof(*info); + struct vfio_info_cap_header *hdr; + struct vfio_iommu_cap_dma *dma_info; + int ret = 0; + + info = g_malloc0(argsz); + +retry: + info->argsz = argsz; + info->flags = VFIO_IOMMU_INFO_CAPABILITIES; + + ret = ioctl(fd, VFIO_IOMMU_GET_INFO, info); + /* Ignore errors */ + if (ret) { + goto out; + } + if (!(info->flags & VFIO_IOMMU_INFO_PGSIZES)) { + info->iova_pgsizes = 4096; + } + + if (info->argsz > argsz) { + argsz = info->argsz; + info = g_realloc(info, argsz); + + goto retry; + } + if (info->argsz != argsz) { + goto out; + } + /* Now we have the capabilities */ + hdr = (struct vfio_info_cap_header *)((unsigned char *)info + + sizeof(struct vfio_iommu_type1_info) + + info->cap_offset); + do { + dma_info = (struct vfio_iommu_cap_dma *) (hdr); + if (hdr->id == VFIO_IOMMU_INFO_CAP_DMA) { + vfio_host_win_add(container, 0, + dma_info->dma_end - dma_info->dma_start, + info->iova_pgsizes); + container->pgsizes = info->iova_pgsizes; + return; + } + hdr = (struct vfio_info_cap_header *)((unsigned char *) dma_info + + hdr->next); + } while (hdr->next); +out: + /* Assume 4k IOVA page size */ + vfio_host_win_add(container, 0, (hwaddr)-1, 4096); + container->pgsizes = 4096; + return; +} + static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, Error **errp) { @@ -1104,7 +1159,6 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU) || ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1v2_IOMMU)) { bool v2 = !!ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1v2_IOMMU); - struct vfio_iommu_type1_info info; ret = ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &fd); if (ret) { @@ -1121,22 +1175,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as, goto free_container_exit; } - /* - * FIXME: This assumes that a Type1 IOMMU can map any 64-bit - * IOVA whatsoever. That's not actually true, but the current - * kernel interface doesn't tell us what it can map, and the - * existing Type1 IOMMUs generally support any IOVA we're - * going to actually try in practice. - */ - info.argsz = sizeof(info); - ret = ioctl(fd, VFIO_IOMMU_GET_INFO, &info); - /* Ignore errors */ - if (ret || !(info.flags & VFIO_IOMMU_INFO_PGSIZES)) { - /* Assume 4k IOVA page size */ - info.iova_pgsizes = 4096; - } - vfio_host_win_add(container, 0, (hwaddr)-1, info.iova_pgsizes); - container->pgsizes = info.iova_pgsizes; + vfio_iommu_type1_get_info(fd, container); } else if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_IOMMU) || ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_v2_IOMMU)) { struct vfio_iommu_spapr_tce_info info; -- 2.7.4