diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt index 58d619f0498b..602f5f1e5816 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt @@ -79,6 +79,12 @@ conditions. - qcom,errata-ctx-fault-hang : Enable workaround for a context fault hang hardware errata. +- qcom,fatal-asf : Enable BUG_ON for address size faults. Some hardware + requires special fixups to recover from address size + faults. Rather than applying the fixups just BUG since + address size faults are due to a fundamental programming + error from which we don't care about recovering anyways. + - clocks : List of clocks to be used during SMMU register access. See Documentation/devicetree/bindings/clock/clock-bindings.txt for information about the format. For each clock specified diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 7f47ee2cda81..f73279c8b09f 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -428,6 +428,7 @@ struct arm_smmu_device { #define ARM_SMMU_OPT_REGISTER_SAVE (1 << 3) #define ARM_SMMU_OPT_SKIP_INIT (1 << 4) #define ARM_SMMU_OPT_ERRATA_CTX_FAULT_HANG (1 << 5) +#define ARM_SMMU_OPT_FATAL_ASF (1 << 6) u32 options; enum arm_smmu_arch_version version; @@ -498,6 +499,7 @@ static struct arm_smmu_option_prop arm_smmu_options[] = { { ARM_SMMU_OPT_REGISTER_SAVE, "qcom,register-save" }, { ARM_SMMU_OPT_SKIP_INIT, "qcom,skip-init" }, { ARM_SMMU_OPT_ERRATA_CTX_FAULT_HANG, "qcom,errata-ctx-fault-hang" }, + { ARM_SMMU_OPT_FATAL_ASF, "qcom,fatal-asf" }, { 0, NULL}, }; @@ -839,6 +841,7 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev) void __iomem *cb_base; bool ctx_hang_errata = smmu->options & ARM_SMMU_OPT_ERRATA_CTX_FAULT_HANG; + bool fatal_asf = smmu->options & ARM_SMMU_OPT_FATAL_ASF; arm_smmu_enable_clocks(smmu); @@ -855,6 +858,12 @@ static irqreturn_t arm_smmu_context_fault(int irq, void *dev) "Unexpected context fault (fsr 0x%x)\n", fsr); + if (fatal_asf && (fsr & FSR_ASF)) { + dev_err(smmu->dev, + "Took an address size fault. Refusing to recover.\n"); + BUG(); + } + fsynr = readl_relaxed(cb_base + ARM_SMMU_CB_FSYNR0); flags = fsynr & FSYNR0_WNR ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ;