iommu/rockchip: refactor iommu to support 3rd_party iommu

Take av1d-iommu as example:

make av1d-iommu as rockchip-iommu sub-driver, all av1d-iommu ops
transform from rockchip-iommu ops.

av1d-iommu should implement struct third_iommu_ops_wrap for transform

Change-Id: I98f059aa890adaecbc5c35763db2efba88b09055
Signed-off-by: Simon Xue <xxm@rock-chips.com>
This commit is contained in:
Simon Xue
2023-07-03 18:13:57 +08:00
committed by Tao Huang
parent 65768b30e3
commit 4b02081506
2 changed files with 121 additions and 0 deletions

View File

@@ -92,6 +92,8 @@ struct rk_iommu_domain {
spinlock_t iommus_lock; /* lock for iommus list */
spinlock_t dt_lock; /* lock for modifying page directory table */
bool shootdown_entire;
struct third_iommu_ops_wrap *opt_ops;
struct device *iommu_dev;
struct iommu_domain domain;
};
@@ -122,6 +124,7 @@ struct rk_iommu {
struct iommu_domain *domain; /* domain to which iommu is attached */
struct iommu_group *group;
bool shootdown_entire;
struct third_iommu_ops_wrap *opt_ops;
bool iommu_enabled;
bool need_res_map;
};
@@ -804,6 +807,10 @@ static phys_addr_t rk_iommu_iova_to_phys(struct iommu_domain *domain,
u32 dte, pte;
u32 *page_table;
if (rk_domain->opt_ops && rk_domain->opt_ops->iova_to_phys)
return rk_domain->opt_ops->iova_to_phys(domain, iova,
rk_domain->iommu_dev);
spin_lock_irqsave(&rk_domain->dt_lock, flags);
dte = rk_domain->dt[rk_iova_dte_index(iova)];
@@ -1005,6 +1012,10 @@ static int rk_iommu_map(struct iommu_domain *domain, unsigned long _iova,
u32 dte, pte_index;
int ret;
if (rk_domain->opt_ops && rk_domain->opt_ops->map)
return rk_domain->opt_ops->map(domain, _iova, paddr, size, prot,
gfp, rk_domain->iommu_dev);
spin_lock_irqsave(&rk_domain->dt_lock, flags);
/*
@@ -1044,6 +1055,10 @@ static size_t rk_iommu_unmap(struct iommu_domain *domain, unsigned long _iova,
size_t unmap_size;
struct rk_iommu *iommu = rk_iommu_get(rk_domain);
if (rk_domain->opt_ops && rk_domain->opt_ops->unmap)
return rk_domain->opt_ops->unmap(domain, _iova, size, gather,
rk_domain->iommu_dev);
spin_lock_irqsave(&rk_domain->dt_lock, flags);
/*
@@ -1081,6 +1096,10 @@ static void rk_iommu_flush_tlb_all(struct iommu_domain *domain)
unsigned long flags;
int i;
if (rk_domain->opt_ops && rk_domain->opt_ops->flush_iotlb_all)
return rk_domain->opt_ops->flush_iotlb_all(domain,
rk_domain->iommu_dev);
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
list_for_each(pos, &rk_domain->iommus) {
struct rk_iommu *iommu;
@@ -1132,11 +1151,18 @@ static void rk_iommu_disable(struct rk_iommu *iommu)
int rockchip_iommu_disable(struct device *dev)
{
struct rk_iommu *iommu;
struct rk_iommu_domain *rk_domain;
iommu = rk_iommu_from_dev(dev);
if (!iommu)
return -ENODEV;
if (iommu->domain) {
rk_domain = to_rk_domain(iommu->domain);
if (rk_domain->opt_ops && rk_domain->opt_ops->disable)
return rk_domain->opt_ops->disable(rk_domain->iommu_dev);
}
rk_iommu_disable(iommu);
return 0;
@@ -1191,11 +1217,18 @@ out_disable_clocks:
int rockchip_iommu_enable(struct device *dev)
{
struct rk_iommu *iommu;
struct rk_iommu_domain *rk_domain;
iommu = rk_iommu_from_dev(dev);
if (!iommu)
return -ENODEV;
if (iommu->domain) {
rk_domain = to_rk_domain(iommu->domain);
if (rk_domain->opt_ops && rk_domain->opt_ops->enable)
return rk_domain->opt_ops->enable(rk_domain->iommu_dev);
}
return rk_iommu_enable(iommu);
}
EXPORT_SYMBOL(rockchip_iommu_enable);
@@ -1247,6 +1280,15 @@ static void rk_iommu_detach_device(struct iommu_domain *domain,
if (!iommu)
return;
if (rk_domain->opt_ops && rk_domain->opt_ops->detach_dev) {
iommu->domain = NULL;
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
list_del_init(&iommu->node);
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
return rk_domain->opt_ops->detach_dev(domain,
rk_domain->iommu_dev);
}
dev_dbg(dev, "Detaching from iommu domain\n");
if (!iommu->domain)
@@ -1282,6 +1324,20 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
if (!iommu)
return 0;
if (iommu->opt_ops) {
rk_domain->opt_ops = iommu->opt_ops;
rk_domain->iommu_dev = iommu->dev;
}
if (rk_domain->opt_ops && rk_domain->opt_ops->attach_dev) {
iommu->domain = domain;
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
list_add_tail(&iommu->node, &rk_domain->iommus);
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
return rk_domain->opt_ops->attach_dev(domain,
rk_domain->iommu_dev);
}
dev_dbg(dev, "Attaching to iommu domain\n");
if (iommu->domain)
@@ -1364,6 +1420,9 @@ static void rk_iommu_domain_free(struct iommu_domain *domain)
struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
int i;
if (rk_domain->opt_ops && rk_domain->opt_ops->free)
rk_domain->opt_ops->free(domain, rk_domain->iommu_dev);
WARN_ON(!list_empty(&rk_domain->iommus));
for (i = 0; i < NUM_DT_ENTRIES; i++) {
@@ -1497,6 +1556,7 @@ static const struct iommu_ops rk_iommu_ops = {
.device_group = rk_iommu_device_group,
.pgsize_bitmap = RK_IOMMU_PGSIZE_BITMAP,
.of_xlate = rk_iommu_of_xlate,
.owner = THIS_MODULE,
.default_domain_ops = &(const struct iommu_domain_ops) {
.attach_dev = rk_iommu_attach_device,
.detach_dev = rk_iommu_detach_device,
@@ -1536,6 +1596,11 @@ static int rk_iommu_probe(struct platform_device *pdev)
if (WARN_ON(rk_ops != ops))
return -EINVAL;
if (device_property_match_string(dev, "compatible", "rockchip,iommu-av1d") >= 0) {
iommu->opt_ops = NULL;
goto alloc_group;
}
iommu->bases = devm_kcalloc(dev, num_res, sizeof(*iommu->bases),
GFP_KERNEL);
if (!iommu->bases)
@@ -1592,6 +1657,7 @@ static int rk_iommu_probe(struct platform_device *pdev)
if (err)
return err;
alloc_group:
iommu->group = iommu_group_alloc();
if (IS_ERR(iommu->group)) {
err = PTR_ERR(iommu->group);
@@ -1614,6 +1680,9 @@ static int rk_iommu_probe(struct platform_device *pdev)
if (!dma_dev)
dma_dev = &pdev->dev;
if (iommu->opt_ops)
goto opt_iommu_probe;
pm_runtime_enable(dev);
if (iommu->skip_read)
@@ -1640,6 +1709,13 @@ skip_request_irq:
pr_info("%s,%d, res_page = 0x%pa\n", __func__, __LINE__, &res_page);
}
opt_iommu_probe:
if (iommu->opt_ops && iommu->opt_ops->probe) {
err = iommu->opt_ops->probe(pdev);
if (err)
goto err_remove_sysfs;
}
dma_set_mask_and_coherent(dev, rk_ops->dma_bit_mask);
return 0;
@@ -1656,6 +1732,13 @@ static void rk_iommu_shutdown(struct platform_device *pdev)
{
struct rk_iommu *iommu = platform_get_drvdata(pdev);
int i;
struct rk_iommu_domain *rk_domain;
if (iommu->domain) {
rk_domain = to_rk_domain(iommu->domain);
if (rk_domain->opt_ops && rk_domain->opt_ops->shutdown)
return rk_domain->opt_ops->shutdown(pdev);
}
if (iommu->skip_read)
goto skip_free_irq;
@@ -1674,10 +1757,15 @@ skip_free_irq:
static int __maybe_unused rk_iommu_suspend(struct device *dev)
{
struct rk_iommu *iommu = dev_get_drvdata(dev);
struct rk_iommu_domain *rk_domain;
if (!iommu->domain)
return 0;
rk_domain = to_rk_domain(iommu->domain);
if (rk_domain->opt_ops && rk_domain->opt_ops->suspend)
return rk_domain->opt_ops->suspend(dev);
if (iommu->dlr_disable)
return 0;
@@ -1688,10 +1776,15 @@ static int __maybe_unused rk_iommu_suspend(struct device *dev)
static int __maybe_unused rk_iommu_resume(struct device *dev)
{
struct rk_iommu *iommu = dev_get_drvdata(dev);
struct rk_iommu_domain *rk_domain;
if (!iommu->domain)
return 0;
rk_domain = to_rk_domain(iommu->domain);
if (rk_domain->opt_ops && rk_domain->opt_ops->resume)
return rk_domain->opt_ops->resume(dev);
if (iommu->dlr_disable)
return 0;

View File

@@ -6,6 +6,34 @@
#define __SOC_ROCKCHIP_IOMMU_H
struct device;
struct iommu_domain;
struct iommu_iotlb_gather;
struct platform_device;
/* 1. dev and pdev is iommu device.
* 2. store third_iommu data in dev->platform_data.
*/
struct third_iommu_ops_wrap {
int (*attach_dev)(struct iommu_domain *domain, struct device *dev);
void (*detach_dev)(struct iommu_domain *domain, struct device *dev);
int (*map)(struct iommu_domain *domain, unsigned long iova,
phys_addr_t paddr, size_t size, int prot, gfp_t gfp,
struct device *dev);
size_t (*unmap)(struct iommu_domain *domain, unsigned long iova,
size_t size, struct iommu_iotlb_gather *iotlb_gather,
struct device *dev);
void (*flush_iotlb_all)(struct iommu_domain *domain,
struct device *dev);
phys_addr_t (*iova_to_phys)(struct iommu_domain *domain,
dma_addr_t iova, struct device *dev);
void (*free)(struct iommu_domain *domain, struct device *dev);
int (*enable)(struct device *dev);
int (*disable)(struct device *dev);
void (*shutdown)(struct platform_device *pdev);
int (*suspend)(struct device *dev);
int (*resume)(struct device *dev);
int (*probe)(struct platform_device *pdev);
};
#if IS_ENABLED(CONFIG_ROCKCHIP_IOMMU)
int rockchip_iommu_enable(struct device *dev);