diff --git a/freedreno/freedreno-symbol-check b/freedreno/freedreno-symbol-check index 6da9d667..002a3989 100755 --- a/freedreno/freedreno-symbol-check +++ b/freedreno/freedreno-symbol-check @@ -49,6 +49,7 @@ fd_ringbuffer_flush fd_ringbuffer_grow fd_ringbuffer_new fd_ringbuffer_new_object +fd_ringbuffer_ref fd_ringbuffer_reloc fd_ringbuffer_reloc2 fd_ringbuffer_reset diff --git a/freedreno/freedreno_ringbuffer.c b/freedreno/freedreno_ringbuffer.c index 1fa33b7a..80af736f 100644 --- a/freedreno/freedreno_ringbuffer.c +++ b/freedreno/freedreno_ringbuffer.c @@ -71,11 +71,21 @@ fd_ringbuffer_new_object(struct fd_pipe *pipe, uint32_t size) drm_public void fd_ringbuffer_del(struct fd_ringbuffer *ring) { - if (!(ring->flags & FD_RINGBUFFER_OBJECT)) - fd_ringbuffer_reset(ring); + if (!atomic_dec_and_test(&ring->refcnt)) + return; + + fd_ringbuffer_reset(ring); ring->funcs->destroy(ring); } +drm_public struct fd_ringbuffer * +fd_ringbuffer_ref(struct fd_ringbuffer *ring) +{ + STATIC_ASSERT(sizeof(ring->refcnt) <= sizeof(ring->__pad)); + atomic_inc(&ring->refcnt); + return ring; +} + /* ringbuffers which are IB targets should set the toplevel rb (ie. * the IB source) as it's parent before emitting reloc's, to ensure * the bookkeeping works out properly. diff --git a/freedreno/freedreno_ringbuffer.h b/freedreno/freedreno_ringbuffer.h index 69e7ed99..b2e8024d 100644 --- a/freedreno/freedreno_ringbuffer.h +++ b/freedreno/freedreno_ringbuffer.h @@ -53,6 +53,19 @@ struct fd_ringbuffer { void *user; uint32_t flags; + + /* This is a bit gross, but we can't use atomic_t in exported + * headers. OTOH, we don't need the refcnt to be publicly + * visible. The only reason that this struct is exported is + * because fd_ringbuffer_emit needs to be something that can + * be inlined for performance reasons. + */ + union { +#ifdef HAS_ATOMIC_OPS + atomic_t refcnt; +#endif + uint64_t __pad; + }; }; struct fd_ringbuffer * fd_ringbuffer_new(struct fd_pipe *pipe, @@ -60,6 +73,7 @@ struct fd_ringbuffer * fd_ringbuffer_new(struct fd_pipe *pipe, struct fd_ringbuffer * fd_ringbuffer_new_object(struct fd_pipe *pipe, uint32_t size); +struct fd_ringbuffer *fd_ringbuffer_ref(struct fd_ringbuffer *ring); void fd_ringbuffer_del(struct fd_ringbuffer *ring); void fd_ringbuffer_set_parent(struct fd_ringbuffer *ring, struct fd_ringbuffer *parent); diff --git a/freedreno/kgsl/kgsl_ringbuffer.c b/freedreno/kgsl/kgsl_ringbuffer.c index e4fdf342..7361f7d5 100644 --- a/freedreno/kgsl/kgsl_ringbuffer.c +++ b/freedreno/kgsl/kgsl_ringbuffer.c @@ -216,6 +216,8 @@ drm_private struct fd_ringbuffer * kgsl_ringbuffer_new(struct fd_pipe *pipe, } ring = &kgsl_ring->base; + atomic_set(&ring->refcnt, 1); + ring->funcs = &funcs; ring->size = size; diff --git a/freedreno/msm/msm_ringbuffer.c b/freedreno/msm/msm_ringbuffer.c index 5a088818..a102ca35 100644 --- a/freedreno/msm/msm_ringbuffer.c +++ b/freedreno/msm/msm_ringbuffer.c @@ -29,6 +29,7 @@ #include #include +#include "xf86atomic.h" #include "freedreno_ringbuffer.h" #include "msm_priv.h" @@ -50,8 +51,6 @@ struct msm_cmd { struct msm_ringbuffer { struct fd_ringbuffer base; - atomic_t refcnt; - /* submit ioctl related tables: * Note that bos and cmds are tracked by the parent ringbuffer, since * that is global to the submit ioctl call. The reloc's table is tracked @@ -97,9 +96,6 @@ static inline struct msm_ringbuffer * to_msm_ringbuffer(struct fd_ringbuffer *x) return (struct msm_ringbuffer *)x; } -static void msm_ringbuffer_unref(struct fd_ringbuffer *ring); -static void msm_ringbuffer_ref(struct fd_ringbuffer *ring); - #define INIT_SIZE 0x1000 static pthread_mutex_t idx_lock = PTHREAD_MUTEX_INITIALIZER; @@ -454,7 +450,7 @@ static int msm_ringbuffer_flush(struct fd_ringbuffer *ring, uint32_t *last_start if (msm_cmd->ring->flags & FD_RINGBUFFER_OBJECT) { /* we could have dropped last reference: */ msm_ring->cmds[i] = NULL; - msm_ringbuffer_unref(msm_cmd->ring); + fd_ringbuffer_del(msm_cmd->ring); free(U642VOID(cmd->relocs)); } } @@ -568,7 +564,7 @@ static uint32_t msm_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring, * destroyed after emitted but before flush, so we must hold a ref: */ if (added_cmd && (target->flags & FD_RINGBUFFER_OBJECT)) { - msm_ringbuffer_ref(target); + fd_ringbuffer_ref(target); } return size; @@ -579,13 +575,10 @@ static uint32_t msm_ringbuffer_cmd_count(struct fd_ringbuffer *ring) return to_msm_ringbuffer(ring)->cmd_count; } -static void msm_ringbuffer_unref(struct fd_ringbuffer *ring) +static void msm_ringbuffer_destroy(struct fd_ringbuffer *ring) { struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); - if (!atomic_dec_and_test(&msm_ring->refcnt)) - return; - flush_reset(ring); delete_cmds(msm_ring); @@ -596,12 +589,6 @@ static void msm_ringbuffer_unref(struct fd_ringbuffer *ring) free(msm_ring); } -static void msm_ringbuffer_ref(struct fd_ringbuffer *ring) -{ - struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); - atomic_inc(&msm_ring->refcnt); -} - static const struct fd_ringbuffer_funcs funcs = { .hostptr = msm_ringbuffer_hostptr, .flush = msm_ringbuffer_flush, @@ -610,7 +597,7 @@ static const struct fd_ringbuffer_funcs funcs = { .emit_reloc = msm_ringbuffer_emit_reloc, .emit_reloc_ring = msm_ringbuffer_emit_reloc_ring, .cmd_count = msm_ringbuffer_cmd_count, - .destroy = msm_ringbuffer_unref, + .destroy = msm_ringbuffer_destroy, }; drm_private struct fd_ringbuffer * msm_ringbuffer_new(struct fd_pipe *pipe, @@ -633,9 +620,10 @@ drm_private struct fd_ringbuffer * msm_ringbuffer_new(struct fd_pipe *pipe, list_inithead(&msm_ring->cmd_list); msm_ring->seqno = ++to_msm_device(pipe->dev)->ring_cnt; - atomic_set(&msm_ring->refcnt, 1); ring = &msm_ring->base; + atomic_set(&ring->refcnt, 1); + ring->funcs = &funcs; ring->size = size; ring->pipe = pipe; /* needed in ring_cmd_new() */