More nv30 exa cleaning up.
[nouveau] / src / nv_dma.c
1 /*
2  * Copyright 2007 Ben Skeggs
3  * Copyright 2007 Stephane Marchesin
4  *
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:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
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
21  * SOFTWARE.
22  */
23
24 #include <errno.h>
25 #include "nv_include.h"
26 #include "nvreg.h"
27
28 void NVDmaKickoffNNN(NVPtr pNv)
29 {
30         if(pNv->dmaCurrent != pNv->dmaPut) {
31                 pNv->dmaPut = pNv->dmaCurrent;
32                 WRITE_PUT(pNv,  pNv->dmaPut);
33         }
34 }
35
36 void NVDmaKickoffCallback(NVPtr pNv)
37 {
38         FIRE_RING();
39         pNv->DMAKickoffCallback = NULL;
40 }
41
42 static uint32_t subchannels[8];
43
44 void NVDmaStartNNN(NVPtr pNv, uint32_t object, uint32_t tag, int size)
45 {
46         int subchannel=-1;
47         int i;
48         
49         /* XXX FIXME */
50         ScrnInfoPtr pScrn = xf86Screens[0];
51
52         /* look for a subchannel already bound to that object */
53         for(i=0;i<8;i++)
54         {
55                 if (subchannels[i]==object)
56                 {
57                         subchannel=i;
58                         break;
59                 }
60         }
61
62         /* add 2 for the potential subchannel binding */
63         if((pNv)->dmaFree <= (size + 2))
64                 WAIT_RING(size + 2);
65
66         if (subchannel==-1)
67         {
68                 /* bind the object */
69                 subchannel=rand()%8;
70                 subchannels[subchannel]=object;
71                 NVDEBUG("Bind object %x on subchannel %d\n", (object), (subchannel));
72                 OUT_RING  ((1<<18) | (subchannel<<13));
73                 OUT_RING  (object);
74                 pNv->dmaFree -= (2);
75         }
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); 
79 }
80
81
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
86  */
87 #define SKIPS  8
88
89 void NVDmaWaitNNN(ScrnInfoPtr pScrn, int size)
90 {
91         NVPtr pNv = NVPTR(pScrn);
92         int t_start;
93         int dmaGet;
94
95         size++;
96
97         t_start = GetTimeInMillis();
98         while(pNv->dmaFree < size) {
99                 dmaGet = READ_GET(pNv);
100
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);
108                                         do {
109                                                 if (GetTimeInMillis() - t_start > 2000)
110                                                         NVSync(pScrn);
111                                                 dmaGet = READ_GET(pNv);
112                                         } while(dmaGet <= SKIPS);
113                                 }
114                                 WRITE_PUT(pNv, SKIPS);
115                                 pNv->dmaCurrent = pNv->dmaPut = SKIPS;
116                                 pNv->dmaFree = dmaGet - (SKIPS + 1);
117                         }
118                 } else
119                         pNv->dmaFree = dmaGet - pNv->dmaCurrent - 1;
120
121                 if (GetTimeInMillis() - t_start > 2000)
122                         NVSync(pScrn);
123         }
124 }
125
126 static void NVDumpLockupInfo(NVPtr pNv)
127 {
128         int i,start;
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");
135 }
136
137 static void
138 NVLockedUp(ScrnInfoPtr pScrn)
139 {
140         NVPtr pNv = NVPTR(pScrn);
141
142         /* avoid re-entering FatalError on shutdown */
143         if (pNv->LockedUp)
144                 return;
145         pNv->LockedUp = TRUE;
146
147         NVDumpLockupInfo(pNv);
148
149         FatalError("DMA queue hang: dmaPut=%x, current=%x, status=%x\n",
150                    pNv->dmaPut, READ_GET(pNv), pNv->PGRAPH[NV_PGRAPH_STATUS/4]);
151 }
152
153 void NVSync(ScrnInfoPtr pScrn)
154 {
155         NVPtr pNv = NVPTR(pScrn);
156         int t_start, timeout = 2000;
157         int grobj = pNv->Architecture < NV_ARCH_50 ? NvImageBlit : Nv2D;
158
159         if(pNv->NoAccel)
160                 return;
161
162         if(pNv->DMAKickoffCallback)
163                 (*pNv->DMAKickoffCallback)(pNv);
164
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) {
170                 NVLockedUp(pScrn);
171                 return;
172         }
173
174         /* Wait for channel to go completely idle */
175         NVNotifierReset(pScrn, pNv->Notifier0);
176         BEGIN_RING(grobj, 0x104, 1);
177         OUT_RING  (0);
178         BEGIN_RING(grobj, 0x100, 1);
179         OUT_RING  (0);
180         FIRE_RING();
181         if (!NVNotifierWaitStatus(pScrn, pNv->Notifier0, 0, timeout))
182                 NVLockedUp(pScrn);
183 }
184
185 void NVResetGraphics(ScrnInfoPtr pScrn)
186 {
187         NVPtr pNv = NVPTR(pScrn);
188         int i;
189
190         pNv->dmaPut = pNv->dmaCurrent = READ_GET(pNv);
191         pNv->dmaMax = (pNv->fifo.cmdbuf_size >> 2) - 2;
192         pNv->dmaFree = pNv->dmaMax - pNv->dmaCurrent;
193
194         /* assert there's enough room for the skips */
195         if(pNv->dmaFree <= SKIPS)
196                 WAIT_RING(SKIPS); 
197         for (i=0; i<SKIPS; i++) {
198                 OUT_RING(0);
199                 pNv->dmaBase[i]=0;
200         }
201         pNv->dmaFree -= SKIPS;
202
203         for(i=0;i<8;i++)
204                 subchannels[i]=0;
205
206         NVAccelCommonInit(pScrn);
207 }
208
209 Bool NVDmaCreateContextObject(NVPtr pNv, int handle, int class)
210 {
211         struct drm_nouveau_grobj_alloc cto;
212         int ret;
213
214         cto.channel = pNv->fifo.channel;
215         cto.handle  = handle;
216         cto.class   = class;
217         ret = drmCommandWrite(pNv->drm_fd, DRM_NOUVEAU_GROBJ_ALLOC,
218                                            &cto, sizeof(cto));
219         return ret == 0;
220 }
221
222 static void NVInitDmaCB(ScrnInfoPtr pScrn)
223 {
224         NVPtr pNv = NVPTR(pScrn);
225         unsigned int cb_location;
226         int cb_size;
227         char *s;
228
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)
231          */
232 #ifndef __powerpc__
233         if (pNv->GARTScratch)
234                 cb_location = NOUVEAU_MEM_AGP | NOUVEAU_MEM_PCI_ACCEPTABLE;
235         else
236 #endif
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;
245                 else
246                         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid value \"%s\" for CBLocation\n", s);
247         }
248         NVDRMSetParam(pNv, NOUVEAU_SETPARAM_CMDBUF_LOCATION, cb_location);
249
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));
253 }
254
255 Bool NVInitDma(ScrnInfoPtr pScrn)
256 {
257         NVPtr pNv = NVPTR(pScrn);
258         int i, ret;
259
260         NVInitDmaCB(pScrn);
261
262         if (pNv->NoAccel)
263                 return TRUE;
264
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));
269         if (ret) {
270                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
271                            "Could not allocate GPU channel: %d\n", ret);
272                 return FALSE;
273         }
274
275         ret = drmMap(pNv->drm_fd, pNv->fifo.cmdbuf, pNv->fifo.cmdbuf_size,
276                      (drmAddressPtr)&pNv->dmaBase);
277         if (ret) {
278                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
279                            "Failed to map DMA push buffer: %d\n", ret);
280                 return FALSE;
281         }
282
283         ret = drmMap(pNv->drm_fd, pNv->fifo.ctrl, pNv->fifo.ctrl_size,
284                      (drmAddressPtr)&pNv->FIFO);
285         if (ret) {
286                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
287                            "Failed to map FIFO control regs: %d\n", ret);
288                 return FALSE;
289         }
290
291         ret = drmMap(pNv->drm_fd, pNv->fifo.notifier, pNv->fifo.notifier_size,
292                      (drmAddressPtr)&pNv->NotifierBlock);
293         if (ret) {
294                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
295                            "Failed to map notifier block: %d\n", ret);
296                 return FALSE;
297         }
298
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);
312
313         pNv->dmaPut = pNv->dmaCurrent = READ_GET(pNv);
314         pNv->dmaMax = (pNv->fifo.cmdbuf_size >> 2) - 2;
315         pNv->dmaFree = pNv->dmaMax - pNv->dmaCurrent;
316
317         for (i=0; i<SKIPS; i++)
318                 OUT_RING(0);
319         pNv->dmaFree -= SKIPS;
320
321         return TRUE;
322 }
323