Commit b3d14960 authored by Jason Gunthorpe's avatar Jason Gunthorpe Committed by Joerg Roedel

iommu/exynos: Implement an IDENTITY domain

What exynos calls exynos_iommu_detach_device is actually putting the iommu
into identity mode.

Move to the new core support for ARM_DMA_USE_IOMMU by defining
ops->identity_domain.
Tested-by: default avatarMarek Szyprowski <m.szyprowski@samsung.com>
Acked-by: default avatarMarek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: default avatarJerry Snitselaar <jsnitsel@redhat.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
Link: https://lore.kernel.org/r/10-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.comSigned-off-by: default avatarJoerg Roedel <jroedel@suse.de>
parent e98befd0
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
typedef u32 sysmmu_iova_t; typedef u32 sysmmu_iova_t;
typedef u32 sysmmu_pte_t; typedef u32 sysmmu_pte_t;
static struct iommu_domain exynos_identity_domain;
/* We do not consider super section mapping (16MB) */ /* We do not consider super section mapping (16MB) */
#define SECT_ORDER 20 #define SECT_ORDER 20
...@@ -829,7 +830,7 @@ static int __maybe_unused exynos_sysmmu_suspend(struct device *dev) ...@@ -829,7 +830,7 @@ static int __maybe_unused exynos_sysmmu_suspend(struct device *dev)
struct exynos_iommu_owner *owner = dev_iommu_priv_get(master); struct exynos_iommu_owner *owner = dev_iommu_priv_get(master);
mutex_lock(&owner->rpm_lock); mutex_lock(&owner->rpm_lock);
if (data->domain) { if (&data->domain->domain != &exynos_identity_domain) {
dev_dbg(data->sysmmu, "saving state\n"); dev_dbg(data->sysmmu, "saving state\n");
__sysmmu_disable(data); __sysmmu_disable(data);
} }
...@@ -847,7 +848,7 @@ static int __maybe_unused exynos_sysmmu_resume(struct device *dev) ...@@ -847,7 +848,7 @@ static int __maybe_unused exynos_sysmmu_resume(struct device *dev)
struct exynos_iommu_owner *owner = dev_iommu_priv_get(master); struct exynos_iommu_owner *owner = dev_iommu_priv_get(master);
mutex_lock(&owner->rpm_lock); mutex_lock(&owner->rpm_lock);
if (data->domain) { if (&data->domain->domain != &exynos_identity_domain) {
dev_dbg(data->sysmmu, "restoring state\n"); dev_dbg(data->sysmmu, "restoring state\n");
__sysmmu_enable(data); __sysmmu_enable(data);
} }
...@@ -980,17 +981,20 @@ static void exynos_iommu_domain_free(struct iommu_domain *iommu_domain) ...@@ -980,17 +981,20 @@ static void exynos_iommu_domain_free(struct iommu_domain *iommu_domain)
kfree(domain); kfree(domain);
} }
static void exynos_iommu_detach_device(struct iommu_domain *iommu_domain, static int exynos_iommu_identity_attach(struct iommu_domain *identity_domain,
struct device *dev) struct device *dev)
{ {
struct exynos_iommu_domain *domain = to_exynos_domain(iommu_domain);
struct exynos_iommu_owner *owner = dev_iommu_priv_get(dev); struct exynos_iommu_owner *owner = dev_iommu_priv_get(dev);
phys_addr_t pagetable = virt_to_phys(domain->pgtable); struct exynos_iommu_domain *domain;
phys_addr_t pagetable;
struct sysmmu_drvdata *data, *next; struct sysmmu_drvdata *data, *next;
unsigned long flags; unsigned long flags;
if (!has_sysmmu(dev) || owner->domain != iommu_domain) if (owner->domain == identity_domain)
return; return 0;
domain = to_exynos_domain(owner->domain);
pagetable = virt_to_phys(domain->pgtable);
mutex_lock(&owner->rpm_lock); mutex_lock(&owner->rpm_lock);
...@@ -1009,15 +1013,25 @@ static void exynos_iommu_detach_device(struct iommu_domain *iommu_domain, ...@@ -1009,15 +1013,25 @@ static void exynos_iommu_detach_device(struct iommu_domain *iommu_domain,
list_del_init(&data->domain_node); list_del_init(&data->domain_node);
spin_unlock(&data->lock); spin_unlock(&data->lock);
} }
owner->domain = NULL; owner->domain = identity_domain;
spin_unlock_irqrestore(&domain->lock, flags); spin_unlock_irqrestore(&domain->lock, flags);
mutex_unlock(&owner->rpm_lock); mutex_unlock(&owner->rpm_lock);
dev_dbg(dev, "%s: Detached IOMMU with pgtable %pa\n", __func__, dev_dbg(dev, "%s: Restored IOMMU to IDENTITY from pgtable %pa\n",
&pagetable); __func__, &pagetable);
return 0;
} }
static struct iommu_domain_ops exynos_identity_ops = {
.attach_dev = exynos_iommu_identity_attach,
};
static struct iommu_domain exynos_identity_domain = {
.type = IOMMU_DOMAIN_IDENTITY,
.ops = &exynos_identity_ops,
};
static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain, static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain,
struct device *dev) struct device *dev)
{ {
...@@ -1026,12 +1040,11 @@ static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain, ...@@ -1026,12 +1040,11 @@ static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain,
struct sysmmu_drvdata *data; struct sysmmu_drvdata *data;
phys_addr_t pagetable = virt_to_phys(domain->pgtable); phys_addr_t pagetable = virt_to_phys(domain->pgtable);
unsigned long flags; unsigned long flags;
int err;
if (!has_sysmmu(dev)) err = exynos_iommu_identity_attach(&exynos_identity_domain, dev);
return -ENODEV; if (err)
return err;
if (owner->domain)
exynos_iommu_detach_device(owner->domain, dev);
mutex_lock(&owner->rpm_lock); mutex_lock(&owner->rpm_lock);
...@@ -1407,26 +1420,12 @@ static struct iommu_device *exynos_iommu_probe_device(struct device *dev) ...@@ -1407,26 +1420,12 @@ static struct iommu_device *exynos_iommu_probe_device(struct device *dev)
return &data->iommu; return &data->iommu;
} }
static void exynos_iommu_set_platform_dma(struct device *dev)
{
struct exynos_iommu_owner *owner = dev_iommu_priv_get(dev);
if (owner->domain) {
struct iommu_group *group = iommu_group_get(dev);
if (group) {
exynos_iommu_detach_device(owner->domain, dev);
iommu_group_put(group);
}
}
}
static void exynos_iommu_release_device(struct device *dev) static void exynos_iommu_release_device(struct device *dev)
{ {
struct exynos_iommu_owner *owner = dev_iommu_priv_get(dev); struct exynos_iommu_owner *owner = dev_iommu_priv_get(dev);
struct sysmmu_drvdata *data; struct sysmmu_drvdata *data;
exynos_iommu_set_platform_dma(dev); WARN_ON(exynos_iommu_identity_attach(&exynos_identity_domain, dev));
list_for_each_entry(data, &owner->controllers, owner_node) list_for_each_entry(data, &owner->controllers, owner_node)
device_link_del(data->link); device_link_del(data->link);
...@@ -1457,6 +1456,7 @@ static int exynos_iommu_of_xlate(struct device *dev, ...@@ -1457,6 +1456,7 @@ static int exynos_iommu_of_xlate(struct device *dev,
INIT_LIST_HEAD(&owner->controllers); INIT_LIST_HEAD(&owner->controllers);
mutex_init(&owner->rpm_lock); mutex_init(&owner->rpm_lock);
owner->domain = &exynos_identity_domain;
dev_iommu_priv_set(dev, owner); dev_iommu_priv_set(dev, owner);
} }
...@@ -1471,11 +1471,9 @@ static int exynos_iommu_of_xlate(struct device *dev, ...@@ -1471,11 +1471,9 @@ static int exynos_iommu_of_xlate(struct device *dev,
} }
static const struct iommu_ops exynos_iommu_ops = { static const struct iommu_ops exynos_iommu_ops = {
.identity_domain = &exynos_identity_domain,
.domain_alloc = exynos_iommu_domain_alloc, .domain_alloc = exynos_iommu_domain_alloc,
.device_group = generic_device_group, .device_group = generic_device_group,
#ifdef CONFIG_ARM
.set_platform_dma_ops = exynos_iommu_set_platform_dma,
#endif
.probe_device = exynos_iommu_probe_device, .probe_device = exynos_iommu_probe_device,
.release_device = exynos_iommu_release_device, .release_device = exynos_iommu_release_device,
.pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE, .pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment