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
23 #ifndef __NOUVEAU_DMA_H__
24 #define __NOUVEAU_DMA_H__
27 #include "nouveau_drmif.h"
28 #include "nouveau_local.h"
32 NOUVEAU_PRIVATE int nouveau_dma_wait(struct nouveau_channel *chan, int size);
33 NOUVEAU_PRIVATE void nouveau_dma_subc_bind(struct nouveau_grobj *);
34 NOUVEAU_PRIVATE void nouveau_dma_channel_init(struct nouveau_channel *);
35 NOUVEAU_PRIVATE void nouveau_dma_kickoff(struct nouveau_channel *);
37 #ifdef NOUVEAU_DMA_DEBUG
38 NOUVEAU_PRIVATE char faulty[1024];
42 nouveau_dma_out(struct nouveau_channel *userchan, uint32_t data)
44 struct nouveau_channel_priv *chan = nouveau_channel(userchan);
46 #ifdef NOUVEAU_DMA_DEBUG
47 if (chan->dma.push_free == 0) {
48 NOUVEAU_ERR("No space left in packet. Error at %s\n",faulty);
51 chan->dma.push_free--;
53 #ifdef NOUVEAU_DMA_TRACE
55 uint32_t offset = (chan->dma.cur << 2) + chan->dma.base;
56 NOUVEAU_MSG("\tOUT_RING %d/0x%08x -> 0x%08x\n",
57 chan->drm.channel, offset, data);
60 chan->pushbuf[chan->dma.cur++] = data;
64 nouveau_dma_outp(struct nouveau_channel *userchan, uint32_t *ptr, int size)
66 struct nouveau_channel_priv *chan = nouveau_channel(userchan);
69 #ifdef NOUVEAU_DMA_DEBUG
70 if (chan->dma.push_free < size) {
71 NOUVEAU_ERR("Packet too small. Free=%d, Need=%d\n",
72 chan->dma.push_free, size);
76 #ifdef NOUVEAU_DMA_TRACE
78 nouveau_dma_out(userchan, *ptr);
82 memcpy(&chan->pushbuf[chan->dma.cur], ptr, size << 2);
83 #ifdef NOUVEAU_DMA_DEBUG
84 chan->dma.push_free -= size;
86 chan->dma.cur += size;
91 nouveau_dma_begin(struct nouveau_channel *userchan, struct nouveau_grobj *grobj,
92 int method, int size, const char* file, int line)
94 struct nouveau_channel_priv *chan = nouveau_channel(userchan);
95 int push_size = size + 1;
97 #ifdef NOUVEAU_DMA_SUBCHAN_LRU
98 if (grobj->bound == NOUVEAU_GROBJ_UNBOUND)
99 nouveau_dma_subc_bind(grobj);
100 chan->subchannel[grobj->subc].seq = chan->subc_sequence++;
103 #ifdef NOUVEAU_DMA_TRACE
104 NOUVEAU_MSG("BEGIN_RING %d/%08x/%d/0x%04x/%d\n", chan->drm.channel,
105 grobj->handle, grobj->subc, method, size);
108 #ifdef NOUVEAU_DMA_DEBUG
109 if (chan->dma.push_free) {
110 NOUVEAU_ERR("Previous packet incomplete: %d left. Error at %s\n",
111 chan->dma.push_free,faulty);
114 sprintf(faulty,"%s:%d",file,line);
117 if (chan->dma.free < push_size) {
118 if (nouveau_dma_wait(userchan, push_size) &&
119 userchan->hang_notify) {
120 userchan->hang_notify(userchan);
123 chan->dma.free -= push_size;
124 #ifdef NOUVEAU_DMA_DEBUG
125 chan->dma.push_free = push_size;
128 nouveau_dma_out(userchan, (size << 18) | (grobj->subc << 13) | method);
132 nouveau_dma_bind(struct nouveau_channel *userchan, struct nouveau_grobj *grobj,
135 struct nouveau_channel_priv *chan = nouveau_channel(userchan);
137 if (chan->subchannel[subc].grobj == grobj)
140 if (chan->subchannel[subc].grobj)
141 chan->subchannel[subc].grobj->bound = NOUVEAU_GROBJ_UNBOUND;
142 chan->subchannel[subc].grobj = grobj;
144 grobj->bound = NOUVEAU_GROBJ_EXPLICIT_BIND;
146 nouveau_dma_begin(userchan, grobj, 0x0000, 1, __FUNCTION__, __LINE__);
147 nouveau_dma_out (userchan, grobj->handle);
150 #define BIND_RING_CH(ch,gr,sc) nouveau_dma_bind((ch), (gr), (sc))
151 #define BEGIN_RING_CH(ch,gr,m,sz) nouveau_dma_begin((ch), (gr), (m), (sz), __FUNCTION__, __LINE__ )
152 #define OUT_RING_CH(ch, data) nouveau_dma_out((ch), (data))
153 #define OUT_RINGp_CH(ch,ptr,dwords) nouveau_dma_outp((ch), (void*)(ptr), \
155 #define FIRE_RING_CH(ch) nouveau_dma_kickoff((ch))
156 #define WAIT_RING_CH(ch,sz) nouveau_dma_wait((ch), (sz))