iommu: Add generic_single_device_group()
authorJason Gunthorpe <jgg@nvidia.com>
Tue, 22 Aug 2023 16:15:57 +0000 (13:15 -0300)
committerJoerg Roedel <jroedel@suse.de>
Mon, 25 Sep 2023 09:45:29 +0000 (11:45 +0200)
This implements the common pattern seen in drivers of a single iommu_group
for the entire iommu driver instance. Implement this in core code so the
drivers that want this can select it from their ops.

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Link: https://lore.kernel.org/r/2-v1-c869a95191f2+5e8-iommu_single_grp_jgg@nvidia.com
Signed-off-by: Joerg Roedel <jroedel@suse.de>
drivers/iommu/iommu.c
include/linux/iommu.h

index 6483d6e19a5ecf8d9279e09a05c1191a21d4587c..03202314322bdf485c5f35d5740ddd2ebbb5493b 100644 (file)
@@ -292,6 +292,10 @@ void iommu_device_unregister(struct iommu_device *iommu)
        spin_lock(&iommu_device_lock);
        list_del(&iommu->list);
        spin_unlock(&iommu_device_lock);
+
+       /* Pairs with the alloc in generic_single_device_group() */
+       iommu_group_put(iommu->singleton_group);
+       iommu->singleton_group = NULL;
 }
 EXPORT_SYMBOL_GPL(iommu_device_unregister);
 
@@ -406,6 +410,7 @@ static int iommu_init_device(struct device *dev, const struct iommu_ops *ops)
                ret = PTR_ERR(iommu_dev);
                goto err_module_put;
        }
+       dev->iommu->iommu_dev = iommu_dev;
 
        ret = iommu_device_link(iommu_dev, dev);
        if (ret)
@@ -420,7 +425,6 @@ static int iommu_init_device(struct device *dev, const struct iommu_ops *ops)
        }
        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);
@@ -434,6 +438,7 @@ err_release:
 err_module_put:
        module_put(ops->owner);
 err_free:
+       dev->iommu->iommu_dev = NULL;
        dev_iommu_free(dev);
        return ret;
 }
@@ -1637,6 +1642,27 @@ struct iommu_group *generic_device_group(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(generic_device_group);
 
+/*
+ * Generic device_group call-back function. It just allocates one
+ * iommu-group per iommu driver instance shared by every device
+ * probed by that iommu driver.
+ */
+struct iommu_group *generic_single_device_group(struct device *dev)
+{
+       struct iommu_device *iommu = dev->iommu->iommu_dev;
+
+       if (!iommu->singleton_group) {
+               struct iommu_group *group;
+
+               group = iommu_group_alloc();
+               if (IS_ERR(group))
+                       return group;
+               iommu->singleton_group = group;
+       }
+       return iommu_group_ref_get(iommu->singleton_group);
+}
+EXPORT_SYMBOL_GPL(generic_single_device_group);
+
 /*
  * Use standard PCI bus topology, isolation features, and DMA alias quirks
  * to find or create an IOMMU group for a device.
index 3f173307434dcca261ac5b6c9d46e9bf2ad178d8..5b693be3d35fc0f6c628e57d8b1208249a0d3f1f 100644 (file)
@@ -378,6 +378,7 @@ struct iommu_domain_ops {
  * @list: Used by the iommu-core to keep a list of registered iommus
  * @ops: iommu-ops for talking to this iommu
  * @dev: struct device for sysfs handling
+ * @singleton_group: Used internally for drivers that have only one group
  * @max_pasids: number of supported PASIDs
  */
 struct iommu_device {
@@ -385,6 +386,7 @@ struct iommu_device {
        const struct iommu_ops *ops;
        struct fwnode_handle *fwnode;
        struct device *dev;
+       struct iommu_group *singleton_group;
        u32 max_pasids;
 };
 
@@ -648,6 +650,7 @@ extern struct iommu_group *pci_device_group(struct device *dev);
 extern struct iommu_group *generic_device_group(struct device *dev);
 /* FSL-MC device grouping function */
 struct iommu_group *fsl_mc_device_group(struct device *dev);
+extern struct iommu_group *generic_single_device_group(struct device *dev);
 
 /**
  * struct iommu_fwspec - per-device IOMMU instance data