Commit 4491b854 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'dma-mapping-6.12-2024-09-24' of git://git.infradead.org/users/hch/dma-mapping

Pull dma-mapping fixes from Christoph Hellwig:

 - sort out a few issues with the direct calls to iommu-dma (Christoph
   Hellwig, Leon Romanovsky)

* tag 'dma-mapping-6.12-2024-09-24' of git://git.infradead.org/users/hch/dma-mapping:
  dma-mapping: report unlimited DMA addressing in IOMMU DMA path
  iommu/dma: remove most stubs in iommu-dma.h
  dma-mapping: fix vmap and mmap of noncontiougs allocations
parents db78436b b348b6d1
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
@@ -1038,6 +1038,21 @@ static void *iommu_dma_alloc_remap(struct device *dev, size_t size,
	return NULL;
}

/*
 * This is the actual return value from the iommu_dma_alloc_noncontiguous.
 *
 * The users of the DMA API should only care about the sg_table, but to make
 * the DMA-API internal vmaping and freeing easier we stash away the page
 * array as well (except for the fallback case).  This can go away any time,
 * e.g. when a vmap-variant that takes a scatterlist comes along.
 */
struct dma_sgt_handle {
	struct sg_table sgt;
	struct page **pages;
};
#define sgt_handle(sgt) \
	container_of((sgt), struct dma_sgt_handle, sgt)

struct sg_table *iommu_dma_alloc_noncontiguous(struct device *dev, size_t size,
	       enum dma_data_direction dir, gfp_t gfp, unsigned long attrs)
{
@@ -1066,6 +1081,24 @@ void iommu_dma_free_noncontiguous(struct device *dev, size_t size,
	kfree(sh);
}

void *iommu_dma_vmap_noncontiguous(struct device *dev, size_t size,
		struct sg_table *sgt)
{
	unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;

	return vmap(sgt_handle(sgt)->pages, count, VM_MAP, PAGE_KERNEL);
}

int iommu_dma_mmap_noncontiguous(struct device *dev, struct vm_area_struct *vma,
		size_t size, struct sg_table *sgt)
{
	unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;

	if (vma->vm_pgoff >= count || vma_pages(vma) > count - vma->vm_pgoff)
		return -ENXIO;
	return vm_map_pages(vma, sgt_handle(sgt)->pages, count);
}

void iommu_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
		size_t size, enum dma_data_direction dir)
{
+0 −19
Original line number Diff line number Diff line
@@ -24,11 +24,6 @@ struct dma_map_ops {
			gfp_t gfp);
	void (*free_pages)(struct device *dev, size_t size, struct page *vaddr,
			dma_addr_t dma_handle, enum dma_data_direction dir);
	struct sg_table *(*alloc_noncontiguous)(struct device *dev, size_t size,
			enum dma_data_direction dir, gfp_t gfp,
			unsigned long attrs);
	void (*free_noncontiguous)(struct device *dev, size_t size,
			struct sg_table *sgt, enum dma_data_direction dir);
	int (*mmap)(struct device *, struct vm_area_struct *,
			void *, dma_addr_t, size_t, unsigned long attrs);

@@ -206,20 +201,6 @@ static inline int dma_mmap_from_global_coherent(struct vm_area_struct *vma,
}
#endif /* CONFIG_DMA_GLOBAL_POOL */

/*
 * This is the actual return value from the ->alloc_noncontiguous method.
 * The users of the DMA API should only care about the sg_table, but to make
 * the DMA-API internal vmaping and freeing easier we stash away the page
 * array as well (except for the fallback case).  This can go away any time,
 * e.g. when a vmap-variant that takes a scatterlist comes along.
 */
struct dma_sgt_handle {
	struct sg_table sgt;
	struct page **pages;
};
#define sgt_handle(sgt) \
	container_of((sgt), struct dma_sgt_handle, sgt)

int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt,
		void *cpu_addr, dma_addr_t dma_addr, size_t size,
		unsigned long attrs);
+14 −100
Original line number Diff line number Diff line
@@ -14,6 +14,13 @@ static inline bool use_dma_iommu(struct device *dev)
{
	return dev->dma_iommu;
}
#else
static inline bool use_dma_iommu(struct device *dev)
{
	return false;
}
#endif /* CONFIG_IOMMU_DMA */

dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page,
		unsigned long offset, size_t size, enum dma_data_direction dir,
		unsigned long attrs);
