[PATCH v4 14/17] iommu: Consolidate the default_domain setup to one function

Jason Gunthorpe
2023-04-12T13:51:56Z

Make iommu_change_dev_def_domain() general enough to setup the initial
default_domain or replace it with a new default_domain. Call the new
function iommu_setup_default_domain() and make it the only place in the
code that stores to group->default_domain.

Consolidate the three copies of the default_domain setup sequence. The flow
flow requires:

- Determining the domain type to use
- Checking if the current default domain is the same type
- Allocating a domain
- Doing iommu_create_device_direct_mappings()
- Attaching it to devices
- Store group->default_domain

This adjusts the domain allocation from the prior patch to be able to
detect if each of the allocation steps is already the domain we already
have, which is a more robust version of what change default domain was
already doing.

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/iommu/iommu.c | 202 +++++++++++++++++++-----------------------
1 file changed, 89 insertions(+), 113 deletions(-)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index bbbc4c865dbecd..8744b15f0bd1f0 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -91,9 +91,6 @@ static const char * const iommu_group_resv_type_string[] = {

static int iommu_bus_notifier(struct notifier_block *nb,
unsigned long action, void *data);
-static struct iommu_domain *
-iommu_group_alloc_default_domain(struct iommu_group *group, int req_type);
-static int iommu_get_def_domain_type(struct device *dev);
static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus,
unsigned type);
static int __iommu_attach_device(struct iommu_domain *domain,
@@ -124,7 +121,9 @@ static void __iommu_group_set_domain_nofail(struct iommu_group *group,
group, new_domain, IOMMU_SET_DOMAIN_MUST_SUCCEED));
}

-static int iommu_create_device_direct_mappings(struct iommu_group *group,
+static int iommu_setup_default_domain(struct iommu_group *group,
+ int target_type);
+static int iommu_create_device_direct_mappings(struct iommu_domain *domain,
struct device *dev);
static struct iommu_group *iommu_group_get_for_dev(struct device *dev);
static ssize_t iommu_group_store_type(struct iommu_group *group,
@@ -419,33 +418,18 @@ int iommu_probe_device(struct device *dev)

mutex_lock(&group->mutex);

- iommu_create_device_direct_mappings(group, dev);
+ if (group->default_domain)
+ iommu_create_device_direct_mappings(group->default_domain, dev);

if (group->domain) {
ret = __iommu_device_set_domain(group, dev, group->domain, 0);
+ if (ret)
+ goto err_unlock;
} else if (!group->default_domain) {
- /*
- * Try to allocate a default domain - needs support from the
- * IOMMU driver. There are still some drivers which don't
- * support default domains, so the return value is not yet
- * checked.
- */
- group->default_domain = iommu_group_alloc_default_domain(
- group, iommu_get_def_domain_type(dev));
- if (group->default_domain) {
- iommu_create_device_direct_mappings(group, dev);
- ret = __iommu_group_set_domain(group,
- group->default_domain);
- }
-
- /*
- * We assume that the iommu driver starts up the device in
- * 'set_platform_dma_ops' mode if it does not support default
- * domains.
- */
+ ret = iommu_setup_default_domain(group, 0);
+ if (ret)
+ goto err_unlock;
}
- if (ret)
- goto err_unlock;

mutex_unlock(&group->mutex);
iommu_group_put(group);
@@ -991,16 +975,15 @@ int iommu_group_set_name(struct iommu_group *group, const char *name)
}
EXPORT_SYMBOL_GPL(iommu_group_set_name);

-static int iommu_create_device_direct_mappings(struct iommu_group *group,
+static int iommu_create_device_direct_mappings(struct iommu_domain *domain,
struct device *dev)
{
- struct iommu_domain *domain = group->default_domain;
struct iommu_resv_region *entry;
struct list_head mappings;
unsigned long pg_size;
int ret = 0;

- if (!domain || !iommu_is_dma_domain(domain))
+ if (!iommu_is_dma_domain(domain))
return 0;

BUG_ON(!domain->pgsize_bitmap);
@@ -1671,6 +1654,15 @@ static int iommu_get_def_domain_type(struct device *dev)
return 0;
}

+static struct iommu_domain *
+__iommu_group_alloc_default_domain(struct bus_type *bus,
+ struct iommu_group *group, int req_type)
+{
+ if (group->default_domain && group->default_domain->type == req_type)
+ return group->default_domain;
+ return __iommu_domain_alloc(bus, req_type);
+}
+
/*
* req_type of 0 means "auto" which means to select a domain based on
* iommu_def_domain_type or what the driver actually supports.
@@ -1686,17 +1678,17 @@ iommu_group_alloc_default_domain(struct iommu_group *group, int req_type)
lockdep_assert_held(&group->mutex);

if (req_type)
- return __iommu_domain_alloc(bus, req_type);
+ return __iommu_group_alloc_default_domain(bus, group, req_type);

/* The driver gave no guidance on what type to use, try the default */
- dom = __iommu_domain_alloc(bus, iommu_def_domain_type);
+ dom = __iommu_group_alloc_default_domain(bus, group, iommu_def_domain_type);
if (dom)
return dom;

/* Otherwise IDENTITY and DMA_FQ defaults will try DMA */
if (iommu_def_domain_type == IOMMU_DOMAIN_DMA)
return NULL;
- dom = __iommu_domain_alloc(bus, IOMMU_DOMAIN_DMA);
+ dom = __iommu_group_alloc_default_domain(bus, group, IOMMU_DOMAIN_DMA);
if (!dom)
return NULL;

@@ -1839,21 +1831,6 @@ static void __iommu_group_dma_finalize(struct iommu_group *group)
iommu_group_do_probe_finalize);
}

