randr12: common tmds access functions
[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_priv *chan = nouveau_channel(pNv->chan);
73         int t_start, timeout = 2000;
74
75         if (pNv->NoAccel)
76                 return;
77
78         /* Wait for entire FIFO to be processed */
79         t_start = GetTimeInMillis();
80         while((GetTimeInMillis() - t_start) < timeout &&
81               (((*chan->get - chan->dma.base) >> 2)!= chan->dma.put));
82         if ((GetTimeInMillis() - t_start) >= timeout) {
83                 NVLockedUp(pScrn);
84                 return;
85         }
86
87         /* Wait for channel to go completely idle */
88         nouveau_notifier_reset(pNv->notify0, 0);
89         if (pNv->Architecture < NV_ARCH_50) {
90                 BEGIN_RING(NvImageBlit, 0x104, 1);
91                 OUT_RING  (0);
92                 BEGIN_RING(NvImageBlit, 0x100, 1);
93                 OUT_RING  (0);
94         } else {
95                 BEGIN_RING(Nv2D, 0x104, 1);
96                 OUT_RING  (0);
97                 BEGIN_RING(Nv2D, 0x100, 1);
98                 OUT_RING  (0);
99         }
100         FIRE_RING();
101         if (nouveau_notifier_wait_status(pNv->notify0, 0,
102                                          NV_NOTIFY_STATE_STATUS_COMPLETED,
103                                          timeout))
104                 NVLockedUp(pScrn);
105 }
106
107 static void NVInitDmaCB(ScrnInfoPtr pScrn)
108 {
109         NVPtr pNv = NVPTR(pScrn);
110         unsigned int cb_location;
111         int cb_size;
112         char *s;
113
114         /* I'm not bothering to check for failures here, the DRM will fall back
115          * on defaults if anything's wrong (ie. out of AGP, invalid sizes)
116          */
117         /* WARNING: on ppc at least, putting cmdbuf in MEM_FB results in DMA hangs */
118         if (pNv->GART)
119                 cb_location = NOUVEAU_MEM_AGP | NOUVEAU_MEM_PCI_ACCEPTABLE;
120         else
121                 cb_location = NOUVEAU_MEM_FB;
122         
123         if((s = (char *)xf86GetOptValString(pNv->Options, OPTION_CMDBUF_LOCATION))) {
124                 if(!xf86NameCmp(s, "AGP"))
125                         cb_location = NOUVEAU_MEM_AGP;
126                 else if (!xf86NameCmp(s, "VRAM"))
127                         cb_location = NOUVEAU_MEM_FB;
128                 else if (!xf86NameCmp(s, "PCI"))
129                         cb_location = NOUVEAU_MEM_PCI;
130                 else
131                         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid value \"%s\" for CBLocation\n", s);
132         }
133         nouveau_device_set_param(pNv->dev, NOUVEAU_SETPARAM_CMDBUF_LOCATION,
134                                  cb_location);
135
136         /* CBSize == size of space reserved for *all* FIFOs in MiB */
137         if (xf86GetOptValInteger(pNv->Options, OPTION_CMDBUF_SIZE, &cb_size))
138                 nouveau_device_set_param(pNv->dev, NOUVEAU_SETPARAM_CMDBUF_SIZE,
139                                          (cb_size << 20));
140 }
141
142 Bool
143 NVInitDma(ScrnInfoPtr pScrn)
144 {
145         NVPtr pNv = NVPTR(pScrn);
146         int ret;
147
148         NVInitDmaCB(pScrn);
149
150         ret = nouveau_channel_alloc(pNv->dev, NvDmaFB, NvDmaTT, &pNv->chan);
151         if (ret) {
152                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
153                            "Error creating GPU channel: %d\n", ret);
154                 return FALSE;
155         }
156         pNv->chan->user_private = pScrn;
157         pNv->chan->hang_notify = NVChannelHangNotify;
158
159         xf86DrvMsg(pScrn->scrnIndex, X_INFO,
160                    "Opened GPU channel %d\n", pNv->chan->id);
161
162         return TRUE;
163 }
164