]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
iommu/arm-smmu: Report USF more clearly
authorRobin Murphy <robin.murphy@arm.com>
Tue, 17 Sep 2019 14:45:34 +0000 (15:45 +0100)
committerWill Deacon <will@kernel.org>
Tue, 1 Oct 2019 11:17:40 +0000 (12:17 +0100)
Although CONFIG_ARM_SMMU_DISABLE_BYPASS_BY_DEFAULT is a welcome tool
for smoking out inadequate firmware, the failure mode is non-obvious
and can be confusing for end users. Add some special-case reporting of
Unidentified Stream Faults to help clarify this particular symptom.
Since we're adding yet another print to the mix, also break out an
explicit ratelimit state to make sure everything stays together (and
reduce the static storage footprint a little).

Reviewed-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Will Deacon <will@kernel.org>
drivers/iommu/arm-smmu.c
drivers/iommu/arm-smmu.h

index d2d357c87b617eaefd466fbc0dc97a49d90dcd44..bd6683c210da6651dad797a3f1a871658fcab811 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/ratelimit.h>
 #include <linux/slab.h>
 
 #include <linux/amba/bus.h>
@@ -477,6 +478,8 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
 {
        u32 gfsr, gfsynr0, gfsynr1, gfsynr2;
        struct arm_smmu_device *smmu = dev;
+       static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
+                                     DEFAULT_RATELIMIT_BURST);
 
        gfsr = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sGFSR);
        gfsynr0 = arm_smmu_gr0_read(smmu, ARM_SMMU_GR0_sGFSYNR0);
@@ -486,11 +489,19 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
        if (!gfsr)
                return IRQ_NONE;
 
-       dev_err_ratelimited(smmu->dev,
-               "Unexpected global fault, this could be serious\n");
-       dev_err_ratelimited(smmu->dev,
-               "\tGFSR 0x%08x, GFSYNR0 0x%08x, GFSYNR1 0x%08x, GFSYNR2 0x%08x\n",
-               gfsr, gfsynr0, gfsynr1, gfsynr2);
+       if (__ratelimit(&rs)) {
+               if (IS_ENABLED(CONFIG_ARM_SMMU_DISABLE_BYPASS_BY_DEFAULT) &&
+                   (gfsr & sGFSR_USF))
+                       dev_err(smmu->dev,
+                               "Blocked unknown Stream ID 0x%hx; boot with \"arm-smmu.disable_bypass=0\" to allow, but this may have security implications\n",
+                               (u16)gfsynr1);
+               else
+                       dev_err(smmu->dev,
+                               "Unexpected global fault, this could be serious\n");
+               dev_err(smmu->dev,
+                       "\tGFSR 0x%08x, GFSYNR0 0x%08x, GFSYNR1 0x%08x, GFSYNR2 0x%08x\n",
+                       gfsr, gfsynr0, gfsynr1, gfsynr2);
+       }
 
        arm_smmu_gr0_write(smmu, ARM_SMMU_GR0_sGFSR, gfsr);
        return IRQ_HANDLED;
index ba0f05952dd9a41d797bd8b488d350b32a3cac23..409716410b0d5b0b475c3ce3a1e19db5ff880d85 100644 (file)
@@ -79,6 +79,8 @@
 #define ID7_MINOR                      GENMASK(3, 0)
 
 #define ARM_SMMU_GR0_sGFSR             0x48
+#define sGFSR_USF                      BIT(1)
+
 #define ARM_SMMU_GR0_sGFSYNR0          0x50
 #define ARM_SMMU_GR0_sGFSYNR1          0x54
 #define ARM_SMMU_GR0_sGFSYNR2          0x58