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_private.h"
29 //#define NOUVEAU_DMA_DEBUG
30 //#define NOUVEAU_DMA_TRACE
31 //#define NOUVEAU_DMA_DUMP_POSTRELOC_PUSHBUF
32 #if defined(__amd64__)
33 #define NOUVEAU_DMA_BARRIER asm volatile("lock; addl $0,0(%%rsp)" ::: "memory")
34 #elif defined(__i386__)
35 #define NOUVEAU_DMA_BARRIER asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
37 #define NOUVEAU_DMA_BARRIER
39 #define NOUVEAU_DMA_TIMEOUT 2000
40 #define NOUVEAU_TIME_MSEC() 0
43 extern int nouveau_dma_wait(struct nouveau_channel
*chan
, unsigned size
);
44 extern void nouveau_dma_subc_bind(struct nouveau_grobj
*);
45 extern void nouveau_dma_channel_init(struct nouveau_channel
*);
46 extern void nouveau_dma_kickoff(struct nouveau_channel
*);
48 #ifdef NOUVEAU_DMA_DEBUG
49 static char faulty
[1024];
53 nouveau_dma_out(struct nouveau_channel
*chan
, uint32_t data
)
55 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
56 struct nouveau_dma_priv
*dma
= nvchan
->dma
;
58 #ifdef NOUVEAU_DMA_DEBUG
59 if (dma
->push_free
== 0) {
60 printf("No space left in packet at %s\n", faulty
);
65 #ifdef NOUVEAU_DMA_TRACE
67 uint32_t offset
= (dma
->cur
<< 2) + dma
->base
;
68 printf("\tOUT_RING %d/0x%08x -> 0x%08x\n",
69 nvchan
->drm
.channel
, offset
, data
);
72 nvchan
->pushbuf
[dma
->cur
+ (dma
->base
- nvchan
->drm
.put_base
)/4] = data
;
77 nouveau_dma_outp(struct nouveau_channel
*chan
, uint32_t *ptr
, int size
)
79 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
80 struct nouveau_dma_priv
*dma
= nvchan
->dma
;
83 #ifdef NOUVEAU_DMA_DEBUG
84 if (dma
->push_free
< size
) {
85 printf("Packet too small. Free=%d, Need=%d\n",
86 dma
->push_free
, size
);
90 #ifdef NOUVEAU_DMA_TRACE
92 nouveau_dma_out(chan
, *ptr
);
96 memcpy(&nvchan
->pushbuf
[dma
->cur
], ptr
, size
<< 2);
97 #ifdef NOUVEAU_DMA_DEBUG
98 dma
->push_free
-= size
;
105 nouveau_dma_space(struct nouveau_channel
*chan
, unsigned size
)
107 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
108 struct nouveau_dma_priv
*dma
= nvchan
->dma
;
110 if (dma
->free
< size
) {
111 if (nouveau_dma_wait(chan
, size
) && chan
->hang_notify
)
112 chan
->hang_notify(chan
);
115 #ifdef NOUVEAU_DMA_DEBUG
116 dma
->push_free
= size
;
121 nouveau_dma_begin(struct nouveau_channel
*chan
, struct nouveau_grobj
*grobj
,
122 int method
, int size
, const char* file
, int line
)
124 struct nouveau_channel_priv
*nvchan
= nouveau_channel(chan
);
125 struct nouveau_dma_priv
*dma
= nvchan
->dma
;
128 #ifdef NOUVEAU_DMA_TRACE
129 printf("BEGIN_RING %d/%08x/%d/0x%04x/%d\n", nvchan
->drm
.channel
,
130 grobj
->handle
, grobj
->subc
, method
, size
);
133 #ifdef NOUVEAU_DMA_DEBUG
134 if (dma
->push_free
) {
135 printf("Previous packet incomplete: %d left at %s\n",
136 dma
->push_free
, faulty
);
139 sprintf(faulty
,"%s:%d",file
,line
);
142 nouveau_dma_space(chan
, (size
+ 1));
143 nouveau_dma_out(chan
, (size
<< 18) | (grobj
->subc
<< 13) | method
);
146 #define RING_SPACE_CH(ch,sz) nouveau_dma_space((ch), (sz))
147 #define BEGIN_RING_CH(ch,gr,m,sz) nouveau_dma_begin((ch), (gr), (m), (sz), __FUNCTION__, __LINE__ )
148 #define OUT_RING_CH(ch, data) nouveau_dma_out((ch), (data))
149 #define OUT_RINGp_CH(ch,ptr,dwords) nouveau_dma_outp((ch), (void*)(ptr), \
151 #define FIRE_RING_CH(ch) nouveau_dma_kickoff((ch))
152 #define WAIT_RING_CH(ch,sz) nouveau_dma_wait((ch), (sz))