Skip to content

Commit b63b343

Browse files
committed
iommu/arm-smmu-v3: Abort all transactions if SMMU is enabled in kdump kernel
If we find that the SMMU is enabled during probe, we reset it by re-initialising its registers and either enabling translation or placing it into bypass based on the disable_bypass commandline option. In the case of a kdump kernel, the SMMU won't have been shutdown cleanly by the previous kernel and there may be concurrent DMA through the SMMU. Rather than reset the SMMU to bypass, which would likely lead to rampant data corruption, we can instead configure the SMMU to abort all incoming transactions when we find that it is enabled from within a kdump kernel. Reported-by: Sameer Goel <[email protected]> Signed-off-by: Will Deacon <[email protected]>
1 parent a71792d commit b63b343

File tree

1 file changed

+16
-6
lines changed

1 file changed

+16
-6
lines changed

drivers/iommu/arm-smmu-v3.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <linux/acpi_iort.h>
2525
#include <linux/bitfield.h>
2626
#include <linux/bitops.h>
27+
#include <linux/crash_dump.h>
2728
#include <linux/delay.h>
2829
#include <linux/dma-iommu.h>
2930
#include <linux/err.h>
@@ -2212,8 +2213,12 @@ static int arm_smmu_update_gbpa(struct arm_smmu_device *smmu, u32 set, u32 clr)
22122213
reg &= ~clr;
22132214
reg |= set;
22142215
writel_relaxed(reg | GBPA_UPDATE, gbpa);
2215-
return readl_relaxed_poll_timeout(gbpa, reg, !(reg & GBPA_UPDATE),
2216-
1, ARM_SMMU_POLL_TIMEOUT_US);
2216+
ret = readl_relaxed_poll_timeout(gbpa, reg, !(reg & GBPA_UPDATE),
2217+
1, ARM_SMMU_POLL_TIMEOUT_US);
2218+
2219+
if (ret)
2220+
dev_err(smmu->dev, "GBPA not responding to update\n");
2221+
return ret;
22172222
}
22182223

22192224
static void arm_smmu_free_msis(void *data)
@@ -2393,8 +2398,15 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
23932398

23942399
/* Clear CR0 and sync (disables SMMU and queue processing) */
23952400
reg = readl_relaxed(smmu->base + ARM_SMMU_CR0);
2396-
if (reg & CR0_SMMUEN)
2401+
if (reg & CR0_SMMUEN) {
2402+
if (is_kdump_kernel()) {
2403+
arm_smmu_update_gbpa(smmu, GBPA_ABORT, 0);
2404+
arm_smmu_device_disable(smmu);
2405+
return -EBUSY;
2406+
}
2407+
23972408
dev_warn(smmu->dev, "SMMU currently enabled! Resetting...\n");
2409+
}
23982410

23992411
ret = arm_smmu_device_disable(smmu);
24002412
if (ret)
@@ -2492,10 +2504,8 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass)
24922504
enables |= CR0_SMMUEN;
24932505
} else {
24942506
ret = arm_smmu_update_gbpa(smmu, 0, GBPA_ABORT);
2495-
if (ret) {
2496-
dev_err(smmu->dev, "GBPA not responding to update\n");
2507+
if (ret)
24972508
return ret;
2498-
}
24992509
}
25002510
ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0,
25012511
ARM_SMMU_CR0ACK);

0 commit comments

Comments
 (0)