-static int iommu_do_create_direct_mappings(struct device *dev, void *data)
-{
- struct iommu_group *group = data;
-
- iommu_create_device_direct_mappings(group, dev);
-
- return 0;
-}
-
-static int iommu_group_create_direct_mappings(struct iommu_group *group)
-{
- return __iommu_group_for_each_dev(group, group,
- iommu_do_create_direct_mappings);
-}
-
int bus_iommu_probe(struct bus_type *bus)
{
struct iommu_group *group, *next;
@@ -1875,27 +1852,16 @@ int bus_iommu_probe(struct bus_type *bus)
/* Remove item from the list */
list_del_init(&group->entry);

- /* Try to allocate default domain */
- group->default_domain = iommu_group_alloc_default_domain(
- group, iommu_get_default_domain_type(group, 0));
- if (!group->default_domain) {
+ ret = iommu_setup_default_domain(group, 0);
+ if (ret) {
mutex_unlock(&group->mutex);
- continue;
+ return ret;
}
-
- iommu_group_create_direct_mappings(group);
-
- ret = __iommu_group_set_domain(group, group->default_domain);
-
mutex_unlock(&group->mutex);
-
- if (ret)
- break;
-
__iommu_group_dma_finalize(group);
}

- return ret;
+ return 0;
}

bool iommu_present(struct bus_type *bus)
@@ -2878,68 +2844,83 @@ int iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features feat)
}
EXPORT_SYMBOL_GPL(iommu_dev_disable_feature);

