1 /*
2  * Copyright (C) 2007 Ben Skeggs.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial
15  * portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  */
26 
27 #include "drmP.h"
28 #include "drm.h"
29 #include "nouveau_drv.h"
30 #include "nouveau_dma.h"
31 
32 int
33 nouveau_dma_init(struct nouveau_channel *chan)
34 {
35 	struct drm_device *dev = chan->dev;
36 	struct drm_nouveau_private *dev_priv = dev->dev_private;
37 	struct nouveau_gpuobj *m2mf = NULL;
38 	int ret, i;
39 
40 	/* Create NV_MEMORY_TO_MEMORY_FORMAT for buffer moves */
41 	ret = nouveau_gpuobj_gr_new(chan, dev_priv->card_type < NV_50 ?
42 				    0x0039 : 0x5039, &m2mf);
43 	if (ret)
44 		return ret;
45 
46 	ret = nouveau_gpuobj_ref_add(dev, chan, NvM2MF, m2mf, NULL);
47 	if (ret)
48 		return ret;
49 
50 	/* NV_MEMORY_TO_MEMORY_FORMAT requires a notifier object */
51 	ret = nouveau_notifier_alloc(chan, NvNotify0, 32, &chan->m2mf_ntfy);
52 	if (ret)
53 		return ret;
54 
55 	/* Map push buffer */
56 	ret = nouveau_bo_map(chan->pushbuf_bo);
57 	if (ret)
58 		return ret;
59 
60 	/* Map M2MF notifier object - fbcon. */
61 	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
62 		ret = nouveau_bo_map(chan->notifier_bo);
63 		if (ret)
64 			return ret;
65 	}
66 
67 	/* Initialise DMA vars */
68 	chan->dma.max  = (chan->pushbuf_bo->bo.mem.size >> 2) - 2;
69 	chan->dma.put  = 0;
70 	chan->dma.cur  = chan->dma.put;
71 	chan->dma.free = chan->dma.max - chan->dma.cur;
72 
73 	/* Insert NOPS for NOUVEAU_DMA_SKIPS */
74 	ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS);
75 	if (ret)
76 		return ret;
77 
78 	for (i = 0; i < NOUVEAU_DMA_SKIPS; i++)
79 		OUT_RING(chan, 0);
80 
81 	/* Initialise NV_MEMORY_TO_MEMORY_FORMAT */
82 	ret = RING_SPACE(chan, 4);
83 	if (ret)
84 		return ret;
85 	BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NAME, 1);
86 	OUT_RING(chan, NvM2MF);
87 	BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1);
88 	OUT_RING(chan, NvNotify0);
89 
90 	/* Sit back and pray the channel works.. */
91 	FIRE_RING(chan);
92 
93 	return 0;
94 }
95 
96 void
97 OUT_RINGp(struct nouveau_channel *chan, const void *data, unsigned nr_dwords)
98 {
99 	bool is_iomem;
100 	u32 *mem = ttm_kmap_obj_virtual(&chan->pushbuf_bo->kmap, &is_iomem);
101 	mem = &mem[chan->dma.cur];
102 	if (is_iomem)
103 		memcpy_toio((void __force __iomem *)mem, data, nr_dwords * 4);
104 	else
105 		memcpy(mem, data, nr_dwords * 4);
106 	chan->dma.cur += nr_dwords;
107 }
108 
109 static inline bool
110 READ_GET(struct nouveau_channel *chan, uint32_t *get)
111 {
112 	uint32_t val;
113 
114 	val = nvchan_rd32(chan, chan->user_get);
115 	if (val < chan->pushbuf_base ||
116 	    val >= chan->pushbuf_base + chan->pushbuf_bo->bo.mem.size) {
117 		/* meaningless to dma_wait() except to know whether the
118 		 * GPU has stalled or not
119 		 */
120 		*get = val;
121 		return false;
122 	}
123 
124 	*get = (val - chan->pushbuf_base) >> 2;
125 	return true;
126 }
127 
128 int
129 nouveau_dma_wait(struct nouveau_channel *chan, int size)
130 {
131 	uint32_t get, prev_get = 0, cnt = 0;
132 	bool get_valid;
133 
134 	while (chan->dma.free < size) {
135 		/* reset counter as long as GET is still advancing, this is
136 		 * to avoid misdetecting a GPU lockup if the GPU happens to
137 		 * just be processing an operation that takes a long time
138 		 */
139 		get_valid = READ_GET(chan, &get);
140 		if (get != prev_get) {
141 			prev_get = get;
142 			cnt = 0;
143 		}
144 
145 		if ((++cnt & 0xff) == 0) {
146 			DRM_UDELAY(1);
147 			if (cnt > 100000)
148 				return -EBUSY;
149 		}
150 
151 		/* loop until we have a usable GET pointer.  the value
152 		 * we read from the GPU may be outside the main ring if
153 		 * PFIFO is processing a buffer called from the main ring,
154 		 * discard these values until something sensible is seen.
155 		 *
156 		 * the other case we discard GET is while the GPU is fetching
157 		 * from the SKIPS area, so the code below doesn't have to deal
158 		 * with some fun corner cases.
159 		 */
160 		if (!get_valid || get < NOUVEAU_DMA_SKIPS)
161 			continue;
162 
163 		if (get <= chan->dma.cur) {
164 			/* engine is fetching behind us, or is completely
165 			 * idle (GET == PUT) so we have free space up until
166 			 * the end of the push buffer
167 			 *
168 			 * we can only hit that path once per call due to
169 			 * looping back to the beginning of the push buffer,
170 			 * we'll hit the fetching-ahead-of-us path from that
171 			 * point on.
172 			 *
173 			 * the *one* exception to that rule is if we read
174 			 * GET==PUT, in which case the below conditional will
175 			 * always succeed and break us out of the wait loop.
176 			 */
177 			chan->dma.free = chan->dma.max - chan->dma.cur;
178 			if (chan->dma.free >= size)
179 				break;
180 
181 			/* not enough space left at the end of the push buffer,
182 			 * instruct the GPU to jump back to the start right
183 			 * after processing the currently pending commands.
184 			 */
185 			OUT_RING(chan, chan->pushbuf_base | 0x20000000);
186 			WRITE_PUT(NOUVEAU_DMA_SKIPS);
187 
188 			/* we're now submitting commands at the start of
189 			 * the push buffer.
190 			 */
191 			chan->dma.cur  =
192 			chan->dma.put  = NOUVEAU_DMA_SKIPS;
193 		}
194 
195 		/* engine fetching ahead of us, we have space up until the
196 		 * current GET pointer.  the "- 1" is to ensure there's
197 		 * space left to emit a jump back to the beginning of the
198 		 * push buffer if we require it.  we can never get GET == PUT
199 		 * here, so this is safe.
200 		 */
201 		chan->dma.free = get - chan->dma.cur - 1;
202 	}
203 
204 	return 0;
205 }
206 
207