xref: /aosp_15_r20/external/mesa3d/src/virtio/vulkan/vn_common.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker  * Copyright 2019 Google LLC
3*61046927SAndroid Build Coastguard Worker  * SPDX-License-Identifier: MIT
4*61046927SAndroid Build Coastguard Worker  *
5*61046927SAndroid Build Coastguard Worker  * based in part on anv and radv which are:
6*61046927SAndroid Build Coastguard Worker  * Copyright © 2015 Intel Corporation
7*61046927SAndroid Build Coastguard Worker  * Copyright © 2016 Red Hat.
8*61046927SAndroid Build Coastguard Worker  * Copyright © 2016 Bas Nieuwenhuizen
9*61046927SAndroid Build Coastguard Worker  */
10*61046927SAndroid Build Coastguard Worker 
11*61046927SAndroid Build Coastguard Worker #include "vn_common.h"
12*61046927SAndroid Build Coastguard Worker 
13*61046927SAndroid Build Coastguard Worker #include <stdarg.h>
14*61046927SAndroid Build Coastguard Worker 
15*61046927SAndroid Build Coastguard Worker #include "util/log.h"
16*61046927SAndroid Build Coastguard Worker #include "util/os_misc.h"
17*61046927SAndroid Build Coastguard Worker #include "util/u_debug.h"
18*61046927SAndroid Build Coastguard Worker #include "venus-protocol/vn_protocol_driver_info.h"
19*61046927SAndroid Build Coastguard Worker #include "vk_enum_to_str.h"
20*61046927SAndroid Build Coastguard Worker 
21*61046927SAndroid Build Coastguard Worker #include "vn_instance.h"
22*61046927SAndroid Build Coastguard Worker #include "vn_ring.h"
23*61046927SAndroid Build Coastguard Worker 
24*61046927SAndroid Build Coastguard Worker static const struct debug_control vn_debug_options[] = {
25*61046927SAndroid Build Coastguard Worker    /* clang-format off */
26*61046927SAndroid Build Coastguard Worker    { "init", VN_DEBUG_INIT },
27*61046927SAndroid Build Coastguard Worker    { "result", VN_DEBUG_RESULT },
28*61046927SAndroid Build Coastguard Worker    { "vtest", VN_DEBUG_VTEST },
29*61046927SAndroid Build Coastguard Worker    { "wsi", VN_DEBUG_WSI },
30*61046927SAndroid Build Coastguard Worker    { "no_abort", VN_DEBUG_NO_ABORT },
31*61046927SAndroid Build Coastguard Worker    { "log_ctx_info", VN_DEBUG_LOG_CTX_INFO },
32*61046927SAndroid Build Coastguard Worker    { "cache", VN_DEBUG_CACHE },
33*61046927SAndroid Build Coastguard Worker    { "no_sparse", VN_DEBUG_NO_SPARSE },
34*61046927SAndroid Build Coastguard Worker    { "no_gpl", VN_DEBUG_NO_GPL },
35*61046927SAndroid Build Coastguard Worker    { NULL, 0 },
36*61046927SAndroid Build Coastguard Worker    /* clang-format on */
37*61046927SAndroid Build Coastguard Worker };
38*61046927SAndroid Build Coastguard Worker 
39*61046927SAndroid Build Coastguard Worker static const struct debug_control vn_perf_options[] = {
40*61046927SAndroid Build Coastguard Worker    /* clang-format off */
41*61046927SAndroid Build Coastguard Worker    { "no_async_set_alloc", VN_PERF_NO_ASYNC_SET_ALLOC },
42*61046927SAndroid Build Coastguard Worker    { "no_async_buffer_create", VN_PERF_NO_ASYNC_BUFFER_CREATE },
43*61046927SAndroid Build Coastguard Worker    { "no_async_queue_submit", VN_PERF_NO_ASYNC_QUEUE_SUBMIT },
44*61046927SAndroid Build Coastguard Worker    { "no_event_feedback", VN_PERF_NO_EVENT_FEEDBACK },
45*61046927SAndroid Build Coastguard Worker    { "no_fence_feedback", VN_PERF_NO_FENCE_FEEDBACK },
46*61046927SAndroid Build Coastguard Worker    { "no_cmd_batching", VN_PERF_NO_CMD_BATCHING },
47*61046927SAndroid Build Coastguard Worker    { "no_semaphore_feedback", VN_PERF_NO_SEMAPHORE_FEEDBACK },
48*61046927SAndroid Build Coastguard Worker    { "no_query_feedback", VN_PERF_NO_QUERY_FEEDBACK },
49*61046927SAndroid Build Coastguard Worker    { "no_async_mem_alloc", VN_PERF_NO_ASYNC_MEM_ALLOC },
50*61046927SAndroid Build Coastguard Worker    { "no_tiled_wsi_image", VN_PERF_NO_TILED_WSI_IMAGE },
51*61046927SAndroid Build Coastguard Worker    { "no_multi_ring", VN_PERF_NO_MULTI_RING },
52*61046927SAndroid Build Coastguard Worker    { "no_async_image_create", VN_PERF_NO_ASYNC_IMAGE_CREATE },
53*61046927SAndroid Build Coastguard Worker    { "no_async_image_format", VN_PERF_NO_ASYNC_IMAGE_FORMAT },
54*61046927SAndroid Build Coastguard Worker    { NULL, 0 },
55*61046927SAndroid Build Coastguard Worker    /* clang-format on */
56*61046927SAndroid Build Coastguard Worker };
57*61046927SAndroid Build Coastguard Worker 
58*61046927SAndroid Build Coastguard Worker uint64_t vn_next_obj_id = 1;
59*61046927SAndroid Build Coastguard Worker struct vn_env vn_env;
60*61046927SAndroid Build Coastguard Worker 
61*61046927SAndroid Build Coastguard Worker static void
vn_env_init_once(void)62*61046927SAndroid Build Coastguard Worker vn_env_init_once(void)
63*61046927SAndroid Build Coastguard Worker {
64*61046927SAndroid Build Coastguard Worker    vn_env.debug =
65*61046927SAndroid Build Coastguard Worker       parse_debug_string(os_get_option("VN_DEBUG"), vn_debug_options);
66*61046927SAndroid Build Coastguard Worker    vn_env.perf =
67*61046927SAndroid Build Coastguard Worker       parse_debug_string(os_get_option("VN_PERF"), vn_perf_options);
68*61046927SAndroid Build Coastguard Worker }
69*61046927SAndroid Build Coastguard Worker 
70*61046927SAndroid Build Coastguard Worker void
vn_env_init(void)71*61046927SAndroid Build Coastguard Worker vn_env_init(void)
72*61046927SAndroid Build Coastguard Worker {
73*61046927SAndroid Build Coastguard Worker    static once_flag once = ONCE_FLAG_INIT;
74*61046927SAndroid Build Coastguard Worker    call_once(&once, vn_env_init_once);
75*61046927SAndroid Build Coastguard Worker 
76*61046927SAndroid Build Coastguard Worker    /* log per VkInstance creation */
77*61046927SAndroid Build Coastguard Worker    if (VN_DEBUG(INIT)) {
78*61046927SAndroid Build Coastguard Worker       vn_log(NULL,
79*61046927SAndroid Build Coastguard Worker              "vn_env is as below:"
80*61046927SAndroid Build Coastguard Worker              "\n\tdebug = 0x%" PRIx64 ""
81*61046927SAndroid Build Coastguard Worker              "\n\tperf = 0x%" PRIx64 "",
82*61046927SAndroid Build Coastguard Worker              vn_env.debug, vn_env.perf);
83*61046927SAndroid Build Coastguard Worker    }
84*61046927SAndroid Build Coastguard Worker }
85*61046927SAndroid Build Coastguard Worker 
86*61046927SAndroid Build Coastguard Worker void
vn_trace_init(void)87*61046927SAndroid Build Coastguard Worker vn_trace_init(void)
88*61046927SAndroid Build Coastguard Worker {
89*61046927SAndroid Build Coastguard Worker #if DETECT_OS_ANDROID
90*61046927SAndroid Build Coastguard Worker    atrace_init();
91*61046927SAndroid Build Coastguard Worker #else
92*61046927SAndroid Build Coastguard Worker    util_cpu_trace_init();
93*61046927SAndroid Build Coastguard Worker #endif
94*61046927SAndroid Build Coastguard Worker }
95*61046927SAndroid Build Coastguard Worker 
96*61046927SAndroid Build Coastguard Worker void
vn_log(struct vn_instance * instance,const char * format,...)97*61046927SAndroid Build Coastguard Worker vn_log(struct vn_instance *instance, const char *format, ...)
98*61046927SAndroid Build Coastguard Worker {
99*61046927SAndroid Build Coastguard Worker    va_list ap;
100*61046927SAndroid Build Coastguard Worker 
101*61046927SAndroid Build Coastguard Worker    va_start(ap, format);
102*61046927SAndroid Build Coastguard Worker    mesa_log_v(MESA_LOG_DEBUG, "MESA-VIRTIO", format, ap);
103*61046927SAndroid Build Coastguard Worker    va_end(ap);
104*61046927SAndroid Build Coastguard Worker 
105*61046927SAndroid Build Coastguard Worker    /* instance may be NULL or partially initialized */
106*61046927SAndroid Build Coastguard Worker }
107*61046927SAndroid Build Coastguard Worker 
108*61046927SAndroid Build Coastguard Worker VkResult
vn_log_result(struct vn_instance * instance,VkResult result,const char * where)109*61046927SAndroid Build Coastguard Worker vn_log_result(struct vn_instance *instance,
110*61046927SAndroid Build Coastguard Worker               VkResult result,
111*61046927SAndroid Build Coastguard Worker               const char *where)
112*61046927SAndroid Build Coastguard Worker {
113*61046927SAndroid Build Coastguard Worker    vn_log(instance, "%s: %s", where, vk_Result_to_str(result));
114*61046927SAndroid Build Coastguard Worker    return result;
115*61046927SAndroid Build Coastguard Worker }
116*61046927SAndroid Build Coastguard Worker 
117*61046927SAndroid Build Coastguard Worker uint32_t
vn_extension_get_spec_version(const char * name)118*61046927SAndroid Build Coastguard Worker vn_extension_get_spec_version(const char *name)
119*61046927SAndroid Build Coastguard Worker {
120*61046927SAndroid Build Coastguard Worker    const int32_t index = vn_info_extension_index(name);
121*61046927SAndroid Build Coastguard Worker    return index >= 0 ? vn_info_extension_get(index)->spec_version : 0;
122*61046927SAndroid Build Coastguard Worker }
123*61046927SAndroid Build Coastguard Worker 
124*61046927SAndroid Build Coastguard Worker static inline bool
vn_watchdog_timeout(const struct vn_watchdog * watchdog)125*61046927SAndroid Build Coastguard Worker vn_watchdog_timeout(const struct vn_watchdog *watchdog)
126*61046927SAndroid Build Coastguard Worker {
127*61046927SAndroid Build Coastguard Worker    return !watchdog->alive;
128*61046927SAndroid Build Coastguard Worker }
129*61046927SAndroid Build Coastguard Worker 
130*61046927SAndroid Build Coastguard Worker static inline void
vn_watchdog_release(struct vn_watchdog * watchdog)131*61046927SAndroid Build Coastguard Worker vn_watchdog_release(struct vn_watchdog *watchdog)
132*61046927SAndroid Build Coastguard Worker {
133*61046927SAndroid Build Coastguard Worker    if (vn_gettid() == watchdog->tid) {
134*61046927SAndroid Build Coastguard Worker       watchdog->tid = 0;
135*61046927SAndroid Build Coastguard Worker       mtx_unlock(&watchdog->mutex);
136*61046927SAndroid Build Coastguard Worker    }
137*61046927SAndroid Build Coastguard Worker }
138*61046927SAndroid Build Coastguard Worker 
139*61046927SAndroid Build Coastguard Worker static bool
vn_watchdog_acquire(struct vn_watchdog * watchdog,bool alive)140*61046927SAndroid Build Coastguard Worker vn_watchdog_acquire(struct vn_watchdog *watchdog, bool alive)
141*61046927SAndroid Build Coastguard Worker {
142*61046927SAndroid Build Coastguard Worker    pid_t tid = vn_gettid();
143*61046927SAndroid Build Coastguard Worker    if (!watchdog->tid && tid != watchdog->tid &&
144*61046927SAndroid Build Coastguard Worker        mtx_trylock(&watchdog->mutex) == thrd_success) {
145*61046927SAndroid Build Coastguard Worker       /* register as the only waiting thread that monitors the ring. */
146*61046927SAndroid Build Coastguard Worker       watchdog->tid = tid;
147*61046927SAndroid Build Coastguard Worker    }
148*61046927SAndroid Build Coastguard Worker 
149*61046927SAndroid Build Coastguard Worker    if (tid != watchdog->tid)
150*61046927SAndroid Build Coastguard Worker       return false;
151*61046927SAndroid Build Coastguard Worker 
152*61046927SAndroid Build Coastguard Worker    watchdog->alive = alive;
153*61046927SAndroid Build Coastguard Worker    return true;
154*61046927SAndroid Build Coastguard Worker }
155*61046927SAndroid Build Coastguard Worker 
156*61046927SAndroid Build Coastguard Worker void
vn_relax_fini(struct vn_relax_state * state)157*61046927SAndroid Build Coastguard Worker vn_relax_fini(struct vn_relax_state *state)
158*61046927SAndroid Build Coastguard Worker {
159*61046927SAndroid Build Coastguard Worker    vn_watchdog_release(&state->instance->ring.watchdog);
160*61046927SAndroid Build Coastguard Worker }
161*61046927SAndroid Build Coastguard Worker 
162*61046927SAndroid Build Coastguard Worker static inline const char *
vn_relax_reason_string(enum vn_relax_reason reason)163*61046927SAndroid Build Coastguard Worker vn_relax_reason_string(enum vn_relax_reason reason)
164*61046927SAndroid Build Coastguard Worker {
165*61046927SAndroid Build Coastguard Worker    /* deliberately avoid default case for -Wswitch to catch upon compile */
166*61046927SAndroid Build Coastguard Worker    switch (reason) {
167*61046927SAndroid Build Coastguard Worker    case VN_RELAX_REASON_RING_SEQNO:
168*61046927SAndroid Build Coastguard Worker       return "ring seqno";
169*61046927SAndroid Build Coastguard Worker    case VN_RELAX_REASON_TLS_RING_SEQNO:
170*61046927SAndroid Build Coastguard Worker       return "tls ring seqno";
171*61046927SAndroid Build Coastguard Worker    case VN_RELAX_REASON_RING_SPACE:
172*61046927SAndroid Build Coastguard Worker       return "ring space";
173*61046927SAndroid Build Coastguard Worker    case VN_RELAX_REASON_FENCE:
174*61046927SAndroid Build Coastguard Worker       return "fence";
175*61046927SAndroid Build Coastguard Worker    case VN_RELAX_REASON_SEMAPHORE:
176*61046927SAndroid Build Coastguard Worker       return "semaphore";
177*61046927SAndroid Build Coastguard Worker    case VN_RELAX_REASON_QUERY:
178*61046927SAndroid Build Coastguard Worker       return "query";
179*61046927SAndroid Build Coastguard Worker    }
180*61046927SAndroid Build Coastguard Worker    return "";
181*61046927SAndroid Build Coastguard Worker }
182*61046927SAndroid Build Coastguard Worker 
183*61046927SAndroid Build Coastguard Worker static struct vn_relax_profile
vn_relax_get_profile(enum vn_relax_reason reason)184*61046927SAndroid Build Coastguard Worker vn_relax_get_profile(enum vn_relax_reason reason)
185*61046927SAndroid Build Coastguard Worker {
186*61046927SAndroid Build Coastguard Worker    /* This is the helper to map a vn_relax_reason to a profile. For new
187*61046927SAndroid Build Coastguard Worker     * profiles added, we MUST also update the pre-calculated "first_warn_time"
188*61046927SAndroid Build Coastguard Worker     * in vn_watchdog_init() if the "first warn" comes sooner.
189*61046927SAndroid Build Coastguard Worker     */
190*61046927SAndroid Build Coastguard Worker 
191*61046927SAndroid Build Coastguard Worker    /* deliberately avoid default case for -Wswitch to catch upon compile */
192*61046927SAndroid Build Coastguard Worker    switch (reason) {
193*61046927SAndroid Build Coastguard Worker    case VN_RELAX_REASON_RING_SEQNO:
194*61046927SAndroid Build Coastguard Worker       /* warn every 4096 iters after having already slept ~3.5s:
195*61046927SAndroid Build Coastguard Worker        *   (yielded 255 times)
196*61046927SAndroid Build Coastguard Worker        *   stuck in wait with iter at 4096  (3.5s slept already)
197*61046927SAndroid Build Coastguard Worker        *   stuck in wait with iter at 8192  (14s slept already)
198*61046927SAndroid Build Coastguard Worker        *   stuck in wait with iter at 12288 (35s slept already)
199*61046927SAndroid Build Coastguard Worker        *   ...
200*61046927SAndroid Build Coastguard Worker        *   aborting after 895s
201*61046927SAndroid Build Coastguard Worker        */
202*61046927SAndroid Build Coastguard Worker       return (struct vn_relax_profile){
203*61046927SAndroid Build Coastguard Worker          .base_sleep_us = 160,
204*61046927SAndroid Build Coastguard Worker          .busy_wait_order = 8,
205*61046927SAndroid Build Coastguard Worker          .warn_order = 12,
206*61046927SAndroid Build Coastguard Worker          .abort_order = 16,
207*61046927SAndroid Build Coastguard Worker       };
208*61046927SAndroid Build Coastguard Worker    case VN_RELAX_REASON_TLS_RING_SEQNO:
209*61046927SAndroid Build Coastguard Worker    case VN_RELAX_REASON_RING_SPACE:
210*61046927SAndroid Build Coastguard Worker    case VN_RELAX_REASON_FENCE:
211*61046927SAndroid Build Coastguard Worker    case VN_RELAX_REASON_SEMAPHORE:
212*61046927SAndroid Build Coastguard Worker    case VN_RELAX_REASON_QUERY:
213*61046927SAndroid Build Coastguard Worker       /* warn every 1024 iters after having already slept ~3.5s:
214*61046927SAndroid Build Coastguard Worker        *   (yielded 15 times)
215*61046927SAndroid Build Coastguard Worker        *   stuck in wait with iter at 1024 (3.5s slept already)
216*61046927SAndroid Build Coastguard Worker        *   stuck in wait with iter at 2048 (14s slept already)
217*61046927SAndroid Build Coastguard Worker        *   stuck in wait with iter at 3072 (35s slept already)
218*61046927SAndroid Build Coastguard Worker        *   ...
219*61046927SAndroid Build Coastguard Worker        *   aborting after 895s
220*61046927SAndroid Build Coastguard Worker        */
221*61046927SAndroid Build Coastguard Worker       return (struct vn_relax_profile){
222*61046927SAndroid Build Coastguard Worker          .base_sleep_us = 160,
223*61046927SAndroid Build Coastguard Worker          .busy_wait_order = 4,
224*61046927SAndroid Build Coastguard Worker          .warn_order = 10,
225*61046927SAndroid Build Coastguard Worker          .abort_order = 14,
226*61046927SAndroid Build Coastguard Worker       };
227*61046927SAndroid Build Coastguard Worker    }
228*61046927SAndroid Build Coastguard Worker 
229*61046927SAndroid Build Coastguard Worker    unreachable("unhandled vn_relax_reason");
230*61046927SAndroid Build Coastguard Worker }
231*61046927SAndroid Build Coastguard Worker 
232*61046927SAndroid Build Coastguard Worker struct vn_relax_state
vn_relax_init(struct vn_instance * instance,enum vn_relax_reason reason)233*61046927SAndroid Build Coastguard Worker vn_relax_init(struct vn_instance *instance, enum vn_relax_reason reason)
234*61046927SAndroid Build Coastguard Worker {
235*61046927SAndroid Build Coastguard Worker    struct vn_ring *ring = instance->ring.ring;
236*61046927SAndroid Build Coastguard Worker    struct vn_watchdog *watchdog = &instance->ring.watchdog;
237*61046927SAndroid Build Coastguard Worker    if (vn_watchdog_acquire(watchdog, true))
238*61046927SAndroid Build Coastguard Worker       vn_ring_unset_status_bits(ring, VK_RING_STATUS_ALIVE_BIT_MESA);
239*61046927SAndroid Build Coastguard Worker 
240*61046927SAndroid Build Coastguard Worker    return (struct vn_relax_state){
241*61046927SAndroid Build Coastguard Worker       .instance = instance,
242*61046927SAndroid Build Coastguard Worker       .iter = 0,
243*61046927SAndroid Build Coastguard Worker       .profile = vn_relax_get_profile(reason),
244*61046927SAndroid Build Coastguard Worker       .reason_str = vn_relax_reason_string(reason),
245*61046927SAndroid Build Coastguard Worker    };
246*61046927SAndroid Build Coastguard Worker }
247*61046927SAndroid Build Coastguard Worker 
248*61046927SAndroid Build Coastguard Worker void
vn_relax(struct vn_relax_state * state)249*61046927SAndroid Build Coastguard Worker vn_relax(struct vn_relax_state *state)
250*61046927SAndroid Build Coastguard Worker {
251*61046927SAndroid Build Coastguard Worker    const uint32_t base_sleep_us = state->profile.base_sleep_us;
252*61046927SAndroid Build Coastguard Worker    const uint32_t busy_wait_order = state->profile.busy_wait_order;
253*61046927SAndroid Build Coastguard Worker    const uint32_t warn_order = state->profile.warn_order;
254*61046927SAndroid Build Coastguard Worker    const uint32_t abort_order = state->profile.abort_order;
255*61046927SAndroid Build Coastguard Worker 
256*61046927SAndroid Build Coastguard Worker    uint32_t *iter = &state->iter;
257*61046927SAndroid Build Coastguard Worker    (*iter)++;
258*61046927SAndroid Build Coastguard Worker    if (*iter < (1 << busy_wait_order)) {
259*61046927SAndroid Build Coastguard Worker       thrd_yield();
260*61046927SAndroid Build Coastguard Worker       return;
261*61046927SAndroid Build Coastguard Worker    }
262*61046927SAndroid Build Coastguard Worker 
263*61046927SAndroid Build Coastguard Worker    if (unlikely(*iter % (1 << warn_order) == 0)) {
264*61046927SAndroid Build Coastguard Worker       struct vn_instance *instance = state->instance;
265*61046927SAndroid Build Coastguard Worker       vn_log(instance, "stuck in %s wait with iter at %d", state->reason_str,
266*61046927SAndroid Build Coastguard Worker              *iter);
267*61046927SAndroid Build Coastguard Worker 
268*61046927SAndroid Build Coastguard Worker       struct vn_ring *ring = instance->ring.ring;
269*61046927SAndroid Build Coastguard Worker       const uint32_t status = vn_ring_load_status(ring);
270*61046927SAndroid Build Coastguard Worker       if (status & VK_RING_STATUS_FATAL_BIT_MESA) {
271*61046927SAndroid Build Coastguard Worker          vn_log(instance, "aborting on ring fatal error at iter %d", *iter);
272*61046927SAndroid Build Coastguard Worker          abort();
273*61046927SAndroid Build Coastguard Worker       }
274*61046927SAndroid Build Coastguard Worker 
275*61046927SAndroid Build Coastguard Worker       struct vn_watchdog *watchdog = &instance->ring.watchdog;
276*61046927SAndroid Build Coastguard Worker       const bool alive = status & VK_RING_STATUS_ALIVE_BIT_MESA;
277*61046927SAndroid Build Coastguard Worker       if (vn_watchdog_acquire(watchdog, alive))
278*61046927SAndroid Build Coastguard Worker          vn_ring_unset_status_bits(ring, VK_RING_STATUS_ALIVE_BIT_MESA);
279*61046927SAndroid Build Coastguard Worker 
280*61046927SAndroid Build Coastguard Worker       if (vn_watchdog_timeout(watchdog) && !VN_DEBUG(NO_ABORT)) {
281*61046927SAndroid Build Coastguard Worker          vn_log(instance, "aborting on expired ring alive status at iter %d",
282*61046927SAndroid Build Coastguard Worker                 *iter);
283*61046927SAndroid Build Coastguard Worker          abort();
284*61046927SAndroid Build Coastguard Worker       }
285*61046927SAndroid Build Coastguard Worker 
286*61046927SAndroid Build Coastguard Worker       if (*iter >= (1 << abort_order) && !VN_DEBUG(NO_ABORT)) {
287*61046927SAndroid Build Coastguard Worker          vn_log(instance, "aborting");
288*61046927SAndroid Build Coastguard Worker          abort();
289*61046927SAndroid Build Coastguard Worker       }
290*61046927SAndroid Build Coastguard Worker    }
291*61046927SAndroid Build Coastguard Worker 
292*61046927SAndroid Build Coastguard Worker    const uint32_t shift = util_last_bit(*iter) - busy_wait_order - 1;
293*61046927SAndroid Build Coastguard Worker    os_time_sleep(base_sleep_us << shift);
294*61046927SAndroid Build Coastguard Worker }
295*61046927SAndroid Build Coastguard Worker 
296*61046927SAndroid Build Coastguard Worker struct vn_ring *
vn_tls_get_ring(struct vn_instance * instance)297*61046927SAndroid Build Coastguard Worker vn_tls_get_ring(struct vn_instance *instance)
298*61046927SAndroid Build Coastguard Worker {
299*61046927SAndroid Build Coastguard Worker    if (VN_PERF(NO_MULTI_RING))
300*61046927SAndroid Build Coastguard Worker       return instance->ring.ring;
301*61046927SAndroid Build Coastguard Worker 
302*61046927SAndroid Build Coastguard Worker    struct vn_tls *tls = vn_tls_get();
303*61046927SAndroid Build Coastguard Worker    if (unlikely(!tls)) {
304*61046927SAndroid Build Coastguard Worker       /* only allow to fallback on missing tls */
305*61046927SAndroid Build Coastguard Worker       return instance->ring.ring;
306*61046927SAndroid Build Coastguard Worker    }
307*61046927SAndroid Build Coastguard Worker 
308*61046927SAndroid Build Coastguard Worker    /* look up tls_ring owned by instance */
309*61046927SAndroid Build Coastguard Worker    list_for_each_entry(struct vn_tls_ring, tls_ring, &tls->tls_rings,
310*61046927SAndroid Build Coastguard Worker                        tls_head) {
311*61046927SAndroid Build Coastguard Worker       mtx_lock(&tls_ring->mutex);
312*61046927SAndroid Build Coastguard Worker       if (tls_ring->instance == instance) {
313*61046927SAndroid Build Coastguard Worker          mtx_unlock(&tls_ring->mutex);
314*61046927SAndroid Build Coastguard Worker          assert(tls_ring->ring);
315*61046927SAndroid Build Coastguard Worker          return tls_ring->ring;
316*61046927SAndroid Build Coastguard Worker       }
317*61046927SAndroid Build Coastguard Worker       mtx_unlock(&tls_ring->mutex);
318*61046927SAndroid Build Coastguard Worker    }
319*61046927SAndroid Build Coastguard Worker 
320*61046927SAndroid Build Coastguard Worker    struct vn_tls_ring *tls_ring = calloc(1, sizeof(*tls_ring));
321*61046927SAndroid Build Coastguard Worker    if (!tls_ring)
322*61046927SAndroid Build Coastguard Worker       return NULL;
323*61046927SAndroid Build Coastguard Worker 
324*61046927SAndroid Build Coastguard Worker    /* keep the extra for potential roundtrip sync on tls ring */
325*61046927SAndroid Build Coastguard Worker    static const size_t extra_size = sizeof(uint32_t);
326*61046927SAndroid Build Coastguard Worker 
327*61046927SAndroid Build Coastguard Worker    /* only need a small ring for synchronous cmds on tls ring */
328*61046927SAndroid Build Coastguard Worker    static const size_t buf_size = 16 * 1024;
329*61046927SAndroid Build Coastguard Worker 
330*61046927SAndroid Build Coastguard Worker    /* single cmd can use the entire ring shmem on tls ring */
331*61046927SAndroid Build Coastguard Worker    static const uint8_t direct_order = 0;
332*61046927SAndroid Build Coastguard Worker 
333*61046927SAndroid Build Coastguard Worker    struct vn_ring_layout layout;
334*61046927SAndroid Build Coastguard Worker    vn_ring_get_layout(buf_size, extra_size, &layout);
335*61046927SAndroid Build Coastguard Worker 
336*61046927SAndroid Build Coastguard Worker    tls_ring->ring =
337*61046927SAndroid Build Coastguard Worker       vn_ring_create(instance, &layout, direct_order, true /* is_tls_ring */);
338*61046927SAndroid Build Coastguard Worker    if (!tls_ring->ring) {
339*61046927SAndroid Build Coastguard Worker       free(tls_ring);
340*61046927SAndroid Build Coastguard Worker       return NULL;
341*61046927SAndroid Build Coastguard Worker    }
342*61046927SAndroid Build Coastguard Worker 
343*61046927SAndroid Build Coastguard Worker    mtx_init(&tls_ring->mutex, mtx_plain);
344*61046927SAndroid Build Coastguard Worker    tls_ring->instance = instance;
345*61046927SAndroid Build Coastguard Worker    list_add(&tls_ring->tls_head, &tls->tls_rings);
346*61046927SAndroid Build Coastguard Worker    list_add(&tls_ring->vk_head, &instance->ring.tls_rings);
347*61046927SAndroid Build Coastguard Worker 
348*61046927SAndroid Build Coastguard Worker    return tls_ring->ring;
349*61046927SAndroid Build Coastguard Worker }
350*61046927SAndroid Build Coastguard Worker 
351*61046927SAndroid Build Coastguard Worker void
vn_tls_destroy_ring(struct vn_tls_ring * tls_ring)352*61046927SAndroid Build Coastguard Worker vn_tls_destroy_ring(struct vn_tls_ring *tls_ring)
353*61046927SAndroid Build Coastguard Worker {
354*61046927SAndroid Build Coastguard Worker    mtx_lock(&tls_ring->mutex);
355*61046927SAndroid Build Coastguard Worker    if (tls_ring->ring) {
356*61046927SAndroid Build Coastguard Worker       vn_ring_destroy(tls_ring->ring);
357*61046927SAndroid Build Coastguard Worker       tls_ring->ring = NULL;
358*61046927SAndroid Build Coastguard Worker       tls_ring->instance = NULL;
359*61046927SAndroid Build Coastguard Worker       mtx_unlock(&tls_ring->mutex);
360*61046927SAndroid Build Coastguard Worker    } else {
361*61046927SAndroid Build Coastguard Worker       mtx_unlock(&tls_ring->mutex);
362*61046927SAndroid Build Coastguard Worker       mtx_destroy(&tls_ring->mutex);
363*61046927SAndroid Build Coastguard Worker       free(tls_ring);
364*61046927SAndroid Build Coastguard Worker    }
365*61046927SAndroid Build Coastguard Worker }
366*61046927SAndroid Build Coastguard Worker 
367*61046927SAndroid Build Coastguard Worker static void
vn_tls_free(void * tls)368*61046927SAndroid Build Coastguard Worker vn_tls_free(void *tls)
369*61046927SAndroid Build Coastguard Worker {
370*61046927SAndroid Build Coastguard Worker    if (tls) {
371*61046927SAndroid Build Coastguard Worker       list_for_each_entry_safe(struct vn_tls_ring, tls_ring,
372*61046927SAndroid Build Coastguard Worker                                &((struct vn_tls *)tls)->tls_rings, tls_head)
373*61046927SAndroid Build Coastguard Worker          vn_tls_destroy_ring(tls_ring);
374*61046927SAndroid Build Coastguard Worker    }
375*61046927SAndroid Build Coastguard Worker    free(tls);
376*61046927SAndroid Build Coastguard Worker }
377*61046927SAndroid Build Coastguard Worker 
378*61046927SAndroid Build Coastguard Worker static tss_t vn_tls_key;
379*61046927SAndroid Build Coastguard Worker static bool vn_tls_key_valid;
380*61046927SAndroid Build Coastguard Worker 
381*61046927SAndroid Build Coastguard Worker static void
vn_tls_key_create_once(void)382*61046927SAndroid Build Coastguard Worker vn_tls_key_create_once(void)
383*61046927SAndroid Build Coastguard Worker {
384*61046927SAndroid Build Coastguard Worker    vn_tls_key_valid = tss_create(&vn_tls_key, vn_tls_free) == thrd_success;
385*61046927SAndroid Build Coastguard Worker    if (!vn_tls_key_valid && VN_DEBUG(INIT))
386*61046927SAndroid Build Coastguard Worker       vn_log(NULL, "WARNING: failed to create vn_tls_key");
387*61046927SAndroid Build Coastguard Worker }
388*61046927SAndroid Build Coastguard Worker 
389*61046927SAndroid Build Coastguard Worker struct vn_tls *
vn_tls_get(void)390*61046927SAndroid Build Coastguard Worker vn_tls_get(void)
391*61046927SAndroid Build Coastguard Worker {
392*61046927SAndroid Build Coastguard Worker    static once_flag once = ONCE_FLAG_INIT;
393*61046927SAndroid Build Coastguard Worker    call_once(&once, vn_tls_key_create_once);
394*61046927SAndroid Build Coastguard Worker    if (unlikely(!vn_tls_key_valid))
395*61046927SAndroid Build Coastguard Worker       return NULL;
396*61046927SAndroid Build Coastguard Worker 
397*61046927SAndroid Build Coastguard Worker    struct vn_tls *tls = tss_get(vn_tls_key);
398*61046927SAndroid Build Coastguard Worker    if (likely(tls))
399*61046927SAndroid Build Coastguard Worker       return tls;
400*61046927SAndroid Build Coastguard Worker 
401*61046927SAndroid Build Coastguard Worker    tls = calloc(1, sizeof(*tls));
402*61046927SAndroid Build Coastguard Worker    if (!tls)
403*61046927SAndroid Build Coastguard Worker       return NULL;
404*61046927SAndroid Build Coastguard Worker 
405*61046927SAndroid Build Coastguard Worker    /* initialize tls */
406*61046927SAndroid Build Coastguard Worker    tls->async_pipeline_create = false;
407*61046927SAndroid Build Coastguard Worker    list_inithead(&tls->tls_rings);
408*61046927SAndroid Build Coastguard Worker 
409*61046927SAndroid Build Coastguard Worker    if (tss_set(vn_tls_key, tls) != thrd_success) {
410*61046927SAndroid Build Coastguard Worker       free(tls);
411*61046927SAndroid Build Coastguard Worker       return NULL;
412*61046927SAndroid Build Coastguard Worker    }
413*61046927SAndroid Build Coastguard Worker 
414*61046927SAndroid Build Coastguard Worker    return tls;
415*61046927SAndroid Build Coastguard Worker }
416