aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2017-02-02 14:41:58 -0500
committerDave Airlie <airlied@redhat.com>2017-02-02 14:41:58 -0500
commit99743ae4c5f52f8f8ceb17783056fcc9b4f8b64c (patch)
tree73c1a0d450585800d40d3dec4d37f6e52fb1353e
parent18566acac18f5784347bc5fe636a26897d1c963b (diff)
parent82260364fd0c7822c782771374cb4a4deb00d3f6 (diff)
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
-rw-r--r--drivers/gpu/drm/etnaviv/Makefile1
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_buffer.c14
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_cmd_parser.c6
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c153
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.h58
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_drv.c5
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_dump.c6
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c8
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gpu.c95
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gpu.h28
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_iommu.c2
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c6
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_mmu.c60
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_mmu.h10
14 files changed, 329 insertions, 123 deletions
diff --git a/drivers/gpu/drm/etnaviv/Makefile b/drivers/gpu/drm/etnaviv/Makefile
index 1086e9876f91..4f76c992043f 100644
--- a/drivers/gpu/drm/etnaviv/Makefile
+++ b/drivers/gpu/drm/etnaviv/Makefile
@@ -1,6 +1,7 @@
1etnaviv-y := \ 1etnaviv-y := \
2 etnaviv_buffer.o \ 2 etnaviv_buffer.o \
3 etnaviv_cmd_parser.o \ 3 etnaviv_cmd_parser.o \
4 etnaviv_cmdbuf.o \
4 etnaviv_drv.o \ 5 etnaviv_drv.o \
5 etnaviv_dump.o \ 6 etnaviv_dump.o \
6 etnaviv_gem_prime.o \ 7 etnaviv_gem_prime.o \
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c
index d9230132dfbc..ed9588f36bc9 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c
@@ -15,6 +15,7 @@
15 * this program. If not, see <http://www.gnu.org/licenses/>. 15 * this program. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18#include "etnaviv_cmdbuf.h"
18#include "etnaviv_gpu.h" 19#include "etnaviv_gpu.h"
19#include "etnaviv_gem.h" 20#include "etnaviv_gem.h"
20#include "etnaviv_mmu.h" 21#include "etnaviv_mmu.h"
@@ -125,7 +126,7 @@ static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu,
125 u32 *ptr = buf->vaddr + off; 126 u32 *ptr = buf->vaddr + off;
126 127
127 dev_info(gpu->dev, "virt %p phys 0x%08x free 0x%08x\n", 128 dev_info(gpu->dev, "virt %p phys 0x%08x free 0x%08x\n",
128 ptr, etnaviv_iommu_get_cmdbuf_va(gpu, buf) + off, size - len * 4 - off); 129 ptr, etnaviv_cmdbuf_get_va(buf) + off, size - len * 4 - off);
129 130
130 print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4, 131 print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4,
131 ptr, len * 4, 0); 132 ptr, len * 4, 0);
@@ -158,7 +159,7 @@ static u32 etnaviv_buffer_reserve(struct etnaviv_gpu *gpu,
158 if (buffer->user_size + cmd_dwords * sizeof(u64) > buffer->size) 159 if (buffer->user_size + cmd_dwords * sizeof(u64) > buffer->size)
159 buffer->user_size = 0; 160 buffer->user_size = 0;
160 161
161 return etnaviv_iommu_get_cmdbuf_va(gpu, buffer) + buffer->user_size; 162 return etnaviv_cmdbuf_get_va(buffer) + buffer->user_size;
162} 163}
163 164
164u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu) 165u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu)
@@ -169,7 +170,7 @@ u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu)
169 buffer->user_size = 0; 170 buffer->user_size = 0;
170 171
171 CMD_WAIT(buffer); 172 CMD_WAIT(buffer);
172 CMD_LINK(buffer, 2, etnaviv_iommu_get_cmdbuf_va(gpu, buffer) + 173 CMD_LINK(buffer, 2, etnaviv_cmdbuf_get_va(buffer) +
173 buffer->user_size - 4); 174 buffer->user_size - 4);
174 175
175 return buffer->user_size / 8; 176 return buffer->user_size / 8;
@@ -261,7 +262,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
261 if (drm_debug & DRM_UT_DRIVER) 262 if (drm_debug & DRM_UT_DRIVER)
262 etnaviv_buffer_dump(gpu, buffer, 0, 0x50); 263 etnaviv_buffer_dump(gpu, buffer, 0, 0x50);
263 264
264 link_target = etnaviv_iommu_get_cmdbuf_va(gpu, cmdbuf); 265 link_target = etnaviv_cmdbuf_get_va(cmdbuf);
265 link_dwords = cmdbuf->size / 8; 266 link_dwords = cmdbuf->size / 8;
266 267
267 /* 268 /*
@@ -355,12 +356,13 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
355 CMD_LOAD_STATE(buffer, VIVS_GL_EVENT, VIVS_GL_EVENT_EVENT_ID(event) | 356 CMD_LOAD_STATE(buffer, VIVS_GL_EVENT, VIVS_GL_EVENT_EVENT_ID(event) |
356 VIVS_GL_EVENT_FROM_PE); 357 VIVS_GL_EVENT_FROM_PE);
357 CMD_WAIT(buffer); 358 CMD_WAIT(buffer);
358 CMD_LINK(buffer, 2, etnaviv_iommu_get_cmdbuf_va(gpu, buffer) + 359 CMD_LINK(buffer, 2, etnaviv_cmdbuf_get_va(buffer) +
359 buffer->user_size - 4); 360 buffer->user_size - 4);
360 361
361 if (drm_debug & DRM_UT_DRIVER) 362 if (drm_debug & DRM_UT_DRIVER)
362 pr_info("stream link to 0x%08x @ 0x%08x %p\n", 363 pr_info("stream link to 0x%08x @ 0x%08x %p\n",
363 return_target, etnaviv_iommu_get_cmdbuf_va(gpu, cmdbuf), cmdbuf->vaddr); 364 return_target, etnaviv_cmdbuf_get_va(cmdbuf),
365 cmdbuf->vaddr);
364 366
365 if (drm_debug & DRM_UT_DRIVER) { 367 if (drm_debug & DRM_UT_DRIVER) {
366 print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4, 368 print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4,
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_cmd_parser.c b/drivers/gpu/drm/etnaviv/etnaviv_cmd_parser.c
index 2a2e5e366ab7..6e3bbcf24160 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_cmd_parser.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_cmd_parser.c
@@ -56,6 +56,8 @@ static const struct {
56 ST(0x0644, 1), 56 ST(0x0644, 1),
57 ST(0x064c, 1), 57 ST(0x064c, 1),
58 ST(0x0680, 8), 58 ST(0x0680, 8),
59 ST(0x086c, 1),
60 ST(0x1028, 1),
59 ST(0x1410, 1), 61 ST(0x1410, 1),
60 ST(0x1430, 1), 62 ST(0x1430, 1),
61 ST(0x1458, 1), 63 ST(0x1458, 1),
@@ -73,8 +75,12 @@ static const struct {
73 ST(0x16c0, 8), 75 ST(0x16c0, 8),
74 ST(0x16e0, 8), 76 ST(0x16e0, 8),
75 ST(0x1740, 8), 77 ST(0x1740, 8),
78 ST(0x17c0, 8),
79 ST(0x17e0, 8),
76 ST(0x2400, 14 * 16), 80 ST(0x2400, 14 * 16),
77 ST(0x10800, 32 * 16), 81 ST(0x10800, 32 * 16),
82 ST(0x14600, 16),
83 ST(0x14800, 8 * 8),
78#undef ST 84#undef ST
79}; 85};
80 86
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c b/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c
new file mode 100644
index 000000000000..633e0f07cbac
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c
@@ -0,0 +1,153 @@
1/*
2 * Copyright (C) 2017 Etnaviv Project
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <drm/drm_mm.h>
18
19#include "etnaviv_cmdbuf.h"
20#include "etnaviv_gpu.h"
21#include "etnaviv_mmu.h"
22
23#define SUBALLOC_SIZE SZ_256K
24#define SUBALLOC_GRANULE SZ_4K
25#define SUBALLOC_GRANULES (SUBALLOC_SIZE / SUBALLOC_GRANULE)
26
27struct etnaviv_cmdbuf_suballoc {
28 /* suballocated dma buffer properties */
29 struct etnaviv_gpu *gpu;
30 void *vaddr;
31 dma_addr_t paddr;
32
33 /* GPU mapping */
34 u32 iova;
35 struct drm_mm_node vram_node; /* only used on MMUv2 */
36
37 /* allocation management */
38 struct mutex lock;
39 DECLARE_BITMAP(granule_map, SUBALLOC_GRANULES);
40 int free_space;
41 wait_queue_head_t free_event;
42};
43
44struct etnaviv_cmdbuf_suballoc *
45etnaviv_cmdbuf_suballoc_new(struct etnaviv_gpu * gpu)
46{
47 struct etnaviv_cmdbuf_suballoc *suballoc;
48 int ret;
49
50 suballoc = kzalloc(sizeof(*suballoc), GFP_KERNEL);
51 if (!suballoc)
52 return ERR_PTR(-ENOMEM);
53
54 suballoc->gpu = gpu;
55 mutex_init(&suballoc->lock);
56 init_waitqueue_head(&suballoc->free_event);
57
58 suballoc->vaddr = dma_alloc_wc(gpu->dev, SUBALLOC_SIZE,
59 &suballoc->paddr, GFP_KERNEL);
60 if (!suballoc->vaddr)
61 goto free_suballoc;
62
63 ret = etnaviv_iommu_get_suballoc_va(gpu, suballoc->paddr,
64 &suballoc->vram_node, SUBALLOC_SIZE,
65 &suballoc->iova);
66 if (ret)
67 goto free_dma;
68
69 return suballoc;
70
71free_dma:
72 dma_free_wc(gpu->dev, SUBALLOC_SIZE, suballoc->vaddr, suballoc->paddr);
73free_suballoc:
74 kfree(suballoc);
75
76 return NULL;
77}
78
79void etnaviv_cmdbuf_suballoc_destroy(struct etnaviv_cmdbuf_suballoc *suballoc)
80{
81 etnaviv_iommu_put_suballoc_va(suballoc->gpu, &suballoc->vram_node,
82 SUBALLOC_SIZE, suballoc->iova);
83 dma_free_wc(suballoc->gpu->dev, SUBALLOC_SIZE, suballoc->vaddr,
84 suballoc->paddr);
85 kfree(suballoc);
86}
87
88struct etnaviv_cmdbuf *
89etnaviv_cmdbuf_new(struct etnaviv_cmdbuf_suballoc *suballoc, u32 size,
90 size_t nr_bos)
91{
92 struct etnaviv_cmdbuf *cmdbuf;
93 size_t sz = size_vstruct(nr_bos, sizeof(cmdbuf->bo_map[0]),
94 sizeof(*cmdbuf));
95 int granule_offs, order, ret;
96
97 cmdbuf = kzalloc(sz, GFP_KERNEL);
98 if (!cmdbuf)
99 return NULL;
100
101 cmdbuf->suballoc = suballoc;
102 cmdbuf->size = size;
103
104 order = order_base_2(ALIGN(size, SUBALLOC_GRANULE) / SUBALLOC_GRANULE);
105retry:
106 mutex_lock(&suballoc->lock);
107 granule_offs = bitmap_find_free_region(suballoc->granule_map,
108 SUBALLOC_GRANULES, order);
109 if (granule_offs < 0) {
110 suballoc->free_space = 0;
111 mutex_unlock(&suballoc->lock);
112 ret = wait_event_interruptible_timeout(suballoc->free_event,
113 suballoc->free_space,
114 msecs_to_jiffies(10 * 1000));
115 if (!ret) {
116 dev_err(suballoc->gpu->dev,
117 "Timeout waiting for cmdbuf space\n");
118 return NULL;
119 }
120 goto retry;
121 }
122 mutex_unlock(&suballoc->lock);
123 cmdbuf->suballoc_offset = granule_offs * SUBALLOC_GRANULE;
124 cmdbuf->vaddr = suballoc->vaddr + cmdbuf->suballoc_offset;
125
126 return cmdbuf;
127}
128
129void etnaviv_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf)
130{
131 struct etnaviv_cmdbuf_suballoc *suballoc = cmdbuf->suballoc;
132 int order = order_base_2(ALIGN(cmdbuf->size, SUBALLOC_GRANULE) /
133 SUBALLOC_GRANULE);
134
135 mutex_lock(&suballoc->lock);
136 bitmap_release_region(suballoc->granule_map,
137 cmdbuf->suballoc_offset / SUBALLOC_GRANULE,
138 order);
139 suballoc->free_space = 1;
140 mutex_unlock(&suballoc->lock);
141 wake_up_all(&suballoc->free_event);
142 kfree(cmdbuf);
143}
144
145u32 etnaviv_cmdbuf_get_va(struct etnaviv_cmdbuf *buf)
146{
147 return buf->suballoc->iova + buf->suballoc_offset;
148}
149
150dma_addr_t etnaviv_cmdbuf_get_pa(struct etnaviv_cmdbuf *buf)
151{
152 return buf->suballoc->paddr + buf->suballoc_offset;
153}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.h b/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.h
new file mode 100644
index 000000000000..80d78076c679
--- /dev/null
+++ b/drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.h
@@ -0,0 +1,58 @@
1/*
2 * Copyright (C) 2017 Etnaviv Project
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef __ETNAVIV_CMDBUF_H__
18#define __ETNAVIV_CMDBUF_H__
19
20#include <linux/types.h>
21
22struct etnaviv_gpu;
23struct etnaviv_cmdbuf_suballoc;
24
25struct etnaviv_cmdbuf {
26 /* suballocator this cmdbuf is allocated from */
27 struct etnaviv_cmdbuf_suballoc *suballoc;
28 /* user context key, must be unique between all active users */
29 struct etnaviv_file_private *ctx;
30 /* cmdbuf properties */
31 int suballoc_offset;
32 void *vaddr;
33 u32 size;
34 u32 user_size;
35 /* fence after which this buffer is to be disposed */
36 struct dma_fence *fence;
37 /* target exec state */
38 u32 exec_state;
39 /* per GPU in-flight list */
40 struct list_head node;
41 /* BOs attached to this command buffer */
42 unsigned int nr_bos;
43 struct etnaviv_vram_mapping *bo_map[0];
44};
45
46struct etnaviv_cmdbuf_suballoc *
47etnaviv_cmdbuf_suballoc_new(struct etnaviv_gpu * gpu);
48void etnaviv_cmdbuf_suballoc_destroy(struct etnaviv_cmdbuf_suballoc *suballoc);
49
50struct etnaviv_cmdbuf *
51etnaviv_cmdbuf_new(struct etnaviv_cmdbuf_suballoc *suballoc, u32 size,
52 size_t nr_bos);
53void etnaviv_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf);
54
55u32 etnaviv_cmdbuf_get_va(struct etnaviv_cmdbuf *buf);
56dma_addr_t etnaviv_cmdbuf_get_pa(struct etnaviv_cmdbuf *buf);
57
58#endif /* __ETNAVIV_CMDBUF_H__ */
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
index 590be0d1dd95..587e45043542 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c
@@ -18,11 +18,11 @@
18#include <linux/of_platform.h> 18#include <linux/of_platform.h>
19#include <drm/drm_of.h> 19#include <drm/drm_of.h>
20 20
21#include "etnaviv_cmdbuf.h"
21#include "etnaviv_drv.h" 22#include "etnaviv_drv.h"
22#include "etnaviv_gpu.h" 23#include "etnaviv_gpu.h"
23#include "etnaviv_gem.h" 24#include "etnaviv_gem.h"
24#include "etnaviv_mmu.h" 25#include "etnaviv_mmu.h"
25#include "etnaviv_gem.h"
26 26
27#ifdef CONFIG_DRM_ETNAVIV_REGISTER_LOGGING 27#ifdef CONFIG_DRM_ETNAVIV_REGISTER_LOGGING
28static bool reglog; 28static bool reglog;
@@ -177,7 +177,8 @@ static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu, struct seq_file *m)
177 u32 i; 177 u32 i;
178 178
179 seq_printf(m, "virt %p - phys 0x%llx - free 0x%08x\n", 179 seq_printf(m, "virt %p - phys 0x%llx - free 0x%08x\n",
180 buf->vaddr, (u64)buf->paddr, size - buf->user_size); 180 buf->vaddr, (u64)etnaviv_cmdbuf_get_pa(buf),
181 size - buf->user_size);
181 182
182 for (i = 0; i < size / 4; i++) { 183 for (i = 0; i < size / 4; i++) {
183 if (i && !(i % 4)) 184 if (i && !(i % 4))
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_dump.c b/drivers/gpu/drm/etnaviv/etnaviv_dump.c
index af65491a78e2..d019b5e311cc 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_dump.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_dump.c
@@ -15,6 +15,7 @@
15 */ 15 */
16 16
17#include <linux/devcoredump.h> 17#include <linux/devcoredump.h>
18#include "etnaviv_cmdbuf.h"
18#include "etnaviv_dump.h" 19#include "etnaviv_dump.h"
19#include "etnaviv_gem.h" 20#include "etnaviv_gem.h"
20#include "etnaviv_gpu.h" 21#include "etnaviv_gpu.h"
@@ -177,12 +178,11 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu)
177 etnaviv_core_dump_mmu(&iter, gpu, mmu_size); 178 etnaviv_core_dump_mmu(&iter, gpu, mmu_size);
178 etnaviv_core_dump_mem(&iter, ETDUMP_BUF_RING, gpu->buffer->vaddr, 179 etnaviv_core_dump_mem(&iter, ETDUMP_BUF_RING, gpu->buffer->vaddr,
179 gpu->buffer->size, 180 gpu->buffer->size,
180 etnaviv_iommu_get_cmdbuf_va(gpu, gpu->buffer)); 181 etnaviv_cmdbuf_get_va(gpu->buffer));
181 182
182 list_for_each_entry(cmd, &gpu->active_cmd_list, node) 183 list_for_each_entry(cmd, &gpu->active_cmd_list, node)
183 etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD, cmd->vaddr, 184 etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD, cmd->vaddr,
184 cmd->size, 185 cmd->size, etnaviv_cmdbuf_get_va(cmd));
185 etnaviv_iommu_get_cmdbuf_va(gpu, cmd));
186 186
187 /* Reserve space for the bomap */ 187 /* Reserve space for the bomap */
188 if (n_bomap_pages) { 188 if (n_bomap_pages) {
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
index afdd55ddf821..726090d7a6ac 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
@@ -15,6 +15,7 @@
15 */ 15 */
16 16
17#include <linux/reservation.h> 17#include <linux/reservation.h>
18#include "etnaviv_cmdbuf.h"
18#include "etnaviv_drv.h" 19#include "etnaviv_drv.h"
19#include "etnaviv_gpu.h" 20#include "etnaviv_gpu.h"
20#include "etnaviv_gem.h" 21#include "etnaviv_gem.h"
@@ -332,8 +333,9 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
332 bos = drm_malloc_ab(args->nr_bos, sizeof(*bos)); 333 bos = drm_malloc_ab(args->nr_bos, sizeof(*bos));
333 relocs = drm_malloc_ab(args->nr_relocs, sizeof(*relocs)); 334 relocs = drm_malloc_ab(args->nr_relocs, sizeof(*relocs));
334 stream = drm_malloc_ab(1, args->stream_size); 335 stream = drm_malloc_ab(1, args->stream_size);
335 cmdbuf = etnaviv_gpu_cmdbuf_new(gpu, ALIGN(args->stream_size, 8) + 8, 336 cmdbuf = etnaviv_cmdbuf_new(gpu->cmdbuf_suballoc,
336 args->nr_bos); 337 ALIGN(args->stream_size, 8) + 8,
338 args->nr_bos);
337 if (!bos || !relocs || !stream || !cmdbuf) { 339 if (!bos || !relocs || !stream || !cmdbuf) {
338 ret = -ENOMEM; 340 ret = -ENOMEM;
339 goto err_submit_cmds; 341 goto err_submit_cmds;
@@ -422,7 +424,7 @@ err_submit_objects:
422err_submit_cmds: 424err_submit_cmds:
423 /* if we still own the cmdbuf */ 425 /* if we still own the cmdbuf */
424 if (cmdbuf) 426 if (cmdbuf)
425 etnaviv_gpu_cmdbuf_free(cmdbuf); 427 etnaviv_cmdbuf_free(cmdbuf);
426 if (stream) 428 if (stream)
427 drm_free_large(stream); 429 drm_free_large(stream);
428 if (bos) 430 if (bos)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 0a67124bb2a4..130d7d517a19 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -18,6 +18,8 @@
18#include <linux/dma-fence.h> 18#include <linux/dma-fence.h>
19#include <linux/moduleparam.h> 19#include <linux/moduleparam.h>
20#include <linux/of_device.h> 20#include <linux/of_device.h>
21
22#include "etnaviv_cmdbuf.h"
21#include "etnaviv_dump.h" 23#include "etnaviv_dump.h"
22#include "etnaviv_gpu.h" 24#include "etnaviv_gpu.h"
23#include "etnaviv_gem.h" 25#include "etnaviv_gem.h"
@@ -546,6 +548,37 @@ void etnaviv_gpu_start_fe(struct etnaviv_gpu *gpu, u32 address, u16 prefetch)
546 VIVS_FE_COMMAND_CONTROL_PREFETCH(prefetch)); 548 VIVS_FE_COMMAND_CONTROL_PREFETCH(prefetch));
547} 549}
548 550
551static void etnaviv_gpu_setup_pulse_eater(struct etnaviv_gpu *gpu)
552{
553 /*
554 * Base value for VIVS_PM_PULSE_EATER register on models where it
555 * cannot be read, extracted from vivante kernel driver.
556 */
557 u32 pulse_eater = 0x01590880;
558
559 if (etnaviv_is_model_rev(gpu, GC4000, 0x5208) ||
560 etnaviv_is_model_rev(gpu, GC4000, 0x5222)) {
561 pulse_eater |= BIT(23);
562
563 }
564
565 if (etnaviv_is_model_rev(gpu, GC1000, 0x5039) ||
566 etnaviv_is_model_rev(gpu, GC1000, 0x5040)) {
567 pulse_eater &= ~BIT(16);
568 pulse_eater |= BIT(17);
569 }
570
571 if ((gpu->identity.revision > 0x5420) &&
572 (gpu->identity.features & chipFeatures_PIPE_3D))
573 {
574 /* Performance fix: disable internal DFS */
575 pulse_eater = gpu_read(gpu, VIVS_PM_PULSE_EATER);
576 pulse_eater |= BIT(18);
577 }
578
579 gpu_write(gpu, VIVS_PM_PULSE_EATER, pulse_eater);
580}
581
549static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu) 582static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
550{ 583{
551 u16 prefetch; 584 u16 prefetch;
@@ -586,6 +619,9 @@ static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
586 gpu_write(gpu, VIVS_MC_BUS_CONFIG, bus_config); 619 gpu_write(gpu, VIVS_MC_BUS_CONFIG, bus_config);
587 } 620 }
588 621
622 /* setup the pulse eater */
623 etnaviv_gpu_setup_pulse_eater(gpu);
624
589 /* setup the MMU */ 625 /* setup the MMU */
590 etnaviv_iommu_restore(gpu); 626 etnaviv_iommu_restore(gpu);
591 627
@@ -593,7 +629,7 @@ static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
593 prefetch = etnaviv_buffer_init(gpu); 629 prefetch = etnaviv_buffer_init(gpu);
594 630
595 gpu_write(gpu, VIVS_HI_INTR_ENBL, ~0U); 631 gpu_write(gpu, VIVS_HI_INTR_ENBL, ~0U);
596 etnaviv_gpu_start_fe(gpu, etnaviv_iommu_get_cmdbuf_va(gpu, gpu->buffer), 632 etnaviv_gpu_start_fe(gpu, etnaviv_cmdbuf_get_va(gpu->buffer),
597 prefetch); 633 prefetch);
598} 634}
599 635
@@ -658,8 +694,15 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
658 goto fail; 694 goto fail;
659 } 695 }
660 696
697 gpu->cmdbuf_suballoc = etnaviv_cmdbuf_suballoc_new(gpu);
698 if (IS_ERR(gpu->cmdbuf_suballoc)) {
699 dev_err(gpu->dev, "Failed to create cmdbuf suballocator\n");
700 ret = PTR_ERR(gpu->cmdbuf_suballoc);
701 goto fail;
702 }
703
661 /* Create buffer: */ 704 /* Create buffer: */
662 gpu->buffer = etnaviv_gpu_cmdbuf_new(gpu, PAGE_SIZE, 0); 705 gpu->buffer = etnaviv_cmdbuf_new(gpu->cmdbuf_suballoc, PAGE_SIZE, 0);
663 if (!gpu->buffer) { 706 if (!gpu->buffer) {
664 ret = -ENOMEM; 707 ret = -ENOMEM;
665 dev_err(gpu->dev, "could not create command buffer\n"); 708 dev_err(gpu->dev, "could not create command buffer\n");
@@ -667,7 +710,7 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
667 } 710 }
668 711
669 if (gpu->mmu->version == ETNAVIV_IOMMU_V1 && 712 if (gpu->mmu->version == ETNAVIV_IOMMU_V1 &&
670 gpu->buffer->paddr - gpu->memory_base > 0x80000000) { 713 etnaviv_cmdbuf_get_va(gpu->buffer) > 0x80000000) {
671 ret = -EINVAL; 714 ret = -EINVAL;
672 dev_err(gpu->dev, 715 dev_err(gpu->dev,
673 "command buffer outside valid memory window\n"); 716 "command buffer outside valid memory window\n");
@@ -694,7 +737,7 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
694 return 0; 737 return 0;
695 738
696free_buffer: 739free_buffer:
697 etnaviv_gpu_cmdbuf_free(gpu->buffer); 740 etnaviv_cmdbuf_free(gpu->buffer);
698 gpu->buffer = NULL; 741 gpu->buffer = NULL;
699destroy_iommu: 742destroy_iommu:
700 etnaviv_iommu_destroy(gpu->mmu); 743 etnaviv_iommu_destroy(gpu->mmu);
@@ -1117,41 +1160,6 @@ static void event_free(struct etnaviv_gpu *gpu, unsigned int event)
1117 * Cmdstream submission/retirement: 1160 * Cmdstream submission/retirement:
1118 */ 1161 */
1119 1162
1120struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu, u32 size,
1121 size_t nr_bos)
1122{
1123 struct etnaviv_cmdbuf *cmdbuf;
1124 size_t sz = size_vstruct(nr_bos, sizeof(cmdbuf->bo_map[0]),
1125 sizeof(*cmdbuf));
1126
1127 cmdbuf = kzalloc(sz, GFP_KERNEL);
1128 if (!cmdbuf)
1129 return NULL;
1130
1131 if (gpu->mmu->version == ETNAVIV_IOMMU_V2)
1132 size = ALIGN(size, SZ_4K);
1133
1134 cmdbuf->vaddr = dma_alloc_wc(gpu->dev, size, &cmdbuf->paddr,
1135 GFP_KERNEL);
1136 if (!cmdbuf->vaddr) {
1137 kfree(cmdbuf);
1138 return NULL;
1139 }
1140
1141 cmdbuf->gpu = gpu;
1142 cmdbuf->size = size;
1143
1144 return cmdbuf;
1145}
1146
1147void etnaviv_gpu_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf)
1148{
1149 etnaviv_iommu_put_cmdbuf_va(cmdbuf->gpu, cmdbuf);
1150 dma_free_wc(cmdbuf->gpu->dev, cmdbuf->size, cmdbuf->vaddr,
1151 cmdbuf->paddr);
1152 kfree(cmdbuf);
1153}
1154
1155static void retire_worker(struct work_struct *work) 1163static void retire_worker(struct work_struct *work)
1156{ 1164{
1157 struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu, 1165 struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
@@ -1177,7 +1185,7 @@ static void retire_worker(struct work_struct *work)
1177 etnaviv_gem_mapping_unreference(mapping); 1185 etnaviv_gem_mapping_unreference(mapping);
1178 } 1186 }
1179 1187
1180 etnaviv_gpu_cmdbuf_free(cmdbuf); 1188 etnaviv_cmdbuf_free(cmdbuf);
1181 /* 1189 /*
1182 * We need to balance the runtime PM count caused by 1190 * We need to balance the runtime PM count caused by
1183 * each submission. Upon submission, we increment 1191 * each submission. Upon submission, we increment
@@ -1593,10 +1601,15 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master,
1593#endif 1601#endif
1594 1602
1595 if (gpu->buffer) { 1603 if (gpu->buffer) {
1596 etnaviv_gpu_cmdbuf_free(gpu->buffer); 1604 etnaviv_cmdbuf_free(gpu->buffer);
1597 gpu->buffer = NULL; 1605 gpu->buffer = NULL;
1598 } 1606 }
1599 1607
1608 if (gpu->cmdbuf_suballoc) {
1609 etnaviv_cmdbuf_suballoc_destroy(gpu->cmdbuf_suballoc);
1610 gpu->cmdbuf_suballoc = NULL;
1611 }
1612
1600 if (gpu->mmu) { 1613 if (gpu->mmu) {
1601 etnaviv_iommu_destroy(gpu->mmu); 1614 etnaviv_iommu_destroy(gpu->mmu);
1602 gpu->mmu = NULL; 1615 gpu->mmu = NULL;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
index 8c6b824e9d0a..1c0606ea7d5e 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
@@ -92,6 +92,7 @@ struct etnaviv_event {
92 struct dma_fence *fence; 92 struct dma_fence *fence;
93}; 93};
94 94
95struct etnaviv_cmdbuf_suballoc;
95struct etnaviv_cmdbuf; 96struct etnaviv_cmdbuf;
96 97
97struct etnaviv_gpu { 98struct etnaviv_gpu {
@@ -135,6 +136,7 @@ struct etnaviv_gpu {
135 int irq; 136 int irq;
136 137
137 struct etnaviv_iommu *mmu; 138 struct etnaviv_iommu *mmu;
139 struct etnaviv_cmdbuf_suballoc *cmdbuf_suballoc;
138 140
139 /* Power Control: */ 141 /* Power Control: */
140 struct clk *clk_bus; 142 struct clk *clk_bus;
@@ -150,29 +152,6 @@ struct etnaviv_gpu {
150 struct work_struct recover_work; 152 struct work_struct recover_work;
151}; 153};
152 154
153struct etnaviv_cmdbuf {
154 /* device this cmdbuf is allocated for */
155 struct etnaviv_gpu *gpu;
156 /* user context key, must be unique between all active users */
157 struct etnaviv_file_private *ctx;
158 /* cmdbuf properties */
159 void *vaddr;
160 dma_addr_t paddr;
161 u32 size;
162 u32 user_size;
163 /* vram node used if the cmdbuf is mapped through the MMUv2 */
164 struct drm_mm_node vram_node;
165 /* fence after which this buffer is to be disposed */
166 struct dma_fence *fence;
167 /* target exec state */
168 u32 exec_state;
169 /* per GPU in-flight list */
170 struct list_head node;
171 /* BOs attached to this command buffer */
172 unsigned int nr_bos;
173 struct etnaviv_vram_mapping *bo_map[0];
174};
175
176static inline void gpu_write(struct etnaviv_gpu *gpu, u32 reg, u32 data) 155static inline void gpu_write(struct etnaviv_gpu *gpu, u32 reg, u32 data)
177{ 156{
178 etnaviv_writel(data, gpu->mmio + reg); 157 etnaviv_writel(data, gpu->mmio + reg);
@@ -211,9 +190,6 @@ int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu,
211 struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout); 190 struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout);
212int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, 191int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
213 struct etnaviv_gem_submit *submit, struct etnaviv_cmdbuf *cmdbuf); 192 struct etnaviv_gem_submit *submit, struct etnaviv_cmdbuf *cmdbuf);
214struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu,
215 u32 size, size_t nr_bos);
216void etnaviv_gpu_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf);
217int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu); 193int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu);
218void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu); 194void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu);
219int etnaviv_gpu_wait_idle(struct etnaviv_gpu *gpu, unsigned int timeout_ms); 195int etnaviv_gpu_wait_idle(struct etnaviv_gpu *gpu, unsigned int timeout_ms);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_iommu.c b/drivers/gpu/drm/etnaviv/etnaviv_iommu.c
index 81f1583a7946..7a7c97f599d7 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_iommu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_iommu.c
@@ -184,7 +184,7 @@ static void etnaviv_iommuv1_dump(struct iommu_domain *domain, void *buf)
184 memcpy(buf, etnaviv_domain->pgtable.pgtable, PT_SIZE); 184 memcpy(buf, etnaviv_domain->pgtable.pgtable, PT_SIZE);
185} 185}
186 186
187static struct etnaviv_iommu_ops etnaviv_iommu_ops = { 187static const struct etnaviv_iommu_ops etnaviv_iommu_ops = {
188 .ops = { 188 .ops = {
189 .domain_free = etnaviv_domain_free, 189 .domain_free = etnaviv_domain_free,
190 .map = etnaviv_iommuv1_map, 190 .map = etnaviv_iommuv1_map,
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c b/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c
index 7e9c4d210a84..cbe447ac5974 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c
@@ -21,6 +21,7 @@
21#include <linux/dma-mapping.h> 21#include <linux/dma-mapping.h>
22#include <linux/bitops.h> 22#include <linux/bitops.h>
23 23
24#include "etnaviv_cmdbuf.h"
24#include "etnaviv_gpu.h" 25#include "etnaviv_gpu.h"
25#include "etnaviv_mmu.h" 26#include "etnaviv_mmu.h"
26#include "etnaviv_iommu.h" 27#include "etnaviv_iommu.h"
@@ -229,7 +230,7 @@ static void etnaviv_iommuv2_dump(struct iommu_domain *domain, void *buf)
229 memcpy(buf, etnaviv_domain->stlb_cpu[i], SZ_4K); 230 memcpy(buf, etnaviv_domain->stlb_cpu[i], SZ_4K);
230} 231}
231 232
232static struct etnaviv_iommu_ops etnaviv_iommu_ops = { 233static const struct etnaviv_iommu_ops etnaviv_iommu_ops = {
233 .ops = { 234 .ops = {
234 .domain_free = etnaviv_iommuv2_domain_free, 235 .domain_free = etnaviv_iommuv2_domain_free,
235 .map = etnaviv_iommuv2_map, 236 .map = etnaviv_iommuv2_map,
@@ -254,7 +255,8 @@ void etnaviv_iommuv2_restore(struct etnaviv_gpu *gpu)
254 prefetch = etnaviv_buffer_config_mmuv2(gpu, 255 prefetch = etnaviv_buffer_config_mmuv2(gpu,
255 (u32)etnaviv_domain->mtlb_dma, 256 (u32)etnaviv_domain->mtlb_dma,
256 (u32)etnaviv_domain->bad_page_dma); 257 (u32)etnaviv_domain->bad_page_dma);
257 etnaviv_gpu_start_fe(gpu, gpu->buffer->paddr, prefetch); 258 etnaviv_gpu_start_fe(gpu, (u32)etnaviv_cmdbuf_get_pa(gpu->buffer),
259 prefetch);
258 etnaviv_gpu_wait_idle(gpu, 100); 260 etnaviv_gpu_wait_idle(gpu, 100);
259 261
260 gpu_write(gpu, VIVS_MMUv2_CONTROL, VIVS_MMUv2_CONTROL_ENABLE); 262 gpu_write(gpu, VIVS_MMUv2_CONTROL, VIVS_MMUv2_CONTROL_ENABLE);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
index f503af462dad..ff826c16fb89 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c
@@ -15,6 +15,7 @@
15 */ 15 */
16 16
17#include "common.xml.h" 17#include "common.xml.h"
18#include "etnaviv_cmdbuf.h"
18#include "etnaviv_drv.h" 19#include "etnaviv_drv.h"
19#include "etnaviv_gem.h" 20#include "etnaviv_gem.h"
20#include "etnaviv_gpu.h" 21#include "etnaviv_gpu.h"
@@ -117,14 +118,9 @@ static int etnaviv_iommu_find_iova(struct etnaviv_iommu *mmu,
117 struct list_head list; 118 struct list_head list;
118 bool found; 119 bool found;
119 120
120 /*
121 * XXX: The DRM_MM_SEARCH_BELOW is really a hack to trick
122 * drm_mm into giving out a low IOVA after address space
123 * rollover. This needs a proper fix.
124 */
125 ret = drm_mm_insert_node_in_range(&mmu->mm, node, 121 ret = drm_mm_insert_node_in_range(&mmu->mm, node,
126 size, 0, mmu->last_iova, ~0UL, 122 size, 0, mmu->last_iova, ~0UL,
127 mmu->last_iova ? DRM_MM_SEARCH_DEFAULT : DRM_MM_SEARCH_BELOW); 123 DRM_MM_SEARCH_DEFAULT);
128 124
129 if (ret != -ENOSPC) 125 if (ret != -ENOSPC)
130 break; 126 break;
@@ -194,11 +190,8 @@ static int etnaviv_iommu_find_iova(struct etnaviv_iommu *mmu,
194 190
195 /* 191 /*
196 * We removed enough mappings so that the new allocation will 192 * We removed enough mappings so that the new allocation will
197 * succeed. Ensure that the MMU will be flushed before the 193 * succeed, retry the allocation one more time.
198 * associated commit requesting this mapping, and retry the
199 * allocation one more time.
200 */ 194 */
201 mmu->need_flush = true;
202 } 195 }
203 196
204 return ret; 197 return ret;
@@ -250,6 +243,7 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
250 } 243 }
251 244
252 list_add_tail(&mapping->mmu_node, &mmu->mappings); 245 list_add_tail(&mapping->mmu_node, &mmu->mappings);
246 mmu->need_flush = true;
253 mutex_unlock(&mmu->lock); 247 mutex_unlock(&mmu->lock);
254 248
255 return ret; 249 return ret;
@@ -267,6 +261,7 @@ void etnaviv_iommu_unmap_gem(struct etnaviv_iommu *mmu,
267 etnaviv_iommu_remove_mapping(mmu, mapping); 261 etnaviv_iommu_remove_mapping(mmu, mapping);
268 262
269 list_del(&mapping->mmu_node); 263 list_del(&mapping->mmu_node);
264 mmu->need_flush = true;
270 mutex_unlock(&mmu->lock); 265 mutex_unlock(&mmu->lock);
271} 266}
272 267
@@ -322,55 +317,50 @@ void etnaviv_iommu_restore(struct etnaviv_gpu *gpu)
322 etnaviv_iommuv2_restore(gpu); 317 etnaviv_iommuv2_restore(gpu);
323} 318}
324 319
325u32 etnaviv_iommu_get_cmdbuf_va(struct etnaviv_gpu *gpu, 320int etnaviv_iommu_get_suballoc_va(struct etnaviv_gpu *gpu, dma_addr_t paddr,
326 struct etnaviv_cmdbuf *buf) 321 struct drm_mm_node *vram_node, size_t size,
322 u32 *iova)
327{ 323{
328 struct etnaviv_iommu *mmu = gpu->mmu; 324 struct etnaviv_iommu *mmu = gpu->mmu;
329 325
330 if (mmu->version == ETNAVIV_IOMMU_V1) { 326 if (mmu->version == ETNAVIV_IOMMU_V1) {
331 return buf->paddr - gpu->memory_base; 327 *iova = paddr - gpu->memory_base;
328 return 0;
332 } else { 329 } else {
333 int ret; 330 int ret;
334 331
335 if (buf->vram_node.allocated)
336 return (u32)buf->vram_node.start;
337
338 mutex_lock(&mmu->lock); 332 mutex_lock(&mmu->lock);
339 ret = etnaviv_iommu_find_iova(mmu, &buf->vram_node, 333 ret = etnaviv_iommu_find_iova(mmu, vram_node, size);
340 buf->size + SZ_64K);
341 if (ret < 0) { 334 if (ret < 0) {
342 mutex_unlock(&mmu->lock); 335 mutex_unlock(&mmu->lock);
343 return 0; 336 return ret;
344 } 337 }
345 ret = iommu_map(mmu->domain, buf->vram_node.start, buf->paddr, 338 ret = iommu_map(mmu->domain, vram_node->start, paddr, size,
346 buf->size, IOMMU_READ); 339 IOMMU_READ);
347 if (ret < 0) { 340 if (ret < 0) {
348 drm_mm_remove_node(&buf->vram_node); 341 drm_mm_remove_node(vram_node);
349 mutex_unlock(&mmu->lock); 342 mutex_unlock(&mmu->lock);
350 return 0; 343 return ret;
351 } 344 }
352 /* 345 mmu->last_iova = vram_node->start + size;
353 * At least on GC3000 the FE MMU doesn't properly flush old TLB
354 * entries. Make sure to space the command buffers out in a way
355 * that the FE MMU prefetch won't load invalid entries.
356 */
357 mmu->last_iova = buf->vram_node.start + buf->size + SZ_64K;
358 gpu->mmu->need_flush = true; 346 gpu->mmu->need_flush = true;
359 mutex_unlock(&mmu->lock); 347 mutex_unlock(&mmu->lock);
360 348
361 return (u32)buf->vram_node.start; 349 *iova = (u32)vram_node->start;
350 return 0;
362 } 351 }
363} 352}
364 353
365void etnaviv_iommu_put_cmdbuf_va(struct etnaviv_gpu *gpu, 354void etnaviv_iommu_put_suballoc_va(struct etnaviv_gpu *gpu,
366 struct etnaviv_cmdbuf *buf) 355 struct drm_mm_node *vram_node, size_t size,
356 u32 iova)
367{ 357{
368 struct etnaviv_iommu *mmu = gpu->mmu; 358 struct etnaviv_iommu *mmu = gpu->mmu;
369 359
370 if (mmu->version == ETNAVIV_IOMMU_V2 && buf->vram_node.allocated) { 360 if (mmu->version == ETNAVIV_IOMMU_V2) {
371 mutex_lock(&mmu->lock); 361 mutex_lock(&mmu->lock);
372 iommu_unmap(mmu->domain, buf->vram_node.start, buf->size); 362 iommu_unmap(mmu->domain,iova, size);
373 drm_mm_remove_node(&buf->vram_node); 363 drm_mm_remove_node(vram_node);
374 mutex_unlock(&mmu->lock); 364 mutex_unlock(&mmu->lock);
375 } 365 }
376} 366}
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.h b/drivers/gpu/drm/etnaviv/etnaviv_mmu.h
index e787e49c9693..54be289e5981 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.h
@@ -62,10 +62,12 @@ void etnaviv_iommu_unmap_gem(struct etnaviv_iommu *mmu,
62 struct etnaviv_vram_mapping *mapping); 62 struct etnaviv_vram_mapping *mapping);
63void etnaviv_iommu_destroy(struct etnaviv_iommu *iommu); 63void etnaviv_iommu_destroy(struct etnaviv_iommu *iommu);
64 64
65u32 etnaviv_iommu_get_cmdbuf_va(struct etnaviv_gpu *gpu, 65int etnaviv_iommu_get_suballoc_va(struct etnaviv_gpu *gpu, dma_addr_t paddr,
66 struct etnaviv_cmdbuf *buf); 66 struct drm_mm_node *vram_node, size_t size,
67void etnaviv_iommu_put_cmdbuf_va(struct etnaviv_gpu *gpu, 67 u32 *iova);
68 struct etnaviv_cmdbuf *buf); 68void etnaviv_iommu_put_suballoc_va(struct etnaviv_gpu *gpu,
69 struct drm_mm_node *vram_node, size_t size,
70 u32 iova);
69 71
70size_t etnaviv_iommu_dump_size(struct etnaviv_iommu *iommu); 72size_t etnaviv_iommu_dump_size(struct etnaviv_iommu *iommu);
71void etnaviv_iommu_dump(struct etnaviv_iommu *iommu, void *buf); 73void etnaviv_iommu_dump(struct etnaviv_iommu *iommu, void *buf);