Play "nuke the typedef"
[nouveau] / src / nv_dma.c
1 #include <errno.h>
2 #include "nv_include.h"
3 #include "nvreg.h"
4
5 void NVDmaKickoff(NVPtr pNv)
6 {
7         if(pNv->dmaCurrent != pNv->dmaPut) {
8                 pNv->dmaPut = pNv->dmaCurrent;
9                 WRITE_PUT(pNv,  pNv->dmaPut);
10         }
11 }
12
13 void NVDmaKickoffCallback(NVPtr pNv)
14 {
15         NVDmaKickoff(pNv);
16         pNv->DMAKickoffCallback = NULL;
17 }
18
19 /* There is a HW race condition with videoram command buffers.
20  * You can't jump to the location of your put offset.  We write put
21  * at the jump offset + SKIPS dwords with noop padding in between
22  * to solve this problem
23  */
24 #define SKIPS  8
25
26 void NVDmaWait (ScrnInfoPtr pScrn, int size)
27 {
28         NVPtr pNv = NVPTR(pScrn);
29         int t_start;
30         int dmaGet;
31
32         size++;
33
34         t_start = GetTimeInMillis();
35         while(pNv->dmaFree < size) {
36                 dmaGet = READ_GET(pNv);
37
38                 if(pNv->dmaPut >= dmaGet) {
39                         pNv->dmaFree = pNv->dmaMax - pNv->dmaCurrent;
40                         if(pNv->dmaFree < size) {
41                                 NVDmaNext(pNv, (0x20000000|pNv->fifo.put_base));
42                                 if(dmaGet <= SKIPS) {
43                                         if(pNv->dmaPut <= SKIPS) /* corner case - will be idle */
44                                                 WRITE_PUT(pNv, SKIPS + 1);
45                                         do {
46                                                 if (GetTimeInMillis() - t_start > 2000)
47                                                         NVSync(pScrn);
48                                                 dmaGet = READ_GET(pNv);
49                                         } while(dmaGet <= SKIPS);
50                                 }
51                                 WRITE_PUT(pNv, SKIPS);
52                                 pNv->dmaCurrent = pNv->dmaPut = SKIPS;
53                                 pNv->dmaFree = dmaGet - (SKIPS + 1);
54                         }
55                 } else
56                         pNv->dmaFree = dmaGet - pNv->dmaCurrent - 1;
57
58                 if (GetTimeInMillis() - t_start > 2000)
59                         NVSync(pScrn);
60         }
61 }
62
63 static void NVDumpLockupInfo(NVPtr pNv)
64 {
65         int i,start;
66         start=READ_GET(pNv)-20;
67         if (start<0) start=0;
68         xf86DrvMsg(0, X_INFO, "Fifo dump (lockup 0x%04x,0x%04x):\n",READ_GET(pNv),pNv->dmaPut);
69         for(i=start;i<pNv->dmaPut+10;i++)
70                 xf86DrvMsg(0, X_INFO, "[0x%04x] 0x%08x\n", i, pNv->dmaBase[i]);
71         xf86DrvMsg(0, X_INFO, "End of fifo dump\n");
72 }
73
74 static void
75 NVLockedUp(ScrnInfoPtr pScrn)
76 {
77         NVPtr pNv = NVPTR(pScrn);
78
79         /* avoid re-entering FatalError on shutdown */
80         if (pNv->LockedUp)
81                 return;
82         pNv->LockedUp = TRUE;
83
84         NVDumpLockupInfo(pNv);
85
86         FatalError("DMA queue hang: dmaPut=%x, current=%x, status=%x\n",
87                    pNv->dmaPut, READ_GET(pNv), pNv->PGRAPH[NV_PGRAPH_STATUS/4]);
88 }
89
90 void NVSync(ScrnInfoPtr pScrn)
91 {
92         NVPtr pNv = NVPTR(pScrn);
93         int t_start, timeout = 2000;
94
95         if(pNv->NoAccel)
96                 return;
97
98         if(pNv->DMAKickoffCallback)
99                 (*pNv->DMAKickoffCallback)(pNv);
100
101         /* Wait for entire FIFO to be processed */
102         t_start = GetTimeInMillis();
103         while((GetTimeInMillis() - t_start) < timeout &&
104                         (READ_GET(pNv) != pNv->dmaPut));
105         if ((GetTimeInMillis() - t_start) >= timeout) {
106                 NVLockedUp(pScrn);
107                 return;
108         }
109
110         /* Wait for channel to go completely idle */
111         NVNotifierReset(pScrn, pNv->Notifier0);
112         NVDmaStart(pNv, NvSubImageBlit, 0x104, 1);
113         NVDmaNext (pNv, 0);
114         NVDmaStart(pNv, NvSubImageBlit, 0x100, 1);
115         NVDmaNext (pNv, 0);
116         NVDmaKickoff(pNv);
117         if (!NVNotifierWaitStatus(pScrn, pNv->Notifier0, 0, timeout))
118                 NVLockedUp(pScrn);
119 }
120
121 void NVResetGraphics(ScrnInfoPtr pScrn)
122 {
123         NVPtr pNv = NVPTR(pScrn);
124         CARD32 surfaceFormat, patternFormat, rectFormat, lineFormat;
125         int pitch, i;
126
127         if(pNv->NoAccel) return;
128
129         pitch = pNv->CurrentLayout.displayWidth * (pNv->CurrentLayout.bitsPerPixel >> 3);
130
131         pNv->dmaPut = pNv->dmaCurrent = READ_GET(pNv);
132         pNv->dmaMax = (pNv->fifo.cmdbuf_size >> 2) - 1;
133         pNv->dmaFree = pNv->dmaMax - pNv->dmaCurrent;
134
135         /* assert there's enough room for the skips */
136         if(pNv->dmaFree <= SKIPS)
137                 NVDmaWait(pScrn, SKIPS); 
138         for (i=0; i<SKIPS; i++) {
139                 NVDmaNext(pNv,0);
140                 pNv->dmaBase[i]=0;
141         }
142         pNv->dmaFree -= SKIPS;
143
144         NVAccelCommonInit(pScrn);
145
146         /* EXA + XAA + Xv */
147         NVDmaSetObjectOnSubchannel(pNv, NvSubContextSurfaces, NvContextSurfaces);
148         NVDmaSetObjectOnSubchannel(pNv, NvSubRectangle   , NvRectangle      );
149         NVDmaSetObjectOnSubchannel(pNv, NvSubScaledImage , NvScaledImage    );
150         /* EXA + XAA */
151         NVDmaSetObjectOnSubchannel(pNv, NvSubRop         , NvRop            );
152         NVDmaSetObjectOnSubchannel(pNv, NvSubImagePattern, NvImagePattern   );
153         NVDmaSetObjectOnSubchannel(pNv, NvSubImageBlit   , NvImageBlit      );
154         if (pNv->useEXA) {
155                 if (pNv->GARTScratch)
156                         NVDmaSetObjectOnSubchannel(pNv, NvSubMemFormat, NvMemFormat);
157         } else if (!pNv->useEXA) {
158                 NVDmaSetObjectOnSubchannel(pNv, NvSubClipRectangle, NvClipRectangle);
159                 NVDmaSetObjectOnSubchannel(pNv, NvSubSolidLine, NvSolidLine);
160         }
161
162         switch(pNv->CurrentLayout.depth) {
163         case 24:
164                 surfaceFormat = SURFACE_FORMAT_X8R8G8B8;
165                 patternFormat = PATTERN_FORMAT_DEPTH24;
166                 rectFormat = RECT_FORMAT_DEPTH24;
167                 lineFormat = LINE_FORMAT_DEPTH24;
168                 break;
169         case 16:
170         case 15:
171                 surfaceFormat = SURFACE_FORMAT_R5G6B5;
172                 patternFormat = PATTERN_FORMAT_DEPTH16;
173                 rectFormat = RECT_FORMAT_DEPTH16;
174                 lineFormat = LINE_FORMAT_DEPTH16;
175                 break;
176         default:
177                 surfaceFormat = SURFACE_FORMAT_Y8;
178                 patternFormat = PATTERN_FORMAT_DEPTH8;
179                 rectFormat = RECT_FORMAT_DEPTH8;
180                 lineFormat = LINE_FORMAT_DEPTH8;
181                 break;
182         }
183
184         NVDmaStart(pNv, NvSubContextSurfaces, SURFACE_FORMAT, 4);
185         NVDmaNext (pNv, surfaceFormat);
186         NVDmaNext (pNv, pitch | (pitch << 16));
187         NVDmaNext (pNv, (uint32_t)pNv->FB->offset);
188         NVDmaNext (pNv, (uint32_t)pNv->FB->offset);
189
190         NVDmaStart(pNv, NvSubImagePattern, PATTERN_FORMAT, 1);
191         NVDmaNext (pNv, patternFormat);
192
193         NVDmaStart(pNv, NvSubRectangle, RECT_FORMAT, 1);
194         NVDmaNext (pNv, rectFormat);
195
196         if (!pNv->useEXA) {
197                 NVDmaStart(pNv, NvSubSolidLine, LINE_FORMAT, 1);
198                 NVDmaNext (pNv, lineFormat);
199         }
200
201         pNv->currentRop = ~0;  /* set to something invalid */
202         NVSetRopSolid(pScrn, GXcopy, ~0);
203
204         pNv->M2MFDirection = -1; /* invalid */
205         /*NVDmaKickoff(pNv);*/
206 }
207
208 Bool NVDmaCreateContextObject(NVPtr pNv, int handle, int class)
209 {
210         struct drm_nouveau_grobj_alloc cto;
211         int ret;
212
213         cto.channel = pNv->fifo.channel;
214         cto.handle  = handle;
215         cto.class   = class;
216         ret = drmCommandWrite(pNv->drm_fd, DRM_NOUVEAU_GROBJ_ALLOC,
217                                            &cto, sizeof(cto));
218         return ret == 0;
219 }
220
221 static void NVInitDmaCB(ScrnInfoPtr pScrn)
222 {
223         NVPtr pNv = NVPTR(pScrn);
224         unsigned int cb_location;
225         int cb_size;
226         char *s;
227
228         /* I'm not bothering to check for failures here, the DRM will fall back
229          * on defaults if anything's wrong (ie. out of AGP, invalid sizes)
230          */
231 #ifndef __powerpc__
232         if (pNv->GARTScratch)
233                 cb_location = NOUVEAU_MEM_AGP | NOUVEAU_MEM_PCI_ACCEPTABLE;
234         else
235 #endif
236         cb_location = NOUVEAU_MEM_FB;
237         if((s = (char *)xf86GetOptValString(pNv->Options, OPTION_CMDBUF_LOCATION))) {
238                 if(!xf86NameCmp(s, "AGP"))
239                         cb_location = NOUVEAU_MEM_AGP;
240                 else if (!xf86NameCmp(s, "VRAM"))
241                         cb_location = NOUVEAU_MEM_FB;
242                 else if (!xf86NameCmp(s, "PCI"))
243                         cb_location = NOUVEAU_MEM_PCI;
244                 else
245                         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid value \"%s\" for CBLocation\n", s);
246         }
247         NVDRMSetParam(pNv, NOUVEAU_SETPARAM_CMDBUF_LOCATION, cb_location);
248
249         /* CBSize == size of space reserved for *all* FIFOs in MiB */
250         if (xf86GetOptValInteger(pNv->Options, OPTION_CMDBUF_SIZE, &cb_size))
251                 NVDRMSetParam(pNv, NOUVEAU_SETPARAM_CMDBUF_SIZE, (cb_size<<20));
252 }
253
254 Bool NVInitDma(ScrnInfoPtr pScrn)
255 {
256         NVPtr pNv = NVPTR(pScrn);
257         int i, ret;
258
259         NVInitDmaCB(pScrn);
260
261         if (pNv->NoAccel)
262                 return TRUE;
263
264         pNv->fifo.fb_ctxdma_handle = NvDmaFB;
265         pNv->fifo.tt_ctxdma_handle = NvDmaTT;
266         ret = drmCommandWriteRead(pNv->drm_fd, DRM_NOUVEAU_FIFO_ALLOC,
267                                   &pNv->fifo, sizeof(pNv->fifo));
268         if (ret) {
269                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
270                            "Could not allocate GPU channel: %d\n", ret);
271                 return FALSE;
272         }
273
274         ret = drmMap(pNv->drm_fd, pNv->fifo.cmdbuf, pNv->fifo.cmdbuf_size,
275                      (drmAddressPtr)&pNv->dmaBase);
276         if (ret) {
277                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
278                            "Failed to map DMA push buffer: %d\n", ret);
279                 return FALSE;
280         }
281
282         ret = drmMap(pNv->drm_fd, pNv->fifo.ctrl, pNv->fifo.ctrl_size,
283                      (drmAddressPtr)&pNv->FIFO);
284         if (ret) {
285                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
286                            "Failed to map FIFO control regs: %d\n", ret);
287                 return FALSE;
288         }
289
290         ret = drmMap(pNv->drm_fd, pNv->fifo.notifier, pNv->fifo.notifier_size,
291                      (drmAddressPtr)&pNv->NotifierBlock);
292         if (ret) {
293                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
294                            "Failed to map notifier block: %d\n", ret);
295                 return FALSE;
296         }
297
298         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
299                    "Using FIFO channel %d\n", pNv->fifo.channel);
300         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
301                    "  Control registers : %p (0x%08x)\n",
302                    pNv->FIFO, pNv->fifo.ctrl);
303         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
304                    "  DMA command buffer: %p (0x%08x)\n",
305                    pNv->dmaBase, pNv->fifo.cmdbuf);
306         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
307                    "  DMA cmdbuf length : %d KiB\n",
308                    pNv->fifo.cmdbuf_size / 1024);
309         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
310                    "  DMA base PUT      : 0x%08x\n", pNv->fifo.put_base);
311
312         pNv->dmaPut = pNv->dmaCurrent = READ_GET(pNv);
313         pNv->dmaMax = (pNv->fifo.cmdbuf_size >> 2) - 1;
314         pNv->dmaFree = pNv->dmaMax - pNv->dmaCurrent;
315
316         for (i=0; i<SKIPS; i++)
317                 NVDmaNext(pNv,0);
318         pNv->dmaFree -= SKIPS;
319
320         return TRUE;
321 }
322