aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Gmeiner <christian.gmeiner@gmail.com>2017-09-24 09:15:28 -0400
committerLucas Stach <l.stach@pengutronix.de>2017-10-10 05:45:45 -0400
commit357713ce9bc86c1ae7ba804731d8db542944463c (patch)
tree6a8a0edd3fc47cb62c172bdf90d04431d880dd81
parent249300c740e5bf2b48425e6f0cccc63964a35892 (diff)
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: Christian Gmeiner <christian.gmeiner@gmail.com> Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_buffer.c36
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_drv.h1
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gpu.c26
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gpu.h6
4 files changed, 69 insertions, 0 deletions
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)
250 } 250 }
251} 251}
252 252
253/* Append a 'sync point' to the ring buffer. */
254void etnaviv_sync_point_queue(struct etnaviv_gpu *gpu, unsigned int event)
255{
256 struct etnaviv_cmdbuf *buffer = gpu->buffer;
257 unsigned int waitlink_offset = buffer->user_size - 16;
258 u32 dwords, target;
259
260 /*
261 * We need at most 3 dwords in the return target:
262 * 1 event + 1 end + 1 wait + 1 link.
263 */
264 dwords = 4;
265 target = etnaviv_buffer_reserve(gpu, buffer, dwords);
266
267 /* Signal sync point event */
268 CMD_LOAD_STATE(buffer, VIVS_GL_EVENT, VIVS_GL_EVENT_EVENT_ID(event) |
269 VIVS_GL_EVENT_FROM_PE);
270
271 /* Stop the FE to 'pause' the GPU */
272 CMD_END(buffer);
273
274 /* Append waitlink */
275 CMD_WAIT(buffer);
276 CMD_LINK(buffer, 2, etnaviv_cmdbuf_get_va(buffer) +
277 buffer->user_size - 4);
278
279 /*
280 * Kick off the 'sync point' command by replacing the previous
281 * WAIT with a link to the address in the ring buffer.
282 */
283 etnaviv_buffer_replace_wait(buffer, waitlink_offset,
284 VIV_FE_LINK_HEADER_OP_LINK |
285 VIV_FE_LINK_HEADER_PREFETCH(dwords),
286 target);
287}
288
253/* Append a command buffer to the ring buffer. */ 289/* Append a command buffer to the ring buffer. */
254void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, 290void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
255 struct etnaviv_cmdbuf *cmdbuf) 291 struct etnaviv_cmdbuf *cmdbuf)
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.h b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
index d157d9379e68..203613ae24dc 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_drv.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.h
@@ -100,6 +100,7 @@ int etnaviv_gem_new_userptr(struct drm_device *dev, struct drm_file *file,
100u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu); 100u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu);
101u16 etnaviv_buffer_config_mmuv2(struct etnaviv_gpu *gpu, u32 mtlb_addr, u32 safe_addr); 101u16 etnaviv_buffer_config_mmuv2(struct etnaviv_gpu *gpu, u32 mtlb_addr, u32 safe_addr);
102void etnaviv_buffer_end(struct etnaviv_gpu *gpu); 102void etnaviv_buffer_end(struct etnaviv_gpu *gpu);
103void etnaviv_sync_point_queue(struct etnaviv_gpu *gpu, unsigned int event);
103void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, 104void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
104 struct etnaviv_cmdbuf *cmdbuf); 105 struct etnaviv_cmdbuf *cmdbuf);
105void etnaviv_validate_init(void); 106void etnaviv_validate_init(void);
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 7b61071af0de..cd70e7c04305 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -25,6 +25,7 @@
25#include "etnaviv_gpu.h" 25#include "etnaviv_gpu.h"
26#include "etnaviv_gem.h" 26#include "etnaviv_gem.h"
27#include "etnaviv_mmu.h" 27#include "etnaviv_mmu.h"
28#include "etnaviv_perfmon.h"
28#include "common.xml.h" 29#include "common.xml.h"
29#include "state.xml.h" 30#include "state.xml.h"
30#include "state_hi.xml.h" 31#include "state_hi.xml.h"
@@ -1364,6 +1365,7 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
1364 } 1365 }
1365 1366
1366 gpu->event[event].fence = fence; 1367 gpu->event[event].fence = fence;
1368 gpu->event[event].sync_point = NULL;
1367 submit->fence = dma_fence_get(fence); 1369 submit->fence = dma_fence_get(fence);
1368 gpu->active_fence = submit->fence->seqno; 1370 gpu->active_fence = submit->fence->seqno;
1369 1371
@@ -1409,6 +1411,24 @@ out_pm_put:
1409 return ret; 1411 return ret;
1410} 1412}
1411 1413
1414static void etnaviv_process_sync_point(struct etnaviv_gpu *gpu,
1415 struct etnaviv_event *event)
1416{
1417 u32 addr = gpu_read(gpu, VIVS_FE_DMA_ADDRESS);
1418
1419 event->sync_point(gpu, event);
1420 etnaviv_gpu_start_fe(gpu, addr + 2, 2);
1421}
1422
1423static void sync_point_worker(struct work_struct *work)
1424{
1425 struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
1426 sync_point_work);
1427
1428 etnaviv_process_sync_point(gpu, &gpu->event[gpu->sync_point_event]);
1429 event_free(gpu, gpu->sync_point_event);
1430}
1431
1412/* 1432/*
1413 * Init/Cleanup: 1433 * Init/Cleanup:
1414 */ 1434 */
@@ -1455,6 +1475,11 @@ static irqreturn_t irq_handler(int irq, void *data)
1455 1475
1456 dev_dbg(gpu->dev, "event %u\n", event); 1476 dev_dbg(gpu->dev, "event %u\n", event);
1457 1477
1478 if (gpu->event[event].sync_point) {
1479 gpu->sync_point_event = event;
1480 etnaviv_queue_work(gpu->drm, &gpu->sync_point_work);
1481 }
1482
1458 fence = gpu->event[event].fence; 1483 fence = gpu->event[event].fence;
1459 gpu->event[event].fence = NULL; 1484 gpu->event[event].fence = NULL;
1460 dma_fence_signal(fence); 1485 dma_fence_signal(fence);
@@ -1660,6 +1685,7 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master,
1660 1685
1661 INIT_LIST_HEAD(&gpu->active_cmd_list); 1686 INIT_LIST_HEAD(&gpu->active_cmd_list);
1662 INIT_WORK(&gpu->retire_work, retire_worker); 1687 INIT_WORK(&gpu->retire_work, retire_worker);
1688 INIT_WORK(&gpu->sync_point_work, sync_point_worker);
1663 INIT_WORK(&gpu->recover_work, recover_worker); 1689 INIT_WORK(&gpu->recover_work, recover_worker);
1664 init_waitqueue_head(&gpu->fence_event); 1690 init_waitqueue_head(&gpu->fence_event);
1665 1691
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
index 70e6590aacdf..3be5cb53e89f 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 {
89 89
90struct etnaviv_event { 90struct etnaviv_event {
91 struct dma_fence *fence; 91 struct dma_fence *fence;
92
93 void (*sync_point)(struct etnaviv_gpu *gpu, struct etnaviv_event *event);
92}; 94};
93 95
94struct etnaviv_cmdbuf_suballoc; 96struct etnaviv_cmdbuf_suballoc;
@@ -135,6 +137,10 @@ struct etnaviv_gpu {
135 /* worker for handling active-list retiring: */ 137 /* worker for handling active-list retiring: */
136 struct work_struct retire_work; 138 struct work_struct retire_work;
137 139
140 /* worker for handling 'sync' points: */
141 struct work_struct sync_point_work;
142 int sync_point_event;
143
138 void __iomem *mmio; 144 void __iomem *mmio;
139 int irq; 145 int irq;
140 146