| /* SPDX-License-Identifier: GPL-2.0 */ | |
| /* | |
| * Copyright (C) 2018 Christoph Hellwig. | |
| * | |
| * DMA operations that map physical memory directly without using an IOMMU. | |
| */ | |
| #ifndef _KERNEL_DMA_DIRECT_H | |
| #define _KERNEL_DMA_DIRECT_H | |
| #include <linux/dma-direct.h> | |
| #include <linux/memremap.h> | |
| int dma_direct_get_sgtable(struct device *dev, struct sg_table *sgt, | |
| void *cpu_addr, dma_addr_t dma_addr, size_t size, | |
| unsigned long attrs); | |
| bool dma_direct_can_mmap(struct device *dev); | |
| int dma_direct_mmap(struct device *dev, struct vm_area_struct *vma, | |
| void *cpu_addr, dma_addr_t dma_addr, size_t size, | |
| unsigned long attrs); | |
| dma_addr_t dma_direct_map_phys(struct device *dev, phys_addr_t phys, | |
| size_t size, enum dma_data_direction dir, | |
| unsigned long attrs, bool flush); | |
| bool dma_direct_need_sync(struct device *dev, dma_addr_t dma_addr); | |
| int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents, | |
| enum dma_data_direction dir, unsigned long attrs); | |
| bool dma_direct_all_ram_mapped(struct device *dev); | |
| size_t dma_direct_max_mapping_size(struct device *dev); | |
| #if defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE) || \ | |
| defined(CONFIG_SWIOTLB) | |
| void dma_direct_sync_sg_for_device(struct device *dev, struct scatterlist *sgl, | |
| int nents, enum dma_data_direction dir); | |
| #else | |
| static inline void dma_direct_sync_sg_for_device(struct device *dev, | |
| struct scatterlist *sgl, int nents, enum dma_data_direction dir) | |
| { | |
| } | |
| #endif | |
| #if defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU) || \ | |
| defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL) || \ | |
| defined(CONFIG_SWIOTLB) | |
| void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sgl, | |
| int nents, enum dma_data_direction dir, unsigned long attrs); | |
| void dma_direct_sync_sg_for_cpu(struct device *dev, | |
| struct scatterlist *sgl, int nents, enum dma_data_direction dir); | |
| #else | |
| static inline void dma_direct_unmap_sg(struct device *dev, | |
| struct scatterlist *sgl, int nents, enum dma_data_direction dir, | |
| unsigned long attrs) | |
| { | |
| } | |
| static inline void dma_direct_sync_sg_for_cpu(struct device *dev, | |
| struct scatterlist *sgl, int nents, enum dma_data_direction dir) | |
| { | |
| } | |
| #endif | |
| static inline void dma_direct_sync_single_for_device(struct device *dev, | |
| dma_addr_t addr, size_t size, enum dma_data_direction dir) | |
| { | |
| phys_addr_t paddr = dma_to_phys(dev, addr); | |
| swiotlb_sync_single_for_device(dev, paddr, size, dir); | |
| if (!dev_is_dma_coherent(dev)) { | |
| arch_sync_dma_for_device(paddr, size, dir); | |
| arch_sync_dma_flush(); | |
| } | |
| } | |
| static inline void dma_direct_sync_single_for_cpu(struct device *dev, | |
| dma_addr_t addr, size_t size, enum dma_data_direction dir, | |
| bool flush) | |
| { | |
| phys_addr_t paddr = dma_to_phys(dev, addr); | |
| if (!dev_is_dma_coherent(dev)) { | |
| arch_sync_dma_for_cpu(paddr, size, dir); | |
| if (flush) | |
| arch_sync_dma_flush(); | |
| arch_sync_dma_for_cpu_all(); | |
| } | |
| swiotlb_sync_single_for_cpu(dev, paddr, size, dir); | |
| } | |
| static inline void dma_direct_unmap_phys(struct device *dev, dma_addr_t addr, | |
| size_t size, enum dma_data_direction dir, unsigned long attrs, | |
| bool flush) | |
| { | |
| phys_addr_t phys; | |
| if (attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT)) | |
| /* nothing to do: uncached and no swiotlb */ | |
| return; | |
| phys = dma_to_phys(dev, addr); | |
| if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC)) | |
| dma_direct_sync_single_for_cpu(dev, addr, size, dir, flush); | |
| swiotlb_tbl_unmap_single(dev, phys, size, dir, | |
| attrs | DMA_ATTR_SKIP_CPU_SYNC); | |
| } | |
| #endif /* _KERNEL_DMA_DIRECT_H */ |