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