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