@@ -44,6 +51,12 @@ struct sg_table *iommu_dma_alloc_noncontiguous(struct device *dev, size_t size,
		enum dma_data_direction dir, gfp_t gfp, unsigned long attrs);
void iommu_dma_free_noncontiguous(struct device *dev, size_t size,
		struct sg_table *sgt, enum dma_data_direction dir);
void *iommu_dma_vmap_noncontiguous(struct device *dev, size_t size,
		struct sg_table *sgt);
#define iommu_dma_vunmap_noncontiguous(dev, vaddr) \
	vunmap(vaddr);
int iommu_dma_mmap_noncontiguous(struct device *dev, struct vm_area_struct *vma,
		size_t size, struct sg_table *sgt);
void iommu_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
		size_t size, enum dma_data_direction dir);
void iommu_dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
@@ -52,104 +65,5 @@ void iommu_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl,
		int nelems, enum dma_data_direction dir);
void iommu_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sgl,
		int nelems, enum dma_data_direction dir);
#else
static inline bool use_dma_iommu(struct device *dev)
{
	return false;
}
static inline dma_addr_t iommu_dma_map_page(struct device *dev,
		struct page *page, unsigned long offset, size_t size,
		enum dma_data_direction dir, unsigned long attrs)
{
	return DMA_MAPPING_ERROR;
}
static inline void iommu_dma_unmap_page(struct device *dev,
		dma_addr_t dma_handle, size_t size, enum dma_data_direction dir,
		unsigned long attrs)
{
}
static inline int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg,
		int nents, enum dma_data_direction dir, unsigned long attrs)
{
	return -EINVAL;
}
static inline void iommu_dma_unmap_sg(struct device *dev,
		struct scatterlist *sg, int nents, enum dma_data_direction dir,
		unsigned long attrs)
{
}
static inline void *iommu_dma_alloc(struct device *dev, size_t size,
		dma_addr_t *handle, gfp_t gfp, unsigned long attrs)
{
	return NULL;
}
static inline int iommu_dma_mmap(struct device *dev, struct vm_area_struct *vma,
		void *cpu_addr, dma_addr_t dma_addr, size_t size,
		unsigned long attrs)
{
	return -EINVAL;
}
static inline int iommu_dma_get_sgtable(struct device *dev,
		struct sg_table *sgt, void *cpu_addr, dma_addr_t dma_addr,
		size_t size, unsigned long attrs)
{
	return -EINVAL;
}
static inline unsigned long iommu_dma_get_merge_boundary(struct device *dev)
{
	return 0;
}
static inline size_t iommu_dma_opt_mapping_size(void)
{
	return 0;
}
static inline size_t iommu_dma_max_mapping_size(struct device *dev)
{
	return 0;
}
static inline void iommu_dma_free(struct device *dev, size_t size,
		void *cpu_addr, dma_addr_t handle, unsigned long attrs)
{
}
static inline dma_addr_t iommu_dma_map_resource(struct device *dev,
		phys_addr_t phys, size_t size, enum dma_data_direction dir,
		unsigned long attrs)
{
	return DMA_MAPPING_ERROR;
}
static inline void iommu_dma_unmap_resource(struct device *dev,
		dma_addr_t handle, size_t size, enum dma_data_direction dir,
		unsigned long attrs)
{
}
static inline struct sg_table *
iommu_dma_alloc_noncontiguous(struct device *dev, size_t size,
		enum dma_data_direction dir, gfp_t gfp, unsigned long attrs)
{
	return NULL;
}
static inline void iommu_dma_free_noncontiguous(struct device *dev, size_t size,
		struct sg_table *sgt, enum dma_data_direction dir)
{
}
static inline void iommu_dma_sync_single_for_cpu(struct device *dev,
		dma_addr_t dma_handle, size_t size,
		enum dma_data_direction dir)
{
}
static inline void iommu_dma_sync_single_for_device(struct device *dev,
		dma_addr_t dma_handle, size_t size, enum dma_data_direction dir)
{
}
static inline void iommu_dma_sync_sg_for_cpu(struct device *dev,
		struct scatterlist *sgl, int nelems,
		enum dma_data_direction dir)
{
}
static inline void iommu_dma_sync_sg_for_device(struct device *dev,
		struct scatterlist *sgl, int nelems,
		enum dma_data_direction dir)
{
}
#endif /* CONFIG_IOMMU_DMA */

