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

Reply via email to