2 * Copyright (C) 2014-2015 Etnaviv Project
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * Christian Gmeiner <christian.gmeiner@gmail.com>
29 #include "etnaviv_drmif.h"
30 #include "etnaviv_priv.h"
32 static pthread_mutex_t idx_lock
= PTHREAD_MUTEX_INITIALIZER
;
34 static void *grow(void *ptr
, uint32_t nr
, uint32_t *max
, uint32_t sz
)
36 if ((nr
+ 1) > *max
) {
37 if ((*max
* 2) < (nr
+ 1))
41 ptr
= realloc(ptr
, *max
* sz
);
47 #define APPEND(x, name) ({ \
48 (x)->name = grow((x)->name, (x)->nr_ ## name, &(x)->max_ ## name, sizeof((x)->name[0])); \
49 (x)->nr_ ## name ++; \
52 static inline struct etna_cmd_stream_priv
*
53 etna_cmd_stream_priv(struct etna_cmd_stream
*stream
)
55 return (struct etna_cmd_stream_priv
*)stream
;
58 struct etna_cmd_stream
*etna_cmd_stream_new(struct etna_pipe
*pipe
,
60 void (*reset_notify
)(struct etna_cmd_stream
*stream
, void *priv
),
63 struct etna_cmd_stream_priv
*stream
= NULL
;
66 ERROR_MSG("invalid size of 0");
70 stream
= calloc(1, sizeof(*stream
));
72 ERROR_MSG("allocation failed");
76 /* allocate even number of 32-bit words */
77 size
= ALIGN(size
, 2);
79 stream
->base
.buffer
= malloc(size
* sizeof(uint32_t));
80 if (!stream
->base
.buffer
) {
81 ERROR_MSG("allocation failed");
85 stream
->base
.size
= size
;
87 stream
->reset_notify
= reset_notify
;
88 stream
->reset_notify_priv
= priv
;
94 etna_cmd_stream_del(&stream
->base
);
99 void etna_cmd_stream_del(struct etna_cmd_stream
*stream
)
101 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
103 free(stream
->buffer
);
104 free(priv
->submit
.relocs
);
105 free(priv
->submit
.pmrs
);
109 static void reset_buffer(struct etna_cmd_stream
*stream
)
111 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
114 priv
->submit
.nr_bos
= 0;
115 priv
->submit
.nr_relocs
= 0;
116 priv
->submit
.nr_pmrs
= 0;
119 if (priv
->reset_notify
)
120 priv
->reset_notify(stream
, priv
->reset_notify_priv
);
123 uint32_t etna_cmd_stream_timestamp(struct etna_cmd_stream
*stream
)
125 return etna_cmd_stream_priv(stream
)->last_timestamp
;
128 static uint32_t append_bo(struct etna_cmd_stream
*stream
, struct etna_bo
*bo
)
130 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
133 idx
= APPEND(&priv
->submit
, bos
);
134 idx
= APPEND(priv
, bos
);
136 priv
->submit
.bos
[idx
].flags
= 0;
137 priv
->submit
.bos
[idx
].handle
= bo
->handle
;
139 priv
->bos
[idx
] = etna_bo_ref(bo
);
144 /* add (if needed) bo, return idx: */
145 static uint32_t bo2idx(struct etna_cmd_stream
*stream
, struct etna_bo
*bo
,
148 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
151 pthread_mutex_lock(&idx_lock
);
153 if (bo
->current_stream
== stream
) {
159 priv
->bo_table
= drmHashCreate();
161 if (!drmHashLookup(priv
->bo_table
, bo
->handle
, &val
)) {
163 idx
= (uint32_t)(uintptr_t)val
;
165 idx
= append_bo(stream
, bo
);
166 val
= (void *)(uintptr_t)idx
;
167 drmHashInsert(priv
->bo_table
, bo
->handle
, val
);
170 bo
->current_stream
= stream
;
173 pthread_mutex_unlock(&idx_lock
);
175 if (flags
& ETNA_RELOC_READ
)
176 priv
->submit
.bos
[idx
].flags
|= ETNA_SUBMIT_BO_READ
;
177 if (flags
& ETNA_RELOC_WRITE
)
178 priv
->submit
.bos
[idx
].flags
|= ETNA_SUBMIT_BO_WRITE
;
183 static void flush(struct etna_cmd_stream
*stream
, int in_fence_fd
,
186 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
187 int ret
, id
= priv
->pipe
->id
;
188 struct etna_gpu
*gpu
= priv
->pipe
->gpu
;
190 struct drm_etnaviv_gem_submit req
= {
193 .bos
= VOID2U64(priv
->submit
.bos
),
194 .nr_bos
= priv
->submit
.nr_bos
,
195 .relocs
= VOID2U64(priv
->submit
.relocs
),
196 .nr_relocs
= priv
->submit
.nr_relocs
,
197 .pmrs
= VOID2U64(priv
->submit
.pmrs
),
198 .nr_pmrs
= priv
->submit
.nr_pmrs
,
199 .stream
= VOID2U64(stream
->buffer
),
200 .stream_size
= stream
->offset
* 4, /* in bytes */
203 if (in_fence_fd
!= -1) {
204 req
.flags
|= ETNA_SUBMIT_FENCE_FD_IN
| ETNA_SUBMIT_NO_IMPLICIT
;
205 req
.fence_fd
= in_fence_fd
;
209 req
.flags
|= ETNA_SUBMIT_FENCE_FD_OUT
;
211 ret
= drmCommandWriteRead(gpu
->dev
->fd
, DRM_ETNAVIV_GEM_SUBMIT
,
215 ERROR_MSG("submit failed: %d (%s)", ret
, strerror(errno
));
217 priv
->last_timestamp
= req
.fence
;
219 for (uint32_t i
= 0; i
< priv
->nr_bos
; i
++) {
220 struct etna_bo
*bo
= priv
->bos
[i
];
222 bo
->current_stream
= NULL
;
226 if (priv
->bo_table
) {
227 drmHashDestroy(priv
->bo_table
);
228 priv
->bo_table
= NULL
;
232 *out_fence_fd
= req
.fence_fd
;
235 void etna_cmd_stream_flush(struct etna_cmd_stream
*stream
)
237 flush(stream
, -1, NULL
);
238 reset_buffer(stream
);
241 void etna_cmd_stream_flush2(struct etna_cmd_stream
*stream
,
245 flush(stream
, in_fence_fd
, out_fence_fd
);
246 reset_buffer(stream
);
249 void etna_cmd_stream_finish(struct etna_cmd_stream
*stream
)
251 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
253 flush(stream
, -1, NULL
);
254 etna_pipe_wait(priv
->pipe
, priv
->last_timestamp
, 5000);
255 reset_buffer(stream
);
258 void etna_cmd_stream_reloc(struct etna_cmd_stream
*stream
,
259 const struct etna_reloc
*r
)
261 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
262 struct drm_etnaviv_gem_submit_reloc
*reloc
;
263 uint32_t idx
= APPEND(&priv
->submit
, relocs
);
266 reloc
= &priv
->submit
.relocs
[idx
];
268 reloc
->reloc_idx
= bo2idx(stream
, r
->bo
, r
->flags
);
269 reloc
->reloc_offset
= r
->offset
;
270 reloc
->submit_offset
= stream
->offset
* 4; /* in bytes */
273 etna_cmd_stream_emit(stream
, addr
);
276 void etna_cmd_stream_perf(struct etna_cmd_stream
*stream
, const struct etna_perf
*p
)
278 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
279 struct drm_etnaviv_gem_submit_pmr
*pmr
;
280 uint32_t idx
= APPEND(&priv
->submit
, pmrs
);
282 pmr
= &priv
->submit
.pmrs
[idx
];
284 pmr
->flags
= p
->flags
;
285 pmr
->sequence
= p
->sequence
;
286 pmr
->read_offset
= p
->offset
;
287 pmr
->read_idx
= bo2idx(stream
, p
->bo
, ETNA_SUBMIT_BO_READ
| ETNA_SUBMIT_BO_WRITE
);
288 pmr
->domain
= p
->signal
->domain
->id
;
289 pmr
->signal
= p
->signal
->signal
;