#endif /* _LINUX_IOMMU_DMA_H */
+15 −28
Original line number Diff line number Diff line
@@ -569,6 +569,10 @@ u64 dma_get_required_mask(struct device *dev)

	if (dma_alloc_direct(dev, ops))
		return dma_direct_get_required_mask(dev);

	if (use_dma_iommu(dev))
		return DMA_BIT_MASK(32);

	if (ops->get_required_mask)
		return ops->get_required_mask(dev);

@@ -750,7 +754,6 @@ static struct sg_table *alloc_single_sgt(struct device *dev, size_t size,
struct sg_table *dma_alloc_noncontiguous(struct device *dev, size_t size,
		enum dma_data_direction dir, gfp_t gfp, unsigned long attrs)
{
	const struct dma_map_ops *ops = get_dma_ops(dev);
	struct sg_table *sgt;

	if (WARN_ON_ONCE(attrs & ~DMA_ATTR_ALLOC_SINGLE_PAGES))
@@ -758,9 +761,7 @@ struct sg_table *dma_alloc_noncontiguous(struct device *dev, size_t size,
	if (WARN_ON_ONCE(gfp & __GFP_COMP))
		return NULL;

	if (ops && ops->alloc_noncontiguous)
		sgt = ops->alloc_noncontiguous(dev, size, dir, gfp, attrs);
	else if (use_dma_iommu(dev))
	if (use_dma_iommu(dev))
		sgt = iommu_dma_alloc_noncontiguous(dev, size, dir, gfp, attrs);
	else
		sgt = alloc_single_sgt(dev, size, dir, gfp);
@@ -786,13 +787,10 @@ static void free_single_sgt(struct device *dev, size_t size,
void dma_free_noncontiguous(struct device *dev, size_t size,
		struct sg_table *sgt, enum dma_data_direction dir)
{
	const struct dma_map_ops *ops = get_dma_ops(dev);

	trace_dma_unmap_sg(dev, sgt->sgl, sgt->orig_nents, dir, 0);
	debug_dma_unmap_sg(dev, sgt->sgl, sgt->orig_nents, dir);
	if (ops && ops->free_noncontiguous)
		ops->free_noncontiguous(dev, size, sgt, dir);
	else if (use_dma_iommu(dev))

	if (use_dma_iommu(dev))
		iommu_dma_free_noncontiguous(dev, size, sgt, dir);
	else
		free_single_sgt(dev, size, sgt, dir);
@@ -802,37 +800,26 @@ EXPORT_SYMBOL_GPL(dma_free_noncontiguous);
void *dma_vmap_noncontiguous(struct device *dev, size_t size,
		struct sg_table *sgt)
{
	const struct dma_map_ops *ops = get_dma_ops(dev);
	unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;

	if (ops && ops->alloc_noncontiguous)
		return vmap(sgt_handle(sgt)->pages, count, VM_MAP, PAGE_KERNEL);
	if (use_dma_iommu(dev))
		return iommu_dma_vmap_noncontiguous(dev, size, sgt);

	return page_address(sg_page(sgt->sgl));
}
EXPORT_SYMBOL_GPL(dma_vmap_noncontiguous);

void dma_vunmap_noncontiguous(struct device *dev, void *vaddr)
{
	const struct dma_map_ops *ops = get_dma_ops(dev);

	if (ops && ops->alloc_noncontiguous)
		vunmap(vaddr);
	if (use_dma_iommu(dev))
		iommu_dma_vunmap_noncontiguous(dev, vaddr);
}
EXPORT_SYMBOL_GPL(dma_vunmap_noncontiguous);

int dma_mmap_noncontiguous(struct device *dev, struct vm_area_struct *vma,
		size_t size, struct sg_table *sgt)
{
	const struct dma_map_ops *ops = get_dma_ops(dev);

	if (ops && ops->alloc_noncontiguous) {
		unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;

		if (vma->vm_pgoff >= count ||
		    vma_pages(vma) > count - vma->vm_pgoff)
			return -ENXIO;
		return vm_map_pages(vma, sgt_handle(sgt)->pages, count);
	}
	if (use_dma_iommu(dev))
		return iommu_dma_mmap_noncontiguous(dev, vma, size, sgt);
	return dma_mmap_pages(dev, vma, size, sg_page(sgt->sgl));
}
EXPORT_SYMBOL_GPL(dma_mmap_noncontiguous);
@@ -926,7 +913,7 @@ bool dma_addressing_limited(struct device *dev)
			 dma_get_required_mask(dev))
		return true;

	if (unlikely(ops))
	if (unlikely(ops) || use_dma_iommu(dev))
		return false;
	return !dma_direct_all_ram_mapped(dev);
}