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

Commit dc9f5d87 authored by Jordan Crouse's avatar Jordan Crouse
Browse files

msm: kgsl: Add an option to always enable I/O coherency



Add a Kconfig option to allow the driver to mark all memory buffers
as I/O coherent by default if the target supports I/O coherency.

This is a config option for now because I/O coherency has traditionally
been a little fickle and it represents a paradigm shift to enable it
universally. Eventually the goal is to leave it on by default and invert
the polarity of this option.

In conjunction we can use this option to manage kernel targets that do not
not support fine grained cache operations. Because it is impossible to stop
the user from creating and using cached surfaces the driver has
to either support I/O coherency by default OR have access to fine grained
cache operations. We can take advantage of the new Kconfig option to
make some compile time decisions and compile out the cache code if it isn't
supported.

This isn't 100% foolproof though. If your target doesn't support I/O
coherency and there are no cache operations available you are out of luck,
so as it stands this precludes cached operations on a3xx and a5xx with this
kernel. We will still allow cached surfaces but they will never be
coherent. If this becomes a problem we'll need to figure out a way to
disallow cached surfaces on those targets.

Change-Id: Ic0dedbad7d923b54f64f34cd68a59c3522ca5ee9
Signed-off-by: default avatarJordan Crouse <jcrouse@codeaurora.org>
parent 71d4d5cb
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -41,3 +41,13 @@ config QCOM_KGSL_CORESIGHT
	  When enabled, the Adreno GPU is available as a source for Coresight
	  data. On a6xx targets there are two sources available for the GX and
	  CX domains respectively. Debug kernels should say 'Y' here.

config QCOM_KGSL_IOCOHERENCY_DEFAULT
	bool "Enable I/O coherency on cached GPU memory by default"
	depends on QCOM_KGSL
	default y if ARCH_LAHAINA
	help
	 Say 'Y' here to enable I/O cache coherency by default on targets that
	 support hardware I/O coherency. If enabled all cached GPU memory
	 will use I/O coherency regardless of the user flags. If not enabled
	 the user can still selectively enable I/O coherency with a flag.
+23 −4
Original line number Diff line number Diff line
@@ -2391,6 +2391,14 @@ static void _setup_cache_mode(struct kgsl_mem_entry *entry,
	entry->memdesc.flags |= (mode << KGSL_CACHEMODE_SHIFT);
}

static bool is_cached(u64 flags)
{
	u32 mode = (flags & KGSL_CACHEMODE_MASK) >> KGSL_CACHEMODE_SHIFT;

	return (mode != KGSL_CACHEMODE_UNCACHED &&
		mode != KGSL_CACHEMODE_WRITECOMBINE);
}

