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

Commit 99743ae4 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge branch 'drm-etnaviv-next' of https://git.pengutronix.de/git/lst/linux into drm-next

It includes code cleanups from Bhumika and Liviu, a significant shader
performance fix and additions to the cmdstream validator from Wladimir
and the addition of a cmdbuf suballocator by myself.
The suballocator improves performance on all chips by reducing the CPU
overhead of the kernel driver and side steps the GC3000 FE MMU flush
erratum, now making the workarounds in IOVA allocation we had before
unnecessary, which results in a nice cleanup of the code in that area.

* 'drm-etnaviv-next' of https://git.pengutronix.de/git/lst/linux:
  drm/etnaviv: Remove duplicate header file include
  Revert "drm/etnaviv: trick drm_mm into giving out a low IOVA"
  drm/etnaviv: add cmdbuf suballocator
  drm/etnaviv: get cmdbuf physical address through the cmdbuf abstraction
  drm/etnaviv: wire up iova handling in new cmdbuf abstraction
  drm/etnaviv: move cmdbuf de-/allocation into own file
  drm/etnaviv: always flush MMU TLBs on map/unmap
  drm/etnaviv: constify etnaviv_iommu_ops structures
  drm/etnaviv: set up initial PULSE_EATER register
  drm/etnaviv: add new GC3000 sensitive states
parents 18566aca 82260364
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
etnaviv-y := \
etnaviv-y := \
	etnaviv_buffer.o \
	etnaviv_buffer.o \
	etnaviv_cmd_parser.o \
	etnaviv_cmd_parser.o \
	etnaviv_cmdbuf.o \
	etnaviv_drv.o \
	etnaviv_drv.o \
	etnaviv_dump.o \
	etnaviv_dump.o \
	etnaviv_gem_prime.o \
	etnaviv_gem_prime.o \
+8 −6
Original line number Original line Diff line number Diff line
@@ -15,6 +15,7 @@
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 */


#include "etnaviv_cmdbuf.h"
#include "etnaviv_gpu.h"
#include "etnaviv_gpu.h"
#include "etnaviv_gem.h"
#include "etnaviv_gem.h"
#include "etnaviv_mmu.h"
#include "etnaviv_mmu.h"
@@ -125,7 +126,7 @@ static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu,
	u32 *ptr = buf->vaddr + off;
	u32 *ptr = buf->vaddr + off;


	dev_info(gpu->dev, "virt %p phys 0x%08x free 0x%08x\n",
	dev_info(gpu->dev, "virt %p phys 0x%08x free 0x%08x\n",
			ptr, etnaviv_iommu_get_cmdbuf_va(gpu, buf) + off, size - len * 4 - off);
			ptr, etnaviv_cmdbuf_get_va(buf) + off, size - len * 4 - off);


	print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4,
	print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4,
			ptr, len * 4, 0);
			ptr, len * 4, 0);
@@ -158,7 +159,7 @@ static u32 etnaviv_buffer_reserve(struct etnaviv_gpu *gpu,
	if (buffer->user_size + cmd_dwords * sizeof(u64) > buffer->size)
	if (buffer->user_size + cmd_dwords * sizeof(u64) > buffer->size)
		buffer->user_size = 0;
		buffer->user_size = 0;


	return etnaviv_iommu_get_cmdbuf_va(gpu, buffer) + buffer->user_size;
	return etnaviv_cmdbuf_get_va(buffer) + buffer->user_size;
}
}


u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu)
u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu)
@@ -169,7 +170,7 @@ u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu)
	buffer->user_size = 0;
	buffer->user_size = 0;


	CMD_WAIT(buffer);
	CMD_WAIT(buffer);
	CMD_LINK(buffer, 2, etnaviv_iommu_get_cmdbuf_va(gpu, buffer) +
	CMD_LINK(buffer, 2, etnaviv_cmdbuf_get_va(buffer) +
		 buffer->user_size - 4);
		 buffer->user_size - 4);


	return buffer->user_size / 8;
	return buffer->user_size / 8;
