[PATCH v3 04/13] iommu/arm: avoid arm-smmu-base.c bound to a specific smmu
Zhen Lei
thunder.leizhen at huawei.com
Wed Jul 9 23:52:57 PDT 2014
To keep all SMMU drivers can be running at the same time, place hwdep-ops hooks
in structure arm_smmu_device, so each smmu can correctly invoke the appropriate
hooks at running time.
Signed-off-by: Zhen Lei <thunder.leizhen at huawei.com>
---
drivers/iommu/arm-smmu-base.c | 28 +++++++++++++++++----------
drivers/iommu/arm-smmu.c | 39 ++++++++++++++++++++++++++++----------
drivers/iommu/arm-smmu.h | 44 +++++++++++++++++++++++++++++++------------
3 files changed, 79 insertions(+), 32 deletions(-)
diff --git a/drivers/iommu/arm-smmu-base.c b/drivers/iommu/arm-smmu-base.c
index 2fd29e5..c6824b5 100644
--- a/drivers/iommu/arm-smmu-base.c
+++ b/drivers/iommu/arm-smmu-base.c
@@ -264,7 +264,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
}
irq = smmu->irqs[smmu->num_global_irqs + root_cfg->irptndx];
- ret = request_irq(irq, arm_smmu_context_fault, IRQF_SHARED,
+ ret = request_irq(irq, smmu->hwdep_ops->context_fault, IRQF_SHARED,
"arm-smmu-context-fault", domain);
if (IS_ERR_VALUE(ret)) {
dev_err(smmu->dev, "failed to request context IRQ %d (%u)\n",
@@ -274,7 +274,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
}
root_cfg->smmu = smmu;
- arm_smmu_init_context_bank(smmu_domain);
+ smmu->hwdep_ops->init_context_bank(smmu_domain);
return ret;
out_free_context:
@@ -425,7 +425,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
if (!master)
return -ENODEV;
- return arm_smmu_domain_add_master(smmu_domain, master);
+ return device_smmu->hwdep_ops->domain_add_master(smmu_domain, master);
err_unlock:
spin_unlock_irqrestore(&smmu_domain->lock, flags);
@@ -436,10 +436,11 @@ static void arm_smmu_detach_dev(struct iommu_domain *domain, struct device *dev)
{
struct arm_smmu_domain *smmu_domain = domain->priv;
struct arm_smmu_master *master;
+ struct arm_smmu_device *smmu = smmu_domain->root_cfg.smmu;
master = find_smmu_master(smmu_domain->leaf_smmu, dev->of_node);
if (master)
- arm_smmu_domain_remove_master(smmu_domain, master);
+ smmu->hwdep_ops->domain_remove_master(smmu_domain, master);
}
static bool arm_smmu_pte_is_contiguous_range(unsigned long addr,
@@ -694,9 +695,10 @@ static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
{
int ret;
struct arm_smmu_domain *smmu_domain = domain->priv;
+ struct arm_smmu_device *smmu = smmu_domain->root_cfg.smmu;
ret = arm_smmu_handle_mapping(smmu_domain, iova, 0, size, 0);
- arm_smmu_tlb_inv_context(&smmu_domain->root_cfg);
+ smmu->hwdep_ops->tlb_inv_context(&smmu_domain->root_cfg);
return ret ? 0 : size;
}
@@ -823,7 +825,8 @@ static struct iommu_ops arm_smmu_ops = {
PAGE_SIZE),
};
-int arm_smmu_device_dt_probe(struct platform_device *pdev)
+int arm_smmu_device_dt_probe(struct platform_device *pdev,
+ struct smmu_hwdep_ops *ops)
{
struct resource *res;
struct arm_smmu_device *smmu;
@@ -901,7 +904,9 @@ int arm_smmu_device_dt_probe(struct platform_device *pdev)
if (dev_node)
smmu->parent_of_node = dev_node;
- err = arm_smmu_device_cfg_probe(smmu);
+ smmu->hwdep_ops = ops;
+
+ err = smmu->hwdep_ops->device_cfg_probe(smmu);
if (err)
goto out_put_parent;
@@ -918,7 +923,7 @@ int arm_smmu_device_dt_probe(struct platform_device *pdev)
for (i = 0; i < smmu->num_global_irqs; ++i) {
err = request_irq(smmu->irqs[i],
- arm_smmu_global_fault,
+ smmu->hwdep_ops->global_fault,
IRQF_SHARED,
"arm-smmu global fault",
smmu);
@@ -934,7 +939,10 @@ int arm_smmu_device_dt_probe(struct platform_device *pdev)
list_add(&smmu->list, &arm_smmu_devices);
spin_unlock(&arm_smmu_devices_lock);
- arm_smmu_device_reset(smmu);
+ err = smmu->hwdep_ops->device_reset(smmu);
+ if (err)
+ goto out_free_irqs;
+
return 0;
out_free_irqs:
@@ -991,7 +999,7 @@ int arm_smmu_device_remove(struct platform_device *pdev)
free_irq(smmu->irqs[i], smmu);
/* Turn the thing off */
- return arm_smmu_device_unload(smmu);
+ return smmu->hwdep_ops->device_remove(smmu);
}
int __init arm_smmu_ops_init(void)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index c368e82..d08149d 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -240,7 +240,7 @@ static void arm_smmu_tlb_sync(struct arm_smmu_device *smmu)
}
}
-void arm_smmu_tlb_inv_context(struct arm_smmu_cfg *cfg)
+static void arm_smmu_tlb_inv_context(struct arm_smmu_cfg *cfg)
{
struct arm_smmu_device *smmu = cfg->smmu;
void __iomem *base = ARM_SMMU_GR0(smmu);
@@ -259,7 +259,7 @@ void arm_smmu_tlb_inv_context(struct arm_smmu_cfg *cfg)
arm_smmu_tlb_sync(smmu);
}
-irqreturn_t arm_smmu_context_fault(int irq, void *dev)
+static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
{
int flags, ret;
u32 fsr, far, fsynr, resume;
@@ -312,7 +312,7 @@ irqreturn_t arm_smmu_context_fault(int irq, void *dev)
return ret;
}
-irqreturn_t arm_smmu_global_fault(int irq, void *dev)
+static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
{
u32 gfsr, gfsynr0, gfsynr1, gfsynr2;
struct arm_smmu_device *smmu = dev;
@@ -336,7 +336,7 @@ irqreturn_t arm_smmu_global_fault(int irq, void *dev)
return IRQ_HANDLED;
}
-void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
+static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
{
u32 reg;
bool stage1;
@@ -604,7 +604,7 @@ static void arm_smmu_bypass_stream_mapping(struct arm_smmu_device *smmu,
}
}
-int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
+static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
struct arm_smmu_master *master)
{
int i, ret;
@@ -642,7 +642,7 @@ int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
return 0;
}
-void arm_smmu_domain_remove_master(struct arm_smmu_domain *smmu_domain,
+static void arm_smmu_domain_remove_master(struct arm_smmu_domain *smmu_domain,
struct arm_smmu_master *master)
{
struct arm_smmu_device *smmu = smmu_domain->root_cfg.smmu;
@@ -655,7 +655,7 @@ void arm_smmu_domain_remove_master(struct arm_smmu_domain *smmu_domain,
arm_smmu_master_free_smrs(smmu, master);
}
-void arm_smmu_device_reset(struct arm_smmu_device *smmu)
+static int arm_smmu_device_reset(struct arm_smmu_device *smmu)
{
void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
void __iomem *cb_base;
@@ -704,6 +704,8 @@ void arm_smmu_device_reset(struct arm_smmu_device *smmu)
/* Push the button */
arm_smmu_tlb_sync(smmu);
writel(reg, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0);
+
+ return 0;
}
static u32 arm_smmu_id_size_to_bits(u32 size)
@@ -725,7 +727,7 @@ static u32 arm_smmu_id_size_to_bits(u32 size)
}
}
-int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
+static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
{
u32 size;
void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
@@ -869,13 +871,25 @@ int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
return 0;
}
-int arm_smmu_device_unload(struct arm_smmu_device *smmu)
+static int arm_smmu_device_unload(struct arm_smmu_device *smmu)
{
writel(sCR0_CLIENTPD, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0);
return 0;
}
+static struct smmu_hwdep_ops arm_smmu_hwdep_ops = {
+ .tlb_inv_context = arm_smmu_tlb_inv_context,
+ .context_fault = arm_smmu_context_fault,
+ .global_fault = arm_smmu_global_fault,
+ .init_context_bank = arm_smmu_init_context_bank,
+ .domain_add_master = arm_smmu_domain_add_master,
+ .domain_remove_master = arm_smmu_domain_remove_master,
+ .device_reset = arm_smmu_device_reset,
+ .device_cfg_probe = arm_smmu_device_cfg_probe,
+ .device_remove = arm_smmu_device_unload,
+};
+
#ifdef CONFIG_OF
static struct of_device_id arm_smmu_of_match[] = {
{ .compatible = "arm,smmu-v1", },
@@ -887,13 +901,18 @@ static struct of_device_id arm_smmu_of_match[] = {
MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
#endif
+static int arm_smmu_device_probe(struct platform_device *pdev)
+{
+ return arm_smmu_device_dt_probe(pdev, &arm_smmu_hwdep_ops);
+}
+
static struct platform_driver arm_smmu_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "arm-smmu",
.of_match_table = of_match_ptr(arm_smmu_of_match),
},
- .probe = arm_smmu_device_dt_probe,
+ .probe = arm_smmu_device_probe,
.remove = arm_smmu_device_remove,
};
diff --git a/drivers/iommu/arm-smmu.h b/drivers/iommu/arm-smmu.h
index 37d9a46..ca35694 100644
--- a/drivers/iommu/arm-smmu.h
+++ b/drivers/iommu/arm-smmu.h
@@ -142,10 +142,14 @@ struct arm_smmu_master {
struct arm_smmu_smr *smrs;
};
+struct smmu_hwdep_ops;
+
struct arm_smmu_device {
struct device *dev;
struct device_node *parent_of_node;
+ struct smmu_hwdep_ops *hwdep_ops;
+
void __iomem *base;
u32 size;
u32 pagesize;
@@ -206,25 +210,41 @@ struct arm_smmu_domain {
spinlock_t lock;
};
+/**
+ * struct smmu_hwdep_ops - smmu hardware dependent ops
+ * @tlb_inv_context: invalid smmu context bank tlb
+ * @context_fault: context fault handler
+ * @global_fault: global fault handler
+ * @init_context_bank: init a context bank
+ * @domain_add_master: add a master into a domain
+ * @domain_remove_master: remove a master from a domain
+ * @device_reset: initialize a smmu
+ * @device_cfg_probe: probe hardware configuration
+ * @device_remove: turn off a smmu and reclaim associated resources
+ */
+struct smmu_hwdep_ops {
+ void (*tlb_inv_context)(struct arm_smmu_cfg *cfg);
+ irqreturn_t (*context_fault)(int irq, void *dev);
+ irqreturn_t (*global_fault)(int irq, void *dev);
+ void (*init_context_bank)(struct arm_smmu_domain *smmu_domain);
+ int (*domain_add_master)(struct arm_smmu_domain *smmu_domain,
+ struct arm_smmu_master *master);
+ void (*domain_remove_master)(struct arm_smmu_domain *smmu_domain,
+ struct arm_smmu_master *master);
+ int (*device_reset)(struct arm_smmu_device *smmu);
+ int (*device_cfg_probe)(struct arm_smmu_device *smmu);
+ int (*device_remove)(struct arm_smmu_device *smmu);
+};
+
extern int __arm_smmu_alloc_bitmap(unsigned long *map, int start, int end);
extern void __arm_smmu_free_bitmap(unsigned long *map, int idx);
extern struct arm_smmu_device *find_parent_smmu(struct arm_smmu_device *smmu);
extern void arm_smmu_flush_pgtable(struct arm_smmu_device *smmu, void *addr,
size_t size);
-extern int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu);
-extern int arm_smmu_device_dt_probe(struct platform_device *pdev);
+extern int arm_smmu_device_dt_probe(struct platform_device *pdev,
+ struct smmu_hwdep_ops *ops);
extern int arm_smmu_device_remove(struct platform_device *pdev);
-extern void arm_smmu_tlb_inv_context(struct arm_smmu_cfg *cfg);
-extern irqreturn_t arm_smmu_context_fault(int irq, void *dev);
-extern irqreturn_t arm_smmu_global_fault(int irq, void *dev);
-extern void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain);
extern void arm_smmu_destroy_domain_context(struct iommu_domain *domain);
-extern int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
- struct arm_smmu_master *master);
-extern void arm_smmu_domain_remove_master(struct arm_smmu_domain *smmu_domain,
- struct arm_smmu_master *master);
-extern void arm_smmu_device_reset(struct arm_smmu_device *smmu);
-extern int arm_smmu_device_unload(struct arm_smmu_device *smmu);
extern int __init arm_smmu_ops_init(void);
#endif
--
1.8.0
More information about the linux-arm-kernel
mailing list