1 | /* |
2 | * Copyright 2012 Red Hat Inc. |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * copy of this software and associated documentation files (the "Software"), |
6 | * to deal in the Software without restriction, including without limitation |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
8 | * and/or sell copies of the Software, and to permit persons to whom the |
9 | * Software is furnished to do so, subject to the following conditions: |
10 | * |
11 | * The above copyright notice and this permission notice shall be included in |
12 | * all copies or substantial portions of the Software. |
13 | * |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
20 | * OTHER DEALINGS IN THE SOFTWARE. |
21 | * |
22 | * Authors: Ben Skeggs |
23 | */ |
24 | #include "nouveau_drv.h" |
25 | #include "nouveau_dma.h" |
26 | #include "nouveau_fence.h" |
27 | #include "nouveau_vmm.h" |
28 | |
29 | #include "nv50_display.h" |
30 | |
31 | #include <nvif/push206e.h> |
32 | |
33 | #include <nvhw/class/cl826f.h> |
34 | |
35 | static int |
36 | nv84_fence_emit32(struct nouveau_channel *chan, u64 virtual, u32 sequence) |
37 | { |
38 | struct nvif_push *push = chan->chan.push; |
39 | int ret = PUSH_WAIT(push, 8); |
40 | if (ret == 0) { |
41 | PUSH_MTHD(push, NV826F, SET_CONTEXT_DMA_SEMAPHORE, chan->vram.handle); |
42 | |
43 | PUSH_MTHD(push, NV826F, SEMAPHOREA, |
44 | NVVAL(NV826F, SEMAPHOREA, OFFSET_UPPER, upper_32_bits(virtual)), |
45 | |
46 | SEMAPHOREB, lower_32_bits(virtual), |
47 | SEMAPHOREC, sequence, |
48 | |
49 | SEMAPHORED, |
50 | NVDEF(NV826F, SEMAPHORED, OPERATION, RELEASE), |
51 | |
52 | NON_STALLED_INTERRUPT, 0); |
53 | PUSH_KICK(push); |
54 | } |
55 | return ret; |
56 | } |
57 | |
58 | static int |
59 | nv84_fence_sync32(struct nouveau_channel *chan, u64 virtual, u32 sequence) |
60 | { |
61 | struct nvif_push *push = chan->chan.push; |
62 | int ret = PUSH_WAIT(push, 7); |
63 | if (ret == 0) { |
64 | PUSH_MTHD(push, NV826F, SET_CONTEXT_DMA_SEMAPHORE, chan->vram.handle); |
65 | |
66 | PUSH_MTHD(push, NV826F, SEMAPHOREA, |
67 | NVVAL(NV826F, SEMAPHOREA, OFFSET_UPPER, upper_32_bits(virtual)), |
68 | |
69 | SEMAPHOREB, lower_32_bits(virtual), |
70 | SEMAPHOREC, sequence, |
71 | |
72 | SEMAPHORED, |
73 | NVDEF(NV826F, SEMAPHORED, OPERATION, ACQ_GEQ)); |
74 | PUSH_KICK(push); |
75 | } |
76 | return ret; |
77 | } |
78 | |
79 | static inline u32 |
80 | nv84_fence_chid(struct nouveau_channel *chan) |
81 | { |
82 | return chan->drm->runl[chan->runlist].chan_id_base + chan->chid; |
83 | } |
84 | |
85 | static int |
86 | nv84_fence_emit(struct nouveau_fence *fence) |
87 | { |
88 | struct nouveau_channel *chan = fence->channel; |
89 | struct nv84_fence_chan *fctx = chan->fence; |
90 | u64 addr = fctx->vma->addr + nv84_fence_chid(chan) * 16; |
91 | |
92 | return fctx->base.emit32(chan, addr, fence->base.seqno); |
93 | } |
94 | |
95 | static int |
96 | nv84_fence_sync(struct nouveau_fence *fence, |
97 | struct nouveau_channel *prev, struct nouveau_channel *chan) |
98 | { |
99 | struct nv84_fence_chan *fctx = chan->fence; |
100 | u64 addr = fctx->vma->addr + nv84_fence_chid(chan: prev) * 16; |
101 | |
102 | return fctx->base.sync32(chan, addr, fence->base.seqno); |
103 | } |
104 | |
105 | static u32 |
106 | nv84_fence_read(struct nouveau_channel *chan) |
107 | { |
108 | struct nv84_fence_priv *priv = chan->drm->fence; |
109 | return nouveau_bo_rd32(priv->bo, index: nv84_fence_chid(chan) * 16/4); |
110 | } |
111 | |
112 | static void |
113 | nv84_fence_context_del(struct nouveau_channel *chan) |
114 | { |
115 | struct nv84_fence_priv *priv = chan->drm->fence; |
116 | struct nv84_fence_chan *fctx = chan->fence; |
117 | |
118 | nouveau_bo_wr32(priv->bo, index: nv84_fence_chid(chan) * 16 / 4, val: fctx->base.sequence); |
119 | mutex_lock(&priv->mutex); |
120 | nouveau_vma_del(&fctx->vma); |
121 | mutex_unlock(lock: &priv->mutex); |
122 | nouveau_fence_context_del(&fctx->base); |
123 | chan->fence = NULL; |
124 | nouveau_fence_context_free(&fctx->base); |
125 | } |
126 | |
127 | int |
128 | nv84_fence_context_new(struct nouveau_channel *chan) |
129 | { |
130 | struct nv84_fence_priv *priv = chan->drm->fence; |
131 | struct nv84_fence_chan *fctx; |
132 | int ret; |
133 | |
134 | fctx = chan->fence = kzalloc(size: sizeof(*fctx), GFP_KERNEL); |
135 | if (!fctx) |
136 | return -ENOMEM; |
137 | |
138 | nouveau_fence_context_new(chan, &fctx->base); |
139 | fctx->base.emit = nv84_fence_emit; |
140 | fctx->base.sync = nv84_fence_sync; |
141 | fctx->base.read = nv84_fence_read; |
142 | fctx->base.emit32 = nv84_fence_emit32; |
143 | fctx->base.sync32 = nv84_fence_sync32; |
144 | fctx->base.sequence = nv84_fence_read(chan); |
145 | |
146 | mutex_lock(&priv->mutex); |
147 | ret = nouveau_vma_new(priv->bo, chan->vmm, &fctx->vma); |
148 | mutex_unlock(lock: &priv->mutex); |
149 | |
150 | if (ret) |
151 | nv84_fence_context_del(chan); |
152 | return ret; |
153 | } |
154 | |
155 | static bool |
156 | nv84_fence_suspend(struct nouveau_drm *drm) |
157 | { |
158 | struct nv84_fence_priv *priv = drm->fence; |
159 | int i; |
160 | |
161 | priv->suspend = vmalloc(array_size(sizeof(u32), drm->chan_total)); |
162 | if (priv->suspend) { |
163 | for (i = 0; i < drm->chan_total; i++) |
164 | priv->suspend[i] = nouveau_bo_rd32(priv->bo, index: i*4); |
165 | } |
166 | |
167 | return priv->suspend != NULL; |
168 | } |
169 | |
170 | static void |
171 | nv84_fence_resume(struct nouveau_drm *drm) |
172 | { |
173 | struct nv84_fence_priv *priv = drm->fence; |
174 | int i; |
175 | |
176 | if (priv->suspend) { |
177 | for (i = 0; i < drm->chan_total; i++) |
178 | nouveau_bo_wr32(priv->bo, index: i*4, val: priv->suspend[i]); |
179 | vfree(addr: priv->suspend); |
180 | priv->suspend = NULL; |
181 | } |
182 | } |
183 | |
184 | static void |
185 | nv84_fence_destroy(struct nouveau_drm *drm) |
186 | { |
187 | struct nv84_fence_priv *priv = drm->fence; |
188 | nouveau_bo_unmap(priv->bo); |
189 | if (priv->bo) |
190 | nouveau_bo_unpin(priv->bo); |
191 | nouveau_bo_ref(NULL, pnvbo: &priv->bo); |
192 | drm->fence = NULL; |
193 | kfree(objp: priv); |
194 | } |
195 | |
196 | int |
197 | nv84_fence_create(struct nouveau_drm *drm) |
198 | { |
199 | struct nv84_fence_priv *priv; |
200 | u32 domain; |
201 | int ret; |
202 | |
203 | priv = drm->fence = kzalloc(size: sizeof(*priv), GFP_KERNEL); |
204 | if (!priv) |
205 | return -ENOMEM; |
206 | |
207 | priv->base.dtor = nv84_fence_destroy; |
208 | priv->base.suspend = nv84_fence_suspend; |
209 | priv->base.resume = nv84_fence_resume; |
210 | priv->base.context_new = nv84_fence_context_new; |
211 | priv->base.context_del = nv84_fence_context_del; |
212 | |
213 | priv->base.uevent = true; |
214 | |
215 | mutex_init(&priv->mutex); |
216 | |
217 | /* Use VRAM if there is any ; otherwise fallback to system memory */ |
218 | domain = drm->client.device.info.ram_size != 0 ? |
219 | NOUVEAU_GEM_DOMAIN_VRAM : |
220 | /* |
221 | * fences created in sysmem must be non-cached or we |
222 | * will lose CPU/GPU coherency! |
223 | */ |
224 | NOUVEAU_GEM_DOMAIN_GART | NOUVEAU_GEM_DOMAIN_COHERENT; |
225 | ret = nouveau_bo_new(&drm->client, size: 16 * drm->chan_total, align: 0, |
226 | domain, tile_mode: 0, tile_flags: 0, NULL, NULL, &priv->bo); |
227 | if (ret == 0) { |
228 | ret = nouveau_bo_pin(priv->bo, flags: domain, contig: false); |
229 | if (ret == 0) { |
230 | ret = nouveau_bo_map(priv->bo); |
231 | if (ret) |
232 | nouveau_bo_unpin(priv->bo); |
233 | } |
234 | if (ret) |
235 | nouveau_bo_ref(NULL, pnvbo: &priv->bo); |
236 | } |
237 | |
238 | if (ret) |
239 | nv84_fence_destroy(drm); |
240 | return ret; |
241 | } |
242 | |