Commit 357713ce authored by Christian Gmeiner's avatar Christian Gmeiner Committed by Lucas Stach

drm/etnaviv: add 'sync point' support

In order to support performance counters in a sane way we need to provide
a method to sync the GPU with the CPU. The GPU can process multpile command
buffers/events per irq. With the help of a 'sync point' we can trigger an event
and stop the GPU/FE immediately. When the CPU is done with is processing it
simply needs to restart the FE and the GPU will process the command stream.

Changes from v1 -> v2:
- process sync point with a work item to keep irq as fast as possible

Changes from v4 -> v5:
- renamed pmrs_* to sync_point_*
- call event_free(..) in sync_point_worker(..)
Signed-off-by: default avatarChristian Gmeiner <christian.gmeiner@gmail.com>
Signed-off-by: default avatarLucas Stach <l.stach@pengutronix.de>
parent 249300c7
...@@ -250,6 +250,42 @@ void etnaviv_buffer_end(struct etnaviv_gpu *gpu) ...@@ -250,6 +250,42 @@ void etnaviv_buffer_end(struct etnaviv_gpu *gpu)
} }
} }
/* Append a 'sync point' to the ring buffer. */
void etnaviv_sync_point_queue(struct etnaviv_gpu *gpu, unsigned int event)
{
struct etnaviv_cmdbuf *buffer = gpu->buffer;
unsigned int waitlink_offset = buffer->user_size - 16;
u32 dwords, target;
/*
* We need at most 3 dwords in the return target:
* 1 event + 1 end + 1 wait + 1 link.
*/
dwords = 4;
target = etnaviv_buffer_reserve(gpu, buffer, dwords);
/* Signal sync point event */
CMD_LOAD_STATE(buffer, VIVS_GL_EVENT, VIVS_GL_EVENT_EVENT_ID(event) |
VIVS_GL_EVENT_FROM_PE);
/* Stop the FE to 'pause' the GPU */
CMD_END(buffer);
/* Append waitlink */
CMD_WAIT(buffer);
CMD_LINK(buffer, 2, etnaviv_cmdbuf_get_va(buffer) +
buffer->user_size - 4);
/*
* Kick off the 'sync point' command by replacing the previous
* WAIT with a link to the address in the ring buffer.
*/
etnaviv_buffer_replace_wait(buffer, waitlink_offset,
VIV_FE_LINK_HEADER_OP_LINK |
VIV_FE_LINK_HEADER_PREFETCH(dwords),
target);
}
/* Append a command buffer to the ring buffer. */ /* Append a command buffer to the ring buffer. */
void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
struct etnaviv_cmdbuf *cmdbuf) struct etnaviv_cmdbuf *cmdbuf)
......
...@@ -100,6 +100,7 @@ int etnaviv_gem_new_userptr(struct drm_device *dev, struct drm_file *file, ...@@ -100,6 +100,7 @@ int etnaviv_gem_new_userptr(struct drm_device *dev, struct drm_file *file,
u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu); u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu);
u16 etnaviv_buffer_config_mmuv2(struct etnaviv_gpu *gpu, u32 mtlb_addr, u32 safe_addr); u16 etnaviv_buffer_config_mmuv2(struct etnaviv_gpu *gpu, u32 mtlb_addr, u32 safe_addr);
void etnaviv_buffer_end(struct etnaviv_gpu *gpu); void etnaviv_buffer_end(struct etnaviv_gpu *gpu);
void etnaviv_sync_point_queue(struct etnaviv_gpu *gpu, unsigned int event);
void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
struct etnaviv_cmdbuf *cmdbuf); struct etnaviv_cmdbuf *cmdbuf);
void etnaviv_validate_init(void); void etnaviv_validate_init(void);
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#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_perfmon.h"
#include "common.xml.h" #include "common.xml.h"
#include "state.xml.h" #include "state.xml.h"
#include "state_hi.xml.h" #include "state_hi.xml.h"
...@@ -1364,6 +1365,7 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, ...@@ -1364,6 +1365,7 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
} }
gpu->event[event].fence = fence; gpu->event[event].fence = fence;
gpu->event[event].sync_point = NULL;
submit->fence = dma_fence_get(fence); submit->fence = dma_fence_get(fence);
gpu->active_fence = submit->fence->seqno; gpu->active_fence = submit->fence->seqno;
...@@ -1409,6 +1411,24 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu, ...@@ -1409,6 +1411,24 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
return ret; return ret;
} }
static void etnaviv_process_sync_point(struct etnaviv_gpu *gpu,
struct etnaviv_event *event)
{
u32 addr = gpu_read(gpu, VIVS_FE_DMA_ADDRESS);
event->sync_point(gpu, event);
etnaviv_gpu_start_fe(gpu, addr + 2, 2);
}
static void sync_point_worker(struct work_struct *work)
{
struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
sync_point_work);
etnaviv_process_sync_point(gpu, &gpu->event[gpu->sync_point_event]);
event_free(gpu, gpu->sync_point_event);
}
/* /*
* Init/Cleanup: * Init/Cleanup:
*/ */
...@@ -1455,6 +1475,11 @@ static irqreturn_t irq_handler(int irq, void *data) ...@@ -1455,6 +1475,11 @@ static irqreturn_t irq_handler(int irq, void *data)
dev_dbg(gpu->dev, "event %u\n", event); dev_dbg(gpu->dev, "event %u\n", event);
if (gpu->event[event].sync_point) {
gpu->sync_point_event = event;
etnaviv_queue_work(gpu->drm, &gpu->sync_point_work);
}
fence = gpu->event[event].fence; fence = gpu->event[event].fence;
gpu->event[event].fence = NULL; gpu->event[event].fence = NULL;
dma_fence_signal(fence); dma_fence_signal(fence);
...@@ -1660,6 +1685,7 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master, ...@@ -1660,6 +1685,7 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master,
INIT_LIST_HEAD(&gpu->active_cmd_list); INIT_LIST_HEAD(&gpu->active_cmd_list);
INIT_WORK(&gpu->retire_work, retire_worker); INIT_WORK(&gpu->retire_work, retire_worker);
INIT_WORK(&gpu->sync_point_work, sync_point_worker);
INIT_WORK(&gpu->recover_work, recover_worker); INIT_WORK(&gpu->recover_work, recover_worker);
init_waitqueue_head(&gpu->fence_event); init_waitqueue_head(&gpu->fence_event);
......
...@@ -89,6 +89,8 @@ struct etnaviv_chip_identity { ...@@ -89,6 +89,8 @@ struct etnaviv_chip_identity {
struct etnaviv_event { struct etnaviv_event {
struct dma_fence *fence; struct dma_fence *fence;
void (*sync_point)(struct etnaviv_gpu *gpu, struct etnaviv_event *event);
}; };
struct etnaviv_cmdbuf_suballoc; struct etnaviv_cmdbuf_suballoc;
...@@ -135,6 +137,10 @@ struct etnaviv_gpu { ...@@ -135,6 +137,10 @@ struct etnaviv_gpu {
/* worker for handling active-list retiring: */ /* worker for handling active-list retiring: */
struct work_struct retire_work; struct work_struct retire_work;
/* worker for handling 'sync' points: */
struct work_struct sync_point_work;
int sync_point_event;
void __iomem *mmio; void __iomem *mmio;
int irq; int irq;
......
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