Commit 17aad8a3 authored by Daniel Vetter's avatar Daniel Vetter

Merge remote-tracking branch 'airlied/drm-next' into drm-misc-next

Yet another backmerge to get at latest etnaviv code, which is need for
Chris' drm_mm patch.
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@intel.com>
parents 7e6328fd 99743ae4
etnaviv-y := \ etnaviv-y := \
etnaviv_buffer.o \ etnaviv_buffer.o \
etnaviv_cmd_parser.o \ etnaviv_cmd_parser.o \
etnaviv_cmdbuf.o \
etnaviv_drv.o \ etnaviv_drv.o \
etnaviv_dump.o \ etnaviv_dump.o \
etnaviv_gem_prime.o \ etnaviv_gem_prime.o \
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
* this program. If not, see <http://www.gnu.org/licenses/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "etnaviv_cmdbuf.h"
#include "etnaviv_gpu.h" #include "etnaviv_gpu.h"
#include "etnaviv_gem.h" #include "etnaviv_gem.h"
#include "etnaviv_mmu.h" #include "etnaviv_mmu.h"
...@@ -125,7 +126,7 @@ static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu, ...@@ -125,7 +126,7 @@ static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu,
u32 *ptr = buf->vaddr + off; u32 *ptr = buf->vaddr + off;
dev_info(gpu->dev, "virt %p phys 0x%08x free 0x%08x\n", dev_info(gpu->dev, "virt %p phys 0x%08x free 0x%08x\n",
ptr, etnaviv_iommu_get_cmdbuf_va(gpu, buf) + off, size - len * 4 - off); ptr, etnaviv_cmdbuf_get_va(buf) + off, size - len * 4 - off);
print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4, print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4,
ptr, len * 4, 0); ptr, len * 4, 0);
...@@ -158,7 +159,7 @@ static u32 etnaviv_buffer_reserve(struct etnaviv_gpu *gpu, ...@@ -158,7 +159,7 @@ static u32 etnaviv_buffer_reserve(struct etnaviv_gpu *gpu,
if (buffer->user_size + cmd_dwords * sizeof(u64) > buffer->size) if (buffer->user_size + cmd_dwords * sizeof(u64) > buffer->size)
buffer->user_size = 0; buffer->user_size = 0;
return etnaviv_iommu_get_cmdbuf_va(gpu, buffer) + buffer->user_size; return etnaviv_cmdbuf_get_va(buffer) + buffer->user_size;
} }
u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu) u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu)
...@@ -169,7 +170,7 @@ u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu) ...@@ -169,7 +170,7 @@ u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu)
buffer->user_size = 0; buffer->user_size = 0;
CMD_WAIT(buffer); CMD_WAIT(buffer);
CMD_LINK(buffer, 2, etnaviv_iommu_get_cmdbuf_va(gpu, buffer) + CMD_LINK(buffer, 2, etnaviv_cmdbuf_get_va(buffer) +
buffer->user_size - 4); buffer->user_size - 4);
return buffer->user_size / 8; return buffer->user_size / 8;
...@@ -261,7 +262,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, ...@@ -261,7 +262,7 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
if (drm_debug & DRM_UT_DRIVER) if (drm_debug & DRM_UT_DRIVER)
etnaviv_buffer_dump(gpu, buffer, 0, 0x50); etnaviv_buffer_dump(gpu, buffer, 0, 0x50);
link_target = etnaviv_iommu_get_cmdbuf_va(gpu, cmdbuf); link_target = etnaviv_cmdbuf_get_va(cmdbuf);
link_dwords = cmdbuf->size / 8; link_dwords = cmdbuf->size / 8;
/* /*
...@@ -355,12 +356,13 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, ...@@ -355,12 +356,13 @@ void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
CMD_LOAD_STATE(buffer, VIVS_GL_EVENT, VIVS_GL_EVENT_EVENT_ID(event) | CMD_LOAD_STATE(buffer, VIVS_GL_EVENT, VIVS_GL_EVENT_EVENT_ID(event) |
VIVS_GL_EVENT_FROM_PE); VIVS_GL_EVENT_FROM_PE);
CMD_WAIT(buffer); CMD_WAIT(buffer);
CMD_LINK(buffer, 2, etnaviv_iommu_get_cmdbuf_va(gpu, buffer) + CMD_LINK(buffer, 2, etnaviv_cmdbuf_get_va(buffer) +
buffer->user_size - 4); buffer->user_size - 4);
if (drm_debug & DRM_UT_DRIVER) if (drm_debug & DRM_UT_DRIVER)
pr_info("stream link to 0x%08x @ 0x%08x %p\n", pr_info("stream link to 0x%08x @ 0x%08x %p\n",
return_target, etnaviv_iommu_get_cmdbuf_va(gpu, cmdbuf), cmdbuf->vaddr); return_target, etnaviv_cmdbuf_get_va(cmdbuf),
cmdbuf->vaddr);
if (drm_debug & DRM_UT_DRIVER) { if (drm_debug & DRM_UT_DRIVER) {
print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4, print_hex_dump(KERN_INFO, "cmd ", DUMP_PREFIX_OFFSET, 16, 4,
......
...@@ -56,6 +56,8 @@ static const struct { ...@@ -56,6 +56,8 @@ static const struct {
ST(0x0644, 1), ST(0x0644, 1),
ST(0x064c, 1), ST(0x064c, 1),
ST(0x0680, 8), ST(0x0680, 8),
ST(0x086c, 1),
ST(0x1028, 1),
ST(0x1410, 1), ST(0x1410, 1),
ST(0x1430, 1), ST(0x1430, 1),
ST(0x1458, 1), ST(0x1458, 1),
...@@ -73,8 +75,12 @@ static const struct { ...@@ -73,8 +75,12 @@ static const struct {
ST(0x16c0, 8), ST(0x16c0, 8),
ST(0x16e0, 8), ST(0x16e0, 8),
ST(0x1740, 8), ST(0x1740, 8),
ST(0x17c0, 8),
ST(0x17e0, 8),
ST(0x2400, 14 * 16), ST(0x2400, 14 * 16),
ST(0x10800, 32 * 16), ST(0x10800, 32 * 16),
ST(0x14600, 16),
ST(0x14800, 8 * 8),
#undef ST #undef ST
}; };
......
/*
* Copyright (C) 2017 Etnaviv Project
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <drm/drm_mm.h>
#include "etnaviv_cmdbuf.h"
#include "etnaviv_gpu.h"
#include "etnaviv_mmu.h"
#define SUBALLOC_SIZE SZ_256K
#define SUBALLOC_GRANULE SZ_4K
#define SUBALLOC_GRANULES (SUBALLOC_SIZE / SUBALLOC_GRANULE)
struct etnaviv_cmdbuf_suballoc {
/* suballocated dma buffer properties */
struct etnaviv_gpu *gpu;
void *vaddr;
dma_addr_t paddr;
/* GPU mapping */
u32 iova;
struct drm_mm_node vram_node; /* only used on MMUv2 */
/* allocation management */
struct mutex lock;
DECLARE_BITMAP(granule_map, SUBALLOC_GRANULES);
int free_space;
wait_queue_head_t free_event;
};
struct etnaviv_cmdbuf_suballoc *
etnaviv_cmdbuf_suballoc_new(struct etnaviv_gpu * gpu)
{
struct etnaviv_cmdbuf_suballoc *suballoc;
int ret;
suballoc = kzalloc(sizeof(*suballoc), GFP_KERNEL);
if (!suballoc)
return ERR_PTR(-ENOMEM);
suballoc->gpu = gpu;
mutex_init(&suballoc->lock);
init_waitqueue_head(&suballoc->free_event);
suballoc->vaddr = dma_alloc_wc(gpu->dev, SUBALLOC_SIZE,
&suballoc->paddr, GFP_KERNEL);
if (!suballoc->vaddr)
goto free_suballoc;
ret = etnaviv_iommu_get_suballoc_va(gpu, suballoc->paddr,
&suballoc->vram_node, SUBALLOC_SIZE,
&suballoc->iova);
if (ret)
goto free_dma;
return suballoc;
free_dma:
dma_free_wc(gpu->dev, SUBALLOC_SIZE, suballoc->vaddr, suballoc->paddr);
free_suballoc:
kfree(suballoc);
return NULL;
}
void etnaviv_cmdbuf_suballoc_destroy(struct etnaviv_cmdbuf_suballoc *suballoc)
{
etnaviv_iommu_put_suballoc_va(suballoc->gpu, &suballoc->vram_node,
SUBALLOC_SIZE, suballoc->iova);
dma_free_wc(suballoc->gpu->dev, SUBALLOC_SIZE, suballoc->vaddr,
suballoc->paddr);
kfree(suballoc);
}
struct etnaviv_cmdbuf *
etnaviv_cmdbuf_new(struct etnaviv_cmdbuf_suballoc *suballoc, u32 size,
size_t nr_bos)
{
struct etnaviv_cmdbuf *cmdbuf;
size_t sz = size_vstruct(nr_bos, sizeof(cmdbuf->bo_map[0]),
sizeof(*cmdbuf));
int granule_offs, order, ret;
cmdbuf = kzalloc(sz, GFP_KERNEL);
if (!cmdbuf)
return NULL;
cmdbuf->suballoc = suballoc;
cmdbuf->size = size;
order = order_base_2(ALIGN(size, SUBALLOC_GRANULE) / SUBALLOC_GRANULE);
retry:
mutex_lock(&suballoc->lock);
granule_offs = bitmap_find_free_region(suballoc->granule_map,
SUBALLOC_GRANULES, order);
if (granule_offs < 0) {
suballoc->free_space = 0;
mutex_unlock(&suballoc->lock);
ret = wait_event_interruptible_timeout(suballoc->free_event,
suballoc->free_space,
msecs_to_jiffies(10 * 1000));
if (!ret) {
dev_err(suballoc->gpu->dev,
"Timeout waiting for cmdbuf space\n");
return NULL;
}
goto retry;
}
mutex_unlock(&suballoc->lock);
cmdbuf->suballoc_offset = granule_offs * SUBALLOC_GRANULE;
cmdbuf->vaddr = suballoc->vaddr + cmdbuf->suballoc_offset;
return cmdbuf;
}
void etnaviv_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf)
{
struct etnaviv_cmdbuf_suballoc *suballoc = cmdbuf->suballoc;
int order = order_base_2(ALIGN(cmdbuf->size, SUBALLOC_GRANULE) /
SUBALLOC_GRANULE);
mutex_lock(&suballoc->lock);
bitmap_release_region(suballoc->granule_map,
cmdbuf->suballoc_offset / SUBALLOC_GRANULE,
order);
suballoc->free_space = 1;
mutex_unlock(&suballoc->lock);
wake_up_all(&suballoc->free_event);
kfree(cmdbuf);
}
u32 etnaviv_cmdbuf_get_va(struct etnaviv_cmdbuf *buf)
{
return buf->suballoc->iova + buf->suballoc_offset;
}
dma_addr_t etnaviv_cmdbuf_get_pa(struct etnaviv_cmdbuf *buf)
{
return buf->suballoc->paddr + buf->suballoc_offset;
}
/*
* Copyright (C) 2017 Etnaviv Project
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ETNAVIV_CMDBUF_H__
#define __ETNAVIV_CMDBUF_H__
#include <linux/types.h>
struct etnaviv_gpu;
struct etnaviv_cmdbuf_suballoc;
struct etnaviv_cmdbuf {
/* suballocator this cmdbuf is allocated from */
struct etnaviv_cmdbuf_suballoc *suballoc;
/* user context key, must be unique between all active users */
struct etnaviv_file_private *ctx;
/* cmdbuf properties */
int suballoc_offset;
void *vaddr;
u32 size;
u32 user_size;
/* fence after which this buffer is to be disposed */
struct dma_fence *fence;
/* target exec state */
u32 exec_state;
/* per GPU in-flight list */
struct list_head node;
/* BOs attached to this command buffer */
unsigned int nr_bos;
struct etnaviv_vram_mapping *bo_map[0];
};
struct etnaviv_cmdbuf_suballoc *
etnaviv_cmdbuf_suballoc_new(struct etnaviv_gpu * gpu);
void etnaviv_cmdbuf_suballoc_destroy(struct etnaviv_cmdbuf_suballoc *suballoc);
struct etnaviv_cmdbuf *
etnaviv_cmdbuf_new(struct etnaviv_cmdbuf_suballoc *suballoc, u32 size,
size_t nr_bos);
void etnaviv_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf);
u32 etnaviv_cmdbuf_get_va(struct etnaviv_cmdbuf *buf);
dma_addr_t etnaviv_cmdbuf_get_pa(struct etnaviv_cmdbuf *buf);
#endif /* __ETNAVIV_CMDBUF_H__ */
...@@ -18,11 +18,11 @@ ...@@ -18,11 +18,11 @@
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <drm/drm_of.h> #include <drm/drm_of.h>
#include "etnaviv_cmdbuf.h"
#include "etnaviv_drv.h" #include "etnaviv_drv.h"
#include "etnaviv_gpu.h" #include "etnaviv_gpu.h"
#include "etnaviv_gem.h" #include "etnaviv_gem.h"
#include "etnaviv_mmu.h" #include "etnaviv_mmu.h"
#include "etnaviv_gem.h"
#ifdef CONFIG_DRM_ETNAVIV_REGISTER_LOGGING #ifdef CONFIG_DRM_ETNAVIV_REGISTER_LOGGING
static bool reglog; static bool reglog;
...@@ -177,7 +177,8 @@ static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu, struct seq_file *m) ...@@ -177,7 +177,8 @@ static void etnaviv_buffer_dump(struct etnaviv_gpu *gpu, struct seq_file *m)
u32 i; u32 i;
seq_printf(m, "virt %p - phys 0x%llx - free 0x%08x\n", seq_printf(m, "virt %p - phys 0x%llx - free 0x%08x\n",
buf->vaddr, (u64)buf->paddr, size - buf->user_size); buf->vaddr, (u64)etnaviv_cmdbuf_get_pa(buf),
size - buf->user_size);
for (i = 0; i < size / 4; i++) { for (i = 0; i < size / 4; i++) {
if (i && !(i % 4)) if (i && !(i % 4))
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
#include <linux/devcoredump.h> #include <linux/devcoredump.h>
#include "etnaviv_cmdbuf.h"
#include "etnaviv_dump.h" #include "etnaviv_dump.h"
#include "etnaviv_gem.h" #include "etnaviv_gem.h"
#include "etnaviv_gpu.h" #include "etnaviv_gpu.h"
...@@ -177,12 +178,11 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu) ...@@ -177,12 +178,11 @@ void etnaviv_core_dump(struct etnaviv_gpu *gpu)
etnaviv_core_dump_mmu(&iter, gpu, mmu_size); etnaviv_core_dump_mmu(&iter, gpu, mmu_size);
etnaviv_core_dump_mem(&iter, ETDUMP_BUF_RING, gpu->buffer->vaddr, etnaviv_core_dump_mem(&iter, ETDUMP_BUF_RING, gpu->buffer->vaddr,
gpu->buffer->size, gpu->buffer->size,
etnaviv_iommu_get_cmdbuf_va(gpu, gpu->buffer)); etnaviv_cmdbuf_get_va(gpu->buffer));
list_for_each_entry(cmd, &gpu->active_cmd_list, node) list_for_each_entry(cmd, &gpu->active_cmd_list, node)
etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD, cmd->vaddr, etnaviv_core_dump_mem(&iter, ETDUMP_BUF_CMD, cmd->vaddr,
cmd->size, cmd->size, etnaviv_cmdbuf_get_va(cmd));
etnaviv_iommu_get_cmdbuf_va(gpu, cmd));
/* Reserve space for the bomap */ /* Reserve space for the bomap */
if (n_bomap_pages) { if (n_bomap_pages) {
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
#include <linux/reservation.h> #include <linux/reservation.h>
#include "etnaviv_cmdbuf.h"
#include "etnaviv_drv.h" #include "etnaviv_drv.h"
#include "etnaviv_gpu.h" #include "etnaviv_gpu.h"
#include "etnaviv_gem.h" #include "etnaviv_gem.h"
...@@ -332,8 +333,9 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, ...@@ -332,8 +333,9 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
bos = drm_malloc_ab(args->nr_bos, sizeof(*bos)); bos = drm_malloc_ab(args->nr_bos, sizeof(*bos));
relocs = drm_malloc_ab(args->nr_relocs, sizeof(*relocs)); relocs = drm_malloc_ab(args->nr_relocs, sizeof(*relocs));
stream = drm_malloc_ab(1, args->stream_size); stream = drm_malloc_ab(1, args->stream_size);
cmdbuf = etnaviv_gpu_cmdbuf_new(gpu, ALIGN(args->stream_size, 8) + 8, cmdbuf = etnaviv_cmdbuf_new(gpu->cmdbuf_suballoc,
args->nr_bos); ALIGN(args->stream_size, 8) + 8,
args->nr_bos);
if (!bos || !relocs || !stream || !cmdbuf) { if (!bos || !relocs || !stream || !cmdbuf) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_submit_cmds; goto err_submit_cmds;
...@@ -422,7 +424,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, ...@@ -422,7 +424,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data,
err_submit_cmds: err_submit_cmds:
/* if we still own the cmdbuf */ /* if we still own the cmdbuf */
if (cmdbuf) if (cmdbuf)
etnaviv_gpu_cmdbuf_free(cmdbuf); etnaviv_cmdbuf_free(cmdbuf);
if (stream) if (stream)
drm_free_large(stream); drm_free_large(stream);
if (bos) if (bos)
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include <linux/dma-fence.h> #include <linux/dma-fence.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include "etnaviv_cmdbuf.h"
#include "etnaviv_dump.h" #include "etnaviv_dump.h"
#include "etnaviv_gpu.h" #include "etnaviv_gpu.h"
#include "etnaviv_gem.h" #include "etnaviv_gem.h"
...@@ -546,6 +548,37 @@ void etnaviv_gpu_start_fe(struct etnaviv_gpu *gpu, u32 address, u16 prefetch) ...@@ -546,6 +548,37 @@ void etnaviv_gpu_start_fe(struct etnaviv_gpu *gpu, u32 address, u16 prefetch)
VIVS_FE_COMMAND_CONTROL_PREFETCH(prefetch)); VIVS_FE_COMMAND_CONTROL_PREFETCH(prefetch));
} }
static void etnaviv_gpu_setup_pulse_eater(struct etnaviv_gpu *gpu)
{
/*
* Base value for VIVS_PM_PULSE_EATER register on models where it
* cannot be read, extracted from vivante kernel driver.
*/
u32 pulse_eater = 0x01590880;
if (etnaviv_is_model_rev(gpu, GC4000, 0x5208) ||
etnaviv_is_model_rev(gpu, GC4000, 0x5222)) {
pulse_eater |= BIT(23);
}
if (etnaviv_is_model_rev(gpu, GC1000, 0x5039) ||
etnaviv_is_model_rev(gpu, GC1000, 0x5040)) {
pulse_eater &= ~BIT(16);
pulse_eater |= BIT(17);
}
if ((gpu->identity.revision > 0x5420) &&
(gpu->identity.features & chipFeatures_PIPE_3D))
{
/* Performance fix: disable internal DFS */
pulse_eater = gpu_read(gpu, VIVS_PM_PULSE_EATER);
pulse_eater |= BIT(18);
}
gpu_write(gpu, VIVS_PM_PULSE_EATER, pulse_eater);
}
static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu) static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
{ {
u16 prefetch; u16 prefetch;
...@@ -586,6 +619,9 @@ static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu) ...@@ -586,6 +619,9 @@ static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
gpu_write(gpu, VIVS_MC_BUS_CONFIG, bus_config); gpu_write(gpu, VIVS_MC_BUS_CONFIG, bus_config);
} }
/* setup the pulse eater */
etnaviv_gpu_setup_pulse_eater(gpu);
/* setup the MMU */ /* setup the MMU */
etnaviv_iommu_restore(gpu); etnaviv_iommu_restore(gpu);
...@@ -593,7 +629,7 @@ static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu) ...@@ -593,7 +629,7 @@ static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
prefetch = etnaviv_buffer_init(gpu); prefetch = etnaviv_buffer_init(gpu);
gpu_write(gpu, VIVS_HI_INTR_ENBL, ~0U); gpu_write(gpu, VIVS_HI_INTR_ENBL, ~0U);
etnaviv_gpu_start_fe(gpu, etnaviv_iommu_get_cmdbuf_va(gpu, gpu->buffer), etnaviv_gpu_start_fe(gpu, etnaviv_cmdbuf_get_va(gpu->buffer),
prefetch); prefetch);
} }
...@@ -658,8 +694,15 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) ...@@ -658,8 +694,15 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
goto fail; goto fail;
} }
gpu->cmdbuf_suballoc = etnaviv_cmdbuf_suballoc_new(gpu);
if (IS_ERR(gpu->cmdbuf_suballoc)) {
dev_err(gpu->dev, "Failed to create cmdbuf suballocator\n");
ret = PTR_ERR(gpu->cmdbuf_suballoc);
goto fail;
}
/* Create buffer: */ /* Create buffer: */
gpu->buffer = etnaviv_gpu_cmdbuf_new(gpu, PAGE_SIZE, 0); gpu->buffer = etnaviv_cmdbuf_new(gpu->cmdbuf_suballoc, PAGE_SIZE, 0);
if (!gpu->buffer) { if (!gpu->buffer) {
ret = -ENOMEM; ret = -ENOMEM;
dev_err(gpu->dev, "could not create command buffer\n"); dev_err(gpu->dev, "could not create command buffer\n");
...@@ -667,7 +710,7 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) ...@@ -667,7 +710,7 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
} }
if (gpu->mmu->version == ETNAVIV_IOMMU_V1 && if (gpu->mmu->version == ETNAVIV_IOMMU_V1 &&
gpu->buffer->paddr - gpu->memory_base > 0x80000000) { etnaviv_cmdbuf_get_va(gpu->buffer) > 0x80000000) {
ret = -EINVAL; ret = -EINVAL;
dev_err(gpu->dev, dev_err(gpu->dev,
"command buffer outside valid memory window\n"); "command buffer outside valid memory window\n");
...@@ -694,7 +737,7 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) ...@@ -694,7 +737,7 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
return 0; return 0;
free_buffer: free_buffer:
etnaviv_gpu_cmdbuf_free(gpu->buffer); etnaviv_cmdbuf_free(gpu->buffer);
gpu->buffer = NULL; gpu->buffer = NULL;
destroy_iommu: destroy_iommu:
etnaviv_iommu_destroy(gpu->mmu); etnaviv_iommu_destroy(gpu->mmu);
...@@ -1117,41 +1160,6 @@ static void event_free(struct etnaviv_gpu *gpu, unsigned int event) ...@@ -1117,41 +1160,6 @@ static void event_free(struct etnaviv_gpu *gpu, unsigned int event)
* Cmdstream submission/retirement: * Cmdstream submission/retirement:
*/ */
struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu, u32 size,
size_t nr_bos)
{
struct etnaviv_cmdbuf *cmdbuf;
size_t sz = size_vstruct(nr_bos, sizeof(cmdbuf->bo_map[0]),
sizeof(*cmdbuf));
cmdbuf = kzalloc(sz, GFP_KERNEL);
if (!cmdbuf)
return NULL;
if (gpu->mmu->version == ETNAVIV_IOMMU_V2)
size = ALIGN(size, SZ_4K);
cmdbuf->vaddr = dma_alloc_wc(gpu->dev, size, &cmdbuf->paddr,
GFP_KERNEL);
if (!cmdbuf->vaddr) {
kfree(cmdbuf);
return NULL;
}
cmdbuf->gpu = gpu;
cmdbuf->size = size;
return cmdbuf;
}
void etnaviv_gpu_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf)
{
etnaviv_iommu_put_cmdbuf_va(cmdbuf->gpu, cmdbuf);
dma_free_wc(cmdbuf->gpu->dev, cmdbuf->size, cmdbuf->vaddr,
cmdbuf->paddr);
kfree(cmdbuf);
}
static void retire_worker(struct work_struct *work) static void retire_worker(struct work_struct *work)
{ {
struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu, struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
...@@ -1177,7 +1185,7 @@ static void retire_worker(struct work_struct *work) ...@@ -1177,7 +1185,7 @@ static void retire_worker(struct work_struct *work)
etnaviv_gem_mapping_unreference(mapping); etnaviv_gem_mapping_unreference(mapping);
} }
etnaviv_gpu_cmdbuf_free(cmdbuf); etnaviv_cmdbuf_free(cmdbuf);
/* /*
* We need to balance the runtime PM count caused by * We need to balance the runtime PM count caused by
* each submission. Upon submission, we increment * each submission. Upon submission, we increment
...@@ -1593,10 +1601,15 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master, ...@@ -1593,10 +1601,15 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master,
#endif #endif
if (gpu->buffer) { if (gpu->buffer) {
etnaviv_gpu_cmdbuf_free(gpu->buffer); etnaviv_cmdbuf_free(gpu->buffer);
gpu->buffer = NULL; gpu->buffer = NULL;
} }
if (gpu->cmdbuf_suballoc) {
etnaviv_cmdbuf_suballoc_destroy(gpu->cmdbuf_suballoc);
gpu->cmdbuf_suballoc = NULL;
}
if (gpu->mmu) { if (gpu->mmu) {
etnaviv_iommu_destroy(gpu->mmu); etnaviv_iommu_destroy(gpu->mmu);
gpu->mmu = NULL; gpu->mmu = NULL;
......
...@@ -92,6 +92,7 @@ struct etnaviv_event { ...@@ -92,6 +92,7 @@ struct etnaviv_event {
struct dma_fence *fence; struct dma_fence *fence;
}; };
struct etnaviv_cmdbuf_suballoc;
struct etnaviv_cmdbuf; struct etnaviv_cmdbuf;
struct etnaviv_gpu { struct etnaviv_gpu {
...@@ -135,6 +136,7 @@ struct etnaviv_gpu { ...@@ -135,6 +136,7 @@ struct etnaviv_gpu {
int irq; int irq;
struct etnaviv_iommu *mmu; struct etnaviv_iommu *mmu;
struct etnaviv_cmdbuf_suballoc *cmdbuf_suballoc;
/* Power Control: */ /* Power Control: */
struct clk *clk_bus; struct clk *clk_bus;
...@@ -150,29 +152,6 @@ struct etnaviv_gpu { ...@@ -150,29 +152,6 @@ struct etnaviv_gpu {
struct work_struct recover_work; struct work_struct recover_work;
}; };
struct etnaviv_cmdbuf {
/* device this cmdbuf is allocated for */
struct etnaviv_gpu *gpu;
/* user context key, must be unique between all active users */
struct etnaviv_file_private *ctx;
/* cmdbuf properties */
void *vaddr;
dma_addr_t paddr;
u32 size;
u32 user_size;
/* vram node used if the cmdbuf is mapped through the MMUv2 */
struct drm_mm_node vram_node;
/* fence after which this buffer is to be disposed */
struct dma_fence *fence;
/* target exec state */
u32 exec_state;
/* per GPU in-flight list */
struct list_head node;
/* BOs attached to this command buffer */
unsigned int nr_bos;
struct etnaviv_vram_mapping *bo_map[0];
};
static inline void gpu_write(struct etnaviv_gpu *gpu, u32 reg, u32 data) static inline void gpu_write(struct etnaviv_gpu *gpu, u32 reg, u32 data)
{ {
etnaviv_writel(data, gpu->mmio + reg); etnaviv_writel(data, gpu->mmio + reg);
...@@ -211,9 +190,6 @@ int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu, ...@@ -211,9 +190,6 @@ int etnaviv_gpu_wait_obj_inactive(struct etnaviv_gpu *gpu,
struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout); struct etnaviv_gem_object *etnaviv_obj, struct timespec *timeout);
int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
struct etnaviv_gem_submit *submit, struct etnaviv_cmdbuf *cmdbuf); struct etnaviv_gem_submit *submit, struct etnaviv_cmdbuf *cmdbuf);
struct etnaviv_cmdbuf *etnaviv_gpu_cmdbuf_new(struct etnaviv_gpu *gpu,
u32 size, size_t nr_bos);
void etnaviv_gpu_cmdbuf_free(struct etnaviv_cmdbuf *cmdbuf);
int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu); int etnaviv_gpu_pm_get_sync(struct etnaviv_gpu *gpu);
void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu); void etnaviv_gpu_pm_put(struct etnaviv_gpu *gpu);
int etnaviv_gpu_wait_idle(struct etnaviv_gpu *gpu, unsigned int timeout_ms); int etnaviv_gpu_wait_idle(struct etnaviv_gpu *gpu, unsigned int timeout_ms);
......
...@@ -184,7 +184,7 @@ static void etnaviv_iommuv1_dump(struct iommu_domain *domain, void *buf) ...@@ -184,7 +184,7 @@ static void etnaviv_iommuv1_dump(struct iommu_domain *domain, void *buf)
memcpy(buf, etnaviv_domain->pgtable.pgtable, PT_SIZE); memcpy(buf, etnaviv_domain->pgtable.pgtable, PT_SIZE);
} }
static struct etnaviv_iommu_ops etnaviv_iommu_ops = { static const struct etnaviv_iommu_ops etnaviv_iommu_ops = {
.ops = { .ops = {
.domain_free = etnaviv_domain_free, .domain_free = etnaviv_domain_free,
.map = etnaviv_iommuv1_map, .map = etnaviv_iommuv1_map,
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include "etnaviv_cmdbuf.h"
#include "etnaviv_gpu.h" #include "etnaviv_gpu.h"
#include "etnaviv_mmu.h" #include "etnaviv_mmu.h"
#include "etnaviv_iommu.h" #include "etnaviv_iommu.h"
...@@ -229,7 +230,7 @@ static void etnaviv_iommuv2_dump(struct iommu_domain *domain, void *buf) ...@@ -229,7 +230,7 @@ static void etnaviv_iommuv2_dump(struct iommu_domain *domain, void *buf)
memcpy(buf, etnaviv_domain->stlb_cpu[i], SZ_4K); memcpy(buf, etnaviv_domain->stlb_cpu[i], SZ_4K);
} }
static struct etnaviv_iommu_ops etnaviv_iommu_ops = { static const struct etnaviv_iommu_ops etnaviv_iommu_ops = {
.ops = { .ops = {
.domain_free = etnaviv_iommuv2_domain_free, .domain_free = etnaviv_iommuv2_domain_free,
.map = etnaviv_iommuv2_map, .map = etnaviv_iommuv2_map,
...@@ -254,7 +255,8 @@ void etnaviv_iommuv2_restore(struct etnaviv_gpu *gpu) ...@@ -254,7 +255,8 @@ void etnaviv_iommuv2_restore(struct etnaviv_gpu *gpu)
prefetch = etnaviv_buffer_config_mmuv2(gpu, prefetch = etnaviv_buffer_config_mmuv2(gpu,
(u32)etnaviv_domain->mtlb_dma, (u32)etnaviv_domain->mtlb_dma,
(u32)etnaviv_domain->bad_page_dma); (u32)etnaviv_domain->bad_page_dma);
etnaviv_gpu_start_fe(gpu, gpu->buffer->paddr, prefetch); etnaviv_gpu_start_fe(gpu, (u32)etnaviv_cmdbuf_get_pa(gpu->buffer),
prefetch);
etnaviv_gpu_wait_idle(gpu, 100); etnaviv_gpu_wait_idle(gpu, 100);
gpu_write(gpu, VIVS_MMUv2_CONTROL, VIVS_MMUv2_CONTROL_ENABLE); gpu_write(gpu, VIVS_MMUv2_CONTROL, VIVS_MMUv2_CONTROL_ENABLE);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
#include "common.xml.h" #include "common.xml.h"
#include "etnaviv_cmdbuf.h"
#include "etnaviv_drv.h" #include "etnaviv_drv.h"
#include "etnaviv_gem.h" #include "etnaviv_gem.h"
#include "etnaviv_gpu.h" #include "etnaviv_gpu.h"
...@@ -117,14 +118,9 @@ static int etnaviv_iommu_find_iova(struct etnaviv_iommu *mmu, ...@@ -117,14 +118,9 @@ static int etnaviv_iommu_find_iova(struct etnaviv_iommu *mmu,
struct list_head list; struct list_head list;
bool found; bool found;
/*
* XXX: The DRM_MM_SEARCH_BELOW is really a hack to trick
* drm_mm into giving out a low IOVA after address space
* rollover. This needs a proper fix.
*/
ret = drm_mm_insert_node_in_range(&mmu->mm, node, ret = drm_mm_insert_node_in_range(&mmu->mm, node,
size, 0, mmu->last_iova, ~0UL, size, 0, mmu->last_iova, ~0UL,
mmu->last_iova ? DRM_MM_SEARCH_DEFAULT : DRM_MM_SEARCH_BELOW); DRM_MM_SEARCH_DEFAULT);
if (ret != -ENOSPC) if (ret != -ENOSPC)
break; break;
...@@ -194,11 +190,8 @@ static int etnaviv_iommu_find_iova(struct etnaviv_iommu *mmu, ...@@ -194,11 +190,8 @@ static int etnaviv_iommu_find_iova(struct etnaviv_iommu *mmu,
/* /*
* We removed enough mappings so that the new allocation will * We removed enough mappings so that the new allocation will
* succeed. Ensure that the MMU will be flushed before the * succeed, retry the allocation one more time.
* associated commit requesting this mapping, and retry the
* allocation one more time.
*/ */
mmu->need_flush = true;
} }
return ret; return ret;
...@@ -250,6 +243,7 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu, ...@@ -250,6 +243,7 @@ int etnaviv_iommu_map_gem(struct etnaviv_iommu *mmu,
} }
list_add_tail(&mapping->mmu_node, &mmu->mappings); list_add_tail(&mapping->mmu_node, &mmu->mappings);
mmu->need_flush = true;
mutex_unlock(&mmu->lock); mutex_unlock(&mmu->lock);
return ret; return ret;
...@@ -267,6 +261,7 @@ void etnaviv_iommu_unmap_gem(struct etnaviv_iommu *mmu, ...@@ -267,6 +261,7 @@ void etnaviv_iommu_unmap_gem(struct etnaviv_iommu *mmu,
etnaviv_iommu_remove_mapping(mmu, mapping); etnaviv_iommu_remove_mapping(mmu, mapping);
list_del(&mapping->mmu_node); list_del(&mapping->mmu_node);
mmu->need_flush = true;
mutex_unlock(&mmu->lock); mutex_unlock(&mmu->lock);
} }
...@@ -322,55 +317,50 @@ void etnaviv_iommu_restore(struct etnaviv_gpu *gpu) ...@@ -322,55 +317,50 @@ void etnaviv_iommu_restore(struct etnaviv_gpu *gpu)
etnaviv_iommuv2_restore(gpu); etnaviv_iommuv2_restore(gpu);
} }
u32 etnaviv_iommu_get_cmdbuf_va(struct etnaviv_gpu *gpu, int etnaviv_iommu_get_suballoc_va(struct etnaviv_gpu *gpu, dma_addr_t paddr,
struct etnaviv_cmdbuf *buf) struct drm_mm_node *vram_node, size_t size,
u32 *iova)
{ {
struct etnaviv_iommu *mmu = gpu->mmu; struct etnaviv_iommu *mmu = gpu->mmu;
if (mmu->version == ETNAVIV_IOMMU_V1) { if (mmu->version == ETNAVIV_IOMMU_V1) {
return buf->paddr - gpu->memory_base; *iova = paddr - gpu->memory_base;
return 0;
} else { } else {
int ret; int ret;
if (buf->vram_node.allocated)
return (u32)buf->vram_node.start;
mutex_lock(&mmu->lock); mutex_lock(&mmu->lock);
ret = etnaviv_iommu_find_iova(mmu, &buf->vram_node, ret = etnaviv_iommu_find_iova(mmu, vram_node, size);
buf->size + SZ_64K);
if (ret < 0) { if (ret < 0) {
mutex_unlock(&mmu->lock); mutex_unlock(&mmu->lock);
return 0; return ret;
} }
ret = iommu_map(mmu->domain, buf->vram_node.start, buf->paddr, ret = iommu_map(mmu->domain, vram_node->start, paddr, size,
buf->size, IOMMU_READ); IOMMU_READ);
if (ret < 0) { if (ret < 0) {
drm_mm_remove_node(&buf->vram_node); drm_mm_remove_node(vram_node);
mutex_unlock(&mmu->lock); mutex_unlock(&mmu->lock);
return 0; return ret;
} }
/* mmu->last_iova = vram_node->start + size;
* At least on GC3000 the FE MMU doesn't properly flush old TLB
* entries. Make sure to space the command buffers out in a way
* that the FE MMU prefetch won't load invalid entries.
*/
mmu->last_iova = buf->vram_node.start + buf->size + SZ_64K;
gpu->mmu->need_flush = true; gpu->mmu->need_flush = true;
mutex_unlock(&mmu->lock); mutex_unlock(&mmu->lock);
return (u32)buf->vram_node.start; *iova = (u32)vram_node->start;
return 0;
} }
} }
void etnaviv_iommu_put_cmdbuf_va(struct etnaviv_gpu *gpu, void etnaviv_iommu_put_suballoc_va(struct etnaviv_gpu *gpu,
struct etnaviv_cmdbuf *buf) struct drm_mm_node *vram_node, size_t size,
u32 iova)
{ {
struct etnaviv_iommu *mmu = gpu->mmu; struct etnaviv_iommu *mmu = gpu->mmu;
if (mmu->version == ETNAVIV_IOMMU_V2 && buf->vram_node.allocated) { if (mmu->version == ETNAVIV_IOMMU_V2) {
mutex_lock(&mmu->lock); mutex_lock(&mmu->lock);
iommu_unmap(mmu->domain, buf->vram_node.start, buf->size); iommu_unmap(mmu->domain,iova, size);
drm_mm_remove_node(&buf->vram_node); drm_mm_remove_node(vram_node);
mutex_unlock(&mmu->lock); mutex_unlock(&mmu->lock);
} }
} }
......
...@@ -62,10 +62,12 @@ void etnaviv_iommu_unmap_gem(struct etnaviv_iommu *mmu, ...@@ -62,10 +62,12 @@ void etnaviv_iommu_unmap_gem(struct etnaviv_iommu *mmu,
struct etnaviv_vram_mapping *mapping); struct etnaviv_vram_mapping *mapping);
void etnaviv_iommu_destroy(struct etnaviv_iommu *iommu); void etnaviv_iommu_destroy(struct etnaviv_iommu *iommu);
u32 etnaviv_iommu_get_cmdbuf_va(struct etnaviv_gpu *gpu, int etnaviv_iommu_get_suballoc_va(struct etnaviv_gpu *gpu, dma_addr_t paddr,
struct etnaviv_cmdbuf *buf); struct drm_mm_node *vram_node, size_t size,
void etnaviv_iommu_put_cmdbuf_va(struct etnaviv_gpu *gpu, u32 *iova);
struct etnaviv_cmdbuf *buf); void etnaviv_iommu_put_suballoc_va(struct etnaviv_gpu *gpu,
struct drm_mm_node *vram_node, size_t size,
u32 iova);
size_t etnaviv_iommu_dump_size(struct etnaviv_iommu *iommu); size_t etnaviv_iommu_dump_size(struct etnaviv_iommu *iommu);
void etnaviv_iommu_dump(struct etnaviv_iommu *iommu, void *buf); void etnaviv_iommu_dump(struct etnaviv_iommu *iommu, void *buf);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment