2 * Copyright 2007 Ben Skeggs
3 * Copyright 2007 Stephane Marchesin
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
20 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 #include "nv_include.h"
28 void NVDmaKickoffNNN(NVPtr pNv)
30 if(pNv->dmaCurrent != pNv->dmaPut) {
31 pNv->dmaPut = pNv->dmaCurrent;
32 WRITE_PUT(pNv, pNv->dmaPut);
36 void NVDmaKickoffCallback(NVPtr pNv)
39 pNv->DMAKickoffCallback = NULL;
42 static uint32_t subchannels[8];
44 void NVDmaStartNNN(NVPtr pNv, uint32_t object, uint32_t tag, int size)
50 ScrnInfoPtr pScrn = xf86Screens[0];
52 /* look for a subchannel already bound to that object */
55 if (subchannels[i]==object)
62 /* add 2 for the potential subchannel binding */
63 if((pNv)->dmaFree <= (size + 2))
70 subchannels[subchannel]=object;
71 NVDEBUG("Bind object %x on subchannel %d\n", (object), (subchannel));
72 OUT_RING ((1<<18) | (subchannel<<13));
76 NVDEBUG("BEGIN_RING: subc=%d, cmd=%x, num=%d\n", (subchannel), (tag), (size));
77 OUT_RING (((size) << 18) | ((subchannel) << 13) | (tag));
78 pNv->dmaFree -= ((size) + 1);
82 /* There is a HW race condition with videoram command buffers.
83 * You can't jump to the location of your put offset. We write put
84 * at the jump offset + SKIPS dwords with noop padding in between
85 * to solve this problem
89 void NVDmaWaitNNN(ScrnInfoPtr pScrn, int size)
91 NVPtr pNv = NVPTR(pScrn);
97 t_start = GetTimeInMillis();
98 while(pNv->dmaFree < size) {
99 dmaGet = READ_GET(pNv);
101 if(pNv->dmaPut >= dmaGet) {
102 pNv->dmaFree = pNv->dmaMax - pNv->dmaCurrent;
103 if(pNv->dmaFree < size) {
104 OUT_RING ((0x20000000|pNv->fifo.put_base));
105 if(dmaGet <= SKIPS) {
106 if(pNv->dmaPut <= SKIPS) /* corner case - will be idle */
107 WRITE_PUT(pNv, SKIPS + 1);
109 if (GetTimeInMillis() - t_start > 2000)
111 dmaGet = READ_GET(pNv);
112 } while(dmaGet <= SKIPS);
114 WRITE_PUT(pNv, SKIPS);
115 pNv->dmaCurrent = pNv->dmaPut = SKIPS;
116 pNv->dmaFree = dmaGet - (SKIPS + 1);
119 pNv->dmaFree = dmaGet - pNv->dmaCurrent - 1;
121 if (GetTimeInMillis() - t_start > 2000)
126 static void NVDumpLockupInfo(NVPtr pNv)
129 start=READ_GET(pNv)-20;
130 if (start<0) start=0;
131 xf86DrvMsg(0, X_INFO, "Fifo dump (lockup 0x%04x,0x%04x):\n",READ_GET(pNv),pNv->dmaPut);
132 for(i=start;i<pNv->dmaPut+10;i++)
133 xf86DrvMsg(0, X_INFO, "[0x%04x] 0x%08x\n", i, pNv->dmaBase[i]);
134 xf86DrvMsg(0, X_INFO, "End of fifo dump\n");
138 NVLockedUp(ScrnInfoPtr pScrn)
140 NVPtr pNv = NVPTR(pScrn);
142 /* avoid re-entering FatalError on shutdown */
145 pNv->LockedUp = TRUE;
147 NVDumpLockupInfo(pNv);
149 FatalError("DMA queue hang: dmaPut=%x, current=%x, status=%x\n",
150 pNv->dmaPut, READ_GET(pNv), pNv->PGRAPH[NV_PGRAPH_STATUS/4]);
153 void NVSync(ScrnInfoPtr pScrn)
155 NVPtr pNv = NVPTR(pScrn);
156 int t_start, timeout = 2000;
157 int grobj = pNv->Architecture < NV_ARCH_50 ? NvImageBlit : Nv2D;
162 if(pNv->DMAKickoffCallback)
163 (*pNv->DMAKickoffCallback)(pNv);
165 /* Wait for entire FIFO to be processed */
166 t_start = GetTimeInMillis();
167 while((GetTimeInMillis() - t_start) < timeout &&
168 (READ_GET(pNv) != pNv->dmaPut));
169 if ((GetTimeInMillis() - t_start) >= timeout) {
174 /* Wait for channel to go completely idle */
175 NVNotifierReset(pScrn, pNv->Notifier0);
176 BEGIN_RING(grobj, 0x104, 1);
178 BEGIN_RING(grobj, 0x100, 1);
181 if (!NVNotifierWaitStatus(pScrn, pNv->Notifier0, 0, timeout))
185 void NVResetGraphics(ScrnInfoPtr pScrn)
187 NVPtr pNv = NVPTR(pScrn);
190 pNv->dmaPut = pNv->dmaCurrent = READ_GET(pNv);
191 pNv->dmaMax = (pNv->fifo.cmdbuf_size >> 2) - 2;
192 pNv->dmaFree = pNv->dmaMax - pNv->dmaCurrent;
194 /* assert there's enough room for the skips */
195 if(pNv->dmaFree <= SKIPS)
197 for (i=0; i<SKIPS; i++) {
201 pNv->dmaFree -= SKIPS;
206 NVAccelCommonInit(pScrn);
209 Bool NVDmaCreateContextObject(NVPtr pNv, int handle, int class)
211 struct drm_nouveau_grobj_alloc cto;
214 cto.channel = pNv->fifo.channel;
217 ret = drmCommandWrite(pNv->drm_fd, DRM_NOUVEAU_GROBJ_ALLOC,
222 static void NVInitDmaCB(ScrnInfoPtr pScrn)
224 NVPtr pNv = NVPTR(pScrn);
225 unsigned int cb_location;
229 /* I'm not bothering to check for failures here, the DRM will fall back
230 * on defaults if anything's wrong (ie. out of AGP, invalid sizes)
233 if (pNv->GARTScratch)
234 cb_location = NOUVEAU_MEM_AGP | NOUVEAU_MEM_PCI_ACCEPTABLE;
237 cb_location = NOUVEAU_MEM_FB;
238 if((s = (char *)xf86GetOptValString(pNv->Options, OPTION_CMDBUF_LOCATION))) {
239 if(!xf86NameCmp(s, "AGP"))
240 cb_location = NOUVEAU_MEM_AGP;
241 else if (!xf86NameCmp(s, "VRAM"))
242 cb_location = NOUVEAU_MEM_FB;
243 else if (!xf86NameCmp(s, "PCI"))
244 cb_location = NOUVEAU_MEM_PCI;
246 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid value \"%s\" for CBLocation\n", s);
248 NVDRMSetParam(pNv, NOUVEAU_SETPARAM_CMDBUF_LOCATION, cb_location);
250 /* CBSize == size of space reserved for *all* FIFOs in MiB */
251 if (xf86GetOptValInteger(pNv->Options, OPTION_CMDBUF_SIZE, &cb_size))
252 NVDRMSetParam(pNv, NOUVEAU_SETPARAM_CMDBUF_SIZE, (cb_size<<20));
255 Bool NVInitDma(ScrnInfoPtr pScrn)
257 NVPtr pNv = NVPTR(pScrn);
265 pNv->fifo.fb_ctxdma_handle = NvDmaFB;
266 pNv->fifo.tt_ctxdma_handle = NvDmaTT;
267 ret = drmCommandWriteRead(pNv->drm_fd, DRM_NOUVEAU_CHANNEL_ALLOC,
268 &pNv->fifo, sizeof(pNv->fifo));
270 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
271 "Could not allocate GPU channel: %d\n", ret);
275 ret = drmMap(pNv->drm_fd, pNv->fifo.cmdbuf, pNv->fifo.cmdbuf_size,
276 (drmAddressPtr)&pNv->dmaBase);
278 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
279 "Failed to map DMA push buffer: %d\n", ret);
283 ret = drmMap(pNv->drm_fd, pNv->fifo.ctrl, pNv->fifo.ctrl_size,
284 (drmAddressPtr)&pNv->FIFO);
286 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
287 "Failed to map FIFO control regs: %d\n", ret);
291 ret = drmMap(pNv->drm_fd, pNv->fifo.notifier, pNv->fifo.notifier_size,
292 (drmAddressPtr)&pNv->NotifierBlock);
294 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
295 "Failed to map notifier block: %d\n", ret);
299 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
300 "Using FIFO channel %d\n", pNv->fifo.channel);
301 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
302 " Control registers : %p (0x%08x)\n",
303 pNv->FIFO, pNv->fifo.ctrl);
304 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
305 " DMA command buffer: %p (0x%08x)\n",
306 pNv->dmaBase, pNv->fifo.cmdbuf);
307 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
308 " DMA cmdbuf length : %d KiB\n",
309 pNv->fifo.cmdbuf_size / 1024);
310 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
311 " DMA base PUT : 0x%08x\n", pNv->fifo.put_base);
313 pNv->dmaPut = pNv->dmaCurrent = READ_GET(pNv);
314 pNv->dmaMax = (pNv->fifo.cmdbuf_size >> 2) - 2;
315 pNv->dmaFree = pNv->dmaMax - pNv->dmaCurrent;
317 for (i=0; i<SKIPS; i++)
319 pNv->dmaFree -= SKIPS;