Re: [RFC PATCH] x86/pci-dma: add "any" keyword to swiotlb= kernel parameter
From: Aakarsh Jain
Date: Wed Jul 08 2026 - 08:03:08 EST
On 7/8/2026 5:12 PM, Aakarsh Jain wrote:
CoCo guests (AMD SEV-SNP, Intel TDX) require large swiotlb pools for
streaming DMA workloads such as high-speed NIC and AI accelerator
inference. The existing swiotlb pool allocator restricts placement to
low memory (below 4GB by default), capping usable pool size at ~1GB even
when a larger pool is requested via swiotlb=<nslabs>.
The SWIOTLB_ANY flag already exists to lift this restriction, and
swiotlb_init_remap() already handles it correctly via the flags
parameter (see CONFIG_SWIOTLB_DYNAMIC path: io_tlb_default_mem.phys_limit
is set to virt_to_phys(high_memory-1) when SWIOTLB_ANY is set).
However, there is no way to set SWIOTLB_ANY from the command line. The
only existing mechanism was via arch-specific code (e.g. powerpc SVM sets
SWIOTLB_ANY in pci_iommu_init). x86 CoCo guests have no such path.
After Aneesh series ("dma-mapping: Track shared DMA state through
direct, pool and swiotlb paths", https://patchwork.kernel.org/project/linux-arm-kernel/cover/20260701054926.825925-1-aneesh.kumar@xxxxxxxxxx/)
removes SWIOTLB_FORCE, x86 pci_swiotlb_detect() leaves x86_swiotlb_flags = 0 for
CoCo guests. The pool falls back to low memory and caps at ~1GB:
Without "any": pool at 0x35a9c000 (~900MB, below 4GB boundary)
With "any": pool at 0x1df9c00000 (~120GB, anywhere in RAM)
[Tested on AMD SEV-SNP guest, swiotlb=4194304]
Add "any" as a new keyword to the swiotlb= kernel parameter. This is an
explicit, opt-in mechanism that sets SWIOTLB_ANY for the default pool at
boot time, without touching any arch-specific code.
Devices with 32-bit DMA masks are not affected, they still use the normal
low-memory bounce buffer path. The "any" option is only meaningful for
workloads where all active DMA devices have 64-bit masks.
Signed-off-by: Aakarsh Jain <aakarsh.jain@xxxxxxxxxxxxxxxx>
---
Documentation/admin-guide/kernel-parameters.txt | 5 ++++-
kernel/dma/swiotlb.c | 5 +++++
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index b5493a7f8f22..8a1fccbd9b25 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -7477,7 +7477,7 @@ Kernel parameters
Execution Facility on pSeries.
swiotlb= [ARM,PPC,MIPS,X86,S390,EARLY]
- Format: { <int> [,<int>] | force | noforce }
+ Format: { <int> [,<int>] | force | noforce | any}
<int> -- Number of I/O TLB slabs
<int> -- Second integer after comma. Number of swiotlb
areas with their own lock. Will be rounded up
@@ -7485,6 +7485,9 @@ Kernel parameters
force -- force using of bounce buffers even if they
wouldn't be automatically used by the kernel
noforce -- Never use bounce buffers (for debugging)
+ any -- Allow the swiotlb pool to be placed anywhere in
+ system RAM, lifting the default low-memory (4GB)
+ restriction.
switches= [HW,M68k,EARLY]
diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c
index 1abd3e6146f4..34773ae7c770 100644
--- a/kernel/dma/swiotlb.c
+++ b/kernel/dma/swiotlb.c
@@ -80,6 +80,7 @@ struct io_tlb_slot {
static bool swiotlb_force_bounce;
static bool swiotlb_force_disable;
+static unsigned int swiotlb_param_flags __initdata;
#ifdef CONFIG_SWIOTLB_DYNAMIC
@@ -198,6 +199,8 @@ setup_io_tlb_npages(char *str)
swiotlb_force_bounce = true;
else if (!strcmp(str, "noforce"))
swiotlb_force_disable = true;
+ else if (!strcmp(str, "any"))
+ swiotlb_param_flags |= SWIOTLB_ANY;
return 0;
}
@@ -445,6 +448,8 @@ int swiotlb_init_late(size_t size, gfp_t gfp_mask,
io_tlb_default_mem.force_bounce = swiotlb_force_bounce;
+ flags |= swiotlb_param_flags;
+
#ifdef CONFIG_SWIOTLB_DYNAMIC
if (!remap)
io_tlb_default_mem.can_grow = true;
One correction to the commit message:
The testing was performed with:
swiotlb=4194304,any
and not:
swiotlb=4194304
The larger swiotlb pool allocation above the 4GB boundary was observed
with the "any" option enabled.
From kernel dmesg logs:
root@ubuntu:/home/ubuntu# dmesg | grep -i sev
[ 21.191917] Memory Encryption Features active: AMD SEV SEV-ES SEV-SNP
[ 21.192883] SEV: Status: SEV SEV-ES SEV-SNP
[ 21.401897] SEV: APIC: wakeup_secondary_cpu() replaced with wakeup_cpu_via_vmgexit()
[ 22.117267] SEV: Using SNP CPUID table, 28 entries present.
[ 22.117884] SEV: SNP running at VMPL0.
[ 24.164260] SEV: SNP guest platform devices initialized.
[ 28.815142] systemd[1]: Detected confidential virtualization sev-snp.
[ 30.063831] sev-guest sev-guest: Initialized SEV guest driver (using VMPCK0 communication key)
root@ubuntu:/home/ubuntu# dmesg | grep -i "IO TLB"
[ 6.743607] software IO TLB: area num 4.
[ 24.164169] software IO TLB: mapped [mem 0x0000001df9c00000-0x0000001ff9c00000] (8192MB)
[ 24.331266] software IO TLB: Memory encryption is active and system is using DMA bounce buffers
Thanks,
Aakarsh