* [PATCH 01/11] iommu: Have __iommu_probe_device() check for already probed devices
2023-04-19 16:11 [PATCH 00/11] Consolidate the probe_device path Jason Gunthorpe
@ 2023-04-19 16:11 ` Jason Gunthorpe
2023-04-26 9:12 ` Tian, Kevin
2023-04-19 16:11 ` [PATCH 02/11] iommu: Use iommu_group_ref_get/put() for dev->iommu_group Jason Gunthorpe
` (9 subsequent siblings)
10 siblings, 1 reply; 25+ messages in thread
From: Jason Gunthorpe @ 2023-04-19 16:11 UTC (permalink / raw)
To: Lu Baolu, Christophe Leroy, David Woodhouse, iommu, Joerg Roedel,
Len Brown, linux-acpi, linuxppc-dev, Michael Ellerman,
Nicholas Piggin, Rafael J. Wysocki, Robin Murphy, Will Deacon
Cc: Kevin Tian, Nicolin Chen
This is a step toward making __iommu_probe_device() self contained.
It should, under proper locking, check if the device is already associated
with an iommu driver and resolve parallel probes. All but one of the
callers open code this test using two different means, but they all
rely on dev->iommu_group.
Currently the bus_iommu_probe()/probe_iommu_group() and
probe_acpi_namespace_devices() rejects already probed devices with an
unlocked read of dev->iommu_group. The OF and ACPI "replay" functions use
device_iommu_mapped() which is the same read without the pointless
refcount.
Move this test into __iommu_probe_device() and put it under the
iommu_probe_device_lock. The store to dev->iommu_group is in
iommu_group_add_device() which is also called under this lock for iommu
driver devices, making it properly locked.
The only path that didn't have this check is the hotplug path triggered by
BUS_NOTIFY_ADD_DEVICE. The only way to get dev->iommu_group assigned
outside the probe path is via iommu_group_add_device(). Today there are
only three callers, VFIO no-iommu, powernv and power pseries - none of
these cases probe iommu drivers. Thus adding this additional check is
safe.
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/acpi/scan.c | 2 +-
drivers/iommu/intel/iommu.c | 7 -------
drivers/iommu/iommu.c | 19 +++++++++----------
drivers/iommu/of_iommu.c | 2 +-
4 files changed, 11 insertions(+), 19 deletions(-)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 0c6f06abe3f47f..945866f3bd8ebd 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1579,7 +1579,7 @@ static const struct iommu_ops *acpi_iommu_configure_id(struct device *dev,
* If we have reason to believe the IOMMU driver missed the initial
* iommu_probe_device() call for dev, replay it to get things in order.
*/
- if (!err && dev->bus && !device_iommu_mapped(dev))
+ if (!err && dev->bus)
err = iommu_probe_device(dev);
/* Ignore all other errors apart from EPROBE_DEFER */
diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index b871a6afd80321..3c37b50c121c2d 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -3763,7 +3763,6 @@ static int __init probe_acpi_namespace_devices(void)
for_each_active_dev_scope(drhd->devices,
drhd->devices_cnt, i, dev) {
struct acpi_device_physical_node *pn;
- struct iommu_group *group;
struct acpi_device *adev;
if (dev->bus != &acpi_bus_type)
@@ -3773,12 +3772,6 @@ static int __init probe_acpi_namespace_devices(void)
mutex_lock(&adev->physical_node_lock);
list_for_each_entry(pn,
&adev->physical_node_list, node) {
- group = iommu_group_get(pn->dev);
- if (group) {
- iommu_group_put(group);
- continue;
- }
-
ret = iommu_probe_device(pn->dev);
if (ret)
break;
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 6bd275fb640441..c486e648402d5c 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -347,9 +347,16 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
* but for now enforcing a simple global ordering is fine.
*/
mutex_lock(&iommu_probe_device_lock);
+
+ /* Device is probed already if in a group */
+ if (dev->iommu_group) {
+ ret = 0;
+ goto out_unlock;
+ }
+
if (!dev_iommu_get(dev)) {
ret = -ENOMEM;
- goto err_unlock;
+ goto out_unlock;
}
if (!try_module_get(ops->owner)) {
@@ -395,7 +402,7 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
err_free:
dev_iommu_free(dev);
-err_unlock:
+out_unlock:
mutex_unlock(&iommu_probe_device_lock);
return ret;
@@ -1707,16 +1714,8 @@ struct iommu_domain *iommu_group_default_domain(struct iommu_group *group)
static int probe_iommu_group(struct device *dev, void *data)
{
struct list_head *group_list = data;
- struct iommu_group *group;
int ret;
- /* Device is probed already if in a group */
- group = iommu_group_get(dev);
- if (group) {
- iommu_group_put(group);
- return 0;
- }
-
ret = __iommu_probe_device(dev, group_list);
if (ret == -ENODEV)
ret = 0;
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
index 40f57d293a79d4..157b286e36bf3a 100644
--- a/drivers/iommu/of_iommu.c
+++ b/drivers/iommu/of_iommu.c
@@ -159,7 +159,7 @@ const struct iommu_ops *of_iommu_configure(struct device *dev,
* If we have reason to believe the IOMMU driver missed the initial
* probe for dev, replay it to get things in order.
*/
- if (!err && dev->bus && !device_iommu_mapped(dev))
+ if (!err && dev->bus)
err = iommu_probe_device(dev);
/* Ignore all other errors apart from EPROBE_DEFER */
--
2.40.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* RE: [PATCH 01/11] iommu: Have __iommu_probe_device() check for already probed devices
2023-04-19 16:11 ` [PATCH 01/11] iommu: Have __iommu_probe_device() check for already probed devices Jason Gunthorpe
@ 2023-04-26 9:12 ` Tian, Kevin
0 siblings, 0 replies; 25+ messages in thread
From: Tian, Kevin @ 2023-04-26 9:12 UTC (permalink / raw)
To: Jason Gunthorpe, Lu Baolu, Christophe Leroy, David Woodhouse,
iommu@lists.linux.dev, Joerg Roedel, Len Brown,
linux-acpi@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
Michael Ellerman, Nicholas Piggin, Rafael J. Wysocki,
Robin Murphy, Will Deacon
Cc: Nicolin Chen
> From: Jason Gunthorpe <jgg@nvidia.com>
> Sent: Thursday, April 20, 2023 12:12 AM
>
> This is a step toward making __iommu_probe_device() self contained.
>
> It should, under proper locking, check if the device is already associated
> with an iommu driver and resolve parallel probes. All but one of the
> callers open code this test using two different means, but they all
> rely on dev->iommu_group.
>
> Currently the bus_iommu_probe()/probe_iommu_group() and
> probe_acpi_namespace_devices() rejects already probed devices with an
> unlocked read of dev->iommu_group. The OF and ACPI "replay" functions
> use
> device_iommu_mapped() which is the same read without the pointless
> refcount.
>
> Move this test into __iommu_probe_device() and put it under the
> iommu_probe_device_lock. The store to dev->iommu_group is in
> iommu_group_add_device() which is also called under this lock for iommu
> driver devices, making it properly locked.
>
> The only path that didn't have this check is the hotplug path triggered by
> BUS_NOTIFY_ADD_DEVICE. The only way to get dev->iommu_group assigned
> outside the probe path is via iommu_group_add_device(). Today there are
> only three callers, VFIO no-iommu, powernv and power pseries - none of
> these cases probe iommu drivers. Thus adding this additional check is
> safe.
>
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 02/11] iommu: Use iommu_group_ref_get/put() for dev->iommu_group
2023-04-19 16:11 [PATCH 00/11] Consolidate the probe_device path Jason Gunthorpe
2023-04-19 16:11 ` [PATCH 01/11] iommu: Have __iommu_probe_device() check for already probed devices Jason Gunthorpe
@ 2023-04-19 16:11 ` Jason Gunthorpe
2023-04-26 9:12 ` Tian, Kevin
2023-04-19 16:11 ` [PATCH 03/11] iommu: Inline iommu_group_get_for_dev() into __iommu_probe_device() Jason Gunthorpe
` (8 subsequent siblings)
10 siblings, 1 reply; 25+ messages in thread
From: Jason Gunthorpe @ 2023-04-19 16:11 UTC (permalink / raw)
To: Lu Baolu, Christophe Leroy, David Woodhouse, iommu, Joerg Roedel,
Len Brown, linux-acpi, linuxppc-dev, Michael Ellerman,
Nicholas Piggin, Rafael J. Wysocki, Robin Murphy, Will Deacon
Cc: Kevin Tian, Nicolin Chen
No reason to open code this, use the proper helper functions.
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/iommu/iommu.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index c486e648402d5c..73e9f50fba9dd2 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -496,7 +496,7 @@ static void __iommu_group_release_device(struct iommu_group *group,
kfree(grp_dev->name);
kfree(grp_dev);
dev->iommu_group = NULL;
- kobject_put(group->devices_kobj);
+ iommu_group_put(group);
}
static void iommu_release_device(struct device *dev)
@@ -1063,8 +1063,7 @@ int iommu_group_add_device(struct iommu_group *group, struct device *dev)
goto err_free_name;
}
- kobject_get(group->devices_kobj);
-
+ iommu_group_ref_get(group);
dev->iommu_group = group;
mutex_lock(&group->mutex);
--
2.40.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* RE: [PATCH 02/11] iommu: Use iommu_group_ref_get/put() for dev->iommu_group
2023-04-19 16:11 ` [PATCH 02/11] iommu: Use iommu_group_ref_get/put() for dev->iommu_group Jason Gunthorpe
@ 2023-04-26 9:12 ` Tian, Kevin
0 siblings, 0 replies; 25+ messages in thread
From: Tian, Kevin @ 2023-04-26 9:12 UTC (permalink / raw)
To: Jason Gunthorpe, Lu Baolu, Christophe Leroy, David Woodhouse,
iommu@lists.linux.dev, Joerg Roedel, Len Brown,
linux-acpi@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
Michael Ellerman, Nicholas Piggin, Rafael J. Wysocki,
Robin Murphy, Will Deacon
Cc: Nicolin Chen
> From: Jason Gunthorpe <jgg@nvidia.com>
> Sent: Thursday, April 20, 2023 12:12 AM
>
> No reason to open code this, use the proper helper functions.
>
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 03/11] iommu: Inline iommu_group_get_for_dev() into __iommu_probe_device()
2023-04-19 16:11 [PATCH 00/11] Consolidate the probe_device path Jason Gunthorpe
2023-04-19 16:11 ` [PATCH 01/11] iommu: Have __iommu_probe_device() check for already probed devices Jason Gunthorpe
2023-04-19 16:11 ` [PATCH 02/11] iommu: Use iommu_group_ref_get/put() for dev->iommu_group Jason Gunthorpe
@ 2023-04-19 16:11 ` Jason Gunthorpe
2023-04-26 9:21 ` Tian, Kevin
2023-04-19 16:11 ` [PATCH 04/11] iommu: Simplify the __iommu_group_remove_device() flow Jason Gunthorpe
` (7 subsequent siblings)
10 siblings, 1 reply; 25+ messages in thread
From: Jason Gunthorpe @ 2023-04-19 16:11 UTC (permalink / raw)
To: Lu Baolu, Christophe Leroy, David Woodhouse, iommu, Joerg Roedel,
Len Brown, linux-acpi, linuxppc-dev, Michael Ellerman,
Nicholas Piggin, Rafael J. Wysocki, Robin Murphy, Will Deacon
Cc: Kevin Tian, Nicolin Chen
This is the only caller, and it doesn't need the generality of the
function. We already know there is no iommu_group, so it is simply two
function calls.
Moving it here allows the following patches to split the logic in these
functions.
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/iommu/iommu.c | 50 ++++++++-----------------------------------
1 file changed, 9 insertions(+), 41 deletions(-)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 73e9f50fba9dd2..e08856c17121d8 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -126,7 +126,6 @@ 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,
const char *buf, size_t count);
@@ -375,12 +374,18 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
if (ops->is_attach_deferred)
dev->iommu->attach_deferred = ops->is_attach_deferred(dev);
- group = iommu_group_get_for_dev(dev);
+ group = ops->device_group(dev);
+ if (WARN_ON_ONCE(group == NULL))
+ group = ERR_PTR(-EINVAL);
if (IS_ERR(group)) {
ret = PTR_ERR(group);
goto out_release;
}
+ ret = iommu_group_add_device(group, dev);
+ if (ret)
+ goto err_put_group;
+
mutex_lock(&group->mutex);
if (group_list && !group->default_domain && list_empty(&group->entry))
list_add_tail(&group->entry, group_list);
@@ -392,6 +397,8 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
return 0;
+err_put_group:
+ iommu_group_put(group);
out_release:
if (ops->release_device)
ops->release_device(dev);
@@ -1666,45 +1673,6 @@ iommu_group_alloc_default_domain(struct iommu_group *group, int req_type)
return dom;
}
-/**
- * iommu_group_get_for_dev - Find or create the IOMMU group for a device
- * @dev: target device
- *
- * This function is intended to be called by IOMMU drivers and extended to
- * support common, bus-defined algorithms when determining or creating the
- * IOMMU group for a device. On success, the caller will hold a reference
- * to the returned IOMMU group, which will already include the provided
- * device. The reference should be released with iommu_group_put().
- */
-static struct iommu_group *iommu_group_get_for_dev(struct device *dev)
-{
- const struct iommu_ops *ops = dev_iommu_ops(dev);
- struct iommu_group *group;
- int ret;
-
- group = iommu_group_get(dev);
- if (group)
- return group;
-
- group = ops->device_group(dev);
- if (WARN_ON_ONCE(group == NULL))
- return ERR_PTR(-EINVAL);
-
- if (IS_ERR(group))
- return group;
-
- ret = iommu_group_add_device(group, dev);
- if (ret)
- goto out_put_group;
-
- return group;
-
-out_put_group:
- iommu_group_put(group);
-
- return ERR_PTR(ret);
-}
-
struct iommu_domain *iommu_group_default_domain(struct iommu_group *group)
{
return group->default_domain;
--
2.40.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* RE: [PATCH 03/11] iommu: Inline iommu_group_get_for_dev() into __iommu_probe_device()
2023-04-19 16:11 ` [PATCH 03/11] iommu: Inline iommu_group_get_for_dev() into __iommu_probe_device() Jason Gunthorpe
@ 2023-04-26 9:21 ` Tian, Kevin
0 siblings, 0 replies; 25+ messages in thread
From: Tian, Kevin @ 2023-04-26 9:21 UTC (permalink / raw)
To: Jason Gunthorpe, Lu Baolu, Christophe Leroy, David Woodhouse,
iommu@lists.linux.dev, Joerg Roedel, Len Brown,
linux-acpi@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
Michael Ellerman, Nicholas Piggin, Rafael J. Wysocki,
Robin Murphy, Will Deacon
Cc: Nicolin Chen
> From: Jason Gunthorpe <jgg@nvidia.com>
> Sent: Thursday, April 20, 2023 12:12 AM
>
> This is the only caller, and it doesn't need the generality of the
> function. We already know there is no iommu_group, so it is simply two
> function calls.
>
> Moving it here allows the following patches to split the logic in these
> functions.
>
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 04/11] iommu: Simplify the __iommu_group_remove_device() flow
2023-04-19 16:11 [PATCH 00/11] Consolidate the probe_device path Jason Gunthorpe
` (2 preceding siblings ...)
2023-04-19 16:11 ` [PATCH 03/11] iommu: Inline iommu_group_get_for_dev() into __iommu_probe_device() Jason Gunthorpe
@ 2023-04-19 16:11 ` Jason Gunthorpe
2023-04-26 9:21 ` Tian, Kevin
2023-04-19 16:11 ` [PATCH 05/11] iommu: Add iommu_init/deinit_driver() paired functions Jason Gunthorpe
` (6 subsequent siblings)
10 siblings, 1 reply; 25+ messages in thread
From: Jason Gunthorpe @ 2023-04-19 16:11 UTC (permalink / raw)
To: Lu Baolu, Christophe Leroy, David Woodhouse, iommu, Joerg Roedel,
Len Brown, linux-acpi, linuxppc-dev, Michael Ellerman,
Nicholas Piggin, Rafael J. Wysocki, Robin Murphy, Will Deacon
Cc: Kevin Tian, Nicolin Chen
Instead of returning the struct group_device and then later freeing it, do
the entire free under the group->mutex and defer only putting the
iommu_group.
It is safe to remove the sysfs_links and free memory while holding that
mutex.
Move the sanity assert of the group status into
__iommu_group_free_device().
The next patch will improve upon this and consolidate the group put and
the mutex into __iommu_group_remove_device().
__iommu_group_free_device() is close to being the paired undo of
iommu_group_add_device(), following patches will improve on that.
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/iommu/iommu.c | 83 ++++++++++++++++++++-----------------------
1 file changed, 39 insertions(+), 44 deletions(-)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index e08856c17121d8..471f19f7de8c4a 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -466,32 +466,8 @@ int iommu_probe_device(struct device *dev)
}
-/*
- * Remove a device from a group's device list and return the group device
- * if successful.
- */
-static struct group_device *
-__iommu_group_remove_device(struct iommu_group *group, struct device *dev)
-{
- struct group_device *device;
-
- lockdep_assert_held(&group->mutex);
- for_each_group_device(group, device) {
- if (device->dev == dev) {
- list_del(&device->list);
- return device;
- }
- }
-
- return NULL;
-}
-
-/*
- * Release a device from its group and decrements the iommu group reference
- * count.
- */
-static void __iommu_group_release_device(struct iommu_group *group,
- struct group_device *grp_dev)
+static void __iommu_group_free_device(struct iommu_group *group,
+ struct group_device *grp_dev)
{
struct device *dev = grp_dev->dev;
@@ -500,16 +476,45 @@ static void __iommu_group_release_device(struct iommu_group *group,
trace_remove_device_from_group(group->id, dev);
+ /*
+ * If the group has become empty then ownership must have been
+ * released, and the current domain must be set back to NULL or
+ * the default domain.
+ */
+ if (list_empty(&group->devices))
+ WARN_ON(group->owner_cnt ||
+ group->domain != group->default_domain);
+
kfree(grp_dev->name);
kfree(grp_dev);
dev->iommu_group = NULL;
- iommu_group_put(group);
}
-static void iommu_release_device(struct device *dev)
+/*
+ * Remove the iommu_group from the struct device. The attached group must be put
+ * by the caller after releaseing the group->mutex.
+ */
+static void __iommu_group_remove_device(struct device *dev)
{
struct iommu_group *group = dev->iommu_group;
struct group_device *device;
+
+ lockdep_assert_held(&group->mutex);
+ for_each_group_device(group, device) {
+ if (device->dev != dev)
+ continue;
+
+ list_del(&device->list);
+ __iommu_group_free_device(group, device);
+ /* Caller must put iommu_group */
+ return;
+ }
+ WARN(true, "Corrupted iommu_group device_list");
+}
+
+static void iommu_release_device(struct device *dev)
+{
+ struct iommu_group *group = dev->iommu_group;
const struct iommu_ops *ops;
if (!dev->iommu || !group)
@@ -518,16 +523,7 @@ static void iommu_release_device(struct device *dev)
iommu_device_unlink(dev->iommu->iommu_dev, dev);
mutex_lock(&group->mutex);
- device = __iommu_group_remove_device(group, dev);
-
- /*
- * If the group has become empty then ownership must have been released,
- * and the current domain must be set back to NULL or the default
- * domain.
- */
- if (list_empty(&group->devices))
- WARN_ON(group->owner_cnt ||
- group->domain != group->default_domain);
+ __iommu_group_remove_device(dev);
/*
* release_device() must stop using any attached domain on the device.
@@ -543,8 +539,8 @@ static void iommu_release_device(struct device *dev)
ops->release_device(dev);
mutex_unlock(&group->mutex);
- if (device)
- __iommu_group_release_device(group, device);
+ /* Pairs with the get in iommu_group_add_device() */
+ iommu_group_put(group);
module_put(ops->owner);
dev_iommu_free(dev);
@@ -1103,7 +1099,6 @@ EXPORT_SYMBOL_GPL(iommu_group_add_device);
void iommu_group_remove_device(struct device *dev)
{
struct iommu_group *group = dev->iommu_group;
- struct group_device *device;
if (!group)
return;
@@ -1111,11 +1106,11 @@ void iommu_group_remove_device(struct device *dev)
dev_info(dev, "Removing from iommu group %d\n", group->id);
mutex_lock(&group->mutex);
- device = __iommu_group_remove_device(group, dev);
+ __iommu_group_remove_device(dev);
mutex_unlock(&group->mutex);
- if (device)
- __iommu_group_release_device(group, device);
+ /* Pairs with the get in iommu_group_add_device() */
+ iommu_group_put(group);
}
EXPORT_SYMBOL_GPL(iommu_group_remove_device);
--
2.40.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* RE: [PATCH 04/11] iommu: Simplify the __iommu_group_remove_device() flow
2023-04-19 16:11 ` [PATCH 04/11] iommu: Simplify the __iommu_group_remove_device() flow Jason Gunthorpe
@ 2023-04-26 9:21 ` Tian, Kevin
0 siblings, 0 replies; 25+ messages in thread
From: Tian, Kevin @ 2023-04-26 9:21 UTC (permalink / raw)
To: Jason Gunthorpe, Lu Baolu, Christophe Leroy, David Woodhouse,
iommu@lists.linux.dev, Joerg Roedel, Len Brown,
linux-acpi@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
Michael Ellerman, Nicholas Piggin, Rafael J. Wysocki,
Robin Murphy, Will Deacon
Cc: Nicolin Chen
> From: Jason Gunthorpe <jgg@nvidia.com>
> Sent: Thursday, April 20, 2023 12:12 AM
>
> Instead of returning the struct group_device and then later freeing it, do
> the entire free under the group->mutex and defer only putting the
> iommu_group.
>
> It is safe to remove the sysfs_links and free memory while holding that
> mutex.
>
> Move the sanity assert of the group status into
> __iommu_group_free_device().
>
> The next patch will improve upon this and consolidate the group put and
> the mutex into __iommu_group_remove_device().
>
> __iommu_group_free_device() is close to being the paired undo of
> iommu_group_add_device(), following patches will improve on that.
>
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 05/11] iommu: Add iommu_init/deinit_driver() paired functions
2023-04-19 16:11 [PATCH 00/11] Consolidate the probe_device path Jason Gunthorpe
` (3 preceding siblings ...)
2023-04-19 16:11 ` [PATCH 04/11] iommu: Simplify the __iommu_group_remove_device() flow Jason Gunthorpe
@ 2023-04-19 16:11 ` Jason Gunthorpe
2023-04-26 9:41 ` Tian, Kevin
2023-04-19 16:11 ` [PATCH 06/11] iommu: Move the iommu driver sysfs setup into iommu_init/deinit_driver() Jason Gunthorpe
` (5 subsequent siblings)
10 siblings, 1 reply; 25+ messages in thread
From: Jason Gunthorpe @ 2023-04-19 16:11 UTC (permalink / raw)
To: Lu Baolu, Christophe Leroy, David Woodhouse, iommu, Joerg Roedel,
Len Brown, linux-acpi, linuxppc-dev, Michael Ellerman,
Nicholas Piggin, Rafael J. Wysocki, Robin Murphy, Will Deacon
Cc: Kevin Tian, Nicolin Chen
Move the driver init and destruction code into two logically paired
functions.
There is a subtle ordering dependency in how the group's domains are
freed, the current code does the kobject_put() on the group which will
hopefully trigger the free of the domains before the module_put() that
protects the domain->ops.
Reorganize this to be explicit and documented. The domains are cleaned up
by iommu_deinit_driver() if it is the last device to be deinit'd from the
group. This must be done in a specific order - after
ops->release_device() and before the module_put(). Make it very clear and
obvious by putting the order directly in one function.
Leave WARN_ON's in case the refcounting gets messed up somehow.
This also moves the module_put() and dev_iommu_free() under the
group->mutex to keep the code simple.
Building paired functions like this helps ensure that error cleanup flows
in __iommu_probe_device() are correct because they share the same code
that handles the normal flow. These details become relavent as following
patches add more error unwind into __iommu_probe_device(), and ultimately
a following series adds fine-grained locking to __iommu_probe_device().
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/iommu/iommu.c | 186 ++++++++++++++++++++++++------------------
1 file changed, 108 insertions(+), 78 deletions(-)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 471f19f7de8c4a..e428de5b386833 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -328,10 +328,95 @@ static u32 dev_iommu_get_max_pasids(struct device *dev)
return min_t(u32, max_pasids, dev->iommu->iommu_dev->max_pasids);
}
+static int iommu_init_driver(struct device *dev, const struct iommu_ops *ops)
+{
+ struct iommu_device *iommu_dev;
+ struct iommu_group *group;
+ int ret;
+
+ if (!dev_iommu_get(dev))
+ return -ENOMEM;
+
+ if (!try_module_get(ops->owner)) {
+ ret = -EINVAL;
+ goto err_free;
+ }
+
+ iommu_dev = ops->probe_device(dev);
+ if (IS_ERR(iommu_dev)) {
+ ret = PTR_ERR(iommu_dev);
+ goto err_module_put;
+ }
+
+ group = ops->device_group(dev);
+ if (WARN_ON_ONCE(group == NULL))
+ group = ERR_PTR(-EINVAL);
+ if (IS_ERR(group)) {
+ ret = PTR_ERR(group);
+ goto err_release;
+ }
+ dev->iommu_group = group;
+
+ dev->iommu->iommu_dev = iommu_dev;
+ dev->iommu->max_pasids = dev_iommu_get_max_pasids(dev);
+ if (ops->is_attach_deferred)
+ dev->iommu->attach_deferred = ops->is_attach_deferred(dev);
+ return 0;
+
+err_release:
+ if (ops->release_device)
+ ops->release_device(dev);
+err_module_put:
+ module_put(ops->owner);
+err_free:
+ dev_iommu_free(dev);
+ return ret;
+}
+
+static void iommu_deinit_driver(struct device *dev)
+{
+ struct iommu_group *group = dev->iommu_group;
+ const struct iommu_ops *ops = dev_iommu_ops(dev);
+
+ lockdep_assert_held(&group->mutex);
+
+ /*
+ * release_device() must stop using any attached domain on the device.
+ * If there are still other devices in the group they are not effected
+ * by this callback.
+ *
+ * The IOMMU driver must set the device to either an identity or
+ * blocking translation and stop using any domain pointer, as it is
+ * going to be freed.
+ */
+ if (ops->release_device)
+ ops->release_device(dev);
+
+ /*
+ * If this is the last driver to use the group then we must free the
+ * domains before we do the module_put().
+ */
+ if (list_empty(&group->devices)) {
+ if (group->default_domain) {
+ iommu_domain_free(group->default_domain);
+ group->default_domain = NULL;
+ }
+ if (group->blocking_domain) {
+ iommu_domain_free(group->blocking_domain);
+ group->blocking_domain = NULL;
+ }
+ group->domain = NULL;
+ }
+
+ /* Caller must put iommu_group */
+ dev->iommu_group = NULL;
+ module_put(ops->owner);
+ dev_iommu_free(dev);
+}
+
static int __iommu_probe_device(struct device *dev, struct list_head *group_list)
{
const struct iommu_ops *ops = dev->bus->iommu_ops;
- struct iommu_device *iommu_dev;
struct iommu_group *group;
static DEFINE_MUTEX(iommu_probe_device_lock);
int ret;
@@ -353,62 +438,30 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
goto out_unlock;
}
- if (!dev_iommu_get(dev)) {
- ret = -ENOMEM;
+ ret = iommu_init_driver(dev, ops);
+ if (ret)
goto out_unlock;
- }
-
- if (!try_module_get(ops->owner)) {
- ret = -EINVAL;
- goto err_free;
- }
-
- iommu_dev = ops->probe_device(dev);
- if (IS_ERR(iommu_dev)) {
- ret = PTR_ERR(iommu_dev);
- goto out_module_put;
- }
-
- dev->iommu->iommu_dev = iommu_dev;
- dev->iommu->max_pasids = dev_iommu_get_max_pasids(dev);
- if (ops->is_attach_deferred)
- dev->iommu->attach_deferred = ops->is_attach_deferred(dev);
-
- group = ops->device_group(dev);
- if (WARN_ON_ONCE(group == NULL))
- group = ERR_PTR(-EINVAL);
- if (IS_ERR(group)) {
- ret = PTR_ERR(group);
- goto out_release;
- }
+ group = dev->iommu_group;
ret = iommu_group_add_device(group, dev);
+ mutex_lock(&group->mutex);
if (ret)
goto err_put_group;
- mutex_lock(&group->mutex);
if (group_list && !group->default_domain && list_empty(&group->entry))
list_add_tail(&group->entry, group_list);
mutex_unlock(&group->mutex);
iommu_group_put(group);
mutex_unlock(&iommu_probe_device_lock);
- iommu_device_link(iommu_dev, dev);
+ iommu_device_link(dev->iommu->iommu_dev, dev);
return 0;
err_put_group:
+ iommu_deinit_driver(dev);
+ mutex_unlock(&group->mutex);
iommu_group_put(group);
-out_release:
- if (ops->release_device)
- ops->release_device(dev);
-
-out_module_put:
- module_put(ops->owner);
-
-err_free:
- dev_iommu_free(dev);
-
out_unlock:
mutex_unlock(&iommu_probe_device_lock);
@@ -487,18 +540,15 @@ static void __iommu_group_free_device(struct iommu_group *group,
kfree(grp_dev->name);
kfree(grp_dev);
- dev->iommu_group = NULL;
}
-/*
- * Remove the iommu_group from the struct device. The attached group must be put
- * by the caller after releaseing the group->mutex.
- */
+/* Remove the iommu_group from the struct device. */
static void __iommu_group_remove_device(struct device *dev)
{
struct iommu_group *group = dev->iommu_group;
struct group_device *device;
+ mutex_lock(&group->mutex);
lockdep_assert_held(&group->mutex);
for_each_group_device(group, device) {
if (device->dev != dev)
@@ -506,44 +556,30 @@ static void __iommu_group_remove_device(struct device *dev)
list_del(&device->list);
__iommu_group_free_device(group, device);
- /* Caller must put iommu_group */
- return;
+ if (dev->iommu && dev->iommu->iommu_dev)
+ iommu_deinit_driver(dev);
+ else
+ dev->iommu_group = NULL;
+ goto out;
}
WARN(true, "Corrupted iommu_group device_list");
+out:
+ mutex_unlock(&group->mutex);
+
+ /* Pairs with the get in iommu_group_add_device() */
+ iommu_group_put(group);
}
static void iommu_release_device(struct device *dev)
{
struct iommu_group *group = dev->iommu_group;
- const struct iommu_ops *ops;
if (!dev->iommu || !group)
return;
iommu_device_unlink(dev->iommu->iommu_dev, dev);
- mutex_lock(&group->mutex);
__iommu_group_remove_device(dev);
-
- /*
- * release_device() must stop using any attached domain on the device.
- * If there are still other devices in the group they are not effected
- * by this callback.
- *
- * The IOMMU driver must set the device to either an identity or
- * blocking translation and stop using any domain pointer, as it is
- * going to be freed.
- */
- ops = dev_iommu_ops(dev);
- if (ops->release_device)
- ops->release_device(dev);
- mutex_unlock(&group->mutex);
-
- /* Pairs with the get in iommu_group_add_device() */
- iommu_group_put(group);
-
- module_put(ops->owner);
- dev_iommu_free(dev);
}
static int __init iommu_set_def_domain_type(char *str)
@@ -804,10 +840,9 @@ static void iommu_group_release(struct kobject *kobj)
ida_free(&iommu_group_ida, group->id);
- if (group->default_domain)
- iommu_domain_free(group->default_domain);
- if (group->blocking_domain)
- iommu_domain_free(group->blocking_domain);
+ /* Domains are free'd by iommu_deinit_driver() */
+ WARN_ON(group->default_domain);
+ WARN_ON(group->blocking_domain);
kfree(group->name);
kfree(group);
@@ -1105,12 +1140,7 @@ void iommu_group_remove_device(struct device *dev)
dev_info(dev, "Removing from iommu group %d\n", group->id);
- mutex_lock(&group->mutex);
__iommu_group_remove_device(dev);
- mutex_unlock(&group->mutex);
-
- /* Pairs with the get in iommu_group_add_device() */
- iommu_group_put(group);
}
EXPORT_SYMBOL_GPL(iommu_group_remove_device);
--
2.40.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* RE: [PATCH 05/11] iommu: Add iommu_init/deinit_driver() paired functions
2023-04-19 16:11 ` [PATCH 05/11] iommu: Add iommu_init/deinit_driver() paired functions Jason Gunthorpe
@ 2023-04-26 9:41 ` Tian, Kevin
2023-04-26 14:36 ` Jason Gunthorpe
0 siblings, 1 reply; 25+ messages in thread
From: Tian, Kevin @ 2023-04-26 9:41 UTC (permalink / raw)
To: Jason Gunthorpe, Lu Baolu, Christophe Leroy, David Woodhouse,
iommu@lists.linux.dev, Joerg Roedel, Len Brown,
linux-acpi@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
Michael Ellerman, Nicholas Piggin, Rafael J. Wysocki,
Robin Murphy, Will Deacon
Cc: Nicolin Chen
> From: Jason Gunthorpe <jgg@nvidia.com>
> Sent: Thursday, April 20, 2023 12:12 AM
>
> +static int iommu_init_driver(struct device *dev, const struct iommu_ops
> *ops)
would iommu_init_device() better fit the purpose?
otherwise,
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 05/11] iommu: Add iommu_init/deinit_driver() paired functions
2023-04-26 9:41 ` Tian, Kevin
@ 2023-04-26 14:36 ` Jason Gunthorpe
0 siblings, 0 replies; 25+ messages in thread
From: Jason Gunthorpe @ 2023-04-26 14:36 UTC (permalink / raw)
To: Tian, Kevin
Cc: Will Deacon, Rafael J. Wysocki, linuxppc-dev@lists.ozlabs.org,
Joerg Roedel, Robin Murphy, linux-acpi@vger.kernel.org,
iommu@lists.linux.dev, Nicolin Chen, Nicholas Piggin, Lu Baolu,
David Woodhouse, Len Brown
On Wed, Apr 26, 2023 at 09:41:38AM +0000, Tian, Kevin wrote:
> > From: Jason Gunthorpe <jgg@nvidia.com>
> > Sent: Thursday, April 20, 2023 12:12 AM
> >
> > +static int iommu_init_driver(struct device *dev, const struct iommu_ops
> > *ops)
>
> would iommu_init_device() better fit the purpose?
Yeah.. that does seem better
Broadly this mostly sets up dev->iommu and gets the driver
connected to the device
Jason
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 06/11] iommu: Move the iommu driver sysfs setup into iommu_init/deinit_driver()
2023-04-19 16:11 [PATCH 00/11] Consolidate the probe_device path Jason Gunthorpe
` (4 preceding siblings ...)
2023-04-19 16:11 ` [PATCH 05/11] iommu: Add iommu_init/deinit_driver() paired functions Jason Gunthorpe
@ 2023-04-19 16:11 ` Jason Gunthorpe
2023-04-26 9:41 ` Tian, Kevin
2023-04-19 16:11 ` [PATCH 07/11] iommu: Do not export iommu_device_link/unlink() Jason Gunthorpe
` (4 subsequent siblings)
10 siblings, 1 reply; 25+ messages in thread
From: Jason Gunthorpe @ 2023-04-19 16:11 UTC (permalink / raw)
To: Lu Baolu, Christophe Leroy, David Woodhouse, iommu, Joerg Roedel,
Len Brown, linux-acpi, linuxppc-dev, Michael Ellerman,
Nicholas Piggin, Rafael J. Wysocki, Robin Murphy, Will Deacon
Cc: Kevin Tian, Nicolin Chen
It makes logical sense that once the driver is attached to the device the
sysfs links appear, even if we haven't fully created the group_device or
attached the device to a domain.
Fix the missing error handling on sysfs creation since
iommu_init_driver() can trivially handle this.
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/iommu/iommu-sysfs.c | 6 ------
drivers/iommu/iommu.c | 13 +++++++++----
2 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/drivers/iommu/iommu-sysfs.c b/drivers/iommu/iommu-sysfs.c
index 99869217fbec7d..c8aba0e2a30d70 100644
--- a/drivers/iommu/iommu-sysfs.c
+++ b/drivers/iommu/iommu-sysfs.c
@@ -107,9 +107,6 @@ int iommu_device_link(struct iommu_device *iommu, struct device *link)
{
int ret;
- if (!iommu || IS_ERR(iommu))
- return -ENODEV;
-
ret = sysfs_add_link_to_group(&iommu->dev->kobj, "devices",
&link->kobj, dev_name(link));
if (ret)
@@ -126,9 +123,6 @@ EXPORT_SYMBOL_GPL(iommu_device_link);
void iommu_device_unlink(struct iommu_device *iommu, struct device *link)
{
- if (!iommu || IS_ERR(iommu))
- return;
-
sysfs_remove_link(&link->kobj, "iommu");
sysfs_remove_link_from_group(&iommu->dev->kobj, "devices", dev_name(link));
}
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index e428de5b386833..dbaf3ed9012c45 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -348,12 +348,16 @@ static int iommu_init_driver(struct device *dev, const struct iommu_ops *ops)
goto err_module_put;
}
+ ret = iommu_device_link(iommu_dev, dev);
+ if (ret)
+ goto err_release;
+
group = ops->device_group(dev);
if (WARN_ON_ONCE(group == NULL))
group = ERR_PTR(-EINVAL);
if (IS_ERR(group)) {
ret = PTR_ERR(group);
- goto err_release;
+ goto err_unlink;
}
dev->iommu_group = group;
@@ -363,6 +367,8 @@ static int iommu_init_driver(struct device *dev, const struct iommu_ops *ops)
dev->iommu->attach_deferred = ops->is_attach_deferred(dev);
return 0;
+err_unlink:
+ iommu_device_unlink(iommu_dev, dev);
err_release:
if (ops->release_device)
ops->release_device(dev);
@@ -380,6 +386,8 @@ static void iommu_deinit_driver(struct device *dev)
lockdep_assert_held(&group->mutex);
+ iommu_device_unlink(dev->iommu->iommu_dev, dev);
+
/*
* release_device() must stop using any attached domain on the device.
* If there are still other devices in the group they are not effected
@@ -454,7 +462,6 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
iommu_group_put(group);
mutex_unlock(&iommu_probe_device_lock);
- iommu_device_link(dev->iommu->iommu_dev, dev);
return 0;
@@ -577,8 +584,6 @@ static void iommu_release_device(struct device *dev)
if (!dev->iommu || !group)
return;
- iommu_device_unlink(dev->iommu->iommu_dev, dev);
-
__iommu_group_remove_device(dev);
}
--
2.40.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* RE: [PATCH 06/11] iommu: Move the iommu driver sysfs setup into iommu_init/deinit_driver()
2023-04-19 16:11 ` [PATCH 06/11] iommu: Move the iommu driver sysfs setup into iommu_init/deinit_driver() Jason Gunthorpe
@ 2023-04-26 9:41 ` Tian, Kevin
0 siblings, 0 replies; 25+ messages in thread
From: Tian, Kevin @ 2023-04-26 9:41 UTC (permalink / raw)
To: Jason Gunthorpe, Lu Baolu, Christophe Leroy, David Woodhouse,
iommu@lists.linux.dev, Joerg Roedel, Len Brown,
linux-acpi@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
Michael Ellerman, Nicholas Piggin, Rafael J. Wysocki,
Robin Murphy, Will Deacon
Cc: Nicolin Chen
> From: Jason Gunthorpe <jgg@nvidia.com>
> Sent: Thursday, April 20, 2023 12:12 AM
>
> It makes logical sense that once the driver is attached to the device the
> sysfs links appear, even if we haven't fully created the group_device or
> attached the device to a domain.
>
> Fix the missing error handling on sysfs creation since
> iommu_init_driver() can trivially handle this.
>
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 07/11] iommu: Do not export iommu_device_link/unlink()
2023-04-19 16:11 [PATCH 00/11] Consolidate the probe_device path Jason Gunthorpe
` (5 preceding siblings ...)
2023-04-19 16:11 ` [PATCH 06/11] iommu: Move the iommu driver sysfs setup into iommu_init/deinit_driver() Jason Gunthorpe
@ 2023-04-19 16:11 ` Jason Gunthorpe
2023-04-26 9:42 ` Tian, Kevin
2023-04-19 16:11 ` [PATCH 08/11] iommu: Always destroy the iommu_group during iommu_release_device() Jason Gunthorpe
` (3 subsequent siblings)
10 siblings, 1 reply; 25+ messages in thread
From: Jason Gunthorpe @ 2023-04-19 16:11 UTC (permalink / raw)
To: Lu Baolu, Christophe Leroy, David Woodhouse, iommu, Joerg Roedel,
Len Brown, linux-acpi, linuxppc-dev, Michael Ellerman,
Nicholas Piggin, Rafael J. Wysocki, Robin Murphy, Will Deacon
Cc: Kevin Tian, Nicolin Chen
These are not used outside iommu.c, they should not be available to
modular code.
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/iommu/iommu-sysfs.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/iommu/iommu-sysfs.c b/drivers/iommu/iommu-sysfs.c
index c8aba0e2a30d70..cbe378c34ba3eb 100644
--- a/drivers/iommu/iommu-sysfs.c
+++ b/drivers/iommu/iommu-sysfs.c
@@ -119,11 +119,9 @@ int iommu_device_link(struct iommu_device *iommu, struct device *link)
return ret;
}
-EXPORT_SYMBOL_GPL(iommu_device_link);
void iommu_device_unlink(struct iommu_device *iommu, struct device *link)
{
sysfs_remove_link(&link->kobj, "iommu");
sysfs_remove_link_from_group(&iommu->dev->kobj, "devices", dev_name(link));
}
-EXPORT_SYMBOL_GPL(iommu_device_unlink);
--
2.40.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* RE: [PATCH 07/11] iommu: Do not export iommu_device_link/unlink()
2023-04-19 16:11 ` [PATCH 07/11] iommu: Do not export iommu_device_link/unlink() Jason Gunthorpe
@ 2023-04-26 9:42 ` Tian, Kevin
0 siblings, 0 replies; 25+ messages in thread
From: Tian, Kevin @ 2023-04-26 9:42 UTC (permalink / raw)
To: Jason Gunthorpe, Lu Baolu, Christophe Leroy, David Woodhouse,
iommu@lists.linux.dev, Joerg Roedel, Len Brown,
linux-acpi@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
Michael Ellerman, Nicholas Piggin, Rafael J. Wysocki,
Robin Murphy, Will Deacon
Cc: Nicolin Chen
> From: Jason Gunthorpe <jgg@nvidia.com>
> Sent: Thursday, April 20, 2023 12:12 AM
>
> These are not used outside iommu.c, they should not be available to
> modular code.
>
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 08/11] iommu: Always destroy the iommu_group during iommu_release_device()
2023-04-19 16:11 [PATCH 00/11] Consolidate the probe_device path Jason Gunthorpe
` (6 preceding siblings ...)
2023-04-19 16:11 ` [PATCH 07/11] iommu: Do not export iommu_device_link/unlink() Jason Gunthorpe
@ 2023-04-19 16:11 ` Jason Gunthorpe
2023-04-20 4:23 ` Baolu Lu
2023-04-26 9:42 ` Tian, Kevin
2023-04-19 16:11 ` [PATCH 09/11] iommu/power: Remove iommu_del_device() Jason Gunthorpe
` (2 subsequent siblings)
10 siblings, 2 replies; 25+ messages in thread
From: Jason Gunthorpe @ 2023-04-19 16:11 UTC (permalink / raw)
To: Lu Baolu, Christophe Leroy, David Woodhouse, iommu, Joerg Roedel,
Len Brown, linux-acpi, linuxppc-dev, Michael Ellerman,
Nicholas Piggin, Rafael J. Wysocki, Robin Murphy, Will Deacon
Cc: Kevin Tian, Nicolin Chen
Have release fully clean up the iommu related parts of the struct device,
no matter what state they are in.
POWER creates iommu_groups without drivers attached, and the next patch
removes the open-coding of this same cleanup from POWER.
Split the logic so that the three things owned by the iommu core are
always cleaned up:
- Any attached iommu_group
- Any allocated dev->iommu, eg for fwsepc
- Any attached driver via a struct group_device
This fixes a bug where a fwspec created without an iommu_group being
probed would not be freed.
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/iommu/iommu.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index dbaf3ed9012c45..a82516c8ea87ad 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -569,7 +569,6 @@ static void __iommu_group_remove_device(struct device *dev)
dev->iommu_group = NULL;
goto out;
}
- WARN(true, "Corrupted iommu_group device_list");
out:
mutex_unlock(&group->mutex);
@@ -581,10 +580,12 @@ static void iommu_release_device(struct device *dev)
{
struct iommu_group *group = dev->iommu_group;
- if (!dev->iommu || !group)
- return;
+ if (group)
+ __iommu_group_remove_device(dev);
- __iommu_group_remove_device(dev);
+ /* Free any fwspec if no iommu_driver was ever attached */
+ if (dev->iommu)
+ dev_iommu_free(dev);
}
static int __init iommu_set_def_domain_type(char *str)
--
2.40.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH 08/11] iommu: Always destroy the iommu_group during iommu_release_device()
2023-04-19 16:11 ` [PATCH 08/11] iommu: Always destroy the iommu_group during iommu_release_device() Jason Gunthorpe
@ 2023-04-20 4:23 ` Baolu Lu
2023-04-26 13:47 ` Jason Gunthorpe
2023-04-26 9:42 ` Tian, Kevin
1 sibling, 1 reply; 25+ messages in thread
From: Baolu Lu @ 2023-04-20 4:23 UTC (permalink / raw)
To: Jason Gunthorpe, Christophe Leroy, David Woodhouse, iommu,
Joerg Roedel, Len Brown, linux-acpi, linuxppc-dev,
Michael Ellerman, Nicholas Piggin, Rafael J. Wysocki,
Robin Murphy, Will Deacon
Cc: Kevin Tian, Nicolin Chen, baolu.lu
On 4/20/23 12:11 AM, Jason Gunthorpe wrote:
> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index dbaf3ed9012c45..a82516c8ea87ad 100644
> --- a/drivers/iommu/iommu.c
> +++ b/drivers/iommu/iommu.c
> @@ -569,7 +569,6 @@ static void __iommu_group_remove_device(struct device *dev)
> dev->iommu_group = NULL;
> goto out;
Nit, given that below line has been removed, can above simply be a
loop break?
> }
> - WARN(true, "Corrupted iommu_group device_list");
> out:
> mutex_unlock(&group->mutex);
Best regards,
baolu
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH 08/11] iommu: Always destroy the iommu_group during iommu_release_device()
2023-04-20 4:23 ` Baolu Lu
@ 2023-04-26 13:47 ` Jason Gunthorpe
0 siblings, 0 replies; 25+ messages in thread
From: Jason Gunthorpe @ 2023-04-26 13:47 UTC (permalink / raw)
To: Baolu Lu
Cc: Kevin Tian, Will Deacon, Rafael J. Wysocki, linuxppc-dev,
Joerg Roedel, Robin Murphy, linux-acpi, iommu, Nicolin Chen,
Nicholas Piggin, David Woodhouse, Len Brown
On Thu, Apr 20, 2023 at 12:23:11PM +0800, Baolu Lu wrote:
> On 4/20/23 12:11 AM, Jason Gunthorpe wrote:
> > diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> > index dbaf3ed9012c45..a82516c8ea87ad 100644
> > --- a/drivers/iommu/iommu.c
> > +++ b/drivers/iommu/iommu.c
> > @@ -569,7 +569,6 @@ static void __iommu_group_remove_device(struct device *dev)
> > dev->iommu_group = NULL;
> > goto out;
>
> Nit, given that below line has been removed, can above simply be a
> loop break?
Yes, that is much nicer
Thanks,
Jason
^ permalink raw reply [flat|nested] 25+ messages in thread
* RE: [PATCH 08/11] iommu: Always destroy the iommu_group during iommu_release_device()
2023-04-19 16:11 ` [PATCH 08/11] iommu: Always destroy the iommu_group during iommu_release_device() Jason Gunthorpe
2023-04-20 4:23 ` Baolu Lu
@ 2023-04-26 9:42 ` Tian, Kevin
1 sibling, 0 replies; 25+ messages in thread
From: Tian, Kevin @ 2023-04-26 9:42 UTC (permalink / raw)
To: Jason Gunthorpe, Lu Baolu, Christophe Leroy, David Woodhouse,
iommu@lists.linux.dev, Joerg Roedel, Len Brown,
linux-acpi@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
Michael Ellerman, Nicholas Piggin, Rafael J. Wysocki,
Robin Murphy, Will Deacon
Cc: Nicolin Chen
> From: Jason Gunthorpe <jgg@nvidia.com>
> Sent: Thursday, April 20, 2023 12:12 AM
>
> Have release fully clean up the iommu related parts of the struct device,
> no matter what state they are in.
>
> POWER creates iommu_groups without drivers attached, and the next patch
> removes the open-coding of this same cleanup from POWER.
>
> Split the logic so that the three things owned by the iommu core are
> always cleaned up:
> - Any attached iommu_group
> - Any allocated dev->iommu, eg for fwsepc
> - Any attached driver via a struct group_device
>
> This fixes a bug where a fwspec created without an iommu_group being
> probed would not be freed.
>
> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 09/11] iommu/power: Remove iommu_del_device()
2023-04-19 16:11 [PATCH 00/11] Consolidate the probe_device path Jason Gunthorpe
` (7 preceding siblings ...)
2023-04-19 16:11 ` [PATCH 08/11] iommu: Always destroy the iommu_group during iommu_release_device() Jason Gunthorpe
@ 2023-04-19 16:11 ` Jason Gunthorpe
2023-04-19 16:11 ` [PATCH 10/11] iommu: Split iommu_group_add_device() Jason Gunthorpe
2023-04-19 16:11 ` [PATCH 11/11] iommu: Avoid locking/unlocking for iommu_probe_device() Jason Gunthorpe
10 siblings, 0 replies; 25+ messages in thread
From: Jason Gunthorpe @ 2023-04-19 16:11 UTC (permalink / raw)
To: Lu Baolu, Christophe Leroy, David Woodhouse, iommu, Joerg Roedel,
Len Brown, linux-acpi, linuxppc-dev, Michael Ellerman,
Nicholas Piggin, Rafael J. Wysocki, Robin Murphy, Will Deacon
Cc: Kevin Tian, Nicolin Chen
This is only called from a BUS_NOTIFY_DEL_DEVICE notifier and it only
calls iommu_group_remove_device().
The core code now cleans up any iommu_group, even without a driver, during
BUS_NOTIFY_REMOVED_DEVICE. There is no reason for POWER to install its own
bus notifiers and duplicate the core code's work, remove this code.
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
arch/powerpc/include/asm/iommu.h | 5 -----
arch/powerpc/kernel/iommu.c | 17 -----------------
arch/powerpc/platforms/powernv/pci.c | 25 -------------------------
arch/powerpc/platforms/pseries/iommu.c | 25 -------------------------
4 files changed, 72 deletions(-)
diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h
index 7e29c73e3dd48d..55d6213dbeaf42 100644
--- a/arch/powerpc/include/asm/iommu.h
+++ b/arch/powerpc/include/asm/iommu.h
@@ -205,7 +205,6 @@ extern void iommu_register_group(struct iommu_table_group *table_group,
int pci_domain_number, unsigned long pe_num);
extern int iommu_add_device(struct iommu_table_group *table_group,
struct device *dev);
-extern void iommu_del_device(struct device *dev);
extern long iommu_tce_xchg(struct mm_struct *mm, struct iommu_table *tbl,
unsigned long entry, unsigned long *hpa,
enum dma_data_direction *direction);
@@ -227,10 +226,6 @@ static inline int iommu_add_device(struct iommu_table_group *table_group,
{
return 0;
}
-
-static inline void iommu_del_device(struct device *dev)
-{
-}
#endif /* !CONFIG_IOMMU_API */
u64 dma_iommu_get_required_mask(struct device *dev);
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index ee95937bdaf14e..f02dd2149394e2 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -1162,21 +1162,4 @@ int iommu_add_device(struct iommu_table_group *table_group, struct device *dev)
return iommu_group_add_device(table_group->group, dev);
}
EXPORT_SYMBOL_GPL(iommu_add_device);
-
-void iommu_del_device(struct device *dev)
-{
- /*
- * Some devices might not have IOMMU table and group
- * and we needn't detach them from the associated
- * IOMMU groups
- */
- if (!device_iommu_mapped(dev)) {
- pr_debug("iommu_tce: skipping device %s with no tbl\n",
- dev_name(dev));
- return;
- }
-
- iommu_group_remove_device(dev);
-}
-EXPORT_SYMBOL_GPL(iommu_del_device);
#endif /* CONFIG_IOMMU_API */
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index 233a50e65fcedd..7725492097b627 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -865,28 +865,3 @@ void __init pnv_pci_init(void)
/* Configure IOMMU DMA hooks */
set_pci_dma_ops(&dma_iommu_ops);
}
-
-static int pnv_tce_iommu_bus_notifier(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct device *dev = data;
-
- switch (action) {
- case BUS_NOTIFY_DEL_DEVICE:
- iommu_del_device(dev);
- return 0;
- default:
- return 0;
- }
-}
-
-static struct notifier_block pnv_tce_iommu_bus_nb = {
- .notifier_call = pnv_tce_iommu_bus_notifier,
-};
-
-static int __init pnv_tce_iommu_bus_notifier_init(void)
-{
- bus_register_notifier(&pci_bus_type, &pnv_tce_iommu_bus_nb);
- return 0;
-}
-machine_subsys_initcall_sync(powernv, pnv_tce_iommu_bus_notifier_init);
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index c74b71d4733d40..7818ace838ce61 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -1699,28 +1699,3 @@ static int __init disable_multitce(char *str)
}
__setup("multitce=", disable_multitce);
-
-static int tce_iommu_bus_notifier(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct device *dev = data;
-
- switch (action) {
- case BUS_NOTIFY_DEL_DEVICE:
- iommu_del_device(dev);
- return 0;
- default:
- return 0;
- }
-}
-
-static struct notifier_block tce_iommu_bus_nb = {
- .notifier_call = tce_iommu_bus_notifier,
-};
-
-static int __init tce_iommu_bus_notifier_init(void)
-{
- bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb);
- return 0;
-}
-machine_subsys_initcall_sync(pseries, tce_iommu_bus_notifier_init);
--
2.40.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* [PATCH 10/11] iommu: Split iommu_group_add_device()
2023-04-19 16:11 [PATCH 00/11] Consolidate the probe_device path Jason Gunthorpe
` (8 preceding siblings ...)
2023-04-19 16:11 ` [PATCH 09/11] iommu/power: Remove iommu_del_device() Jason Gunthorpe
@ 2023-04-19 16:11 ` Jason Gunthorpe
2023-04-20 4:25 ` Baolu Lu
2023-04-19 16:11 ` [PATCH 11/11] iommu: Avoid locking/unlocking for iommu_probe_device() Jason Gunthorpe
10 siblings, 1 reply; 25+ messages in thread
From: Jason Gunthorpe @ 2023-04-19 16:11 UTC (permalink / raw)
To: Lu Baolu, Christophe Leroy, David Woodhouse, iommu, Joerg Roedel,
Len Brown, linux-acpi, linuxppc-dev, Michael Ellerman,
Nicholas Piggin, Rafael J. Wysocki, Robin Murphy, Will Deacon
Cc: Kevin Tian, Nicolin Chen
Move the list_add_tail() for the group_device into the critical region
that immediately follows in __iommu_probe_device(). This avoids one case
of unlocking and immediately re-locking the group->mutex.
Consistently make the caller responsible for setting dev->iommu_group,
prior patches moved this into iommu_init_driver(), make the no-driver path
do this in iommu_group_add_device().
This completes making __iommu_group_free_device() and
iommu_group_alloc_device() into pair'd functions.
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/iommu/iommu.c | 66 ++++++++++++++++++++++++++++---------------
1 file changed, 43 insertions(+), 23 deletions(-)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index a82516c8ea87ad..5ebff82041f2d1 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -128,6 +128,8 @@ static int iommu_create_device_direct_mappings(struct iommu_domain *domain,
struct device *dev);
static ssize_t iommu_group_store_type(struct iommu_group *group,
const char *buf, size_t count);
+static struct group_device *iommu_group_alloc_device(struct iommu_group *group,
+ struct device *dev);
#define IOMMU_GROUP_ATTR(_name, _mode, _show, _store) \
struct iommu_group_attribute iommu_group_attr_##_name = \
@@ -427,6 +429,7 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
const struct iommu_ops *ops = dev->bus->iommu_ops;
struct iommu_group *group;
static DEFINE_MUTEX(iommu_probe_device_lock);
+ struct group_device *gdev;
int ret;
if (!ops)
@@ -451,16 +454,17 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
goto out_unlock;
group = dev->iommu_group;
- ret = iommu_group_add_device(group, dev);
+ gdev = iommu_group_alloc_device(group, dev);
mutex_lock(&group->mutex);
- if (ret)
+ if (IS_ERR(gdev)) {
+ ret = PTR_ERR(gdev);
goto err_put_group;
+ }
+ list_add_tail(&gdev->list, &group->devices);
if (group_list && !group->default_domain && list_empty(&group->entry))
list_add_tail(&group->entry, group_list);
mutex_unlock(&group->mutex);
- iommu_group_put(group);
-
mutex_unlock(&iommu_probe_device_lock);
return 0;
@@ -572,7 +576,10 @@ static void __iommu_group_remove_device(struct device *dev)
out:
mutex_unlock(&group->mutex);
- /* Pairs with the get in iommu_group_add_device() */
+ /*
+ * Pairs with the get in iommu_init_driver() or
+ * iommu_group_add_device()
+ */
iommu_group_put(group);
}
@@ -1061,22 +1068,16 @@ static int iommu_create_device_direct_mappings(struct iommu_domain *domain,
return ret;
}
-/**
- * iommu_group_add_device - add a device to an iommu group
- * @group: the group into which to add the device (reference should be held)
- * @dev: the device
- *
- * This function is called by an iommu driver to add a device into a
- * group. Adding a device increments the group reference count.
- */
-int iommu_group_add_device(struct iommu_group *group, struct device *dev)
+/* This is undone by __iommu_group_free_device() */
+static struct group_device *iommu_group_alloc_device(struct iommu_group *group,
+ struct device *dev)
{
int ret, i = 0;
struct group_device *device;
device = kzalloc(sizeof(*device), GFP_KERNEL);
if (!device)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
device->dev = dev;
@@ -1107,17 +1108,11 @@ int iommu_group_add_device(struct iommu_group *group, struct device *dev)
goto err_free_name;
}
- iommu_group_ref_get(group);
- dev->iommu_group = group;
-
- mutex_lock(&group->mutex);
- list_add_tail(&device->list, &group->devices);
- mutex_unlock(&group->mutex);
trace_add_device_to_group(group->id, dev);
dev_info(dev, "Adding to iommu group %d\n", group->id);
- return 0;
+ return device;
err_free_name:
kfree(device->name);
@@ -1126,7 +1121,32 @@ int iommu_group_add_device(struct iommu_group *group, struct device *dev)
err_free_device:
kfree(device);
dev_err(dev, "Failed to add to iommu group %d: %d\n", group->id, ret);
- return ret;
+ return ERR_PTR(ret);
+}
+
+/**
+ * iommu_group_add_device - add a device to an iommu group
+ * @group: the group into which to add the device (reference should be held)
+ * @dev: the device
+ *
+ * This function is called by an iommu driver to add a device into a
+ * group. Adding a device increments the group reference count.
+ */
+int iommu_group_add_device(struct iommu_group *group, struct device *dev)
+{
+ struct group_device *gdev;
+
+ gdev = iommu_group_alloc_device(group, dev);
+ if (IS_ERR(gdev))
+ return PTR_ERR(gdev);
+
+ iommu_group_ref_get(group);
+ dev->iommu_group = group;
+
+ mutex_lock(&group->mutex);
+ list_add_tail(&gdev->list, &group->devices);
+ mutex_unlock(&group->mutex);
+ return 0;
}
EXPORT_SYMBOL_GPL(iommu_group_add_device);
--
2.40.0
^ permalink raw reply related [flat|nested] 25+ messages in thread* Re: [PATCH 10/11] iommu: Split iommu_group_add_device()
2023-04-19 16:11 ` [PATCH 10/11] iommu: Split iommu_group_add_device() Jason Gunthorpe
@ 2023-04-20 4:25 ` Baolu Lu
2023-04-20 13:09 ` Jason Gunthorpe
0 siblings, 1 reply; 25+ messages in thread
From: Baolu Lu @ 2023-04-20 4:25 UTC (permalink / raw)
To: Jason Gunthorpe, Christophe Leroy, David Woodhouse, iommu,
Joerg Roedel, Len Brown, linux-acpi, linuxppc-dev,
Michael Ellerman, Nicholas Piggin, Rafael J. Wysocki,
Robin Murphy, Will Deacon
Cc: Kevin Tian, Nicolin Chen, baolu.lu
On 4/20/23 12:11 AM, Jason Gunthorpe wrote:
> @@ -451,16 +454,17 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
> goto out_unlock;
>
> group = dev->iommu_group;
> - ret = iommu_group_add_device(group, dev);
> + gdev = iommu_group_alloc_device(group, dev);
> mutex_lock(&group->mutex);
> - if (ret)
> + if (IS_ERR(gdev)) {
> + ret = PTR_ERR(gdev);
> goto err_put_group;
> + }
>
> + list_add_tail(&gdev->list, &group->devices);
Do we need to put
dev->iommu_group = group;
here?
> if (group_list && !group->default_domain && list_empty(&group->entry))
> list_add_tail(&group->entry, group_list);
> mutex_unlock(&group->mutex);
> - iommu_group_put(group);
> -
> mutex_unlock(&iommu_probe_device_lock);
>
> return 0;
Best regards,
baolu
^ permalink raw reply [flat|nested] 25+ messages in thread* Re: [PATCH 10/11] iommu: Split iommu_group_add_device()
2023-04-20 4:25 ` Baolu Lu
@ 2023-04-20 13:09 ` Jason Gunthorpe
0 siblings, 0 replies; 25+ messages in thread
From: Jason Gunthorpe @ 2023-04-20 13:09 UTC (permalink / raw)
To: Baolu Lu
Cc: Kevin Tian, Will Deacon, Rafael J. Wysocki, linuxppc-dev,
Joerg Roedel, Robin Murphy, linux-acpi, iommu, Nicolin Chen,
Nicholas Piggin, David Woodhouse, Len Brown
On Thu, Apr 20, 2023 at 12:25:11PM +0800, Baolu Lu wrote:
> On 4/20/23 12:11 AM, Jason Gunthorpe wrote:
> > @@ -451,16 +454,17 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
> > goto out_unlock;
> > group = dev->iommu_group;
> > - ret = iommu_group_add_device(group, dev);
> > + gdev = iommu_group_alloc_device(group, dev);
> > mutex_lock(&group->mutex);
> > - if (ret)
> > + if (IS_ERR(gdev)) {
> > + ret = PTR_ERR(gdev);
> > goto err_put_group;
> > + }
> > + list_add_tail(&gdev->list, &group->devices);
>
> Do we need to put
>
> dev->iommu_group = group;
>
> here?
It is done in iommu_init_driver() and iommu_deinit_driver() NULL's it
group = ops->device_group(dev);
if (WARN_ON_ONCE(group == NULL))
group = ERR_PTR(-EINVAL);
if (IS_ERR(group)) {
ret = PTR_ERR(group);
goto err_unlink;
}
dev->iommu_group = group;
Jason
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH 11/11] iommu: Avoid locking/unlocking for iommu_probe_device()
2023-04-19 16:11 [PATCH 00/11] Consolidate the probe_device path Jason Gunthorpe
` (9 preceding siblings ...)
2023-04-19 16:11 ` [PATCH 10/11] iommu: Split iommu_group_add_device() Jason Gunthorpe
@ 2023-04-19 16:11 ` Jason Gunthorpe
10 siblings, 0 replies; 25+ messages in thread
From: Jason Gunthorpe @ 2023-04-19 16:11 UTC (permalink / raw)
To: Lu Baolu, Christophe Leroy, David Woodhouse, iommu, Joerg Roedel,
Len Brown, linux-acpi, linuxppc-dev, Michael Ellerman,
Nicholas Piggin, Rafael J. Wysocki, Robin Murphy, Will Deacon
Cc: Kevin Tian, Nicolin Chen
Remove the race where a hotplug of a device into an existing group will
have the device installed in the group->devices, but not yet attached to
the group's current domain.
Move the group attachment logic from iommu_probe_device() and put it under
the same mutex that updates the group->devices list so everything is
atomic under the lock.
We retain the two step setup of the default domain for the
bus_iommu_probe() case solely so that we have a more complete view of the
group when creating the default domain for boot time devices. This is not
generally necessary with the current code structure but seems to be
supporting some odd corner cases like alias RID's and IOMMU_RESV_DIRECT or
driver bugs returning different default_domain types for the same group.
During bus_iommu_probe() the group will have a device list but both
group->default_domain and group->domain will be NULL.
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/iommu/iommu.c | 78 +++++++++++++++++++------------------------
1 file changed, 35 insertions(+), 43 deletions(-)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 5ebff82041f2d1..8fc230eb36d65f 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -130,6 +130,8 @@ static ssize_t iommu_group_store_type(struct iommu_group *group,
const char *buf, size_t count);
static struct group_device *iommu_group_alloc_device(struct iommu_group *group,
struct device *dev);
+static void __iommu_group_free_device(struct iommu_group *group,
+ struct group_device *grp_dev);
#define IOMMU_GROUP_ATTR(_name, _mode, _show, _store) \
struct iommu_group_attribute iommu_group_attr_##_name = \
@@ -461,14 +463,39 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
goto err_put_group;
}
+ /*
+ * The gdev must be in the list before calling
+ * iommu_setup_default_domain()
+ */
list_add_tail(&gdev->list, &group->devices);
- if (group_list && !group->default_domain && list_empty(&group->entry))
- list_add_tail(&group->entry, group_list);
+ WARN_ON(group->default_domain && !group->domain);
+ 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_remove_gdev;
+ } else if (!group->default_domain && !group_list) {
+ ret = iommu_setup_default_domain(group, 0);
+ if (ret)
+ goto err_remove_gdev;
+ } else if (!group->default_domain) {
+ /*
+ * With a group_list argument we defer the default_domain setup
+ * to the caller by providing a de-duplicated list of groups
+ * that need further setup.
+ */
+ if (list_empty(&group->entry))
+ list_add_tail(&group->entry, group_list);
+ }
mutex_unlock(&group->mutex);
mutex_unlock(&iommu_probe_device_lock);
return 0;
+err_remove_gdev:
+ list_del(&gdev->list);
+ __iommu_group_free_device(group, gdev);
err_put_group:
iommu_deinit_driver(dev);
mutex_unlock(&group->mutex);
@@ -482,52 +509,17 @@ static int __iommu_probe_device(struct device *dev, struct list_head *group_list
int iommu_probe_device(struct device *dev)
{
const struct iommu_ops *ops;
- struct iommu_group *group;
int ret;
ret = __iommu_probe_device(dev, NULL);
if (ret)
- goto err_out;
-
- group = iommu_group_get(dev);
- if (!group) {
- ret = -ENODEV;
- goto err_release;
- }
-
- mutex_lock(&group->mutex);
-
- 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) {
- ret = iommu_setup_default_domain(group, 0);
- if (ret)
- goto err_unlock;
- }
-
- mutex_unlock(&group->mutex);
- iommu_group_put(group);
+ return ret;
ops = dev_iommu_ops(dev);
if (ops->probe_finalize)
ops->probe_finalize(dev);
return 0;
-
-err_unlock:
- mutex_unlock(&group->mutex);
- iommu_group_put(group);
-err_release:
- iommu_release_device(dev);
-
-err_out:
- return ret;
-
}
static void __iommu_group_free_device(struct iommu_group *group,
@@ -1809,11 +1801,6 @@ int bus_iommu_probe(struct bus_type *bus)
LIST_HEAD(group_list);
int ret;
- /*
- * This code-path does not allocate the default domain when
- * creating the iommu group, so do it after the groups are
- * created.
- */
ret = bus_for_each_dev(bus, NULL, &group_list, probe_iommu_group);
if (ret)
return ret;
@@ -1826,6 +1813,11 @@ int bus_iommu_probe(struct bus_type *bus)
/* Remove item from the list */
list_del_init(&group->entry);
+ /*
+ * We go to the trouble of deferred default domain creation so
+ * that the cross-group default domain type and the setup of the
+ * IOMMU_RESV_DIRECT will work correctly in non-hotpug scenarios.
+ */
ret = iommu_setup_default_domain(group, 0);
if (ret) {
mutex_unlock(&group->mutex);
--
2.40.0
^ permalink raw reply related [flat|nested] 25+ messages in thread