Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0e5bee44 authored by Suren Baghdasaryan's avatar Suren Baghdasaryan
Browse files

ANDROID: GKI: add dma_map_ops remap/unremap operations



Trimmed down version of:
4008eb49 "iommu/arm-smmu: Merge of smmu changes from 4.14"
which includes only changes required for removed-dma-pool driver.

Bug: 145617272
Signed-off-by: default avatarSwathi Sridhar <swatsrid@codeaurora.org>
Signed-off-by: default avatarSuren Baghdasaryan <surenb@google.com>
Change-Id: I4b9ae665aaf8aabf89c3b158bc38db458f31657a
parent 30485f20
Loading
Loading
Loading
Loading
+53 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#include <linux/pci.h>

#include <asm/cacheflush.h>
#include <asm/tlbflush.h>

static int swiotlb __ro_after_init;

@@ -321,6 +322,56 @@ static int __swiotlb_dma_supported(struct device *hwdev, u64 mask)
	return 1;
}

static void *arm64_dma_remap(struct device *dev, void *cpu_addr,
			dma_addr_t handle, size_t size,
			unsigned long attrs)
{
	struct page *page = phys_to_page(dma_to_phys(dev, handle));
	bool coherent = is_device_dma_coherent(dev);
	pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL, coherent);
	unsigned long offset = handle & ~PAGE_MASK;
	struct vm_struct *area;
	unsigned long addr;

	size = PAGE_ALIGN(size + offset);

	/*
	 * DMA allocation can be mapped to user space, so lets
	 * set VM_USERMAP flags too.
	 */
	area = get_vm_area(size, VM_USERMAP);
	if (!area)
		return NULL;

	addr = (unsigned long)area->addr;
	area->phys_addr = __pfn_to_phys(page_to_pfn(page));

	if (ioremap_page_range(addr, addr + size, area->phys_addr, prot)) {
		vunmap((void *)addr);
		return NULL;
	}
	return (void *)addr + offset;
}

static void arm64_dma_unremap(struct device *dev, void *remapped_addr,
				size_t size)
{
	struct vm_struct *area;

	size = PAGE_ALIGN(size);
	remapped_addr = (void *)((unsigned long)remapped_addr & PAGE_MASK);

	area = find_vm_area(remapped_addr);
	if (!area) {
		WARN(1, "trying to free invalid coherent area: %pK\n",
			remapped_addr);
		return;
	}
	vunmap(remapped_addr);
	flush_tlb_kernel_range((unsigned long)remapped_addr,
			(unsigned long)(remapped_addr + size));
}

static int __swiotlb_dma_mapping_error(struct device *hwdev, dma_addr_t addr)
{
	if (swiotlb)
@@ -343,6 +394,8 @@ static const struct dma_map_ops arm64_swiotlb_dma_ops = {
	.sync_sg_for_device = __swiotlb_sync_sg_for_device,
	.dma_supported = __swiotlb_dma_supported,
	.mapping_error = __swiotlb_dma_mapping_error,
	.remap = arm64_dma_remap,
	.unremap = arm64_dma_unremap,
};

static int __init atomic_pool_init(void)
+38 −0
Original line number Diff line number Diff line
@@ -70,6 +70,11 @@
 */
#define DMA_ATTR_PRIVILEGED		(1UL << 9)

/*
 * DMA_ATTR_SKIP_ZEROING: Do not zero mapping.
 */
#define DMA_ATTR_SKIP_ZEROING		(1UL << 11)

/*
 * A dma_addr_t can hold any valid DMA or bus address for the platform.
 * It can be given to a device to use as a DMA source or target.  A CPU cannot
@@ -130,6 +135,10 @@ struct dma_map_ops {
			enum dma_data_direction direction);
	int (*mapping_error)(struct device *dev, dma_addr_t dma_addr);
	int (*dma_supported)(struct device *dev, u64 mask);
	void *(*remap)(struct device *dev, void *cpu_addr, dma_addr_t handle,
			size_t size, unsigned long attrs);
	void (*unremap)(struct device *dev, void *remapped_address,
			size_t size);
#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK
	u64 (*get_required_mask)(struct device *dev);
#endif
@@ -608,6 +617,35 @@ static inline int dma_set_mask(struct device *dev, u64 mask)
	return 0;
}
#endif
static inline void *dma_remap(struct device *dev, void *cpu_addr,
		dma_addr_t dma_handle, size_t size, unsigned long attrs)
{
	const struct dma_map_ops *ops = get_dma_ops(dev);

	if (!ops->remap) {
		WARN_ONCE(1, "Remap function not implemented for %pS\n",
				ops->remap);
		return NULL;
	}

	return ops->remap(dev, cpu_addr, dma_handle, size, attrs);
}


static inline void dma_unremap(struct device *dev, void *remapped_addr,
				size_t size)
{
	const struct dma_map_ops *ops = get_dma_ops(dev);

	if (!ops->unremap) {
		WARN_ONCE(1, "unremap function not implemented for %pS\n",
				ops->unremap);
		return;
	}

	return ops->unremap(dev, remapped_addr, size);
}


static inline u64 dma_get_mask(struct device *dev)
{