Re: [PATCH v6 08/25] iommu: Reorganize iommu_get_default_domain_type() to respect def_domain_type()

Jason Gunthorpe
2023-08-14T17:26:45Z

On Sat, Aug 12, 2023 at 10:15:42AM +0800, Baolu Lu wrote:

>
> How about consolidating above into a single helper?
>
> --- a/drivers/iommu/iommu.c
> +++ b/drivers/iommu/iommu.c
> @@ -1787,6 +1787,21 @@ __iommu_group_alloc_default_domain(struct iommu_group
> *group, int req_type)
> return __iommu_group_domain_alloc(group, req_type);
> }
>
> +/*
> + * Returns the iommu_ops for the devices in an iommu group.
> + *
> + * It is assumed that all devices in an iommu group are managed by a single
> + * IOMMU unit. Therefore, this returns the dev_iommu_ops of the first
> device
> + * in the group.
> + */
> +static const struct iommu_ops *group_iommu_ops(struct iommu_group *group)
> +{
> + struct group_device *device;
> +
> + device = list_first_entry(&group->devices, struct group_device, list);
> + return dev_iommu_ops(device->dev);
> +}

Okay I did this, but it doesn't help as much..

> @@ -2124,13 +2134,9 @@ static struct iommu_domain
> *__iommu_domain_alloc(const struct iommu_ops *ops,
> static struct iommu_domain *
> __iommu_group_domain_alloc(struct iommu_group *group, unsigned int type)
> {
> - struct device *dev =
> - list_first_entry(&group->devices, struct group_device, list)
> - ->dev;
> -
> lockdep_assert_held(&group->mutex);
>
> - return __iommu_domain_alloc(dev_iommu_ops(dev), dev, type);
> + return __iommu_domain_alloc(group_iommu_ops(group), dev, type);
> }

Since this is all still needed to calculate dev

> > +err:
> > + if (target_type) {
> > + dev_err_ratelimited(
> > + gdev->dev,
> > + "Device cannot be in %s domain - it is forcing %s\n",
> > + iommu_domain_type_str(target_type),
> > + iommu_domain_type_str(type));
> > + return -1;
> > + }
> > +
> > + dev_warn(
> > + gdev->dev,
> > + "Device needs domain type %s, but device %s in the same iommu group requires type %s - using default\n",
> > + iommu_domain_type_str(type), dev_name(last_dev),
> > + iommu_domain_type_str(best_type));
> > + return 0;
>
> This doesn't match the commit message, where it states:
>
> "Arrange things so that if the driver says it needs IDENTITY then
> iommu_get_default_domain_type() either fails or returns IDENTITY.
> "
>
> I saw that this change was made in the sequential patch. It is probably
> better to put that here?

Ah, I went over all this again and decided to try again, it is too
complicated. This patch can do what the commit message says and the
following patches are even simpler:

/*
* Combine the driver's choosen def_domain_type across all the devices in a
* group. Drivers must give a consistent result.
*/
static int iommu_get_def_domain_type(struct iommu_group *group,
struct device *dev, int cur_type)
{
const struct iommu_ops *ops = group_iommu_ops(group);
int type;

if (!ops->def_domain_type)
return cur_type;

type = ops->def_domain_type(dev);
if (!type || cur_type == type)
return cur_type;
if (!cur_type)
return type;

dev_err_ratelimited(
dev,
"IOMMU driver error, requesting conflicting def_domain_type, %s and %s, for devices in group %u.\n",
iommu_domain_type_str(cur_type), iommu_domain_type_str(type),
group->id);

/*
* Try to recover, drivers are allowed to force IDENITY or DMA, IDENTITY
* takes precedence.
*/
if (cur_type || type == IOMMU_DOMAIN_IDENTITY)
return IOMMU_DOMAIN_IDENTITY;
return cur_type;
}

/*
* A target_type of 0 will select the best domain type. 0 can be returned in
* this case meaning the global default should be used.
*/
static int iommu_get_default_domain_type(struct iommu_group *group,
int target_type)
{
struct device *untrusted = NULL;
struct group_device *gdev;
int driver_type = 0;

lockdep_assert_held(&group->mutex);

/*
* ARM32 drivers supporting CONFIG_ARM_DMA_USE_IOMMU can declare an
* identity_domain and it will automatically become their default
* domain. Later on ARM_DMA_USE_IOMMU will install its UNMANAGED domain.
* Override the selection to IDENTITY.
*/
if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
static_assert(!(IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) &&
IS_ENABLED(CONFIG_IOMMU_DMA)));
driver_type = IOMMU_DOMAIN_IDENTITY;
}

for_each_group_device(group, gdev) {
driver_type = iommu_get_def_domain_type(group, gdev->dev,
driver_type);

if (dev_is_pci(gdev->dev) && to_pci_dev(gdev->dev)->untrusted) {
/*
* No ARM32 using systems will set untrusted, it cannot
* work.
*/
if (WARN_ON(IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)))
return -1;
untrusted = gdev->dev;
}
}

if (untrusted) {
if (driver_type && driver_type != IOMMU_DOMAIN_DMA) {
dev_err_ratelimited(
untrusted,
"Device is not trusted, but driver is overriding group %u to %s, refusing to probe.\n",
group->id, iommu_domain_type_str(driver_type));
return -1;
}
driver_type = IOMMU_DOMAIN_DMA;
}

if (target_type) {
if (driver_type && target_type != driver_type)
return -1;
return target_type;
}
return driver_type;
}

Thanks,
Jason