1145132Sanholt/* mach64_state.c -- State support for mach64 (Rage Pro) driver -*- linux-c -*-
2145132Sanholt * Created: Sun Dec 03 19:20:26 2000 by gareth@valinux.com
3152909Sanholt */
4152909Sanholt/*-
5145132Sanholt * Copyright 2000 Gareth Hughes
6145132Sanholt * Copyright 2002-2003 Leif Delgass
7145132Sanholt * All Rights Reserved.
8145132Sanholt *
9145132Sanholt * Permission is hereby granted, free of charge, to any person obtaining a
10145132Sanholt * copy of this software and associated documentation files (the "Software"),
11145132Sanholt * to deal in the Software without restriction, including without limitation
12145132Sanholt * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13145132Sanholt * and/or sell copies of the Software, and to permit persons to whom the
14145132Sanholt * Software is furnished to do so, subject to the following conditions:
15145132Sanholt *
16145132Sanholt * The above copyright notice and this permission notice (including the next
17145132Sanholt * paragraph) shall be included in all copies or substantial portions of the
18145132Sanholt * Software.
19145132Sanholt *
20145132Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21145132Sanholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22145132Sanholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23145132Sanholt * THE COPYRIGHT OWNER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24145132Sanholt * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25145132Sanholt * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26145132Sanholt *
27145132Sanholt * Authors:
28145132Sanholt *    Gareth Hughes <gareth@valinux.com>
29145132Sanholt *    Leif Delgass <ldelgass@retinalburn.net>
30182080Srnoland *    Jos�� Fonseca <j_r_fonseca@yahoo.co.uk>
31145132Sanholt */
32145132Sanholt
33152909Sanholt#include <sys/cdefs.h>
34152909Sanholt__FBSDID("$FreeBSD$");
35152909Sanholt
36145132Sanholt#include "dev/drm/drmP.h"
37145132Sanholt#include "dev/drm/drm.h"
38145132Sanholt#include "dev/drm/mach64_drm.h"
39145132Sanholt#include "dev/drm/mach64_drv.h"
40145132Sanholt
41145132Sanholt/* Interface history:
42145132Sanholt *
43145132Sanholt * 1.0 - Initial mach64 DRM
44145132Sanholt *
45145132Sanholt */
46182080Srnolandstruct drm_ioctl_desc mach64_ioctls[] = {
47182080Srnoland	DRM_IOCTL_DEF(DRM_MACH64_INIT, mach64_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
48182080Srnoland	DRM_IOCTL_DEF(DRM_MACH64_CLEAR, mach64_dma_clear, DRM_AUTH),
49182080Srnoland	DRM_IOCTL_DEF(DRM_MACH64_SWAP, mach64_dma_swap, DRM_AUTH),
50182080Srnoland	DRM_IOCTL_DEF(DRM_MACH64_IDLE, mach64_dma_idle, DRM_AUTH),
51182080Srnoland	DRM_IOCTL_DEF(DRM_MACH64_RESET, mach64_engine_reset, DRM_AUTH),
52182080Srnoland	DRM_IOCTL_DEF(DRM_MACH64_VERTEX, mach64_dma_vertex, DRM_AUTH),
53182080Srnoland	DRM_IOCTL_DEF(DRM_MACH64_BLIT, mach64_dma_blit, DRM_AUTH),
54182080Srnoland	DRM_IOCTL_DEF(DRM_MACH64_FLUSH, mach64_dma_flush, DRM_AUTH),
55182080Srnoland	DRM_IOCTL_DEF(DRM_MACH64_GETPARAM, mach64_get_param, DRM_AUTH),
56145132Sanholt};
57145132Sanholt
58145132Sanholtint mach64_max_ioctl = DRM_ARRAY_SIZE(mach64_ioctls);
59145132Sanholt
60145132Sanholt/* ================================================================
61145132Sanholt * DMA hardware state programming functions
62145132Sanholt */
63145132Sanholt
64145132Sanholtstatic void mach64_print_dirty(const char *msg, unsigned int flags)
65145132Sanholt{
66145132Sanholt	DRM_DEBUG("%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s\n",
67145132Sanholt		  msg,
68145132Sanholt		  flags,
69145132Sanholt		  (flags & MACH64_UPLOAD_DST_OFF_PITCH) ? "dst_off_pitch, " :
70145132Sanholt		  "",
71145132Sanholt		  (flags & MACH64_UPLOAD_Z_ALPHA_CNTL) ? "z_alpha_cntl, " : "",
72145132Sanholt		  (flags & MACH64_UPLOAD_SCALE_3D_CNTL) ? "scale_3d_cntl, " :
73145132Sanholt		  "", (flags & MACH64_UPLOAD_DP_FOG_CLR) ? "dp_fog_clr, " : "",
74145132Sanholt		  (flags & MACH64_UPLOAD_DP_WRITE_MASK) ? "dp_write_mask, " :
75145132Sanholt		  "",
76145132Sanholt		  (flags & MACH64_UPLOAD_DP_PIX_WIDTH) ? "dp_pix_width, " : "",
77145132Sanholt		  (flags & MACH64_UPLOAD_SETUP_CNTL) ? "setup_cntl, " : "",
78145132Sanholt		  (flags & MACH64_UPLOAD_MISC) ? "misc, " : "",
79145132Sanholt		  (flags & MACH64_UPLOAD_TEXTURE) ? "texture, " : "",
80145132Sanholt		  (flags & MACH64_UPLOAD_TEX0IMAGE) ? "tex0 image, " : "",
81145132Sanholt		  (flags & MACH64_UPLOAD_TEX1IMAGE) ? "tex1 image, " : "",
82145132Sanholt		  (flags & MACH64_UPLOAD_CLIPRECTS) ? "cliprects, " : "");
83145132Sanholt}
84145132Sanholt
85145132Sanholt/* Mach64 doesn't have hardware cliprects, just one hardware scissor,
86145132Sanholt * so the GL scissor is intersected with each cliprect here
87145132Sanholt */
88145132Sanholt/* This function returns 0 on success, 1 for no intersection, and
89145132Sanholt * negative for an error
90145132Sanholt */
91182080Srnolandstatic int mach64_emit_cliprect(struct drm_file *file_priv,
92182080Srnoland				drm_mach64_private_t * dev_priv,
93182080Srnoland				struct drm_clip_rect * box)
94145132Sanholt{
95145132Sanholt	u32 sc_left_right, sc_top_bottom;
96182080Srnoland	struct drm_clip_rect scissor;
97145132Sanholt	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
98145132Sanholt	drm_mach64_context_regs_t *regs = &sarea_priv->context_state;
99145132Sanholt	DMALOCALS;
100145132Sanholt
101182080Srnoland	DRM_DEBUG("box=%p\n", box);
102145132Sanholt
103145132Sanholt	/* Get GL scissor */
104145132Sanholt	/* FIXME: store scissor in SAREA as a cliprect instead of in
105145132Sanholt	 * hardware format, or do intersection client-side
106145132Sanholt	 */
107145132Sanholt	scissor.x1 = regs->sc_left_right & 0xffff;
108145132Sanholt	scissor.x2 = (regs->sc_left_right & 0xffff0000) >> 16;
109145132Sanholt	scissor.y1 = regs->sc_top_bottom & 0xffff;
110145132Sanholt	scissor.y2 = (regs->sc_top_bottom & 0xffff0000) >> 16;
111145132Sanholt
112145132Sanholt	/* Intersect GL scissor with cliprect */
113145132Sanholt	if (box->x1 > scissor.x1)
114145132Sanholt		scissor.x1 = box->x1;
115145132Sanholt	if (box->y1 > scissor.y1)
116145132Sanholt		scissor.y1 = box->y1;
117145132Sanholt	if (box->x2 < scissor.x2)
118145132Sanholt		scissor.x2 = box->x2;
119145132Sanholt	if (box->y2 < scissor.y2)
120145132Sanholt		scissor.y2 = box->y2;
121145132Sanholt	/* positive return means skip */
122145132Sanholt	if (scissor.x1 >= scissor.x2)
123145132Sanholt		return 1;
124145132Sanholt	if (scissor.y1 >= scissor.y2)
125145132Sanholt		return 1;
126145132Sanholt
127182080Srnoland	DMAGETPTR(file_priv, dev_priv, 2);	/* returns on failure to get buffer */
128145132Sanholt
129145132Sanholt	sc_left_right = ((scissor.x1 << 0) | (scissor.x2 << 16));
130145132Sanholt	sc_top_bottom = ((scissor.y1 << 0) | (scissor.y2 << 16));
131145132Sanholt
132145132Sanholt	DMAOUTREG(MACH64_SC_LEFT_RIGHT, sc_left_right);
133145132Sanholt	DMAOUTREG(MACH64_SC_TOP_BOTTOM, sc_top_bottom);
134145132Sanholt
135145132Sanholt	DMAADVANCE(dev_priv, 1);
136145132Sanholt
137145132Sanholt	return 0;
138145132Sanholt}
139145132Sanholt
140182080Srnolandstatic __inline__ int mach64_emit_state(struct drm_file *file_priv,
141145132Sanholt					drm_mach64_private_t * dev_priv)
142145132Sanholt{
143145132Sanholt	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
144145132Sanholt	drm_mach64_context_regs_t *regs = &sarea_priv->context_state;
145145132Sanholt	unsigned int dirty = sarea_priv->dirty;
146145132Sanholt	u32 offset = ((regs->tex_size_pitch & 0xf0) >> 2);
147145132Sanholt	DMALOCALS;
148145132Sanholt
149145132Sanholt	if (MACH64_VERBOSE) {
150145132Sanholt		mach64_print_dirty(__FUNCTION__, dirty);
151145132Sanholt	} else {
152182080Srnoland		DRM_DEBUG("dirty=0x%08x\n", dirty);
153145132Sanholt	}
154145132Sanholt
155182080Srnoland	DMAGETPTR(file_priv, dev_priv, 17);	/* returns on failure to get buffer */
156145132Sanholt
157145132Sanholt	if (dirty & MACH64_UPLOAD_MISC) {
158145132Sanholt		DMAOUTREG(MACH64_DP_MIX, regs->dp_mix);
159145132Sanholt		DMAOUTREG(MACH64_DP_SRC, regs->dp_src);
160145132Sanholt		DMAOUTREG(MACH64_CLR_CMP_CNTL, regs->clr_cmp_cntl);
161145132Sanholt		DMAOUTREG(MACH64_GUI_TRAJ_CNTL, regs->gui_traj_cntl);
162145132Sanholt		sarea_priv->dirty &= ~MACH64_UPLOAD_MISC;
163145132Sanholt	}
164145132Sanholt
165145132Sanholt	if (dirty & MACH64_UPLOAD_DST_OFF_PITCH) {
166145132Sanholt		DMAOUTREG(MACH64_DST_OFF_PITCH, regs->dst_off_pitch);
167145132Sanholt		sarea_priv->dirty &= ~MACH64_UPLOAD_DST_OFF_PITCH;
168145132Sanholt	}
169145132Sanholt	if (dirty & MACH64_UPLOAD_Z_OFF_PITCH) {
170145132Sanholt		DMAOUTREG(MACH64_Z_OFF_PITCH, regs->z_off_pitch);
171145132Sanholt		sarea_priv->dirty &= ~MACH64_UPLOAD_Z_OFF_PITCH;
172145132Sanholt	}
173145132Sanholt	if (dirty & MACH64_UPLOAD_Z_ALPHA_CNTL) {
174145132Sanholt		DMAOUTREG(MACH64_Z_CNTL, regs->z_cntl);
175145132Sanholt		DMAOUTREG(MACH64_ALPHA_TST_CNTL, regs->alpha_tst_cntl);
176145132Sanholt		sarea_priv->dirty &= ~MACH64_UPLOAD_Z_ALPHA_CNTL;
177145132Sanholt	}
178145132Sanholt	if (dirty & MACH64_UPLOAD_SCALE_3D_CNTL) {
179145132Sanholt		DMAOUTREG(MACH64_SCALE_3D_CNTL, regs->scale_3d_cntl);
180145132Sanholt		sarea_priv->dirty &= ~MACH64_UPLOAD_SCALE_3D_CNTL;
181145132Sanholt	}
182145132Sanholt	if (dirty & MACH64_UPLOAD_DP_FOG_CLR) {
183145132Sanholt		DMAOUTREG(MACH64_DP_FOG_CLR, regs->dp_fog_clr);
184145132Sanholt		sarea_priv->dirty &= ~MACH64_UPLOAD_DP_FOG_CLR;
185145132Sanholt	}
186145132Sanholt	if (dirty & MACH64_UPLOAD_DP_WRITE_MASK) {
187145132Sanholt		DMAOUTREG(MACH64_DP_WRITE_MASK, regs->dp_write_mask);
188145132Sanholt		sarea_priv->dirty &= ~MACH64_UPLOAD_DP_WRITE_MASK;
189145132Sanholt	}
190145132Sanholt	if (dirty & MACH64_UPLOAD_DP_PIX_WIDTH) {
191145132Sanholt		DMAOUTREG(MACH64_DP_PIX_WIDTH, regs->dp_pix_width);
192145132Sanholt		sarea_priv->dirty &= ~MACH64_UPLOAD_DP_PIX_WIDTH;
193145132Sanholt	}
194145132Sanholt	if (dirty & MACH64_UPLOAD_SETUP_CNTL) {
195145132Sanholt		DMAOUTREG(MACH64_SETUP_CNTL, regs->setup_cntl);
196145132Sanholt		sarea_priv->dirty &= ~MACH64_UPLOAD_SETUP_CNTL;
197145132Sanholt	}
198145132Sanholt
199145132Sanholt	if (dirty & MACH64_UPLOAD_TEXTURE) {
200145132Sanholt		DMAOUTREG(MACH64_TEX_SIZE_PITCH, regs->tex_size_pitch);
201145132Sanholt		DMAOUTREG(MACH64_TEX_CNTL, regs->tex_cntl);
202145132Sanholt		DMAOUTREG(MACH64_SECONDARY_TEX_OFF, regs->secondary_tex_off);
203145132Sanholt		DMAOUTREG(MACH64_TEX_0_OFF + offset, regs->tex_offset);
204145132Sanholt		sarea_priv->dirty &= ~MACH64_UPLOAD_TEXTURE;
205145132Sanholt	}
206145132Sanholt
207145132Sanholt	DMAADVANCE(dev_priv, 1);
208145132Sanholt
209145132Sanholt	sarea_priv->dirty &= MACH64_UPLOAD_CLIPRECTS;
210145132Sanholt
211145132Sanholt	return 0;
212145132Sanholt
213145132Sanholt}
214145132Sanholt
215145132Sanholt/* ================================================================
216145132Sanholt * DMA command dispatch functions
217145132Sanholt */
218145132Sanholt
219182080Srnolandstatic int mach64_dma_dispatch_clear(struct drm_device * dev,
220182080Srnoland				     struct drm_file *file_priv,
221145132Sanholt				     unsigned int flags,
222145132Sanholt				     int cx, int cy, int cw, int ch,
223145132Sanholt				     unsigned int clear_color,
224145132Sanholt				     unsigned int clear_depth)
225145132Sanholt{
226145132Sanholt	drm_mach64_private_t *dev_priv = dev->dev_private;
227145132Sanholt	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
228145132Sanholt	drm_mach64_context_regs_t *ctx = &sarea_priv->context_state;
229145132Sanholt	int nbox = sarea_priv->nbox;
230182080Srnoland	struct drm_clip_rect *pbox = sarea_priv->boxes;
231145132Sanholt	u32 fb_bpp, depth_bpp;
232145132Sanholt	int i;
233145132Sanholt	DMALOCALS;
234145132Sanholt
235182080Srnoland	DRM_DEBUG("\n");
236145132Sanholt
237145132Sanholt	switch (dev_priv->fb_bpp) {
238145132Sanholt	case 16:
239145132Sanholt		fb_bpp = MACH64_DATATYPE_RGB565;
240145132Sanholt		break;
241145132Sanholt	case 32:
242145132Sanholt		fb_bpp = MACH64_DATATYPE_ARGB8888;
243145132Sanholt		break;
244145132Sanholt	default:
245182080Srnoland		return -EINVAL;
246145132Sanholt	}
247145132Sanholt	switch (dev_priv->depth_bpp) {
248145132Sanholt	case 16:
249145132Sanholt		depth_bpp = MACH64_DATATYPE_RGB565;
250145132Sanholt		break;
251145132Sanholt	case 24:
252145132Sanholt	case 32:
253145132Sanholt		depth_bpp = MACH64_DATATYPE_ARGB8888;
254145132Sanholt		break;
255145132Sanholt	default:
256182080Srnoland		return -EINVAL;
257145132Sanholt	}
258145132Sanholt
259145132Sanholt	if (!nbox)
260145132Sanholt		return 0;
261145132Sanholt
262182080Srnoland	DMAGETPTR(file_priv, dev_priv, nbox * 31);	/* returns on failure to get buffer */
263145132Sanholt
264145132Sanholt	for (i = 0; i < nbox; i++) {
265145132Sanholt		int x = pbox[i].x1;
266145132Sanholt		int y = pbox[i].y1;
267145132Sanholt		int w = pbox[i].x2 - x;
268145132Sanholt		int h = pbox[i].y2 - y;
269145132Sanholt
270145132Sanholt		DRM_DEBUG("dispatch clear %d,%d-%d,%d flags 0x%x\n",
271145132Sanholt			  pbox[i].x1, pbox[i].y1,
272145132Sanholt			  pbox[i].x2, pbox[i].y2, flags);
273145132Sanholt
274145132Sanholt		if (flags & (MACH64_FRONT | MACH64_BACK)) {
275145132Sanholt			/* Setup for color buffer clears
276145132Sanholt			 */
277145132Sanholt
278145132Sanholt			DMAOUTREG(MACH64_Z_CNTL, 0);
279145132Sanholt			DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
280145132Sanholt
281145132Sanholt			DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right);
282145132Sanholt			DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom);
283145132Sanholt
284145132Sanholt			DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);
285145132Sanholt			DMAOUTREG(MACH64_GUI_TRAJ_CNTL,
286145132Sanholt				  (MACH64_DST_X_LEFT_TO_RIGHT |
287145132Sanholt				   MACH64_DST_Y_TOP_TO_BOTTOM));
288145132Sanholt
289145132Sanholt			DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) |
290145132Sanholt							(fb_bpp << 4) |
291145132Sanholt							(fb_bpp << 8) |
292145132Sanholt							(fb_bpp << 16) |
293145132Sanholt							(fb_bpp << 28)));
294145132Sanholt
295145132Sanholt			DMAOUTREG(MACH64_DP_FRGD_CLR, clear_color);
296145132Sanholt			DMAOUTREG(MACH64_DP_WRITE_MASK, ctx->dp_write_mask);
297145132Sanholt			DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D |
298145132Sanholt						  MACH64_FRGD_MIX_S));
299145132Sanholt			DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR |
300145132Sanholt						  MACH64_FRGD_SRC_FRGD_CLR |
301145132Sanholt						  MACH64_MONO_SRC_ONE));
302145132Sanholt
303145132Sanholt		}
304145132Sanholt
305145132Sanholt		if (flags & MACH64_FRONT) {
306145132Sanholt
307145132Sanholt			DMAOUTREG(MACH64_DST_OFF_PITCH,
308145132Sanholt				  dev_priv->front_offset_pitch);
309145132Sanholt			DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x);
310145132Sanholt			DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
311145132Sanholt
312145132Sanholt		}
313145132Sanholt
314145132Sanholt		if (flags & MACH64_BACK) {
315145132Sanholt
316145132Sanholt			DMAOUTREG(MACH64_DST_OFF_PITCH,
317145132Sanholt				  dev_priv->back_offset_pitch);
318145132Sanholt			DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x);
319145132Sanholt			DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
320145132Sanholt
321145132Sanholt		}
322145132Sanholt
323145132Sanholt		if (flags & MACH64_DEPTH) {
324145132Sanholt			/* Setup for depth buffer clear
325145132Sanholt			 */
326145132Sanholt			DMAOUTREG(MACH64_Z_CNTL, 0);
327145132Sanholt			DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
328145132Sanholt
329145132Sanholt			DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right);
330145132Sanholt			DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom);
331145132Sanholt
332145132Sanholt			DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);
333145132Sanholt			DMAOUTREG(MACH64_GUI_TRAJ_CNTL,
334145132Sanholt				  (MACH64_DST_X_LEFT_TO_RIGHT |
335145132Sanholt				   MACH64_DST_Y_TOP_TO_BOTTOM));
336145132Sanholt
337145132Sanholt			DMAOUTREG(MACH64_DP_PIX_WIDTH, ((depth_bpp << 0) |
338145132Sanholt							(depth_bpp << 4) |
339145132Sanholt							(depth_bpp << 8) |
340145132Sanholt							(depth_bpp << 16) |
341145132Sanholt							(depth_bpp << 28)));
342145132Sanholt
343145132Sanholt			DMAOUTREG(MACH64_DP_FRGD_CLR, clear_depth);
344145132Sanholt			DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff);
345145132Sanholt			DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D |
346145132Sanholt						  MACH64_FRGD_MIX_S));
347145132Sanholt			DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR |
348145132Sanholt						  MACH64_FRGD_SRC_FRGD_CLR |
349145132Sanholt						  MACH64_MONO_SRC_ONE));
350145132Sanholt
351145132Sanholt			DMAOUTREG(MACH64_DST_OFF_PITCH,
352145132Sanholt				  dev_priv->depth_offset_pitch);
353145132Sanholt			DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x);
354145132Sanholt			DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
355145132Sanholt		}
356145132Sanholt	}
357145132Sanholt
358145132Sanholt	DMAADVANCE(dev_priv, 1);
359145132Sanholt
360145132Sanholt	return 0;
361145132Sanholt}
362145132Sanholt
363182080Srnolandstatic int mach64_dma_dispatch_swap(struct drm_device * dev,
364182080Srnoland				    struct drm_file *file_priv)
365145132Sanholt{
366145132Sanholt	drm_mach64_private_t *dev_priv = dev->dev_private;
367145132Sanholt	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
368145132Sanholt	int nbox = sarea_priv->nbox;
369182080Srnoland	struct drm_clip_rect *pbox = sarea_priv->boxes;
370145132Sanholt	u32 fb_bpp;
371145132Sanholt	int i;
372145132Sanholt	DMALOCALS;
373145132Sanholt
374182080Srnoland	DRM_DEBUG("\n");
375145132Sanholt
376145132Sanholt	switch (dev_priv->fb_bpp) {
377145132Sanholt	case 16:
378145132Sanholt		fb_bpp = MACH64_DATATYPE_RGB565;
379145132Sanholt		break;
380145132Sanholt	case 32:
381145132Sanholt	default:
382145132Sanholt		fb_bpp = MACH64_DATATYPE_ARGB8888;
383145132Sanholt		break;
384145132Sanholt	}
385145132Sanholt
386145132Sanholt	if (!nbox)
387145132Sanholt		return 0;
388145132Sanholt
389182080Srnoland	DMAGETPTR(file_priv, dev_priv, 13 + nbox * 4);	/* returns on failure to get buffer */
390145132Sanholt
391145132Sanholt	DMAOUTREG(MACH64_Z_CNTL, 0);
392145132Sanholt	DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
393145132Sanholt
394145132Sanholt	DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16));	/* no scissor */
395145132Sanholt	DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16));
396145132Sanholt
397145132Sanholt	DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);
398145132Sanholt	DMAOUTREG(MACH64_GUI_TRAJ_CNTL, (MACH64_DST_X_LEFT_TO_RIGHT |
399145132Sanholt					 MACH64_DST_Y_TOP_TO_BOTTOM));
400145132Sanholt
401145132Sanholt	DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) |
402145132Sanholt					(fb_bpp << 4) |
403145132Sanholt					(fb_bpp << 8) |
404145132Sanholt					(fb_bpp << 16) | (fb_bpp << 28)));
405145132Sanholt
406145132Sanholt	DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff);
407145132Sanholt	DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S));
408145132Sanholt	DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_BKGD_CLR |
409145132Sanholt				  MACH64_FRGD_SRC_BLIT | MACH64_MONO_SRC_ONE));
410145132Sanholt
411145132Sanholt	DMAOUTREG(MACH64_SRC_OFF_PITCH, dev_priv->back_offset_pitch);
412145132Sanholt	DMAOUTREG(MACH64_DST_OFF_PITCH, dev_priv->front_offset_pitch);
413145132Sanholt
414145132Sanholt	for (i = 0; i < nbox; i++) {
415145132Sanholt		int x = pbox[i].x1;
416145132Sanholt		int y = pbox[i].y1;
417145132Sanholt		int w = pbox[i].x2 - x;
418145132Sanholt		int h = pbox[i].y2 - y;
419145132Sanholt
420145132Sanholt		DRM_DEBUG("dispatch swap %d,%d-%d,%d\n",
421145132Sanholt			  pbox[i].x1, pbox[i].y1, pbox[i].x2, pbox[i].y2);
422145132Sanholt
423145132Sanholt		DMAOUTREG(MACH64_SRC_WIDTH1, w);
424145132Sanholt		DMAOUTREG(MACH64_SRC_Y_X, (x << 16) | y);
425145132Sanholt		DMAOUTREG(MACH64_DST_Y_X, (x << 16) | y);
426145132Sanholt		DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
427145132Sanholt
428145132Sanholt	}
429145132Sanholt
430145132Sanholt	DMAADVANCE(dev_priv, 1);
431145132Sanholt
432145132Sanholt	if (dev_priv->driver_mode == MACH64_MODE_DMA_ASYNC) {
433145132Sanholt		for (i = 0; i < MACH64_MAX_QUEUED_FRAMES - 1; i++) {
434145132Sanholt			dev_priv->frame_ofs[i] = dev_priv->frame_ofs[i + 1];
435145132Sanholt		}
436145132Sanholt		dev_priv->frame_ofs[i] = GETRINGOFFSET();
437145132Sanholt
438145132Sanholt		dev_priv->sarea_priv->frames_queued++;
439145132Sanholt	}
440145132Sanholt
441145132Sanholt	return 0;
442145132Sanholt}
443145132Sanholt
444145132Sanholtstatic int mach64_do_get_frames_queued(drm_mach64_private_t * dev_priv)
445145132Sanholt{
446145132Sanholt	drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
447145132Sanholt	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
448145132Sanholt	int i, start;
449145132Sanholt	u32 head, tail, ofs;
450145132Sanholt
451182080Srnoland	DRM_DEBUG("\n");
452145132Sanholt
453145132Sanholt	if (sarea_priv->frames_queued == 0)
454145132Sanholt		return 0;
455145132Sanholt
456145132Sanholt	tail = ring->tail;
457145132Sanholt	mach64_ring_tick(dev_priv, ring);
458145132Sanholt	head = ring->head;
459145132Sanholt
460145132Sanholt	start = (MACH64_MAX_QUEUED_FRAMES -
461145132Sanholt		 DRM_MIN(MACH64_MAX_QUEUED_FRAMES, sarea_priv->frames_queued));
462145132Sanholt
463145132Sanholt	if (head == tail) {
464145132Sanholt		sarea_priv->frames_queued = 0;
465145132Sanholt		for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) {
466145132Sanholt			dev_priv->frame_ofs[i] = ~0;
467145132Sanholt		}
468145132Sanholt		return 0;
469145132Sanholt	}
470145132Sanholt
471145132Sanholt	for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) {
472145132Sanholt		ofs = dev_priv->frame_ofs[i];
473145132Sanholt		DRM_DEBUG("frame_ofs[%d] ofs: %d\n", i, ofs);
474145132Sanholt		if (ofs == ~0 ||
475145132Sanholt		    (head < tail && (ofs < head || ofs >= tail)) ||
476145132Sanholt		    (head > tail && (ofs < head && ofs >= tail))) {
477145132Sanholt			sarea_priv->frames_queued =
478145132Sanholt			    (MACH64_MAX_QUEUED_FRAMES - 1) - i;
479145132Sanholt			dev_priv->frame_ofs[i] = ~0;
480145132Sanholt		}
481145132Sanholt	}
482145132Sanholt
483145132Sanholt	return sarea_priv->frames_queued;
484145132Sanholt}
485145132Sanholt
486145132Sanholt/* Copy and verify a client submited buffer.
487145132Sanholt * FIXME: Make an assembly optimized version
488145132Sanholt */
489182080Srnolandstatic __inline__ int copy_from_user_vertex(u32 *to,
490182080Srnoland					    const u32 __user *ufrom,
491182080Srnoland					    unsigned long bytes)
492145132Sanholt{
493145132Sanholt	unsigned long n = bytes;	/* dwords remaining in buffer */
494152909Sanholt	u32 *from, *orig_from;
495145132Sanholt
496152909Sanholt	from = drm_alloc(bytes, DRM_MEM_DRIVER);
497152909Sanholt	if (from == NULL)
498182080Srnoland		return -ENOMEM;
499152909Sanholt
500152909Sanholt	if (DRM_COPY_FROM_USER(from, ufrom, bytes)) {
501152909Sanholt		drm_free(from, bytes, DRM_MEM_DRIVER);
502182080Srnoland		return -EFAULT;
503145132Sanholt	}
504152909Sanholt	orig_from = from; /* we'll be modifying the "from" ptr, so save it */
505145132Sanholt
506145132Sanholt	n >>= 2;
507145132Sanholt
508145132Sanholt	while (n > 1) {
509145132Sanholt		u32 data, reg, count;
510145132Sanholt
511152909Sanholt		data = *from++;
512145132Sanholt
513145132Sanholt		n--;
514145132Sanholt
515145132Sanholt		reg = le32_to_cpu(data);
516145132Sanholt		count = (reg >> 16) + 1;
517145132Sanholt		if (count <= n) {
518145132Sanholt			n -= count;
519145132Sanholt			reg &= 0xffff;
520145132Sanholt
521145132Sanholt			/* This is an exact match of Mach64's Setup Engine registers,
522145132Sanholt			 * excluding SETUP_CNTL (1_C1).
523145132Sanholt			 */
524145132Sanholt			if ((reg >= 0x0190 && reg < 0x01c1) ||
525145132Sanholt			    (reg >= 0x01ca && reg <= 0x01cf)) {
526145132Sanholt				*to++ = data;
527152909Sanholt				memcpy(to, from, count << 2);
528152909Sanholt				from += count;
529145132Sanholt				to += count;
530145132Sanholt			} else {
531182080Srnoland				DRM_ERROR("Got bad command: 0x%04x\n", reg);
532152909Sanholt				drm_free(orig_from, bytes, DRM_MEM_DRIVER);
533182080Srnoland				return -EACCES;
534145132Sanholt			}
535145132Sanholt		} else {
536145132Sanholt			DRM_ERROR
537182080Srnoland			    ("Got bad command count(=%u) dwords remaining=%lu\n",
538182080Srnoland			     count, n);
539152909Sanholt			drm_free(orig_from, bytes, DRM_MEM_DRIVER);
540182080Srnoland			return -EINVAL;
541145132Sanholt		}
542145132Sanholt	}
543145132Sanholt
544152909Sanholt	drm_free(orig_from, bytes, DRM_MEM_DRIVER);
545145132Sanholt	if (n == 0)
546145132Sanholt		return 0;
547145132Sanholt	else {
548182080Srnoland		DRM_ERROR("Bad buf->used(=%lu)\n", bytes);
549182080Srnoland		return -EINVAL;
550145132Sanholt	}
551145132Sanholt}
552145132Sanholt
553182080Srnolandstatic int mach64_dma_dispatch_vertex(struct drm_device * dev,
554182080Srnoland				      struct drm_file *file_priv,
555182080Srnoland				      drm_mach64_vertex_t * vertex)
556145132Sanholt{
557145132Sanholt	drm_mach64_private_t *dev_priv = dev->dev_private;
558145132Sanholt	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
559182080Srnoland	struct drm_buf *copy_buf;
560182080Srnoland	void *buf = vertex->buf;
561182080Srnoland	unsigned long used = vertex->used;
562182080Srnoland	int ret = 0;
563182080Srnoland	int i = 0;
564145132Sanholt	int done = 0;
565145132Sanholt	int verify_ret = 0;
566145132Sanholt	DMALOCALS;
567145132Sanholt
568182080Srnoland	DRM_DEBUG("buf=%p used=%lu nbox=%d\n",
569182080Srnoland		  buf, used, sarea_priv->nbox);
570145132Sanholt
571182080Srnoland	if (!used)
572182080Srnoland		goto _vertex_done;
573145132Sanholt
574182080Srnoland	copy_buf = mach64_freelist_get(dev_priv);
575182080Srnoland	if (copy_buf == NULL) {
576182080Srnoland		DRM_ERROR("couldn't get buffer\n");
577182080Srnoland		return -EAGAIN;
578182080Srnoland	}
579145132Sanholt
580182080Srnoland	/* Mach64's vertex data is actually register writes. To avoid security
581182080Srnoland	 * compromises these register writes have to be verified and copied from
582182080Srnoland	 * user space into a private DMA buffer.
583182080Srnoland	 */
584182080Srnoland	verify_ret = copy_from_user_vertex(GETBUFPTR(copy_buf), buf, used);
585145132Sanholt
586182080Srnoland	if (verify_ret != 0) {
587182080Srnoland		mach64_freelist_put(dev_priv, copy_buf);
588182080Srnoland		goto _vertex_done;
589182080Srnoland	}
590145132Sanholt
591182080Srnoland	copy_buf->used = used;
592145132Sanholt
593182080Srnoland	DMASETPTR(copy_buf);
594182080Srnoland
595182080Srnoland	if (sarea_priv->dirty & ~MACH64_UPLOAD_CLIPRECTS) {
596182080Srnoland		ret = mach64_emit_state(file_priv, dev_priv);
597182080Srnoland		if (ret < 0)
598182080Srnoland			return ret;
599182080Srnoland	}
600182080Srnoland
601182080Srnoland	do {
602182080Srnoland		/* Emit the next cliprect */
603182080Srnoland		if (i < sarea_priv->nbox) {
604182080Srnoland			ret = mach64_emit_cliprect(file_priv, dev_priv,
605182080Srnoland						   &sarea_priv->boxes[i]);
606182080Srnoland			if (ret < 0) {
607182080Srnoland				/* failed to get buffer */
608182080Srnoland				return ret;
609182080Srnoland			} else if (ret != 0) {
610182080Srnoland				/* null intersection with scissor */
611182080Srnoland				continue;
612145132Sanholt			}
613182080Srnoland		}
614182080Srnoland		if ((i >= sarea_priv->nbox - 1))
615182080Srnoland			done = 1;
616145132Sanholt
617182080Srnoland		/* Add the buffer to the DMA queue */
618182080Srnoland		DMAADVANCE(dev_priv, done);
619145132Sanholt
620182080Srnoland	} while (++i < sarea_priv->nbox);
621145132Sanholt
622182080Srnoland	if (!done) {
623182080Srnoland		if (copy_buf->pending) {
624145132Sanholt			DMADISCARDBUF();
625182080Srnoland		} else {
626182080Srnoland			/* This buffer wasn't used (no cliprects), so place it
627182080Srnoland			 * back on the free list
628145132Sanholt			 */
629182080Srnoland			mach64_freelist_put(dev_priv, copy_buf);
630145132Sanholt		}
631145132Sanholt	}
632145132Sanholt
633182080Srnoland_vertex_done:
634145132Sanholt	sarea_priv->dirty &= ~MACH64_UPLOAD_CLIPRECTS;
635145132Sanholt	sarea_priv->nbox = 0;
636145132Sanholt
637145132Sanholt	return verify_ret;
638145132Sanholt}
639145132Sanholt
640182080Srnolandstatic __inline__ int copy_from_user_blit(u32 *to,
641182080Srnoland					  const u32 __user *ufrom,
642182080Srnoland					  unsigned long bytes)
643182080Srnoland{
644182080Srnoland	to = (u32 *)((char *)to + MACH64_HOSTDATA_BLIT_OFFSET);
645182080Srnoland
646182080Srnoland	if (DRM_COPY_FROM_USER(to, ufrom, bytes)) {
647182080Srnoland		return -EFAULT;
648182080Srnoland	}
649182080Srnoland
650182080Srnoland	return 0;
651182080Srnoland}
652182080Srnoland
653182080Srnolandstatic int mach64_dma_dispatch_blit(struct drm_device * dev,
654182080Srnoland				    struct drm_file *file_priv,
655145132Sanholt				    drm_mach64_blit_t * blit)
656145132Sanholt{
657145132Sanholt	drm_mach64_private_t *dev_priv = dev->dev_private;
658145132Sanholt	int dword_shift, dwords;
659182080Srnoland	unsigned long used;
660182080Srnoland	struct drm_buf *copy_buf;
661182080Srnoland	int verify_ret = 0;
662145132Sanholt	DMALOCALS;
663145132Sanholt
664145132Sanholt	/* The compiler won't optimize away a division by a variable,
665145132Sanholt	 * even if the only legal values are powers of two.  Thus, we'll
666145132Sanholt	 * use a shift instead.
667145132Sanholt	 */
668145132Sanholt	switch (blit->format) {
669145132Sanholt	case MACH64_DATATYPE_ARGB8888:
670145132Sanholt		dword_shift = 0;
671145132Sanholt		break;
672145132Sanholt	case MACH64_DATATYPE_ARGB1555:
673145132Sanholt	case MACH64_DATATYPE_RGB565:
674145132Sanholt	case MACH64_DATATYPE_VYUY422:
675145132Sanholt	case MACH64_DATATYPE_YVYU422:
676145132Sanholt	case MACH64_DATATYPE_ARGB4444:
677145132Sanholt		dword_shift = 1;
678145132Sanholt		break;
679145132Sanholt	case MACH64_DATATYPE_CI8:
680145132Sanholt	case MACH64_DATATYPE_RGB8:
681145132Sanholt		dword_shift = 2;
682145132Sanholt		break;
683145132Sanholt	default:
684145132Sanholt		DRM_ERROR("invalid blit format %d\n", blit->format);
685182080Srnoland		return -EINVAL;
686145132Sanholt	}
687145132Sanholt
688145132Sanholt	/* Set buf->used to the bytes of blit data based on the blit dimensions
689145132Sanholt	 * and verify the size.  When the setup is emitted to the buffer with
690145132Sanholt	 * the DMA* macros below, buf->used is incremented to include the bytes
691145132Sanholt	 * used for setup as well as the blit data.
692145132Sanholt	 */
693145132Sanholt	dwords = (blit->width * blit->height) >> dword_shift;
694182080Srnoland	used = dwords << 2;
695182080Srnoland	if (used <= 0 ||
696182080Srnoland	    used > MACH64_BUFFER_SIZE - MACH64_HOSTDATA_BLIT_OFFSET) {
697182080Srnoland		DRM_ERROR("Invalid blit size: %lu bytes\n", used);
698182080Srnoland		return -EINVAL;
699145132Sanholt	}
700145132Sanholt
701182080Srnoland	copy_buf = mach64_freelist_get(dev_priv);
702182080Srnoland	if (copy_buf == NULL) {
703182080Srnoland		DRM_ERROR("couldn't get buffer\n");
704182080Srnoland		return -EAGAIN;
705182080Srnoland	}
706182080Srnoland
707182080Srnoland	/* Copy the blit data from userspace.
708182080Srnoland	 *
709182080Srnoland	 * XXX: This is overkill. The most efficient solution would be having
710182080Srnoland	 * two sets of buffers (one set private for vertex data, the other set
711182080Srnoland	 * client-writable for blits). However that would bring more complexity
712182080Srnoland	 * and would break backward compatability. The solution currently
713182080Srnoland	 * implemented is keeping all buffers private, allowing to secure the
714182080Srnoland	 * driver, without increasing complexity at the expense of some speed
715182080Srnoland	 * transfering data.
716182080Srnoland	 */
717182080Srnoland	verify_ret = copy_from_user_blit(GETBUFPTR(copy_buf), blit->buf, used);
718182080Srnoland
719182080Srnoland	if (verify_ret != 0) {
720182080Srnoland		mach64_freelist_put(dev_priv, copy_buf);
721182080Srnoland		goto _blit_done;
722182080Srnoland	}
723182080Srnoland
724182080Srnoland	copy_buf->used = used;
725182080Srnoland
726145132Sanholt	/* FIXME: Use a last buffer flag and reduce the state emitted for subsequent,
727145132Sanholt	 * continuation buffers?
728145132Sanholt	 */
729145132Sanholt
730145132Sanholt	/* Blit via BM_HOSTDATA (gui-master) - like HOST_DATA[0-15], but doesn't require
731145132Sanholt	 * a register command every 16 dwords.  State setup is added at the start of the
732145132Sanholt	 * buffer -- the client leaves space for this based on MACH64_HOSTDATA_BLIT_OFFSET
733145132Sanholt	 */
734182080Srnoland	DMASETPTR(copy_buf);
735145132Sanholt
736145132Sanholt	DMAOUTREG(MACH64_Z_CNTL, 0);
737145132Sanholt	DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
738145132Sanholt
739145132Sanholt	DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16));	/* no scissor */
740145132Sanholt	DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16));
741145132Sanholt
742145132Sanholt	DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);	/* disable */
743145132Sanholt	DMAOUTREG(MACH64_GUI_TRAJ_CNTL,
744145132Sanholt		  MACH64_DST_X_LEFT_TO_RIGHT | MACH64_DST_Y_TOP_TO_BOTTOM);
745145132Sanholt
746145132Sanholt	DMAOUTREG(MACH64_DP_PIX_WIDTH, (blit->format << 0)	/* dst pix width */
747145132Sanholt		  |(blit->format << 4)	/* composite pix width */
748145132Sanholt		  |(blit->format << 8)	/* src pix width */
749145132Sanholt		  |(blit->format << 16)	/* host data pix width */
750145132Sanholt		  |(blit->format << 28)	/* scaler/3D pix width */
751145132Sanholt	    );
752145132Sanholt
753145132Sanholt	DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff);	/* enable all planes */
754145132Sanholt	DMAOUTREG(MACH64_DP_MIX, MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S);
755145132Sanholt	DMAOUTREG(MACH64_DP_SRC,
756145132Sanholt		  MACH64_BKGD_SRC_BKGD_CLR
757145132Sanholt		  | MACH64_FRGD_SRC_HOST | MACH64_MONO_SRC_ONE);
758145132Sanholt
759145132Sanholt	DMAOUTREG(MACH64_DST_OFF_PITCH,
760145132Sanholt		  (blit->pitch << 22) | (blit->offset >> 3));
761145132Sanholt	DMAOUTREG(MACH64_DST_X_Y, (blit->y << 16) | blit->x);
762145132Sanholt	DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (blit->height << 16) | blit->width);
763145132Sanholt
764182080Srnoland	DRM_DEBUG("%lu bytes\n", used);
765145132Sanholt
766145132Sanholt	/* Add the buffer to the queue */
767145132Sanholt	DMAADVANCEHOSTDATA(dev_priv);
768145132Sanholt
769182080Srnoland_blit_done:
770182080Srnoland	return verify_ret;
771145132Sanholt}
772145132Sanholt
773145132Sanholt/* ================================================================
774145132Sanholt * IOCTL functions
775145132Sanholt */
776145132Sanholt
777182080Srnolandint mach64_dma_clear(struct drm_device *dev, void *data,
778182080Srnoland		     struct drm_file *file_priv)
779145132Sanholt{
780145132Sanholt	drm_mach64_private_t *dev_priv = dev->dev_private;
781145132Sanholt	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
782182080Srnoland	drm_mach64_clear_t *clear = data;
783145132Sanholt	int ret;
784145132Sanholt
785182080Srnoland	DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
786145132Sanholt
787182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
788145132Sanholt
789145132Sanholt	if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
790145132Sanholt		sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
791145132Sanholt
792182080Srnoland	ret = mach64_dma_dispatch_clear(dev, file_priv, clear->flags,
793182080Srnoland					clear->x, clear->y, clear->w, clear->h,
794182080Srnoland					clear->clear_color,
795182080Srnoland					clear->clear_depth);
796145132Sanholt
797145132Sanholt	/* Make sure we restore the 3D state next time.
798145132Sanholt	 */
799145132Sanholt	sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC);
800145132Sanholt	return ret;
801145132Sanholt}
802145132Sanholt
803182080Srnolandint mach64_dma_swap(struct drm_device *dev, void *data,
804182080Srnoland		    struct drm_file *file_priv)
805145132Sanholt{
806145132Sanholt	drm_mach64_private_t *dev_priv = dev->dev_private;
807145132Sanholt	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
808145132Sanholt	int ret;
809145132Sanholt
810182080Srnoland	DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
811145132Sanholt
812182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
813145132Sanholt
814145132Sanholt	if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
815145132Sanholt		sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
816145132Sanholt
817182080Srnoland	ret = mach64_dma_dispatch_swap(dev, file_priv);
818145132Sanholt
819145132Sanholt	/* Make sure we restore the 3D state next time.
820145132Sanholt	 */
821145132Sanholt	sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC);
822145132Sanholt	return ret;
823145132Sanholt}
824145132Sanholt
825182080Srnolandint mach64_dma_vertex(struct drm_device *dev, void *data,
826182080Srnoland		      struct drm_file *file_priv)
827145132Sanholt{
828145132Sanholt	drm_mach64_private_t *dev_priv = dev->dev_private;
829198332Sbrueffer	drm_mach64_sarea_t *sarea_priv;
830182080Srnoland	drm_mach64_vertex_t *vertex = data;
831145132Sanholt
832182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
833145132Sanholt
834145132Sanholt	if (!dev_priv) {
835182080Srnoland		DRM_ERROR("called with no initialization\n");
836182080Srnoland		return -EINVAL;
837145132Sanholt	}
838198332Sbrueffer	sarea_priv = dev_priv->sarea_priv;
839145132Sanholt
840182080Srnoland	DRM_DEBUG("pid=%d buf=%p used=%lu discard=%d\n",
841182080Srnoland		  DRM_CURRENTPID,
842182080Srnoland		  vertex->buf, vertex->used, vertex->discard);
843145132Sanholt
844182080Srnoland	if (vertex->prim < 0 || vertex->prim > MACH64_PRIM_POLYGON) {
845182080Srnoland		DRM_ERROR("buffer prim %d\n", vertex->prim);
846182080Srnoland		return -EINVAL;
847145132Sanholt	}
848145132Sanholt
849182080Srnoland	if (vertex->used > MACH64_BUFFER_SIZE || (vertex->used & 3) != 0) {
850145132Sanholt		DRM_ERROR("Invalid vertex buffer size: %lu bytes\n",
851182080Srnoland			  vertex->used);
852182080Srnoland		return -EINVAL;
853145132Sanholt	}
854145132Sanholt
855145132Sanholt	if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
856145132Sanholt		sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
857145132Sanholt
858182080Srnoland	return mach64_dma_dispatch_vertex(dev, file_priv, vertex);
859145132Sanholt}
860145132Sanholt
861182080Srnolandint mach64_dma_blit(struct drm_device *dev, void *data,
862182080Srnoland		    struct drm_file *file_priv)
863145132Sanholt{
864145132Sanholt	drm_mach64_private_t *dev_priv = dev->dev_private;
865145132Sanholt	drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
866182080Srnoland	drm_mach64_blit_t *blit = data;
867145132Sanholt	int ret;
868145132Sanholt
869182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
870145132Sanholt
871182080Srnoland	ret = mach64_dma_dispatch_blit(dev, file_priv, blit);
872145132Sanholt
873145132Sanholt	/* Make sure we restore the 3D state next time.
874145132Sanholt	 */
875145132Sanholt	sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT |
876145132Sanholt			      MACH64_UPLOAD_MISC | MACH64_UPLOAD_CLIPRECTS);
877145132Sanholt
878145132Sanholt	return ret;
879145132Sanholt}
880145132Sanholt
881182080Srnolandint mach64_get_param(struct drm_device *dev, void *data,
882182080Srnoland		     struct drm_file *file_priv)
883145132Sanholt{
884145132Sanholt	drm_mach64_private_t *dev_priv = dev->dev_private;
885182080Srnoland	drm_mach64_getparam_t *param = data;
886145132Sanholt	int value;
887145132Sanholt
888182080Srnoland	DRM_DEBUG("\n");
889145132Sanholt
890145132Sanholt	if (!dev_priv) {
891182080Srnoland		DRM_ERROR("called with no initialization\n");
892182080Srnoland		return -EINVAL;
893145132Sanholt	}
894145132Sanholt
895182080Srnoland	switch (param->param) {
896145132Sanholt	case MACH64_PARAM_FRAMES_QUEUED:
897145132Sanholt		/* Needs lock since it calls mach64_ring_tick() */
898182080Srnoland		LOCK_TEST_WITH_RETURN(dev, file_priv);
899145132Sanholt		value = mach64_do_get_frames_queued(dev_priv);
900145132Sanholt		break;
901145132Sanholt	case MACH64_PARAM_IRQ_NR:
902145132Sanholt		value = dev->irq;
903145132Sanholt		break;
904145132Sanholt	default:
905182080Srnoland		return -EINVAL;
906145132Sanholt	}
907145132Sanholt
908182080Srnoland	if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
909145132Sanholt		DRM_ERROR("copy_to_user\n");
910182080Srnoland		return -EFAULT;
911145132Sanholt	}
912145132Sanholt
913145132Sanholt	return 0;
914145132Sanholt}
915