diff options
author | Christian Gmeiner <christian.gmeiner@gmail.com> | 2017-09-24 09:15:28 -0400 |
---|---|---|
committer | Lucas Stach <l.stach@pengutronix.de> | 2017-10-10 05:45:45 -0400 |
commit | 357713ce9bc86c1ae7ba804731d8db542944463c (patch) | |
tree | 6a8a0edd3fc47cb62c172bdf90d04431d880dd81 | |
parent | 249300c740e5bf2b48425e6f0cccc63964a35892 (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.c | 36 | ||||
-rw-r--r-- | drivers/gpu/drm/etnaviv/etnaviv_drv.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 26 | ||||
-rw-r--r-- | drivers/gpu/drm/etnaviv/etnaviv_gpu.h | 6 |
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. */ | ||
254 | void 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. */ |
254 | void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, | 290 | void 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, | |||
100 | u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu); | 100 | u16 etnaviv_buffer_init(struct etnaviv_gpu *gpu); |
101 | u16 etnaviv_buffer_config_mmuv2(struct etnaviv_gpu *gpu, u32 mtlb_addr, u32 safe_addr); | 101 | u16 etnaviv_buffer_config_mmuv2(struct etnaviv_gpu *gpu, u32 mtlb_addr, u32 safe_addr); |
102 | void etnaviv_buffer_end(struct etnaviv_gpu *gpu); | 102 | void etnaviv_buffer_end(struct etnaviv_gpu *gpu); |
103 | void etnaviv_sync_point_queue(struct etnaviv_gpu *gpu, unsigned int event); | ||
103 | void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, | 104 | void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event, |
104 | struct etnaviv_cmdbuf *cmdbuf); | 105 | struct etnaviv_cmdbuf *cmdbuf); |
105 | void etnaviv_validate_init(void); | 106 | void 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 | ||
1414 | static 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 | |||
1423 | static 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 | ||
90 | struct etnaviv_event { | 90 | struct 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 | ||
94 | struct etnaviv_cmdbuf_suballoc; | 96 | struct 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 | ||