diff options
-rw-r--r-- | drivers/iommu/iommu.c | 28 | ||||
-rw-r--r-- | include/linux/iommu.h | 4 |
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 */ |