Skip to content

Commit

Permalink
Merge branch 'drm-etnaviv-next' of https://git.pengutronix.de/git/lst…
Browse files Browse the repository at this point in the history
…/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
  • Loading branch information
Dave Airlie committed Feb 2, 2017
2 parents 18566ac + 8226036 commit 99743ae
Show file tree
Hide file tree
Showing 14 changed files with 329 additions and 123 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/etnaviv/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
etnaviv-y := \
etnaviv_buffer.o \
etnaviv_cmd_parser.o \
etnaviv_cmdbuf.o \
etnaviv_drv.o \
etnaviv_dump.o \
etnaviv_gem_prime.o \
Expand Down
14 changes: 8 additions & 6 deletions drivers/gpu/drm/etnaviv/etnaviv_buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/

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

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,
ptr, len * 4, 0);
Expand Down Expand Up @@ -158,7 +159,7 @@ static u32 etnaviv_buffer_reserve(struct etnaviv_gpu *gpu,
if (buffer->user_size + cmd_dwords * sizeof(u64) > buffer->size)
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)
Expand All @@ -169,7 +170,7 @@ u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu)
buffer->user_size = 0;

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);

return buffer->user_size / 8;
Expand Down Expand Up @@ -261,7 +262,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
if (drm_debug & DRM_UT_DRIVER)
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;

/*
Expand Down Expand Up @@ -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) |
VIVS_GL_EVENT_FROM_PE);
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);

if (drm_debug & DRM_UT_DRIVER)
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) {
print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4,
Expand Down
6 changes: 6 additions & 0 deletions drivers/gpu/drm/etnaviv/etnaviv_cmd_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ static const struct {
ST(0x0644, 1),
ST(0x064c, 1),
ST(0x0680, 8),
ST(0x086c, 1),
ST(0x1028, 1),
ST(0x1410, 1),
ST(0x1430, 1),
ST(0x1458, 1),
Expand All @@ -73,8 +75,12 @@ static const struct {
ST(0x16c0, 8),
ST(0x16e0, 8),
ST(0x1740, 8),
ST(0x17c0, 8),
ST(0x17e0, 8),
ST(0x2400, 14 * 16),
ST(0x10800, 32 * 16),
ST(0x14600, 16),
ST(0x14800, 8 * 8),
#undef ST
};

Expand Down
153 changes: 153 additions & 0 deletions drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
* 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 changes: 58 additions & 0 deletions drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* 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__ */
5 changes: 3 additions & 2 deletions drivers/gpu/drm/etnaviv/etnaviv_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
#include <linux/of_platform.h>
#include <drm/drm_of.h>

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

#ifdef CONFIG_DRM_ETNAVIV_REGISTER_LOGGING
static bool reglog;
Expand Down Expand Up @@ -177,7 +177,8 @@ static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu, struct seq_file *m)
u32 i;

seq_printf(m, "virt %p - phys 0x%llx - free 0x%08x\n",
buf->vaddr, (u64)buf->paddr, size - buf->user_size);
buf->vaddr, (u64)etnaviv_cmdbuf_get_pa(buf),
size - buf->user_size);

for (i = 0; i < size / 4; i++) {
if (i && !(i % 4))
Expand Down
6 changes: 3 additions & 3 deletions drivers/gpu/drm/etnaviv/etnaviv_dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

#include <linux/devcoredump.h>
#include "etnaviv_cmdbuf.h"
#include "etnaviv_dump.h"
#include "etnaviv_gem.h"
#include "etnaviv_gpu.h"
Expand Down Expand Up @@ -177,12 +178,11 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu)
etnaviv_core_dump_mmu(&iter, gpu, mmu_size);
etnaviv_core_dump_mem(&iter, ETDUMP_BUF_RING, gpu->buffer->vaddr,
gpu->buffer->size,
etnaviv_iommu_get_cmdbuf_va(gpu, gpu->buffer));
etnaviv_cmdbuf_get_va(gpu->buffer));

list_for_each_entry(cmd, &gpu->active_cmd_list, node)
etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD, cmd->vaddr,
cmd->size,
etnaviv_iommu_get_cmdbuf_va(gpu, cmd));
cmd->size, etnaviv_cmdbuf_get_va(cmd));

/* Reserve space for the bomap */
if (n_bomap_pages) {
Expand Down
8 changes: 5 additions & 3 deletions drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

#include <linux/reservation.h>
#include "etnaviv_cmdbuf.h"
#include "etnaviv_drv.h"
#include "etnaviv_gpu.h"
#include "etnaviv_gem.h"
Expand Down Expand Up @@ -332,8 +333,9 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
bos = drm_malloc_ab(args->nr_bos, sizeof(*bos));
relocs = drm_malloc_ab(args->nr_relocs, sizeof(*relocs));
stream = drm_malloc_ab(1, args->stream_size);
cmdbuf = etnaviv_gpu_cmdbuf_new(gpu, ALIGN(args->stream_size, 8) + 8,
args->nr_bos);
cmdbuf = etnaviv_cmdbuf_new(gpu->cmdbuf_suballoc,
ALIGN(args->stream_size, 8) + 8,
args->nr_bos);
if (!bos || !relocs || !stream || !cmdbuf) {
ret = -ENOMEM;
goto err_submit_cmds;
Expand Down Expand Up @@ -422,7 +424,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
err_submit_cmds:
/* if we still own the cmdbuf */
if (cmdbuf)
etnaviv_gpu_cmdbuf_free(cmdbuf);
etnaviv_cmdbuf_free(cmdbuf);
if (stream)
drm_free_large(stream);
if (bos)
Expand Down
Loading

0 comments on commit 99743ae

Please sign in to comment.