aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Clark2016-06-20 13:06:24 -0500
committerRob Clark2016-07-20 18:42:21 -0500
commit419a154dbef839b920689bea72aa9af41b2b114f (patch)
treeba0c9c5869dae77d3dc13e5019c6314e61ca624d /freedreno
parentd93d697deb4a808890bc9c64ec453b2d2f2ebb7f (diff)
downloadexternal-libgbm-419a154dbef839b920689bea72aa9af41b2b114f.tar.gz
external-libgbm-419a154dbef839b920689bea72aa9af41b2b114f.tar.xz
external-libgbm-419a154dbef839b920689bea72aa9af41b2b114f.zip
freedreno: support growable cmdstream buffers
The issue that userspace needed to solve is that there is ~two orders of magnitude size difference in cmdstream buffers (both for gmem commands and for draw commands), and that the previous practice of allocating worst-case sizes is quite wasteful. Previously a submit would be constructed (for example) like: CMD TARGET DESCRIPTION g0 N gmem/tiling commands b0 Y binning commands d0 Y draw commands Which, after the one non-IB-target cmd buffer is inserted into the kernel controlled ringbuffer, looks like (not to scale): b0: d0: +-----+ +-----+ IB1 | ... | | ... | +-----+ +-----+ ^ ^ | | +-----+ +-+---------+ g0: | | | +----+----+----+----+----+----+---- IB0 | .. | IB | .. | IB | .. | IB | ... +----+----+----+----+----+----+---- ^ tile0 tile1 | +-----------+ userspace | ~~~~~~~~~~~~~~~~~~~|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ kernel | ----+----+---- ringbuffer ... | IB | ... ----+----+---- Now, multiple physical cmdstream buffers per fd_ringbuffer are supported, so this becomes: CMD TARGET DESCRIPTION g0 N ... N gmem/tiling commands gN N b0 Y ... Y binning commands bN Y d0 Y ... Y draw commands dN Y Which, after the non-IB-target cmd buffers (g0..gN) are inserted into the kernel controlled ringbuffer, looks like: b0: b1 d0: d1 +-----+ +-----+ +-----+ +-----+ IB1 | ... | | ... | ... | ... | | ... | ... +-----+ +-----+ +-----+ +-----+ ^ ^ ^ ^ | | | | | +-+ | +-----+------+ +-----+ | | | | | | +--+----------+ | g0: | | | | | | +----+----+----+----+----+----+---+----+----+---- IB0 | .. | IB | IB | .. | IB | IB |.. | IB | IB |... +----+----+----+----+----+----+---+----+----+---- ^ tile0 tile1 | to b0 to b1 | | | to|d0 to|d1 | | +----+ | +-+-----------+ | | | | | | | +------+ | +-+-------------+ | | g1: | | | | | | | +----+----+----+----+----+----+---+----+----+---- IB0 | | .. | IB | IB | .. | IB | IB |.. | IB | IB |... | +----+----+----+----+----+----+---+----+----+---- | ^ tileX tileY | | | +-----------+ +-----------+ | userspace | | ~~~~~~~~~~~~~~~~~~~|~~~~|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ kernel | | ----+----+----+---- ringbuffer ... | IB | IB | ... ----+----+----+---- Signed-off-by: Rob Clark <robclark@freedesktop.org>
Diffstat (limited to 'freedreno')
-rw-r--r--freedreno/freedreno_priv.h6
-rw-r--r--freedreno/freedreno_ringbuffer.c32
-rw-r--r--freedreno/freedreno_ringbuffer.h2
-rw-r--r--freedreno/kgsl/kgsl_ringbuffer.c7
-rw-r--r--freedreno/msm/msm_ringbuffer.c155
5 files changed, 166 insertions, 36 deletions
diff --git a/freedreno/freedreno_priv.h b/freedreno/freedreno_priv.h
index 9737b322..cdfdbe8d 100644
--- a/freedreno/freedreno_priv.h
+++ b/freedreno/freedreno_priv.h
@@ -134,12 +134,14 @@ struct fd_ringmarker {
134struct fd_ringbuffer_funcs { 134struct fd_ringbuffer_funcs {
135 void * (*hostptr)(struct fd_ringbuffer *ring); 135 void * (*hostptr)(struct fd_ringbuffer *ring);
136 int (*flush)(struct fd_ringbuffer *ring, uint32_t *last_start); 136 int (*flush)(struct fd_ringbuffer *ring, uint32_t *last_start);
137 void (*grow)(struct fd_ringbuffer *ring, uint32_t size);
137 void (*reset)(struct fd_ringbuffer *ring); 138 void (*reset)(struct fd_ringbuffer *ring);
138 void (*emit_reloc)(struct fd_ringbuffer *ring, 139 void (*emit_reloc)(struct fd_ringbuffer *ring,
139 const struct fd_reloc *reloc); 140 const struct fd_reloc *reloc);
140 void (*emit_reloc_ring)(struct fd_ringbuffer *ring, 141 uint32_t (*emit_reloc_ring)(struct fd_ringbuffer *ring,
141 struct fd_ringbuffer *target, 142 struct fd_ringbuffer *target, uint32_t cmd_idx,
142 uint32_t submit_offset, uint32_t size); 143 uint32_t submit_offset, uint32_t size);
144 uint32_t (*cmd_count)(struct fd_ringbuffer *ring);
143 void (*destroy)(struct fd_ringbuffer *ring); 145 void (*destroy)(struct fd_ringbuffer *ring);
144}; 146};
145 147
diff --git a/freedreno/freedreno_ringbuffer.c b/freedreno/freedreno_ringbuffer.c
index 34a06d83..22dafb39 100644
--- a/freedreno/freedreno_ringbuffer.c
+++ b/freedreno/freedreno_ringbuffer.c
@@ -45,10 +45,9 @@ fd_ringbuffer_new(struct fd_pipe *pipe, uint32_t size)
45 if (!ring) 45 if (!ring)
46 return NULL; 46 return NULL;
47 47
48 ring->size = size;
49 ring->pipe = pipe; 48 ring->pipe = pipe;
50 ring->start = ring->funcs->hostptr(ring); 49 ring->start = ring->funcs->hostptr(ring);
51 ring->end = &(ring->start[size/4]); 50 ring->end = &(ring->start[ring->size/4]);
52 51
53 ring->cur = ring->last_start = ring->start; 52 ring->cur = ring->last_start = ring->start;
54 53
@@ -87,6 +86,22 @@ int fd_ringbuffer_flush(struct fd_ringbuffer *ring)
87 return ring->funcs->flush(ring, ring->last_start); 86 return ring->funcs->flush(ring, ring->last_start);
88} 87}
89 88
89void fd_ringbuffer_grow(struct fd_ringbuffer *ring, uint32_t ndwords)
90{
91 assert(ring->funcs->grow); /* unsupported on kgsl */
92
93 /* there is an upper bound on IB size, which appears to be 0x100000 */
94 if (ring->size < 0x100000)
95 ring->size *= 2;
96
97 ring->funcs->grow(ring, ring->size);
98
99 ring->start = ring->funcs->hostptr(ring);
100 ring->end = &(ring->start[ring->size/4]);
101
102 ring->cur = ring->last_start = ring->start;
103}
104
90uint32_t fd_ringbuffer_timestamp(struct fd_ringbuffer *ring) 105uint32_t fd_ringbuffer_timestamp(struct fd_ringbuffer *ring)
91{ 106{
92 return ring->last_timestamp; 107 return ring->last_timestamp;
@@ -108,7 +123,14 @@ void fd_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring,
108 submit_offset = offset_bytes(target->cur, target->ring->start); 123 submit_offset = offset_bytes(target->cur, target->ring->start);
109 size = offset_bytes(end->cur, target->cur); 124 size = offset_bytes(end->cur, target->cur);
110 125
111 ring->funcs->emit_reloc_ring(ring, target->ring, submit_offset, size); 126 ring->funcs->emit_reloc_ring(ring, target->ring, 0, submit_offset, size);
127}
128
129uint32_t fd_ringbuffer_cmd_count(struct fd_ringbuffer *ring)
130{
131 if (!ring->funcs->cmd_count)
132 return 1;
133 return ring->funcs->cmd_count(ring);
112} 134}
113 135
114uint32_t 136uint32_t
@@ -116,9 +138,7 @@ fd_ringbuffer_emit_reloc_ring_full(struct fd_ringbuffer *ring,
116 struct fd_ringbuffer *target, uint32_t cmd_idx) 138 struct fd_ringbuffer *target, uint32_t cmd_idx)
117{ 139{
118 uint32_t size = offset_bytes(target->cur, target->start); 140 uint32_t size = offset_bytes(target->cur, target->start);
119 assert(cmd_idx == 0); 141 return ring->funcs->emit_reloc_ring(ring, target, cmd_idx, 0, size);
120 ring->funcs->emit_reloc_ring(ring, target, 0, size);
121 return size;
122} 142}
123 143
124struct fd_ringmarker * fd_ringmarker_new(struct fd_ringbuffer *ring) 144struct fd_ringmarker * fd_ringmarker_new(struct fd_ringbuffer *ring)
diff --git a/freedreno/freedreno_ringbuffer.h b/freedreno/freedreno_ringbuffer.h
index 643f50b7..8899b5de 100644
--- a/freedreno/freedreno_ringbuffer.h
+++ b/freedreno/freedreno_ringbuffer.h
@@ -56,6 +56,7 @@ void fd_ringbuffer_set_parent(struct fd_ringbuffer *ring,
56 struct fd_ringbuffer *parent); 56 struct fd_ringbuffer *parent);
57void fd_ringbuffer_reset(struct fd_ringbuffer *ring); 57void fd_ringbuffer_reset(struct fd_ringbuffer *ring);
58int fd_ringbuffer_flush(struct fd_ringbuffer *ring); 58int fd_ringbuffer_flush(struct fd_ringbuffer *ring);
59void fd_ringbuffer_grow(struct fd_ringbuffer *ring, uint32_t ndwords);
59uint32_t fd_ringbuffer_timestamp(struct fd_ringbuffer *ring); 60uint32_t fd_ringbuffer_timestamp(struct fd_ringbuffer *ring);
60 61
61static inline void fd_ringbuffer_emit(struct fd_ringbuffer *ring, 62static inline void fd_ringbuffer_emit(struct fd_ringbuffer *ring,
@@ -77,6 +78,7 @@ struct fd_reloc {
77void fd_ringbuffer_reloc(struct fd_ringbuffer *ring, const struct fd_reloc *reloc); 78void fd_ringbuffer_reloc(struct fd_ringbuffer *ring, const struct fd_reloc *reloc);
78will_be_deprecated void fd_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring, 79will_be_deprecated void fd_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring,
79 struct fd_ringmarker *target, struct fd_ringmarker *end); 80 struct fd_ringmarker *target, struct fd_ringmarker *end);
81uint32_t fd_ringbuffer_cmd_count(struct fd_ringbuffer *ring);
80uint32_t fd_ringbuffer_emit_reloc_ring_full(struct fd_ringbuffer *ring, 82uint32_t fd_ringbuffer_emit_reloc_ring_full(struct fd_ringbuffer *ring,
81 struct fd_ringbuffer *target, uint32_t cmd_idx); 83 struct fd_ringbuffer *target, uint32_t cmd_idx);
82 84
diff --git a/freedreno/kgsl/kgsl_ringbuffer.c b/freedreno/kgsl/kgsl_ringbuffer.c
index a0bc9d07..7b3298ab 100644
--- a/freedreno/kgsl/kgsl_ringbuffer.c
+++ b/freedreno/kgsl/kgsl_ringbuffer.c
@@ -173,12 +173,14 @@ static void kgsl_ringbuffer_emit_reloc(struct fd_ringbuffer *ring,
173 kgsl_pipe_add_submit(to_kgsl_pipe(ring->pipe), kgsl_bo); 173 kgsl_pipe_add_submit(to_kgsl_pipe(ring->pipe), kgsl_bo);
174} 174}
175 175
176static void kgsl_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring, 176static uint32_t kgsl_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring,
177 struct fd_ringbuffer *target, 177 struct fd_ringbuffer *target, uint32_t cmd_idx,
178 uint32_t submit_offset, uint32_t size) 178 uint32_t submit_offset, uint32_t size)
179{ 179{
180 struct kgsl_ringbuffer *target_ring = to_kgsl_ringbuffer(target); 180 struct kgsl_ringbuffer *target_ring = to_kgsl_ringbuffer(target);
181 assert(cmd_idx == 0);
181 (*ring->cur++) = target_ring->bo->gpuaddr + submit_offset; 182 (*ring->cur++) = target_ring->bo->gpuaddr + submit_offset;
183 return size;
182} 184}
183 185
184static void kgsl_ringbuffer_destroy(struct fd_ringbuffer *ring) 186static void kgsl_ringbuffer_destroy(struct fd_ringbuffer *ring)
@@ -213,6 +215,7 @@ drm_private struct fd_ringbuffer * kgsl_ringbuffer_new(struct fd_pipe *pipe,
213 215
214 ring = &kgsl_ring->base; 216 ring = &kgsl_ring->base;
215 ring->funcs = &funcs; 217 ring->funcs = &funcs;
218 ring->size = size;
216 219
217 kgsl_ring->bo = kgsl_rb_bo_new(to_kgsl_pipe(pipe), size); 220 kgsl_ring->bo = kgsl_rb_bo_new(to_kgsl_pipe(pipe), size);
218 if (!kgsl_ring->bo) { 221 if (!kgsl_ring->bo) {
diff --git a/freedreno/msm/msm_ringbuffer.c b/freedreno/msm/msm_ringbuffer.c
index 301ac66f..86fc83e0 100644
--- a/freedreno/msm/msm_ringbuffer.c
+++ b/freedreno/msm/msm_ringbuffer.c
@@ -40,12 +40,16 @@
40 * a backing bo, and a reloc table. 40 * a backing bo, and a reloc table.
41 */ 41 */
42struct msm_cmd { 42struct msm_cmd {
43 struct list_head list;
44
43 struct fd_ringbuffer *ring; 45 struct fd_ringbuffer *ring;
44 struct fd_bo *ring_bo; 46 struct fd_bo *ring_bo;
45 47
46 /* reloc's table: */ 48 /* reloc's table: */
47 struct drm_msm_gem_submit_reloc *relocs; 49 struct drm_msm_gem_submit_reloc *relocs;
48 uint32_t nr_relocs, max_relocs; 50 uint32_t nr_relocs, max_relocs;
51
52 uint32_t size;
49}; 53};
50 54
51struct msm_ringbuffer { 55struct msm_ringbuffer {
@@ -75,10 +79,28 @@ struct msm_ringbuffer {
75 struct msm_cmd **cmds; 79 struct msm_cmd **cmds;
76 uint32_t nr_cmds, max_cmds; 80 uint32_t nr_cmds, max_cmds;
77 81
78 /* current cmd-buffer: */ 82 /* List of physical cmdstream buffers (msm_cmd) assocated with this
79 struct msm_cmd *cmd; 83 * logical fd_ringbuffer.
84 *
85 * Note that this is different from msm_ringbuffer::cmds (which
86 * shadows msm_ringbuffer::submit::cmds for tracking submit ioctl
87 * related stuff, and *only* is tracked in the parent ringbuffer.
88 * And only has "completed" cmd buffers (ie. we already know the
89 * size) added via get_cmd().
90 */
91 struct list_head cmd_list;
92
93 int is_growable;
94 unsigned cmd_count;
80}; 95};
81 96
97static inline struct msm_ringbuffer * to_msm_ringbuffer(struct fd_ringbuffer *x)
98{
99 return (struct msm_ringbuffer *)x;
100}
101
102#define INIT_SIZE 0x1000
103
82static pthread_mutex_t idx_lock = PTHREAD_MUTEX_INITIALIZER; 104static pthread_mutex_t idx_lock = PTHREAD_MUTEX_INITIALIZER;
83drm_private extern pthread_mutex_t table_lock; 105drm_private extern pthread_mutex_t table_lock;
84 106
@@ -118,12 +140,15 @@ static void ring_cmd_del(struct msm_cmd *cmd)
118{ 140{
119 if (cmd->ring_bo) 141 if (cmd->ring_bo)
120 ring_bo_del(cmd->ring->pipe->dev, cmd->ring_bo); 142 ring_bo_del(cmd->ring->pipe->dev, cmd->ring_bo);
143 list_del(&cmd->list);
144 to_msm_ringbuffer(cmd->ring)->cmd_count--;
121 free(cmd->relocs); 145 free(cmd->relocs);
122 free(cmd); 146 free(cmd);
123} 147}
124 148
125static struct msm_cmd * ring_cmd_new(struct fd_ringbuffer *ring, uint32_t size) 149static struct msm_cmd * ring_cmd_new(struct fd_ringbuffer *ring, uint32_t size)
126{ 150{
151 struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
127 struct msm_cmd *cmd = calloc(1, sizeof(*cmd)); 152 struct msm_cmd *cmd = calloc(1, sizeof(*cmd));
128 153
129 if (!cmd) 154 if (!cmd)
@@ -134,6 +159,9 @@ static struct msm_cmd * ring_cmd_new(struct fd_ringbuffer *ring, uint32_t size)
134 if (!cmd->ring_bo) 159 if (!cmd->ring_bo)
135 goto fail; 160 goto fail;
136 161
162 list_addtail(&cmd->list, &msm_ring->cmd_list);
163 msm_ring->cmd_count++;
164
137 return cmd; 165 return cmd;
138 166
139fail: 167fail:
@@ -158,9 +186,11 @@ static void *grow(void *ptr, uint32_t nr, uint32_t *max, uint32_t sz)
158 (x)->nr_ ## name ++; \ 186 (x)->nr_ ## name ++; \
159}) 187})
160 188
161static inline struct msm_ringbuffer * to_msm_ringbuffer(struct fd_ringbuffer *x) 189static struct msm_cmd *current_cmd(struct fd_ringbuffer *ring)
162{ 190{
163 return (struct msm_ringbuffer *)x; 191 struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
192 assert(!LIST_IS_EMPTY(&msm_ring->cmd_list));
193 return LIST_LAST_ENTRY(&msm_ring->cmd_list, struct msm_cmd, list);
164} 194}
165 195
166static uint32_t append_bo(struct fd_ringbuffer *ring, struct fd_bo *bo) 196static uint32_t append_bo(struct fd_ringbuffer *ring, struct fd_bo *bo)
@@ -248,12 +278,13 @@ static void get_cmd(struct fd_ringbuffer *ring, struct msm_cmd *target_cmd,
248 cmd->submit_offset = submit_offset; 278 cmd->submit_offset = submit_offset;
249 cmd->size = size; 279 cmd->size = size;
250 cmd->pad = 0; 280 cmd->pad = 0;
281
282 target_cmd->size = size;
251} 283}
252 284
253static void * msm_ringbuffer_hostptr(struct fd_ringbuffer *ring) 285static void * msm_ringbuffer_hostptr(struct fd_ringbuffer *ring)
254{ 286{
255 struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 287 return fd_bo_map(current_cmd(ring)->ring_bo);
256 return fd_bo_map(msm_ring->cmd->ring_bo);
257} 288}
258 289
259static uint32_t find_next_reloc_idx(struct msm_cmd *msm_cmd, 290static uint32_t find_next_reloc_idx(struct msm_cmd *msm_cmd,
@@ -271,6 +302,15 @@ static uint32_t find_next_reloc_idx(struct msm_cmd *msm_cmd,
271 return i; 302 return i;
272} 303}
273 304
305static void delete_cmds(struct msm_ringbuffer *msm_ring)
306{
307 struct msm_cmd *cmd, *tmp;
308
309 LIST_FOR_EACH_ENTRY_SAFE(cmd, tmp, &msm_ring->cmd_list, list) {
310 ring_cmd_del(cmd);
311 }
312}
313
274static void flush_reset(struct fd_ringbuffer *ring) 314static void flush_reset(struct fd_ringbuffer *ring)
275{ 315{
276 struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 316 struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
@@ -288,11 +328,36 @@ static void flush_reset(struct fd_ringbuffer *ring)
288 target_cmd->nr_relocs = 0; 328 target_cmd->nr_relocs = 0;
289 } 329 }
290 330
291 msm_ring->cmd->nr_relocs = 0;
292 msm_ring->submit.nr_cmds = 0; 331 msm_ring->submit.nr_cmds = 0;
293 msm_ring->submit.nr_bos = 0; 332 msm_ring->submit.nr_bos = 0;
294 msm_ring->nr_cmds = 0; 333 msm_ring->nr_cmds = 0;
295 msm_ring->nr_bos = 0; 334 msm_ring->nr_bos = 0;
335
336 if (msm_ring->is_growable) {
337 delete_cmds(msm_ring);
338 } else {
339 /* in old mode, just reset the # of relocs: */
340 current_cmd(ring)->nr_relocs = 0;
341 }
342}
343
344static void finalize_current_cmd(struct fd_ringbuffer *ring, uint32_t *last_start)
345{
346 uint32_t submit_offset, size, type;
347 struct fd_ringbuffer *parent;
348
349 if (ring->parent) {
350 parent = ring->parent;
351 type = MSM_SUBMIT_CMD_IB_TARGET_BUF;
352 } else {
353 parent = ring;
354 type = MSM_SUBMIT_CMD_BUF;
355 }
356
357 submit_offset = offset_bytes(last_start, ring->start);
358 size = offset_bytes(ring->cur, last_start);
359
360 get_cmd(parent, current_cmd(ring), submit_offset, size, type);
296} 361}
297 362
298static void dump_submit(struct msm_ringbuffer *msm_ring) 363static void dump_submit(struct msm_ringbuffer *msm_ring)
@@ -323,13 +388,10 @@ static int msm_ringbuffer_flush(struct fd_ringbuffer *ring, uint32_t *last_start
323 struct drm_msm_gem_submit req = { 388 struct drm_msm_gem_submit req = {
324 .pipe = to_msm_pipe(ring->pipe)->pipe, 389 .pipe = to_msm_pipe(ring->pipe)->pipe,
325 }; 390 };
326 uint32_t i, submit_offset, size; 391 uint32_t i;
327 int ret; 392 int ret;
328 393
329 submit_offset = offset_bytes(last_start, ring->start); 394 finalize_current_cmd(ring, last_start);
330 size = offset_bytes(ring->cur, last_start);
331
332 get_cmd(ring, msm_ring->cmd, submit_offset, size, MSM_SUBMIT_CMD_BUF);
333 395
334 /* needs to be after get_cmd() as that could create bos/cmds table: */ 396 /* needs to be after get_cmd() as that could create bos/cmds table: */
335 req.bos = VOID2U64(msm_ring->submit.bos), 397 req.bos = VOID2U64(msm_ring->submit.bos),
@@ -367,6 +429,13 @@ static int msm_ringbuffer_flush(struct fd_ringbuffer *ring, uint32_t *last_start
367 return ret; 429 return ret;
368} 430}
369 431
432static void msm_ringbuffer_grow(struct fd_ringbuffer *ring, uint32_t size)
433{
434 assert(to_msm_ringbuffer(ring)->is_growable);
435 finalize_current_cmd(ring, ring->last_start);
436 ring_cmd_new(ring, size);
437}
438
370static void msm_ringbuffer_reset(struct fd_ringbuffer *ring) 439static void msm_ringbuffer_reset(struct fd_ringbuffer *ring)
371{ 440{
372 flush_reset(ring); 441 flush_reset(ring);
@@ -375,14 +444,14 @@ static void msm_ringbuffer_reset(struct fd_ringbuffer *ring)
375static void msm_ringbuffer_emit_reloc(struct fd_ringbuffer *ring, 444static void msm_ringbuffer_emit_reloc(struct fd_ringbuffer *ring,
376 const struct fd_reloc *r) 445 const struct fd_reloc *r)
377{ 446{
378 struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
379 struct fd_ringbuffer *parent = ring->parent ? ring->parent : ring; 447 struct fd_ringbuffer *parent = ring->parent ? ring->parent : ring;
380 struct msm_bo *msm_bo = to_msm_bo(r->bo); 448 struct msm_bo *msm_bo = to_msm_bo(r->bo);
381 struct drm_msm_gem_submit_reloc *reloc; 449 struct drm_msm_gem_submit_reloc *reloc;
382 uint32_t idx = APPEND(msm_ring->cmd, relocs); 450 struct msm_cmd *cmd = current_cmd(ring);
451 uint32_t idx = APPEND(cmd, relocs);
383 uint32_t addr; 452 uint32_t addr;
384 453
385 reloc = &msm_ring->cmd->relocs[idx]; 454 reloc = &cmd->relocs[idx];
386 455
387 reloc->reloc_idx = bo2idx(parent, r->bo, r->flags); 456 reloc->reloc_idx = bo2idx(parent, r->bo, r->flags);
388 reloc->reloc_offset = r->offset; 457 reloc->reloc_offset = r->offset;
@@ -398,26 +467,53 @@ static void msm_ringbuffer_emit_reloc(struct fd_ringbuffer *ring,
398 (*ring->cur++) = addr | r->or; 467 (*ring->cur++) = addr | r->or;
399} 468}
400 469
401static void msm_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring, 470static uint32_t msm_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring,
402 struct fd_ringbuffer *target, 471 struct fd_ringbuffer *target, uint32_t cmd_idx,
403 uint32_t submit_offset, uint32_t size) 472 uint32_t submit_offset, uint32_t size)
404{ 473{
405 struct msm_cmd *cmd = to_msm_ringbuffer(target)->cmd; 474 struct msm_cmd *cmd = NULL;
475 uint32_t idx = 0;
476
477 LIST_FOR_EACH_ENTRY(cmd, &to_msm_ringbuffer(target)->cmd_list, list) {
478 if (idx == cmd_idx)
479 break;
480 idx++;
481 }
406 482
407 get_cmd(ring, cmd, submit_offset, size, MSM_SUBMIT_CMD_IB_TARGET_BUF); 483 assert(cmd && (idx == cmd_idx));
484
485 if (idx < (to_msm_ringbuffer(target)->cmd_count - 1)) {
486 /* All but the last cmd buffer is fully "baked" (ie. already has
487 * done get_cmd() to add it to the cmds table). But in this case,
488 * the size we get is invalid (since it is calculated from the
489 * last cmd buffer):
490 */
491 size = cmd->size;
492 } else {
493 get_cmd(ring, cmd, submit_offset, size, MSM_SUBMIT_CMD_IB_TARGET_BUF);
494 }
408 495
409 msm_ringbuffer_emit_reloc(ring, &(struct fd_reloc){ 496 msm_ringbuffer_emit_reloc(ring, &(struct fd_reloc){
410 .bo = cmd->ring_bo, 497 .bo = cmd->ring_bo,
411 .flags = FD_RELOC_READ, 498 .flags = FD_RELOC_READ,
412 .offset = submit_offset, 499 .offset = submit_offset,
413 }); 500 });
501
502 return size;
503}
504
505static uint32_t msm_ringbuffer_cmd_count(struct fd_ringbuffer *ring)
506{
507 return to_msm_ringbuffer(ring)->cmd_count;
414} 508}
415 509
416static void msm_ringbuffer_destroy(struct fd_ringbuffer *ring) 510static void msm_ringbuffer_destroy(struct fd_ringbuffer *ring)
417{ 511{
418 struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); 512 struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring);
419 if (msm_ring->cmd) 513
420 ring_cmd_del(msm_ring->cmd); 514 flush_reset(ring);
515 delete_cmds(msm_ring);
516
421 free(msm_ring->submit.cmds); 517 free(msm_ring->submit.cmds);
422 free(msm_ring->submit.bos); 518 free(msm_ring->submit.bos);
423 free(msm_ring->bos); 519 free(msm_ring->bos);
@@ -428,9 +524,11 @@ static void msm_ringbuffer_destroy(struct fd_ringbuffer *ring)
428static const struct fd_ringbuffer_funcs funcs = { 524static const struct fd_ringbuffer_funcs funcs = {
429 .hostptr = msm_ringbuffer_hostptr, 525 .hostptr = msm_ringbuffer_hostptr,
430 .flush = msm_ringbuffer_flush, 526 .flush = msm_ringbuffer_flush,
527 .grow = msm_ringbuffer_grow,
431 .reset = msm_ringbuffer_reset, 528 .reset = msm_ringbuffer_reset,
432 .emit_reloc = msm_ringbuffer_emit_reloc, 529 .emit_reloc = msm_ringbuffer_emit_reloc,
433 .emit_reloc_ring = msm_ringbuffer_emit_reloc_ring, 530 .emit_reloc_ring = msm_ringbuffer_emit_reloc_ring,
531 .cmd_count = msm_ringbuffer_cmd_count,
434 .destroy = msm_ringbuffer_destroy, 532 .destroy = msm_ringbuffer_destroy,
435}; 533};
436 534
@@ -446,15 +544,20 @@ drm_private struct fd_ringbuffer * msm_ringbuffer_new(struct fd_pipe *pipe,
446 goto fail; 544 goto fail;
447 } 545 }
448 546
547 if (size == 0) {
548 assert(pipe->dev->version >= FD_VERSION_UNLIMITED_CMDS);
549 size = INIT_SIZE;
550 msm_ring->is_growable = TRUE;
551 }
552
553 list_inithead(&msm_ring->cmd_list);
554
449 ring = &msm_ring->base; 555 ring = &msm_ring->base;
450 ring->funcs = &funcs; 556 ring->funcs = &funcs;
557 ring->size = size;
451 ring->pipe = pipe; /* needed in ring_cmd_new() */ 558 ring->pipe = pipe; /* needed in ring_cmd_new() */
452 559
453 msm_ring->cmd = ring_cmd_new(ring, size); 560 ring_cmd_new(ring, size);
454 if (!msm_ring->cmd) {
455 ERROR_MSG("command buffer allocation failed");
456 goto fail;
457 }
458 561
459 return ring; 562 return ring;
460fail: 563fail: