Dongli Zhang
2022-Jun-09 00:55 UTC
[PATCH RFC v1 0/7] swiotlb: extra 64-bit buffer for dev->dma_io_tlb_mem
Hello, I used to send out a patchset on 64-bit buffer and people thought it was the same as Restricted DMA. However, the 64-bit buffer is still not supported. https://lore.kernel.org/all/20210203233709.19819-1-dongli.zhang at oracle.com/ This RFC is to introduce the extra swiotlb buffer with SWIOTLB_ANY flag, to support 64-bit swiotlb. The core ideas are: 1. Create an extra io_tlb_mem with SWIOTLB_ANY flags. 2. The dev->dma_io_tlb_mem is set to either default or the extra io_tlb_mem, depending on dma mask. Would you please help suggest for below questions in the RFC? - Is it fine to create the extra io_tlb_mem? - Which one is better: to create a separate variable for the extra io_tlb_mem, or make it an array of two io_tlb_mem? - Should I set dev->dma_io_tlb_mem in each driver (e.g., virtio driver as in this patchset)based on the value of min_not_zero(*dev->dma_mask, dev->bus_dma_limit), or at higher level (e.g., post pci driver)? This patchset is to demonstrate that the idea works. Since this is just a RFC, I have only tested virtio-blk on qemu-7.0 by enforcing swiotlb. It is not tested on AMD SEV environment. qemu-system-x86_64 -cpu host -name debug-threads=on \ -smp 8 -m 16G -machine q35,accel=kvm -vnc :5 -hda boot.img \ -kernel mainline-linux/arch/x86_64/boot/bzImage \ -append "root=/dev/sda1 init=/sbin/init text console=ttyS0 loglevel=7 swiotlb=327680,3145728,force" \ -device virtio-blk-pci,id=vblk0,num-queues=8,drive=drive0,disable-legacy=on,iommu_platform=true \ -drive file=test.raw,if=none,id=drive0,cache=none \ -net nic -net user,hostfwd=tcp::5025-:22 -serial stdio The kernel command line "swiotlb=327680,3145728,force" is to allocate 6GB for the extra swiotlb. [ 2.826676] PCI-DMA: Using software bounce buffering for IO (SWIOTLB) [ 2.826693] software IO TLB: default mapped [mem 0x0000000037000000-0x000000005f000000] (640MB) [ 2.826697] software IO TLB: high mapped [mem 0x00000002edc80000-0x000000046dc80000] (6144MB) The highmem swiotlb is being used by virtio-blk. $ cat /sys/kernel/debug/swiotlb/swiotlb-hi/io_tlb_nslabs 3145728 $ cat /sys/kernel/debug/swiotlb/swiotlb-hi/io_tlb_used 8960 Dongli Zhang (7): swiotlb: introduce the highmem swiotlb buffer swiotlb: change the signature of remap function swiotlb-xen: support highmem for xen specific code swiotlb: to implement io_tlb_high_mem swiotlb: add interface to set dev->dma_io_tlb_mem virtio: use io_tlb_high_mem if it is active swiotlb: fix the slot_addr() overflow arch/powerpc/kernel/dma-swiotlb.c | 8 +- arch/x86/include/asm/xen/swiotlb-xen.h | 2 +- arch/x86/kernel/pci-dma.c | 5 +- drivers/virtio/virtio.c | 8 ++ drivers/xen/swiotlb-xen.c | 16 +++- include/linux/swiotlb.h | 14 ++- kernel/dma/swiotlb.c | 136 +++++++++++++++++++++------- 7 files changed, 145 insertions(+), 44 deletions(-) Thank you very much for feedback and suggestion! Dongli Zhang
Dongli Zhang
2022-Jun-09 00:55 UTC
[PATCH RFC v1 1/7] swiotlb: introduce the highmem swiotlb buffer
Currently, the virtio driver is not able to use 4+ GB memory when the swiotlb is enforced, e.g., when amd sev is involved. Fortunately, the SWIOTLB_ANY flag has been introduced since commit 8ba2ed1be90f ("swiotlb: add a SWIOTLB_ANY flag to lift the low memory restriction") to allocate swiotlb buffer from high memory. While the default swiotlb is 'io_tlb_default_mem', the extra 'io_tlb_high_mem' is introduced to allocate with SWIOTLB_ANY flag in the future patches. E.g., the user may configure the extra highmem swiotlb buffer via "swiotlb=327680,4194304" to allocate 8GB memory. In the future, the driver will be able to decide to use whether 'io_tlb_default_mem' or 'io_tlb_high_mem'. The highmem swiotlb is enabled by user if io_tlb_high_mem is set. It can be actively used if swiotlb_high_active() returns true. The kernel command line "swiotlb=32768,3145728,force" is to allocate 64MB for default swiotlb, and 6GB for the extra highmem swiotlb. Cc: Konrad Wilk <konrad.wilk at oracle.com> Cc: Joe Jin <joe.jin at oracle.com> Signed-off-by: Dongli Zhang <dongli.zhang at oracle.com> --- include/linux/swiotlb.h | 2 ++ kernel/dma/swiotlb.c | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index 7ed35dd3de6e..e67e605af2dd 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h @@ -109,6 +109,7 @@ struct io_tlb_mem { } *slots; }; extern struct io_tlb_mem io_tlb_default_mem; +extern struct io_tlb_mem io_tlb_high_mem; static inline bool is_swiotlb_buffer(struct device *dev, phys_addr_t paddr) { @@ -164,6 +165,7 @@ static inline void swiotlb_adjust_size(unsigned long size) } #endif /* CONFIG_SWIOTLB */ +extern bool swiotlb_high_active(void); extern void swiotlb_print_info(void); #ifdef CONFIG_DMA_RESTRICTED_POOL diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index cb50f8d38360..569bc30e7b7a 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -66,10 +66,12 @@ static bool swiotlb_force_bounce; static bool swiotlb_force_disable; struct io_tlb_mem io_tlb_default_mem; +struct io_tlb_mem io_tlb_high_mem; phys_addr_t swiotlb_unencrypted_base; static unsigned long default_nslabs = IO_TLB_DEFAULT_SIZE >> IO_TLB_SHIFT; +static unsigned long high_nslabs; static int __init setup_io_tlb_npages(char *str) @@ -81,6 +83,15 @@ setup_io_tlb_npages(char *str) } if (*str == ',') ++str; + + if (isdigit(*str)) { + /* avoid tail segment of size < IO_TLB_SEGSIZE */ + high_nslabs + ALIGN(simple_strtoul(str, &str, 0), IO_TLB_SEGSIZE); + } + if (*str == ',') + ++str; + if (!strcmp(str, "force")) swiotlb_force_bounce = true; else if (!strcmp(str, "noforce")) @@ -90,6 +101,11 @@ setup_io_tlb_npages(char *str) } early_param("swiotlb", setup_io_tlb_npages); +bool swiotlb_high_active(void) +{ + return high_nslabs && io_tlb_high_mem.nslabs; +} + unsigned int swiotlb_max_segment(void) { if (!io_tlb_default_mem.nslabs) -- 2.17.1
Dongli Zhang
2022-Jun-09 00:55 UTC
[PATCH RFC v1 2/7] swiotlb: change the signature of remap function
Add new argument 'high' to remap function, so that it will be able to remap the swiotlb buffer based on whether the swiotlb is 32-bit or 64-bit. Currently the only remap function is xen_swiotlb_fixup(). Cc: Konrad Wilk <konrad.wilk at oracle.com> Cc: Joe Jin <joe.jin at oracle.com> Signed-off-by: Dongli Zhang <dongli.zhang at oracle.com> --- arch/x86/include/asm/xen/swiotlb-xen.h | 2 +- drivers/xen/swiotlb-xen.c | 2 +- include/linux/swiotlb.h | 4 ++-- kernel/dma/swiotlb.c | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/x86/include/asm/xen/swiotlb-xen.h b/arch/x86/include/asm/xen/swiotlb-xen.h index 77a2d19cc990..a54eae15605e 100644 --- a/arch/x86/include/asm/xen/swiotlb-xen.h +++ b/arch/x86/include/asm/xen/swiotlb-xen.h @@ -8,7 +8,7 @@ extern int pci_xen_swiotlb_init_late(void); static inline int pci_xen_swiotlb_init_late(void) { return -ENXIO; } #endif -int xen_swiotlb_fixup(void *buf, unsigned long nslabs); +int xen_swiotlb_fixup(void *buf, unsigned long nslabs, bool high); int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order, unsigned int address_bits, dma_addr_t *dma_handle); diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 67aa74d20162..339f46e21053 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -104,7 +104,7 @@ static int is_xen_swiotlb_buffer(struct device *dev, dma_addr_t dma_addr) } #ifdef CONFIG_X86 -int xen_swiotlb_fixup(void *buf, unsigned long nslabs) +int xen_swiotlb_fixup(void *buf, unsigned long nslabs, bool high) { int rc; unsigned int order = get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT); diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index e67e605af2dd..e61c074c55eb 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h @@ -36,9 +36,9 @@ struct scatterlist; unsigned long swiotlb_size_or_default(void); void __init swiotlb_init_remap(bool addressing_limit, unsigned int flags, - int (*remap)(void *tlb, unsigned long nslabs)); + int (*remap)(void *tlb, unsigned long nslabs, bool high)); int swiotlb_init_late(size_t size, gfp_t gfp_mask, - int (*remap)(void *tlb, unsigned long nslabs)); + int (*remap)(void *tlb, unsigned long nslabs, bool high)); extern void __init swiotlb_update_mem_attributes(void); phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, phys_addr_t phys, diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index 569bc30e7b7a..7988883ca7f9 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -245,7 +245,7 @@ static void swiotlb_init_io_tlb_mem(struct io_tlb_mem *mem, phys_addr_t start, * structures for the software IO TLB used to implement the DMA API. */ void __init swiotlb_init_remap(bool addressing_limit, unsigned int flags, - int (*remap)(void *tlb, unsigned long nslabs)) + int (*remap)(void *tlb, unsigned long nslabs, bool high)) { struct io_tlb_mem *mem = &io_tlb_default_mem; unsigned long nslabs = default_nslabs; @@ -274,7 +274,7 @@ void __init swiotlb_init_remap(bool addressing_limit, unsigned int flags, return; } - if (remap && remap(tlb, nslabs) < 0) { + if (remap && remap(tlb, nslabs, false) < 0) { memblock_free(tlb, PAGE_ALIGN(bytes)); nslabs = ALIGN(nslabs >> 1, IO_TLB_SEGSIZE); @@ -307,7 +307,7 @@ void __init swiotlb_init(bool addressing_limit, unsigned int flags) * This should be just like above, but with some error catching. */ int swiotlb_init_late(size_t size, gfp_t gfp_mask, - int (*remap)(void *tlb, unsigned long nslabs)) + int (*remap)(void *tlb, unsigned long nslabs, bool high)) { struct io_tlb_mem *mem = &io_tlb_default_mem; unsigned long nslabs = ALIGN(size >> IO_TLB_SHIFT, IO_TLB_SEGSIZE); @@ -337,7 +337,7 @@ int swiotlb_init_late(size_t size, gfp_t gfp_mask, return -ENOMEM; if (remap) - rc = remap(vstart, nslabs); + rc = remap(vstart, nslabs, false); if (rc) { free_pages((unsigned long)vstart, order); -- 2.17.1
Dongli Zhang
2022-Jun-09 00:55 UTC
[PATCH RFC v1 3/7] swiotlb-xen: support highmem for xen specific code
While for most of times the swiotlb-xen relies on the generic swiotlb api to initialize and use swiotlb, this patch is to support highmem swiotlb for swiotlb-xen specific code. E.g., the xen_swiotlb_fixup() may request the hypervisor to provide 64-bit memory pages as swiotlb buffer. Cc: Konrad Wilk <konrad.wilk at oracle.com> Cc: Joe Jin <joe.jin at oracle.com> Signed-off-by: Dongli Zhang <dongli.zhang at oracle.com> --- drivers/xen/swiotlb-xen.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 339f46e21053..d15321e9f9db 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -38,7 +38,8 @@ #include <asm/dma-mapping.h> #include <trace/events/swiotlb.h> -#define MAX_DMA_BITS 32 +#define MAX_DMA32_BITS 32 +#define MAX_DMA64_BITS 64 /* * Quick lookup value of the bus address of the IOTLB. @@ -109,19 +110,25 @@ int xen_swiotlb_fixup(void *buf, unsigned long nslabs, bool high) int rc; unsigned int order = get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT); unsigned int i, dma_bits = order + PAGE_SHIFT; + unsigned int max_dma_bits = MAX_DMA32_BITS; dma_addr_t dma_handle; phys_addr_t p = virt_to_phys(buf); BUILD_BUG_ON(IO_TLB_SEGSIZE & (IO_TLB_SEGSIZE - 1)); BUG_ON(nslabs % IO_TLB_SEGSIZE); + if (high) { + dma_bits = MAX_DMA64_BITS; + max_dma_bits = MAX_DMA64_BITS; + } + i = 0; do { do { rc = xen_create_contiguous_region( p + (i << IO_TLB_SHIFT), order, dma_bits, &dma_handle); - } while (rc && dma_bits++ < MAX_DMA_BITS); + } while (rc && dma_bits++ < max_dma_bits); if (rc) return rc; @@ -381,7 +388,8 @@ xen_swiotlb_sync_sg_for_device(struct device *dev, struct scatterlist *sgl, static int xen_swiotlb_dma_supported(struct device *hwdev, u64 mask) { - return xen_phys_to_dma(hwdev, io_tlb_default_mem.end - 1) <= mask; + return xen_phys_to_dma(hwdev, io_tlb_default_mem.end - 1) <= mask || + xen_phys_to_dma(hwdev, io_tlb_high_mem.end - 1) <= mask; } const struct dma_map_ops xen_swiotlb_dma_ops = { -- 2.17.1
Dongli Zhang
2022-Jun-09 00:55 UTC
[PATCH RFC v1 4/7] swiotlb: to implement io_tlb_high_mem
This patch is to implement the extra 'io_tlb_high_mem'. In the future, the device drivers may choose to use either 'io_tlb_default_mem' or 'io_tlb_high_mem' as dev->dma_io_tlb_mem. The highmem buffer is regarded as active if (high_nslabs && io_tlb_high_mem.nslabs) returns true. Cc: Konrad Wilk <konrad.wilk at oracle.com> Cc: Joe Jin <joe.jin at oracle.com> Signed-off-by: Dongli Zhang <dongli.zhang at oracle.com> --- arch/powerpc/kernel/dma-swiotlb.c | 8 ++- arch/x86/kernel/pci-dma.c | 5 +- include/linux/swiotlb.h | 2 +- kernel/dma/swiotlb.c | 103 +++++++++++++++++++++--------- 4 files changed, 84 insertions(+), 34 deletions(-) diff --git a/arch/powerpc/kernel/dma-swiotlb.c b/arch/powerpc/kernel/dma-swiotlb.c index ba256c37bcc0..f18694881264 100644 --- a/arch/powerpc/kernel/dma-swiotlb.c +++ b/arch/powerpc/kernel/dma-swiotlb.c @@ -20,9 +20,11 @@ void __init swiotlb_detect_4g(void) static int __init check_swiotlb_enabled(void) { - if (ppc_swiotlb_enable) - swiotlb_print_info(); - else + if (ppc_swiotlb_enable) { + swiotlb_print_info(false); + if (swiotlb_high_active()) + swiotlb_print_info(true); + } else swiotlb_exit(); return 0; diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 30bbe4abb5d6..1504b349b312 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -196,7 +196,10 @@ static int __init pci_iommu_init(void) /* An IOMMU turned us off. */ if (x86_swiotlb_enable) { pr_info("PCI-DMA: Using software bounce buffering for IO (SWIOTLB)\n"); - swiotlb_print_info(); + + swiotlb_print_info(false); + if (swiotlb_high_active()) + swiotlb_print_info(true); } else { swiotlb_exit(); } diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index e61c074c55eb..8196bf961aab 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h @@ -166,7 +166,7 @@ static inline void swiotlb_adjust_size(unsigned long size) #endif /* CONFIG_SWIOTLB */ extern bool swiotlb_high_active(void); -extern void swiotlb_print_info(void); +extern void swiotlb_print_info(bool high); #ifdef CONFIG_DMA_RESTRICTED_POOL struct page *swiotlb_alloc(struct device *dev, size_t size); diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index 7988883ca7f9..ff82b281ce01 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -101,6 +101,21 @@ setup_io_tlb_npages(char *str) } early_param("swiotlb", setup_io_tlb_npages); +static struct io_tlb_mem *io_tlb_mem_get(bool high) +{ + return high ? &io_tlb_high_mem : &io_tlb_default_mem; +} + +static unsigned long nslabs_get(bool high) +{ + return high ? high_nslabs : default_nslabs; +} + +static char *swiotlb_name_get(bool high) +{ + return high ? "high" : "default"; +} + bool swiotlb_high_active(void) { return high_nslabs && io_tlb_high_mem.nslabs; @@ -133,17 +148,18 @@ void __init swiotlb_adjust_size(unsigned long size) pr_info("SWIOTLB bounce buffer size adjusted to %luMB", size >> 20); } -void swiotlb_print_info(void) +void swiotlb_print_info(bool high) { - struct io_tlb_mem *mem = &io_tlb_default_mem; + struct io_tlb_mem *mem = io_tlb_mem_get(high); if (!mem->nslabs) { pr_warn("No low mem\n"); return; } - pr_info("mapped [mem %pa-%pa] (%luMB)\n", &mem->start, &mem->end, - (mem->nslabs << IO_TLB_SHIFT) >> 20); + pr_info("%s mapped [mem %pa-%pa] (%luMB)\n", + swiotlb_name_get(high), &mem->start, &mem->end, + (mem->nslabs << IO_TLB_SHIFT) >> 20); } static inline unsigned long io_tlb_offset(unsigned long val) @@ -184,15 +200,9 @@ static void *swiotlb_mem_remap(struct io_tlb_mem *mem, unsigned long bytes) } #endif -/* - * Early SWIOTLB allocation may be too early to allow an architecture to - * perform the desired operations. This function allows the architecture to - * call SWIOTLB when the operations are possible. It needs to be called - * before the SWIOTLB memory is used. - */ -void __init swiotlb_update_mem_attributes(void) +static void __init __swiotlb_update_mem_attributes(bool high) { - struct io_tlb_mem *mem = &io_tlb_default_mem; + struct io_tlb_mem *mem = io_tlb_mem_get(high); void *vaddr; unsigned long bytes; @@ -207,6 +217,19 @@ void __init swiotlb_update_mem_attributes(void) mem->vaddr = vaddr; } +/* + * Early SWIOTLB allocation may be too early to allow an architecture to + * perform the desired operations. This function allows the architecture to + * call SWIOTLB when the operations are possible. It needs to be called + * before the SWIOTLB memory is used. + */ +void __init swiotlb_update_mem_attributes(void) +{ + __swiotlb_update_mem_attributes(false); + if (swiotlb_high_active()) + __swiotlb_update_mem_attributes(true); +} + static void swiotlb_init_io_tlb_mem(struct io_tlb_mem *mem, phys_addr_t start, unsigned long nslabs, unsigned int flags, bool late_alloc) { @@ -240,15 +263,13 @@ static void swiotlb_init_io_tlb_mem(struct io_tlb_mem *mem, phys_addr_t start, return; } -/* - * Statically reserve bounce buffer space and initialize bounce buffer data - * structures for the software IO TLB used to implement the DMA API. - */ -void __init swiotlb_init_remap(bool addressing_limit, unsigned int flags, - int (*remap)(void *tlb, unsigned long nslabs, bool high)) +static void __init +__swiotlb_init_remap(bool addressing_limit, unsigned int flags, + int (*remap)(void *tlb, unsigned long nslabs, bool high), + bool high) { - struct io_tlb_mem *mem = &io_tlb_default_mem; - unsigned long nslabs = default_nslabs; + struct io_tlb_mem *mem = io_tlb_mem_get(high); + unsigned long nslabs = nslabs_get(high); size_t alloc_size; size_t bytes; void *tlb; @@ -274,7 +295,7 @@ void __init swiotlb_init_remap(bool addressing_limit, unsigned int flags, return; } - if (remap && remap(tlb, nslabs, false) < 0) { + if (remap && remap(tlb, nslabs, high) < 0) { memblock_free(tlb, PAGE_ALIGN(bytes)); nslabs = ALIGN(nslabs >> 1, IO_TLB_SEGSIZE); @@ -293,7 +314,20 @@ void __init swiotlb_init_remap(bool addressing_limit, unsigned int flags, swiotlb_init_io_tlb_mem(mem, __pa(tlb), nslabs, flags, false); if (flags & SWIOTLB_VERBOSE) - swiotlb_print_info(); + swiotlb_print_info(high); +} + +/* + * Statically reserve bounce buffer space and initialize bounce buffer data + * structures for the software IO TLB used to implement the DMA API. + */ +void __init swiotlb_init_remap(bool addressing_limit, unsigned int flags, + int (*remap)(void *tlb, unsigned long nslabs, bool high)) +{ + __swiotlb_init_remap(addressing_limit, flags, remap, false); + if (high_nslabs) + __swiotlb_init_remap(addressing_limit, flags | SWIOTLB_ANY, + remap, true); } void __init swiotlb_init(bool addressing_limit, unsigned int flags) @@ -364,23 +398,20 @@ int swiotlb_init_late(size_t size, gfp_t gfp_mask, (nslabs << IO_TLB_SHIFT) >> PAGE_SHIFT); swiotlb_init_io_tlb_mem(mem, virt_to_phys(vstart), nslabs, 0, true); - swiotlb_print_info(); + swiotlb_print_info(false); return 0; } -void __init swiotlb_exit(void) +static void __init __swiotlb_exit(bool high) { - struct io_tlb_mem *mem = &io_tlb_default_mem; + struct io_tlb_mem *mem = io_tlb_mem_get(high); unsigned long tbl_vaddr; size_t tbl_size, slots_size; - if (swiotlb_force_bounce) - return; - if (!mem->nslabs) return; - pr_info("tearing down default memory pool\n"); + pr_info("tearing down %s memory pool\n", swiotlb_name_get(high)); tbl_vaddr = (unsigned long)phys_to_virt(mem->start); tbl_size = PAGE_ALIGN(mem->end - mem->start); slots_size = PAGE_ALIGN(array_size(sizeof(*mem->slots), mem->nslabs)); @@ -397,6 +428,16 @@ void __init swiotlb_exit(void) memset(mem, 0, sizeof(*mem)); } +void __init swiotlb_exit(void) +{ + if (swiotlb_force_bounce) + return; + + __swiotlb_exit(false); + if (swiotlb_high_active()) + __swiotlb_exit(true); +} + /* * Return the offset into a iotlb slot required to keep the device happy. */ @@ -786,6 +827,10 @@ static void swiotlb_create_debugfs_files(struct io_tlb_mem *mem, static int __init __maybe_unused swiotlb_create_default_debugfs(void) { swiotlb_create_debugfs_files(&io_tlb_default_mem, "swiotlb"); + + if (swiotlb_high_active()) + swiotlb_create_debugfs_files(&io_tlb_high_mem, "swiotlb-hi"); + return 0; } -- 2.17.1
Dongli Zhang
2022-Jun-09 00:55 UTC
[PATCH RFC v1 5/7] swiotlb: add interface to set dev->dma_io_tlb_mem
The interface re-configures dev->dma_io_tlb_mem conditionally, if the 'io_tlb_high_mem' is active. Cc: Konrad Wilk <konrad.wilk at oracle.com> Cc: Joe Jin <joe.jin at oracle.com> Signed-off-by: Dongli Zhang <dongli.zhang at oracle.com> --- include/linux/swiotlb.h | 6 ++++++ kernel/dma/swiotlb.c | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index 8196bf961aab..78217d8bbee2 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h @@ -131,6 +131,7 @@ unsigned int swiotlb_max_segment(void); size_t swiotlb_max_mapping_size(struct device *dev); bool is_swiotlb_active(struct device *dev); void __init swiotlb_adjust_size(unsigned long size); +bool swiotlb_use_high(struct device *dev); #else static inline void swiotlb_init(bool addressing_limited, unsigned int flags) { @@ -163,6 +164,11 @@ static inline bool is_swiotlb_active(struct device *dev) static inline void swiotlb_adjust_size(unsigned long size) { } + +static bool swiotlb_use_high(struct device *dev); +{ + return false; +} #endif /* CONFIG_SWIOTLB */ extern bool swiotlb_high_active(void); diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index ff82b281ce01..0dcdd25ea95d 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -121,6 +121,16 @@ bool swiotlb_high_active(void) return high_nslabs && io_tlb_high_mem.nslabs; } +bool swiotlb_use_high(struct device *dev) +{ + if (!swiotlb_high_active()) + return false; + + dev->dma_io_tlb_mem = &io_tlb_high_mem; + return true; +} +EXPORT_SYMBOL_GPL(swiotlb_use_high); + unsigned int swiotlb_max_segment(void) { if (!io_tlb_default_mem.nslabs) -- 2.17.1
Dongli Zhang
2022-Jun-09 00:55 UTC
[PATCH RFC v1 6/7] virtio: use io_tlb_high_mem if it is active
When the swiotlb is enforced (e.g., when amd sev is involved), the virito driver will not be able to use 4+ GB memory. Therefore, the virtio driver uses 'io_tlb_high_mem' as swiotlb. Cc: Konrad Wilk <konrad.wilk at oracle.com> Cc: Joe Jin <joe.jin at oracle.com> Signed-off-by: Dongli Zhang <dongli.zhang at oracle.com> --- drivers/virtio/virtio.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index ef04a96942bf..d9ebe3940e2d 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -5,6 +5,8 @@ #include <linux/module.h> #include <linux/idr.h> #include <linux/of.h> +#include <linux/swiotlb.h> +#include <linux/dma-mapping.h> #include <uapi/linux/virtio_ids.h> /* Unique numbering for virtio devices. */ @@ -241,6 +243,12 @@ static int virtio_dev_probe(struct device *_d) u64 device_features; u64 driver_features; u64 driver_features_legacy; + struct device *parent = dev->dev.parent; + u64 dma_mask = min_not_zero(*parent->dma_mask, + parent->bus_dma_limit); + + if (dma_mask == DMA_BIT_MASK(64)) + swiotlb_use_high(parent); /* We have a driver! */ virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER); -- 2.17.1
Dongli Zhang
2022-Jun-09 00:55 UTC
[PATCH RFC v1 7/7] swiotlb: fix the slot_addr() overflow
Since the type of swiotlb slot index is a signed integer, the "((idx) << IO_TLB_SHIFT)" will returns incorrect value. As a result, the slot_addr() returns a value which is smaller than the expected one. E.g., the 'tlb_addr' generated in swiotlb_tbl_map_single() may return a value smaller than the expected one. As a result, the swiotlb_bounce() will access a wrong swiotlb slot. Cc: Konrad Wilk <konrad.wilk at oracle.com> Cc: Joe Jin <joe.jin at oracle.com> Signed-off-by: Dongli Zhang <dongli.zhang at oracle.com> --- kernel/dma/swiotlb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index 0dcdd25ea95d..c64e557de55c 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -531,7 +531,8 @@ static void swiotlb_bounce(struct device *dev, phys_addr_t tlb_addr, size_t size } } -#define slot_addr(start, idx) ((start) + ((idx) << IO_TLB_SHIFT)) +#define slot_addr(start, idx) ((start) + \ + (((unsigned long)idx) << IO_TLB_SHIFT)) /* * Carefully handle integer overflow which can occur when boundary_mask == ~0UL. -- 2.17.1