mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
video: rockchip: mpp: fix share iommu issue for rk3528 on Arch32
Issue: 1. On arm32 platform iommu use the mapping->domain, while use the group->domain on arm64 platform. 2. __iommu_attach_group use group->default to judge whether new device in kernel 5.10 branch, while use group->domain in kernel 6.1 branch. For this change, when two devices share the iommu, the first device attach success, while the second device failed in kernel 6.1 branch. Method: 1. Set driver_managed_dma=true to ensure that during the IOMMU probe phase, even if attach group failed, the mapping will not be released. 2. After the IOMMU probe succeeds, record info->domain=mapping->domain and detach it, ensuring that group->domain is set to NULL. This prevents the next device which sharing the IOMMU, not return -EBUSY when attach the group. 3. Before hardware running, the shared IOMMU should check whether the device has been switched. If so, it needs to attach the current device's info->domain. 4. When removing a shared IOMMU, it must also ensure that group->domain corresponds to the current device. Change-Id: If0fec01a0bcf9c49850129bfa5ac28484fece9a2 Signed-off-by: Ding Wei <leo.ding@rock-chips.com>
This commit is contained in:
@@ -2239,7 +2239,10 @@ int mpp_dev_probe(struct mpp_dev *mpp,
|
||||
if (IS_ERR(mpp->iommu_info)) {
|
||||
dev_err(dev, "failed to attach iommu\n");
|
||||
mpp->iommu_info = NULL;
|
||||
} else {
|
||||
mpp->iommu_info->queue = mpp->queue;
|
||||
}
|
||||
|
||||
if (mpp->hw_ops->init) {
|
||||
ret = mpp->hw_ops->init(mpp);
|
||||
if (ret)
|
||||
|
||||
@@ -507,6 +507,9 @@ struct mpp_taskqueue {
|
||||
u32 core_id_max;
|
||||
u32 core_count;
|
||||
unsigned long dev_active_flags;
|
||||
|
||||
/* for devices which share iommu, record last attach device */
|
||||
struct mpp_iommu_info *last_iommu_info;
|
||||
};
|
||||
|
||||
struct mpp_reset_group {
|
||||
@@ -547,6 +550,9 @@ struct mpp_service {
|
||||
/* global timing record flag */
|
||||
u32 timing_en;
|
||||
u32 load_interval;
|
||||
|
||||
/* bit mask for iommu shared */
|
||||
u32 iommu_shared_mask;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/kref.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#ifdef CONFIG_ARM_DMA_USE_IOMMU
|
||||
#include <asm/dma-iommu.h>
|
||||
@@ -451,9 +452,19 @@ int mpp_iommu_detach(struct mpp_iommu_info *info)
|
||||
|
||||
int mpp_iommu_attach(struct mpp_iommu_info *info)
|
||||
{
|
||||
struct mpp_iommu_info *last_info;
|
||||
|
||||
if (!info)
|
||||
return 0;
|
||||
|
||||
/* if device changed, detach last first */
|
||||
last_info = info->queue->last_iommu_info;
|
||||
if (info->shared && last_info && last_info->shared
|
||||
&& (info->dev != last_info->dev)) {
|
||||
iommu_detach_group(last_info->domain, last_info->group);
|
||||
}
|
||||
info->queue->last_iommu_info = info;
|
||||
|
||||
if (info->domain == iommu_get_domain_for_dev(info->dev))
|
||||
return 0;
|
||||
|
||||
@@ -561,6 +572,15 @@ mpp_iommu_probe(struct device *dev)
|
||||
info->irq = platform_get_irq(pdev, 0);
|
||||
info->got_irq = (info->irq < 0) ? false : true;
|
||||
|
||||
/* get shared flag, if true detach */
|
||||
if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
|
||||
struct platform_driver *drv = to_platform_driver(dev->driver);
|
||||
|
||||
info->shared = drv->driver_managed_dma;
|
||||
if (info->shared)
|
||||
iommu_detach_group(info->domain, info->group);
|
||||
}
|
||||
|
||||
return info;
|
||||
|
||||
err_put_group:
|
||||
@@ -578,6 +598,10 @@ int mpp_iommu_remove(struct mpp_iommu_info *info)
|
||||
if (!info)
|
||||
return 0;
|
||||
|
||||
/* if iommu shared, ensure current device's domain, then remove correctly */
|
||||
if (info->shared)
|
||||
mpp_iommu_attach(info);
|
||||
|
||||
iommu_group_put(info->group);
|
||||
platform_device_put(info->pdev);
|
||||
|
||||
|
||||
@@ -102,6 +102,9 @@ struct mpp_iommu_info {
|
||||
|
||||
int irq;
|
||||
int got_irq;
|
||||
/* flag for mark iommu whether shared */
|
||||
bool shared;
|
||||
struct mpp_taskqueue *queue;
|
||||
};
|
||||
|
||||
struct mpp_dma_session *
|
||||
|
||||
@@ -100,6 +100,9 @@ static int mpp_add_driver(struct mpp_service *srv,
|
||||
&srv->grf_infos[type],
|
||||
grf_name);
|
||||
|
||||
if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU))
|
||||
driver->driver_managed_dma = (srv->iommu_shared_mask & BIT(type)) ? true : false;
|
||||
|
||||
ret = platform_driver_register(driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -444,6 +447,9 @@ static int mpp_service_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
of_property_read_u32(np, "rockchip,iommu-shared-mask",
|
||||
&srv->iommu_shared_mask);
|
||||
|
||||
ret = mpp_register_service(srv, MPP_SERVICE_NAME);
|
||||
if (ret) {
|
||||
dev_err(dev, "register %s device\n", MPP_SERVICE_NAME);
|
||||
|
||||
Reference in New Issue
Block a user