@@ -261,7 +262,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
	if (drm_debug & DRM_UT_DRIVER)
	if (drm_debug & DRM_UT_DRIVER)
		etnaviv_buffer_dump(gpu, buffer, 0, 0x50);
		etnaviv_buffer_dump(gpu, buffer, 0, 0x50);


	link_target = etnaviv_iommu_get_cmdbuf_va(gpu, cmdbuf);
	link_target = etnaviv_cmdbuf_get_va(cmdbuf);
	link_dwords = cmdbuf->size / 8;
	link_dwords = cmdbuf->size / 8;


	/*
	/*
@@ -355,12 +356,13 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
	CMD_LOAD_STATE(buffer, VIVS_GL_EVENT, VIVS_GL_EVENT_EVENT_ID(event) |
	CMD_LOAD_STATE(buffer, VIVS_GL_EVENT, VIVS_GL_EVENT_EVENT_ID(event) |
		       VIVS_GL_EVENT_FROM_PE);
		       VIVS_GL_EVENT_FROM_PE);
	CMD_WAIT(buffer);
	CMD_WAIT(buffer);
	CMD_LINK(buffer, 2, etnaviv_iommu_get_cmdbuf_va(gpu, buffer) +
	CMD_LINK(buffer, 2, etnaviv_cmdbuf_get_va(buffer) +
			    buffer->user_size - 4);
			    buffer->user_size - 4);


	if (drm_debug & DRM_UT_DRIVER)
	if (drm_debug & DRM_UT_DRIVER)
		pr_info("stream link to 0x%08x @ 0x%08x %p\n",
		pr_info("stream link to 0x%08x @ 0x%08x %p\n",
			return_target, etnaviv_iommu_get_cmdbuf_va(gpu, cmdbuf), cmdbuf->vaddr);
			return_target, etnaviv_cmdbuf_get_va(cmdbuf),
			cmdbuf->vaddr);


	if (drm_debug & DRM_UT_DRIVER) {
	if (drm_debug & DRM_UT_DRIVER) {
		print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4,
		print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4,
+6 −0
Original line number Original line Diff line number Diff line
@@ -56,6 +56,8 @@ static const struct {
	ST(0x0644, 1),
	ST(0x0644, 1),
	ST(0x064c, 1),
	ST(0x064c, 1),
	ST(0x0680, 8),
	ST(0x0680, 8),
	ST(0x086c, 1),
	ST(0x1028, 1),
	ST(0x1410, 1),
	ST(0x1410, 1),
	ST(0x1430, 1),
	ST(0x1430, 1),
	ST(0x1458, 1),
	ST(0x1458, 1),
@@ -73,8 +75,12 @@ static const struct {
	ST(0x16c0, 8),
	ST(0x16c0, 8),
	ST(0x16e0, 8),
	ST(0x16e0, 8),
	ST(0x1740, 8),
	ST(0x1740, 8),
	ST(0x17c0, 8),
	ST(0x17e0, 8),
	ST(0x2400, 14 * 16),
	ST(0x2400, 14 * 16),
	ST(0x10800, 32 * 16),
	ST(0x10800, 32 * 16),
	ST(0x14600, 16),
	ST(0x14800, 8 * 8),
#undef ST
#undef ST
};
};


+153 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2017 Etnaviv Project
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <drm/drm_mm.h>

#include "etnaviv_cmdbuf.h"
#include "etnaviv_gpu.h"
#include "etnaviv_mmu.h"

#define SUBALLOC_SIZE		SZ_256K
#define SUBALLOC_GRANULE	SZ_4K
#define SUBALLOC_GRANULES	(SUBALLOC_SIZE / SUBALLOC_GRANULE)

struct etnaviv_cmdbuf_suballoc {
	/* suballocated dma buffer properties */
	struct etnaviv_gpu *gpu;
	void *vaddr;
	dma_addr_t paddr;

	/* GPU mapping */
	u32 iova;
	struct drm_mm_node vram_node; /* only used on MMUv2 */

	/* allocation management */
	struct mutex lock;
	DECLARE_BITMAP(granule_map, SUBALLOC_GRANULES);
	int free_space;
	wait_queue_head_t free_event;
};

struct etnaviv_cmdbuf_suballoc *
etnaviv_cmdbuf_suballoc_new(struct etnaviv_gpu * gpu)
{
	struct etnaviv_cmdbuf_suballoc *suballoc;
	int ret;

	suballoc = kzalloc(sizeof(*suballoc), GFP_KERNEL);
	if (!suballoc)
		return ERR_PTR(-ENOMEM);

	suballoc->gpu = gpu;
	mutex_init(&suballoc->lock);
	init_waitqueue_head(&suballoc->free_event);

	suballoc->vaddr = dma_alloc_wc(gpu->dev, SUBALLOC_SIZE,
				       &suballoc->paddr, GFP_KERNEL);
	if (!suballoc->vaddr)
		goto free_suballoc;

	ret = etnaviv_iommu_get_suballoc_va(gpu, suballoc->paddr,
					    &suballoc->vram_node, SUBALLOC_SIZE,
					    &suballoc->iova);
	if (ret)
		goto free_dma;

	return suballoc;

free_dma:
	dma_free_wc(gpu->dev, SUBALLOC_SIZE, suballoc->vaddr, suballoc->paddr);
free_suballoc:
	kfree(suballoc);

	return NULL;
}

