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);