2 #include "nv_include.h"
5 void NVDmaKickoff(NVPtr pNv)
7 if(pNv->dmaCurrent != pNv->dmaPut) {
8 pNv->dmaPut = pNv->dmaCurrent;
9 WRITE_PUT(pNv, pNv->dmaPut);
13 void NVDmaKickoffCallback(NVPtr pNv)
16 pNv->DMAKickoffCallback = NULL;
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 */
25 void NVDmaWait (NVPtr pNv, int size)
32 t_start = GetTimeInMillis();
33 while(pNv->dmaFree < size) {
34 dmaGet = READ_GET(pNv);
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));
41 if(pNv->dmaPut <= SKIPS) /* corner case - will be idle */
42 WRITE_PUT(pNv, SKIPS + 1);
44 if (GetTimeInMillis() - t_start > 2000)
46 dmaGet = READ_GET(pNv);
47 } while(dmaGet <= SKIPS);
49 WRITE_PUT(pNv, SKIPS);
50 pNv->dmaCurrent = pNv->dmaPut = SKIPS;
51 pNv->dmaFree = dmaGet - (SKIPS + 1);
54 pNv->dmaFree = dmaGet - pNv->dmaCurrent - 1;
56 if (GetTimeInMillis() - t_start > 2000)
61 static void NVDumpLockupInfo(NVPtr pNv)
64 start=READ_GET(pNv)-10;
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");
72 void NVDoSync(NVPtr pNv)
74 int t_start, timeout = 2000;
76 if(pNv->DMAKickoffCallback)
77 (*pNv->DMAKickoffCallback)(pNv);
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]);
83 if ((GetTimeInMillis() - t_start) >= timeout) {
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]);
93 void NVSync(ScrnInfoPtr pScrn)
95 NVPtr pNv = NVPTR(pScrn);
99 void NVResetGraphics(ScrnInfoPtr pScrn)
101 NVPtr pNv = NVPTR(pScrn);
102 CARD32 surfaceFormat, patternFormat, rectFormat, lineFormat;
105 if(pNv->NoAccel) return;
107 pitch = pNv->CurrentLayout.displayWidth *
108 (pNv->CurrentLayout.bitsPerPixel >> 3);
110 pNv->dmaPut = pNv->dmaCurrent = READ_GET(pNv);
111 pNv->dmaMax = (pNv->fifo.cmdbuf_size >> 2) - 1;
112 pNv->dmaFree = pNv->dmaMax - pNv->dmaCurrent;
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++)
122 pNv->dmaFree -= SKIPS;
125 NVDmaSetObjectOnSubchannel(pNv, NvSubContextSurfaces, NvContextSurfaces);
126 NVDmaSetObjectOnSubchannel(pNv, NvSubRectangle , NvRectangle );
127 NVDmaSetObjectOnSubchannel(pNv, NvSubScaledImage , NvScaledImage );
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 );
139 switch(pNv->CurrentLayout.depth) {
141 surfaceFormat = SURFACE_FORMAT_X8R8G8B8;
142 patternFormat = PATTERN_FORMAT_DEPTH24;
143 rectFormat = RECT_FORMAT_DEPTH24;
144 lineFormat = LINE_FORMAT_DEPTH24;
148 surfaceFormat = SURFACE_FORMAT_R5G6B5;
149 patternFormat = PATTERN_FORMAT_DEPTH16;
150 rectFormat = RECT_FORMAT_DEPTH16;
151 lineFormat = LINE_FORMAT_DEPTH16;
154 surfaceFormat = SURFACE_FORMAT_Y8;
155 patternFormat = PATTERN_FORMAT_DEPTH8;
156 rectFormat = RECT_FORMAT_DEPTH8;
157 lineFormat = LINE_FORMAT_DEPTH8;
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));
167 NVDmaStart(pNv, NvSubImagePattern, PATTERN_FORMAT, 1);
168 NVDmaNext (pNv, patternFormat);
170 NVDmaStart(pNv, NvSubRectangle, RECT_FORMAT, 1);
171 NVDmaNext (pNv, rectFormat);
174 NVDmaStart(pNv, NvSubSolidLine, LINE_FORMAT, 1);
175 NVDmaNext (pNv, lineFormat);
178 pNv->currentRop = ~0; /* set to something invalid */
179 NVSetRopSolid(pScrn, GXcopy, ~0);
181 pNv->M2MFDirection = -1; /* invalid */
182 /*NVDmaKickoff(pNv);*/
185 Bool NVDmaCreateDMAObject(NVPtr pNv, int handle, int target, CARD32 base_address, CARD32 size, int access)
187 drm_nouveau_dma_object_init_t dma;
194 dma.offset = base_address;
195 ret = drmCommandWrite(pNv->drm_fd, DRM_NOUVEAU_DMA_OBJECT_INIT, &dma, sizeof(dma));
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.
205 NVAllocRec *NVDmaCreateNotifier(NVPtr pNv, int handle)
207 NVAllocRec *notifier = NULL;
210 notifier = NVAllocateMemory(pNv, NOUVEAU_MEM_AGP, 256);
213 notifier = NVAllocateMemory(pNv, NOUVEAU_MEM_FB, 256);
215 if (!NVDmaCreateDMAObject(pNv, handle,
216 notifier->type & NOUVEAU_MEM_AGP ?
217 NV_DMA_TARGET_AGP : NV_DMA_TARGET_VIDMEM,
221 NVFreeMemory(pNv, notifier);
229 How do we wait for DMA completion (by notifiers) ?
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.
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
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.
248 Bool NVDmaWaitForNotifier(NVPtr pNv, void *notifier)
250 int t_start, timeout = 0;
253 n = (volatile CARD32 *)notifier;
254 NVDEBUG("NVDmaWaitForNotifier @%p", n);
255 t_start = GetTimeInMillis();
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));
264 if (GetTimeInMillis() - t_start >= 2000) {
265 /* We've timed out, call NVSync() to detect lockups */
266 if (timeout++ == 0) {
268 /* If we're still here, wait another second for notifier.. */
269 t_start = GetTimeInMillis() + 1000;
273 /* Still haven't recieved notification, log error */
274 ErrorF("Notifier timeout\n");
278 if (status == 0xffffffff)
288 Bool NVDmaCreateContextObject(NVPtr pNv, int handle, int class, CARD32 flags,
289 CARD32 dma_in, CARD32 dma_out, CARD32 dma_notifier)
291 drm_nouveau_object_init_t cto;
292 CARD32 nv_flags0 = 0, nv_flags1 = 0, nv_flags2 = 0;
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;
307 if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
308 nv_flags1 |= 0x02000000;
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;
322 if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
323 nv_flags1 |= 0x00000002;
329 cto.flags0 = nv_flags0;
330 cto.flags1 = nv_flags1;
331 cto.flags2 = nv_flags2;
334 cto.dma_notifier = dma_notifier;
335 ret = drmCommandWrite(pNv->drm_fd, DRM_NOUVEAU_OBJECT_INIT, &cto, sizeof(cto));
340 static void NVInitDmaCB(ScrnInfoPtr pScrn)
342 NVPtr pNv = NVPTR(pScrn);
343 unsigned int cb_location;
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)
352 cb_location = NOUVEAU_MEM_AGP;
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;
362 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid value \"%s\" for CBLocation\n", s);
364 NVDRMSetParam(pNv, NOUVEAU_SETPARAM_CMDBUF_LOCATION, cb_location);
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));
371 Bool NVInitDma(ScrnInfoPtr pScrn)
373 NVPtr pNv = NVPTR(pScrn);
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");
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");
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");
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);
398 NVDmaCreateDMAObject(pNv, NvDmaFB, NV_DMA_TARGET_VIDMEM, 0, pNv->VRAMPhysicalSize, NV_DMA_ACCES_RW);
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,
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);
420 NVDmaCreateContextObject (pNv, NvScaledImage,
421 NV10_SCALED_IMAGE_FROM_MEMORY,
422 NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY,
423 NvDmaFB, NvDmaFB, 0);
426 NVDmaCreateContextObject (pNv, NvRop,
428 NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND,
430 NVDmaCreateContextObject (pNv, NvImagePattern,
432 NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND|NV_DMA_CONTEXT_FLAGS_MONO,
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);
440 NVDmaCreateContextObject (pNv, NvClipRectangle,
441 NV_IMAGE_BLACK_RECTANGLE,
442 NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND,
444 NVDmaCreateContextObject (pNv, NvSolidLine,
445 NV4_RENDER_SOLID_LIN,
446 NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND|NV_DMA_CONTEXT_FLAGS_CLIP_ENABLE,
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);
457 NVDmaCreateContextObject (pNv, NvMemFormat,
458 NV_MEMORY_TO_MEMORY_FORMAT, 0,
463 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to create DMA notifier - DMA transfers disabled\n");
464 NVFreeMemory(pNv, pNv->AGPScratch);
465 pNv->AGPScratch = NULL;