[PATCH V4 10/23] drm/etnaviv: add 'sync point' support
Christian Gmeiner
christian.gmeiner at gmail.com
Tue Sep 12 15:11:42 UTC 2017
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
Signed-off-by: Christian Gmeiner <christian.gmeiner at gmail.com>
---
drivers/gpu/drm/etnaviv/etnaviv_buffer.c | 36 ++++++++++++++++++++++++++++++++
drivers/gpu/drm/etnaviv/etnaviv_drv.h | 1 +
drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 25 ++++++++++++++++++++++
drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 6 ++++++
4 files changed, 68 insertions(+)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c
index ed9588f36bc9..9e7098e3207f 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_buffer.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_buffer.c
@@ -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. */
void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
struct etnaviv_cmdbuf *cmdbuf)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index 058389f93b69..f6cdd694ca51 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -101,6 +101,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_config_mmuv2(struct etnaviv_gpu *gpu, u32 mtlb_addr, u32 safe_addr);
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,
struct etnaviv_cmdbuf *cmdbuf);
void etnaviv_validate_init(void);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 9372296b5b9c..1f5e6b3e1027 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -25,6 +25,7 @@
#include "etnaviv_gpu.h"
#include "etnaviv_gem.h"
#include "etnaviv_mmu.h"
+#include "etnaviv_perfmon.h"
#include "common.xml.h"
#include "state.xml.h"
#include "state_hi.xml.h"
@@ -1359,6 +1360,7 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
}
gpu->event[event].fence = fence;
+ gpu->event[event].sync_point = NULL;
submit->fence = dma_fence_get(fence);
gpu->active_fence = submit->fence->seqno;
@@ -1404,6 +1406,23 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
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 pmrs_worker(struct work_struct *work)
+{
+ struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
+ pmrs_work);
+
+ etnaviv_process_sync_point(gpu, &gpu->event[gpu->pmrs_event]);
+}
+
/*
* Init/Cleanup:
*/
@@ -1450,6 +1469,11 @@ static irqreturn_t irq_handler(int irq, void *data)
dev_dbg(gpu->dev, "event %u\n", event);
+ if (gpu->event[event].sync_point) {
+ gpu->pmrs_event = event;
+ etnaviv_queue_work(gpu->drm, &gpu->pmrs_work);
+ }
+
fence = gpu->event[event].fence;
gpu->event[event].fence = NULL;
dma_fence_signal(fence);
@@ -1653,6 +1677,7 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master,
INIT_LIST_HEAD(&gpu->active_cmd_list);
INIT_WORK(&gpu->retire_work, retire_worker);
+ INIT_WORK(&gpu->pmrs_work, pmrs_worker);
INIT_WORK(&gpu->recover_work, recover_worker);
init_waitqueue_head(&gpu->fence_event);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
index 70e6590aacdf..7d5f785b0f08 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
@@ -89,6 +89,8 @@ struct etnaviv_chip_identity {
struct etnaviv_event {
struct dma_fence *fence;
+
+ void (*sync_point)(struct etnaviv_gpu *gpu, struct etnaviv_event *event);
};
struct etnaviv_cmdbuf_suballoc;
@@ -135,6 +137,10 @@ struct etnaviv_gpu {
/* worker for handling active-list retiring: */
struct work_struct retire_work;
+ /* worker for handling performance monitor requests: */
+ struct work_struct pmrs_work;
+ int pmrs_event;
+
void __iomem *mmio;
int irq;
--
2.13.5
More information about the etnaviv
mailing list