gallium/radeon: fix (S)DMA read-after-write hazards
[mesa.git] / src / gallium / drivers / radeonsi / cik_sdma.c
1 /*
2 * Copyright 2010 Jerome Glisse <glisse@freedesktop.org>
3 * Copyright 2014,2015 Advanced Micro Devices, Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * on the rights to use, copy, modify, merge, publish, distribute, sub
9 * license, and/or sell copies of the Software, and to permit persons to whom
10 * the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22 * USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Jerome Glisse
26 */
27
28 #include "sid.h"
29 #include "si_pipe.h"
30 #include "radeon/r600_cs.h"
31
32 #include "util/u_format.h"
33
34 static void cik_sdma_do_copy_buffer(struct si_context *ctx,
35 struct pipe_resource *dst,
36 struct pipe_resource *src,
37 uint64_t dst_offset,
38 uint64_t src_offset,
39 uint64_t size)
40 {
41 struct radeon_winsys_cs *cs = ctx->b.dma.cs;
42 unsigned i, ncopy, csize;
43 struct r600_resource *rdst = (struct r600_resource*)dst;
44 struct r600_resource *rsrc = (struct r600_resource*)src;
45
46 dst_offset += r600_resource(dst)->gpu_address;
47 src_offset += r600_resource(src)->gpu_address;
48
49 ncopy = DIV_ROUND_UP(size, CIK_SDMA_COPY_MAX_SIZE);
50 r600_need_dma_space(&ctx->b, ncopy * 7);
51
52 radeon_add_to_buffer_list(&ctx->b, &ctx->b.dma, rsrc, RADEON_USAGE_READ,
53 RADEON_PRIO_SDMA_BUFFER);
54 radeon_add_to_buffer_list(&ctx->b, &ctx->b.dma, rdst, RADEON_USAGE_WRITE,
55 RADEON_PRIO_SDMA_BUFFER);
56
57 for (i = 0; i < ncopy; i++) {
58 csize = MIN2(size, CIK_SDMA_COPY_MAX_SIZE);
59 cs->buf[cs->cdw++] = CIK_SDMA_PACKET(CIK_SDMA_OPCODE_COPY,
60 CIK_SDMA_COPY_SUB_OPCODE_LINEAR,
61 0);
62 cs->buf[cs->cdw++] = csize;
63 cs->buf[cs->cdw++] = 0; /* src/dst endian swap */
64 cs->buf[cs->cdw++] = src_offset;
65 cs->buf[cs->cdw++] = src_offset >> 32;
66 cs->buf[cs->cdw++] = dst_offset;
67 cs->buf[cs->cdw++] = dst_offset >> 32;
68 dst_offset += csize;
69 src_offset += csize;
70 size -= csize;
71 }
72 }
73
74 static void cik_sdma_copy_buffer(struct si_context *ctx,
75 struct pipe_resource *dst,
76 struct pipe_resource *src,
77 uint64_t dst_offset,
78 uint64_t src_offset,
79 uint64_t size)
80 {
81 struct r600_resource *rdst = (struct r600_resource*)dst;
82
83 /* Mark the buffer range of destination as valid (initialized),
84 * so that transfer_map knows it should wait for the GPU when mapping
85 * that range. */
86 util_range_add(&rdst->valid_buffer_range, dst_offset,
87 dst_offset + size);
88
89 cik_sdma_do_copy_buffer(ctx, dst, src, dst_offset, src_offset, size);
90 r600_dma_emit_wait_idle(&ctx->b);
91 }
92
93 static void cik_sdma_copy(struct pipe_context *ctx,
94 struct pipe_resource *dst,
95 unsigned dst_level,
96 unsigned dstx, unsigned dsty, unsigned dstz,
97 struct pipe_resource *src,
98 unsigned src_level,
99 const struct pipe_box *src_box)
100 {
101 struct si_context *sctx = (struct si_context *)ctx;
102
103 if (!sctx->b.dma.cs)
104 goto fallback;
105
106 if (dst->target == PIPE_BUFFER && src->target == PIPE_BUFFER) {
107 cik_sdma_copy_buffer(sctx, dst, src, dstx, src_box->x, src_box->width);
108 return;
109 }
110
111 fallback:
112 si_resource_copy_region(ctx, dst, dst_level, dstx, dsty, dstz,
113 src, src_level, src_box);
114 }
115
116 void cik_init_sdma_functions(struct si_context *sctx)
117 {
118 sctx->b.dma_copy = cik_sdma_copy;
119 }