summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/iommu/iommu.c28
-rw-r--r--include/linux/iommu.h4
2 files changed, 28 insertions, 4 deletions
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index de91dd88705b..1c8b2c7678f7 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -2163,6 +2163,16 @@ static int iommu_group_do_detach_device(struct device *dev, void *data)
return 0;
}
+static int iommu_group_do_set_platform_dma(struct device *dev, void *data)
+{
+ const struct iommu_ops *ops = dev_iommu_ops(dev);
+
+ if (!WARN_ON(!ops->set_platform_dma_ops))
+ ops->set_platform_dma_ops(dev);
+
+ return 0;
+}
+
static int __iommu_group_set_domain(struct iommu_group *group,
struct iommu_domain *new_domain)
{
@@ -2177,10 +2187,20 @@ static int __iommu_group_set_domain(struct iommu_group *group,
* platform specific behavior.
*/
if (!new_domain) {
- if (WARN_ON(!group->domain->ops->detach_dev))
- return -EINVAL;
- __iommu_group_for_each_dev(group, group->domain,
- iommu_group_do_detach_device);
+ struct group_device *grp_dev;
+
+ grp_dev = list_first_entry(&group->devices,
+ struct group_device, list);
+
+ if (dev_iommu_ops(grp_dev->dev)->set_platform_dma_ops)
+ __iommu_group_for_each_dev(group, NULL,
+ iommu_group_do_set_platform_dma);
+ else if (group->domain->ops->detach_dev)
+ __iommu_group_for_each_dev(group, group->domain,
+ iommu_group_do_detach_device);
+ else
+ WARN_ON_ONCE(1);
+
group->domain = NULL;
return 0;
}
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 46e1347bfa22..7b3e3775b069 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -228,6 +228,9 @@ struct iommu_iotlb_gather {
* @release_device: Remove device from iommu driver handling
* @probe_finalize: Do final setup work after the device is added to an IOMMU
* group and attached to the groups domain
+ * @set_platform_dma_ops: Returning control back to the platform DMA ops. This op
+ * is to support old IOMMU drivers, new drivers should use
+ * default domains, and the common IOMMU DMA ops.
* @device_group: find iommu group for a particular device
* @get_resv_regions: Request list of reserved regions for a device
* @of_xlate: add OF master IDs to iommu grouping
@@ -256,6 +259,7 @@ struct iommu_ops {
struct iommu_device *(*probe_device)(struct device *dev);
void (*release_device)(struct device *dev);
void (*probe_finalize)(struct device *dev);
+ void (*set_platform_dma_ops)(struct device *dev);
struct iommu_group *(*device_group)(struct device *dev);
/* Request/Free a list of reserved regions for a device */