exa: FIRE_RING at the end of composite
[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 static void NVDumpLockupInfo(NVPtr pNv)
29 {
30         struct nouveau_channel_priv *chan = nouveau_channel(pNv->chan);
31         int i, start;
32
33         start = ((*chan->get - chan->dma.base) >> 2) - 20;
34         if (start < 0)
35                 start = 0;
36
37         xf86DrvMsg(0, X_INFO, "Fifo dump (lockup 0x%04x,0x%04x):\n",
38                    (*chan->get - chan->dma.base) >> 2, chan->dma.put);
39         for(i = start; i < chan->dma.put + 10; i++)
40                 xf86DrvMsg(0, X_INFO, "[0x%04x] 0x%08x\n", i, chan->pushbuf[i]);
41         xf86DrvMsg(0, X_INFO, "End of fifo dump\n");
42 }
43
44 static void
45 NVLockedUp(ScrnInfoPtr pScrn)
46 {
47         NVPtr pNv = NVPTR(pScrn);
48         struct nouveau_channel_priv *chan = nouveau_channel(pNv->chan);
49
50         /* avoid re-entering FatalError on shutdown */
51         if (pNv->LockedUp)
52                 return;
53         pNv->LockedUp = TRUE;
54
55         NVDumpLockupInfo(pNv);
56
57         FatalError("DMA queue hang: dmaPut=%x, current=%x, status=%x\n",
58                    chan->dma.put, (*chan->get - chan->dma.base) >> 2,
59                    pNv->PGRAPH[NV_PGRAPH_STATUS/4]);
60 }
61
62 static void
63 NVChannelHangNotify(struct nouveau_channel *chan)
64 {
65         ScrnInfoPtr pScrn = chan->user_private;
66         NVLockedUp(pScrn);
67 }
68
69 void NVSync(ScrnInfoPtr pScrn)
70 {
71         NVPtr pNv = NVPTR(pScrn);
72         struct nouveau_channel *chan = pNv->chan;
73         struct nouveau_channel_priv *nvchan = nouveau_channel(chan);
74         struct nouveau_grobj *gr = pNv->Nv2D ? pNv->Nv2D : pNv->NvImageBlit;
75         int t_start, timeout = 2000;
76
77         if (pNv->NoAccel)
78                 return;
79
80         /* Wait for entire FIFO to be processed */
81         t_start = GetTimeInMillis();
82         while((GetTimeInMillis() - t_start) < timeout &&
83               (((*nvchan->get - nvchan->dma.base) >> 2)!= nvchan->dma.put));
84         if ((GetTimeInMillis() - t_start) >= timeout) {
85                 NVLockedUp(pScrn);
86                 return;
87         }
88
89         /* Wait for nvchannel to go completely idle */
90         nouveau_notifier_reset(pNv->notify0, 0);
91         BEGIN_RING(chan, gr, 0x104, 1);
92         OUT_RING  (chan, 0);
93         BEGIN_RING(chan, gr, 0x100, 1);
94         OUT_RING  (chan, 0);
95         FIRE_RING (chan);
96         if (nouveau_notifier_wait_status(pNv->notify0, 0,
97                                          NV_NOTIFY_STATE_STATUS_COMPLETED,
98                                          timeout))
99                 NVLockedUp(pScrn);
100 }
101
102 static void NVInitDmaCB(ScrnInfoPtr pScrn)
103 {
104         NVPtr pNv = NVPTR(pScrn);
105         unsigned int cb_location;
106         int cb_size;
107         char *s;
108
109         /* I'm not bothering to check for failures here, the DRM will fall back
110          * on defaults if anything's wrong (ie. out of AGP, invalid sizes)
111          */
112         /* WARNING: on ppc at least, putting cmdbuf in MEM_FB results in DMA hangs */
113         if (pNv->GART)
114                 cb_location = NOUVEAU_MEM_AGP | NOUVEAU_MEM_PCI_ACCEPTABLE;
115         else
116                 cb_location = NOUVEAU_MEM_FB;
117         
118         if((s = (char *)xf86GetOptValString(pNv->Options, OPTION_CMDBUF_LOCATION))) {
119                 if(!xf86NameCmp(s, "AGP"))
120                         cb_location = NOUVEAU_MEM_AGP;
121                 else if (!xf86NameCmp(s, "VRAM"))
122                         cb_location = NOUVEAU_MEM_FB;
123                 else if (!xf86NameCmp(s, "PCI"))
124                         cb_location = NOUVEAU_MEM_PCI;
125                 else
126                         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid value \"%s\" for CBLocation\n", s);
127         }
128         nouveau_device_set_param(pNv->dev, NOUVEAU_SETPARAM_CMDBUF_LOCATION,
129                                  cb_location);
130
131         /* CBSize == size of space reserved for *all* FIFOs in MiB */
132         if (xf86GetOptValInteger(pNv->Options, OPTION_CMDBUF_SIZE, &cb_size))
133                 nouveau_device_set_param(pNv->dev, NOUVEAU_SETPARAM_CMDBUF_SIZE,
134                                          (cb_size << 20));
135 }
136
137 Bool
138 NVInitDma(ScrnInfoPtr pScrn)
139 {
140         NVPtr pNv = NVPTR(pScrn);
141         int ret;
142
143         NVInitDmaCB(pScrn);
144
145         ret = nouveau_channel_alloc(pNv->dev, NvDmaFB, NvDmaTT, &pNv->chan);
146         if (ret) {
147                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
148                            "Error creating GPU channel: %d\n", ret);
149                 return FALSE;
150         }
151         pNv->chan->user_private = pScrn;
152         pNv->chan->hang_notify = NVChannelHangNotify;
153
154         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
155                    "Opened GPU channel %d\n", pNv->chan->id);
156
157         return TRUE;
158 }
159