2 * Copyright 2007 Nouveau Project
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 #include "nouveau_drmif.h"
28 #include "nouveau_dma.h"
31 nouveau_pushbuf_init(struct nouveau_channel
*chan
)
33 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
38 /* Everything except first 4KiB of the push buffer is managed by us */
39 if (nouveau_resource_init(&nvchan
->pb_heap
,
40 nvchan
->drm
.cmdbuf_size
- 4096))
43 /* Shrink master ring to 4KiB */
44 assert(nvchan
->dma
.cur
<= (4096/4));
45 nvchan
->dma
.max
= (4096 / 4) - 2;
46 nvchan
->dma
.free
= nvchan
->dma
.max
- nvchan
->dma
.cur
;
51 /* This would be our TTM "superioctl" */
53 nouveau_pushbuf_flush(struct nouveau_channel
*chan
)
55 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
56 struct nouveau_pushbuf_priv
*nvpb
= nouveau_pushbuf(nvchan
->pb_tail
);
57 struct nouveau_pushbuf_bo
*pbbo
;
58 struct nouveau_fence
*fence
= NULL
;
65 if (nvpb
->base
.remaining
== nvpb
->res
->size
/ 4)
68 ret
= nouveau_fence_new(chan
, &fence
);
72 /* Validate buffers + apply relocations */
73 while ((pbbo
= ptr_to_pbbo(nvpb
->buffers
))) {
74 struct nouveau_pushbuf_reloc
*r
;
75 struct nouveau_bo
*bo
= &ptr_to_bo(pbbo
->handle
)->base
;
77 ret
= nouveau_bo_validate(chan
, bo
, fence
, pbbo
->flags
);
80 sync_hack
|= nouveau_bo(bo
)->sync_hack
;
81 nouveau_bo(bo
)->sync_hack
= 0;
83 while ((r
= ptr_to_pbrel(pbbo
->relocs
))) {
86 if (r
->flags
& NOUVEAU_BO_LOW
) {
87 push
= bo
->offset
+ r
->data
;
89 if (r
->flags
& NOUVEAU_BO_HIGH
) {
90 push
= (bo
->offset
+ r
->data
) >> 32;
95 if (r
->flags
& NOUVEAU_BO_OR
) {
96 if (bo
->flags
& NOUVEAU_BO_VRAM
)
103 pbbo
->relocs
= r
->next
;
107 nvpb
->buffers
= pbbo
->next
;
110 nvpb
->nr_buffers
= 0;
112 /* Emit JMP to indirect pushbuf */
113 if (nvchan
->dma
.free
< 1)
114 WAIT_RING_CH(chan
, 1);
115 nvchan
->dma
.free
-= 1;
116 #ifdef NOUVEAU_DMA_DEBUG
117 nvchan
->dma
.push_free
= 1;
119 OUT_RING_CH(chan
, 0x20000000 | (nvpb
->res
->start
+ 4096));
121 /* Add JMP back to master pushbuf from indirect pushbuf */
122 (*nvpb
->base
.cur
++) =
123 0x20000000 | ((nvchan
->dma
.cur
<< 2) + nvchan
->dma
.base
);
127 nouveau_fence_emit(nvpb
->fence
);
132 /* Allocate space for next push buffer */
134 nvpb
= calloc(1, sizeof(struct nouveau_pushbuf_priv
));
138 if (nouveau_resource_alloc(nvchan
->pb_heap
, 0x2000, NULL
, &nvpb
->res
)) {
139 struct nouveau_pushbuf_priv
*e
;
143 nouveau_fence_flush(chan
);
145 /* Free any push buffers that have already been executed */
146 e
= nouveau_pushbuf(nvchan
->pb_head
);
147 while (e
&& e
->fence
) {
148 if (!e
->fence
|| !nouveau_fence(e
->fence
)->signalled
)
150 nouveau_fence_del(&e
->fence
);
151 nouveau_resource_free(&e
->res
);
154 nvchan
->pb_head
= e
->next
;
155 if (nvchan
->pb_head
== NULL
)
156 nvchan
->pb_tail
= NULL
;
158 e
= nouveau_pushbuf(nvchan
->pb_head
);
161 /* We didn't free any buffers above. As a last resort, busy
162 * wait on the oldest buffer becoming available.
165 e
= nouveau_pushbuf(nvchan
->pb_head
);
166 nouveau_fence_wait(&e
->fence
);
167 nouveau_resource_free(&e
->res
);
169 nvchan
->pb_head
= e
->next
;
170 if (nvchan
->pb_head
== NULL
)
171 nvchan
->pb_tail
= NULL
;
175 if (nouveau_resource_alloc(nvchan
->pb_heap
, 0x2000, nvpb
,
180 nvpb
->base
.channel
= chan
;
181 nvpb
->base
.remaining
= nvpb
->res
->size
/ 4;
182 nvpb
->base
.cur
= &nvchan
->pushbuf
[(nvpb
->res
->start
+ 4096)/4];
184 if (nvchan
->pb_tail
) {
185 nouveau_pushbuf(nvchan
->pb_tail
)->next
= &nvpb
->base
;
187 nvchan
->pb_head
= &nvpb
->base
;
189 nvchan
->pb_tail
= &nvpb
->base
;
192 struct nouveau_fence
*f
= NULL
;
193 nouveau_fence_ref(nvpb
->fence
, &f
);
194 nouveau_fence_wait(&f
);
200 static struct nouveau_pushbuf_bo
*
201 nouveau_pushbuf_emit_buffer(struct nouveau_channel
*chan
, struct nouveau_bo
*bo
)
203 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
204 struct nouveau_pushbuf_priv
*nvpb
= nouveau_pushbuf(nvchan
->pb_tail
);
205 struct nouveau_pushbuf_bo
*pbbo
= ptr_to_pbbo(nvpb
->buffers
);
208 if (pbbo
->handle
== bo
->handle
)
210 pbbo
= ptr_to_pbbo(pbbo
->next
);
213 pbbo
= malloc(sizeof(struct nouveau_pushbuf_bo
));
214 pbbo
->next
= nvpb
->buffers
;
215 nvpb
->buffers
= pbbo_to_ptr(pbbo
);
218 pbbo
->handle
= bo_to_ptr(bo
);
219 pbbo
->flags
= NOUVEAU_BO_VRAM
| NOUVEAU_BO_GART
;
226 nouveau_pushbuf_emit_reloc(struct nouveau_channel
*chan
, void *ptr
,
227 struct nouveau_bo
*bo
, uint32_t data
, uint32_t flags
,
228 uint32_t vor
, uint32_t tor
)
230 struct nouveau_pushbuf_bo
*pbbo
;
231 struct nouveau_pushbuf_reloc
*r
;
236 pbbo
= nouveau_pushbuf_emit_buffer(chan
, bo
);
240 r
= malloc(sizeof(struct nouveau_pushbuf_reloc
));
241 r
->next
= pbbo
->relocs
;
242 pbbo
->relocs
= pbrel_to_ptr(r
);
245 pbbo
->flags
|= (flags
& NOUVEAU_BO_RDWR
);
246 pbbo
->flags
&= (flags
| NOUVEAU_BO_RDWR
);
248 r
->handle
= bo_to_ptr(r
);