No empty .Rs/.Re
[netbsd-mini2440.git] / sys / external / bsd / drm / dist / libdrm / nouveau / nouveau_dma.c
blobb084f7069cd6e2be0fcd8cfdebc803173a575c08
1 /*
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
20 * SOFTWARE.
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <assert.h>
26 #include <errno.h>
28 #include "nouveau_drmif.h"
29 #include "nouveau_dma.h"
31 static inline uint32_t
32 READ_GET(struct nouveau_channel_priv *nvchan)
34 return *nvchan->get;
37 static inline void
38 WRITE_PUT(struct nouveau_channel_priv *nvchan, uint32_t val)
40 uint32_t put = ((val << 2) + nvchan->dma->base);
41 volatile int dum;
43 NOUVEAU_DMA_BARRIER;
44 dum = nvchan->pushbuf[0];
45 dum = READ_GET(nvchan);
47 *nvchan->put = put;
48 nvchan->dma->put = val;
49 #ifdef NOUVEAU_DMA_TRACE
50 printf("WRITE_PUT %d/0x%08x\n", nvchan->drm.channel, put);
51 #endif
53 NOUVEAU_DMA_BARRIER;
56 static inline int
57 LOCAL_GET(struct nouveau_dma_priv *dma, uint32_t *val)
59 uint32_t get = *val;
61 if (get >= dma->base && get <= (dma->base + (dma->max << 2))) {
62 *val = (get - dma->base) >> 2;
63 return 1;
66 return 0;
69 void
70 nouveau_dma_channel_init(struct nouveau_channel *chan)
72 struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
73 int i;
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++)
83 OUT_RING_CH(chan, 0);
86 #define CHECK_TIMEOUT() do { \
87 if ((NOUVEAU_TIME_MSEC() - t_start) > NOUVEAU_DMA_TIMEOUT) \
88 return - EBUSY; \
89 } while(0)
91 int
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;
98 FIRE_RING_CH(chan);
100 t_start = NOUVEAU_TIME_MSEC();
101 while (dma->free < size) {
102 CHECK_TIMEOUT();
104 get = READ_GET(nvchan);
105 if (!LOCAL_GET(dma, &get))
106 continue;
108 if (dma->put >= get) {
109 dma->free = dma->max - dma->cur;
111 if (dma->free < size) {
112 #ifdef NOUVEAU_DMA_DEBUG
113 dma->push_free = 1;
114 #endif
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)
119 WRITE_PUT(nvchan,
120 RING_SKIPS + 1);
122 do {
123 CHECK_TIMEOUT();
124 get = READ_GET(nvchan);
125 if (!LOCAL_GET(dma, &get))
126 get = 0;
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);
134 } else {
135 dma->free = get - dma->cur - 1;
139 return 0;
142 #ifdef NOUVEAU_DMA_DUMP_POSTRELOC_PUSHBUF
143 static void
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;
149 while (get != put) {
150 uint32_t gpuget = (get << 2) + nvchan->drm.put_base;
151 uint32_t data;
153 if (get < 0 || get >= nvchan->drm.cmdbuf_size)
154 assert(0);
155 data = nvchan->pushbuf[get++];
157 if (mthd_count) {
158 printf("0x%08x 0x%08x\n", gpuget, data);
159 mthd_count--;
160 continue;
163 switch (data & 0x60000000) {
164 case 0x00000000:
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,
169 mthd_count);
170 break;
171 case 0x20000000:
172 get = (data & 0x1ffffffc) >> 2;
173 printf("0x%08x 0x%08x JUMP 0x%08x\n",
174 gpuget, data, data & 0x1ffffffc);
175 continue;
176 case 0x40000000:
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,
181 mthd_count);
182 break;
183 case 0x60000000:
184 /* DMA_OPCODE_CALL apparently, doesn't seem to work on
185 * my NV40 at least..
187 /* fall-through */
188 default:
189 printf("DMA_PUSHER 0x%08x 0x%08x\n", gpuget, data);
190 assert(0);
194 #endif
196 void
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)
203 return;
205 #ifdef NOUVEAU_DMA_DEBUG
206 if (dma->push_free) {
207 printf("Packet incomplete: %d left\n", dma->push_free);
208 return;
210 #endif
212 #ifdef NOUVEAU_DMA_DUMP_POSTRELOC_PUSHBUF
213 nouveau_dma_parse_pushbuf(chan, dma->put, dma->cur);
214 #endif
216 WRITE_PUT(nvchan, dma->cur);