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"
30 #define PB_RSVD_DWORDS 2
33 nouveau_pushbuf_init(struct nouveau_channel
*chan
)
35 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
40 /* Everything except first 4KiB of the push buffer is managed by us */
41 if (nouveau_resource_init(&nvchan
->pb_heap
, 4096,
42 nvchan
->drm
.cmdbuf_size
- 4096))
45 /* Shrink master ring to 4KiB */
46 assert(nvchan
->dma
.cur
<= (4096/4));
47 nvchan
->dma
.max
= (4096 / 4) - 2;
48 nvchan
->dma
.free
= nvchan
->dma
.max
- nvchan
->dma
.cur
;
54 nouveau_pushbuf_fence_signalled(void *priv
)
56 struct nouveau_pushbuf_priv
*nvpb
= nouveau_pushbuf(priv
);
58 nouveau_fence_del(&nvpb
->fence
);
59 nouveau_resource_free(&nvpb
->res
);
63 /* This would be our TTM "superioctl" */
65 nouveau_pushbuf_flush(struct nouveau_channel
*chan
)
67 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
68 struct nouveau_pushbuf_priv
*nvpb
= nouveau_pushbuf(nvchan
->pb_tail
);
69 struct nouveau_pushbuf_bo
*pbbo
;
70 struct nouveau_fence
*fence
= NULL
;
77 if (nvpb
->base
.remaining
== (nvpb
->res
->size
/ 4) - PB_RSVD_DWORDS
)
79 nvchan
->pb_tail
= NULL
;
81 ret
= nouveau_fence_new(chan
, &fence
);
85 /* Validate buffers + apply relocations */
86 while ((pbbo
= ptr_to_pbbo(nvpb
->buffers
))) {
87 struct nouveau_pushbuf_reloc
*r
;
88 struct nouveau_bo
*bo
= &ptr_to_bo(pbbo
->handle
)->base
;
90 ret
= nouveau_bo_validate(chan
, bo
, fence
, pbbo
->flags
);
93 sync_hack
|= nouveau_bo(bo
)->sync_hack
;
94 nouveau_bo(bo
)->sync_hack
= 0;
96 while ((r
= ptr_to_pbrel(pbbo
->relocs
))) {
99 if (r
->flags
& NOUVEAU_BO_LOW
) {
100 push
= bo
->offset
+ r
->data
;
102 if (r
->flags
& NOUVEAU_BO_HIGH
) {
103 push
= (bo
->offset
+ r
->data
) >> 32;
108 if (r
->flags
& NOUVEAU_BO_OR
) {
109 if (bo
->flags
& NOUVEAU_BO_VRAM
)
116 pbbo
->relocs
= r
->next
;
120 nvpb
->buffers
= pbbo
->next
;
123 nvpb
->nr_buffers
= 0;
125 /* Emit JMP to indirect pushbuf */
126 if (nvchan
->dma
.free
< 1)
127 WAIT_RING_CH(chan
, 1);
128 nvchan
->dma
.free
-= 1;
129 #ifdef NOUVEAU_DMA_DEBUG
130 nvchan
->dma
.push_free
= 1;
132 OUT_RING_CH(chan
, 0x20000000 | nvpb
->res
->start
);
134 /* Add JMP back to master pushbuf from indirect pushbuf */
135 (*nvpb
->base
.cur
++) =
136 0x20000000 | ((nvchan
->dma
.cur
<< 2) + nvchan
->dma
.base
);
140 nouveau_fence_signal_cb(nvpb
->fence
, nouveau_pushbuf_fence_signalled
,
142 nouveau_fence_emit(nvpb
->fence
);
148 struct nouveau_fence
*f
= NULL
;
149 nouveau_fence_ref(nvpb
->fence
, &f
);
150 nouveau_fence_wait(&f
);
153 /* Allocate space for next push buffer */
155 nvpb
= calloc(1, sizeof(struct nouveau_pushbuf_priv
));
159 while (nouveau_resource_alloc(nvchan
->pb_heap
, 0x2100, NULL
,
161 nouveau_fence_flush(chan
);
164 nvpb
->base
.channel
= chan
;
165 nvpb
->base
.remaining
= (nvpb
->res
->size
/ 4) - PB_RSVD_DWORDS
;
166 nvpb
->base
.cur
= &nvchan
->pushbuf
[nvpb
->res
->start
/4];
167 nvchan
->pb_tail
= &nvpb
->base
;
172 static struct nouveau_pushbuf_bo
*
173 nouveau_pushbuf_emit_buffer(struct nouveau_channel
*chan
, struct nouveau_bo
*bo
)
175 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
176 struct nouveau_pushbuf_priv
*nvpb
= nouveau_pushbuf(nvchan
->pb_tail
);
177 struct nouveau_pushbuf_bo
*pbbo
= ptr_to_pbbo(nvpb
->buffers
);
180 if (pbbo
->handle
== bo
->handle
)
182 pbbo
= ptr_to_pbbo(pbbo
->next
);
185 pbbo
= malloc(sizeof(struct nouveau_pushbuf_bo
));
186 pbbo
->next
= nvpb
->buffers
;
187 nvpb
->buffers
= pbbo_to_ptr(pbbo
);
190 pbbo
->handle
= bo_to_ptr(bo
);
191 pbbo
->flags
= NOUVEAU_BO_VRAM
| NOUVEAU_BO_GART
;
198 nouveau_pushbuf_emit_reloc(struct nouveau_channel
*chan
, void *ptr
,
199 struct nouveau_bo
*bo
, uint32_t data
, uint32_t flags
,
200 uint32_t vor
, uint32_t tor
)
202 struct nouveau_pushbuf_bo
*pbbo
;
203 struct nouveau_pushbuf_reloc
*r
;
208 pbbo
= nouveau_pushbuf_emit_buffer(chan
, bo
);
212 r
= malloc(sizeof(struct nouveau_pushbuf_reloc
));
213 r
->next
= pbbo
->relocs
;
214 pbbo
->relocs
= pbrel_to_ptr(r
);
217 pbbo
->flags
|= (flags
& NOUVEAU_BO_RDWR
);
218 pbbo
->flags
&= (flags
| NOUVEAU_BO_RDWR
);
220 r
->handle
= bo_to_ptr(r
);