iommu: Reject drivers with broken_unmanaged_domain
Subsystems (20)
cover iommu: Reject drivers with broken_unmanaged_domain
Hi all,
Both IOMMU_DOMAIN_UNMANAGED and IOMMU_DOMAIN_DMA require the support of __IOMMU_DOMAIN_PAGING capability, i.e. iommu_map/unmap. However, some older iommu drivers do not fully support that, and these drivers also do not advertise support for dma-iommu.c via IOMMU_DOMAIN_DMA, or use arm_iommu_create_mapping(), so largely their implementations of IOMMU_DOMAIN_UNMANAGED are untested. This means that a user like vfio/iommufd does not likely work with them.
Thus, mark all these drivers as having "broken" UNAMANGED domains and add a new device_iommu_unmanaged_supported() API for vfio/iommufd and dma-iommu to refuse to work with these drivers.
These are preparatory changes for a new IOMMU API that will be used by iommufd. Having this flag allows us to prevent any use of the new API in iommufd, to keep things clean.
You can also find this series on Github:
https://github.com/nicolinc/iommufd/commits/broken_unmanaged_domain
Thank you
Nicolin Chen
Nicolin Chen (4):
iommu: Add a broken_unmanaged_domain flag in iommu_ops iommu/dma: Do not init domain if broken_unmanaged_domain
iommufd: Do not allocate device object if broken_unmanaged_domain
vfio: Do not allocate domain if broken_unmanaged_domain
drivers/iommu/dma-iommu.c | 3 +++ drivers/iommu/fsl_pamu_domain.c | 1 + drivers/iommu/iommu.c | 24 ++++++++++++++++++++++++ drivers/iommu/iommufd/device.c | 3 +++ drivers/iommu/msm_iommu.c | 1 + drivers/iommu/mtk_iommu_v1.c | 1 + drivers/iommu/omap-iommu.c | 1 + drivers/iommu/tegra-gart.c | 1 + drivers/iommu/tegra-smmu.c | 1 + drivers/vfio/vfio_iommu_type1.c | 5 ++++- include/linux/iommu.h | 11 +++++++++++ 11 files changed, 51 insertions(+), 1 deletion(-)
Signature · 1 line
2.39.1
PATCH 1/4 iommu: Add a broken_unmanaged_domain flag in iommu_ops
Both IOMMU_DOMAIN_UNMANAGED and IOMMU_DOMAIN_DMA require the support of __IOMMU_DOMAIN_PAGING capability, i.e. iommu_map/unmap. However, some older iommu drivers do not fully support that, and these drivers also do not advertise support for dma-iommu.c via IOMMU_DOMAIN_DMA, or use arm_iommu_create_mapping(), so largely their implementations of IOMMU_DOMAIN_UNMANAGED are untested. This means that a user like vfio/iommufd does not likely work with them.
Several of them have obvious problems:
* fsl_pamu_domain.c
Without map/unmap ops in the default_domain_ops, it isn't an unmanaged domain at all.
* mtk_iommu_v1.c
With a fixed 4M "pagetable", it can only map exactly 4G of memory, but doesn't set the aperture.
* tegra-gart.c
Its notion of attach/detach and groups has to be a complete lie to get around all the other API expectations.
Some others might work but have never been tested with vfio/iommufd:
* msm_iommu.c
* omap-iommu.c
* tegra-smmu.c
Thus, mark all these drivers as having "broken" UNAMANGED domains and add a new device_iommu_unmanaged_supported() API for vfio/iommufd and dma-iommu to refuse to work with these drivers.
--- drivers/iommu/fsl_pamu_domain.c | 1 + drivers/iommu/iommu.c | 24 ++++++++++++++++++++++++ drivers/iommu/msm_iommu.c | 1 + drivers/iommu/mtk_iommu_v1.c | 1 + drivers/iommu/omap-iommu.c | 1 + drivers/iommu/tegra-gart.c | 1 + drivers/iommu/tegra-smmu.c | 1 + include/linux/iommu.h | 11 +++++++++++ 8 files changed, 41 insertions(+)
drivers/iommu/fsl_pamu_domain.c +1 -0
@@ -448,6 +448,7 @@ static struct iommu_device *fsl_pamu_probe_device(struct device *dev) }static const struct iommu_ops fsl_pamu_ops = { + .broken_unmanaged_domain = true, .capable = fsl_pamu_capable, .domain_alloc = fsl_pamu_domain_alloc, .probe_device = fsl_pamu_probe_device,
drivers/iommu/iommu.c +24 -0
@@ -1897,6 +1897,30 @@ bool device_iommu_capable(struct device *dev, enum iommu_cap cap) }EXPORT_SYMBOL_GPL (device_iommu_capable); +/** +* device_iommu_unmanaged_supported() - full support of IOMMU_DOMAIN_UNMANAGED +* @dev: device that is behind the iommu +* +* In general, all IOMMU drivers can allocate IOMMU_DOMAIN_UNMANAGED domains. +* However, some of them set the broken_unmanaged_domain, indicating something +* is wrong about its support of IOMMU_DOMAIN_UNMANAGED/__IOMMU_DOMAIN_PAGING. +* This can happen, when a driver lies about the support to get around with the +* IOMMU API, merely for other drivers to use, or when a driver has never been +* tested with vfio/iommufd that need a full support of IOMMU_DOMAIN_UNMANAGED. +* +* Return: true if an IOMMU is present and broken_unmanaged_domain is not set, +* otherwise, false. +*/ +bool device_iommu_unmanaged_supported (struct device *dev) +{ +if (dev->iommu && dev->iommu->iommu_dev && + !dev_iommu_ops (dev)->broken_unmanaged_domain) +return true; + +return false; +} +EXPORT_SYMBOL_GPL (device_iommu_unmanaged_supported); +/** * iommu_set_fault_handler() - set a fault handler for an iommu domain * @domain: iommu domain
drivers/iommu/msm_iommu.c +1 -0
@@ -675,6 +675,7 @@ irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id) }static struct iommu_ops msm_iommu_ops = { + .broken_unmanaged_domain = true, .domain_alloc = msm_iommu_domain_alloc, .probe_device = msm_iommu_probe_device, .device_group = generic_device_group,
drivers/iommu/mtk_iommu_v1.c +1 -0
@@ -578,6 +578,7 @@ static int mtk_iommu_v1_hw_init(const struct mtk_iommu_v1_data *data) }static const struct iommu_ops mtk_iommu_v1_ops = { + .broken_unmanaged_domain = true, .domain_alloc = mtk_iommu_v1_domain_alloc, .probe_device = mtk_iommu_v1_probe_device, .probe_finalize = mtk_iommu_v1_probe_finalize,
drivers/iommu/omap-iommu.c +1 -0
@@ -1733,6 +1733,7 @@ static struct iommu_group *omap_iommu_device_group(struct device *dev) }static const struct iommu_ops omap_iommu_ops = { + .broken_unmanaged_domain = true, .domain_alloc = omap_iommu_domain_alloc, .probe_device = omap_iommu_probe_device, .release_device = omap_iommu_release_device,
drivers/iommu/tegra-gart.c +1 -0
@@ -267,6 +267,7 @@ static void gart_iommu_sync(struct iommu_domain *domain, }static const struct iommu_ops gart_iommu_ops = { + .broken_unmanaged_domain = true, .domain_alloc = gart_iommu_domain_alloc, .probe_device = gart_iommu_probe_device, .device_group = generic_device_group,
drivers/iommu/tegra-smmu.c +1 -0
@@ -962,6 +962,7 @@ static int tegra_smmu_of_xlate(struct device *dev, }static const struct iommu_ops tegra_smmu_ops = { + .broken_unmanaged_domain = true, .domain_alloc = tegra_smmu_domain_alloc, .probe_device = tegra_smmu_probe_device, .device_group = tegra_smmu_device_group,
include/linux/iommu.h +11 -0
@@ -245,6 +245,10 @@ struct iommu_iotlb_gather {* pasid, so that any DMA transactions with this pasid * will be blocked by the hardware. * @pgsize_bitmap: bitmap of all possible supported page sizes +* @broken_unmanaged_domain: IOMMU_DOMAIN_UNMANAGED is not fully functional; the +* driver does not really support iommu_map/unmap, but +* uses UNMANAGED domains for the IOMMU API, called by +* other SOC drivers. * @owner: Driver module providing these ops */ struct iommu_ops {
@@ -277,6 +281,7 @@ struct iommu_ops {const struct iommu_domain_ops *default_domain_ops;unsigned long pgsize_bitmap; +bool broken_unmanaged_domain;struct module *owner; };
@@ -455,6 +460,7 @@ static inline const struct iommu_ops *dev_iommu_ops(struct device *dev)extern int bus_iommu_probe (struct bus_type *bus);extern bool iommu_present (struct bus_type *bus);extern bool device_iommu_capable (struct device *dev,enum iommu_cap cap); +extern bool device_iommu_unmanaged_supported (struct device *dev);extern struct iommu_domain *iommu_domain_alloc (struct bus_type *bus);extern struct iommu_group *iommu_group_get_by_id (int id);extern void iommu_domain_free (struct iommu_domain *domain);
@@ -742,6 +748,11 @@ static inline bool device_iommu_capable(struct device *dev, enum iommu_cap cap)return false; } +static inline bool device_iommu_unmanaged_supported (struct device *dev) +{ +return false; +} +static inline struct iommu_domain *iommu_domain_alloc (struct bus_type *bus) {return NULL ;
Signature · 1 line
2.39.1
Robin Murphy
maintainerRe: [PATCH 1/4] iommu: Add a broken_unmanaged_domain flag in iommu_ops
Quoted 8 lines · Nicolin Chen
Both
IOMMU_DOMAIN_UNMANAGEDandIOMMU_DOMAIN_DMArequire the support of__IOMMU_DOMAIN_PAGINGcapability, i.e. iommu_map/unmap. However, some older iommu drivers do not fully support that, and these drivers also do not advertise support fordma-iommu.cviaIOMMU_DOMAIN_DMA, or usearm_iommu_create_mapping(), so largely their implementations ofIOMMU_DOMAIN_UNMANAGEDare untested. This means that a user like vfio/iommufd does not likely work with them.
Quoted 7 lines
Several of them have obvious problems:
*fsl_pamu_domain.c
Without map/unmap ops in thedefault_domain_ops, it isn't an unmanaged domain at all.
*mtk_iommu_v1.c
With a fixed 4M "pagetable", it can only map exactly 4G of memory, but doesn't set the aperture.
The aperture is easily fixed (one could argue that what's broken there are the ARM DMA ops for assuming every IOMMU has a 32-bit IOVA space and not checking).
Quoted 3 lines
*
tegra-gart.c
Its notion of attach/detach and groups has to be a complete lie to get around all the other API expectations.
That's true, and the domain is tiny and not isolated from the rest of the address space outside the aperture, but the one thing it does do is support iommu_map/unmap just fine, which is what this flag is documented as saying it doesn't.
Quoted 4 lines
Some others might work but have never been tested with vfio/iommufd:
*msm_iommu.c
*omap-iommu.c
*tegra-smmu.c
And yet they all have other in-tree users (GPUs on MSM and Tegra, remoteproc on OMAP) that allocate unmanaged domains and use iommu_map/unmap just fine, so they're clearly not broken either.
On the flipside, you're also missing cases like apple-dart, which can have broken unmanaged domains by any definition, but only under certain conditions (at least it "fails safe" and they will refuse attempts to attach anything). I'd also question sprd-iommu, which hardly has a generally-useful domain size, and has only just recently gained the ability to unmap anything successfully. TBH none of the SoC IOMMUs are likely to ever be of interest to VFIO or IOMMUFD, since the only things they could assign to userspace are the individual devices - usually graphics and media engines - that they're coupled to, whose useful functionality tends to depend on clocks, phys, and random other low-level stuff that would be somewhere between impractical and downright unsafe to attempt to somehow expose as well.
Quoted 7 lines
Thus, mark all these drivers as having "broken" UNAMANGED domains and add a new
device_iommu_unmanaged_supported()API for vfio/iommufd and dma-iommu to refuse to work with these drivers.Co-developed-by Jason Gunthorpe <[email protected]>Signed-off-by Jason Gunthorpe <[email protected]>Signed-off-by Nicolin Chen <[email protected]>
[...]
include/linux/iommu.h struct iommu_iotlb_gather { · line 251
Quoted 12 lines
include/linux/iommu.h +4
-0@@ -245,6 +245,10 @@ struct iommu_iotlb_gather {* pasid, so that any DMA transactions with this pasid * will be blocked by the hardware. * @pgsize_bitmap: bitmap of all possible supported page sizes +* @broken_unmanaged_domain: IOMMU_DOMAIN_UNMANAGED is not fully functional; the +* driver does not really support iommu_map/unmap, but +* uses UNMANAGED domains for the IOMMU API, called by +* other SOC drivers.
"uses UNMANAGED domains for the IOMMU API" is literally the definition of unmanaged domains :/
Some "other SOC drivers" use more of the IOMMU API than VFIO does :/
Please just add IOMMU_CAP_IOMMUFD to represent whatever the nebulous requirements of IOMMUFD actually are (frankly it's no less informative than calling domains "broken"), handle that in the drivers you care about and have tested, and use device_iommu_capable(). What you're describing in this series is a capability, and we have a perfectly good API for drivers to express those already. Plus, as demonstrated above, a positive capability based on empirical testing will be infinitely more robust than a negative one based on guessing.
Thanks,
Robin.
Re: [PATCH 1/4] iommu: Add a broken_unmanaged_domain flag in iommu_ops
Hi Robin.
Quoted 42 lines · Robin Murphy
External email: Use caution opening links or attachments
Quoted 8 lines · Nicolin Chen
Both
IOMMU_DOMAIN_UNMANAGEDandIOMMU_DOMAIN_DMArequire the support of__IOMMU_DOMAIN_PAGINGcapability, i.e. iommu_map/unmap. However, some older iommu drivers do not fully support that, and these drivers also do not advertise support fordma-iommu.cviaIOMMU_DOMAIN_DMA, or usearm_iommu_create_mapping(), so largely their implementations ofIOMMU_DOMAIN_UNMANAGEDare untested. This means that a user like vfio/iommufd does not likely work with them.Quoted 7 lines
Several of them have obvious problems:
*fsl_pamu_domain.c
Without map/unmap ops in thedefault_domain_ops, it isn't an unmanaged domain at all.
*mtk_iommu_v1.c
With a fixed 4M "pagetable", it can only map exactly 4G of memory, but doesn't set the aperture.The aperture is easily fixed (one could argue that what's broken there are the ARM DMA ops for assuming every IOMMU has a 32-bit IOVA space and not checking).
Quoted 3 lines
*
tegra-gart.c
Its notion of attach/detach and groups has to be a complete lie to get around all the other API expectations.That's true, and the domain is tiny and not isolated from the rest of the address space outside the aperture, but the one thing it does do is support iommu_map/unmap just fine, which is what this flag is documented as saying it doesn't.
Quoted 4 lines
Some others might work but have never been tested with vfio/iommufd:
*msm_iommu.c
*omap-iommu.c
*tegra-smmu.cAnd yet they all have other in-tree users (GPUs on MSM and Tegra, remoteproc on OMAP) that allocate unmanaged domains and use iommu_map/unmap just fine, so they're clearly not broken either.
Quoted 12 lines
On the flipside, you're also missing cases like apple-dart, which can have broken unmanaged domains by any definition, but only under certain conditions (at least it "fails safe" and they will refuse attempts to attach anything). I'd also question sprd-iommu, which hardly has a generally-useful domain size, and has only just recently gained the ability to unmap anything successfully. TBH none of the SoC IOMMUs are likely to ever be of interest to VFIO or IOMMUFD, since the only things they could assign to userspace are the individual devices - usually graphics and media engines - that they're coupled to, whose useful functionality tends to depend on clocks, phys, and random other low-level stuff that would be somewhere between impractical and downright unsafe to attempt to somehow expose as well.
Thanks for all the inputs.
Quoted 28 lines
Quoted 7 lines
Thus, mark all these drivers as having "broken" UNAMANGED domains and add a new
device_iommu_unmanaged_supported()API for vfio/iommufd and dma-iommu to refuse to work with these drivers.Co-developed-by Jason Gunthorpe <[email protected]>Signed-off-by Jason Gunthorpe <[email protected]>Signed-off-by Nicolin Chen <[email protected]>[...]
include/linux/iommu.h struct iommu_iotlb_gather { · line 251
Quoted 12 lines
include/linux/iommu.h +4
-0@@ -245,6 +245,10 @@ struct iommu_iotlb_gather {* pasid, so that any DMA transactions with this pasid * will be blocked by the hardware. * @pgsize_bitmap: bitmap of all possible supported page sizes +* @broken_unmanaged_domain: IOMMU_DOMAIN_UNMANAGED is not fully functional; the +* driver does not really support iommu_map/unmap, but +* uses UNMANAGED domains for the IOMMU API, called by +* other SOC drivers. "uses UNMANAGED domains for the IOMMU API" is literally the definition of unmanaged domains :/
Some "other SOC drivers" use more of the IOMMU API than VFIO does :/
Quoted 8 lines
Please just add
IOMMU_CAP_IOMMUFDto represent whatever the nebulous requirements of IOMMUFD actually are (frankly it's no less informative than calling domains "broken"), handle that in the drivers you care about and have tested, and usedevice_iommu_capable(). What you're describing in this series is a capability, and we have a perfectly good API for drivers to express those already. Plus, as demonstrated above, a positive capability based on empirical testing will be infinitely more robust than a negative one based on guessing.
OK. I can change to IOMMU_CAP_IOMMUFD, and add to the drivers that are tested. And an IOMMU driver that wants to use IOMMUFD can add such a CAP later whenever it's ready.
Yet, "IOMMU_CAP_IOMMUFD" would make the VFIO change suspicious, so perhaps the next version is just one CAP patch + one IOMMUFD patch. @Jason, any concern?
Thank you
Nicolin
Jason Gunthorpe
maintainerRe: [PATCH 1/4] iommu: Add a broken_unmanaged_domain flag in iommu_ops
In reply to Robin MurphyQuoted 4 lines · Robin Murphy
Please just add
IOMMU_CAP_IOMMUFDto represent whatever the nebulous requirements of IOMMUFD actually are (frankly it's no less informative than calling domains "broken"), handle that in the drivers you care about and
I don't want to tie this to iommufd, that isn't the point.
We clearly have drivers that don't implement the iommu kernel API properly, because their only use is between the iommu driver and some other same-SOC driver.
As a user of the iommu API iommufd and VFIO want to avoid these drivers.
We have that acknowledgment already via the IOMMU_DOMAIN_DMA stuff protecting the dma_iommu.c from those same drivers.
So, how about this below instead. Imagine it is followed by something along the lines of my other sketch:
https://lore.kernel.org/linux-iommu/Y4%[email protected]/
And we completely delete IOMMU_DOMAIN_DMA/_FQ and get dma-iommu.c mostly out of driver code.
iommufd/vfio would refuse to work with drivers that don't indicate they support dma_iommu.c, that is good enough.
We'd eventually rename IOMMU_DOMAIN_UNMANAGED to IOMMU_DOMAIN_MAPPING.
Subject: [PATCH] iommu: Remove IOMMU_DOMAIN_DMA from drivers
The IOMMU_DOMAIN_DMA is exactly the same driver functionality as IOMMU_DOMAIN_UNMANAGED, except it also implies that dma_iommu.c should be able to use this driver.
As a first step to removing IOMMU_DOMAIN_DMA remove all references to it from the drivers. Two simple ops flags are enough to indicate if the driver is compatible with dma_iommu.c and if the driver will allow the FQ mode to be selected. When dma-iommu.c needs an a domain it will request an IOMMU_DOMAIN_UNMANAGED.
--- drivers/iommu/apple-dart.c | 3 ++- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 4 +-- drivers/iommu/arm/arm-smmu/arm-smmu.c | 11 ++++---- drivers/iommu/arm/arm-smmu/qcom_iommu.c | 3 ++- drivers/iommu/exynos-iommu.c | 3 ++- drivers/iommu/intel/iommu.c | 3 +-- drivers/iommu/iommu.c | 29 ++++++++++++++++----- drivers/iommu/ipmmu-vmsa.c | 3 ++- drivers/iommu/mtk_iommu.c | 3 ++- drivers/iommu/rockchip-iommu.c | 3 ++- drivers/iommu/sprd-iommu.c | 3 ++- drivers/iommu/sun50i-iommu.c | 4 +-- drivers/iommu/virtio-iommu.c | 2 +- include/linux/iommu.h | 2 ++ 14 files changed, 50 insertions(+), 26 deletions(-)
drivers/iommu/apple-dart.c +2 -1
@@ -580,7 +580,7 @@ static struct iommu_domain *apple_dart_domain_alloc(unsigned int type) {struct apple_dart_domain *dart_domain; -if (type !=IOMMU_DOMAIN_DMA && type !=IOMMU_DOMAIN_UNMANAGED && +if (type !=IOMMU_DOMAIN_UNMANAGED && type !=IOMMU_DOMAIN_IDENTITY && type !=IOMMU_DOMAIN_BLOCKED )return NULL ;
@@ -769,6 +769,7 @@ static void apple_dart_get_resv_regions(struct device *dev, }static const struct iommu_ops apple_dart_iommu_ops = { + .use_dma_iommu = true, .domain_alloc = apple_dart_domain_alloc, .probe_device = apple_dart_probe_device, .release_device = apple_dart_release_device,
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +2 -2
@@ -2013,8 +2013,6 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)return arm_smmu_sva_domain_alloc ();if (type !=IOMMU_DOMAIN_UNMANAGED && - type !=IOMMU_DOMAIN_DMA && - type !=IOMMU_DOMAIN_DMA_FQ && type !=IOMMU_DOMAIN_IDENTITY )return NULL ;
@@ -2844,6 +2842,8 @@ static void arm_smmu_remove_dev_pasid(struct device *dev, ioasid_t pasid) }static struct iommu_ops arm_smmu_ops = { + .use_dma_iommu = true, + .allow_dma_fq = true, .capable = arm_smmu_capable, .domain_alloc = arm_smmu_domain_alloc, .probe_device = arm_smmu_probe_device,
drivers/iommu/arm/arm-smmu/arm-smmu.c +6 -5
@@ -855,11 +855,9 @@ static struct iommu_domain *arm_smmu_domain_alloc(unsigned type) {struct arm_smmu_domain *smmu_domain; -if (type !=IOMMU_DOMAIN_UNMANAGED && type !=IOMMU_DOMAIN_IDENTITY ) { -if (using_legacy_binding || - (type !=IOMMU_DOMAIN_DMA && type !=IOMMU_DOMAIN_DMA_FQ )) -return NULL ; - } +if (type !=IOMMU_DOMAIN_UNMANAGED && type !=IOMMU_DOMAIN_IDENTITY ) +return NULL ; +/* * Allocate the domain and initialise some of its data structures. * We can't really do anything meaningful until we've added a
@@ -1555,6 +1553,8 @@ static int arm_smmu_def_domain_type(struct device *dev) }static struct iommu_ops arm_smmu_ops = { + .use_dma_iommu = true, + .allow_dma_fq = true, .capable = arm_smmu_capable, .domain_alloc = arm_smmu_domain_alloc, .probe_device = arm_smmu_probe_device,
@@ -1982,6 +1982,7 @@ static int arm_smmu_device_dt_probe(struct arm_smmu_device *smmu, IS_ENABLED(CONFIG_ARM_SMMU_LEGACY_DT_BINDINGS) ? "DMA API" : "SMMU"); } using_legacy_binding = true; + arm_smmu_ops.use_dma_iommu = false; }else if (!legacy_binding && !using_legacy_binding) { using_generic_binding = true; }else {
drivers/iommu/arm/arm-smmu/qcom_iommu.c +2 -1
@@ -323,7 +323,7 @@ static struct iommu_domain *qcom_iommu_domain_alloc(unsigned type) {struct qcom_iommu_domain *qcom_domain; -if (type !=IOMMU_DOMAIN_UNMANAGED && type !=IOMMU_DOMAIN_DMA ) +if (type !=IOMMU_DOMAIN_UNMANAGED )return NULL ;/* * Allocate the domain and initialise some of its data structures.
@@ -575,6 +575,7 @@ static int qcom_iommu_of_xlate(struct device *dev, struct of_phandle_args *args) }static const struct iommu_ops qcom_iommu_ops = { + .use_dma_iommu = true, .capable = qcom_iommu_capable, .domain_alloc = qcom_iommu_domain_alloc, .probe_device = qcom_iommu_probe_device,
drivers/iommu/exynos-iommu.c +2 -1
@@ -825,7 +825,7 @@ static struct iommu_domain *exynos_iommu_domain_alloc(unsigned type)/* Check if correct PTE offsets are initialized */ BUG_ON (PG_ENT_SHIFT <0 || !dma_dev); -if (type !=IOMMU_DOMAIN_DMA && type !=IOMMU_DOMAIN_UNMANAGED ) +if (type !=IOMMU_DOMAIN_UNMANAGED )return NULL ; domain =kzalloc (sizeof (*domain),GFP_KERNEL );
@@ -1396,6 +1396,7 @@ static int exynos_iommu_of_xlate(struct device *dev, }static const struct iommu_ops exynos_iommu_ops = { + .use_dma_iommu = true, .domain_alloc = exynos_iommu_domain_alloc, .device_group = generic_device_group, .probe_device = exynos_iommu_probe_device,
drivers/iommu/intel/iommu.c +1 -2
@@ -4165,8 +4165,6 @@ static struct iommu_domain *intel_iommu_domain_alloc(unsigned type)switch (type) {case IOMMU_DOMAIN_BLOCKED :return &blocking_domain; -case IOMMU_DOMAIN_DMA : -case IOMMU_DOMAIN_DMA_FQ :case IOMMU_DOMAIN_UNMANAGED : dmar_domain =alloc_domain (type);if (!dmar_domain) {
@@ -4761,6 +4759,7 @@ static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid) }const struct iommu_ops intel_iommu_ops = { + .use_dma_iommu = true, .capable = intel_iommu_capable, .domain_alloc = intel_iommu_domain_alloc, .probe_device = intel_iommu_probe_device,
drivers/iommu/iommu.c +22 -7
@@ -1618,17 +1618,32 @@ static int iommu_group_alloc_default_domain(struct bus_type *bus, {struct iommu_domain *dom; - dom =__iommu_domain_alloc (bus, type); -if (!dom && type !=IOMMU_DOMAIN_DMA ) { - dom =__iommu_domain_alloc (bus,IOMMU_DOMAIN_DMA ); -if (dom) +/* +* Keep the DMA domain type out of the drivers, eventually it will go +* away completely. +*/ +if (type ==IOMMU_DOMAIN_IDENTITY ) { + dom =__iommu_domain_alloc (bus,IOMMU_DOMAIN_IDENTITY ); +if (!dom) +return -ENOMEM ; + }else if (type ==IOMMU_DOMAIN_DMA_FQ || type ==IOMMU_DOMAIN_DMA ) { +if (!bus->iommu_ops->use_dma_iommu) +return -EINVAL ; + + dom =__iommu_domain_alloc (bus,IOMMU_DOMAIN_UNMANAGED ); +if (!dom) +return -ENOMEM ; +if (type ==IOMMU_DOMAIN_DMA_FQ && + !bus->iommu_ops->allow_dma_fq) {pr_warn ("Failed to allocate default IOMMU domain of type %u for group %s - Falling back to IOMMU_DOMAIN_DMA" , type, group->name); + type =IOMMU_DOMAIN_DMA ; + } + dom->type = type; + }else { +return -EINVAL ; } -if (!dom) -return -ENOMEM ; - group->default_domain = dom;if (!group->domain) group->domain = dom;
drivers/iommu/ipmmu-vmsa.c +2 -1
@@ -571,7 +571,7 @@ static struct iommu_domain *ipmmu_domain_alloc(unsigned type) {struct ipmmu_vmsa_domain *domain; -if (type !=IOMMU_DOMAIN_UNMANAGED && type !=IOMMU_DOMAIN_DMA ) +if (type !=IOMMU_DOMAIN_UNMANAGED )return NULL ; domain =kzalloc (sizeof (*domain),GFP_KERNEL );
@@ -866,6 +866,7 @@ static struct iommu_group *ipmmu_find_group(struct device *dev) }static const struct iommu_ops ipmmu_ops = { + .use_dma_iommu = true, .domain_alloc = ipmmu_domain_alloc, .probe_device = ipmmu_probe_device, .release_device = ipmmu_release_device,
drivers/iommu/mtk_iommu.c +2 -1
@@ -636,7 +636,7 @@ static struct iommu_domain *mtk_iommu_domain_alloc(unsigned type) {struct mtk_iommu_domain *dom; -if (type !=IOMMU_DOMAIN_DMA && type !=IOMMU_DOMAIN_UNMANAGED ) +if (type !=IOMMU_DOMAIN_UNMANAGED )return NULL ; dom =kzalloc (sizeof (*dom),GFP_KERNEL );
@@ -936,6 +936,7 @@ static void mtk_iommu_get_resv_regions(struct device *dev, }static const struct iommu_ops mtk_iommu_ops = { + .use_dma_iommu = true, .domain_alloc = mtk_iommu_domain_alloc, .probe_device = mtk_iommu_probe_device, .release_device = mtk_iommu_release_device,
drivers/iommu/rockchip-iommu.c +2 -1
@@ -1061,7 +1061,7 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type) {struct rk_iommu_domain *rk_domain; -if (type !=IOMMU_DOMAIN_UNMANAGED && type !=IOMMU_DOMAIN_DMA ) +if (type !=IOMMU_DOMAIN_UNMANAGED )return NULL ;if (!dma_dev)
@@ -1184,6 +1184,7 @@ static int rk_iommu_of_xlate(struct device *dev, }static const struct iommu_ops rk_iommu_ops = { + .use_dma_iommu = true, .domain_alloc = rk_iommu_domain_alloc, .probe_device = rk_iommu_probe_device, .release_device = rk_iommu_release_device,
drivers/iommu/sprd-iommu.c +2 -1
@@ -136,7 +136,7 @@ static struct iommu_domain *sprd_iommu_domain_alloc(unsigned int domain_type) {struct sprd_iommu_domain *dom; -if (domain_type !=IOMMU_DOMAIN_DMA && domain_type !=IOMMU_DOMAIN_UNMANAGED ) +if (domain_type !=IOMMU_DOMAIN_UNMANAGED )return NULL ; dom =kzalloc (sizeof (*dom),GFP_KERNEL );
@@ -406,6 +406,7 @@ static int sprd_iommu_of_xlate(struct device *dev, struct of_phandle_args *args)static const struct iommu_ops sprd_iommu_ops = { + .use_dma_iommu = true, .domain_alloc = sprd_iommu_domain_alloc, .probe_device = sprd_iommu_probe_device, .device_group = sprd_iommu_device_group,
drivers/iommu/sun50i-iommu.c +2 -2
@@ -671,8 +671,7 @@ static struct iommu_domain *sun50i_iommu_domain_alloc(unsigned type) {struct sun50i_iommu_domain *sun50i_domain; -if (type !=IOMMU_DOMAIN_DMA && - type !=IOMMU_DOMAIN_UNMANAGED ) +if (type !=IOMMU_DOMAIN_UNMANAGED )return NULL ; sun50i_domain =kzalloc (sizeof (*sun50i_domain),GFP_KERNEL );
@@ -827,6 +826,7 @@ static int sun50i_iommu_of_xlate(struct device *dev, }static const struct iommu_ops sun50i_iommu_ops = { + .use_dma_iommu = true, .pgsize_bitmap =SZ_4K , .device_group = sun50i_iommu_device_group, .domain_alloc = sun50i_iommu_domain_alloc,
drivers/iommu/virtio-iommu.c +1 -1
@@ -642,7 +642,6 @@ static struct iommu_domain *viommu_domain_alloc(unsigned type)struct viommu_domain *vdomain;if (type !=IOMMU_DOMAIN_UNMANAGED && - type !=IOMMU_DOMAIN_DMA && type !=IOMMU_DOMAIN_IDENTITY )return NULL ;
@@ -1018,6 +1017,7 @@ static bool viommu_capable(struct device *dev, enum iommu_cap cap) }static struct iommu_ops viommu_ops = { + .use_dma_iommu = true, .capable = viommu_capable, .domain_alloc = viommu_domain_alloc, .probe_device = viommu_probe_device,
include/linux/iommu.h +2 -0
@@ -277,6 +277,8 @@ struct iommu_ops {const struct iommu_domain_ops *default_domain_ops;unsigned long pgsize_bitmap; + u8 use_dma_iommu : 1; + u8 allow_dma_fq : 1;struct module *owner; };
Signature · 1 line
2.39.0
Tian, Kevin
maintainerRE: [PATCH 1/4] iommu: Add a broken_unmanaged_domain flag in iommu_ops
Quoted 27 lines
From: Jason Gunthorpe <[email protected]>
Sent: Saturday, January 28, 2023 7:54 AMQuoted 1 line · Robin Murphy
Please just add
IOMMU_CAP_IOMMUFDto represent whatever thenebulous
Quoted 1 line
requirements of IOMMUFD actually are (frankly it's no less informative
than
Quoted 2 lines
calling domains "broken"), handle that in the drivers you care about and
I don't want to tie this to iommufd, that isn't the point.
We clearly have drivers that don't implement the iommu kernel API properly, because their only use is between the iommu driver and some other same-SOC driver.
As a user of the iommu API iommufd and VFIO want to avoid these drivers.
We have that acknowledgment already via the
IOMMU_DOMAIN_DMAstuff protecting thedma_iommu.cfrom those same drivers.So, how about this below instead. Imagine it is followed by something along the lines of my other sketch:
Quoted 8 lines
https://lore.kernel.org/linux-iommu/Y4%[email protected]/
And we completely delete IOMMU_DOMAIN_DMA/_FQ and get dma-
iommu.c
mostly out of driver code.iommufd/vfio would refuse to work with drivers that don't indicate they support
dma_iommu.c, that is good enough.
this is a good idea. Just one doubt. Robin mentioned that sprd-iommu might have a broken unmanaged domains:
" I'd also question sprd-iommu, which hardly has a generally-useful domain size, and has only just recently gained the ability to unmap anything successfully."
Want to understand why that restriction is not a problem for DMA API.
what Jason proposed here assumes that existing driver support for DMA API can be safely applied to vfio/iommufd. But above looks warning certain exception?
Quoted 15 lines
drivers/iommu/intel/iommu.c +0
-2@@ -4165,8 +4165,6 @@ static struct iommu_domain *intel_iommu_domain_alloc(unsigned type)switch (type) {case IOMMU_DOMAIN_BLOCKED :return &blocking_domain; -case IOMMU_DOMAIN_DMA : -case IOMMU_DOMAIN_DMA_FQ :case IOMMU_DOMAIN_UNMANAGED : dmar_domain =alloc_domain (type);drivers/iommu/intel/iommu.c +0
-0if (!dmar_domain) {
drivers/iommu/intel/iommu.c static void intel_iommu_remove_dev_pasid(struct · line 4763
Quoted 5 lines
drivers/iommu/intel/iommu.c +1
-0@@ -4761,6 +4759,7 @@ static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid) }const struct iommu_ops intel_iommu_ops = { + .use_dma_iommu = true,
missed:
+ .allow_dma_fq = true,
Jason Gunthorpe
maintainerRe: [PATCH 1/4] iommu: Add a broken_unmanaged_domain flag in iommu_ops
Quoted 3 lines · Kevin
" I'd also question sprd-iommu, which hardly has a generally-useful domain size, and has only just recently gained the ability to unmap anything successfully."
So long as it has a correct kernel API and exposes the right (small) aperture then it is OK.
The device will not be useful for qemu, but it would run some dpdk configurations just fine.
All the VFIO world is not VMs.
Review
Quoted 9 lines
drivers/iommu/intel/iommu.c static void intel_iommu_remove_dev_pasid(struct · line 4763
Quoted 6 lines
drivers/iommu/intel/iommu.c +1
-0@@ -4761,6 +4759,7 @@ static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid) }const struct iommu_ops intel_iommu_ops = { + .use_dma_iommu = true,missed:
(quoted diff) +1
-0+ .allow_dma_fq = true,
Yep
Jason
Tian, Kevin
maintainerRE: [PATCH 1/4] iommu: Add a broken_unmanaged_domain flag in iommu_ops
Quoted 9 lines
From: Jason Gunthorpe <[email protected]>
Sent: Monday, January 30, 2023 9:33 PMQuoted 3 lines · Kevin
" I'd also question sprd-iommu, which hardly has a generally-useful domain size, and has only just recently gained the ability to unmap anything successfully."
Quoted 5 lines
So long as it has a correct kernel API and exposes the right (small) aperture then it is OK.
The device will not be useful for qemu, but it would run some dpdk configurations just fine.
I still didn't get the restriction here. Can you elaborate why it works with dpdk but not qemu?
Can qemu verify this restriction via existing path or need new uAPI flag to communicate?
Jason Gunthorpe
maintainerRe: [PATCH 1/4] iommu: Add a broken_unmanaged_domain flag in iommu_ops
Quoted 9 lines · Kevin
Quoted 9 lines
From: Jason Gunthorpe <[email protected]>
Sent: Monday, January 30, 2023 9:33 PMQuoted 3 lines · Kevin
" I'd also question sprd-iommu, which hardly has a generally-useful domain size, and has only just recently gained the ability to unmap anything successfully."
Quoted 8 lines
Quoted 5 lines
So long as it has a correct kernel API and exposes the right (small) aperture then it is OK.
The device will not be useful for qemu, but it would run some dpdk configurations just fine.
I still didn't get the restriction here. Can you elaborate why it works with dpdk but not qemu?
dpdk needs like, say, 64M of aperture and doesn't care what the IOVAs are
qemu needs the entire guest memory of aperture and must have IOVAs that are 1:1 with the GPA.
So aperture size and location can exclude qemu
Quoted 2 lines
Can qemu verify this restriction via existing path or need new uAPI flag to communicate?
It already happens, the aperture/etc is convayed to qemu through IOMMUFD_CMD_IOAS_IOVA_RANGES and if qemu cannot get the IOVA's it needs to create the guest it should fail.
Jason
Tian, Kevin
maintainerRE: [PATCH 1/4] iommu: Add a broken_unmanaged_domain flag in iommu_ops
Quoted 28 lines
From: Jason Gunthorpe <[email protected]>
Sent: Wednesday, February 1, 2023 10:56 PMQuoted 9 lines · Kevin
Quoted 9 lines
From: Jason Gunthorpe <[email protected]>
Sent: Monday, January 30, 2023 9:33 PMQuoted 3 lines · Kevin
" I'd also question sprd-iommu, which hardly has a generally-useful domain size, and has only just recently gained the ability to unmap anything successfully."
Quoted 8 lines
Quoted 5 lines
So long as it has a correct kernel API and exposes the right (small) aperture then it is OK.
The device will not be useful for qemu, but it would run some dpdk configurations just fine.
I still didn't get the restriction here. Can you elaborate why it works with dpdk but not qemu?
dpdk needs like, say, 64M of aperture and doesn't care what the IOVAs are
qemu needs the entire guest memory of aperture and must have IOVAs that are 1:1 with the GPA.
Quoted 9 lines
So aperture size and location can exclude qemu
Quoted 2 lines
Can qemu verify this restriction via existing path or need new uAPI flag to communicate?
It already happens, the aperture/etc is convayed to qemu through
IOMMUFD_CMD_IOAS_IOVA_RANGESand if qemu cannot get the IOVA's it needs to create the guest it should fail.
Make sense.
Tian, Kevin
maintainerRE: [PATCH 1/4] iommu: Add a broken_unmanaged_domain flag in iommu_ops
In reply to Nicolin ChenQuoted 24 lines
From: Nicolin Chen <[email protected]>
Sent: Saturday, January 28, 2023 4:04 AMBoth
IOMMU_DOMAIN_UNMANAGEDandIOMMU_DOMAIN_DMArequire the support
of__IOMMU_DOMAIN_PAGINGcapability, i.e. iommu_map/unmap. However,
some older iommu drivers do not fully support that, and these drivers also do not advertise support fordma-iommu.cviaIOMMU_DOMAIN_DMA, or usearm_iommu_create_mapping(), so largely their implementations ofIOMMU_DOMAIN_UNMANAGEDare untested. This means that a user like vfio/iommufd does not likely work with them.Several of them have obvious problems:
*fsl_pamu_domain.c
Without map/unmap ops in thedefault_domain_ops, it isn't an unmanaged domain at all.
*mtk_iommu_v1.c
With a fixed 4M "pagetable", it can only map exactly 4G of memory, but doesn't set the aperture.
*tegra-gart.c
Its notion of attach/detach and groups has to be a complete lie to get around all the other API expectations.
Quoted 5 lines
Some others might work but have never been tested with vfio/iommufd:
*msm_iommu.c
*omap-iommu.c
*tegra-smmu.c
Do we have a link where all drivers tested with vfio/iommufd have been listed?
In a quick glance at least exynos-iommu.c and apple-dart.c both support UNMANAGED with map/unmap ops. They are not mentioned in above list but I doubt they are tested for vfio/iommufd.
PATCH 2/4 iommu/dma: Do not init domain if broken_unmanaged_domain
In reply to Nicolin ChenAdd a sanity of the broken_unmanaged_domain flag to reject the use of dma-iommu in the early stage, if the flag is set by the iommu driver.
--- drivers/iommu/dma-iommu.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/iommu/dma-iommu.c +3 -0
@@ -545,6 +545,9 @@ static int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,if (!cookie || cookie->type !=IOMMU_DMA_IOVA_COOKIE )return -EINVAL ; +if (WARN_ON (!device_iommu_unmanaged_supported (dev))) +return -EINVAL ; + iovad = &cookie->iovad;/* Use the smallest supported page size for IOVA granularity */
Signature · 1 line
2.39.1
Robin Murphy
maintainerRe: [PATCH 2/4] iommu/dma: Do not init domain if broken_unmanaged_domain
Quoted 2 lines · Nicolin Chen
Add a sanity of the
broken_unmanaged_domainflag to reject the use of dma-iommu in the early stage, if the flag is set by the iommu driver.
Realistically, iommu-dma will never be enabled on PPC32, let alone used. It will not be enabled on ARM until I've fixed any drivers which need fixing to work with it. We don't need to add dead code here.
Thanks,
Robin.
Quoted 20 lines
Suggested-by Jason Gunthorpe <[email protected]>Signed-off-by Nicolin Chen <[email protected]>--- drivers/iommu/dma-iommu.c | 3 +++ 1 file changed, 3 insertions(+)drivers/iommu/dma-iommu.c +3
-0@@ -545,6 +545,9 @@ static int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,if (!cookie || cookie->type !=IOMMU_DMA_IOVA_COOKIE )return -EINVAL ; +if (WARN_ON (!device_iommu_unmanaged_supported (dev))) +return -EINVAL ; + iovad = &cookie->iovad;/* Use the smallest supported page size for IOVA granularity */
Re: [PATCH 2/4] iommu/dma: Do not init domain if broken_unmanaged_domain
Quoted 10 lines · Robin Murphy
External email: Use caution opening links or attachments
Quoted 2 lines · Nicolin Chen
Add a sanity of the
broken_unmanaged_domainflag to reject the use of dma-iommu in the early stage, if the flag is set by the iommu driver.Realistically, iommu-dma will never be enabled on PPC32, let alone used. It will not be enabled on ARM until I've fixed any drivers which need fixing to work with it. We don't need to add dead code here.
OK. Sounds like I can drop this patch.
Thanks
Nicolin
PATCH 3/4 iommufd: Do not allocate device object if broken_unmanaged_domain
In reply to Nicolin ChenAdd a sanity of the broken_unmanaged_domain flag to reject the use of iommufd in the early stage, if the flag is set by the iommu driver.
--- drivers/iommu/iommufd/device.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/iommu/iommufd/device.c +3 -0
@@ -73,6 +73,9 @@ struct iommufd_device *iommufd_device_bind(struct iommufd_ctx *ictx,if (!device_iommu_capable (dev,IOMMU_CAP_CACHE_COHERENCY ))return ERR_PTR (-EINVAL ); +if (!device_iommu_unmanaged_supported (dev)) +return ERR_PTR (-EINVAL ); + group =iommu_group_get (dev);if (!group)return ERR_PTR (-ENODEV );
Signature · 1 line
2.39.1
PATCH 4/4 vfio: Do not allocate domain if broken_unmanaged_domain
In reply to Nicolin ChenAdd a sanity of the broken_unmanaged_domain flag to reject the use of vfio_iommu_type1 in the early stage, if the flag is set by the iommu driver.
--- drivers/vfio/vfio_iommu_type1.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/vfio/vfio_iommu_type1.c +4 -1
@@ -2170,7 +2170,10 @@ static int vfio_iommu_domain_alloc(struct device *dev, void *data) {struct iommu_domain **domain = data; - *domain =iommu_domain_alloc (dev->bus); +if (device_iommu_unmanaged_supported (dev)) + *domain =iommu_domain_alloc (dev->bus); +else + *domain =NULL ;return 1 ;/* Don't iterate */ }
Signature · 1 line
2.39.1
Tian, Kevin
maintainerQuoted 15 lines
From: Nicolin Chen <[email protected]>
Sent: Saturday, January 28, 2023 4:04 AMHi all,
Both
IOMMU_DOMAIN_UNMANAGEDandIOMMU_DOMAIN_DMArequire the support
of__IOMMU_DOMAIN_PAGINGcapability, i.e. iommu_map/unmap. However,
some older iommu drivers do not fully support that, and these drivers also do not advertise support fordma-iommu.cviaIOMMU_DOMAIN_DMA, or usearm_iommu_create_mapping(), so largely their implementations ofIOMMU_DOMAIN_UNMANAGEDare untested. This means that a user like vfio/iommufd does not likely work with them.
Quoted 5 lines
Thus, mark all these drivers as having "broken" UNAMANGED domains and add a new
device_iommu_unmanaged_supported()API for vfio/iommufd and
dma-iommu to refuse to work with these drivers.
Why not making an explicit way to mark which drivers are tested to support vfio/iommufd? Not sure whether pure code review is reliable to filter out 'broken' vs. 'non-broken'...