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
;
76 if (nvpb
->base
.remaining
== (nvpb
->res
->size
/ 4) - PB_RSVD_DWORDS
)
78 nvchan
->pb_tail
= NULL
;
80 ret
= nouveau_fence_new(chan
, &fence
);
84 /* Validate buffers + apply relocations */
85 while ((pbbo
= ptr_to_pbbo(nvpb
->buffers
))) {
86 struct nouveau_pushbuf_reloc
*r
;
87 struct nouveau_bo
*bo
= &ptr_to_bo(pbbo
->handle
)->base
;
89 ret
= nouveau_bo_validate(chan
, bo
, fence
, pbbo
->flags
);
92 while ((r
= ptr_to_pbrel(pbbo
->relocs
))) {
95 if (r
->flags
& NOUVEAU_BO_LOW
) {
96 push
= bo
->offset
+ r
->data
;
98 if (r
->flags
& NOUVEAU_BO_HIGH
) {
99 push
= (bo
->offset
+ r
->data
) >> 32;
104 if (r
->flags
& NOUVEAU_BO_OR
) {
105 if (bo
->flags
& NOUVEAU_BO_VRAM
)
112 pbbo
->relocs
= r
->next
;
116 nvpb
->buffers
= pbbo
->next
;
119 nvpb
->nr_buffers
= 0;
121 /* Emit JMP to indirect pushbuf */
122 if (nvchan
->dma
.free
< 1)
123 WAIT_RING_CH(chan
, 1);
124 nvchan
->dma
.free
-= 1;
125 #ifdef NOUVEAU_DMA_DEBUG
126 nvchan
->dma
.push_free
= 1;
128 OUT_RING_CH(chan
, 0x20000000 | nvpb
->res
->start
);
130 /* Add JMP back to master pushbuf from indirect pushbuf */
131 (*nvpb
->base
.cur
++) =
132 0x20000000 | ((nvchan
->dma
.cur
<< 2) + nvchan
->dma
.base
);
136 nouveau_fence_signal_cb(nvpb
->fence
, nouveau_pushbuf_fence_signalled
,
138 nouveau_fence_emit(nvpb
->fence
);
143 /* Allocate space for next push buffer */
145 nvpb
= calloc(1, sizeof(struct nouveau_pushbuf_priv
));
149 while (nouveau_resource_alloc(nvchan
->pb_heap
, 0x2100, NULL
,
151 nouveau_fence_flush(chan
);
154 nvpb
->base
.channel
= chan
;
155 nvpb
->base
.remaining
= (nvpb
->res
->size
/ 4) - PB_RSVD_DWORDS
;
156 nvpb
->base
.cur
= &nvchan
->pushbuf
[nvpb
->res
->start
/4];
157 nvchan
->pb_tail
= &nvpb
->base
;
162 static struct nouveau_pushbuf_bo
*
163 nouveau_pushbuf_emit_buffer(struct nouveau_channel
*chan
, struct nouveau_bo
*bo
)
165 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
166 struct nouveau_pushbuf_priv
*nvpb
= nouveau_pushbuf(nvchan
->pb_tail
);
167 struct nouveau_pushbuf_bo
*pbbo
= ptr_to_pbbo(nvpb
->buffers
);
170 if (pbbo
->handle
== bo
->handle
)
172 pbbo
= ptr_to_pbbo(pbbo
->next
);
175 pbbo
= malloc(sizeof(struct nouveau_pushbuf_bo
));
176 pbbo
->next
= nvpb
->buffers
;
177 nvpb
->buffers
= pbbo_to_ptr(pbbo
);
180 pbbo
->handle
= bo_to_ptr(bo
);
181 pbbo
->flags
= NOUVEAU_BO_VRAM
| NOUVEAU_BO_GART
;
188 nouveau_pushbuf_emit_reloc(struct nouveau_channel
*chan
, void *ptr
,
189 struct nouveau_bo
*bo
, uint32_t data
, uint32_t flags
,
190 uint32_t vor
, uint32_t tor
)
192 struct nouveau_pushbuf_bo
*pbbo
;
193 struct nouveau_pushbuf_reloc
*r
;
198 pbbo
= nouveau_pushbuf_emit_buffer(chan
, bo
);
202 r
= malloc(sizeof(struct nouveau_pushbuf_reloc
));
203 r
->next
= pbbo
->relocs
;
204 pbbo
->relocs
= pbrel_to_ptr(r
);
207 pbbo
->flags
|= (flags
& NOUVEAU_BO_RDWR
);
208 pbbo
->flags
&= (flags
| NOUVEAU_BO_RDWR
);
210 r
->handle
= bo_to_ptr(r
);