From e17a0ded5ca158bbb801082edc0810b38b1d4e74 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 15 Dec 2016 13:11:30 +0100 Subject: drm/etnaviv: set up initial PULSE_EATER register Set up the PULSE_EATER register (0x0010C) in etnaviv_gpu_hw_init. This ports three mostly undocumented model/revision-specific register overrides from the Vivante kernel driver. This is relevant as at least the "disable internal DFS" for revisions > 0x5420 has shown to have a huge impact on shader performance (sped up memory read performance by 7.5x and write performance by 1.5x) on an affected GPU. Signed-off-by: Wladimir J. van der Laan Signed-off-by: Lucas Stach --- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'drivers/gpu/drm/etnaviv/etnaviv_gpu.c') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 0a67124..8bc68ae 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -546,6 +546,37 @@ void etnaviv_gpu_start_fe(struct etnaviv_gpu *gpu, u32 address, u16 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) { u16 prefetch; @@ -586,6 +617,9 @@ static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu) gpu_write(gpu, VIVS_MC_BUS_CONFIG, bus_config); } + /* setup the pulse eater */ + etnaviv_gpu_setup_pulse_eater(gpu); + /* setup the MMU */ etnaviv_iommu_restore(gpu); -- cgit v1.1 From ea1f5729aa1bbe68f9a394e259288d6ff894b0aa Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 16 Jan 2017 16:09:51 +0100 Subject: drm/etnaviv: move cmdbuf de-/allocation into own file This will get more complex with the following changes, so move it into its own place. Signed-off-by: Lucas Stach Reviewed-by: Christian Gmeiner --- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 45 +++++------------------------------ 1 file changed, 6 insertions(+), 39 deletions(-) (limited to 'drivers/gpu/drm/etnaviv/etnaviv_gpu.c') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 8bc68ae..ee8aacc 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -18,6 +18,8 @@ #include #include #include + +#include "etnaviv_cmdbuf.h" #include "etnaviv_dump.h" #include "etnaviv_gpu.h" #include "etnaviv_gem.h" @@ -693,7 +695,7 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) } /* Create buffer: */ - gpu->buffer = etnaviv_gpu_cmdbuf_new(gpu, PAGE_SIZE, 0); + gpu->buffer = etnaviv_cmdbuf_new(gpu, PAGE_SIZE, 0); if (!gpu->buffer) { ret = -ENOMEM; dev_err(gpu->dev, "could not create command buffer\n"); @@ -728,7 +730,7 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) return 0; free_buffer: - etnaviv_gpu_cmdbuf_free(gpu->buffer); + etnaviv_cmdbuf_free(gpu->buffer); gpu->buffer = NULL; destroy_iommu: etnaviv_iommu_destroy(gpu->mmu); @@ -1151,41 +1153,6 @@ static void event_free(struct etnaviv_gpu *gpu, unsigned int event) * 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) { struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu, @@ -1211,7 +1178,7 @@ static void retire_worker(struct work_struct *work) etnaviv_gem_mapping_unreference(mapping); } - etnaviv_gpu_cmdbuf_free(cmdbuf); + etnaviv_cmdbuf_free(cmdbuf); /* * We need to balance the runtime PM count caused by * each submission. Upon submission, we increment @@ -1627,7 +1594,7 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master, #endif if (gpu->buffer) { - etnaviv_gpu_cmdbuf_free(gpu->buffer); + etnaviv_cmdbuf_free(gpu->buffer); gpu->buffer = NULL; } -- cgit v1.1 From c3ef4b8c3e108397980014a4616c56f50026d547 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 16 Jan 2017 16:52:44 +0100 Subject: drm/etnaviv: wire up iova handling in new cmdbuf abstraction Don't call the IOMMU directly, but go through the new cmdbuf abstraction. Signed-off-by: Lucas Stach Reviewed-by: Christian Gmeiner --- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/etnaviv/etnaviv_gpu.c') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index ee8aacc..3a689c3 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -629,7 +629,7 @@ static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu) prefetch = etnaviv_buffer_init(gpu); 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); } @@ -703,7 +703,7 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) } if (gpu->mmu->version == ETNAVIV_IOMMU_V1 && - gpu->buffer->paddr - gpu->memory_base > 0x80000000) { + etnaviv_cmdbuf_get_va(gpu->buffer) > 0x80000000) { ret = -EINVAL; dev_err(gpu->dev, "command buffer outside valid memory window\n"); -- cgit v1.1 From e66774dd6f6a3d44559599e4eeb785734c28d034 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Mon, 16 Jan 2017 17:29:57 +0100 Subject: drm/etnaviv: add cmdbuf suballocator There are 3 big benefits to suballocating a single big DMA buffer for command submission: 1. Avoid hammering CMA. The old way of allocating and freeing a DMA buffer for each submission was hitting some of the real slow pathes in CMA, as this allocator was not designed for a concurrent small buffers load. 2. Less TLB flushes on IOMMUv2. If a new command buffer is mapped into the GPU address space the MMU TLBs need to be flushed. By having one big buffer statically mapped to the GPU, a lot of those flushes can be avoided. 3. No funky workarounds for GC3000. The FE TLB flush on GC3000 isn't reliable. To work around that we tried to lay out the cmdbufs in the GPU address space in a way to avoid this issue. This hasn't always worked if the address space is crowded. A single statically mapped buffer avoids the erratum completely. Signed-off-by: Lucas Stach Reviewed-by: Christian Gmeiner --- drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/etnaviv/etnaviv_gpu.c') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 3a689c3..130d7d5 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -694,8 +694,15 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu) 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: */ - gpu->buffer = etnaviv_cmdbuf_new(gpu, PAGE_SIZE, 0); + gpu->buffer = etnaviv_cmdbuf_new(gpu->cmdbuf_suballoc, PAGE_SIZE, 0); if (!gpu->buffer) { ret = -ENOMEM; dev_err(gpu->dev, "could not create command buffer\n"); @@ -1598,6 +1605,11 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master, gpu->buffer = NULL; } + if (gpu->cmdbuf_suballoc) { + etnaviv_cmdbuf_suballoc_destroy(gpu->cmdbuf_suballoc); + gpu->cmdbuf_suballoc = NULL; + } + if (gpu->mmu) { etnaviv_iommu_destroy(gpu->mmu); gpu->mmu = NULL; -- cgit v1.1