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