-/*
- * Changes the default domain of an iommu group
- *
- * @group: The group for which the default domain should be changed
- * @dev: The first device in the group
- * @type: The type of the new default domain that gets associated with the group
- *
- * Returns 0 on success and error code on failure
+/**
+ * iommu_setup_default_domain - Set the default_domain for the group
+ * @group: Group to change
+ * @target_type: Domain type to set as the default_domain
*
- * Note:
- * 1. Presently, this function is called only when user requests to change the
- * group's default domain type through /sys/kernel/iommu_groups/<grp_id>/type
- * Please take a closer look if intended to use for other purposes.
+ * Allocate a default domain and set it as the current domain on the group. If
+ * the group already has a default domain it will be changed to the target_type.
+ * When target_type is 0 the default domain is selected based on driver and
+ * system preferences.
*/
-static int iommu_change_dev_def_domain(struct iommu_group *group,
- struct device *dev, int type)
+static int iommu_setup_default_domain(struct iommu_group *group,
+ int target_type)
{
- struct iommu_domain *prev_dom;
+ struct iommu_domain *old_dom = group->default_domain;
+ struct group_device *gdev;
+ struct iommu_domain *dom;
+ int req_type;
int ret;

lockdep_assert_held(&group->mutex);

- prev_dom = group->default_domain;
- type = iommu_get_default_domain_type(group, type);
- if (type < 0)
+ req_type = iommu_get_default_domain_type(group, target_type);
+ if (req_type < 0)
return -EINVAL;

/*
- * Switch to a new domain only if the requested domain type is different
- * from the existing default domain type
+ * There are still some drivers which don't support default domains, so
+ * we ignore the failure and leave group->default_domain NULL.
+ *
+ * We assume that the iommu driver starts up the device in
+ * 'set_platform_dma_ops' mode if it does not support default domains.
*/
- if (prev_dom->type == type)
+ dom = iommu_group_alloc_default_domain(group, req_type);
+ if (!dom) {
+ /* Once in default_domain mode we never leave */
+ if (group->default_domain)
+ return -ENODEV;
+ group->default_domain = NULL;
return 0;
-
- group->default_domain = NULL;
- group->domain = NULL;
-
- /* Sets group->default_domain to the newly allocated domain */
- group->default_domain = iommu_group_alloc_default_domain(group, type);
- if (!group->default_domain) {
- ret = -EINVAL;
- goto restore_old_domain;
}

- group->domain = prev_dom;
- ret = iommu_create_device_direct_mappings(group, dev);
- if (ret)
- goto free_new_domain;
-
- ret = __iommu_group_set_domain(group, group->default_domain);
- if (ret)
- goto free_new_domain;
-
- iommu_domain_free(prev_dom);
+ if (group->default_domain == dom)
+ return 0;

- return 0;
+ /*
+ * IOMMU_RESV_DIRECT and IOMMU_RESV_DIRECT_RELAXABLE regions must be
+ * mapped before their device is attached, in order to guarantee
+ * continuity with any FW activity
+ */
+ for_each_group_device(group, gdev)
+ iommu_create_device_direct_mappings(dom, gdev->dev);

-free_new_domain:
- iommu_domain_free(group->default_domain);
-restore_old_domain:
- group->default_domain = prev_dom;
+ /* We must set default_domain early for __iommu_device_set_domain */
+ group->default_domain = dom;
+ if (!group->domain) {
+ /*
+ * Drivers are not allowed to fail the first domain attach.
+ * The only way to recover from this is to fail attaching the
+ * iommu driver and call ops->release_device. Put the domain
+ * in group->default_domain so it is freed after.
+ */
+ ret = __iommu_group_set_domain_internal(
+ group, dom, IOMMU_SET_DOMAIN_MUST_SUCCEED);
+ if (WARN_ON(ret))
+ goto out_free;
+ } else {
+ ret = __iommu_group_set_domain(group, dom);
+ if (ret) {
+ iommu_domain_free(dom);
+ group->default_domain = old_dom;
+ return ret;
+ }
+ }

+out_free:
+ if (old_dom)
+ iommu_domain_free(old_dom);
return ret;
}

@@ -2955,8 +2936,6 @@ static int iommu_change_dev_def_domain(struct iommu_group *group,
static ssize_t iommu_group_store_type(struct iommu_group *group,
const char *buf, size_t count)
{
- struct group_device *grp_dev;
- struct device *dev;
int ret, req_type;

if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
@@ -2994,10 +2973,7 @@ static ssize_t iommu_group_store_type(struct iommu_group *group,
return -EPERM;
}

- grp_dev = list_first_entry(&group->devices, struct group_device, list);
- dev = grp_dev->dev;
-
- ret = iommu_change_dev_def_domain(group, dev, req_type);
+ ret = iommu_setup_default_domain(group, req_type);

/*
* Release the mutex here because ops->probe_finalize() call-back of
--
2.40.0