2 #include "nv_include.h"
5 void NVDmaCreateDMAObject(NVPtr pNv, int handle, int target, CARD32 base_address, CARD32 size, int access)
7 drm_nouveau_dma_object_init_t dma;
13 dma.offset = base_address;
14 drmCommandWrite(pNv->drm_fd, DRM_NOUVEAU_DMA_OBJECT_INIT, &dma, sizeof(dma));
18 A DMA notifier is a DMA object that references a small (32 byte it
19 seems, we use 256 for saftey) memory area that will be used by the HW to give feedback
20 about a DMA operation.
22 void *NVDmaCreateNotifier(NVPtr pNv, int handle)
24 uint64_t notifier_base;
25 void *notifier = NULL;
29 if (pNv->AGPScratch) {
30 drm_nouveau_mem_alloc_t alloc;
32 alloc.flags = NOUVEAU_MEM_AGP|NOUVEAU_MEM_MAPPED;
35 alloc.region_offset = ¬ifier_base;
36 if (!(drmCommandWriteRead(pNv->drm_fd, DRM_NOUVEAU_MEM_ALLOC,
37 &alloc, sizeof(alloc)))) {
38 if (!drmMap(pNv->drm_fd, notifier_base, alloc.size, ¬ifier))
39 target = NV_DMA_TARGET_AGP;
44 if (!target) /* FIXME: try a FB notifier when we can alloc the memory */
47 NVDmaCreateDMAObject(pNv, handle, target, notifier_base, 256, NV_DMA_ACCES_RW);
52 How do we wait for DMA completion (by notifiers) ?
54 Either repeatedly read the notifier address and wait until it changes,
55 or enable a 'wakeup' interrupt by writing NOTIFY_WRITE_LE_AWAKEN into
56 the 'notify' field of the object in the channel. My guess is that
57 this causes an interrupt in PGRAPH/NOTIFY as soon as the transfer is
58 completed. Clients probably can use poll on the nv* devices to get this
59 event. All this is a guess. I don't know any details, and I have not
60 tested is. Also, I have no idea how the 'nvdriver' reacts if it gets
61 notify events that are not registered.
63 Writing NV_NOTIFY_WRITE_LE_AWAKEN into the 'Notify' field of an object
64 in a channel really causes an interrupt in the PGRAPH engine. Thus
65 we can determine whether a DMA transfer has finished in the interrupt
68 We can't use interrupts in user land, so we do the simple polling approach.
69 The method returns FALSE in case of an error.
71 Bool NVDmaWaitForNotifier(NVPtr pNv, void *notifier)
73 int t_start, timeout = 0;
76 n = (volatile CARD32 *)notifier;
77 NVDEBUG("NVDmaWaitForNotifier @%p", n);
78 t_start = GetTimeInMillis();
84 NVDEBUG("status: n[0]=%x, n[1]=%x, n[2]=%x, n[3]=%x\n", a, b, c, status);
85 NVDEBUG("status: GET: 0x%08x\n", READ_GET(pNv));
87 if (GetTimeInMillis() - t_start >= 2000) {
88 /* We've timed out, call NVSync() to detect lockups */
91 /* If we're still here, wait another second for notifier.. */
92 t_start = GetTimeInMillis() + 1000;
96 /* Still haven't recieved notification, log error */
97 ErrorF("Notifier timeout\n");
101 if (status == 0xffffffff)
111 void NVDmaCreateContextObject(NVPtr pNv, int handle, int class, CARD32 flags,
112 CARD32 dma_in, CARD32 dma_out, CARD32 dma_notifier)
114 drm_nouveau_object_init_t cto;
115 CARD32 nv_flags0 = 0, nv_flags1 = 0, nv_flags2 = 0;
117 if (pNv->Architecture >= NV_ARCH_40) {
118 if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND)
119 nv_flags0 |= 0x02080000;
120 else if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY)
121 nv_flags0 |= 0x02080000;
122 if (flags & NV_DMA_CONTEXT_FLAGS_CLIP_ENABLE)
123 nv_flags0 |= 0x00020000;
124 #if X_BYTE_ORDER == X_BIG_ENDIAN
125 if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
126 nv_flags1 |= 0x01000000;
127 nv_flags2 |= 0x01000000;
129 if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
130 nv_flags1 |= 0x02000000;
133 if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND)
134 nv_flags0 |= 0x01008000;
135 else if (flags & NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY)
136 nv_flags0 |= 0x01018000;
137 if (flags & NV_DMA_CONTEXT_FLAGS_CLIP_ENABLE)
138 nv_flags0 |= 0x00002000;
139 #if X_BYTE_ORDER == X_BIG_ENDIAN
140 nv_flags0 |= 0x00080000;
141 if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
142 nv_flags1 |= 0x00000001;
144 if (flags & NV_DMA_CONTEXT_FLAGS_MONO)
145 nv_flags1 |= 0x00000002;
151 cto.flags0 = nv_flags0;
152 cto.flags1 = nv_flags1;
153 cto.flags2 = nv_flags2;
156 cto.dma_notifier = dma_notifier;
157 drmCommandWrite(pNv->drm_fd, DRM_NOUVEAU_OBJECT_INIT, &cto, sizeof(cto));
160 Bool NVInitDma(ScrnInfoPtr pScrn)
162 NVPtr pNv = NVPTR(pScrn);
163 drm_nouveau_fifo_init_t fifo;
165 if (!NVDRIScreenInit(pScrn))
168 if (drmCommandWriteRead(pNv->drm_fd, DRM_NOUVEAU_FIFO_INIT, &pNv->fifo, sizeof(pNv->fifo)) != 0) {
169 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Could not initialise kernel module\n");
173 if (drmMap(pNv->drm_fd, pNv->fifo.cmdbuf, pNv->fifo.cmdbuf_size, (drmAddressPtr)&pNv->dmaBase)) {
174 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to map DMA command buffer\n");
178 if (drmMap(pNv->drm_fd, pNv->fifo.ctrl, pNv->fifo.ctrl_size, (drmAddressPtr)&pNv->FIFO)) {
179 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to map FIFO control regs\n");
183 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using FIFO channel %d\n", pNv->fifo.channel);
184 xf86DrvMsg(pScrn->scrnIndex, X_INFO, " Control registers : %p (0x%08x)\n", pNv->FIFO, pNv->fifo.ctrl);
185 xf86DrvMsg(pScrn->scrnIndex, X_INFO, " DMA command buffer: %p (0x%08x)\n", pNv->dmaBase, pNv->fifo.cmdbuf);
186 xf86DrvMsg(pScrn->scrnIndex, X_INFO, " DMA cmdbuf length : %d KiB\n", pNv->fifo.cmdbuf_size / 1024);
187 xf86DrvMsg(pScrn->scrnIndex, X_INFO, " DMA base PUT : 0x%08x\n", pNv->fifo.put_base);
189 NVDmaCreateDMAObject(pNv, NvDmaFB, NV_DMA_TARGET_VIDMEM, 0, pNv->VRAMPhysicalSize, NV_DMA_ACCES_RW);
191 NVDmaCreateContextObject (pNv, NvContextSurfaces,
192 (pNv->Architecture >= NV_ARCH_10) ? NV10_CONTEXT_SURFACES_2D : NV4_SURFACE,
193 NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND,
194 NvDmaFB, NvDmaFB, 0);
195 NVDmaCreateContextObject (pNv, NvRop,
197 NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND,
199 NVDmaCreateContextObject (pNv, NvImagePattern,
201 NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND|NV_DMA_CONTEXT_FLAGS_MONO,
203 NVDmaCreateContextObject (pNv, NvClipRectangle,
204 NV_IMAGE_BLACK_RECTANGLE,
205 NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND,
207 NVDmaCreateContextObject (pNv, NvSolidLine,
208 NV4_RENDER_SOLID_LIN,
209 NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND|NV_DMA_CONTEXT_FLAGS_CLIP_ENABLE,
211 NVDmaCreateContextObject (pNv, NvImageBlit,
212 pNv->WaitVSyncPossible ? NV12_IMAGE_BLIT : NV_IMAGE_BLIT,
213 NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND,
214 NvDmaFB, NvDmaFB, 0);
215 NVDmaCreateContextObject (pNv, NvRectangle,
216 NV4_GDI_RECTANGLE_TEXT,
217 NV_DMA_CONTEXT_FLAGS_PATCH_ROP_AND|NV_DMA_CONTEXT_FLAGS_MONO,
219 if (pNv->Chipset==CHIPSET_NV04)
220 NVDmaCreateContextObject (pNv, NvScaledImage,
221 NV_SCALED_IMAGE_FROM_MEMORY,
222 NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY,
223 NvDmaFB, NvDmaFB, 0);
224 else if (pNv->Architecture==NV_ARCH_04)
225 NVDmaCreateContextObject (pNv, NvScaledImage,
226 NV5_SCALED_IMAGE_FROM_MEMORY,
227 NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY,
228 NvDmaFB, NvDmaFB, 0);
230 NVDmaCreateContextObject (pNv, NvScaledImage,
231 NV10_SCALED_IMAGE_FROM_MEMORY,
232 NV_DMA_CONTEXT_FLAGS_PATCH_SRCCOPY,
233 NvDmaFB, NvDmaFB, 0);
236 if (NVInitAGP(pScrn) && pNv->AGPScratch) {
237 pNv->Notifier0 = NVDmaCreateNotifier(pNv, NvDmaNotifier0);
238 if (pNv->Notifier0) {
239 NVDmaCreateDMAObject(pNv, NvDmaAGP, NV_DMA_TARGET_AGP,
240 pNv->AGPScratch->offset, pNv->AGPScratch->size, NV_DMA_ACCES_RW);
242 NVDmaCreateContextObject (pNv, NvGraphicsToAGP,
243 NV_MEMORY_TO_MEMORY_FORMAT, 0,
244 NvDmaFB, NvDmaAGP, NvDmaNotifier0
247 NVDmaCreateContextObject (pNv, NvAGPToGraphics,
248 NV_MEMORY_TO_MEMORY_FORMAT, 0,
249 NvDmaAGP, NvDmaFB, NvDmaNotifier0
253 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to create DMA notifier - DMA transfers disabled\n");
254 NVFreeMemory(pNv, pNv->AGPScratch);
255 pNv->AGPScratch = NULL;