1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright (C) 2012-2018 Rob Clark <robclark@freedesktop.org>
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21bf215546Sopenharmony_ci * SOFTWARE.
22bf215546Sopenharmony_ci *
23bf215546Sopenharmony_ci * Authors:
24bf215546Sopenharmony_ci *    Rob Clark <robclark@freedesktop.org>
25bf215546Sopenharmony_ci */
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci#include "os/os_mman.h"
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ci#include "freedreno_drmif.h"
30bf215546Sopenharmony_ci#include "freedreno_priv.h"
31bf215546Sopenharmony_ci
32bf215546Sopenharmony_cisimple_mtx_t table_lock = _SIMPLE_MTX_INITIALIZER_NP;
33bf215546Sopenharmony_civoid bo_del(struct fd_bo *bo);
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_ci/* set buffer name, and add to table, call w/ table_lock held: */
36bf215546Sopenharmony_cistatic void
37bf215546Sopenharmony_ciset_name(struct fd_bo *bo, uint32_t name)
38bf215546Sopenharmony_ci{
39bf215546Sopenharmony_ci   bo->name = name;
40bf215546Sopenharmony_ci   /* add ourself into the handle table: */
41bf215546Sopenharmony_ci   _mesa_hash_table_insert(bo->dev->name_table, &bo->name, bo);
42bf215546Sopenharmony_ci}
43bf215546Sopenharmony_ci
44bf215546Sopenharmony_ci/* lookup a buffer, call w/ table_lock held: */
45bf215546Sopenharmony_cistatic struct fd_bo *
46bf215546Sopenharmony_cilookup_bo(struct hash_table *tbl, uint32_t key)
47bf215546Sopenharmony_ci{
48bf215546Sopenharmony_ci   struct fd_bo *bo = NULL;
49bf215546Sopenharmony_ci   struct hash_entry *entry = _mesa_hash_table_search(tbl, &key);
50bf215546Sopenharmony_ci   if (entry) {
51bf215546Sopenharmony_ci      /* found, incr refcnt and return: */
52bf215546Sopenharmony_ci      bo = fd_bo_ref(entry->data);
53bf215546Sopenharmony_ci
54bf215546Sopenharmony_ci      /* don't break the bucket if this bo was found in one */
55bf215546Sopenharmony_ci      list_delinit(&bo->list);
56bf215546Sopenharmony_ci   }
57bf215546Sopenharmony_ci   return bo;
58bf215546Sopenharmony_ci}
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_civoid
61bf215546Sopenharmony_cifd_bo_init_common(struct fd_bo *bo, struct fd_device *dev)
62bf215546Sopenharmony_ci{
63bf215546Sopenharmony_ci   /* Backend should have initialized these: */
64bf215546Sopenharmony_ci   assert(bo->size);
65bf215546Sopenharmony_ci   assert(bo->handle);
66bf215546Sopenharmony_ci
67bf215546Sopenharmony_ci   bo->dev = dev;
68bf215546Sopenharmony_ci   bo->iova = bo->funcs->iova(bo);
69bf215546Sopenharmony_ci   bo->reloc_flags = FD_RELOC_FLAGS_INIT;
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_ci   p_atomic_set(&bo->refcnt, 1);
72bf215546Sopenharmony_ci   list_inithead(&bo->list);
73bf215546Sopenharmony_ci}
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_ci/* allocate a new buffer object, call w/ table_lock held */
76bf215546Sopenharmony_cistatic struct fd_bo *
77bf215546Sopenharmony_cibo_from_handle(struct fd_device *dev, uint32_t size, uint32_t handle)
78bf215546Sopenharmony_ci{
79bf215546Sopenharmony_ci   struct fd_bo *bo;
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_ci   simple_mtx_assert_locked(&table_lock);
82bf215546Sopenharmony_ci
83bf215546Sopenharmony_ci   bo = dev->funcs->bo_from_handle(dev, size, handle);
84bf215546Sopenharmony_ci   if (!bo) {
85bf215546Sopenharmony_ci      struct drm_gem_close req = {
86bf215546Sopenharmony_ci         .handle = handle,
87bf215546Sopenharmony_ci      };
88bf215546Sopenharmony_ci      drmIoctl(dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
89bf215546Sopenharmony_ci      return NULL;
90bf215546Sopenharmony_ci   }
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_ci   /* add ourself into the handle table: */
93bf215546Sopenharmony_ci   _mesa_hash_table_insert(dev->handle_table, &bo->handle, bo);
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_ci   return bo;
96bf215546Sopenharmony_ci}
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_cistatic struct fd_bo *
99bf215546Sopenharmony_cibo_new(struct fd_device *dev, uint32_t size, uint32_t flags,
100bf215546Sopenharmony_ci       struct fd_bo_cache *cache)
101bf215546Sopenharmony_ci{
102bf215546Sopenharmony_ci   struct fd_bo *bo = NULL;
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ci   /* demote cached-coherent to WC if not supported: */
105bf215546Sopenharmony_ci   if ((flags & FD_BO_CACHED_COHERENT) && !dev->has_cached_coherent)
106bf215546Sopenharmony_ci      flags &= ~FD_BO_CACHED_COHERENT;
107bf215546Sopenharmony_ci
108bf215546Sopenharmony_ci   bo = fd_bo_cache_alloc(cache, &size, flags);
109bf215546Sopenharmony_ci   if (bo)
110bf215546Sopenharmony_ci      return bo;
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_ci   bo = dev->funcs->bo_new(dev, size, flags);
113bf215546Sopenharmony_ci   if (!bo)
114bf215546Sopenharmony_ci      return NULL;
115bf215546Sopenharmony_ci
116bf215546Sopenharmony_ci   simple_mtx_lock(&table_lock);
117bf215546Sopenharmony_ci   /* add ourself into the handle table: */
118bf215546Sopenharmony_ci   _mesa_hash_table_insert(dev->handle_table, &bo->handle, bo);
119bf215546Sopenharmony_ci   simple_mtx_unlock(&table_lock);
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_ci   bo->alloc_flags = flags;
122bf215546Sopenharmony_ci   bo->max_fences = 1;
123bf215546Sopenharmony_ci   bo->fences = &bo->_inline_fence;
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci   VG_BO_ALLOC(bo);
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_ci   return bo;
128bf215546Sopenharmony_ci}
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_cistruct fd_bo *
131bf215546Sopenharmony_ci_fd_bo_new(struct fd_device *dev, uint32_t size, uint32_t flags)
132bf215546Sopenharmony_ci{
133bf215546Sopenharmony_ci   struct fd_bo *bo = bo_new(dev, size, flags, &dev->bo_cache);
134bf215546Sopenharmony_ci   if (bo)
135bf215546Sopenharmony_ci      bo->bo_reuse = BO_CACHE;
136bf215546Sopenharmony_ci   return bo;
137bf215546Sopenharmony_ci}
138bf215546Sopenharmony_ci
139bf215546Sopenharmony_civoid
140bf215546Sopenharmony_ci_fd_bo_set_name(struct fd_bo *bo, const char *fmt, va_list ap)
141bf215546Sopenharmony_ci{
142bf215546Sopenharmony_ci   bo->funcs->set_name(bo, fmt, ap);
143bf215546Sopenharmony_ci}
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_ci/* internal function to allocate bo's that use the ringbuffer cache
146bf215546Sopenharmony_ci * instead of the normal bo_cache.  The purpose is, because cmdstream
147bf215546Sopenharmony_ci * bo's get vmap'd on the kernel side, and that is expensive, we want
148bf215546Sopenharmony_ci * to re-use cmdstream bo's for cmdstream and not unrelated purposes.
149bf215546Sopenharmony_ci */
150bf215546Sopenharmony_cistruct fd_bo *
151bf215546Sopenharmony_cifd_bo_new_ring(struct fd_device *dev, uint32_t size)
152bf215546Sopenharmony_ci{
153bf215546Sopenharmony_ci   uint32_t flags = FD_BO_GPUREADONLY | FD_BO_CACHED_COHERENT;
154bf215546Sopenharmony_ci   struct fd_bo *bo = bo_new(dev, size, flags, &dev->ring_cache);
155bf215546Sopenharmony_ci   if (bo) {
156bf215546Sopenharmony_ci      bo->bo_reuse = RING_CACHE;
157bf215546Sopenharmony_ci      bo->reloc_flags |= FD_RELOC_DUMP;
158bf215546Sopenharmony_ci      fd_bo_set_name(bo, "cmdstream");
159bf215546Sopenharmony_ci   }
160bf215546Sopenharmony_ci   return bo;
161bf215546Sopenharmony_ci}
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_cistruct fd_bo *
164bf215546Sopenharmony_cifd_bo_from_handle(struct fd_device *dev, uint32_t handle, uint32_t size)
165bf215546Sopenharmony_ci{
166bf215546Sopenharmony_ci   struct fd_bo *bo = NULL;
167bf215546Sopenharmony_ci
168bf215546Sopenharmony_ci   simple_mtx_lock(&table_lock);
169bf215546Sopenharmony_ci
170bf215546Sopenharmony_ci   bo = lookup_bo(dev->handle_table, handle);
171bf215546Sopenharmony_ci   if (bo)
172bf215546Sopenharmony_ci      goto out_unlock;
173bf215546Sopenharmony_ci
174bf215546Sopenharmony_ci   bo = bo_from_handle(dev, size, handle);
175bf215546Sopenharmony_ci
176bf215546Sopenharmony_ci   VG_BO_ALLOC(bo);
177bf215546Sopenharmony_ci
178bf215546Sopenharmony_ciout_unlock:
179bf215546Sopenharmony_ci   simple_mtx_unlock(&table_lock);
180bf215546Sopenharmony_ci
181bf215546Sopenharmony_ci   return bo;
182bf215546Sopenharmony_ci}
183bf215546Sopenharmony_ci
184bf215546Sopenharmony_cistruct fd_bo *
185bf215546Sopenharmony_cifd_bo_from_dmabuf(struct fd_device *dev, int fd)
186bf215546Sopenharmony_ci{
187bf215546Sopenharmony_ci   int ret, size;
188bf215546Sopenharmony_ci   uint32_t handle;
189bf215546Sopenharmony_ci   struct fd_bo *bo;
190bf215546Sopenharmony_ci
191bf215546Sopenharmony_ci   simple_mtx_lock(&table_lock);
192bf215546Sopenharmony_ci   ret = drmPrimeFDToHandle(dev->fd, fd, &handle);
193bf215546Sopenharmony_ci   if (ret) {
194bf215546Sopenharmony_ci      simple_mtx_unlock(&table_lock);
195bf215546Sopenharmony_ci      return NULL;
196bf215546Sopenharmony_ci   }
197bf215546Sopenharmony_ci
198bf215546Sopenharmony_ci   bo = lookup_bo(dev->handle_table, handle);
199bf215546Sopenharmony_ci   if (bo)
200bf215546Sopenharmony_ci      goto out_unlock;
201bf215546Sopenharmony_ci
202bf215546Sopenharmony_ci   /* lseek() to get bo size */
203bf215546Sopenharmony_ci   size = lseek(fd, 0, SEEK_END);
204bf215546Sopenharmony_ci   lseek(fd, 0, SEEK_CUR);
205bf215546Sopenharmony_ci
206bf215546Sopenharmony_ci   bo = bo_from_handle(dev, size, handle);
207bf215546Sopenharmony_ci
208bf215546Sopenharmony_ci   VG_BO_ALLOC(bo);
209bf215546Sopenharmony_ci
210bf215546Sopenharmony_ciout_unlock:
211bf215546Sopenharmony_ci   simple_mtx_unlock(&table_lock);
212bf215546Sopenharmony_ci
213bf215546Sopenharmony_ci   return bo;
214bf215546Sopenharmony_ci}
215bf215546Sopenharmony_ci
216bf215546Sopenharmony_cistruct fd_bo *
217bf215546Sopenharmony_cifd_bo_from_name(struct fd_device *dev, uint32_t name)
218bf215546Sopenharmony_ci{
219bf215546Sopenharmony_ci   struct drm_gem_open req = {
220bf215546Sopenharmony_ci      .name = name,
221bf215546Sopenharmony_ci   };
222bf215546Sopenharmony_ci   struct fd_bo *bo;
223bf215546Sopenharmony_ci
224bf215546Sopenharmony_ci   simple_mtx_lock(&table_lock);
225bf215546Sopenharmony_ci
226bf215546Sopenharmony_ci   /* check name table first, to see if bo is already open: */
227bf215546Sopenharmony_ci   bo = lookup_bo(dev->name_table, name);
228bf215546Sopenharmony_ci   if (bo)
229bf215546Sopenharmony_ci      goto out_unlock;
230bf215546Sopenharmony_ci
231bf215546Sopenharmony_ci   if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) {
232bf215546Sopenharmony_ci      ERROR_MSG("gem-open failed: %s", strerror(errno));
233bf215546Sopenharmony_ci      goto out_unlock;
234bf215546Sopenharmony_ci   }
235bf215546Sopenharmony_ci
236bf215546Sopenharmony_ci   bo = lookup_bo(dev->handle_table, req.handle);
237bf215546Sopenharmony_ci   if (bo)
238bf215546Sopenharmony_ci      goto out_unlock;
239bf215546Sopenharmony_ci
240bf215546Sopenharmony_ci   bo = bo_from_handle(dev, req.size, req.handle);
241bf215546Sopenharmony_ci   if (bo) {
242bf215546Sopenharmony_ci      set_name(bo, name);
243bf215546Sopenharmony_ci      VG_BO_ALLOC(bo);
244bf215546Sopenharmony_ci   }
245bf215546Sopenharmony_ci
246bf215546Sopenharmony_ciout_unlock:
247bf215546Sopenharmony_ci   simple_mtx_unlock(&table_lock);
248bf215546Sopenharmony_ci
249bf215546Sopenharmony_ci   return bo;
250bf215546Sopenharmony_ci}
251bf215546Sopenharmony_ci
252bf215546Sopenharmony_civoid
253bf215546Sopenharmony_cifd_bo_mark_for_dump(struct fd_bo *bo)
254bf215546Sopenharmony_ci{
255bf215546Sopenharmony_ci   bo->reloc_flags |= FD_RELOC_DUMP;
256bf215546Sopenharmony_ci}
257bf215546Sopenharmony_ci
258bf215546Sopenharmony_ciuint64_t
259bf215546Sopenharmony_cifd_bo_get_iova(struct fd_bo *bo)
260bf215546Sopenharmony_ci{
261bf215546Sopenharmony_ci   /* ancient kernels did not support this */
262bf215546Sopenharmony_ci   assert(bo->iova != 0);
263bf215546Sopenharmony_ci   return bo->iova;
264bf215546Sopenharmony_ci}
265bf215546Sopenharmony_ci
266bf215546Sopenharmony_cistruct fd_bo *
267bf215546Sopenharmony_cifd_bo_ref(struct fd_bo *bo)
268bf215546Sopenharmony_ci{
269bf215546Sopenharmony_ci   p_atomic_inc(&bo->refcnt);
270bf215546Sopenharmony_ci   return bo;
271bf215546Sopenharmony_ci}
272bf215546Sopenharmony_ci
273bf215546Sopenharmony_cistatic void
274bf215546Sopenharmony_cibo_del_or_recycle(struct fd_bo *bo)
275bf215546Sopenharmony_ci{
276bf215546Sopenharmony_ci   struct fd_device *dev = bo->dev;
277bf215546Sopenharmony_ci
278bf215546Sopenharmony_ci   simple_mtx_assert_locked(&table_lock);
279bf215546Sopenharmony_ci
280bf215546Sopenharmony_ci   if ((bo->bo_reuse == BO_CACHE) &&
281bf215546Sopenharmony_ci       (fd_bo_cache_free(&dev->bo_cache, bo) == 0))
282bf215546Sopenharmony_ci      return;
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_ci   if ((bo->bo_reuse == RING_CACHE) &&
285bf215546Sopenharmony_ci       (fd_bo_cache_free(&dev->ring_cache, bo) == 0))
286bf215546Sopenharmony_ci      return;
287bf215546Sopenharmony_ci
288bf215546Sopenharmony_ci   bo_del(bo);
289bf215546Sopenharmony_ci}
290bf215546Sopenharmony_ci
291bf215546Sopenharmony_civoid
292bf215546Sopenharmony_cifd_bo_del_locked(struct fd_bo *bo)
293bf215546Sopenharmony_ci{
294bf215546Sopenharmony_ci   simple_mtx_assert_locked(&table_lock);
295bf215546Sopenharmony_ci
296bf215546Sopenharmony_ci   if (!p_atomic_dec_zero(&bo->refcnt))
297bf215546Sopenharmony_ci      return;
298bf215546Sopenharmony_ci
299bf215546Sopenharmony_ci   bo_del_or_recycle(bo);
300bf215546Sopenharmony_ci}
301bf215546Sopenharmony_ci
302bf215546Sopenharmony_civoid
303bf215546Sopenharmony_cifd_bo_del(struct fd_bo *bo)
304bf215546Sopenharmony_ci{
305bf215546Sopenharmony_ci   if (!p_atomic_dec_zero(&bo->refcnt))
306bf215546Sopenharmony_ci      return;
307bf215546Sopenharmony_ci
308bf215546Sopenharmony_ci   simple_mtx_lock(&table_lock);
309bf215546Sopenharmony_ci   bo_del_or_recycle(bo);
310bf215546Sopenharmony_ci   simple_mtx_unlock(&table_lock);
311bf215546Sopenharmony_ci}
312bf215546Sopenharmony_ci
313bf215546Sopenharmony_ci/**
314bf215546Sopenharmony_ci * Cleanup fences, dropping pipe references.  If 'expired' is true, only
315bf215546Sopenharmony_ci * cleanup expired fences.
316bf215546Sopenharmony_ci *
317bf215546Sopenharmony_ci * Normally we expect at most a single fence, the exception being bo's
318bf215546Sopenharmony_ci * shared between contexts
319bf215546Sopenharmony_ci */
320bf215546Sopenharmony_cistatic void
321bf215546Sopenharmony_cicleanup_fences(struct fd_bo *bo, bool expired)
322bf215546Sopenharmony_ci{
323bf215546Sopenharmony_ci   simple_mtx_assert_locked(&table_lock);
324bf215546Sopenharmony_ci
325bf215546Sopenharmony_ci   for (int i = 0; i < bo->nr_fences; i++) {
326bf215546Sopenharmony_ci      struct fd_bo_fence *f = &bo->fences[i];
327bf215546Sopenharmony_ci
328bf215546Sopenharmony_ci      if (expired && fd_fence_before(f->pipe->control->fence, f->fence))
329bf215546Sopenharmony_ci         continue;
330bf215546Sopenharmony_ci
331bf215546Sopenharmony_ci      struct fd_pipe *pipe = f->pipe;
332bf215546Sopenharmony_ci
333bf215546Sopenharmony_ci      bo->nr_fences--;
334bf215546Sopenharmony_ci
335bf215546Sopenharmony_ci      if (bo->nr_fences > 0) {
336bf215546Sopenharmony_ci         /* Shuffle up the last entry to replace the current slot: */
337bf215546Sopenharmony_ci         bo->fences[i] = bo->fences[bo->nr_fences];
338bf215546Sopenharmony_ci         i--;
339bf215546Sopenharmony_ci      }
340bf215546Sopenharmony_ci
341bf215546Sopenharmony_ci      fd_pipe_del_locked(pipe);
342bf215546Sopenharmony_ci   }
343bf215546Sopenharmony_ci}
344bf215546Sopenharmony_ci
345bf215546Sopenharmony_ci/* Called under table_lock */
346bf215546Sopenharmony_civoid
347bf215546Sopenharmony_cibo_del(struct fd_bo *bo)
348bf215546Sopenharmony_ci{
349bf215546Sopenharmony_ci   struct fd_device *dev = bo->dev;
350bf215546Sopenharmony_ci   uint32_t handle = bo->handle;
351bf215546Sopenharmony_ci
352bf215546Sopenharmony_ci   VG_BO_FREE(bo);
353bf215546Sopenharmony_ci
354bf215546Sopenharmony_ci   simple_mtx_assert_locked(&table_lock);
355bf215546Sopenharmony_ci
356bf215546Sopenharmony_ci   cleanup_fences(bo, false);
357bf215546Sopenharmony_ci   if (bo->fences != &bo->_inline_fence)
358bf215546Sopenharmony_ci      free(bo->fences);
359bf215546Sopenharmony_ci
360bf215546Sopenharmony_ci   if (bo->map)
361bf215546Sopenharmony_ci      os_munmap(bo->map, bo->size);
362bf215546Sopenharmony_ci
363bf215546Sopenharmony_ci   if (handle) {
364bf215546Sopenharmony_ci      _mesa_hash_table_remove_key(dev->handle_table, &handle);
365bf215546Sopenharmony_ci      if (bo->name)
366bf215546Sopenharmony_ci         _mesa_hash_table_remove_key(dev->name_table, &bo->name);
367bf215546Sopenharmony_ci   }
368bf215546Sopenharmony_ci
369bf215546Sopenharmony_ci   bo->funcs->destroy(bo);
370bf215546Sopenharmony_ci
371bf215546Sopenharmony_ci   if (handle) {
372bf215546Sopenharmony_ci      struct drm_gem_close req = {
373bf215546Sopenharmony_ci         .handle = handle,
374bf215546Sopenharmony_ci      };
375bf215546Sopenharmony_ci      drmIoctl(dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
376bf215546Sopenharmony_ci   }
377bf215546Sopenharmony_ci}
378bf215546Sopenharmony_ci
379bf215546Sopenharmony_cistatic void
380bf215546Sopenharmony_cibo_flush(struct fd_bo *bo)
381bf215546Sopenharmony_ci{
382bf215546Sopenharmony_ci   for (int i = 0; i < bo->nr_fences; i++) {
383bf215546Sopenharmony_ci      struct fd_bo_fence *f = &bo->fences[i];
384bf215546Sopenharmony_ci      fd_pipe_flush(f->pipe, f->fence);
385bf215546Sopenharmony_ci   }
386bf215546Sopenharmony_ci}
387bf215546Sopenharmony_ci
388bf215546Sopenharmony_ciint
389bf215546Sopenharmony_cifd_bo_get_name(struct fd_bo *bo, uint32_t *name)
390bf215546Sopenharmony_ci{
391bf215546Sopenharmony_ci   if (!bo->name) {
392bf215546Sopenharmony_ci      struct drm_gem_flink req = {
393bf215546Sopenharmony_ci         .handle = bo->handle,
394bf215546Sopenharmony_ci      };
395bf215546Sopenharmony_ci      int ret;
396bf215546Sopenharmony_ci
397bf215546Sopenharmony_ci      ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req);
398bf215546Sopenharmony_ci      if (ret) {
399bf215546Sopenharmony_ci         return ret;
400bf215546Sopenharmony_ci      }
401bf215546Sopenharmony_ci
402bf215546Sopenharmony_ci      simple_mtx_lock(&table_lock);
403bf215546Sopenharmony_ci      set_name(bo, req.name);
404bf215546Sopenharmony_ci      simple_mtx_unlock(&table_lock);
405bf215546Sopenharmony_ci      bo->bo_reuse = NO_CACHE;
406bf215546Sopenharmony_ci      bo->shared = true;
407bf215546Sopenharmony_ci      bo_flush(bo);
408bf215546Sopenharmony_ci   }
409bf215546Sopenharmony_ci
410bf215546Sopenharmony_ci   *name = bo->name;
411bf215546Sopenharmony_ci
412bf215546Sopenharmony_ci   return 0;
413bf215546Sopenharmony_ci}
414bf215546Sopenharmony_ci
415bf215546Sopenharmony_ciuint32_t
416bf215546Sopenharmony_cifd_bo_handle(struct fd_bo *bo)
417bf215546Sopenharmony_ci{
418bf215546Sopenharmony_ci   bo->bo_reuse = NO_CACHE;
419bf215546Sopenharmony_ci   bo->shared = true;
420bf215546Sopenharmony_ci   bo_flush(bo);
421bf215546Sopenharmony_ci   return bo->handle;
422bf215546Sopenharmony_ci}
423bf215546Sopenharmony_ci
424bf215546Sopenharmony_ciint
425bf215546Sopenharmony_cifd_bo_dmabuf(struct fd_bo *bo)
426bf215546Sopenharmony_ci{
427bf215546Sopenharmony_ci   int ret, prime_fd;
428bf215546Sopenharmony_ci
429bf215546Sopenharmony_ci   ret = drmPrimeHandleToFD(bo->dev->fd, bo->handle, DRM_CLOEXEC | DRM_RDWR,
430bf215546Sopenharmony_ci                            &prime_fd);
431bf215546Sopenharmony_ci   if (ret) {
432bf215546Sopenharmony_ci      ERROR_MSG("failed to get dmabuf fd: %d", ret);
433bf215546Sopenharmony_ci      return ret;
434bf215546Sopenharmony_ci   }
435bf215546Sopenharmony_ci
436bf215546Sopenharmony_ci   bo->bo_reuse = NO_CACHE;
437bf215546Sopenharmony_ci   bo->shared = true;
438bf215546Sopenharmony_ci   bo_flush(bo);
439bf215546Sopenharmony_ci
440bf215546Sopenharmony_ci   return prime_fd;
441bf215546Sopenharmony_ci}
442bf215546Sopenharmony_ci
443bf215546Sopenharmony_ciuint32_t
444bf215546Sopenharmony_cifd_bo_size(struct fd_bo *bo)
445bf215546Sopenharmony_ci{
446bf215546Sopenharmony_ci   return bo->size;
447bf215546Sopenharmony_ci}
448bf215546Sopenharmony_ci
449bf215546Sopenharmony_cibool
450bf215546Sopenharmony_cifd_bo_is_cached(struct fd_bo *bo)
451bf215546Sopenharmony_ci{
452bf215546Sopenharmony_ci   return !!(bo->alloc_flags & FD_BO_CACHED_COHERENT);
453bf215546Sopenharmony_ci}
454bf215546Sopenharmony_ci
455bf215546Sopenharmony_cistatic void *
456bf215546Sopenharmony_cibo_map(struct fd_bo *bo)
457bf215546Sopenharmony_ci{
458bf215546Sopenharmony_ci   if (!bo->map) {
459bf215546Sopenharmony_ci      uint64_t offset;
460bf215546Sopenharmony_ci      int ret;
461bf215546Sopenharmony_ci
462bf215546Sopenharmony_ci      ret = bo->funcs->offset(bo, &offset);
463bf215546Sopenharmony_ci      if (ret) {
464bf215546Sopenharmony_ci         return NULL;
465bf215546Sopenharmony_ci      }
466bf215546Sopenharmony_ci
467bf215546Sopenharmony_ci      bo->map = os_mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
468bf215546Sopenharmony_ci                        bo->dev->fd, offset);
469bf215546Sopenharmony_ci      if (bo->map == MAP_FAILED) {
470bf215546Sopenharmony_ci         ERROR_MSG("mmap failed: %s", strerror(errno));
471bf215546Sopenharmony_ci         bo->map = NULL;
472bf215546Sopenharmony_ci      }
473bf215546Sopenharmony_ci   }
474bf215546Sopenharmony_ci   return bo->map;
475bf215546Sopenharmony_ci}
476bf215546Sopenharmony_ci
477bf215546Sopenharmony_civoid *
478bf215546Sopenharmony_cifd_bo_map(struct fd_bo *bo)
479bf215546Sopenharmony_ci{
480bf215546Sopenharmony_ci   /* don't allow mmap'ing something allocated with FD_BO_NOMAP
481bf215546Sopenharmony_ci    * for sanity
482bf215546Sopenharmony_ci    */
483bf215546Sopenharmony_ci   if (bo->alloc_flags & FD_BO_NOMAP)
484bf215546Sopenharmony_ci      return NULL;
485bf215546Sopenharmony_ci
486bf215546Sopenharmony_ci   return bo_map(bo);
487bf215546Sopenharmony_ci}
488bf215546Sopenharmony_ci
489bf215546Sopenharmony_civoid
490bf215546Sopenharmony_cifd_bo_upload(struct fd_bo *bo, void *src, unsigned len)
491bf215546Sopenharmony_ci{
492bf215546Sopenharmony_ci   if (bo->funcs->upload) {
493bf215546Sopenharmony_ci      bo->funcs->upload(bo, src, len);
494bf215546Sopenharmony_ci      return;
495bf215546Sopenharmony_ci   }
496bf215546Sopenharmony_ci
497bf215546Sopenharmony_ci   memcpy(bo_map(bo), src, len);
498bf215546Sopenharmony_ci}
499bf215546Sopenharmony_ci
500bf215546Sopenharmony_ci/* a bit odd to take the pipe as an arg, but it's a, umm, quirk of kgsl.. */
501bf215546Sopenharmony_ciint
502bf215546Sopenharmony_cifd_bo_cpu_prep(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op)
503bf215546Sopenharmony_ci{
504bf215546Sopenharmony_ci   simple_mtx_lock(&table_lock);
505bf215546Sopenharmony_ci   enum fd_bo_state state = fd_bo_state(bo);
506bf215546Sopenharmony_ci   simple_mtx_unlock(&table_lock);
507bf215546Sopenharmony_ci
508bf215546Sopenharmony_ci   if (state == FD_BO_STATE_IDLE)
509bf215546Sopenharmony_ci      return 0;
510bf215546Sopenharmony_ci
511bf215546Sopenharmony_ci   if (op & (FD_BO_PREP_NOSYNC | FD_BO_PREP_FLUSH)) {
512bf215546Sopenharmony_ci      if (op & FD_BO_PREP_FLUSH)
513bf215546Sopenharmony_ci         bo_flush(bo);
514bf215546Sopenharmony_ci
515bf215546Sopenharmony_ci      /* If we have *only* been asked to flush, then we aren't really
516bf215546Sopenharmony_ci       * interested about whether shared buffers are busy, so avoid
517bf215546Sopenharmony_ci       * the kernel ioctl.
518bf215546Sopenharmony_ci       */
519bf215546Sopenharmony_ci      if ((state == FD_BO_STATE_BUSY) ||
520bf215546Sopenharmony_ci          (op == FD_BO_PREP_FLUSH))
521bf215546Sopenharmony_ci         return -EBUSY;
522bf215546Sopenharmony_ci   }
523bf215546Sopenharmony_ci
524bf215546Sopenharmony_ci   /* In case the bo is referenced by a deferred submit, flush up to the
525bf215546Sopenharmony_ci    * required fence now:
526bf215546Sopenharmony_ci    */
527bf215546Sopenharmony_ci   bo_flush(bo);
528bf215546Sopenharmony_ci
529bf215546Sopenharmony_ci   /* FD_BO_PREP_FLUSH is purely a frontend flag, and is not seen/handled
530bf215546Sopenharmony_ci    * by backend or kernel:
531bf215546Sopenharmony_ci    */
532bf215546Sopenharmony_ci   return bo->funcs->cpu_prep(bo, pipe, op & ~FD_BO_PREP_FLUSH);
533bf215546Sopenharmony_ci}
534bf215546Sopenharmony_ci
535bf215546Sopenharmony_civoid
536bf215546Sopenharmony_cifd_bo_cpu_fini(struct fd_bo *bo)
537bf215546Sopenharmony_ci{
538bf215546Sopenharmony_ci// TODO until we have cached buffers, the kernel side ioctl does nothing,
539bf215546Sopenharmony_ci//      so just skip it.  When we have cached buffers, we can make the
540bf215546Sopenharmony_ci//      ioctl conditional
541bf215546Sopenharmony_ci//   bo->funcs->cpu_fini(bo);
542bf215546Sopenharmony_ci}
543bf215546Sopenharmony_ci
544bf215546Sopenharmony_civoid
545bf215546Sopenharmony_cifd_bo_add_fence(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t fence)
546bf215546Sopenharmony_ci{
547bf215546Sopenharmony_ci   simple_mtx_assert_locked(&table_lock);
548bf215546Sopenharmony_ci
549bf215546Sopenharmony_ci   if (bo->nosync)
550bf215546Sopenharmony_ci      return;
551bf215546Sopenharmony_ci
552bf215546Sopenharmony_ci   /* The common case is bo re-used on the same pipe it had previously
553bf215546Sopenharmony_ci    * been used on:
554bf215546Sopenharmony_ci    */
555bf215546Sopenharmony_ci   for (int i = 0; i < bo->nr_fences; i++) {
556bf215546Sopenharmony_ci      struct fd_bo_fence *f = &bo->fences[i];
557bf215546Sopenharmony_ci      if (f->pipe == pipe) {
558bf215546Sopenharmony_ci         assert(fd_fence_before(f->fence, fence));
559bf215546Sopenharmony_ci         f->fence = fence;
560bf215546Sopenharmony_ci         return;
561bf215546Sopenharmony_ci      }
562bf215546Sopenharmony_ci   }
563bf215546Sopenharmony_ci
564bf215546Sopenharmony_ci   cleanup_fences(bo, true);
565bf215546Sopenharmony_ci
566bf215546Sopenharmony_ci   /* The first time we grow past a single fence, we need some special
567bf215546Sopenharmony_ci    * handling, as we've been using the embedded _inline_fence to avoid
568bf215546Sopenharmony_ci    * a separate allocation:
569bf215546Sopenharmony_ci    */
570bf215546Sopenharmony_ci   if (unlikely((bo->nr_fences == 1) &&
571bf215546Sopenharmony_ci                (bo->fences == &bo->_inline_fence))) {
572bf215546Sopenharmony_ci      bo->nr_fences = bo->max_fences = 0;
573bf215546Sopenharmony_ci      bo->fences = NULL;
574bf215546Sopenharmony_ci      APPEND(bo, fences, bo->_inline_fence);
575bf215546Sopenharmony_ci   }
576bf215546Sopenharmony_ci
577bf215546Sopenharmony_ci   APPEND(bo, fences, (struct fd_bo_fence){
578bf215546Sopenharmony_ci      .pipe = fd_pipe_ref_locked(pipe),
579bf215546Sopenharmony_ci      .fence = fence,
580bf215546Sopenharmony_ci   });
581bf215546Sopenharmony_ci}
582bf215546Sopenharmony_ci
583bf215546Sopenharmony_cienum fd_bo_state
584bf215546Sopenharmony_cifd_bo_state(struct fd_bo *bo)
585bf215546Sopenharmony_ci{
586bf215546Sopenharmony_ci   simple_mtx_assert_locked(&table_lock);
587bf215546Sopenharmony_ci
588bf215546Sopenharmony_ci   cleanup_fences(bo, true);
589bf215546Sopenharmony_ci
590bf215546Sopenharmony_ci   if (bo->shared || bo->nosync)
591bf215546Sopenharmony_ci      return FD_BO_STATE_UNKNOWN;
592bf215546Sopenharmony_ci
593bf215546Sopenharmony_ci   if (!bo->nr_fences)
594bf215546Sopenharmony_ci      return FD_BO_STATE_IDLE;
595bf215546Sopenharmony_ci
596bf215546Sopenharmony_ci   return FD_BO_STATE_BUSY;
597bf215546Sopenharmony_ci}
598bf215546Sopenharmony_ci
599