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 "freedreno_drmif.h"
28bf215546Sopenharmony_ci#include "freedreno_priv.h"
29bf215546Sopenharmony_ci
30bf215546Sopenharmony_ci/**
31bf215546Sopenharmony_ci * priority of zero is highest priority, and higher numeric values are
32bf215546Sopenharmony_ci * lower priorities
33bf215546Sopenharmony_ci */
34bf215546Sopenharmony_cistruct fd_pipe *
35bf215546Sopenharmony_cifd_pipe_new2(struct fd_device *dev, enum fd_pipe_id id, uint32_t prio)
36bf215546Sopenharmony_ci{
37bf215546Sopenharmony_ci   struct fd_pipe *pipe;
38bf215546Sopenharmony_ci   uint64_t val;
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ci   if (id > FD_PIPE_MAX) {
41bf215546Sopenharmony_ci      ERROR_MSG("invalid pipe id: %d", id);
42bf215546Sopenharmony_ci      return NULL;
43bf215546Sopenharmony_ci   }
44bf215546Sopenharmony_ci
45bf215546Sopenharmony_ci   if ((prio != 1) && (fd_device_version(dev) < FD_VERSION_SUBMIT_QUEUES)) {
46bf215546Sopenharmony_ci      ERROR_MSG("invalid priority!");
47bf215546Sopenharmony_ci      return NULL;
48bf215546Sopenharmony_ci   }
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_ci   pipe = dev->funcs->pipe_new(dev, id, prio);
51bf215546Sopenharmony_ci   if (!pipe) {
52bf215546Sopenharmony_ci      ERROR_MSG("allocation failed");
53bf215546Sopenharmony_ci      return NULL;
54bf215546Sopenharmony_ci   }
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_ci   pipe->dev = fd_device_ref(dev);
57bf215546Sopenharmony_ci   pipe->id = id;
58bf215546Sopenharmony_ci   p_atomic_set(&pipe->refcnt, 1);
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_ci   fd_pipe_get_param(pipe, FD_GPU_ID, &val);
61bf215546Sopenharmony_ci   pipe->dev_id.gpu_id = val;
62bf215546Sopenharmony_ci
63bf215546Sopenharmony_ci   fd_pipe_get_param(pipe, FD_CHIP_ID, &val);
64bf215546Sopenharmony_ci   pipe->dev_id.chip_id = val;
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_ci   pipe->control_mem = fd_bo_new(dev, sizeof(*pipe->control),
67bf215546Sopenharmony_ci                                 FD_BO_CACHED_COHERENT,
68bf215546Sopenharmony_ci                                 "pipe-control");
69bf215546Sopenharmony_ci   pipe->control = fd_bo_map(pipe->control_mem);
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_ci   /* We could be getting a bo from the bo-cache, make sure the fence value
72bf215546Sopenharmony_ci    * is not garbage:
73bf215546Sopenharmony_ci    */
74bf215546Sopenharmony_ci   pipe->control->fence = 0;
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci   /* We don't want the control_mem bo to hold a reference to the ourself,
77bf215546Sopenharmony_ci    * so disable userspace fencing.  This also means that we won't be able
78bf215546Sopenharmony_ci    * to determine if the buffer is idle which is needed by bo-cache.  But
79bf215546Sopenharmony_ci    * pipe creation/destroy is not a high frequency event so just disable
80bf215546Sopenharmony_ci    * the bo-cache as well:
81bf215546Sopenharmony_ci    */
82bf215546Sopenharmony_ci   pipe->control_mem->nosync = true;
83bf215546Sopenharmony_ci   pipe->control_mem->bo_reuse = NO_CACHE;
84bf215546Sopenharmony_ci
85bf215546Sopenharmony_ci   return pipe;
86bf215546Sopenharmony_ci}
87bf215546Sopenharmony_ci
88bf215546Sopenharmony_cistruct fd_pipe *
89bf215546Sopenharmony_cifd_pipe_new(struct fd_device *dev, enum fd_pipe_id id)
90bf215546Sopenharmony_ci{
91bf215546Sopenharmony_ci   return fd_pipe_new2(dev, id, 1);
92bf215546Sopenharmony_ci}
93bf215546Sopenharmony_ci
94bf215546Sopenharmony_cistruct fd_pipe *
95bf215546Sopenharmony_cifd_pipe_ref(struct fd_pipe *pipe)
96bf215546Sopenharmony_ci{
97bf215546Sopenharmony_ci   simple_mtx_lock(&table_lock);
98bf215546Sopenharmony_ci   fd_pipe_ref_locked(pipe);
99bf215546Sopenharmony_ci   simple_mtx_unlock(&table_lock);
100bf215546Sopenharmony_ci   return pipe;
101bf215546Sopenharmony_ci}
102bf215546Sopenharmony_ci
103bf215546Sopenharmony_cistruct fd_pipe *
104bf215546Sopenharmony_cifd_pipe_ref_locked(struct fd_pipe *pipe)
105bf215546Sopenharmony_ci{
106bf215546Sopenharmony_ci   simple_mtx_assert_locked(&table_lock);
107bf215546Sopenharmony_ci   pipe->refcnt++;
108bf215546Sopenharmony_ci   return pipe;
109bf215546Sopenharmony_ci}
110bf215546Sopenharmony_ci
111bf215546Sopenharmony_civoid
112bf215546Sopenharmony_cifd_pipe_del(struct fd_pipe *pipe)
113bf215546Sopenharmony_ci{
114bf215546Sopenharmony_ci   simple_mtx_lock(&table_lock);
115bf215546Sopenharmony_ci   fd_pipe_del_locked(pipe);
116bf215546Sopenharmony_ci   simple_mtx_unlock(&table_lock);
117bf215546Sopenharmony_ci}
118bf215546Sopenharmony_ci
119bf215546Sopenharmony_civoid
120bf215546Sopenharmony_cifd_pipe_del_locked(struct fd_pipe *pipe)
121bf215546Sopenharmony_ci{
122bf215546Sopenharmony_ci   simple_mtx_assert_locked(&table_lock);
123bf215546Sopenharmony_ci   if (!p_atomic_dec_zero(&pipe->refcnt))
124bf215546Sopenharmony_ci      return;
125bf215546Sopenharmony_ci   fd_bo_del_locked(pipe->control_mem);
126bf215546Sopenharmony_ci   fd_device_del_locked(pipe->dev);
127bf215546Sopenharmony_ci   pipe->funcs->destroy(pipe);
128bf215546Sopenharmony_ci}
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci/**
131bf215546Sopenharmony_ci * Discard any unflushed deferred submits.  This is called at context-
132bf215546Sopenharmony_ci * destroy to make sure we don't leak unflushed submits.
133bf215546Sopenharmony_ci */
134bf215546Sopenharmony_civoid
135bf215546Sopenharmony_cifd_pipe_purge(struct fd_pipe *pipe)
136bf215546Sopenharmony_ci{
137bf215546Sopenharmony_ci   struct fd_device *dev = pipe->dev;
138bf215546Sopenharmony_ci   struct list_head deferred_submits;
139bf215546Sopenharmony_ci
140bf215546Sopenharmony_ci   list_inithead(&deferred_submits);
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci   simple_mtx_lock(&dev->submit_lock);
143bf215546Sopenharmony_ci
144bf215546Sopenharmony_ci   foreach_submit_safe (deferred_submit, &dev->deferred_submits) {
145bf215546Sopenharmony_ci      if (deferred_submit->pipe != pipe)
146bf215546Sopenharmony_ci         continue;
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_ci      list_del(&deferred_submit->node);
149bf215546Sopenharmony_ci      list_addtail(&deferred_submit->node, &deferred_submits);
150bf215546Sopenharmony_ci      dev->deferred_cmds -= fd_ringbuffer_cmd_count(deferred_submit->primary);
151bf215546Sopenharmony_ci   }
152bf215546Sopenharmony_ci
153bf215546Sopenharmony_ci   simple_mtx_unlock(&dev->submit_lock);
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_ci   foreach_submit_safe (deferred_submit, &deferred_submits) {
156bf215546Sopenharmony_ci      list_del(&deferred_submit->node);
157bf215546Sopenharmony_ci      fd_submit_del(deferred_submit);
158bf215546Sopenharmony_ci   }
159bf215546Sopenharmony_ci}
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_ciint
162bf215546Sopenharmony_cifd_pipe_get_param(struct fd_pipe *pipe, enum fd_param_id param, uint64_t *value)
163bf215546Sopenharmony_ci{
164bf215546Sopenharmony_ci   return pipe->funcs->get_param(pipe, param, value);
165bf215546Sopenharmony_ci}
166bf215546Sopenharmony_ci
167bf215546Sopenharmony_ciint
168bf215546Sopenharmony_cifd_pipe_set_param(struct fd_pipe *pipe, enum fd_param_id param, uint64_t value)
169bf215546Sopenharmony_ci{
170bf215546Sopenharmony_ci   return pipe->funcs->set_param(pipe, param, value);
171bf215546Sopenharmony_ci}
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_ciconst struct fd_dev_id *
174bf215546Sopenharmony_cifd_pipe_dev_id(struct fd_pipe *pipe)
175bf215546Sopenharmony_ci{
176bf215546Sopenharmony_ci   return &pipe->dev_id;
177bf215546Sopenharmony_ci}
178bf215546Sopenharmony_ci
179bf215546Sopenharmony_ciint
180bf215546Sopenharmony_cifd_pipe_wait(struct fd_pipe *pipe, const struct fd_fence *fence)
181bf215546Sopenharmony_ci{
182bf215546Sopenharmony_ci   return fd_pipe_wait_timeout(pipe, fence, ~0);
183bf215546Sopenharmony_ci}
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_ciint
186bf215546Sopenharmony_cifd_pipe_wait_timeout(struct fd_pipe *pipe, const struct fd_fence *fence,
187bf215546Sopenharmony_ci                     uint64_t timeout)
188bf215546Sopenharmony_ci{
189bf215546Sopenharmony_ci   if (!fd_fence_after(fence->ufence, pipe->control->fence))
190bf215546Sopenharmony_ci      return 0;
191bf215546Sopenharmony_ci
192bf215546Sopenharmony_ci   fd_pipe_flush(pipe, fence->ufence);
193bf215546Sopenharmony_ci
194bf215546Sopenharmony_ci   return pipe->funcs->wait(pipe, fence, timeout);
195bf215546Sopenharmony_ci}
196bf215546Sopenharmony_ci
197bf215546Sopenharmony_ciuint32_t
198bf215546Sopenharmony_cifd_pipe_emit_fence(struct fd_pipe *pipe, struct fd_ringbuffer *ring)
199bf215546Sopenharmony_ci{
200bf215546Sopenharmony_ci   uint32_t fence = ++pipe->last_fence;
201bf215546Sopenharmony_ci
202bf215546Sopenharmony_ci   if (fd_dev_64b(&pipe->dev_id)) {
203bf215546Sopenharmony_ci      OUT_PKT7(ring, CP_EVENT_WRITE, 4);
204bf215546Sopenharmony_ci      OUT_RING(ring, CP_EVENT_WRITE_0_EVENT(CACHE_FLUSH_TS));
205bf215546Sopenharmony_ci      OUT_RELOC(ring, control_ptr(pipe, fence));   /* ADDR_LO/HI */
206bf215546Sopenharmony_ci      OUT_RING(ring, fence);
207bf215546Sopenharmony_ci   } else {
208bf215546Sopenharmony_ci      OUT_PKT3(ring, CP_EVENT_WRITE, 3);
209bf215546Sopenharmony_ci      OUT_RING(ring, CP_EVENT_WRITE_0_EVENT(CACHE_FLUSH_TS));
210bf215546Sopenharmony_ci      OUT_RELOC(ring, control_ptr(pipe, fence));   /* ADDR */
211bf215546Sopenharmony_ci      OUT_RING(ring, fence);
212bf215546Sopenharmony_ci   }
213bf215546Sopenharmony_ci
214bf215546Sopenharmony_ci   return fence;
215bf215546Sopenharmony_ci}
216