[PATCH v5 2/2] iommu/arm-smmu-v3: Default queue depths to one page in a kdump kernel

From: Kiryl Shutsemau (Meta)

Date: Mon Sep 07 2026 - 06:18:42 EST


All three queues are sized from the maxima the hardware advertises in IDR1
and allocated at probe, up to 4 MB each on a 4K-page kernel. The capture
kernel already disables two of them: arm_smmu_device_reset() drops
CR0_EVTQEN and CR0_PRIQEN. It still allocates both at full size.

A kdump capture kernel runs from a small crashkernel reservation, and every
SMMUv3 instance pays that cost again, up to 12 MB apiece. It goes to queues
that either serve the handful of devices used to save the dump or are
switched off outright, and it is memory the dump itself needs.

Default all three depths to one page worth of entries when
is_kdump_kernel(). The queues carry commands and fault records rather than
DMA data, so dump throughput is unaffected. A shallower command queue only
bounds how many commands may be in flight before a sync, which does not
matter for the few devices that save the dump.

An explicit cmdq_max_entries still wins, so a capture kernel that wants a
deeper command queue can ask for one on the command line.

Suggested-by: Kyle McMartin <jkkm@xxxxxxxx>
Signed-off-by: Kiryl Shutsemau (Meta) <kas@xxxxxxxxxx>
Assisted-by: Claude-Code:claude-opus-5
---
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 37 +++++++++++++++++----
1 file changed, 30 insertions(+), 7 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 4550b1105e9c..67dca0cb487b 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -4424,6 +4424,9 @@ static struct iommu_dirty_ops arm_smmu_dirty_ops = {
* @ent_sz_shift: log2 of the queue entry size in bytes
* @entries: number of entries to cap the queue at, or zero for the default
*
+ * The default is @ceiling, except in a kdump capture kernel, which defaults to
+ * one page worth of entries.
+ *
* @entries is rounded down to a power of two and floored at one page, because
* coherent DMA is page granular: a shallower queue occupies the same memory as
* one that fills the page, and arm_smmu_init_one_queue() stops shrinking at a
@@ -4433,11 +4436,32 @@ static u32 arm_smmu_queue_max_n_shift(u32 ceiling, u32 ent_sz_shift,
u32 entries)
{
u32 floor = PAGE_SHIFT - ent_sz_shift;
+ u32 new_ceiling;

- if (!entries)
+ if (entries)
+ new_ceiling = max(ilog2(entries), floor);
+ else if (is_kdump_kernel())
+ new_ceiling = floor;
+ else
return ceiling;

- return min(ceiling, max(ilog2(entries), floor));
+ return min(ceiling, new_ceiling);
+}
+
+static inline u32 arm_smmu_evtq_max_n_shift(u32 ceiling)
+{
+ /* Capped to ensure natural alignment */
+ ceiling = min(EVTQ_MAX_SZ_SHIFT, ceiling);
+
+ return arm_smmu_queue_max_n_shift(ceiling, EVTQ_ENT_SZ_SHIFT, 0);
+}
+
+static inline u32 arm_smmu_priq_max_n_shift(u32 ceiling)
+{
+ /* Capped to ensure natural alignment */
+ ceiling = min(PRIQ_MAX_SZ_SHIFT, ceiling);
+
+ return arm_smmu_queue_max_n_shift(ceiling, PRIQ_ENT_SZ_SHIFT, 0);
}

/*
@@ -5196,7 +5220,6 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
if (reg & IDR1_ATTR_TYPES_OVR)
smmu->features |= ARM_SMMU_FEAT_ATTR_TYPES_OVR;

- /* Queue sizes, capped to ensure natural alignment */
smmu->cmdq.q.llq.max_n_shift =
arm_smmu_cmdq_max_n_shift(FIELD_GET(IDR1_CMDQS, reg));
if (smmu->cmdq.q.llq.max_n_shift <= ilog2(CMDQ_BATCH_ENTRIES)) {
@@ -5211,10 +5234,10 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
return -ENXIO;
}

- smmu->evtq.q.llq.max_n_shift = min_t(u32, EVTQ_MAX_SZ_SHIFT,
- FIELD_GET(IDR1_EVTQS, reg));
- smmu->priq.q.llq.max_n_shift = min_t(u32, PRIQ_MAX_SZ_SHIFT,
- FIELD_GET(IDR1_PRIQS, reg));
+ smmu->evtq.q.llq.max_n_shift =
+ arm_smmu_evtq_max_n_shift(FIELD_GET(IDR1_EVTQS, reg));
+ smmu->priq.q.llq.max_n_shift =
+ arm_smmu_priq_max_n_shift(FIELD_GET(IDR1_PRIQS, reg));

/* SID/SSID sizes */
smmu->ssid_bits = FIELD_GET(IDR1_SSIDSIZE, reg);
--
2.54.0