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
28 #include "nouveau_drmif.h"
29 #include "nouveau_dma.h"
31 static inline uint32_t
32 READ_GET(struct nouveau_channel_priv
*nvchan
)
38 WRITE_PUT(struct nouveau_channel_priv
*nvchan
, uint32_t val
)
40 uint32_t put
= ((val
<< 2) + nvchan
->dma
->base
);
44 dum
= nvchan
->pushbuf
[0];
45 dum
= READ_GET(nvchan
);
48 nvchan
->dma
->put
= val
;
49 #ifdef NOUVEAU_DMA_TRACE
50 printf("WRITE_PUT %d/0x%08x\n", nvchan
->drm
.channel
, put
);
57 LOCAL_GET(struct nouveau_dma_priv
*dma
, uint32_t *val
)
61 if (get
>= dma
->base
&& get
<= (dma
->base
+ (dma
->max
<< 2))) {
62 *val
= (get
- dma
->base
) >> 2;
70 nouveau_dma_channel_init(struct nouveau_channel
*chan
)
72 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
75 nvchan
->dma
= &nvchan
->struct_dma
;
76 nvchan
->dma
->base
= nvchan
->drm
.put_base
;
77 nvchan
->dma
->cur
= nvchan
->dma
->put
= 0;
78 nvchan
->dma
->max
= (nvchan
->drm
.cmdbuf_size
>> 2) - 2;
79 nvchan
->dma
->free
= nvchan
->dma
->max
- nvchan
->dma
->cur
;
81 RING_SPACE_CH(chan
, RING_SKIPS
);
82 for (i
= 0; i
< RING_SKIPS
; i
++)
86 #define CHECK_TIMEOUT() do { \
87 if ((NOUVEAU_TIME_MSEC() - t_start) > NOUVEAU_DMA_TIMEOUT) \
92 nouveau_dma_wait(struct nouveau_channel
*chan
, unsigned size
)
94 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
95 struct nouveau_dma_priv
*dma
= nvchan
->dma
;
96 uint32_t get
, t_start
;
100 t_start
= NOUVEAU_TIME_MSEC();
101 while (dma
->free
< size
) {
104 get
= READ_GET(nvchan
);
105 if (!LOCAL_GET(dma
, &get
))
108 if (dma
->put
>= get
) {
109 dma
->free
= dma
->max
- dma
->cur
;
111 if (dma
->free
< size
) {
112 #ifdef NOUVEAU_DMA_DEBUG
115 OUT_RING_CH(chan
, 0x20000000 | dma
->base
);
116 if (get
<= RING_SKIPS
) {
117 /*corner case - will be idle*/
118 if (dma
->put
<= RING_SKIPS
)
124 get
= READ_GET(nvchan
);
125 if (!LOCAL_GET(dma
, &get
))
127 } while (get
<= RING_SKIPS
);
130 WRITE_PUT(nvchan
, RING_SKIPS
);
131 dma
->cur
= dma
->put
= RING_SKIPS
;
132 dma
->free
= get
- (RING_SKIPS
+ 1);
135 dma
->free
= get
- dma
->cur
- 1;
142 #ifdef NOUVEAU_DMA_DUMP_POSTRELOC_PUSHBUF
144 nouveau_dma_parse_pushbuf(struct nouveau_channel
*chan
, int get
, int put
)
146 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
147 unsigned mthd_count
= 0;
150 uint32_t gpuget
= (get
<< 2) + nvchan
->drm
.put_base
;
153 if (get
< 0 || get
>= nvchan
->drm
.cmdbuf_size
)
155 data
= nvchan
->pushbuf
[get
++];
158 printf("0x%08x 0x%08x\n", gpuget
, data
);
163 switch (data
& 0x60000000) {
165 mthd_count
= (data
>> 18) & 0x7ff;
166 printf("0x%08x 0x%08x MTHD "
167 "Sc %d Mthd 0x%04x Size %d\n",
168 gpuget
, data
, (data
>>13) & 7, data
& 0x1ffc,
172 get
= (data
& 0x1ffffffc) >> 2;
173 printf("0x%08x 0x%08x JUMP 0x%08x\n",
174 gpuget
, data
, data
& 0x1ffffffc);
177 mthd_count
= (data
>> 18) & 0x7ff;
178 printf("0x%08x 0x%08x NINC "
179 "Sc %d Mthd 0x%04x Size %d\n",
180 gpuget
, data
, (data
>>13) & 7, data
& 0x1ffc,
184 /* DMA_OPCODE_CALL apparently, doesn't seem to work on
189 printf("DMA_PUSHER 0x%08x 0x%08x\n", gpuget
, data
);
197 nouveau_dma_kickoff(struct nouveau_channel
*chan
)
199 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
200 struct nouveau_dma_priv
*dma
= nvchan
->dma
;
202 if (dma
->cur
== dma
->put
)
205 #ifdef NOUVEAU_DMA_DEBUG
206 if (dma
->push_free
) {
207 printf("Packet incomplete: %d left\n", dma
->push_free
);
212 #ifdef NOUVEAU_DMA_DUMP_POSTRELOC_PUSHBUF
213 nouveau_dma_parse_pushbuf(chan
, dma
->put
, dma
->cur
);
216 WRITE_PUT(nvchan
, dma
->cur
);