Loading drivers/iommu/Kconfig +10 −0 Original line number Diff line number Diff line Loading @@ -395,6 +395,16 @@ config ARM_SMMU_V3 Say Y here if your system includes an IOMMU device implementing the ARM SMMUv3 architecture. config ARM_SMMU_SELFTEST bool "ARM SMMU self test support" depends on ARM_SMMU help Enables self tests for arm smmu. Tests basic hardware configurations like interrupts. Note that enabling this option can marginally increase the boot time. If unsure, say N here. config QCOM_LAZY_MAPPING bool "Reference counted iommu-mapping support" depends on ION Loading drivers/iommu/arm-smmu.c +105 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,8 @@ #include <linux/msm-bus.h> #include <trace/events/iommu.h> #include <dt-bindings/msm/msm-bus-ids.h> #include <linux/irq.h> #include <linux/wait.h> #include <linux/amba/bus.h> Loading Loading @@ -519,6 +521,108 @@ static void arm_smmu_secure_domain_unlock(struct arm_smmu_domain *smmu_domain) mutex_unlock(&smmu_domain->assign_lock); } #ifdef CONFIG_ARM_SMMU_SELFTEST static int selftest; module_param_named(selftest, selftest, int, 0644); static int irq_count; static DECLARE_WAIT_QUEUE_HEAD(wait_int); static irqreturn_t arm_smmu_cf_selftest(int irq, void *cb_base) { u32 fsr; struct irq_data *irq_data = irq_get_irq_data(irq); unsigned long hwirq = ULONG_MAX; fsr = readl_relaxed(cb_base + ARM_SMMU_CB_FSR); irq_count++; if (irq_data) hwirq = irq_data->hwirq; pr_info("Interrupt (irq:%d hwirq:%ld) received, fsr:0x%x\n", irq, hwirq, fsr); writel_relaxed(fsr, cb_base + ARM_SMMU_CB_FSR); wake_up(&wait_int); return IRQ_HANDLED; } static void arm_smmu_interrupt_selftest(struct arm_smmu_device *smmu) { int cb; int cb_count = 0; if (!selftest) return; if (arm_smmu_is_static_cb(smmu)) return; cb = smmu->num_s2_context_banks; if (smmu->version < ARM_SMMU_V2) return; for_each_clear_bit_from(cb, smmu->context_map, smmu->num_context_banks) { int irq; int ret; void *cb_base; u32 reg; u32 reg_orig; int irq_cnt; irq = smmu->irqs[smmu->num_global_irqs + cb]; cb_base = ARM_SMMU_CB(smmu, cb); ret = devm_request_threaded_irq(smmu->dev, irq, NULL, arm_smmu_cf_selftest, IRQF_ONESHOT | IRQF_SHARED, "arm-smmu-context-fault", cb_base); if (ret < 0) { dev_err(smmu->dev, "Failed to request cntx IRQ %d (%u)\n", cb, irq); continue; } cb_count++; irq_cnt = irq_count; reg_orig = readl_relaxed(cb_base + ARM_SMMU_CB_SCTLR); reg = reg_orig | SCTLR_CFIE | SCTLR_CFRE; writel_relaxed(reg, cb_base + ARM_SMMU_CB_SCTLR); dev_info(smmu->dev, "Testing cntx %d irq %d\n", cb, irq); /* Make sure ARM_SMMU_CB_SCTLR is configured */ wmb(); writel_relaxed(FSR_TF, cb_base + ARM_SMMU_CB_FSRRESTORE); wait_event_timeout(wait_int, (irq_count > irq_cnt), msecs_to_jiffies(1000)); /* Make sure ARM_SMMU_CB_FSRRESTORE is written to */ wmb(); writel_relaxed(reg_orig, cb_base + ARM_SMMU_CB_SCTLR); devm_free_irq(smmu->dev, irq, cb_base); } dev_info(smmu->dev, "Interrupt selftest completed...\n"); dev_info(smmu->dev, "Tested %d contexts, received %d interrupts\n", cb_count, irq_count); WARN_ON(cb_count != irq_count); irq_count = 0; } #else static void arm_smmu_interrupt_selftest(struct arm_smmu_device *smmu) { } #endif /* * init() * Hook for additional device tree parsing at probe time. Loading Loading @@ -4768,6 +4872,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) platform_set_drvdata(pdev, smmu); arm_smmu_device_reset(smmu); arm_smmu_test_smr_masks(smmu); arm_smmu_interrupt_selftest(smmu); arm_smmu_power_off(smmu->pwr); /* Loading Loading
drivers/iommu/Kconfig +10 −0 Original line number Diff line number Diff line Loading @@ -395,6 +395,16 @@ config ARM_SMMU_V3 Say Y here if your system includes an IOMMU device implementing the ARM SMMUv3 architecture. config ARM_SMMU_SELFTEST bool "ARM SMMU self test support" depends on ARM_SMMU help Enables self tests for arm smmu. Tests basic hardware configurations like interrupts. Note that enabling this option can marginally increase the boot time. If unsure, say N here. config QCOM_LAZY_MAPPING bool "Reference counted iommu-mapping support" depends on ION Loading
drivers/iommu/arm-smmu.c +105 −0 Original line number Diff line number Diff line Loading @@ -56,6 +56,8 @@ #include <linux/msm-bus.h> #include <trace/events/iommu.h> #include <dt-bindings/msm/msm-bus-ids.h> #include <linux/irq.h> #include <linux/wait.h> #include <linux/amba/bus.h> Loading Loading @@ -519,6 +521,108 @@ static void arm_smmu_secure_domain_unlock(struct arm_smmu_domain *smmu_domain) mutex_unlock(&smmu_domain->assign_lock); } #ifdef CONFIG_ARM_SMMU_SELFTEST static int selftest; module_param_named(selftest, selftest, int, 0644); static int irq_count; static DECLARE_WAIT_QUEUE_HEAD(wait_int); static irqreturn_t arm_smmu_cf_selftest(int irq, void *cb_base) { u32 fsr; struct irq_data *irq_data = irq_get_irq_data(irq); unsigned long hwirq = ULONG_MAX; fsr = readl_relaxed(cb_base + ARM_SMMU_CB_FSR); irq_count++; if (irq_data) hwirq = irq_data->hwirq; pr_info("Interrupt (irq:%d hwirq:%ld) received, fsr:0x%x\n", irq, hwirq, fsr); writel_relaxed(fsr, cb_base + ARM_SMMU_CB_FSR); wake_up(&wait_int); return IRQ_HANDLED; } static void arm_smmu_interrupt_selftest(struct arm_smmu_device *smmu) { int cb; int cb_count = 0; if (!selftest) return; if (arm_smmu_is_static_cb(smmu)) return; cb = smmu->num_s2_context_banks; if (smmu->version < ARM_SMMU_V2) return; for_each_clear_bit_from(cb, smmu->context_map, smmu->num_context_banks) { int irq; int ret; void *cb_base; u32 reg; u32 reg_orig; int irq_cnt; irq = smmu->irqs[smmu->num_global_irqs + cb]; cb_base = ARM_SMMU_CB(smmu, cb); ret = devm_request_threaded_irq(smmu->dev, irq, NULL, arm_smmu_cf_selftest, IRQF_ONESHOT | IRQF_SHARED, "arm-smmu-context-fault", cb_base); if (ret < 0) { dev_err(smmu->dev, "Failed to request cntx IRQ %d (%u)\n", cb, irq); continue; } cb_count++; irq_cnt = irq_count; reg_orig = readl_relaxed(cb_base + ARM_SMMU_CB_SCTLR); reg = reg_orig | SCTLR_CFIE | SCTLR_CFRE; writel_relaxed(reg, cb_base + ARM_SMMU_CB_SCTLR); dev_info(smmu->dev, "Testing cntx %d irq %d\n", cb, irq); /* Make sure ARM_SMMU_CB_SCTLR is configured */ wmb(); writel_relaxed(FSR_TF, cb_base + ARM_SMMU_CB_FSRRESTORE); wait_event_timeout(wait_int, (irq_count > irq_cnt), msecs_to_jiffies(1000)); /* Make sure ARM_SMMU_CB_FSRRESTORE is written to */ wmb(); writel_relaxed(reg_orig, cb_base + ARM_SMMU_CB_SCTLR); devm_free_irq(smmu->dev, irq, cb_base); } dev_info(smmu->dev, "Interrupt selftest completed...\n"); dev_info(smmu->dev, "Tested %d contexts, received %d interrupts\n", cb_count, irq_count); WARN_ON(cb_count != irq_count); irq_count = 0; } #else static void arm_smmu_interrupt_selftest(struct arm_smmu_device *smmu) { } #endif /* * init() * Hook for additional device tree parsing at probe time. Loading Loading @@ -4768,6 +4872,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) platform_set_drvdata(pdev, smmu); arm_smmu_device_reset(smmu); arm_smmu_test_smr_masks(smmu); arm_smmu_interrupt_selftest(smmu); arm_smmu_power_off(smmu->pwr); /* Loading