Commit ef20808d authored by leoliu-oc's avatar leoliu-oc
Browse files

Add kh40000_iommu_dma_ops for KH-40000 platform

zhaoxin inclusion
category: other
bugzilla: https://gitee.com/openeuler/kernel/issues/I9ARTM


CVE: NA

--------------------------------------------

Add 'kh40000_iommu_dma_ops' to replace 'intel_dma_ops' for KH-40000
platform.

For coherent DMA access, memory can be allocated only from the memory node
of the node where the device resides.

For streaming DMA access, add a PCI read operation at the end of DMA
access.

Signed-off-by: default avatarleoliu-oc <leoliu-oc@zhaoxin.com>
parent 4332dbb0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@ static inline const struct dma_map_ops *get_arch_dma_ops(void)

extern bool is_zhaoxin_kh40000;
extern const struct dma_map_ops kh40000_dma_direct_ops;
extern void kh40000_set_iommu_dma_ops(struct device *dev);

#endif

+175 −0
Original line number Diff line number Diff line
@@ -176,3 +176,178 @@ const struct dma_map_ops kh40000_dma_direct_ops = {
	.map_sg			= dma_direct_map_sg,
	.map_resource		= dma_direct_map_resource,
};

/* zhaoxin kh-40000 iommu dma ops */
static const struct dma_map_ops *iommu_dma_ops;

static void *kh40000_iommu_dma_alloc(struct device *dev, size_t size,
		dma_addr_t *addr, gfp_t gfp, unsigned long attrs)
{
	gfp |= __GFP_THISNODE;

	return iommu_dma_ops->alloc(dev, size, addr, gfp, attrs);
}

static void kh40000_iommu_dma_free(struct device *dev, size_t size, void *cpu_addr,
		dma_addr_t handle, unsigned long attrs)
{
	iommu_dma_ops->free(dev, size, cpu_addr, handle, attrs);
}

static struct page *kh40000_dma_common_alloc_pages(struct device *dev, size_t size,
		dma_addr_t *dma_handle, enum dma_data_direction dir, gfp_t gfp)
{
	return iommu_dma_ops->alloc_pages(dev, size, dma_handle, dir, gfp);
}

static void kh40000_dma_common_free_pages(struct device *dev, size_t size, struct page *page,
		dma_addr_t dma_handle, enum dma_data_direction dir)
{
	iommu_dma_ops->free_pages(dev, size, page, dma_handle, dir);
}

static struct sg_table *kh40000_iommu_dma_alloc_noncontiguous(struct device *dev,
		size_t size, enum dma_data_direction dir, gfp_t gfp,
		unsigned long attrs)
{
	return iommu_dma_ops->alloc_noncontiguous(dev, size, dir, gfp, attrs);
}

static void kh40000_iommu_dma_free_noncontiguous(struct device *dev, size_t size,
		struct sg_table *sgt, enum dma_data_direction dir)
{
	return iommu_dma_ops->free_noncontiguous(dev, size, sgt, dir);
}

static int kh40000_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 iommu_dma_ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs);
}

static void kh40000_iommu_dma_unmap_page(struct device *dev, dma_addr_t addr,
		size_t size, enum dma_data_direction dir, unsigned long attrs)
{
	kh40000_sync_single_dma_for_cpu(dev, addr, dir, 1);
	iommu_dma_ops->unmap_page(dev, addr, size, dir, attrs);
}

static int kh40000_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 iommu_dma_ops->get_sgtable(dev, sgt, cpu_addr, dma_addr, size, attrs);
}

static dma_addr_t kh40000_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 iommu_dma_ops->map_page(dev, page, offset, size, dir, attrs);
}

static int kh40000_iommu_dma_map_sg(struct device *dev, struct scatterlist *sgl,
		int nents, enum dma_data_direction dir, unsigned long attrs)
{
	return iommu_dma_ops->map_sg(dev, sgl, nents, dir, attrs);
}

static void kh40000_iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sgl,
		int nelems, enum dma_data_direction dir, unsigned long attrs)
{
	struct scatterlist *sg;
	int i;

	for_each_sg(sgl, sg, nelems, i)
		kh40000_sync_single_dma_for_cpu(dev, sg_dma_address(sg), dir, 1);
	iommu_dma_ops->unmap_sg(dev, sgl, nelems, dir, attrs);
}

static void kh40000_iommu_dma_sync_single_for_cpu(struct device *dev,
		dma_addr_t addr, size_t size, enum dma_data_direction dir)
{
	kh40000_sync_single_dma_for_cpu(dev, addr, dir, 1);
	iommu_dma_ops->sync_single_for_cpu(dev, addr, size, dir);
}

