1 /* 2 * Copyright 2021 Google LLC 3 * SPDX-License-Identifier: MIT 4 */ 5 6 #ifndef VKR_RING_H 7 #define VKR_RING_H 8 9 #include "vkr_common.h" 10 11 /* We read from the ring buffer to a temporary buffer for 12 * virgl_context::submit_cmd. Until that is changed, we want to put a limit 13 * on the size of the temporary buffer. It also makes no sense to have huge 14 * rings. 15 * 16 * This must not exceed UINT32_MAX because the ring head and tail are 32-bit. 17 */ 18 #define VKR_RING_BUFFER_MAX_SIZE (16u * 1024 * 1024) 19 20 /* The layout of a ring in a virgl_resource. This is parsed and discarded by 21 * vkr_ring_create. 22 */ 23 struct vkr_ring_layout { 24 const struct vkr_resource_attachment *attachment; 25 26 struct vkr_region head; 27 struct vkr_region tail; 28 struct vkr_region status; 29 struct vkr_region buffer; 30 struct vkr_region extra; 31 }; 32 33 static_assert(ATOMIC_INT_LOCK_FREE == 2 && sizeof(atomic_uint) == 4, 34 "vkr_ring_control requires lock-free 32-bit atomic_uint"); 35 36 /* the control region of a ring */ 37 struct vkr_ring_control { 38 /* Pointers to ring head, tail, and status. 39 * 40 * Clients increment the tail after commands are added. We increment the 41 * head after commands are executed. The status is updated when there is a 42 * status change to the ring thread. 43 */ 44 volatile atomic_uint *head; 45 const volatile atomic_uint *tail; 46 volatile atomic_uint *status; 47 }; 48 49 /* the buffer region of a ring */ 50 struct vkr_ring_buffer { 51 /* the base of the region in the resource */ 52 int base_iov_index; 53 size_t base_iov_offset; 54 55 uint32_t size; 56 uint32_t mask; 57 58 /* The current offset in the buffer region. It is free-running and must be 59 * masked to be between [0, size). 60 */ 61 uint32_t cur; 62 63 /* The current iov and iov offset in the resource. */ 64 const struct iovec *cur_iov; 65 int cur_iov_index; 66 size_t cur_iov_offset; 67 }; 68 69 /* the extra region of a ring */ 70 struct vkr_ring_extra { 71 /* the base of the region in the resource */ 72 int base_iov_index; 73 size_t base_iov_offset; 74 75 /* used for offset validation */ 76 struct vkr_region region; 77 78 /* cache the latest offset->pointer result */ 79 size_t cached_offset; 80 volatile atomic_uint *cached_data; 81 }; 82 83 struct vkr_ring { 84 /* used by the caller */ 85 vkr_object_id id; 86 struct list_head head; 87 88 /* ring regions */ 89 const struct vkr_resource_attachment *attachment; 90 struct vkr_ring_control control; 91 struct vkr_ring_buffer buffer; 92 struct vkr_ring_extra extra; 93 94 /* ring thread */ 95 struct virgl_context *context; 96 uint64_t idle_timeout; 97 void *cmd; 98 99 mtx_t mutex; 100 cnd_t cond; 101 thrd_t thread; 102 atomic_bool started; 103 atomic_bool pending_notify; 104 }; 105 106 struct vkr_ring * 107 vkr_ring_create(const struct vkr_ring_layout *layout, 108 struct virgl_context *ctx, 109 uint64_t idle_timeout); 110 111 void 112 vkr_ring_destroy(struct vkr_ring *ring); 113 114 void 115 vkr_ring_start(struct vkr_ring *ring); 116 117 bool 118 vkr_ring_stop(struct vkr_ring *ring); 119 120 void 121 vkr_ring_notify(struct vkr_ring *ring); 122 123 bool 124 vkr_ring_write_extra(struct vkr_ring *ring, size_t offset, uint32_t val); 125 126 #endif /* VKR_RING_H */ 127