Documentation/core-api/dma-api.rst | 4 +- Documentation/core-api/dma-attributes.rst | 7 ++ arch/powerpc/kernel/dma-iommu.c | 4 +- block/blk-mq-dma.c | 15 ++- drivers/iommu/dma-iommu.c | 69 +++++++------ drivers/nvme/host/pci.c | 18 +++- drivers/virtio/virtio_ring.c | 4 +- drivers/xen/swiotlb-xen.c | 21 +++- include/linux/blk-mq-dma.h | 6 +- include/linux/blk_types.h | 2 + include/linux/dma-direct.h | 2 - include/linux/dma-map-ops.h | 8 +- include/linux/dma-mapping.h | 27 +++++ include/linux/iommu-dma.h | 11 +-- include/linux/kmsan.h | 12 ++- include/trace/events/dma.h | 9 +- kernel/dma/debug.c | 71 ++++--------- kernel/dma/debug.h | 37 ++----- kernel/dma/direct.c | 22 +---- kernel/dma/direct.h | 50 ++++++---- kernel/dma/mapping.c | 115 +++++++++++++--------- kernel/dma/ops_helpers.c | 6 +- mm/hmm.c | 19 ++-- mm/kmsan/hooks.c | 36 +++++-- rust/kernel/dma.rs | 3 + tools/virtio/linux/kmsan.h | 2 +- 26 files changed, 320 insertions(+), 260 deletions(-)
Changelog: v1: * Added new DMA_ATTR_MMIO attribute to indicate PCI_P2PDMA_MAP_THRU_HOST_BRIDGE path. * Rewrote dma_map_* functions to use thus new attribute v0: https://lore.kernel.org/all/cover.1750854543.git.leon@kernel.org/ ------------------------------------------------------------------------ This series refactors the DMA mapping to use physical addresses as the primary interface instead of page+offset parameters. This change aligns the DMA API with the underlying hardware reality where DMA operations work with physical addresses, not page structures. The series maintains export symbol backward compatibility by keeping the old page-based API as wrapper functions around the new physical address-based implementations. Thanks Leon Romanovsky (16): dma-mapping: introduce new DMA attribute to indicate MMIO memory iommu/dma: handle MMIO path in dma_iova_link dma-debug: refactor to use physical addresses for page mapping dma-mapping: rename trace_dma_*map_page to trace_dma_*map_phys iommu/dma: rename iommu_dma_*map_page to iommu_dma_*map_phys iommu/dma: extend iommu_dma_*map_phys API to handle MMIO memory dma-mapping: convert dma_direct_*map_page to be phys_addr_t based kmsan: convert kmsan_handle_dma to use physical addresses dma-mapping: handle MMIO flow in dma_map|unmap_page xen: swiotlb: Open code map_resource callback dma-mapping: export new dma_*map_phys() interface mm/hmm: migrate to physical address-based DMA mapping API mm/hmm: properly take MMIO path block-dma: migrate to dma_map_phys instead of map_page block-dma: properly take MMIO path nvme-pci: unmap MMIO pages with appropriate interface Documentation/core-api/dma-api.rst | 4 +- Documentation/core-api/dma-attributes.rst | 7 ++ arch/powerpc/kernel/dma-iommu.c | 4 +- block/blk-mq-dma.c | 15 ++- drivers/iommu/dma-iommu.c | 69 +++++++------ drivers/nvme/host/pci.c | 18 +++- drivers/virtio/virtio_ring.c | 4 +- drivers/xen/swiotlb-xen.c | 21 +++- include/linux/blk-mq-dma.h | 6 +- include/linux/blk_types.h | 2 + include/linux/dma-direct.h | 2 - include/linux/dma-map-ops.h | 8 +- include/linux/dma-mapping.h | 27 +++++ include/linux/iommu-dma.h | 11 +-- include/linux/kmsan.h | 12 ++- include/trace/events/dma.h | 9 +- kernel/dma/debug.c | 71 ++++--------- kernel/dma/debug.h | 37 ++----- kernel/dma/direct.c | 22 +---- kernel/dma/direct.h | 50 ++++++---- kernel/dma/mapping.c | 115 +++++++++++++--------- kernel/dma/ops_helpers.c | 6 +- mm/hmm.c | 19 ++-- mm/kmsan/hooks.c | 36 +++++-- rust/kernel/dma.rs | 3 + tools/virtio/linux/kmsan.h | 2 +- 26 files changed, 320 insertions(+), 260 deletions(-) -- 2.50.1
On Mon, Aug 04, 2025 at 03:42:34PM +0300, Leon Romanovsky wrote: > Changelog: > v1: > * Added new DMA_ATTR_MMIO attribute to indicate > PCI_P2PDMA_MAP_THRU_HOST_BRIDGE path. > * Rewrote dma_map_* functions to use thus new attribute > v0: https://lore.kernel.org/all/cover.1750854543.git.leon@kernel.org/ > ------------------------------------------------------------------------ > > This series refactors the DMA mapping to use physical addresses > as the primary interface instead of page+offset parameters. This > change aligns the DMA API with the underlying hardware reality where > DMA operations work with physical addresses, not page structures. Lets elaborate this as Robin asked: This series refactors the DMA mapping API to provide a phys_addr_t based, and struct-page free, external API that can handle all the mapping cases we want in modern systems: - struct page based cachable DRAM - struct page MEMORY_DEVICE_PCI_P2PDMA PCI peer to peer non-cachable MMIO - struct page-less PCI peer to peer non-cachable MMIO - struct page-less "resource" MMIO Overall this gets much closer to Matthew's long term wish for struct-pageless IO to cachable DRAM. The remaining primary work would be in the mm side to allow kmap_local_pfn()/phys_to_virt() to work on phys_addr_t without a struct page. The general design is to remove struct page usage entirely from the DMA API inner layers. For flows that need to have a KVA for the physical address they can use kmap_local_pfn() or phys_to_virt(). This isolates the struct page requirements to MM code only. Long term all removals of struct page usage are supporting Matthew's memdesc project which seeks to substantially transform how struct page works. Instead make the DMA API internals work on phys_addr_t. Internally there are still dedicated 'page' and 'resource' flows, except they are now distinguished by a new DMA_ATTR_MMIO instead of by callchain. Both flows use the same phys_addr_t. When DMA_ATTR_MMIO is specified things work similar to the existing 'resource' flow. kmap_local_pfn(), phys_to_virt(), phys_to_page(), pfn_valid(), etc are never called on the phys_addr_t. This requires rejecting any configuration that would need swiotlb. CPU cache flushing is not required, and avoided, as ATTR_MMIO also indicates the address have no cachable mappings. This effectively removes any DMA API side requirement to have struct page when DMA_ATTR_MMIO is used. In the !DMA_ATTR_MMIO mode things work similarly to the 'page' flow, except on the common path of no cache flush, no swiotlb it never touches a struct page. When cache flushing or swiotlb copying kmap_local_pfn()/phys_to_virt() are used to get a KVA for CPU usage. This was already the case on the unmap side, now the map side is symmetric. Callers are adjusted to set DMA_ATTR_MMIO. Existing 'resource' users must set it. The existing struct page based MEMORY_DEVICE_PCI_P2PDMA path must also set it. This corrects some existing bugs where iommu mappings for P2P MMIO were improperly marked IOMMU_CACHE. Since ATTR_MMIO is made to work with all the existing DMA map entry points, particularly dma_iova_link(), this finally allows a way to use the new DMA API to map PCI P2P MMIO without creating struct page. The VFIO DMABUF series demonstrates how this works. This is intended to replace the incorrect driver use of dma_map_resource() on PCI BAR addresses. This series does the core code and modern flows. A followup series will give the same treatement to the legacy dma_ops implementation. Jason
On 07.08.2025 16:19, Jason Gunthorpe wrote: > On Mon, Aug 04, 2025 at 03:42:34PM +0300, Leon Romanovsky wrote: >> Changelog: >> v1: >> * Added new DMA_ATTR_MMIO attribute to indicate >> PCI_P2PDMA_MAP_THRU_HOST_BRIDGE path. >> * Rewrote dma_map_* functions to use thus new attribute >> v0: https://lore.kernel.org/all/cover.1750854543.git.leon@kernel.org/ >> ------------------------------------------------------------------------ >> >> This series refactors the DMA mapping to use physical addresses >> as the primary interface instead of page+offset parameters. This >> change aligns the DMA API with the underlying hardware reality where >> DMA operations work with physical addresses, not page structures. > Lets elaborate this as Robin asked: > > This series refactors the DMA mapping API to provide a phys_addr_t > based, and struct-page free, external API that can handle all the > mapping cases we want in modern systems: > > - struct page based cachable DRAM > - struct page MEMORY_DEVICE_PCI_P2PDMA PCI peer to peer non-cachable MMIO > - struct page-less PCI peer to peer non-cachable MMIO > - struct page-less "resource" MMIO > > Overall this gets much closer to Matthew's long term wish for > struct-pageless IO to cachable DRAM. The remaining primary work would > be in the mm side to allow kmap_local_pfn()/phys_to_virt() to work on > phys_addr_t without a struct page. > > The general design is to remove struct page usage entirely from the > DMA API inner layers. For flows that need to have a KVA for the > physical address they can use kmap_local_pfn() or phys_to_virt(). This > isolates the struct page requirements to MM code only. Long term all > removals of struct page usage are supporting Matthew's memdesc > project which seeks to substantially transform how struct page works. > > Instead make the DMA API internals work on phys_addr_t. Internally > there are still dedicated 'page' and 'resource' flows, except they are > now distinguished by a new DMA_ATTR_MMIO instead of by callchain. Both > flows use the same phys_addr_t. > > When DMA_ATTR_MMIO is specified things work similar to the existing > 'resource' flow. kmap_local_pfn(), phys_to_virt(), phys_to_page(), > pfn_valid(), etc are never called on the phys_addr_t. This requires > rejecting any configuration that would need swiotlb. CPU cache > flushing is not required, and avoided, as ATTR_MMIO also indicates the > address have no cachable mappings. This effectively removes any > DMA API side requirement to have struct page when DMA_ATTR_MMIO is > used. > > In the !DMA_ATTR_MMIO mode things work similarly to the 'page' flow, > except on the common path of no cache flush, no swiotlb it never > touches a struct page. When cache flushing or swiotlb copying > kmap_local_pfn()/phys_to_virt() are used to get a KVA for CPU > usage. This was already the case on the unmap side, now the map side > is symmetric. > > Callers are adjusted to set DMA_ATTR_MMIO. Existing 'resource' users > must set it. The existing struct page based MEMORY_DEVICE_PCI_P2PDMA > path must also set it. This corrects some existing bugs where iommu > mappings for P2P MMIO were improperly marked IOMMU_CACHE. > > Since ATTR_MMIO is made to work with all the existing DMA map entry > points, particularly dma_iova_link(), this finally allows a way to use > the new DMA API to map PCI P2P MMIO without creating struct page. The > VFIO DMABUF series demonstrates how this works. This is intended to > replace the incorrect driver use of dma_map_resource() on PCI BAR > addresses. > > This series does the core code and modern flows. A followup series > will give the same treatement to the legacy dma_ops implementation. Thanks for the elaborate description, that's something that was missing in the previous attempt. I read again all the previous discussion and this explanation and there are still two things that imho needs more clarification. First - basing the API on the phys_addr_t. Page based API had the advantage that it was really hard to abuse it and call for something that is not 'a normal RAM'. I initially though that phys_addr_t based API will somehow simplify arch specific implementation, as some of them indeed rely on phys_addr_t internally, but I missed other things pointed by Robin. Do we have here any alternative? Second - making dma_map_phys() a single API to handle all cases. Do we really need such single function to handle all cases? To handle P2P case, the caller already must pass DMA_ATTR_MMIO, so it must somehow keep such information internally. Cannot it just call existing dma_map_resource(), so there will be clear distinction between these 2 cases (DMA to RAM and P2P DMA)? Do we need additional check for DMA_ATTR_MMIO for every typical DMA user? I know that branching is cheap, but this will probably increase code size for most of the typical users for no reason. Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland
On Fri, Aug 08, 2025 at 08:51:08PM +0200, Marek Szyprowski wrote: > First - basing the API on the phys_addr_t. > > Page based API had the advantage that it was really hard to abuse it and > call for something that is not 'a normal RAM'. This is not true anymore. Today we have ZONE_DEVICE as a struct page type with a whole bunch of non-dram sub-types: enum memory_type { /* 0 is reserved to catch uninitialized type fields */ MEMORY_DEVICE_PRIVATE = 1, MEMORY_DEVICE_COHERENT, MEMORY_DEVICE_FS_DAX, MEMORY_DEVICE_GENERIC, MEMORY_DEVICE_PCI_P2PDMA, }; Few of which are kmappable/page_to_virtable() in a way that is useful for the DMA API. DMA API sort of ignores all of this and relies on the caller to not pass in an incorrect struct page. eg we rely on things like the block stack to do the right stuff when a MEMORY_DEVICE_PCI_P2PDMA is present in a bio_vec. Which is not really fundamentally different from just using phys_addr_t in the first place. Sure, this was a stronger argument when this stuff was originally written, before ZONE_DEVICE was invented. > I initially though that phys_addr_t based API will somehow simplify > arch specific implementation, as some of them indeed rely on > phys_addr_t internally, but I missed other things pointed by > Robin. Do we have here any alternative? I think it is less of a code simplification, more as a reduction in conceptual load. When we can say directly there is no struct page type anyhwere in the DMA API layers then we only have to reason about kmap/phys_to_virt compatibly. This is also a weaker overall requirement than needing an actual struct page which allows optimizing other parts of the kernel. Like we aren't forced to create MEMORY_DEVICE_PCI_P2PDMA stuct pages just to use the dma api. Again, any place in the kernel we can get rid of struct page the smoother the road will be for the MM side struct page restructuring. For example one of the bigger eventual goes here is to make a bio_vec store phys_addr_t, not struct page pointers. DMA API is not alone here, we have been de-struct-paging the kernel for a long time now: netdev: https://lore.kernel.org/linux-mm/20250609043225.77229-1-byungchul@sk.com/ slab: https://lore.kernel.org/linux-mm/20211201181510.18784-1-vbabka@suse.cz/ iommmu: https://lore.kernel.org/all/0-v4-c8663abbb606+3f7-iommu_pages_jgg@nvidia.com/ page tables: https://lore.kernel.org/linux-mm/20230731170332.69404-1-vishal.moola@gmail.com/ zswap: https://lore.kernel.org/all/20241216150450.1228021-1-42.hyeyoo@gmail.com/ With a long term goal that struct page only exists for legacy code, and is maybe entirely compiled out of modern server kernels. > Second - making dma_map_phys() a single API to handle all cases. > > Do we really need such single function to handle all cases? If we accept the direction to remove struct page then it makes little sense to have a dma_map_ram(phys_addr) and dma_map_resource(phys_addr) and force key callers (like block) to have more ifs - especially if the conditional could become "free" inside the dma API (see below). Plus if we keep the callchain split then adding a "dma_link_resource"/etc are now needed as well. > DMA_ATTR_MMIO for every typical DMA user? I know that branching is > cheap, but this will probably increase code size for most of the typical > users for no reason. Well, having two call chains will increase the code size much more, and 'resource' can't be compiled out. Arguably this unification should reduce the .text size since many of the resource only functions go away. There are some branches, and I think the push toward re-using DMA_ATTR_SKIP_CPU_SYNC was directly to try to reduce that branch cost. However, I think we should be looking for a design here that is "free" on the fast no-swiotlb and non-cache-flush path. I think this can be achieved by checking ATTR_MMIO only after seeing swiotlb is needed (like today's is p2p check). And we can probably freely fold it into the existing sync check: if ((attrs & (DMA_ATTR_SKIP_CPU_SYNC | DMA_ATTR_MMIO)) == 0) I saw Leon hasn't done these micro optimizations, but it seems like it could work out. Regards, Jason
On 8/9/25 09:34, Jason Gunthorpe wrote: > On Fri, Aug 08, 2025 at 08:51:08PM +0200, Marek Szyprowski wrote: >> First - basing the API on the phys_addr_t. >> >> Page based API had the advantage that it was really hard to abuse it and >> call for something that is not 'a normal RAM'. > > This is not true anymore. Today we have ZONE_DEVICE as a struct page > type with a whole bunch of non-dram sub-types: > > enum memory_type { > /* 0 is reserved to catch uninitialized type fields */ > MEMORY_DEVICE_PRIVATE = 1, > MEMORY_DEVICE_COHERENT, > MEMORY_DEVICE_FS_DAX, > MEMORY_DEVICE_GENERIC, > MEMORY_DEVICE_PCI_P2PDMA, > }; > > Few of which are kmappable/page_to_virtable() in a way that is useful > for the DMA API. > > DMA API sort of ignores all of this and relies on the caller to not > pass in an incorrect struct page. eg we rely on things like the block > stack to do the right stuff when a MEMORY_DEVICE_PCI_P2PDMA is present > in a bio_vec. > > Which is not really fundamentally different from just using > phys_addr_t in the first place. > > Sure, this was a stronger argument when this stuff was originally > written, before ZONE_DEVICE was invented. > >> I initially though that phys_addr_t based API will somehow simplify >> arch specific implementation, as some of them indeed rely on >> phys_addr_t internally, but I missed other things pointed by >> Robin. Do we have here any alternative? > > I think it is less of a code simplification, more as a reduction in > conceptual load. When we can say directly there is no struct page type > anyhwere in the DMA API layers then we only have to reason about > kmap/phys_to_virt compatibly. > > This is also a weaker overall requirement than needing an actual > struct page which allows optimizing other parts of the kernel. Like we > aren't forced to create MEMORY_DEVICE_PCI_P2PDMA stuct pages just to > use the dma api. > > Again, any place in the kernel we can get rid of struct page the > smoother the road will be for the MM side struct page restructuring. > > For example one of the bigger eventual goes here is to make a bio_vec > store phys_addr_t, not struct page pointers. > > DMA API is not alone here, we have been de-struct-paging the kernel > for a long time now: > > netdev: https://lore.kernel.org/linux-mm/20250609043225.77229-1-byungchul@sk.com/ > slab: https://lore.kernel.org/linux-mm/20211201181510.18784-1-vbabka@suse.cz/ > iommmu: https://lore.kernel.org/all/0-v4-c8663abbb606+3f7-iommu_pages_jgg@nvidia.com/ > page tables: https://lore.kernel.org/linux-mm/20230731170332.69404-1-vishal.moola@gmail.com/ > zswap: https://lore.kernel.org/all/20241216150450.1228021-1-42.hyeyoo@gmail.com/ > > With a long term goal that struct page only exists for legacy code, > and is maybe entirely compiled out of modern server kernels. Why just server kernels? I suspect client systems actually run newer kernels than servers do. -- Sincerely, Demi Marie Obenour (she/her/hers)
On Sat, Aug 09, 2025 at 12:53:09PM -0400, Demi Marie Obenour wrote: > > With a long term goal that struct page only exists for legacy code, > > and is maybe entirely compiled out of modern server kernels. > > Why just server kernels? I suspect client systems actually run > newer kernels than servers do. I would guess this is because of the people who are interested in this work. Frankly there isn't much benifit for small memory client systems. Modern servers have > 1TB of memory and struct page really hurts here. The flip side of this is the work is enormous and I think there is a general idea that the smaller set of server related drivers and subsystems will get ready well before the wider universe of stuff a client or android might use. It is not that more can't happen it just ultimately depends on interest and time. Many modern servers use quite new kernels if you ignore the enterprise distros :\ Jason
© 2016 - 2025 Red Hat, Inc.