mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 19:08:57 +09:00
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:
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user