void etnaviv_cmdbuf_suballoc_destroy(struct etnaviv_cmdbuf_suballoc *suballoc)
{
	etnaviv_iommu_put_suballoc_va(suballoc->gpu, &suballoc->vram_node,
				      SUBALLOC_SIZE, suballoc->iova);
	dma_free_wc(suballoc->gpu->dev, SUBALLOC_SIZE, suballoc->vaddr,
		    suballoc->paddr);
	kfree(suballoc);
}

struct etnaviv_cmdbuf *
etnaviv_cmdbuf_new(struct etnaviv_cmdbuf_suballoc *suballoc, u32 size,
		   size_t nr_bos)
{
	struct etnaviv_cmdbuf *cmdbuf;
	size_t sz = size_vstruct(nr_bos, sizeof(cmdbuf->bo_map[0]),
				 sizeof(*cmdbuf));
	int granule_offs, order, ret;

	cmdbuf = kzalloc(sz, GFP_KERNEL);
	if (!cmdbuf)
		return NULL;

	cmdbuf->suballoc = suballoc;
	cmdbuf->size = size;

	order = order_base_2(ALIGN(size, SUBALLOC_GRANULE) / SUBALLOC_GRANULE);
retry:
	mutex_lock(&suballoc->lock);
	granule_offs = bitmap_find_free_region(suballoc->granule_map,
					SUBALLOC_GRANULES, order);
	if (granule_offs < 0) {
		suballoc->free_space = 0;
		mutex_unlock(&suballoc->lock);
		ret = wait_event_interruptible_timeout(suballoc->free_event,
						       suballoc->free_space,
						       msecs_to_jiffies(10 * 1000));
		if (!ret) {
			dev_err(suballoc->gpu->dev,
				"Timeout waiting for cmdbuf space\n");
			return NULL;
		}
		goto retry;
	}
	mutex_unlock(&suballoc->lock);
	cmdbuf->suballoc_offset = granule_offs * SUBALLOC_GRANULE;
	cmdbuf->vaddr = suballoc->vaddr + cmdbuf->suballoc_offset;

	return cmdbuf;
}

void etnaviv_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf)
{
	struct etnaviv_cmdbuf_suballoc *suballoc = cmdbuf->suballoc;
	int order = order_base_2(ALIGN(cmdbuf->size, SUBALLOC_GRANULE) /
				 SUBALLOC_GRANULE);

	mutex_lock(&suballoc->lock);
	bitmap_release_region(suballoc->granule_map,
			      cmdbuf->suballoc_offset / SUBALLOC_GRANULE,
			      order);
	suballoc->free_space = 1;
	mutex_unlock(&suballoc->lock);
	wake_up_all(&suballoc->free_event);
	kfree(cmdbuf);
}

u32 etnaviv_cmdbuf_get_va(struct etnaviv_cmdbuf *buf)
{
	return buf->suballoc->iova + buf->suballoc_offset;
}

dma_addr_t etnaviv_cmdbuf_get_pa(struct etnaviv_cmdbuf *buf)
{
	return buf->suballoc->paddr + buf->suballoc_offset;
}
+58 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2017 Etnaviv Project
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __ETNAVIV_CMDBUF_H__
#define __ETNAVIV_CMDBUF_H__

#include <linux/types.h>

struct etnaviv_gpu;
struct etnaviv_cmdbuf_suballoc;

struct etnaviv_cmdbuf {
	/* suballocator this cmdbuf is allocated from */
	struct etnaviv_cmdbuf_suballoc *suballoc;
	/* user context key, must be unique between all active users */
	struct etnaviv_file_private *ctx;
	/* cmdbuf properties */
	int suballoc_offset;
	void *vaddr;
	u32 size;
	u32 user_size;
	/* fence after which this buffer is to be disposed */
	struct dma_fence *fence;
	/* target exec state */
	u32 exec_state;
	/* per GPU in-flight list */
	struct list_head node;
	/* BOs attached to this command buffer */
	unsigned int nr_bos;
	struct etnaviv_vram_mapping *bo_map[0];
};

struct etnaviv_cmdbuf_suballoc *
etnaviv_cmdbuf_suballoc_new(struct etnaviv_gpu * gpu);
void etnaviv_cmdbuf_suballoc_destroy(struct etnaviv_cmdbuf_suballoc *suballoc);

struct etnaviv_cmdbuf *
etnaviv_cmdbuf_new(struct etnaviv_cmdbuf_suballoc *suballoc, u32 size,
		   size_t nr_bos);
void etnaviv_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf);

u32 etnaviv_cmdbuf_get_va(struct etnaviv_cmdbuf *buf);
dma_addr_t etnaviv_cmdbuf_get_pa(struct etnaviv_cmdbuf *buf);

#endif /* __ETNAVIV_CMDBUF_H__ */
Loading