diff options
-rw-r--r-- | drivers/gpu/drm/etnaviv/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/etnaviv/etnaviv_buffer.c | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/etnaviv/etnaviv_cmd_parser.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.c | 153 | ||||
-rw-r--r-- | drivers/gpu/drm/etnaviv/etnaviv_cmdbuf.h | 58 | ||||
-rw-r--r-- | drivers/gpu/drm/etnaviv/etnaviv_drv.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/etnaviv/etnaviv_dump.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 95 | ||||
-rw-r--r-- | drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 28 | ||||
-rw-r--r-- | drivers/gpu/drm/etnaviv/etnaviv_iommu.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/etnaviv/etnaviv_iommu_v2.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/etnaviv/etnaviv_mmu.c | 60 | ||||
-rw-r--r-- | drivers/gpu/drm/etnaviv/etnaviv_mmu.h | 10 |
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 @@ | |||
1 | etnaviv-y := \ | 1 | etnaviv-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 | ||
164 | u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu) | 165 | u16 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 | |||
27 | struct 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 | |||
44 | struct etnaviv_cmdbuf_suballoc * | ||
45 | etnaviv_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 | |||
71 | free_dma: | ||
72 | dma_free_wc(gpu->dev, SUBALLOC_SIZE, suballoc->vaddr, suballoc->paddr); | ||
73 | free_suballoc: | ||
74 | kfree(suballoc); | ||
75 | |||
76 | return NULL; | ||
77 | } | ||
78 | |||
79 | void 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 | |||
88 | struct etnaviv_cmdbuf * | ||
89 | etnaviv_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); | ||
105 | retry: | ||
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 | |||
129 | void 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 | |||
145 | u32 etnaviv_cmdbuf_get_va(struct etnaviv_cmdbuf *buf) | ||
146 | { | ||
147 | return buf->suballoc->iova + buf->suballoc_offset; | ||
148 | } | ||
149 | |||
150 | dma_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 | |||
22 | struct etnaviv_gpu; | ||
23 | struct etnaviv_cmdbuf_suballoc; | ||
24 | |||
25 | struct 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 | |||
46 | struct etnaviv_cmdbuf_suballoc * | ||
47 | etnaviv_cmdbuf_suballoc_new(struct etnaviv_gpu * gpu); | ||
48 | void etnaviv_cmdbuf_suballoc_destroy(struct etnaviv_cmdbuf_suballoc *suballoc); | ||
49 | |||
50 | struct etnaviv_cmdbuf * | ||
51 | etnaviv_cmdbuf_new(struct etnaviv_cmdbuf_suballoc *suballoc, u32 size, | ||
52 | size_t nr_bos); | ||
53 | void etnaviv_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf); | ||
54 | |||
55 | u32 etnaviv_cmdbuf_get_va(struct etnaviv_cmdbuf *buf); | ||
56 | dma_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 |
28 | static bool reglog; | 28 | static 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: | |||
422 | err_submit_cmds: | 424 | err_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 | ||
551 | static 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 | |||
549 | static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu) | 582 | static 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 | ||
696 | free_buffer: | 739 | free_buffer: |
697 | etnaviv_gpu_cmdbuf_free(gpu->buffer); | 740 | etnaviv_cmdbuf_free(gpu->buffer); |
698 | gpu->buffer = NULL; | 741 | gpu->buffer = NULL; |
699 | destroy_iommu: | 742 | destroy_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 | ||
1120 | struct 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 | |||
1147 | void 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 | |||
1155 | static void retire_worker(struct work_struct *work) | 1163 | static 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 | ||
95 | struct etnaviv_cmdbuf_suballoc; | ||
95 | struct etnaviv_cmdbuf; | 96 | struct etnaviv_cmdbuf; |
96 | 97 | ||
97 | struct etnaviv_gpu { | 98 | struct 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 | ||
153 | struct 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 | |||
176 | static inline void gpu_write(struct etnaviv_gpu *gpu, u32 reg, u32 data) | 155 | static 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); |
212 | int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, | 191 | int 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); |
214 | struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu, | ||
215 | u32 size, size_t nr_bos); | ||
216 | void etnaviv_gpu_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf); | ||
217 | int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu); | 193 | int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu); |
218 | void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu); | 194 | void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu); |
219 | int etnaviv_gpu_wait_idle(struct etnaviv_gpu *gpu, unsigned int timeout_ms); | 195 | int 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 | ||
187 | static struct etnaviv_iommu_ops etnaviv_iommu_ops = { | 187 | static 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 | ||
232 | static struct etnaviv_iommu_ops etnaviv_iommu_ops = { | 233 | static 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 | ||
325 | u32 etnaviv_iommu_get_cmdbuf_va(struct etnaviv_gpu *gpu, | 320 | int 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 | ||
365 | void etnaviv_iommu_put_cmdbuf_va(struct etnaviv_gpu *gpu, | 354 | void 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); |
63 | void etnaviv_iommu_destroy(struct etnaviv_iommu *iommu); | 63 | void etnaviv_iommu_destroy(struct etnaviv_iommu *iommu); |
64 | 64 | ||
65 | u32 etnaviv_iommu_get_cmdbuf_va(struct etnaviv_gpu *gpu, | 65 | int 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, |
67 | void etnaviv_iommu_put_cmdbuf_va(struct etnaviv_gpu *gpu, | 67 | u32 *iova); |
68 | struct etnaviv_cmdbuf *buf); | 68 | void etnaviv_iommu_put_suballoc_va(struct etnaviv_gpu *gpu, |
69 | struct drm_mm_node *vram_node, size_t size, | ||
70 | u32 iova); | ||
69 | 71 | ||
70 | size_t etnaviv_iommu_dump_size(struct etnaviv_iommu *iommu); | 72 | size_t etnaviv_iommu_dump_size(struct etnaviv_iommu *iommu); |
71 | void etnaviv_iommu_dump(struct etnaviv_iommu *iommu, void *buf); | 73 | void etnaviv_iommu_dump(struct etnaviv_iommu *iommu, void *buf); |