17e102996Smaya/*
27e102996Smaya * Copyright (C) 2012-2018 Rob Clark <robclark@freedesktop.org>
37e102996Smaya *
47e102996Smaya * Permission is hereby granted, free of charge, to any person obtaining a
57e102996Smaya * copy of this software and associated documentation files (the "Software"),
67e102996Smaya * to deal in the Software without restriction, including without limitation
77e102996Smaya * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87e102996Smaya * and/or sell copies of the Software, and to permit persons to whom the
97e102996Smaya * Software is furnished to do so, subject to the following conditions:
107e102996Smaya *
117e102996Smaya * The above copyright notice and this permission notice (including the next
127e102996Smaya * paragraph) shall be included in all copies or substantial portions of the
137e102996Smaya * Software.
147e102996Smaya *
157e102996Smaya * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167e102996Smaya * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177e102996Smaya * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
187e102996Smaya * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
197e102996Smaya * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
207e102996Smaya * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
217e102996Smaya * SOFTWARE.
227e102996Smaya *
237e102996Smaya * Authors:
247e102996Smaya *    Rob Clark <robclark@freedesktop.org>
257e102996Smaya */
267e102996Smaya
277e102996Smaya#include "freedreno_drmif.h"
287e102996Smaya#include "freedreno_priv.h"
297e102996Smaya
307e102996Smaya/**
317e102996Smaya * priority of zero is highest priority, and higher numeric values are
327e102996Smaya * lower priorities
337e102996Smaya */
347e102996Smayastruct fd_pipe *
357e102996Smayafd_pipe_new2(struct fd_device *dev, enum fd_pipe_id id, uint32_t prio)
367e102996Smaya{
377ec681f3Smrg   struct fd_pipe *pipe;
387ec681f3Smrg   uint64_t val;
397e102996Smaya
407ec681f3Smrg   if (id > FD_PIPE_MAX) {
417ec681f3Smrg      ERROR_MSG("invalid pipe id: %d", id);
427ec681f3Smrg      return NULL;
437ec681f3Smrg   }
447e102996Smaya
457ec681f3Smrg   if ((prio != 1) && (fd_device_version(dev) < FD_VERSION_SUBMIT_QUEUES)) {
467ec681f3Smrg      ERROR_MSG("invalid priority!");
477ec681f3Smrg      return NULL;
487ec681f3Smrg   }
497e102996Smaya
507ec681f3Smrg   pipe = dev->funcs->pipe_new(dev, id, prio);
517ec681f3Smrg   if (!pipe) {
527ec681f3Smrg      ERROR_MSG("allocation failed");
537ec681f3Smrg      return NULL;
547ec681f3Smrg   }
557e102996Smaya
567ec681f3Smrg   pipe->dev = fd_device_ref(dev);
577ec681f3Smrg   pipe->id = id;
587ec681f3Smrg   p_atomic_set(&pipe->refcnt, 1);
597e102996Smaya
607ec681f3Smrg   fd_pipe_get_param(pipe, FD_GPU_ID, &val);
617ec681f3Smrg   pipe->dev_id.gpu_id = val;
627e102996Smaya
637ec681f3Smrg   fd_pipe_get_param(pipe, FD_CHIP_ID, &val);
647ec681f3Smrg   pipe->dev_id.chip_id = val;
657ec681f3Smrg
667ec681f3Smrg   pipe->control_mem = fd_bo_new(dev, sizeof(*pipe->control),
677ec681f3Smrg                                 FD_BO_CACHED_COHERENT,
687ec681f3Smrg                                 "pipe-control");
697ec681f3Smrg   pipe->control = fd_bo_map(pipe->control_mem);
707ec681f3Smrg
717ec681f3Smrg   /* We could be getting a bo from the bo-cache, make sure the fence value
727ec681f3Smrg    * is not garbage:
737ec681f3Smrg    */
747ec681f3Smrg   pipe->control->fence = 0;
757ec681f3Smrg
767ec681f3Smrg   /* We don't want the control_mem bo to hold a reference to the ourself,
777ec681f3Smrg    * so disable userspace fencing.  This also means that we won't be able
787ec681f3Smrg    * to determine if the buffer is idle which is needed by bo-cache.  But
797ec681f3Smrg    * pipe creation/destroy is not a high frequency event so just disable
807ec681f3Smrg    * the bo-cache as well:
817ec681f3Smrg    */
827ec681f3Smrg   pipe->control_mem->nosync = true;
837ec681f3Smrg   pipe->control_mem->bo_reuse = NO_CACHE;
847ec681f3Smrg
857ec681f3Smrg   return pipe;
867e102996Smaya}
877e102996Smaya
887e102996Smayastruct fd_pipe *
897e102996Smayafd_pipe_new(struct fd_device *dev, enum fd_pipe_id id)
907e102996Smaya{
917ec681f3Smrg   return fd_pipe_new2(dev, id, 1);
927e102996Smaya}
937e102996Smaya
947ec681f3Smrgstruct fd_pipe *
957ec681f3Smrgfd_pipe_ref(struct fd_pipe *pipe)
967e102996Smaya{
977ec681f3Smrg   simple_mtx_lock(&table_lock);
987ec681f3Smrg   fd_pipe_ref_locked(pipe);
997ec681f3Smrg   simple_mtx_unlock(&table_lock);
1007ec681f3Smrg   return pipe;
1017e102996Smaya}
1027e102996Smaya
1037ec681f3Smrgstruct fd_pipe *
1047ec681f3Smrgfd_pipe_ref_locked(struct fd_pipe *pipe)
1057e102996Smaya{
1067ec681f3Smrg   simple_mtx_assert_locked(&table_lock);
1077ec681f3Smrg   pipe->refcnt++;
1087ec681f3Smrg   return pipe;
1097e102996Smaya}
1107e102996Smaya
1117ec681f3Smrgvoid
1127ec681f3Smrgfd_pipe_del(struct fd_pipe *pipe)
1137e102996Smaya{
1147ec681f3Smrg   simple_mtx_lock(&table_lock);
1157ec681f3Smrg   fd_pipe_del_locked(pipe);
1167ec681f3Smrg   simple_mtx_unlock(&table_lock);
1177e102996Smaya}
1187e102996Smaya
1197ec681f3Smrgvoid
1207ec681f3Smrgfd_pipe_del_locked(struct fd_pipe *pipe)
1217e102996Smaya{
1227ec681f3Smrg   simple_mtx_assert_locked(&table_lock);
1237ec681f3Smrg   if (!p_atomic_dec_zero(&pipe->refcnt))
1247ec681f3Smrg      return;
1257ec681f3Smrg   fd_bo_del_locked(pipe->control_mem);
1267ec681f3Smrg   fd_device_del_locked(pipe->dev);
1277ec681f3Smrg   pipe->funcs->destroy(pipe);
1287ec681f3Smrg}
1297ec681f3Smrg
1307ec681f3Smrg/**
1317ec681f3Smrg * Discard any unflushed deferred submits.  This is called at context-
1327ec681f3Smrg * destroy to make sure we don't leak unflushed submits.
1337ec681f3Smrg */
1347ec681f3Smrgvoid
1357ec681f3Smrgfd_pipe_purge(struct fd_pipe *pipe)
1367ec681f3Smrg{
1377ec681f3Smrg   struct fd_device *dev = pipe->dev;
1387ec681f3Smrg   struct list_head deferred_submits;
1397ec681f3Smrg
1407ec681f3Smrg   list_inithead(&deferred_submits);
1417ec681f3Smrg
1427ec681f3Smrg   simple_mtx_lock(&dev->submit_lock);
1437ec681f3Smrg
1447ec681f3Smrg   foreach_submit_safe (deferred_submit, &dev->deferred_submits) {
1457ec681f3Smrg      if (deferred_submit->pipe != pipe)
1467ec681f3Smrg         continue;
1477ec681f3Smrg
1487ec681f3Smrg      list_del(&deferred_submit->node);
1497ec681f3Smrg      list_addtail(&deferred_submit->node, &deferred_submits);
1507ec681f3Smrg      dev->deferred_cmds -= fd_ringbuffer_cmd_count(deferred_submit->primary);
1517ec681f3Smrg   }
1527ec681f3Smrg
1537ec681f3Smrg   simple_mtx_unlock(&dev->submit_lock);
1547ec681f3Smrg
1557ec681f3Smrg   foreach_submit_safe (deferred_submit, &deferred_submits) {
1567ec681f3Smrg      list_del(&deferred_submit->node);
1577ec681f3Smrg      fd_submit_del(deferred_submit);
1587ec681f3Smrg   }
1597e102996Smaya}
1607e102996Smaya
1617ec681f3Smrgint
1627ec681f3Smrgfd_pipe_get_param(struct fd_pipe *pipe, enum fd_param_id param, uint64_t *value)
1637e102996Smaya{
1647ec681f3Smrg   return pipe->funcs->get_param(pipe, param, value);
1657ec681f3Smrg}
1667ec681f3Smrg
1677ec681f3Smrgconst struct fd_dev_id *
1687ec681f3Smrgfd_pipe_dev_id(struct fd_pipe *pipe)
1697ec681f3Smrg{
1707ec681f3Smrg   return &pipe->dev_id;
1717ec681f3Smrg}
1727ec681f3Smrg
1737ec681f3Smrgint
1747ec681f3Smrgfd_pipe_wait(struct fd_pipe *pipe, const struct fd_fence *fence)
1757ec681f3Smrg{
1767ec681f3Smrg   return fd_pipe_wait_timeout(pipe, fence, ~0);
1777ec681f3Smrg}
1787ec681f3Smrg
1797ec681f3Smrgint
1807ec681f3Smrgfd_pipe_wait_timeout(struct fd_pipe *pipe, const struct fd_fence *fence,
1817ec681f3Smrg                     uint64_t timeout)
1827ec681f3Smrg{
1837ec681f3Smrg   if (!fd_fence_after(fence->ufence, pipe->control->fence))
1847ec681f3Smrg      return 0;
1857ec681f3Smrg
1867ec681f3Smrg   fd_pipe_flush(pipe, fence->ufence);
1877ec681f3Smrg
1887ec681f3Smrg   return pipe->funcs->wait(pipe, fence, timeout);
1897ec681f3Smrg}
1907ec681f3Smrg
1917ec681f3Smrguint32_t
1927ec681f3Smrgfd_pipe_emit_fence(struct fd_pipe *pipe, struct fd_ringbuffer *ring)
1937ec681f3Smrg{
1947ec681f3Smrg   uint32_t fence = ++pipe->last_fence;
1957ec681f3Smrg
1967ec681f3Smrg   if (fd_dev_64b(&pipe->dev_id)) {
1977ec681f3Smrg      OUT_PKT7(ring, CP_EVENT_WRITE, 4);
1987ec681f3Smrg      OUT_RING(ring, CP_EVENT_WRITE_0_EVENT(CACHE_FLUSH_TS));
1997ec681f3Smrg      OUT_RELOC(ring, control_ptr(pipe, fence));   /* ADDR_LO/HI */
2007ec681f3Smrg      OUT_RING(ring, fence);
2017ec681f3Smrg   } else {
2027ec681f3Smrg      OUT_PKT3(ring, CP_EVENT_WRITE, 3);
2037ec681f3Smrg      OUT_RING(ring, CP_EVENT_WRITE_0_EVENT(CACHE_FLUSH_TS));
2047ec681f3Smrg      OUT_RELOC(ring, control_ptr(pipe, fence));   /* ADDR */
2057ec681f3Smrg      OUT_RING(ring, fence);
2067ec681f3Smrg   }
2077ec681f3Smrg
2087ec681f3Smrg   return fence;
2097e102996Smaya}
210