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
, 4096,
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
;
52 nouveau_pushbuf_fence_signalled(void *priv
)
54 struct nouveau_pushbuf_priv
*nvpb
= nouveau_pushbuf(priv
);
56 nouveau_fence_del(&nvpb
->fence
);
57 nouveau_resource_free(&nvpb
->res
);
61 /* This would be our TTM "superioctl" */
63 nouveau_pushbuf_flush(struct nouveau_channel
*chan
)
65 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
66 struct nouveau_pushbuf_priv
*nvpb
= nouveau_pushbuf(nvchan
->pb_tail
);
67 struct nouveau_pushbuf_bo
*pbbo
;
68 struct nouveau_fence
*fence
= NULL
;
75 if (nvpb
->base
.remaining
== nvpb
->res
->size
/ 4)
77 nvchan
->pb_tail
= NULL
;
79 ret
= nouveau_fence_new(chan
, &fence
);
83 /* Validate buffers + apply relocations */
84 while ((pbbo
= ptr_to_pbbo(nvpb
->buffers
))) {
85 struct nouveau_pushbuf_reloc
*r
;
86 struct nouveau_bo
*bo
= &ptr_to_bo(pbbo
->handle
)->base
;
88 ret
= nouveau_bo_validate(chan
, bo
, fence
, pbbo
->flags
);
91 sync_hack
|= nouveau_bo(bo
)->sync_hack
;
92 nouveau_bo(bo
)->sync_hack
= 0;
94 while ((r
= ptr_to_pbrel(pbbo
->relocs
))) {
97 if (r
->flags
& NOUVEAU_BO_LOW
) {
98 push
= bo
->offset
+ r
->data
;
100 if (r
->flags
& NOUVEAU_BO_HIGH
) {
101 push
= (bo
->offset
+ r
->data
) >> 32;
106 if (r
->flags
& NOUVEAU_BO_OR
) {
107 if (bo
->flags
& NOUVEAU_BO_VRAM
)
114 pbbo
->relocs
= r
->next
;
118 nvpb
->buffers
= pbbo
->next
;
121 nvpb
->nr_buffers
= 0;
123 /* Emit JMP to indirect pushbuf */
124 if (nvchan
->dma
.free
< 1)
125 WAIT_RING_CH(chan
, 1);
126 nvchan
->dma
.free
-= 1;
127 #ifdef NOUVEAU_DMA_DEBUG
128 nvchan
->dma
.push_free
= 1;
130 OUT_RING_CH(chan
, 0x20000000 | nvpb
->res
->start
);
132 /* Add JMP back to master pushbuf from indirect pushbuf */
133 (*nvpb
->base
.cur
++) =
134 0x20000000 | ((nvchan
->dma
.cur
<< 2) + nvchan
->dma
.base
);
138 nouveau_fence_signal_cb(nvpb
->fence
, nouveau_pushbuf_fence_signalled
,
140 nouveau_fence_emit(nvpb
->fence
);
146 struct nouveau_fence
*f
= NULL
;
147 nouveau_fence_ref(nvpb
->fence
, &f
);
148 nouveau_fence_wait(&f
);
151 /* Allocate space for next push buffer */
153 nvpb
= calloc(1, sizeof(struct nouveau_pushbuf_priv
));
157 while (nouveau_resource_alloc(nvchan
->pb_heap
, 0x2000, NULL
,
159 nouveau_fence_flush(chan
);
162 nvpb
->base
.channel
= chan
;
163 nvpb
->base
.remaining
= nvpb
->res
->size
/ 4;
164 nvpb
->base
.cur
= &nvchan
->pushbuf
[nvpb
->res
->start
/4];
165 nvchan
->pb_tail
= &nvpb
->base
;
170 static struct nouveau_pushbuf_bo
*
171 nouveau_pushbuf_emit_buffer(struct nouveau_channel
*chan
, struct nouveau_bo
*bo
)
173 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
174 struct nouveau_pushbuf_priv
*nvpb
= nouveau_pushbuf(nvchan
->pb_tail
);
175 struct nouveau_pushbuf_bo
*pbbo
= ptr_to_pbbo(nvpb
->buffers
);
178 if (pbbo
->handle
== bo
->handle
)
180 pbbo
= ptr_to_pbbo(pbbo
->next
);
183 pbbo
= malloc(sizeof(struct nouveau_pushbuf_bo
));
184 pbbo
->next
= nvpb
->buffers
;
185 nvpb
->buffers
= pbbo_to_ptr(pbbo
);
188 pbbo
->handle
= bo_to_ptr(bo
);
189 pbbo
->flags
= NOUVEAU_BO_VRAM
| NOUVEAU_BO_GART
;
196 nouveau_pushbuf_emit_reloc(struct nouveau_channel
*chan
, void *ptr
,
197 struct nouveau_bo
*bo
, uint32_t data
, uint32_t flags
,
198 uint32_t vor
, uint32_t tor
)
200 struct nouveau_pushbuf_bo
*pbbo
;
201 struct nouveau_pushbuf_reloc
*r
;
206 pbbo
= nouveau_pushbuf_emit_buffer(chan
, bo
);
210 r
= malloc(sizeof(struct nouveau_pushbuf_reloc
));
211 r
->next
= pbbo
->relocs
;
212 pbbo
->relocs
= pbrel_to_ptr(r
);
215 pbbo
->flags
|= (flags
& NOUVEAU_BO_RDWR
);
216 pbbo
->flags
&= (flags
| NOUVEAU_BO_RDWR
);
218 r
->handle
= bo_to_ptr(r
);