mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-09-03 01:28:04 +00:00
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: Marek Szyprowski <m.szyprowski@samsung.com> Acked-by: Marek Szyprowski <m.szyprowski@samsung.com> Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> Link: https://lore.kernel.org/r/10-v8-81230027b2fa+9d-iommu_all_defdom_jgg@nvidia.com Signed-off-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
parent
e98befd010
commit
b3d14960e6
@ -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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
|
Loading…
Reference in New Issue
Block a user