1 /* mach64_state.c -- State support for mach64 (Rage Pro) driver -*- linux-c -*-
2  * Created: Sun Dec 03 19:20:26 2000 by gareth@valinux.com
3  */
4 /*-
5  * Copyright 2000 Gareth Hughes
6  * Copyright 2002-2003 Leif Delgass
7  * All Rights Reserved.
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a
10  * copy of this software and associated documentation files (the "Software"),
11  * to deal in the Software without restriction, including without limitation
12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  * and/or sell copies of the Software, and to permit persons to whom the
14  * Software is furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice (including the next
17  * paragraph) shall be included in all copies or substantial portions of the
18  * Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23  * THE COPYRIGHT OWNER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *
27  * Authors:
28  *    Gareth Hughes <gareth@valinux.com>
29  *    Leif Delgass <ldelgass@retinalburn.net>
30  *    José Fonseca <j_r_fonseca@yahoo.co.uk>
31  */
32 
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD: stable/10/sys/dev/drm/mach64_state.c 198332 2009-10-21 15:54:45Z brueffer $");
35 
36 #include "dev/drm/drmP.h"
37 #include "dev/drm/drm.h"
38 #include "dev/drm/mach64_drm.h"
39 #include "dev/drm/mach64_drv.h"
40 
41 /* Interface history:
42  *
43  * 1.0 - Initial mach64 DRM
44  *
45  */
46 struct drm_ioctl_desc mach64_ioctls[] = {
47 	DRM_IOCTL_DEF(DRM_MACH64_INIT, mach64_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
48 	DRM_IOCTL_DEF(DRM_MACH64_CLEAR, mach64_dma_clear, DRM_AUTH),
49 	DRM_IOCTL_DEF(DRM_MACH64_SWAP, mach64_dma_swap, DRM_AUTH),
50 	DRM_IOCTL_DEF(DRM_MACH64_IDLE, mach64_dma_idle, DRM_AUTH),
51 	DRM_IOCTL_DEF(DRM_MACH64_RESET, mach64_engine_reset, DRM_AUTH),
52 	DRM_IOCTL_DEF(DRM_MACH64_VERTEX, mach64_dma_vertex, DRM_AUTH),
53 	DRM_IOCTL_DEF(DRM_MACH64_BLIT, mach64_dma_blit, DRM_AUTH),
54 	DRM_IOCTL_DEF(DRM_MACH64_FLUSH, mach64_dma_flush, DRM_AUTH),
55 	DRM_IOCTL_DEF(DRM_MACH64_GETPARAM, mach64_get_param, DRM_AUTH),
56 };
57 
58 int mach64_max_ioctl = DRM_ARRAY_SIZE(mach64_ioctls);
59 
60 /* ================================================================
61  * DMA hardware state programming functions
62  */
63 
mach64_print_dirty(const char * msg,unsigned int flags)64 static void mach64_print_dirty(const char *msg, unsigned int flags)
65 {
66 	DRM_DEBUG("%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s\n",
67 		  msg,
68 		  flags,
69 		  (flags & MACH64_UPLOAD_DST_OFF_PITCH) ? "dst_off_pitch, " :
70 		  "",
71 		  (flags & MACH64_UPLOAD_Z_ALPHA_CNTL) ? "z_alpha_cntl, " : "",
72 		  (flags & MACH64_UPLOAD_SCALE_3D_CNTL) ? "scale_3d_cntl, " :
73 		  "", (flags & MACH64_UPLOAD_DP_FOG_CLR) ? "dp_fog_clr, " : "",
74 		  (flags & MACH64_UPLOAD_DP_WRITE_MASK) ? "dp_write_mask, " :
75 		  "",
76 		  (flags & MACH64_UPLOAD_DP_PIX_WIDTH) ? "dp_pix_width, " : "",
77 		  (flags & MACH64_UPLOAD_SETUP_CNTL) ? "setup_cntl, " : "",
78 		  (flags & MACH64_UPLOAD_MISC) ? "misc, " : "",
79 		  (flags & MACH64_UPLOAD_TEXTURE) ? "texture, " : "",
80 		  (flags & MACH64_UPLOAD_TEX0IMAGE) ? "tex0 image, " : "",
81 		  (flags & MACH64_UPLOAD_TEX1IMAGE) ? "tex1 image, " : "",
82 		  (flags & MACH64_UPLOAD_CLIPRECTS) ? "cliprects, " : "");
83 }
84 
85 /* Mach64 doesn't have hardware cliprects, just one hardware scissor,
86  * so the GL scissor is intersected with each cliprect here
87  */
88 /* This function returns 0 on success, 1 for no intersection, and
89  * negative for an error
90  */
mach64_emit_cliprect(struct drm_file * file_priv,drm_mach64_private_t * dev_priv,struct drm_clip_rect * box)91 static int mach64_emit_cliprect(struct drm_file *file_priv,
92 				drm_mach64_private_t * dev_priv,
93 				struct drm_clip_rect * box)
94 {
95 	u32 sc_left_right, sc_top_bottom;
96 	struct drm_clip_rect scissor;
97 	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
98 	drm_mach64_context_regs_t *regs = &sarea_priv->context_state;
99 	DMALOCALS;
100 
101 	DRM_DEBUG("box=%p\n", box);
102 
103 	/* Get GL scissor */
104 	/* FIXME: store scissor in SAREA as a cliprect instead of in
105 	 * hardware format, or do intersection client-side
106 	 */
107 	scissor.x1 = regs->sc_left_right & 0xffff;
108 	scissor.x2 = (regs->sc_left_right & 0xffff0000) >> 16;
109 	scissor.y1 = regs->sc_top_bottom & 0xffff;
110 	scissor.y2 = (regs->sc_top_bottom & 0xffff0000) >> 16;
111 
112 	/* Intersect GL scissor with cliprect */
113 	if (box->x1 > scissor.x1)
114 		scissor.x1 = box->x1;
115 	if (box->y1 > scissor.y1)
116 		scissor.y1 = box->y1;
117 	if (box->x2 < scissor.x2)
118 		scissor.x2 = box->x2;
119 	if (box->y2 < scissor.y2)
120 		scissor.y2 = box->y2;
121 	/* positive return means skip */
122 	if (scissor.x1 >= scissor.x2)
123 		return 1;
124 	if (scissor.y1 >= scissor.y2)
125 		return 1;
126 
127 	DMAGETPTR(file_priv, dev_priv, 2);	/* returns on failure to get buffer */
128 
129 	sc_left_right = ((scissor.x1 << 0) | (scissor.x2 << 16));
130 	sc_top_bottom = ((scissor.y1 << 0) | (scissor.y2 << 16));
131 
132 	DMAOUTREG(MACH64_SC_LEFT_RIGHT, sc_left_right);
133 	DMAOUTREG(MACH64_SC_TOP_BOTTOM, sc_top_bottom);
134 
135 	DMAADVANCE(dev_priv, 1);
136 
137 	return 0;
138 }
139 
mach64_emit_state(struct drm_file * file_priv,drm_mach64_private_t * dev_priv)140 static __inline__ int mach64_emit_state(struct drm_file *file_priv,
141 					drm_mach64_private_t * dev_priv)
142 {
143 	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
144 	drm_mach64_context_regs_t *regs = &sarea_priv->context_state;
145 	unsigned int dirty = sarea_priv->dirty;
146 	u32 offset = ((regs->tex_size_pitch & 0xf0) >> 2);
147 	DMALOCALS;
148 
149 	if (MACH64_VERBOSE) {
150 		mach64_print_dirty(__FUNCTION__, dirty);
151 	} else {
152 		DRM_DEBUG("dirty=0x%08x\n", dirty);
153 	}
154 
155 	DMAGETPTR(file_priv, dev_priv, 17);	/* returns on failure to get buffer */
156 
157 	if (dirty & MACH64_UPLOAD_MISC) {
158 		DMAOUTREG(MACH64_DP_MIX, regs->dp_mix);
159 		DMAOUTREG(MACH64_DP_SRC, regs->dp_src);
160 		DMAOUTREG(MACH64_CLR_CMP_CNTL, regs->clr_cmp_cntl);
161 		DMAOUTREG(MACH64_GUI_TRAJ_CNTL, regs->gui_traj_cntl);
162 		sarea_priv->dirty &= ~MACH64_UPLOAD_MISC;
163 	}
164 
165 	if (dirty & MACH64_UPLOAD_DST_OFF_PITCH) {
166 		DMAOUTREG(MACH64_DST_OFF_PITCH, regs->dst_off_pitch);
167 		sarea_priv->dirty &= ~MACH64_UPLOAD_DST_OFF_PITCH;
168 	}
169 	if (dirty & MACH64_UPLOAD_Z_OFF_PITCH) {
170 		DMAOUTREG(MACH64_Z_OFF_PITCH, regs->z_off_pitch);
171 		sarea_priv->dirty &= ~MACH64_UPLOAD_Z_OFF_PITCH;
172 	}
173 	if (dirty & MACH64_UPLOAD_Z_ALPHA_CNTL) {
174 		DMAOUTREG(MACH64_Z_CNTL, regs->z_cntl);
175 		DMAOUTREG(MACH64_ALPHA_TST_CNTL, regs->alpha_tst_cntl);
176 		sarea_priv->dirty &= ~MACH64_UPLOAD_Z_ALPHA_CNTL;
177 	}
178 	if (dirty & MACH64_UPLOAD_SCALE_3D_CNTL) {
179 		DMAOUTREG(MACH64_SCALE_3D_CNTL, regs->scale_3d_cntl);
180 		sarea_priv->dirty &= ~MACH64_UPLOAD_SCALE_3D_CNTL;
181 	}
182 	if (dirty & MACH64_UPLOAD_DP_FOG_CLR) {
183 		DMAOUTREG(MACH64_DP_FOG_CLR, regs->dp_fog_clr);
184 		sarea_priv->dirty &= ~MACH64_UPLOAD_DP_FOG_CLR;
185 	}
186 	if (dirty & MACH64_UPLOAD_DP_WRITE_MASK) {
187 		DMAOUTREG(MACH64_DP_WRITE_MASK, regs->dp_write_mask);
188 		sarea_priv->dirty &= ~MACH64_UPLOAD_DP_WRITE_MASK;
189 	}
190 	if (dirty & MACH64_UPLOAD_DP_PIX_WIDTH) {
191 		DMAOUTREG(MACH64_DP_PIX_WIDTH, regs->dp_pix_width);
192 		sarea_priv->dirty &= ~MACH64_UPLOAD_DP_PIX_WIDTH;
193 	}
194 	if (dirty & MACH64_UPLOAD_SETUP_CNTL) {
195 		DMAOUTREG(MACH64_SETUP_CNTL, regs->setup_cntl);
196 		sarea_priv->dirty &= ~MACH64_UPLOAD_SETUP_CNTL;
197 	}
198 
199 	if (dirty & MACH64_UPLOAD_TEXTURE) {
200 		DMAOUTREG(MACH64_TEX_SIZE_PITCH, regs->tex_size_pitch);
201 		DMAOUTREG(MACH64_TEX_CNTL, regs->tex_cntl);
202 		DMAOUTREG(MACH64_SECONDARY_TEX_OFF, regs->secondary_tex_off);
203 		DMAOUTREG(MACH64_TEX_0_OFF + offset, regs->tex_offset);
204 		sarea_priv->dirty &= ~MACH64_UPLOAD_TEXTURE;
205 	}
206 
207 	DMAADVANCE(dev_priv, 1);
208 
209 	sarea_priv->dirty &= MACH64_UPLOAD_CLIPRECTS;
210 
211 	return 0;
212 
213 }
214 
215 /* ================================================================
216  * DMA command dispatch functions
217  */
218 
mach64_dma_dispatch_clear(struct drm_device * dev,struct drm_file * file_priv,unsigned int flags,int cx,int cy,int cw,int ch,unsigned int clear_color,unsigned int clear_depth)219 static int mach64_dma_dispatch_clear(struct drm_device * dev,
220 				     struct drm_file *file_priv,
221 				     unsigned int flags,
222 				     int cx, int cy, int cw, int ch,
223 				     unsigned int clear_color,
224 				     unsigned int clear_depth)
225 {
226 	drm_mach64_private_t *dev_priv = dev->dev_private;
227 	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
228 	drm_mach64_context_regs_t *ctx = &sarea_priv->context_state;
229 	int nbox = sarea_priv->nbox;
230 	struct drm_clip_rect *pbox = sarea_priv->boxes;
231 	u32 fb_bpp, depth_bpp;
232 	int i;
233 	DMALOCALS;
234 
235 	DRM_DEBUG("\n");
236 
237 	switch (dev_priv->fb_bpp) {
238 	case 16:
239 		fb_bpp = MACH64_DATATYPE_RGB565;
240 		break;
241 	case 32:
242 		fb_bpp = MACH64_DATATYPE_ARGB8888;
243 		break;
244 	default:
245 		return -EINVAL;
246 	}
247 	switch (dev_priv->depth_bpp) {
248 	case 16:
249 		depth_bpp = MACH64_DATATYPE_RGB565;
250 		break;
251 	case 24:
252 	case 32:
253 		depth_bpp = MACH64_DATATYPE_ARGB8888;
254 		break;
255 	default:
256 		return -EINVAL;
257 	}
258 
259 	if (!nbox)
260 		return 0;
261 
262 	DMAGETPTR(file_priv, dev_priv, nbox * 31);	/* returns on failure to get buffer */
263 
264 	for (i = 0; i < nbox; i++) {
265 		int x = pbox[i].x1;
266 		int y = pbox[i].y1;
267 		int w = pbox[i].x2 - x;
268 		int h = pbox[i].y2 - y;
269 
270 		DRM_DEBUG("dispatch clear %d,%d-%d,%d flags 0x%x\n",
271 			  pbox[i].x1, pbox[i].y1,
272 			  pbox[i].x2, pbox[i].y2, flags);
273 
274 		if (flags & (MACH64_FRONT | MACH64_BACK)) {
275 			/* Setup for color buffer clears
276 			 */
277 
278 			DMAOUTREG(MACH64_Z_CNTL, 0);
279 			DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
280 
281 			DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right);
282 			DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom);
283 
284 			DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);
285 			DMAOUTREG(MACH64_GUI_TRAJ_CNTL,
286 				  (MACH64_DST_X_LEFT_TO_RIGHT |
287 				   MACH64_DST_Y_TOP_TO_BOTTOM));
288 
289 			DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) |
290 							(fb_bpp << 4) |
291 							(fb_bpp << 8) |
292 							(fb_bpp << 16) |
293 							(fb_bpp << 28)));
294 
295 			DMAOUTREG(MACH64_DP_FRGD_CLR, clear_color);
296 			DMAOUTREG(MACH64_DP_WRITE_MASK, ctx->dp_write_mask);
297 			DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D |
298 						  MACH64_FRGD_MIX_S));
299 			DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR |
300 						  MACH64_FRGD_SRC_FRGD_CLR |
301 						  MACH64_MONO_SRC_ONE));
302 
303 		}
304 
305 		if (flags & MACH64_FRONT) {
306 
307 			DMAOUTREG(MACH64_DST_OFF_PITCH,
308 				  dev_priv->front_offset_pitch);
309 			DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x);
310 			DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
311 
312 		}
313 
314 		if (flags & MACH64_BACK) {
315 
316 			DMAOUTREG(MACH64_DST_OFF_PITCH,
317 				  dev_priv->back_offset_pitch);
318 			DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x);
319 			DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
320 
321 		}
322 
323 		if (flags & MACH64_DEPTH) {
324 			/* Setup for depth buffer clear
325 			 */
326 			DMAOUTREG(MACH64_Z_CNTL, 0);
327 			DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
328 
329 			DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right);
330 			DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom);
331 
332 			DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);
333 			DMAOUTREG(MACH64_GUI_TRAJ_CNTL,
334 				  (MACH64_DST_X_LEFT_TO_RIGHT |
335 				   MACH64_DST_Y_TOP_TO_BOTTOM));
336 
337 			DMAOUTREG(MACH64_DP_PIX_WIDTH, ((depth_bpp << 0) |
338 							(depth_bpp << 4) |
339 							(depth_bpp << 8) |
340 							(depth_bpp << 16) |
341 							(depth_bpp << 28)));
342 
343 			DMAOUTREG(MACH64_DP_FRGD_CLR, clear_depth);
344 			DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff);
345 			DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D |
346 						  MACH64_FRGD_MIX_S));
347 			DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR |
348 						  MACH64_FRGD_SRC_FRGD_CLR |
349 						  MACH64_MONO_SRC_ONE));
350 
351 			DMAOUTREG(MACH64_DST_OFF_PITCH,
352 				  dev_priv->depth_offset_pitch);
353 			DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x);
354 			DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
355 		}
356 	}
357 
358 	DMAADVANCE(dev_priv, 1);
359 
360 	return 0;
361 }
362 
mach64_dma_dispatch_swap(struct drm_device * dev,struct drm_file * file_priv)363 static int mach64_dma_dispatch_swap(struct drm_device * dev,
364 				    struct drm_file *file_priv)
365 {
366 	drm_mach64_private_t *dev_priv = dev->dev_private;
367 	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
368 	int nbox = sarea_priv->nbox;
369 	struct drm_clip_rect *pbox = sarea_priv->boxes;
370 	u32 fb_bpp;
371 	int i;
372 	DMALOCALS;
373 
374 	DRM_DEBUG("\n");
375 
376 	switch (dev_priv->fb_bpp) {
377 	case 16:
378 		fb_bpp = MACH64_DATATYPE_RGB565;
379 		break;
380 	case 32:
381 	default:
382 		fb_bpp = MACH64_DATATYPE_ARGB8888;
383 		break;
384 	}
385 
386 	if (!nbox)
387 		return 0;
388 
389 	DMAGETPTR(file_priv, dev_priv, 13 + nbox * 4);	/* returns on failure to get buffer */
390 
391 	DMAOUTREG(MACH64_Z_CNTL, 0);
392 	DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
393 
394 	DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16));	/* no scissor */
395 	DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16));
396 
397 	DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);
398 	DMAOUTREG(MACH64_GUI_TRAJ_CNTL, (MACH64_DST_X_LEFT_TO_RIGHT |
399 					 MACH64_DST_Y_TOP_TO_BOTTOM));
400 
401 	DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) |
402 					(fb_bpp << 4) |
403 					(fb_bpp << 8) |
404 					(fb_bpp << 16) | (fb_bpp << 28)));
405 
406 	DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff);
407 	DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S));
408 	DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_BKGD_CLR |
409 				  MACH64_FRGD_SRC_BLIT | MACH64_MONO_SRC_ONE));
410 
411 	DMAOUTREG(MACH64_SRC_OFF_PITCH, dev_priv->back_offset_pitch);
412 	DMAOUTREG(MACH64_DST_OFF_PITCH, dev_priv->front_offset_pitch);
413 
414 	for (i = 0; i < nbox; i++) {
415 		int x = pbox[i].x1;
416 		int y = pbox[i].y1;
417 		int w = pbox[i].x2 - x;
418 		int h = pbox[i].y2 - y;
419 
420 		DRM_DEBUG("dispatch swap %d,%d-%d,%d\n",
421 			  pbox[i].x1, pbox[i].y1, pbox[i].x2, pbox[i].y2);
422 
423 		DMAOUTREG(MACH64_SRC_WIDTH1, w);
424 		DMAOUTREG(MACH64_SRC_Y_X, (x << 16) | y);
425 		DMAOUTREG(MACH64_DST_Y_X, (x << 16) | y);
426 		DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
427 
428 	}
429 
430 	DMAADVANCE(dev_priv, 1);
431 
432 	if (dev_priv->driver_mode == MACH64_MODE_DMA_ASYNC) {
433 		for (i = 0; i < MACH64_MAX_QUEUED_FRAMES - 1; i++) {
434 			dev_priv->frame_ofs[i] = dev_priv->frame_ofs[i + 1];
435 		}
436 		dev_priv->frame_ofs[i] = GETRINGOFFSET();
437 
438 		dev_priv->sarea_priv->frames_queued++;
439 	}
440 
441 	return 0;
442 }
443 
mach64_do_get_frames_queued(drm_mach64_private_t * dev_priv)444 static int mach64_do_get_frames_queued(drm_mach64_private_t * dev_priv)
445 {
446 	drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
447 	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
448 	int i, start;
449 	u32 head, tail, ofs;
450 
451 	DRM_DEBUG("\n");
452 
453 	if (sarea_priv->frames_queued == 0)
454 		return 0;
455 
456 	tail = ring->tail;
457 	mach64_ring_tick(dev_priv, ring);
458 	head = ring->head;
459 
460 	start = (MACH64_MAX_QUEUED_FRAMES -
461 		 DRM_MIN(MACH64_MAX_QUEUED_FRAMES, sarea_priv->frames_queued));
462 
463 	if (head == tail) {
464 		sarea_priv->frames_queued = 0;
465 		for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) {
466 			dev_priv->frame_ofs[i] = ~0;
467 		}
468 		return 0;
469 	}
470 
471 	for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) {
472 		ofs = dev_priv->frame_ofs[i];
473 		DRM_DEBUG("frame_ofs[%d] ofs: %d\n", i, ofs);
474 		if (ofs == ~0 ||
475 		    (head < tail && (ofs < head || ofs >= tail)) ||
476 		    (head > tail && (ofs < head && ofs >= tail))) {
477 			sarea_priv->frames_queued =
478 			    (MACH64_MAX_QUEUED_FRAMES - 1) - i;
479 			dev_priv->frame_ofs[i] = ~0;
480 		}
481 	}
482 
483 	return sarea_priv->frames_queued;
484 }
485 
486 /* Copy and verify a client submited buffer.
487  * FIXME: Make an assembly optimized version
488  */
copy_from_user_vertex(u32 * to,const u32 __user * ufrom,unsigned long bytes)489 static __inline__ int copy_from_user_vertex(u32 *to,
490 					    const u32 __user *ufrom,
491 					    unsigned long bytes)
492 {
493 	unsigned long n = bytes;	/* dwords remaining in buffer */
494 	u32 *from, *orig_from;
495 
496 	from = drm_alloc(bytes, DRM_MEM_DRIVER);
497 	if (from == NULL)
498 		return -ENOMEM;
499 
500 	if (DRM_COPY_FROM_USER(from, ufrom, bytes)) {
501 		drm_free(from, bytes, DRM_MEM_DRIVER);
502 		return -EFAULT;
503 	}
504 	orig_from = from; /* we'll be modifying the "from" ptr, so save it */
505 
506 	n >>= 2;
507 
508 	while (n > 1) {
509 		u32 data, reg, count;
510 
511 		data = *from++;
512 
513 		n--;
514 
515 		reg = le32_to_cpu(data);
516 		count = (reg >> 16) + 1;
517 		if (count <= n) {
518 			n -= count;
519 			reg &= 0xffff;
520 
521 			/* This is an exact match of Mach64's Setup Engine registers,
522 			 * excluding SETUP_CNTL (1_C1).
523 			 */
524 			if ((reg >= 0x0190 && reg < 0x01c1) ||
525 			    (reg >= 0x01ca && reg <= 0x01cf)) {
526 				*to++ = data;
527 				memcpy(to, from, count << 2);
528 				from += count;
529 				to += count;
530 			} else {
531 				DRM_ERROR("Got bad command: 0x%04x\n", reg);
532 				drm_free(orig_from, bytes, DRM_MEM_DRIVER);
533 				return -EACCES;
534 			}
535 		} else {
536 			DRM_ERROR
537 			    ("Got bad command count(=%u) dwords remaining=%lu\n",
538 			     count, n);
539 			drm_free(orig_from, bytes, DRM_MEM_DRIVER);
540 			return -EINVAL;
541 		}
542 	}
543 
544 	drm_free(orig_from, bytes, DRM_MEM_DRIVER);
545 	if (n == 0)
546 		return 0;
547 	else {
548 		DRM_ERROR("Bad buf->used(=%lu)\n", bytes);
549 		return -EINVAL;
550 	}
551 }
552 
mach64_dma_dispatch_vertex(struct drm_device * dev,struct drm_file * file_priv,drm_mach64_vertex_t * vertex)553 static int mach64_dma_dispatch_vertex(struct drm_device * dev,
554 				      struct drm_file *file_priv,
555 				      drm_mach64_vertex_t * vertex)
556 {
557 	drm_mach64_private_t *dev_priv = dev->dev_private;
558 	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
559 	struct drm_buf *copy_buf;
560 	void *buf = vertex->buf;
561 	unsigned long used = vertex->used;
562 	int ret = 0;
563 	int i = 0;
564 	int done = 0;
565 	int verify_ret = 0;
566 	DMALOCALS;
567 
568 	DRM_DEBUG("buf=%p used=%lu nbox=%d\n",
569 		  buf, used, sarea_priv->nbox);
570 
571 	if (!used)
572 		goto _vertex_done;
573 
574 	copy_buf = mach64_freelist_get(dev_priv);
575 	if (copy_buf == NULL) {
576 		DRM_ERROR("couldn't get buffer\n");
577 		return -EAGAIN;
578 	}
579 
580 	/* Mach64's vertex data is actually register writes. To avoid security
581 	 * compromises these register writes have to be verified and copied from
582 	 * user space into a private DMA buffer.
583 	 */
584 	verify_ret = copy_from_user_vertex(GETBUFPTR(copy_buf), buf, used);
585 
586 	if (verify_ret != 0) {
587 		mach64_freelist_put(dev_priv, copy_buf);
588 		goto _vertex_done;
589 	}
590 
591 	copy_buf->used = used;
592 
593 	DMASETPTR(copy_buf);
594 
595 	if (sarea_priv->dirty & ~MACH64_UPLOAD_CLIPRECTS) {
596 		ret = mach64_emit_state(file_priv, dev_priv);
597 		if (ret < 0)
598 			return ret;
599 	}
600 
601 	do {
602 		/* Emit the next cliprect */
603 		if (i < sarea_priv->nbox) {
604 			ret = mach64_emit_cliprect(file_priv, dev_priv,
605 						   &sarea_priv->boxes[i]);
606 			if (ret < 0) {
607 				/* failed to get buffer */
608 				return ret;
609 			} else if (ret != 0) {
610 				/* null intersection with scissor */
611 				continue;
612 			}
613 		}
614 		if ((i >= sarea_priv->nbox - 1))
615 			done = 1;
616 
617 		/* Add the buffer to the DMA queue */
618 		DMAADVANCE(dev_priv, done);
619 
620 	} while (++i < sarea_priv->nbox);
621 
622 	if (!done) {
623 		if (copy_buf->pending) {
624 			DMADISCARDBUF();
625 		} else {
626 			/* This buffer wasn't used (no cliprects), so place it
627 			 * back on the free list
628 			 */
629 			mach64_freelist_put(dev_priv, copy_buf);
630 		}
631 	}
632 
633 _vertex_done:
634 	sarea_priv->dirty &= ~MACH64_UPLOAD_CLIPRECTS;
635 	sarea_priv->nbox = 0;
636 
637 	return verify_ret;
638 }
639 
copy_from_user_blit(u32 * to,const u32 __user * ufrom,unsigned long bytes)640 static __inline__ int copy_from_user_blit(u32 *to,
641 					  const u32 __user *ufrom,
642 					  unsigned long bytes)
643 {
644 	to = (u32 *)((char *)to + MACH64_HOSTDATA_BLIT_OFFSET);
645 
646 	if (DRM_COPY_FROM_USER(to, ufrom, bytes)) {
647 		return -EFAULT;
648 	}
649 
650 	return 0;
651 }
652 
mach64_dma_dispatch_blit(struct drm_device * dev,struct drm_file * file_priv,drm_mach64_blit_t * blit)653 static int mach64_dma_dispatch_blit(struct drm_device * dev,
654 				    struct drm_file *file_priv,
655 				    drm_mach64_blit_t * blit)
656 {
657 	drm_mach64_private_t *dev_priv = dev->dev_private;
658 	int dword_shift, dwords;
659 	unsigned long used;
660 	struct drm_buf *copy_buf;
661 	int verify_ret = 0;
662 	DMALOCALS;
663 
664 	/* The compiler won't optimize away a division by a variable,
665 	 * even if the only legal values are powers of two.  Thus, we'll
666 	 * use a shift instead.
667 	 */
668 	switch (blit->format) {
669 	case MACH64_DATATYPE_ARGB8888:
670 		dword_shift = 0;
671 		break;
672 	case MACH64_DATATYPE_ARGB1555:
673 	case MACH64_DATATYPE_RGB565:
674 	case MACH64_DATATYPE_VYUY422:
675 	case MACH64_DATATYPE_YVYU422:
676 	case MACH64_DATATYPE_ARGB4444:
677 		dword_shift = 1;
678 		break;
679 	case MACH64_DATATYPE_CI8:
680 	case MACH64_DATATYPE_RGB8:
681 		dword_shift = 2;
682 		break;
683 	default:
684 		DRM_ERROR("invalid blit format %d\n", blit->format);
685 		return -EINVAL;
686 	}
687 
688 	/* Set buf->used to the bytes of blit data based on the blit dimensions
689 	 * and verify the size.  When the setup is emitted to the buffer with
690 	 * the DMA* macros below, buf->used is incremented to include the bytes
691 	 * used for setup as well as the blit data.
692 	 */
693 	dwords = (blit->width * blit->height) >> dword_shift;
694 	used = dwords << 2;
695 	if (used <= 0 ||
696 	    used > MACH64_BUFFER_SIZE - MACH64_HOSTDATA_BLIT_OFFSET) {
697 		DRM_ERROR("Invalid blit size: %lu bytes\n", used);
698 		return -EINVAL;
699 	}
700 
701 	copy_buf = mach64_freelist_get(dev_priv);
702 	if (copy_buf == NULL) {
703 		DRM_ERROR("couldn't get buffer\n");
704 		return -EAGAIN;
705 	}
706 
707 	/* Copy the blit data from userspace.
708 	 *
709 	 * XXX: This is overkill. The most efficient solution would be having
710 	 * two sets of buffers (one set private for vertex data, the other set
711 	 * client-writable for blits). However that would bring more complexity
712 	 * and would break backward compatability. The solution currently
713 	 * implemented is keeping all buffers private, allowing to secure the
714 	 * driver, without increasing complexity at the expense of some speed
715 	 * transfering data.
716 	 */
717 	verify_ret = copy_from_user_blit(GETBUFPTR(copy_buf), blit->buf, used);
718 
719 	if (verify_ret != 0) {
720 		mach64_freelist_put(dev_priv, copy_buf);
721 		goto _blit_done;
722 	}
723 
724 	copy_buf->used = used;
725 
726 	/* FIXME: Use a last buffer flag and reduce the state emitted for subsequent,
727 	 * continuation buffers?
728 	 */
729 
730 	/* Blit via BM_HOSTDATA (gui-master) - like HOST_DATA[0-15], but doesn't require
731 	 * a register command every 16 dwords.  State setup is added at the start of the
732 	 * buffer -- the client leaves space for this based on MACH64_HOSTDATA_BLIT_OFFSET
733 	 */
734 	DMASETPTR(copy_buf);
735 
736 	DMAOUTREG(MACH64_Z_CNTL, 0);
737 	DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
738 
739 	DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16));	/* no scissor */
740 	DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16));
741 
742 	DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);	/* disable */
743 	DMAOUTREG(MACH64_GUI_TRAJ_CNTL,
744 		  MACH64_DST_X_LEFT_TO_RIGHT | MACH64_DST_Y_TOP_TO_BOTTOM);
745 
746 	DMAOUTREG(MACH64_DP_PIX_WIDTH, (blit->format << 0)	/* dst pix width */
747 		  |(blit->format << 4)	/* composite pix width */
748 		  |(blit->format << 8)	/* src pix width */
749 		  |(blit->format << 16)	/* host data pix width */
750 		  |(blit->format << 28)	/* scaler/3D pix width */
751 	    );
752 
753 	DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff);	/* enable all planes */
754 	DMAOUTREG(MACH64_DP_MIX, MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S);
755 	DMAOUTREG(MACH64_DP_SRC,
756 		  MACH64_BKGD_SRC_BKGD_CLR
757 		  | MACH64_FRGD_SRC_HOST | MACH64_MONO_SRC_ONE);
758 
759 	DMAOUTREG(MACH64_DST_OFF_PITCH,
760 		  (blit->pitch << 22) | (blit->offset >> 3));
761 	DMAOUTREG(MACH64_DST_X_Y, (blit->y << 16) | blit->x);
762 	DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (blit->height << 16) | blit->width);
763 
764 	DRM_DEBUG("%lu bytes\n", used);
765 
766 	/* Add the buffer to the queue */
767 	DMAADVANCEHOSTDATA(dev_priv);
768 
769 _blit_done:
770 	return verify_ret;
771 }
772 
773 /* ================================================================
774  * IOCTL functions
775  */
776 
mach64_dma_clear(struct drm_device * dev,void * data,struct drm_file * file_priv)777 int mach64_dma_clear(struct drm_device *dev, void *data,
778 		     struct drm_file *file_priv)
779 {
780 	drm_mach64_private_t *dev_priv = dev->dev_private;
781 	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
782 	drm_mach64_clear_t *clear = data;
783 	int ret;
784 
785 	DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
786 
787 	LOCK_TEST_WITH_RETURN(dev, file_priv);
788 
789 	if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
790 		sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
791 
792 	ret = mach64_dma_dispatch_clear(dev, file_priv, clear->flags,
793 					clear->x, clear->y, clear->w, clear->h,
794 					clear->clear_color,
795 					clear->clear_depth);
796 
797 	/* Make sure we restore the 3D state next time.
798 	 */
799 	sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC);
800 	return ret;
801 }
802 
mach64_dma_swap(struct drm_device * dev,void * data,struct drm_file * file_priv)803 int mach64_dma_swap(struct drm_device *dev, void *data,
804 		    struct drm_file *file_priv)
805 {
806 	drm_mach64_private_t *dev_priv = dev->dev_private;
807 	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
808 	int ret;
809 
810 	DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
811 
812 	LOCK_TEST_WITH_RETURN(dev, file_priv);
813 
814 	if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
815 		sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
816 
817 	ret = mach64_dma_dispatch_swap(dev, file_priv);
818 
819 	/* Make sure we restore the 3D state next time.
820 	 */
821 	sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC);
822 	return ret;
823 }
824 
mach64_dma_vertex(struct drm_device * dev,void * data,struct drm_file * file_priv)825 int mach64_dma_vertex(struct drm_device *dev, void *data,
826 		      struct drm_file *file_priv)
827 {
828 	drm_mach64_private_t *dev_priv = dev->dev_private;
829 	drm_mach64_sarea_t *sarea_priv;
830 	drm_mach64_vertex_t *vertex = data;
831 
832 	LOCK_TEST_WITH_RETURN(dev, file_priv);
833 
834 	if (!dev_priv) {
835 		DRM_ERROR("called with no initialization\n");
836 		return -EINVAL;
837 	}
838 	sarea_priv = dev_priv->sarea_priv;
839 
840 	DRM_DEBUG("pid=%d buf=%p used=%lu discard=%d\n",
841 		  DRM_CURRENTPID,
842 		  vertex->buf, vertex->used, vertex->discard);
843 
844 	if (vertex->prim < 0 || vertex->prim > MACH64_PRIM_POLYGON) {
845 		DRM_ERROR("buffer prim %d\n", vertex->prim);
846 		return -EINVAL;
847 	}
848 
849 	if (vertex->used > MACH64_BUFFER_SIZE || (vertex->used & 3) != 0) {
850 		DRM_ERROR("Invalid vertex buffer size: %lu bytes\n",
851 			  vertex->used);
852 		return -EINVAL;
853 	}
854 
855 	if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
856 		sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
857 
858 	return mach64_dma_dispatch_vertex(dev, file_priv, vertex);
859 }
860 
mach64_dma_blit(struct drm_device * dev,void * data,struct drm_file * file_priv)861 int mach64_dma_blit(struct drm_device *dev, void *data,
862 		    struct drm_file *file_priv)
863 {
864 	drm_mach64_private_t *dev_priv = dev->dev_private;
865 	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
866 	drm_mach64_blit_t *blit = data;
867 	int ret;
868 
869 	LOCK_TEST_WITH_RETURN(dev, file_priv);
870 
871 	ret = mach64_dma_dispatch_blit(dev, file_priv, blit);
872 
873 	/* Make sure we restore the 3D state next time.
874 	 */
875 	sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT |
876 			      MACH64_UPLOAD_MISC | MACH64_UPLOAD_CLIPRECTS);
877 
878 	return ret;
879 }
880 
mach64_get_param(struct drm_device * dev,void * data,struct drm_file * file_priv)881 int mach64_get_param(struct drm_device *dev, void *data,
882 		     struct drm_file *file_priv)
883 {
884 	drm_mach64_private_t *dev_priv = dev->dev_private;
885 	drm_mach64_getparam_t *param = data;
886 	int value;
887 
888 	DRM_DEBUG("\n");
889 
890 	if (!dev_priv) {
891 		DRM_ERROR("called with no initialization\n");
892 		return -EINVAL;
893 	}
894 
895 	switch (param->param) {
896 	case MACH64_PARAM_FRAMES_QUEUED:
897 		/* Needs lock since it calls mach64_ring_tick() */
898 		LOCK_TEST_WITH_RETURN(dev, file_priv);
899 		value = mach64_do_get_frames_queued(dev_priv);
900 		break;
901 	case MACH64_PARAM_IRQ_NR:
902 		value = dev->irq;
903 		break;
904 	default:
905 		return -EINVAL;
906 	}
907 
908 	if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
909 		DRM_ERROR("copy_to_user\n");
910 		return -EFAULT;
911 	}
912 
913 	return 0;
914 }
915