Remove the PFIFO_REINIT hack, and enable the irq by default. This commit requires...
[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 #define SKIPS  8
24
25 void NVDmaWait (NVPtr pNv, int size)
26 {
27     int t_start;
28     int dmaGet;
29
30     size++;
31
32     t_start = GetTimeInMillis();
33     while(pNv->dmaFree < size) {
34        dmaGet = READ_GET(pNv);
35
36        if(pNv->dmaPut >= dmaGet) {
37            pNv->dmaFree = pNv->dmaMax - pNv->dmaCurrent;
38            if(pNv->dmaFree < size) {
39                NVDmaNext(pNv, (0x20000000|pNv->fifo.put_base));
40                if(dmaGet <= SKIPS) {
41                    if(pNv->dmaPut <= SKIPS) /* corner case - will be idle */
42                       WRITE_PUT(pNv, SKIPS + 1);
43                    do {
44                        if (GetTimeInMillis() - t_start > 2000)
45                            NVDoSync(pNv);
46                        dmaGet = READ_GET(pNv);
47                    } while(dmaGet <= SKIPS);
48                }
49                WRITE_PUT(pNv, SKIPS);
50                pNv->dmaCurrent = pNv->dmaPut = SKIPS;
51                pNv->dmaFree = dmaGet - (SKIPS + 1);
52            }
53        } else 
54            pNv->dmaFree = dmaGet - pNv->dmaCurrent - 1;
55
56        if (GetTimeInMillis() - t_start > 2000)
57            NVDoSync(pNv);
58     }
59 }
60
61 static void NVDumpLockupInfo(NVPtr pNv)
62 {
63         int i,start;
64         start=READ_GET(pNv)-10;
65         if (start<0) start=0;
66         xf86DrvMsg(0, X_INFO, "Fifo dump (lockup 0x%04x,0x%04x):\n",READ_GET(pNv),pNv->dmaPut);
67         for(i=start;i<pNv->dmaPut+10;i++)
68                 xf86DrvMsg(0, X_INFO, "[0x%04x] 0x%08x\n", i, pNv->dmaBase[i]);
69         xf86DrvMsg(0, X_INFO, "End of fifo dump\n");
70 }
71
72 void NVDoSync(NVPtr pNv)
73 {
74     int t_start, timeout = 2000;
75
76     if(pNv->DMAKickoffCallback)
77        (*pNv->DMAKickoffCallback)(pNv);
78
79     t_start = GetTimeInMillis();
80     while((GetTimeInMillis() - t_start) < timeout && (READ_GET(pNv) != pNv->dmaPut));
81     while((GetTimeInMillis() - t_start) < timeout && pNv->PGRAPH[NV_PGRAPH_STATUS/4]);
82
83     if ((GetTimeInMillis() - t_start) >= timeout) {
84         if (pNv->LockedUp)
85             return;
86         NVDumpLockupInfo(pNv);
87         pNv->LockedUp = TRUE; /* avoid re-entering FatalError on shutdown */
88         FatalError("DMA queue hang: dmaPut=%x, current=%x, status=%x\n",
89                pNv->dmaPut, READ_GET(pNv), pNv->PGRAPH[NV_PGRAPH_STATUS/4]);
90     }
91 }
92
93 void NVSync(ScrnInfoPtr pScrn)
94 {
95     NVPtr pNv = NVPTR(pScrn);
96     NVDoSync(pNv);
97 }
98
99 void NVResetGraphics(ScrnInfoPtr pScrn)
100 {
101     NVPtr pNv = NVPTR(pScrn);
102     CARD32 surfaceFormat, patternFormat, rectFormat, lineFormat;
103     int pitch, i;
104
105     if(pNv->NoAccel) return;
106
107     pitch = pNv->CurrentLayout.displayWidth * 
108             (pNv->CurrentLayout.bitsPerPixel >> 3);
109
110     pNv->dmaPut = pNv->dmaCurrent = READ_GET(pNv);
111     pNv->dmaMax = (pNv->fifo.cmdbuf_size >> 2) - 1;
112     pNv->dmaFree = pNv->dmaMax - pNv->dmaCurrent;
113
114     /* assert there's enough room for the skips */
115     if(pNv->dmaFree <= SKIPS)
116             NVDmaWait(pNv, SKIPS); 
117     for (i=0; i<SKIPS; i++)
118     {
119             NVDmaNext(pNv,0);
120             pNv->dmaBase[i]=0;
121     }
122     pNv->dmaFree -= SKIPS;
123
124         /* EXA + XAA + Xv */
125     NVDmaSetObjectOnSubchannel(pNv, NvSubContextSurfaces, NvContextSurfaces);
126     NVDmaSetObjectOnSubchannel(pNv, NvSubRectangle      , NvRectangle      );
127     NVDmaSetObjectOnSubchannel(pNv, NvSubScaledImage    , NvScaledImage    );
128         /* EXA + XAA */
129     NVDmaSetObjectOnSubchannel(pNv, NvSubRop            , NvRop            );
130     NVDmaSetObjectOnSubchannel(pNv, NvSubImagePattern   , NvImagePattern   );
131     NVDmaSetObjectOnSubchannel(pNv, NvSubImageBlit      , NvImageBlit      );
132         if (pNv->useEXA && pNv->AGPScratch) {
133                 NVDmaSetObjectOnSubchannel(pNv, NvSubMemFormat    , NvMemFormat    );
134         } else if (!pNv->useEXA) {
135         NVDmaSetObjectOnSubchannel(pNv, NvSubClipRectangle, NvClipRectangle);
136         NVDmaSetObjectOnSubchannel(pNv, NvSubSolidLine    , NvSolidLine    );
137         }
138
139     switch(pNv->CurrentLayout.depth) {
140     case 24:
141        surfaceFormat = SURFACE_FORMAT_X8R8G8B8;
142        patternFormat = PATTERN_FORMAT_DEPTH24;
143        rectFormat    = RECT_FORMAT_DEPTH24;
144        lineFormat    = LINE_FORMAT_DEPTH24;
145        break;
146     case 16:
147     case 15:
148        surfaceFormat = SURFACE_FORMAT_R5G6B5;
149        patternFormat = PATTERN_FORMAT_DEPTH16;
150        rectFormat    = RECT_FORMAT_DEPTH16;
151        lineFormat    = LINE_FORMAT_DEPTH16;
152        break;
153     default:
154        surfaceFormat = SURFACE_FORMAT_Y8;
155        patternFormat = PATTERN_FORMAT_DEPTH8;
156        rectFormat    = RECT_FORMAT_DEPTH8;
157        lineFormat    = LINE_FORMAT_DEPTH8;
158        break;
159     }
160
161     NVDmaStart(pNv, NvSubContextSurfaces, SURFACE_FORMAT, 4);
162     NVDmaNext (pNv, surfaceFormat);
163     NVDmaNext (pNv, pitch | (pitch << 16));
164     NVDmaNext (pNv, (CARD32)(pNv->FB->offset - pNv->VRAMPhysical));
165     NVDmaNext (pNv, (CARD32)(pNv->FB->offset - pNv->VRAMPhysical));
166
167     NVDmaStart(pNv, NvSubImagePattern, PATTERN_FORMAT, 1);
168     NVDmaNext (pNv, patternFormat);
169
170     NVDmaStart(pNv, NvSubRectangle, RECT_FORMAT, 1);
171     NVDmaNext (pNv, rectFormat);
172
173         if (!pNv->useEXA) {
174         NVDmaStart(pNv, NvSubSolidLine, LINE_FORMAT, 1);
175         NVDmaNext (pNv, lineFormat);
176         }
177
178     pNv->currentRop = ~0;  /* set to something invalid */
179     NVSetRopSolid(pScrn, GXcopy, ~0);
180
181     pNv->M2MFDirection = -1; /* invalid */
182     /*NVDmaKickoff(pNv);*/
183 }
184
185 Bool NVDmaCreateDMAObject(NVPtr pNv, int handle, int target, CARD32 base_address, CARD32 size, int access)
186 {
187     drm_nouveau_dma_object_init_t dma;
188         int ret;
189
190     dma.handle = handle;
191     dma.access = access;
192     dma.target = target;
193     dma.size   = size;
194     dma.offset = base_address;
195     ret = drmCommandWrite(pNv->drm_fd, DRM_NOUVEAU_DMA_OBJECT_INIT, &dma, sizeof(dma));
196
197     return ret == 0;
198 }
199
200 /*
201    A DMA notifier is a DMA object that references a small (32 byte it
202    seems, we use 256 for saftey) memory area that will be used by the HW to give feedback
203    about a DMA operation.
204 */
205 NVAllocRec *NVDmaCreateNotifier(NVPtr pNv, int handle)
206 {
207         NVAllocRec *notifier = NULL;
208
209 #ifndef __powerpc__
210         notifier = NVAllocateMemory(pNv, NOUVEAU_MEM_AGP, 256);
211 #endif
212         if (!notifier)
213                 notifier = NVAllocateMemory(pNv, NOUVEAU_MEM_FB, 256);
214
215         if (!NVDmaCreateDMAObject(pNv, handle,
216                         notifier->type & NOUVEAU_MEM_AGP ?
217                                 NV_DMA_TARGET_AGP : NV_DMA_TARGET_VIDMEM,
218                         notifier->offset,
219                         notifier->size,
220                         NV_DMA_ACCES_RW)) {
221                 NVFreeMemory(pNv, notifier);
222                 return NULL;
223         }
224
225         return notifier;
226 }
227
228 /*
229   How do we wait for DMA completion (by notifiers) ?
230
231    Either repeatedly read the notifier address and wait until it changes,
232    or enable a 'wakeup' interrupt by writing NOTIFY_WRITE_LE_AWAKEN into
233    the 'notify' field of the object in the channel.  My guess is that 
234    this causes an interrupt in PGRAPH/NOTIFY as soon as the transfer is
235    completed.  Clients probably can use poll on the nv* devices to get this 
236    event.  All this is a guess.  I don't know any details, and I have not
237    tested is.  Also, I have no idea how the 'nvdriver' reacts if it gets 
238    notify events that are not registered.
239
240    Writing NV_NOTIFY_WRITE_LE_AWAKEN into the 'Notify' field of an object
241    in a channel really causes an interrupt in the PGRAPH engine.  Thus
242    we can determine whether a DMA transfer has finished in the interrupt
243    handler.
244
245    We can't use interrupts in user land, so we do the simple polling approach.
246    The method returns FALSE in case of an error.
247 */
248 Bool NVDmaWaitForNotifier(NVPtr pNv, void *notifier)
249 {
250     int t_start, timeout = 0;
251     volatile CARD32 *n;
252
253     n = (volatile CARD32 *)notifier;
254     NVDEBUG("NVDmaWaitForNotifier @%p", n);
255     t_start = GetTimeInMillis();
256     while (1) {
257         CARD32 a = n[0];
258         CARD32 b = n[1];
259         CARD32 c = n[2];
260         CARD32 status = n[3];
261         NVDEBUG("status: n[0]=%x, n[1]=%x, n[2]=%x, n[3]=%x\n", a, b, c, status);
262         NVDEBUG("status: GET: 0x%08x\n", READ_GET(pNv));
263
264         if (GetTimeInMillis() - t_start >= 2000) {
265             /* We've timed out, call NVSync() to detect lockups */
266             if (timeout++ == 0) {
267                 NVDoSync(pNv);
268                 /* If we're still here, wait another second for notifier.. */
269                 t_start = GetTimeInMillis() + 1000;
270                 break;
271             }
272
273             /* Still haven't recieved notification, log error */
274             ErrorF("Notifier timeout\n");
275             return FALSE;
276         }
277
278         if (status == 0xffffffff)
279             continue;
280         if (!status)
281             break;
282         if (status & 0xffff)
283             return FALSE;
284     }
285     return TRUE;
286 }
287
288 Bool NVDmaCreateContextObject(NVPtr pNv, int handle, int class, CARD32 flags,
289                               CARD32 dma_in, CARD32 dma_out, CARD32 dma_notifier)
290 {
291     drm_nouveau_object_init_t cto;
292     CARD32 nv_flags0 = 0, nv_flags1 = 0, nv_flags2 = 0;
293         int ret;
294     
295     if (pNv->Architecture >= NV_ARCH_40) {
296         if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND)
297             nv_flags0 |= 0x02080000;
298         else if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY)
299             nv_flags0 |= 0x02080000;
300         if (flags & NV_DMA_CONTEXT_FLAGS_CLIP_ENABLE)
301             nv_flags0 |= 0x00020000;
302 #if X_BYTE_ORDER == X_BIG_ENDIAN
303         if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
304             nv_flags1 |= 0x01000000;
305         nv_flags2 |= 0x01000000;
306 #else
307         if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
308             nv_flags1 |= 0x02000000;
309 #endif
310     } else {
311         if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND)
312             nv_flags0 |= 0x01008000;
313         else if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY)
314             nv_flags0 |= 0x01018000;
315         if (flags & NV_DMA_CONTEXT_FLAGS_CLIP_ENABLE)
316             nv_flags0 |= 0x00002000;
317 #if X_BYTE_ORDER == X_BIG_ENDIAN
318         nv_flags0 |= 0x00080000;
319         if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
320             nv_flags1 |= 0x00000001;
321 #else
322         if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
323             nv_flags1 |= 0x00000002;
324 #endif
325     }
326
327     cto.handle = handle;
328     cto.class  = class;
329     cto.flags0 = nv_flags0;
330     cto.flags1 = nv_flags1;
331     cto.flags2 = nv_flags2;
332     cto.dma0   = dma_in;
333     cto.dma1   = dma_out;
334     cto.dma_notifier = dma_notifier;
335     ret = drmCommandWrite(pNv->drm_fd, DRM_NOUVEAU_OBJECT_INIT, &cto, sizeof(cto));
336
337         return ret == 0;
338 }
339
340 static void NVInitDmaCB(ScrnInfoPtr pScrn)
341 {
342         NVPtr pNv = NVPTR(pScrn);
343         unsigned int cb_location;
344         int cb_size;
345         char *s;
346
347         /* I'm not bothering to check for failures here, the DRM will fall back
348          * on defaults if anything's wrong (ie. out of AGP, invalid sizes)
349          */
350 #ifndef __powerpc__
351         if (pNv->AGPScratch)
352                 cb_location = NOUVEAU_MEM_AGP;
353         else
354 #endif
355         cb_location = NOUVEAU_MEM_FB;
356         if((s = (char *)xf86GetOptValString(pNv->Options, OPTION_CMDBUF_LOCATION))) {
357                 if(!xf86NameCmp(s, "AGP"))
358                         cb_location = NOUVEAU_MEM_AGP;
359                 else if (!xf86NameCmp(s, "VRAM"))
360                         cb_location = NOUVEAU_MEM_FB;
361                 else
362                         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid value \"%s\" for CBLocation\n", s);
363         }
364         NVDRMSetParam(pNv, NOUVEAU_SETPARAM_CMDBUF_LOCATION, cb_location);
365
366         /* CBSize == size of space reserved for *all* FIFOs in MiB */
367         if (xf86GetOptValInteger(pNv->Options, OPTION_CMDBUF_SIZE, &cb_size))
368                 NVDRMSetParam(pNv, NOUVEAU_SETPARAM_CMDBUF_SIZE, (cb_size<<20));
369 }
370
371 Bool NVInitDma(ScrnInfoPtr pScrn)
372 {
373     NVPtr pNv = NVPTR(pScrn);
374
375         NVInitDmaCB(pScrn);
376
377     if (drmCommandWriteRead(pNv->drm_fd, DRM_NOUVEAU_FIFO_INIT, &pNv->fifo, sizeof(pNv->fifo)) != 0) {
378         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not initialise kernel module\n");
379         return FALSE;
380     }
381
382     if (drmMap(pNv->drm_fd, pNv->fifo.cmdbuf, pNv->fifo.cmdbuf_size, (drmAddressPtr)&pNv->dmaBase)) {
383         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to map DMA command buffer\n");
384         return FALSE;
385     }
386
387     if (drmMap(pNv->drm_fd, pNv->fifo.ctrl, pNv->fifo.ctrl_size, (drmAddressPtr)&pNv->FIFO)) {
388         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to map FIFO control regs\n");
389         return FALSE;
390     }
391
392     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using FIFO channel %d\n", pNv->fifo.channel);
393     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "  Control registers : %p (0x%08x)\n", pNv->FIFO, pNv->fifo.ctrl);
394     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "  DMA command buffer: %p (0x%08x)\n", pNv->dmaBase, pNv->fifo.cmdbuf);
395     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "  DMA cmdbuf length : %d KiB\n", pNv->fifo.cmdbuf_size / 1024);
396     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "  DMA base PUT      : 0x%08x\n", pNv->fifo.put_base);
397
398     NVDmaCreateDMAObject(pNv, NvDmaFB, NV_DMA_TARGET_VIDMEM, 0, pNv->VRAMPhysicalSize, NV_DMA_ACCES_RW);
399    
400         /* EXA + XAA + Xv */
401     NVDmaCreateContextObject (pNv, NvContextSurfaces,
402                               (pNv->Architecture >= NV_ARCH_10) ? NV10_CONTEXT_SURFACES_2D : NV4_SURFACE,
403                               NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND,
404                               NvDmaFB, NvDmaFB, 0);
405     NVDmaCreateContextObject (pNv, NvRectangle,
406                               NV4_GDI_RECTANGLE_TEXT, 
407                               NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND|NV_DMA_CONTEXT_FLAGS_MONO, 
408                               0, 0, 0);
409     if (pNv->Chipset<=CHIPSET_NV04)
410         NVDmaCreateContextObject (pNv, NvScaledImage,
411                                   NV_SCALED_IMAGE_FROM_MEMORY, 
412                                   NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY, 
413                                   NvDmaFB, NvDmaFB, 0);
414     else if (pNv->Architecture==NV_ARCH_04)
415         NVDmaCreateContextObject (pNv, NvScaledImage,
416                                   NV5_SCALED_IMAGE_FROM_MEMORY, 
417                                   NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY, 
418                                   NvDmaFB, NvDmaFB, 0);
419     else
420         NVDmaCreateContextObject (pNv, NvScaledImage,
421                                   NV10_SCALED_IMAGE_FROM_MEMORY, 
422                                   NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY, 
423                                   NvDmaFB, NvDmaFB, 0);
424         
425         /* EXA + XAA */
426     NVDmaCreateContextObject (pNv, NvRop,
427                               NV_ROP5_SOLID, 
428                               NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND,
429                               0, 0, 0);
430     NVDmaCreateContextObject (pNv, NvImagePattern,
431                               NV4_IMAGE_PATTERN, 
432                               NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND|NV_DMA_CONTEXT_FLAGS_MONO,
433                               0, 0, 0);
434     NVDmaCreateContextObject (pNv, NvImageBlit,
435                               pNv->WaitVSyncPossible ? NV12_IMAGE_BLIT : NV_IMAGE_BLIT,
436                               NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND, 
437                               NvDmaFB, NvDmaFB, 0);
438
439         if (!pNv->useEXA) {
440         NVDmaCreateContextObject (pNv, NvClipRectangle,
441                                   NV_IMAGE_BLACK_RECTANGLE, 
442                                   NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND,
443                                   0, 0, 0);
444         NVDmaCreateContextObject (pNv, NvSolidLine,
445                                   NV4_RENDER_SOLID_LIN, 
446                                   NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND|NV_DMA_CONTEXT_FLAGS_CLIP_ENABLE,
447                                   0, 0, 0);
448         }
449
450 #ifdef XF86DRI
451     if (pNv->useEXA && NVInitAGP(pScrn) && pNv->AGPScratch) {
452         pNv->Notifier0 = NVDmaCreateNotifier(pNv, NvDmaNotifier0);
453                 if (pNv->Notifier0) {
454                         NVDmaCreateDMAObject(pNv, NvDmaAGP, NV_DMA_TARGET_AGP,
455                                         pNv->AGPScratch->offset, pNv->AGPScratch->size, NV_DMA_ACCES_RW);
456
457                 NVDmaCreateContextObject (pNv, NvMemFormat,
458                                         NV_MEMORY_TO_MEMORY_FORMAT, 0,
459                                         0, 0, NvDmaNotifier0
460                                         );
461                 } else {
462                         /* FIXME */
463                         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to create DMA notifier - DMA transfers disabled\n");
464                         NVFreeMemory(pNv, pNv->AGPScratch);
465                         pNv->AGPScratch = NULL;
466                 }
467     }
468 #endif
469
470     return TRUE;
471 }