iommu/rockchip: Add missing set_platform_dma_ops callback
Similar to exynos, we need a set_platform_dma_ops() callback for proper operation on ARM 32 bit after recent changes in the IOMMU framework (detach ops removal). But also the use of a NULL domain is confusing. Rework the code to add support for IOMMU_DOMAIN_IDENTITY and a singleton rk_identity_domain which is assigned to domain when using an identity mapping rather than "detaching". This makes the code easier to reason about. Signed-off-by: Steven Price <steven.price@arm.com> Acked-by: Heiko Stuebner <heiko@sntech.de> Tested-by: Heiko Stuebner <heiko@sntech.de> Link: https://lore.kernel.org/r/20230331095154.2671129-1-steven.price@arm.com Signed-off-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
parent
e8d018dd02
commit
25c2325575
|
@ -124,6 +124,7 @@ struct rk_iommudata {
|
|||
|
||||
static struct device *dma_dev;
|
||||
static const struct rk_iommu_ops *rk_ops;
|
||||
static struct iommu_domain rk_identity_domain;
|
||||
|
||||
static inline void rk_table_flush(struct rk_iommu_domain *dom, dma_addr_t dma,
|
||||
unsigned int count)
|
||||
|
@ -646,7 +647,7 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
|
|||
* Ignore the return code, though, since we always zap cache
|
||||
* and clear the page fault anyway.
|
||||
*/
|
||||
if (iommu->domain)
|
||||
if (iommu->domain != &rk_identity_domain)
|
||||
report_iommu_fault(iommu->domain, iommu->dev, iova,
|
||||
flags);
|
||||
else
|
||||
|
@ -980,26 +981,27 @@ out_disable_clocks:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void rk_iommu_detach_device(struct iommu_domain *domain,
|
||||
struct device *dev)
|
||||
static int rk_iommu_identity_attach(struct iommu_domain *identity_domain,
|
||||
struct device *dev)
|
||||
{
|
||||
struct rk_iommu *iommu;
|
||||
struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
|
||||
struct rk_iommu_domain *rk_domain;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
/* Allow 'virtual devices' (eg drm) to detach from domain */
|
||||
iommu = rk_iommu_from_dev(dev);
|
||||
if (!iommu)
|
||||
return;
|
||||
return -ENODEV;
|
||||
|
||||
rk_domain = to_rk_domain(iommu->domain);
|
||||
|
||||
dev_dbg(dev, "Detaching from iommu domain\n");
|
||||
|
||||
/* iommu already detached */
|
||||
if (iommu->domain != domain)
|
||||
return;
|
||||
if (iommu->domain == identity_domain)
|
||||
return 0;
|
||||
|
||||
iommu->domain = NULL;
|
||||
iommu->domain = identity_domain;
|
||||
|
||||
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
|
||||
list_del_init(&iommu->node);
|
||||
|
@ -1011,8 +1013,31 @@ static void rk_iommu_detach_device(struct iommu_domain *domain,
|
|||
rk_iommu_disable(iommu);
|
||||
pm_runtime_put(iommu->dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rk_iommu_identity_free(struct iommu_domain *domain)
|
||||
{
|
||||
}
|
||||
|
||||
static struct iommu_domain_ops rk_identity_ops = {
|
||||
.attach_dev = rk_iommu_identity_attach,
|
||||
.free = rk_iommu_identity_free,
|
||||
};
|
||||
|
||||
static struct iommu_domain rk_identity_domain = {
|
||||
.type = IOMMU_DOMAIN_IDENTITY,
|
||||
.ops = &rk_identity_ops,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ARM
|
||||
static void rk_iommu_set_platform_dma(struct device *dev)
|
||||
{
|
||||
WARN_ON(rk_iommu_identity_attach(&rk_identity_domain, dev));
|
||||
}
|
||||
#endif
|
||||
|
||||
static int rk_iommu_attach_device(struct iommu_domain *domain,
|
||||
struct device *dev)
|
||||
{
|
||||
|
@ -1035,8 +1060,9 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
|
|||
if (iommu->domain == domain)
|
||||
return 0;
|
||||
|
||||
if (iommu->domain)
|
||||
rk_iommu_detach_device(iommu->domain, dev);
|
||||
ret = rk_iommu_identity_attach(&rk_identity_domain, dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
iommu->domain = domain;
|
||||
|
||||
|
@ -1050,7 +1076,7 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
|
|||
|
||||
ret = rk_iommu_enable(iommu);
|
||||
if (ret)
|
||||
rk_iommu_detach_device(iommu->domain, dev);
|
||||
WARN_ON(rk_iommu_identity_attach(&rk_identity_domain, dev));
|
||||
|
||||
pm_runtime_put(iommu->dev);
|
||||
|
||||
|
@ -1061,6 +1087,9 @@ static struct iommu_domain *rk_iommu_domain_alloc(unsigned type)
|
|||
{
|
||||
struct rk_iommu_domain *rk_domain;
|
||||
|
||||
if (type == IOMMU_DOMAIN_IDENTITY)
|
||||
return &rk_identity_domain;
|
||||
|
||||
if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA)
|
||||
return NULL;
|
||||
|
||||
|
@ -1176,6 +1205,7 @@ static int rk_iommu_of_xlate(struct device *dev,
|
|||
iommu_dev = of_find_device_by_node(args->np);
|
||||
|
||||
data->iommu = platform_get_drvdata(iommu_dev);
|
||||
data->iommu->domain = &rk_identity_domain;
|
||||
dev_iommu_priv_set(dev, data);
|
||||
|
||||
platform_device_put(iommu_dev);
|
||||
|
@ -1188,6 +1218,9 @@ static const struct iommu_ops rk_iommu_ops = {
|
|||
.probe_device = rk_iommu_probe_device,
|
||||
.release_device = rk_iommu_release_device,
|
||||
.device_group = rk_iommu_device_group,
|
||||
#ifdef CONFIG_ARM
|
||||
.set_platform_dma_ops = rk_iommu_set_platform_dma,
|
||||
#endif
|
||||
.pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP,
|
||||
.of_xlate = rk_iommu_of_xlate,
|
||||
.default_domain_ops = &(const struct iommu_domain_ops) {
|
||||
|
@ -1343,7 +1376,7 @@ static int __maybe_unused rk_iommu_suspend(struct device *dev)
|
|||
{
|
||||
struct rk_iommu *iommu = dev_get_drvdata(dev);
|
||||
|
||||
if (!iommu->domain)
|
||||
if (iommu->domain == &rk_identity_domain)
|
||||
return 0;
|
||||
|
||||
rk_iommu_disable(iommu);
|
||||
|
@ -1354,7 +1387,7 @@ static int __maybe_unused rk_iommu_resume(struct device *dev)
|
|||
{
|
||||
struct rk_iommu *iommu = dev_get_drvdata(dev);
|
||||
|
||||
if (!iommu->domain)
|
||||
if (iommu->domain == &rk_identity_domain)
|
||||
return 0;
|
||||
|
||||
return rk_iommu_enable(iommu);
|
||||
|
|
Loading…
Reference in New Issue