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"
29 #include "nouveau_local.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
= READ_GET(nvchan
);
47 nvchan
->dma
->put
= val
;
48 #ifdef NOUVEAU_DMA_TRACE
49 NOUVEAU_MSG("WRITE_PUT %d/0x%08x\n", nvchan
->drm
.channel
, put
);
56 LOCAL_GET(struct nouveau_dma_priv
*dma
, uint32_t *val
)
60 if (get
>= dma
->base
&& get
<= (dma
->base
+ (dma
->max
<< 2))) {
61 *val
= (get
- dma
->base
) >> 2;
69 nouveau_dma_channel_init(struct nouveau_channel
*chan
)
71 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
74 nvchan
->dma
= &nvchan
->dma_master
;
75 nvchan
->dma
->base
= nvchan
->drm
.put_base
;
76 nvchan
->dma
->cur
= nvchan
->dma
->put
= 0;
77 nvchan
->dma
->max
= (nvchan
->drm
.cmdbuf_size
>> 2) - 2;
78 nvchan
->dma
->free
= nvchan
->dma
->max
- nvchan
->dma
->cur
;
80 RING_SPACE_CH(chan
, RING_SKIPS
);
81 for (i
= 0; i
< RING_SKIPS
; i
++)
85 #define CHECK_TIMEOUT() do { \
86 if ((NOUVEAU_TIME_MSEC() - t_start) > NOUVEAU_DMA_TIMEOUT) \
91 nouveau_dma_wait(struct nouveau_channel
*chan
, int size
)
93 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
94 struct nouveau_dma_priv
*dma
= nvchan
->dma
;
95 uint32_t get
, t_start
;
99 t_start
= NOUVEAU_TIME_MSEC();
100 while (dma
->free
< size
) {
103 get
= READ_GET(nvchan
);
104 if (!LOCAL_GET(dma
, &get
))
107 if (dma
->put
>= get
) {
108 dma
->free
= dma
->max
- dma
->cur
;
110 if (dma
->free
< size
) {
111 #ifdef NOUVEAU_DMA_DEBUG
114 OUT_RING_CH(chan
, 0x20000000 | dma
->base
);
115 if (get
<= RING_SKIPS
) {
116 /*corner case - will be idle*/
117 if (dma
->put
<= RING_SKIPS
)
123 get
= READ_GET(nvchan
);
124 if (!LOCAL_GET(dma
, &get
))
126 } while (get
<= RING_SKIPS
);
129 WRITE_PUT(nvchan
, RING_SKIPS
);
130 dma
->cur
= dma
->put
= RING_SKIPS
;
131 dma
->free
= get
- (RING_SKIPS
+ 1);
134 dma
->free
= get
- dma
->cur
- 1;
141 #ifdef NOUVEAU_DMA_DUMP_POSTRELOC_PUSHBUF
143 nouveau_dma_parse_pushbuf(struct nouveau_channel
*chan
, int get
, int put
)
145 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
146 unsigned mthd_count
= 0;
149 uint32_t gpuget
= (get
<< 2) + nvchan
->drm
.put_base
;
152 if (get
< 0 || get
>= nvchan
->drm
.cmdbuf_size
) {
153 NOUVEAU_ERR("DMA_PT 0x%08x\n", gpuget
);
156 data
= nvchan
->pushbuf
[get
++];
159 NOUVEAU_MSG("0x%08x 0x%08x\n", gpuget
, data
);
164 switch (data
& 0x60000000) {
166 mthd_count
= (data
>> 18) & 0x7ff;
167 NOUVEAU_MSG("0x%08x 0x%08x MTHD "
168 "Sc %d Mthd 0x%04x Size %d\n",
169 gpuget
, data
, (data
>>13) & 7, data
& 0x1ffc,
173 get
= (data
& 0x1ffffffc) >> 2;
174 NOUVEAU_MSG("0x%08x 0x%08x JUMP 0x%08x\n",
175 gpuget
, data
, data
& 0x1ffffffc);
178 mthd_count
= (data
>> 18) & 0x7ff;
179 NOUVEAU_MSG("0x%08x 0x%08x NINC "
180 "Sc %d Mthd 0x%04x Size %d\n",
181 gpuget
, data
, (data
>>13) & 7, data
& 0x1ffc,
185 /* DMA_OPCODE_CALL apparently, doesn't seem to work on
190 NOUVEAU_MSG("DMA_PUSHER 0x%08x 0x%08x\n",
199 nouveau_dma_kickoff(struct nouveau_channel
*chan
)
201 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
202 struct nouveau_dma_priv
*dma
= nvchan
->dma
;
204 if (dma
->cur
== dma
->put
)
207 #ifdef NOUVEAU_DMA_DEBUG
208 if (dma
->push_free
) {
209 NOUVEAU_ERR("Packet incomplete: %d left\n", dma
->push_free
);
214 #ifdef NOUVEAU_DMA_DUMP_POSTRELOC_PUSHBUF
215 nouveau_dma_parse_pushbuf(chan
, dma
->put
, dma
->cur
);
218 WRITE_PUT(nvchan
, dma
->cur
);