static void kh40000_iommu_dma_sync_single_for_device(struct device *dev,
		dma_addr_t addr, size_t size, enum dma_data_direction dir)
{
	iommu_dma_ops->sync_single_for_device(dev, addr, size, dir);
}

static void kh40000_iommu_dma_sync_sg_for_cpu(struct device *dev,
		struct scatterlist *sgl, int nelems,
		enum dma_data_direction dir)
{
	struct scatterlist *sg;
	int i;

	for_each_sg(sgl, sg, nelems, i)
		kh40000_sync_single_dma_for_cpu(dev, sg_dma_address(sg), dir, 1);
	iommu_dma_ops->sync_sg_for_cpu(dev, sgl, nelems, dir);
}

static void kh40000_iommu_dma_sync_sg_for_device(struct device *dev,
		struct scatterlist *sgl, int nelems,
		enum dma_data_direction dir)
{
	iommu_dma_ops->sync_sg_for_device(dev, sgl, nelems, dir);
}

static dma_addr_t kh40000_iommu_dma_map_resource(struct device *dev, phys_addr_t phys,
		size_t size, enum dma_data_direction dir, unsigned long attrs)
{
	return iommu_dma_ops->map_resource(dev, phys, size, dir, attrs);
}

static void kh40000_iommu_dma_unmap_resource(struct device *dev, dma_addr_t addr,
		size_t size, enum dma_data_direction dir, unsigned long attrs)
{
	kh40000_sync_single_dma_for_cpu(dev, addr, dir, 1);
	iommu_dma_ops->unmap_resource(dev, addr, size, dir, attrs);
}

static unsigned long kh40000_iommu_dma_get_merge_boundary(struct device *dev)
{
	return iommu_dma_ops->get_merge_boundary(dev);
}

static size_t kh40000_iommu_dma_opt_mapping_size(void)
{
	return iommu_dma_ops->opt_mapping_size();
}

const struct dma_map_ops kh40000_dma_iommu_ops = {
	.flags			= DMA_F_PCI_P2PDMA_SUPPORTED,
	.alloc			= kh40000_iommu_dma_alloc,
	.free			= kh40000_iommu_dma_free,
	.unmap_page		= kh40000_iommu_dma_unmap_page,
	.alloc_pages		= kh40000_dma_common_alloc_pages,
	.free_pages		= kh40000_dma_common_free_pages,
	.alloc_noncontiguous	= kh40000_iommu_dma_alloc_noncontiguous,
	.free_noncontiguous	= kh40000_iommu_dma_free_noncontiguous,
	.mmap			= kh40000_iommu_dma_mmap,
	.get_sgtable		= kh40000_iommu_dma_get_sgtable,
	.map_page		= kh40000_iommu_dma_map_page,
	.map_sg			= kh40000_iommu_dma_map_sg,
	.unmap_sg		= kh40000_iommu_dma_unmap_sg,
	.sync_single_for_cpu	= kh40000_iommu_dma_sync_single_for_cpu,
	.sync_single_for_device	= kh40000_iommu_dma_sync_single_for_device,
	.sync_sg_for_cpu	= kh40000_iommu_dma_sync_sg_for_cpu,
	.sync_sg_for_device	= kh40000_iommu_dma_sync_sg_for_device,
	.map_resource		= kh40000_iommu_dma_map_resource,
	.unmap_resource		= kh40000_iommu_dma_unmap_resource,
	.get_merge_boundary	= kh40000_iommu_dma_get_merge_boundary,
	.opt_mapping_size	= kh40000_iommu_dma_opt_mapping_size,
};

void kh40000_set_iommu_dma_ops(struct device *dev)
{
	if (dev->dma_ops) {
		iommu_dma_ops = dev->dma_ops;
		set_dma_ops(dev, &kh40000_dma_iommu_ops);
		pr_info_once("zhaoxin iommu dma patch enabled\n");
	}
}
+4 −0
Original line number Diff line number Diff line
@@ -4359,6 +4359,10 @@ static void intel_iommu_probe_finalize(struct device *dev)
{
	set_dma_ops(dev, NULL);
	iommu_setup_dma_ops(dev, 0, U64_MAX);
#ifdef CONFIG_X86_64
	if (is_zhaoxin_kh40000)
		kh40000_set_iommu_dma_ops(dev);
#endif
}

static void intel_iommu_get_resv_regions(struct device *device,