Path: blob/21.2-virgl/src/freedreno/drm/freedreno_ringbuffer.h
4564 views
/*1* Copyright (C) 2012-2018 Rob Clark <[email protected]>2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,19* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE20* SOFTWARE.21*22* Authors:23* Rob Clark <[email protected]>24*/2526#ifndef FREEDRENO_RINGBUFFER_H_27#define FREEDRENO_RINGBUFFER_H_2829#include <stdio.h>30#include "util/u_atomic.h"31#include "util/u_debug.h"32#include "util/u_queue.h"3334#include "adreno_common.xml.h"35#include "adreno_pm4.xml.h"36#include "freedreno_drmif.h"37#include "freedreno_pm4.h"3839#ifdef __cplusplus40extern "C" {41#endif4243struct fd_submit;44struct fd_ringbuffer;4546enum fd_ringbuffer_flags {4748/* Primary ringbuffer for a submit, ie. an IB1 level rb49* which kernel must setup RB->IB1 CP_INDIRECT_BRANCH50* packets.51*/52FD_RINGBUFFER_PRIMARY = 0x1,5354/* Hint that the stateobj will be used for streaming state55* that is used once or a few times and then discarded.56*57* For sub-allocation, non streaming stateobj's should be58* sub-allocated from a page size buffer, so one long lived59* state obj doesn't prevent other pages from being freed.60* (Ie. it would be no worse than allocating a page sized61* bo for each small non-streaming stateobj).62*63* But streaming stateobj's could be sub-allocated from a64* larger buffer to reduce the alloc/del overhead.65*/66FD_RINGBUFFER_STREAMING = 0x2,6768/* Indicates that "growable" cmdstream can be used,69* consisting of multiple physical cmdstream buffers70*/71FD_RINGBUFFER_GROWABLE = 0x4,7273/* Internal use only: */74_FD_RINGBUFFER_OBJECT = 0x8,75};7677/* A submit object manages/tracks all the state buildup for a "submit"78* ioctl to the kernel. Additionally, with the exception of long-lived79* non-STREAMING stateobj rb's, rb's are allocated from the submit.80*/81struct fd_submit *fd_submit_new(struct fd_pipe *pipe);8283/* NOTE: all ringbuffer's create from the submit should be unref'd84* before destroying the submit.85*/86void fd_submit_del(struct fd_submit *submit);8788struct fd_submit * fd_submit_ref(struct fd_submit *submit);8990/* Allocate a new rb from the submit. */91struct fd_ringbuffer *fd_submit_new_ringbuffer(struct fd_submit *submit,92uint32_t size,93enum fd_ringbuffer_flags flags);9495/**96* Encapsulates submit out-fence(s), which consist of a 'timestamp' (per-97* pipe (submitqueue) sequence number) and optionally, if requested, an98* out-fence-fd99*/100struct fd_submit_fence {101/**102* The ready fence is signaled once the submit is actually flushed down103* to the kernel, and fence/fence_fd are populated. You must wait for104* this fence to be signaled before reading fence/fence_fd.105*/106struct util_queue_fence ready;107108struct fd_fence fence;109110/**111* Optional dma_fence fd, returned by submit if use_fence_fd is true112*/113int fence_fd;114bool use_fence_fd;115};116117/* in_fence_fd: -1 for no in-fence, else fence fd118* out_fence can be NULL if no output fence is required119*/120int fd_submit_flush(struct fd_submit *submit, int in_fence_fd,121struct fd_submit_fence *out_fence);122123struct fd_ringbuffer;124struct fd_reloc;125126struct fd_ringbuffer_funcs {127void (*grow)(struct fd_ringbuffer *ring, uint32_t size);128void (*emit_reloc)(struct fd_ringbuffer *ring, const struct fd_reloc *reloc);129uint32_t (*emit_reloc_ring)(struct fd_ringbuffer *ring,130struct fd_ringbuffer *target, uint32_t cmd_idx);131uint32_t (*cmd_count)(struct fd_ringbuffer *ring);132bool (*check_size)(struct fd_ringbuffer *ring);133void (*destroy)(struct fd_ringbuffer *ring);134};135136/* the ringbuffer object is not opaque so that OUT_RING() type stuff137* can be inlined. Note that users should not make assumptions about138* the size of this struct.139*/140struct fd_ringbuffer {141uint32_t *cur, *end, *start;142const struct fd_ringbuffer_funcs *funcs;143144// size or end coudl probably go away145int size;146int32_t refcnt;147enum fd_ringbuffer_flags flags;148};149150/* Allocate a new long-lived state object, not associated with151* a submit:152*/153struct fd_ringbuffer *fd_ringbuffer_new_object(struct fd_pipe *pipe,154uint32_t size);155156static inline void157fd_ringbuffer_del(struct fd_ringbuffer *ring)158{159if (!p_atomic_dec_zero(&ring->refcnt))160return;161162ring->funcs->destroy(ring);163}164165static inline struct fd_ringbuffer *166fd_ringbuffer_ref(struct fd_ringbuffer *ring)167{168p_atomic_inc(&ring->refcnt);169return ring;170}171172static inline void173fd_ringbuffer_grow(struct fd_ringbuffer *ring, uint32_t ndwords)174{175assert(ring->funcs->grow); /* unsupported on kgsl */176177/* there is an upper bound on IB size, which appears to be 0x0fffff */178ring->size = MIN2(ring->size << 1, 0x0fffff);179180ring->funcs->grow(ring, ring->size);181}182183static inline bool184fd_ringbuffer_check_size(struct fd_ringbuffer *ring)185{186return ring->funcs->check_size(ring);187}188189static inline void190fd_ringbuffer_emit(struct fd_ringbuffer *ring, uint32_t data)191{192(*ring->cur++) = data;193}194195struct fd_reloc {196struct fd_bo *bo;197uint64_t iova;198#define FD_RELOC_READ 0x0001199#define FD_RELOC_WRITE 0x0002200#define FD_RELOC_DUMP 0x0004201uint32_t offset;202uint32_t orlo;203int32_t shift;204uint32_t orhi; /* used for a5xx+ */205};206207/* We always mark BOs for write, instead of tracking it across reloc208* sources in userspace. On the kernel side, this means we track a single209* excl fence in the BO instead of a set of read fences, which is cheaper.210* The downside is that a dmabuf-shared device won't be able to read in211* parallel with a read-only access by freedreno, but most other drivers212* have decided that that usecase isn't important enough to do this213* tracking, as well.214*/215#define FD_RELOC_FLAGS_INIT (FD_RELOC_READ | FD_RELOC_WRITE)216217/* NOTE: relocs are 2 dwords on a5xx+ */218219static inline void220fd_ringbuffer_reloc(struct fd_ringbuffer *ring, const struct fd_reloc *reloc)221{222ring->funcs->emit_reloc(ring, reloc);223}224225static inline uint32_t226fd_ringbuffer_cmd_count(struct fd_ringbuffer *ring)227{228if (!ring->funcs->cmd_count)229return 1;230return ring->funcs->cmd_count(ring);231}232233static inline uint32_t234fd_ringbuffer_emit_reloc_ring_full(struct fd_ringbuffer *ring,235struct fd_ringbuffer *target,236uint32_t cmd_idx)237{238return ring->funcs->emit_reloc_ring(ring, target, cmd_idx);239}240241static inline uint32_t242offset_bytes(void *end, void *start)243{244return ((char *)end) - ((char *)start);245}246247static inline uint32_t248fd_ringbuffer_size(struct fd_ringbuffer *ring)249{250/* only really needed for stateobj ringbuffers, and won't really251* do what you expect for growable rb's.. so lets just restrict252* this to stateobj's for now:253*/254debug_assert(!(ring->flags & FD_RINGBUFFER_GROWABLE));255return offset_bytes(ring->cur, ring->start);256}257258#define LOG_DWORDS 0259260static inline void261OUT_RING(struct fd_ringbuffer *ring, uint32_t data)262{263if (LOG_DWORDS) {264fprintf(stderr, "ring[%p]: OUT_RING %04x: %08x", ring,265(uint32_t)(ring->cur - ring->start), data);266}267fd_ringbuffer_emit(ring, data);268}269270/*271* NOTE: OUT_RELOC() is 2 dwords (64b) on a5xx+272*/273#ifndef __cplusplus274static inline void275OUT_RELOC(struct fd_ringbuffer *ring, struct fd_bo *bo, uint32_t offset,276uint64_t or, int32_t shift)277{278if (LOG_DWORDS) {279fprintf(stderr, "ring[%p]: OUT_RELOC %04x: %p+%u << %d", ring,280(uint32_t)(ring->cur - ring->start), bo, offset, shift);281}282debug_assert(offset < fd_bo_size(bo));283284uint64_t iova = fd_bo_get_iova(bo) + offset;285286if (shift < 0)287iova >>= -shift;288else289iova <<= shift;290291iova |= or ;292293fd_ringbuffer_reloc(ring, &(struct fd_reloc){294.bo = bo,295.iova = iova,296.offset = offset,297.orlo = or298,299.shift = shift,300.orhi = or >> 32,301});302}303#endif304305static inline void306OUT_RB(struct fd_ringbuffer *ring, struct fd_ringbuffer *target)307{308fd_ringbuffer_emit_reloc_ring_full(ring, target, 0);309}310311static inline void312BEGIN_RING(struct fd_ringbuffer *ring, uint32_t ndwords)313{314if (unlikely(ring->cur + ndwords > ring->end))315fd_ringbuffer_grow(ring, ndwords);316}317318static inline void319OUT_PKT0(struct fd_ringbuffer *ring, uint16_t regindx, uint16_t cnt)320{321BEGIN_RING(ring, cnt + 1);322OUT_RING(ring, pm4_pkt0_hdr(regindx, cnt));323}324325static inline void326OUT_PKT2(struct fd_ringbuffer *ring)327{328BEGIN_RING(ring, 1);329OUT_RING(ring, CP_TYPE2_PKT);330}331332static inline void333OUT_PKT3(struct fd_ringbuffer *ring, uint8_t opcode, uint16_t cnt)334{335BEGIN_RING(ring, cnt + 1);336OUT_RING(ring, CP_TYPE3_PKT | ((cnt - 1) << 16) | ((opcode & 0xFF) << 8));337}338339/*340* Starting with a5xx, pkt4/pkt7 are used instead of pkt0/pkt3341*/342343static inline void344OUT_PKT4(struct fd_ringbuffer *ring, uint16_t regindx, uint16_t cnt)345{346BEGIN_RING(ring, cnt + 1);347OUT_RING(ring, pm4_pkt4_hdr(regindx, cnt));348}349350static inline void351OUT_PKT7(struct fd_ringbuffer *ring, uint8_t opcode, uint16_t cnt)352{353BEGIN_RING(ring, cnt + 1);354OUT_RING(ring, pm4_pkt7_hdr(opcode, cnt));355}356357static inline void358OUT_WFI(struct fd_ringbuffer *ring)359{360OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1);361OUT_RING(ring, 0x00000000);362}363364static inline void365OUT_WFI5(struct fd_ringbuffer *ring)366{367OUT_PKT7(ring, CP_WAIT_FOR_IDLE, 0);368}369370#ifdef __cplusplus371} /* end of extern "C" */372#endif373374#endif /* FREEDRENO_RINGBUFFER_H_ */375376377