static int kgsl_setup_dma_buf(struct kgsl_device *device,
				struct kgsl_pagetable *pagetable,
				struct kgsl_mem_entry *entry,
@@ -2455,6 +2463,11 @@ static int kgsl_setup_dmabuf_useraddr(struct kgsl_device *device,
	/* Setup the user addr/cache mode for cache operations */
	entry->memdesc.useraddr = hostptr;
	_setup_cache_mode(entry, vma);

	if (IS_ENABLED(CONFIG_QCOM_KGSL_IOCOHERENCY_DEFAULT) &&
		is_cached(entry->memdesc.flags))
		entry->memdesc.flags |= KGSL_MEMFLAGS_IOCOHERENT;

	up_read(&current->mm->mmap_sem);
	return 0;
}
@@ -2979,7 +2992,6 @@ static int _kgsl_gpumem_sync_cache(struct kgsl_mem_entry *entry,
{
	int ret = 0;
	int cacheop;
	int mode;

	if (!entry)
		return 0;
@@ -3010,9 +3022,7 @@ static int _kgsl_gpumem_sync_cache(struct kgsl_mem_entry *entry,
		length = entry->memdesc.size;
	}

	mode = kgsl_memdesc_get_cachemode(&entry->memdesc);
	if (mode != KGSL_CACHEMODE_UNCACHED
		&& mode != KGSL_CACHEMODE_WRITECOMBINE) {
	if (is_cached(entry->memdesc.flags)) {
		trace_kgsl_mem_sync_cache(entry, offset, length, op);
		ret = kgsl_cache_range_op(&entry->memdesc, offset,
					length, cacheop);
@@ -3319,6 +3329,10 @@ struct kgsl_mem_entry *gpumem_alloc_entry(
	if (entry == NULL)
		return ERR_PTR(-ENOMEM);

	if (IS_ENABLED(CONFIG_QCOM_KGSL_IOCOHERENCY_DEFAULT) &&
		is_cached(flags))
		flags |= KGSL_MEMFLAGS_IOCOHERENT;

	ret = kgsl_allocate_user(dev_priv->device, &entry->memdesc,
		size, flags, 0);
	if (ret != 0)
@@ -3540,6 +3554,11 @@ long kgsl_ioctl_sparse_phys_alloc(struct kgsl_device_private *dev_priv,
		((ilog2(param->pagesize) << KGSL_MEMALIGN_SHIFT) &
			KGSL_MEMALIGN_MASK);


	if (IS_ENABLED(CONFIG_QCOM_KGSL_IOCOHERENCY_DEFAULT) &&
		is_cached(flags))
		flags |= KGSL_MEMFLAGS_IOCOHERENT;

	ret = kgsl_allocate_user(dev_priv->device, &entry->memdesc,
			param->size, flags, 0);
	if (ret)
+35 −12
Original line number Diff line number Diff line
@@ -13,6 +13,15 @@
#include "kgsl_pool.h"
#include "kgsl_sharedmem.h"

/*
 * For now, we either need the low level cache operations or
 * QCOM_KGSL_IOCOHERENCY_DEFAULT enabled because we can't stop userspace
 * from expecting to enable cached surfaces and have them work
 */
#if !defined(dmac_flush_range) && !IS_ENABLED(CONFIG_QCOM_KGSL_IOCOHERENCY_DEFAULT)
#error "KGSL needs either dmac_flush_range or CONFIG_QCOM_KGSL_IOCOHERENCY_DEFAULT enabled"
#endif

/*
 * The user can set this from debugfs to force failed memory allocations to
 * fail without trying OOM first.  This is a debug setting useful for
@@ -512,7 +521,8 @@ static inline unsigned int _fixup_cache_range_op(unsigned int op)
}
#endif

static inline void _cache_op(unsigned int op,
#ifdef dmac_flush_range
static void _cache_op(unsigned int op,
			const void *start, const void *end)
{
	/*
@@ -532,8 +542,8 @@ static inline void _cache_op(unsigned int op,
	}
}

static int kgsl_do_cache_op(struct page *page, void *addr,
		uint64_t offset, uint64_t size, unsigned int op)
static void kgsl_do_cache_op(struct page *page, void *addr, u64 offset,
		u64 size, unsigned int op)
{
	if (page != NULL) {
		unsigned long pfn = page_to_pfn(page) + offset / PAGE_SIZE;
@@ -562,15 +572,21 @@ static int kgsl_do_cache_op(struct page *page, void *addr,
				offset = 0;
			} while (size);

			return 0;
			return;
		}

		addr = page_address(page);
	}

	_cache_op(op, addr + offset, addr + offset + (size_t) size);
	return 0;
}
#else

static void kgsl_do_cache_op(struct page *page, void *addr, u64 offset,
		u64 size, unsigned int op)
{
}
#endif

int kgsl_cache_range_op(struct kgsl_memdesc *memdesc, uint64_t offset,
		uint64_t size, unsigned int op)
@@ -579,7 +595,9 @@ int kgsl_cache_range_op(struct kgsl_memdesc *memdesc, uint64_t offset,
	struct sg_table *sgt = NULL;
	struct scatterlist *sg;
	unsigned int i, pos = 0;
	int ret = 0;

	if (memdesc->flags & KGSL_MEMFLAGS_IOCOHERENT)
		return 0;

	if (size == 0 || size > UINT_MAX)
		return -EINVAL;
@@ -598,8 +616,8 @@ int kgsl_cache_range_op(struct kgsl_memdesc *memdesc, uint64_t offset,
		if (addr + ((size_t) offset + (size_t) size) < addr)
			return -ERANGE;

		ret = kgsl_do_cache_op(NULL, addr, offset, size, op);
		return ret;
		kgsl_do_cache_op(NULL, addr, offset, size, op);
		return 0;
	}

	/*
@@ -610,7 +628,7 @@ int kgsl_cache_range_op(struct kgsl_memdesc *memdesc, uint64_t offset,
		sgt = memdesc->sgt;
	else {
		if (memdesc->pages == NULL)
			return ret;
			return  0;

		sgt = kgsl_alloc_sgt_from_pages(memdesc);
		if (IS_ERR(sgt))
@@ -627,7 +645,7 @@ int kgsl_cache_range_op(struct kgsl_memdesc *memdesc, uint64_t offset,
		sg_offset = offset > pos ? offset - pos : 0;
		sg_left = (sg->length - sg_offset > size) ? size :
					sg->length - sg_offset;
		ret = kgsl_do_cache_op(sg_page(sg), NULL, sg_offset,
		kgsl_do_cache_op(sg_page(sg), NULL, sg_offset,
							sg_left, op);
		size -= sg_left;
		if (size == 0)
@@ -638,7 +656,7 @@ int kgsl_cache_range_op(struct kgsl_memdesc *memdesc, uint64_t offset,
	if (memdesc->sgt == NULL)
		kgsl_free_sgt(sgt);

	return ret;
	return 0;
}

void kgsl_memdesc_init(struct kgsl_device *device,
@@ -657,9 +675,14 @@ void kgsl_memdesc_init(struct kgsl_device *device,
		flags &= ~((uint64_t) KGSL_MEMFLAGS_USE_CPU_MAP);

	/* Disable IO coherence if it is not supported on the chip */
	if (!MMU_FEATURE(mmu, KGSL_MMU_IO_COHERENT))
	if (!MMU_FEATURE(mmu, KGSL_MMU_IO_COHERENT)) {
		flags &= ~((uint64_t) KGSL_MEMFLAGS_IOCOHERENT);

		WARN_ONCE(IS_ENABLED(CONFIG_QCOM_KGSL_IOCOHERENCY_DEFAULT),
			"I/O coherency is not supported on this target\n");
	} else if (IS_ENABLED(CONFIG_QCOM_KGSL_IOCOHERENCY_DEFAULT))
		flags |= KGSL_MEMFLAGS_IOCOHERENT;

	if (MMU_FEATURE(mmu, KGSL_MMU_NEED_GUARD_PAGE))
		memdesc->priv |= KGSL_MEMDESC_GUARD_PAGE;