1254885Sdumbbell/* radeon_state.c -- State support for Radeon -*- linux-c -*- */
2254885Sdumbbell/*
3254885Sdumbbell * Copyright 2000 VA Linux Systems, Inc., Fremont, California.
4254885Sdumbbell * All Rights Reserved.
5254885Sdumbbell *
6254885Sdumbbell * Permission is hereby granted, free of charge, to any person obtaining a
7254885Sdumbbell * copy of this software and associated documentation files (the "Software"),
8254885Sdumbbell * to deal in the Software without restriction, including without limitation
9254885Sdumbbell * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10254885Sdumbbell * and/or sell copies of the Software, and to permit persons to whom the
11254885Sdumbbell * Software is furnished to do so, subject to the following conditions:
12254885Sdumbbell *
13254885Sdumbbell * The above copyright notice and this permission notice (including the next
14254885Sdumbbell * paragraph) shall be included in all copies or substantial portions of the
15254885Sdumbbell * Software.
16254885Sdumbbell *
17254885Sdumbbell * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18254885Sdumbbell * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19254885Sdumbbell * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20254885Sdumbbell * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21254885Sdumbbell * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22254885Sdumbbell * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23254885Sdumbbell * DEALINGS IN THE SOFTWARE.
24254885Sdumbbell *
25254885Sdumbbell * Authors:
26254885Sdumbbell *    Gareth Hughes <gareth@valinux.com>
27254885Sdumbbell *    Kevin E. Martin <martin@valinux.com>
28254885Sdumbbell */
29254885Sdumbbell
30254885Sdumbbell#include <sys/cdefs.h>
31254885Sdumbbell__FBSDID("$FreeBSD$");
32254885Sdumbbell
33254885Sdumbbell#include <dev/drm2/drmP.h>
34254885Sdumbbell#include <dev/drm2/drm_buffer.h>
35254885Sdumbbell#include <dev/drm2/radeon/radeon_drm.h>
36254885Sdumbbell#include "radeon_drv.h"
37254885Sdumbbell
38254885Sdumbbell/* ================================================================
39254885Sdumbbell * Helper functions for client state checking and fixup
40254885Sdumbbell */
41254885Sdumbbell
42254885Sdumbbellstatic __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
43254885Sdumbbell						    dev_priv,
44254885Sdumbbell						    struct drm_file * file_priv,
45254885Sdumbbell						    u32 *offset)
46254885Sdumbbell{
47254885Sdumbbell	u64 off = *offset;
48254885Sdumbbell	u32 fb_end = dev_priv->fb_location + dev_priv->fb_size - 1;
49254885Sdumbbell	struct drm_radeon_driver_file_fields *radeon_priv;
50254885Sdumbbell
51254885Sdumbbell	/* Hrm ... the story of the offset ... So this function converts
52254885Sdumbbell	 * the various ideas of what userland clients might have for an
53254885Sdumbbell	 * offset in the card address space into an offset into the card
54254885Sdumbbell	 * address space :) So with a sane client, it should just keep
55254885Sdumbbell	 * the value intact and just do some boundary checking. However,
56254885Sdumbbell	 * not all clients are sane. Some older clients pass us 0 based
57254885Sdumbbell	 * offsets relative to the start of the framebuffer and some may
58254885Sdumbbell	 * assume the AGP aperture it appended to the framebuffer, so we
59254885Sdumbbell	 * try to detect those cases and fix them up.
60254885Sdumbbell	 *
61254885Sdumbbell	 * Note: It might be a good idea here to make sure the offset lands
62254885Sdumbbell	 * in some "allowed" area to protect things like the PCIE GART...
63254885Sdumbbell	 */
64254885Sdumbbell
65254885Sdumbbell	/* First, the best case, the offset already lands in either the
66254885Sdumbbell	 * framebuffer or the GART mapped space
67254885Sdumbbell	 */
68254885Sdumbbell	if (radeon_check_offset(dev_priv, off))
69254885Sdumbbell		return 0;
70254885Sdumbbell
71254885Sdumbbell	/* Ok, that didn't happen... now check if we have a zero based
72254885Sdumbbell	 * offset that fits in the framebuffer + gart space, apply the
73254885Sdumbbell	 * magic offset we get from SETPARAM or calculated from fb_location
74254885Sdumbbell	 */
75254885Sdumbbell	if (off < (dev_priv->fb_size + dev_priv->gart_size)) {
76254885Sdumbbell		radeon_priv = file_priv->driver_priv;
77254885Sdumbbell		off += radeon_priv->radeon_fb_delta;
78254885Sdumbbell	}
79254885Sdumbbell
80254885Sdumbbell	/* Finally, assume we aimed at a GART offset if beyond the fb */
81254885Sdumbbell	if (off > fb_end)
82254885Sdumbbell		off = off - fb_end - 1 + dev_priv->gart_vm_start;
83254885Sdumbbell
84254885Sdumbbell	/* Now recheck and fail if out of bounds */
85254885Sdumbbell	if (radeon_check_offset(dev_priv, off)) {
86254885Sdumbbell		DRM_DEBUG("offset fixed up to 0x%x\n", (unsigned int)off);
87254885Sdumbbell		*offset = off;
88254885Sdumbbell		return 0;
89254885Sdumbbell	}
90254885Sdumbbell	return -EINVAL;
91254885Sdumbbell}
92254885Sdumbbell
93254885Sdumbbellstatic __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
94254885Sdumbbell						     dev_priv,
95254885Sdumbbell						     struct drm_file *file_priv,
96254885Sdumbbell						     int id, struct drm_buffer *buf)
97254885Sdumbbell{
98254885Sdumbbell	u32 *data;
99254885Sdumbbell	switch (id) {
100254885Sdumbbell
101254885Sdumbbell	case RADEON_EMIT_PP_MISC:
102254885Sdumbbell		data = drm_buffer_pointer_to_dword(buf,
103254885Sdumbbell			(RADEON_RB3D_DEPTHOFFSET - RADEON_PP_MISC) / 4);
104254885Sdumbbell
105254885Sdumbbell		if (radeon_check_and_fixup_offset(dev_priv, file_priv, data)) {
106254885Sdumbbell			DRM_ERROR("Invalid depth buffer offset\n");
107254885Sdumbbell			return -EINVAL;
108254885Sdumbbell		}
109254885Sdumbbell		dev_priv->have_z_offset = 1;
110254885Sdumbbell		break;
111254885Sdumbbell
112254885Sdumbbell	case RADEON_EMIT_PP_CNTL:
113254885Sdumbbell		data = drm_buffer_pointer_to_dword(buf,
114254885Sdumbbell			(RADEON_RB3D_COLOROFFSET - RADEON_PP_CNTL) / 4);
115254885Sdumbbell
116254885Sdumbbell		if (radeon_check_and_fixup_offset(dev_priv, file_priv, data)) {
117254885Sdumbbell			DRM_ERROR("Invalid colour buffer offset\n");
118254885Sdumbbell			return -EINVAL;
119254885Sdumbbell		}
120254885Sdumbbell		break;
121254885Sdumbbell
122254885Sdumbbell	case R200_EMIT_PP_TXOFFSET_0:
123254885Sdumbbell	case R200_EMIT_PP_TXOFFSET_1:
124254885Sdumbbell	case R200_EMIT_PP_TXOFFSET_2:
125254885Sdumbbell	case R200_EMIT_PP_TXOFFSET_3:
126254885Sdumbbell	case R200_EMIT_PP_TXOFFSET_4:
127254885Sdumbbell	case R200_EMIT_PP_TXOFFSET_5:
128254885Sdumbbell		data = drm_buffer_pointer_to_dword(buf, 0);
129254885Sdumbbell		if (radeon_check_and_fixup_offset(dev_priv, file_priv, data)) {
130254885Sdumbbell			DRM_ERROR("Invalid R200 texture offset\n");
131254885Sdumbbell			return -EINVAL;
132254885Sdumbbell		}
133254885Sdumbbell		break;
134254885Sdumbbell
135254885Sdumbbell	case RADEON_EMIT_PP_TXFILTER_0:
136254885Sdumbbell	case RADEON_EMIT_PP_TXFILTER_1:
137254885Sdumbbell	case RADEON_EMIT_PP_TXFILTER_2:
138254885Sdumbbell		data = drm_buffer_pointer_to_dword(buf,
139254885Sdumbbell			(RADEON_PP_TXOFFSET_0 - RADEON_PP_TXFILTER_0) / 4);
140254885Sdumbbell		if (radeon_check_and_fixup_offset(dev_priv, file_priv, data)) {
141254885Sdumbbell			DRM_ERROR("Invalid R100 texture offset\n");
142254885Sdumbbell			return -EINVAL;
143254885Sdumbbell		}
144254885Sdumbbell		break;
145254885Sdumbbell
146254885Sdumbbell	case R200_EMIT_PP_CUBIC_OFFSETS_0:
147254885Sdumbbell	case R200_EMIT_PP_CUBIC_OFFSETS_1:
148254885Sdumbbell	case R200_EMIT_PP_CUBIC_OFFSETS_2:
149254885Sdumbbell	case R200_EMIT_PP_CUBIC_OFFSETS_3:
150254885Sdumbbell	case R200_EMIT_PP_CUBIC_OFFSETS_4:
151254885Sdumbbell	case R200_EMIT_PP_CUBIC_OFFSETS_5:{
152254885Sdumbbell			int i;
153254885Sdumbbell			for (i = 0; i < 5; i++) {
154254885Sdumbbell				data = drm_buffer_pointer_to_dword(buf, i);
155254885Sdumbbell				if (radeon_check_and_fixup_offset(dev_priv,
156254885Sdumbbell								  file_priv,
157254885Sdumbbell								  data)) {
158254885Sdumbbell					DRM_ERROR
159254885Sdumbbell					    ("Invalid R200 cubic texture offset\n");
160254885Sdumbbell					return -EINVAL;
161254885Sdumbbell				}
162254885Sdumbbell			}
163254885Sdumbbell			break;
164254885Sdumbbell		}
165254885Sdumbbell
166254885Sdumbbell	case RADEON_EMIT_PP_CUBIC_OFFSETS_T0:
167254885Sdumbbell	case RADEON_EMIT_PP_CUBIC_OFFSETS_T1:
168254885Sdumbbell	case RADEON_EMIT_PP_CUBIC_OFFSETS_T2:{
169254885Sdumbbell			int i;
170254885Sdumbbell			for (i = 0; i < 5; i++) {
171254885Sdumbbell				data = drm_buffer_pointer_to_dword(buf, i);
172254885Sdumbbell				if (radeon_check_and_fixup_offset(dev_priv,
173254885Sdumbbell								  file_priv,
174254885Sdumbbell								  data)) {
175254885Sdumbbell					DRM_ERROR
176254885Sdumbbell					    ("Invalid R100 cubic texture offset\n");
177254885Sdumbbell					return -EINVAL;
178254885Sdumbbell				}
179254885Sdumbbell			}
180254885Sdumbbell		}
181254885Sdumbbell		break;
182254885Sdumbbell
183254885Sdumbbell	case R200_EMIT_VAP_CTL:{
184254885Sdumbbell			RING_LOCALS;
185254885Sdumbbell			BEGIN_RING(2);
186254885Sdumbbell			OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
187254885Sdumbbell			ADVANCE_RING();
188254885Sdumbbell		}
189254885Sdumbbell		break;
190254885Sdumbbell
191254885Sdumbbell	case RADEON_EMIT_RB3D_COLORPITCH:
192254885Sdumbbell	case RADEON_EMIT_RE_LINE_PATTERN:
193254885Sdumbbell	case RADEON_EMIT_SE_LINE_WIDTH:
194254885Sdumbbell	case RADEON_EMIT_PP_LUM_MATRIX:
195254885Sdumbbell	case RADEON_EMIT_PP_ROT_MATRIX_0:
196254885Sdumbbell	case RADEON_EMIT_RB3D_STENCILREFMASK:
197254885Sdumbbell	case RADEON_EMIT_SE_VPORT_XSCALE:
198254885Sdumbbell	case RADEON_EMIT_SE_CNTL:
199254885Sdumbbell	case RADEON_EMIT_SE_CNTL_STATUS:
200254885Sdumbbell	case RADEON_EMIT_RE_MISC:
201254885Sdumbbell	case RADEON_EMIT_PP_BORDER_COLOR_0:
202254885Sdumbbell	case RADEON_EMIT_PP_BORDER_COLOR_1:
203254885Sdumbbell	case RADEON_EMIT_PP_BORDER_COLOR_2:
204254885Sdumbbell	case RADEON_EMIT_SE_ZBIAS_FACTOR:
205254885Sdumbbell	case RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT:
206254885Sdumbbell	case RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED:
207254885Sdumbbell	case R200_EMIT_PP_TXCBLEND_0:
208254885Sdumbbell	case R200_EMIT_PP_TXCBLEND_1:
209254885Sdumbbell	case R200_EMIT_PP_TXCBLEND_2:
210254885Sdumbbell	case R200_EMIT_PP_TXCBLEND_3:
211254885Sdumbbell	case R200_EMIT_PP_TXCBLEND_4:
212254885Sdumbbell	case R200_EMIT_PP_TXCBLEND_5:
213254885Sdumbbell	case R200_EMIT_PP_TXCBLEND_6:
214254885Sdumbbell	case R200_EMIT_PP_TXCBLEND_7:
215254885Sdumbbell	case R200_EMIT_TCL_LIGHT_MODEL_CTL_0:
216254885Sdumbbell	case R200_EMIT_TFACTOR_0:
217254885Sdumbbell	case R200_EMIT_VTX_FMT_0:
218254885Sdumbbell	case R200_EMIT_MATRIX_SELECT_0:
219254885Sdumbbell	case R200_EMIT_TEX_PROC_CTL_2:
220254885Sdumbbell	case R200_EMIT_TCL_UCP_VERT_BLEND_CTL:
221254885Sdumbbell	case R200_EMIT_PP_TXFILTER_0:
222254885Sdumbbell	case R200_EMIT_PP_TXFILTER_1:
223254885Sdumbbell	case R200_EMIT_PP_TXFILTER_2:
224254885Sdumbbell	case R200_EMIT_PP_TXFILTER_3:
225254885Sdumbbell	case R200_EMIT_PP_TXFILTER_4:
226254885Sdumbbell	case R200_EMIT_PP_TXFILTER_5:
227254885Sdumbbell	case R200_EMIT_VTE_CNTL:
228254885Sdumbbell	case R200_EMIT_OUTPUT_VTX_COMP_SEL:
229254885Sdumbbell	case R200_EMIT_PP_TAM_DEBUG3:
230254885Sdumbbell	case R200_EMIT_PP_CNTL_X:
231254885Sdumbbell	case R200_EMIT_RB3D_DEPTHXY_OFFSET:
232254885Sdumbbell	case R200_EMIT_RE_AUX_SCISSOR_CNTL:
233254885Sdumbbell	case R200_EMIT_RE_SCISSOR_TL_0:
234254885Sdumbbell	case R200_EMIT_RE_SCISSOR_TL_1:
235254885Sdumbbell	case R200_EMIT_RE_SCISSOR_TL_2:
236254885Sdumbbell	case R200_EMIT_SE_VAP_CNTL_STATUS:
237254885Sdumbbell	case R200_EMIT_SE_VTX_STATE_CNTL:
238254885Sdumbbell	case R200_EMIT_RE_POINTSIZE:
239254885Sdumbbell	case R200_EMIT_TCL_INPUT_VTX_VECTOR_ADDR_0:
240254885Sdumbbell	case R200_EMIT_PP_CUBIC_FACES_0:
241254885Sdumbbell	case R200_EMIT_PP_CUBIC_FACES_1:
242254885Sdumbbell	case R200_EMIT_PP_CUBIC_FACES_2:
243254885Sdumbbell	case R200_EMIT_PP_CUBIC_FACES_3:
244254885Sdumbbell	case R200_EMIT_PP_CUBIC_FACES_4:
245254885Sdumbbell	case R200_EMIT_PP_CUBIC_FACES_5:
246254885Sdumbbell	case RADEON_EMIT_PP_TEX_SIZE_0:
247254885Sdumbbell	case RADEON_EMIT_PP_TEX_SIZE_1:
248254885Sdumbbell	case RADEON_EMIT_PP_TEX_SIZE_2:
249254885Sdumbbell	case R200_EMIT_RB3D_BLENDCOLOR:
250254885Sdumbbell	case R200_EMIT_TCL_POINT_SPRITE_CNTL:
251254885Sdumbbell	case RADEON_EMIT_PP_CUBIC_FACES_0:
252254885Sdumbbell	case RADEON_EMIT_PP_CUBIC_FACES_1:
253254885Sdumbbell	case RADEON_EMIT_PP_CUBIC_FACES_2:
254254885Sdumbbell	case R200_EMIT_PP_TRI_PERF_CNTL:
255254885Sdumbbell	case R200_EMIT_PP_AFS_0:
256254885Sdumbbell	case R200_EMIT_PP_AFS_1:
257254885Sdumbbell	case R200_EMIT_ATF_TFACTOR:
258254885Sdumbbell	case R200_EMIT_PP_TXCTLALL_0:
259254885Sdumbbell	case R200_EMIT_PP_TXCTLALL_1:
260254885Sdumbbell	case R200_EMIT_PP_TXCTLALL_2:
261254885Sdumbbell	case R200_EMIT_PP_TXCTLALL_3:
262254885Sdumbbell	case R200_EMIT_PP_TXCTLALL_4:
263254885Sdumbbell	case R200_EMIT_PP_TXCTLALL_5:
264254885Sdumbbell	case R200_EMIT_VAP_PVS_CNTL:
265254885Sdumbbell		/* These packets don't contain memory offsets */
266254885Sdumbbell		break;
267254885Sdumbbell
268254885Sdumbbell	default:
269254885Sdumbbell		DRM_ERROR("Unknown state packet ID %d\n", id);
270254885Sdumbbell		return -EINVAL;
271254885Sdumbbell	}
272254885Sdumbbell
273254885Sdumbbell	return 0;
274254885Sdumbbell}
275254885Sdumbbell
276254885Sdumbbellstatic int radeon_check_and_fixup_packet3(drm_radeon_private_t *
277254885Sdumbbell					  dev_priv,
278254885Sdumbbell					  struct drm_file *file_priv,
279254885Sdumbbell					  drm_radeon_kcmd_buffer_t *
280254885Sdumbbell					  cmdbuf,
281254885Sdumbbell					  unsigned int *cmdsz)
282254885Sdumbbell{
283254885Sdumbbell	u32 *cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
284254885Sdumbbell	u32 offset, narrays;
285254885Sdumbbell	int count, i, k;
286254885Sdumbbell
287254885Sdumbbell	count = ((*cmd & RADEON_CP_PACKET_COUNT_MASK) >> 16);
288254885Sdumbbell	*cmdsz = 2 + count;
289254885Sdumbbell
290254885Sdumbbell	if ((*cmd & 0xc0000000) != RADEON_CP_PACKET3) {
291254885Sdumbbell		DRM_ERROR("Not a type 3 packet\n");
292254885Sdumbbell		return -EINVAL;
293254885Sdumbbell	}
294254885Sdumbbell
295254885Sdumbbell	if (4 * *cmdsz > drm_buffer_unprocessed(cmdbuf->buffer)) {
296254885Sdumbbell		DRM_ERROR("Packet size larger than size of data provided\n");
297254885Sdumbbell		return -EINVAL;
298254885Sdumbbell	}
299254885Sdumbbell
300254885Sdumbbell	switch (*cmd & 0xff00) {
301254885Sdumbbell	/* XXX Are there old drivers needing other packets? */
302254885Sdumbbell
303254885Sdumbbell	case RADEON_3D_DRAW_IMMD:
304254885Sdumbbell	case RADEON_3D_DRAW_VBUF:
305254885Sdumbbell	case RADEON_3D_DRAW_INDX:
306254885Sdumbbell	case RADEON_WAIT_FOR_IDLE:
307254885Sdumbbell	case RADEON_CP_NOP:
308254885Sdumbbell	case RADEON_3D_CLEAR_ZMASK:
309254885Sdumbbell/*	case RADEON_CP_NEXT_CHAR:
310254885Sdumbbell	case RADEON_CP_PLY_NEXTSCAN:
311254885Sdumbbell	case RADEON_CP_SET_SCISSORS: */ /* probably safe but will never need them? */
312254885Sdumbbell		/* these packets are safe */
313254885Sdumbbell		break;
314254885Sdumbbell
315254885Sdumbbell	case RADEON_CP_3D_DRAW_IMMD_2:
316254885Sdumbbell	case RADEON_CP_3D_DRAW_VBUF_2:
317254885Sdumbbell	case RADEON_CP_3D_DRAW_INDX_2:
318254885Sdumbbell	case RADEON_3D_CLEAR_HIZ:
319254885Sdumbbell		/* safe but r200 only */
320254885Sdumbbell		if (dev_priv->microcode_version != UCODE_R200) {
321254885Sdumbbell			DRM_ERROR("Invalid 3d packet for r100-class chip\n");
322254885Sdumbbell			return -EINVAL;
323254885Sdumbbell		}
324254885Sdumbbell		break;
325254885Sdumbbell
326254885Sdumbbell	case RADEON_3D_LOAD_VBPNTR:
327254885Sdumbbell
328254885Sdumbbell		if (count > 18) { /* 12 arrays max */
329254885Sdumbbell			DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n",
330254885Sdumbbell				  count);
331254885Sdumbbell			return -EINVAL;
332254885Sdumbbell		}
333254885Sdumbbell
334254885Sdumbbell		/* carefully check packet contents */
335254885Sdumbbell		cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1);
336254885Sdumbbell
337254885Sdumbbell		narrays = *cmd & ~0xc000;
338254885Sdumbbell		k = 0;
339254885Sdumbbell		i = 2;
340254885Sdumbbell		while ((k < narrays) && (i < (count + 2))) {
341254885Sdumbbell			i++;		/* skip attribute field */
342254885Sdumbbell			cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, i);
343254885Sdumbbell			if (radeon_check_and_fixup_offset(dev_priv, file_priv,
344254885Sdumbbell							  cmd)) {
345254885Sdumbbell				DRM_ERROR
346254885Sdumbbell				    ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
347254885Sdumbbell				     k, i);
348254885Sdumbbell				return -EINVAL;
349254885Sdumbbell			}
350254885Sdumbbell			k++;
351254885Sdumbbell			i++;
352254885Sdumbbell			if (k == narrays)
353254885Sdumbbell				break;
354254885Sdumbbell			/* have one more to process, they come in pairs */
355254885Sdumbbell			cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, i);
356254885Sdumbbell
357254885Sdumbbell			if (radeon_check_and_fixup_offset(dev_priv,
358254885Sdumbbell							  file_priv, cmd))
359254885Sdumbbell			{
360254885Sdumbbell				DRM_ERROR
361254885Sdumbbell				    ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
362254885Sdumbbell				     k, i);
363254885Sdumbbell				return -EINVAL;
364254885Sdumbbell			}
365254885Sdumbbell			k++;
366254885Sdumbbell			i++;
367254885Sdumbbell		}
368254885Sdumbbell		/* do the counts match what we expect ? */
369254885Sdumbbell		if ((k != narrays) || (i != (count + 2))) {
370254885Sdumbbell			DRM_ERROR
371254885Sdumbbell			    ("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n",
372254885Sdumbbell			      k, i, narrays, count + 1);
373254885Sdumbbell			return -EINVAL;
374254885Sdumbbell		}
375254885Sdumbbell		break;
376254885Sdumbbell
377254885Sdumbbell	case RADEON_3D_RNDR_GEN_INDX_PRIM:
378254885Sdumbbell		if (dev_priv->microcode_version != UCODE_R100) {
379254885Sdumbbell			DRM_ERROR("Invalid 3d packet for r200-class chip\n");
380254885Sdumbbell			return -EINVAL;
381254885Sdumbbell		}
382254885Sdumbbell
383254885Sdumbbell		cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1);
384254885Sdumbbell		if (radeon_check_and_fixup_offset(dev_priv, file_priv, cmd)) {
385254885Sdumbbell				DRM_ERROR("Invalid rndr_gen_indx offset\n");
386254885Sdumbbell				return -EINVAL;
387254885Sdumbbell		}
388254885Sdumbbell		break;
389254885Sdumbbell
390254885Sdumbbell	case RADEON_CP_INDX_BUFFER:
391254885Sdumbbell		if (dev_priv->microcode_version != UCODE_R200) {
392254885Sdumbbell			DRM_ERROR("Invalid 3d packet for r100-class chip\n");
393254885Sdumbbell			return -EINVAL;
394254885Sdumbbell		}
395254885Sdumbbell
396254885Sdumbbell		cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1);
397254885Sdumbbell		if ((*cmd & 0x8000ffff) != 0x80000810) {
398254885Sdumbbell			DRM_ERROR("Invalid indx_buffer reg address %08X\n", *cmd);
399254885Sdumbbell			return -EINVAL;
400254885Sdumbbell		}
401254885Sdumbbell		cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 2);
402254885Sdumbbell		if (radeon_check_and_fixup_offset(dev_priv, file_priv, cmd)) {
403254885Sdumbbell			DRM_ERROR("Invalid indx_buffer offset is %08X\n", *cmd);
404254885Sdumbbell			return -EINVAL;
405254885Sdumbbell		}
406254885Sdumbbell		break;
407254885Sdumbbell
408254885Sdumbbell	case RADEON_CNTL_HOSTDATA_BLT:
409254885Sdumbbell	case RADEON_CNTL_PAINT_MULTI:
410254885Sdumbbell	case RADEON_CNTL_BITBLT_MULTI:
411254885Sdumbbell		/* MSB of opcode: next DWORD GUI_CNTL */
412254885Sdumbbell		cmd = drm_buffer_pointer_to_dword(cmdbuf->buffer, 1);
413254885Sdumbbell		if (*cmd & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
414254885Sdumbbell			      | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
415254885Sdumbbell			u32 *cmd2 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 2);
416254885Sdumbbell			offset = *cmd2 << 10;
417254885Sdumbbell			if (radeon_check_and_fixup_offset
418254885Sdumbbell			    (dev_priv, file_priv, &offset)) {
419254885Sdumbbell				DRM_ERROR("Invalid first packet offset\n");
420254885Sdumbbell				return -EINVAL;
421254885Sdumbbell			}
422254885Sdumbbell			*cmd2 = (*cmd2 & 0xffc00000) | offset >> 10;
423254885Sdumbbell		}
424254885Sdumbbell
425254885Sdumbbell		if ((*cmd & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&
426254885Sdumbbell		    (*cmd & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
427254885Sdumbbell			u32 *cmd3 = drm_buffer_pointer_to_dword(cmdbuf->buffer, 3);
428254885Sdumbbell			offset = *cmd3 << 10;
429254885Sdumbbell			if (radeon_check_and_fixup_offset
430254885Sdumbbell			    (dev_priv, file_priv, &offset)) {
431254885Sdumbbell				DRM_ERROR("Invalid second packet offset\n");
432254885Sdumbbell				return -EINVAL;
433254885Sdumbbell			}
434254885Sdumbbell			*cmd3 = (*cmd3 & 0xffc00000) | offset >> 10;
435254885Sdumbbell		}
436254885Sdumbbell		break;
437254885Sdumbbell
438254885Sdumbbell	default:
439254885Sdumbbell		DRM_ERROR("Invalid packet type %x\n", *cmd & 0xff00);
440254885Sdumbbell		return -EINVAL;
441254885Sdumbbell	}
442254885Sdumbbell
443254885Sdumbbell	return 0;
444254885Sdumbbell}
445254885Sdumbbell
446254885Sdumbbell/* ================================================================
447254885Sdumbbell * CP hardware state programming functions
448254885Sdumbbell */
449254885Sdumbbell
450254885Sdumbbellstatic void radeon_emit_clip_rect(drm_radeon_private_t * dev_priv,
451254885Sdumbbell				  struct drm_clip_rect * box)
452254885Sdumbbell{
453254885Sdumbbell	RING_LOCALS;
454254885Sdumbbell
455254885Sdumbbell	DRM_DEBUG("   box:  x1=%d y1=%d  x2=%d y2=%d\n",
456254885Sdumbbell		  box->x1, box->y1, box->x2, box->y2);
457254885Sdumbbell
458254885Sdumbbell	BEGIN_RING(4);
459254885Sdumbbell	OUT_RING(CP_PACKET0(RADEON_RE_TOP_LEFT, 0));
460254885Sdumbbell	OUT_RING((box->y1 << 16) | box->x1);
461254885Sdumbbell	OUT_RING(CP_PACKET0(RADEON_RE_WIDTH_HEIGHT, 0));
462254885Sdumbbell	OUT_RING(((box->y2 - 1) << 16) | (box->x2 - 1));
463254885Sdumbbell	ADVANCE_RING();
464254885Sdumbbell}
465254885Sdumbbell
466254885Sdumbbell/* Emit 1.1 state
467254885Sdumbbell */
468254885Sdumbbellstatic int radeon_emit_state(drm_radeon_private_t * dev_priv,
469254885Sdumbbell			     struct drm_file *file_priv,
470254885Sdumbbell			     drm_radeon_context_regs_t * ctx,
471254885Sdumbbell			     drm_radeon_texture_regs_t * tex,
472254885Sdumbbell			     unsigned int dirty)
473254885Sdumbbell{
474254885Sdumbbell	RING_LOCALS;
475254885Sdumbbell	DRM_DEBUG("dirty=0x%08x\n", dirty);
476254885Sdumbbell
477254885Sdumbbell	if (dirty & RADEON_UPLOAD_CONTEXT) {
478254885Sdumbbell		if (radeon_check_and_fixup_offset(dev_priv, file_priv,
479254885Sdumbbell						  &ctx->rb3d_depthoffset)) {
480254885Sdumbbell			DRM_ERROR("Invalid depth buffer offset\n");
481254885Sdumbbell			return -EINVAL;
482254885Sdumbbell		}
483254885Sdumbbell
484254885Sdumbbell		if (radeon_check_and_fixup_offset(dev_priv, file_priv,
485254885Sdumbbell						  &ctx->rb3d_coloroffset)) {
486254885Sdumbbell			DRM_ERROR("Invalid depth buffer offset\n");
487254885Sdumbbell			return -EINVAL;
488254885Sdumbbell		}
489254885Sdumbbell
490254885Sdumbbell		BEGIN_RING(14);
491254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_PP_MISC, 6));
492254885Sdumbbell		OUT_RING(ctx->pp_misc);
493254885Sdumbbell		OUT_RING(ctx->pp_fog_color);
494254885Sdumbbell		OUT_RING(ctx->re_solid_color);
495254885Sdumbbell		OUT_RING(ctx->rb3d_blendcntl);
496254885Sdumbbell		OUT_RING(ctx->rb3d_depthoffset);
497254885Sdumbbell		OUT_RING(ctx->rb3d_depthpitch);
498254885Sdumbbell		OUT_RING(ctx->rb3d_zstencilcntl);
499254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 2));
500254885Sdumbbell		OUT_RING(ctx->pp_cntl);
501254885Sdumbbell		OUT_RING(ctx->rb3d_cntl);
502254885Sdumbbell		OUT_RING(ctx->rb3d_coloroffset);
503254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_RB3D_COLORPITCH, 0));
504254885Sdumbbell		OUT_RING(ctx->rb3d_colorpitch);
505254885Sdumbbell		ADVANCE_RING();
506254885Sdumbbell	}
507254885Sdumbbell
508254885Sdumbbell	if (dirty & RADEON_UPLOAD_VERTFMT) {
509254885Sdumbbell		BEGIN_RING(2);
510254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_SE_COORD_FMT, 0));
511254885Sdumbbell		OUT_RING(ctx->se_coord_fmt);
512254885Sdumbbell		ADVANCE_RING();
513254885Sdumbbell	}
514254885Sdumbbell
515254885Sdumbbell	if (dirty & RADEON_UPLOAD_LINE) {
516254885Sdumbbell		BEGIN_RING(5);
517254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_RE_LINE_PATTERN, 1));
518254885Sdumbbell		OUT_RING(ctx->re_line_pattern);
519254885Sdumbbell		OUT_RING(ctx->re_line_state);
520254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_SE_LINE_WIDTH, 0));
521254885Sdumbbell		OUT_RING(ctx->se_line_width);
522254885Sdumbbell		ADVANCE_RING();
523254885Sdumbbell	}
524254885Sdumbbell
525254885Sdumbbell	if (dirty & RADEON_UPLOAD_BUMPMAP) {
526254885Sdumbbell		BEGIN_RING(5);
527254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_PP_LUM_MATRIX, 0));
528254885Sdumbbell		OUT_RING(ctx->pp_lum_matrix);
529254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_PP_ROT_MATRIX_0, 1));
530254885Sdumbbell		OUT_RING(ctx->pp_rot_matrix_0);
531254885Sdumbbell		OUT_RING(ctx->pp_rot_matrix_1);
532254885Sdumbbell		ADVANCE_RING();
533254885Sdumbbell	}
534254885Sdumbbell
535254885Sdumbbell	if (dirty & RADEON_UPLOAD_MASKS) {
536254885Sdumbbell		BEGIN_RING(4);
537254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_RB3D_STENCILREFMASK, 2));
538254885Sdumbbell		OUT_RING(ctx->rb3d_stencilrefmask);
539254885Sdumbbell		OUT_RING(ctx->rb3d_ropcntl);
540254885Sdumbbell		OUT_RING(ctx->rb3d_planemask);
541254885Sdumbbell		ADVANCE_RING();
542254885Sdumbbell	}
543254885Sdumbbell
544254885Sdumbbell	if (dirty & RADEON_UPLOAD_VIEWPORT) {
545254885Sdumbbell		BEGIN_RING(7);
546254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_SE_VPORT_XSCALE, 5));
547254885Sdumbbell		OUT_RING(ctx->se_vport_xscale);
548254885Sdumbbell		OUT_RING(ctx->se_vport_xoffset);
549254885Sdumbbell		OUT_RING(ctx->se_vport_yscale);
550254885Sdumbbell		OUT_RING(ctx->se_vport_yoffset);
551254885Sdumbbell		OUT_RING(ctx->se_vport_zscale);
552254885Sdumbbell		OUT_RING(ctx->se_vport_zoffset);
553254885Sdumbbell		ADVANCE_RING();
554254885Sdumbbell	}
555254885Sdumbbell
556254885Sdumbbell	if (dirty & RADEON_UPLOAD_SETUP) {
557254885Sdumbbell		BEGIN_RING(4);
558254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_SE_CNTL, 0));
559254885Sdumbbell		OUT_RING(ctx->se_cntl);
560254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_SE_CNTL_STATUS, 0));
561254885Sdumbbell		OUT_RING(ctx->se_cntl_status);
562254885Sdumbbell		ADVANCE_RING();
563254885Sdumbbell	}
564254885Sdumbbell
565254885Sdumbbell	if (dirty & RADEON_UPLOAD_MISC) {
566254885Sdumbbell		BEGIN_RING(2);
567254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_RE_MISC, 0));
568254885Sdumbbell		OUT_RING(ctx->re_misc);
569254885Sdumbbell		ADVANCE_RING();
570254885Sdumbbell	}
571254885Sdumbbell
572254885Sdumbbell	if (dirty & RADEON_UPLOAD_TEX0) {
573254885Sdumbbell		if (radeon_check_and_fixup_offset(dev_priv, file_priv,
574254885Sdumbbell						  &tex[0].pp_txoffset)) {
575254885Sdumbbell			DRM_ERROR("Invalid texture offset for unit 0\n");
576254885Sdumbbell			return -EINVAL;
577254885Sdumbbell		}
578254885Sdumbbell
579254885Sdumbbell		BEGIN_RING(9);
580254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_0, 5));
581254885Sdumbbell		OUT_RING(tex[0].pp_txfilter);
582254885Sdumbbell		OUT_RING(tex[0].pp_txformat);
583254885Sdumbbell		OUT_RING(tex[0].pp_txoffset);
584254885Sdumbbell		OUT_RING(tex[0].pp_txcblend);
585254885Sdumbbell		OUT_RING(tex[0].pp_txablend);
586254885Sdumbbell		OUT_RING(tex[0].pp_tfactor);
587254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_0, 0));
588254885Sdumbbell		OUT_RING(tex[0].pp_border_color);
589254885Sdumbbell		ADVANCE_RING();
590254885Sdumbbell	}
591254885Sdumbbell
592254885Sdumbbell	if (dirty & RADEON_UPLOAD_TEX1) {
593254885Sdumbbell		if (radeon_check_and_fixup_offset(dev_priv, file_priv,
594254885Sdumbbell						  &tex[1].pp_txoffset)) {
595254885Sdumbbell			DRM_ERROR("Invalid texture offset for unit 1\n");
596254885Sdumbbell			return -EINVAL;
597254885Sdumbbell		}
598254885Sdumbbell
599254885Sdumbbell		BEGIN_RING(9);
600254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_1, 5));
601254885Sdumbbell		OUT_RING(tex[1].pp_txfilter);
602254885Sdumbbell		OUT_RING(tex[1].pp_txformat);
603254885Sdumbbell		OUT_RING(tex[1].pp_txoffset);
604254885Sdumbbell		OUT_RING(tex[1].pp_txcblend);
605254885Sdumbbell		OUT_RING(tex[1].pp_txablend);
606254885Sdumbbell		OUT_RING(tex[1].pp_tfactor);
607254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_1, 0));
608254885Sdumbbell		OUT_RING(tex[1].pp_border_color);
609254885Sdumbbell		ADVANCE_RING();
610254885Sdumbbell	}
611254885Sdumbbell
612254885Sdumbbell	if (dirty & RADEON_UPLOAD_TEX2) {
613254885Sdumbbell		if (radeon_check_and_fixup_offset(dev_priv, file_priv,
614254885Sdumbbell						  &tex[2].pp_txoffset)) {
615254885Sdumbbell			DRM_ERROR("Invalid texture offset for unit 2\n");
616254885Sdumbbell			return -EINVAL;
617254885Sdumbbell		}
618254885Sdumbbell
619254885Sdumbbell		BEGIN_RING(9);
620254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_2, 5));
621254885Sdumbbell		OUT_RING(tex[2].pp_txfilter);
622254885Sdumbbell		OUT_RING(tex[2].pp_txformat);
623254885Sdumbbell		OUT_RING(tex[2].pp_txoffset);
624254885Sdumbbell		OUT_RING(tex[2].pp_txcblend);
625254885Sdumbbell		OUT_RING(tex[2].pp_txablend);
626254885Sdumbbell		OUT_RING(tex[2].pp_tfactor);
627254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_2, 0));
628254885Sdumbbell		OUT_RING(tex[2].pp_border_color);
629254885Sdumbbell		ADVANCE_RING();
630254885Sdumbbell	}
631254885Sdumbbell
632254885Sdumbbell	return 0;
633254885Sdumbbell}
634254885Sdumbbell
635254885Sdumbbell/* Emit 1.2 state
636254885Sdumbbell */
637254885Sdumbbellstatic int radeon_emit_state2(drm_radeon_private_t * dev_priv,
638254885Sdumbbell			      struct drm_file *file_priv,
639254885Sdumbbell			      drm_radeon_state_t * state)
640254885Sdumbbell{
641254885Sdumbbell	RING_LOCALS;
642254885Sdumbbell
643254885Sdumbbell	if (state->dirty & RADEON_UPLOAD_ZBIAS) {
644254885Sdumbbell		BEGIN_RING(3);
645254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_SE_ZBIAS_FACTOR, 1));
646254885Sdumbbell		OUT_RING(state->context2.se_zbias_factor);
647254885Sdumbbell		OUT_RING(state->context2.se_zbias_constant);
648254885Sdumbbell		ADVANCE_RING();
649254885Sdumbbell	}
650254885Sdumbbell
651254885Sdumbbell	return radeon_emit_state(dev_priv, file_priv, &state->context,
652254885Sdumbbell				 state->tex, state->dirty);
653254885Sdumbbell}
654254885Sdumbbell
655254885Sdumbbell/* New (1.3) state mechanism.  3 commands (packet, scalar, vector) in
656254885Sdumbbell * 1.3 cmdbuffers allow all previous state to be updated as well as
657254885Sdumbbell * the tcl scalar and vector areas.
658254885Sdumbbell */
659254885Sdumbbellstatic struct {
660254885Sdumbbell	int start;
661254885Sdumbbell	int len;
662254885Sdumbbell	const char *name;
663254885Sdumbbell} packet[RADEON_MAX_STATE_PACKETS] = {
664254885Sdumbbell	{RADEON_PP_MISC, 7, "RADEON_PP_MISC"},
665254885Sdumbbell	{RADEON_PP_CNTL, 3, "RADEON_PP_CNTL"},
666254885Sdumbbell	{RADEON_RB3D_COLORPITCH, 1, "RADEON_RB3D_COLORPITCH"},
667254885Sdumbbell	{RADEON_RE_LINE_PATTERN, 2, "RADEON_RE_LINE_PATTERN"},
668254885Sdumbbell	{RADEON_SE_LINE_WIDTH, 1, "RADEON_SE_LINE_WIDTH"},
669254885Sdumbbell	{RADEON_PP_LUM_MATRIX, 1, "RADEON_PP_LUM_MATRIX"},
670254885Sdumbbell	{RADEON_PP_ROT_MATRIX_0, 2, "RADEON_PP_ROT_MATRIX_0"},
671254885Sdumbbell	{RADEON_RB3D_STENCILREFMASK, 3, "RADEON_RB3D_STENCILREFMASK"},
672254885Sdumbbell	{RADEON_SE_VPORT_XSCALE, 6, "RADEON_SE_VPORT_XSCALE"},
673254885Sdumbbell	{RADEON_SE_CNTL, 2, "RADEON_SE_CNTL"},
674254885Sdumbbell	{RADEON_SE_CNTL_STATUS, 1, "RADEON_SE_CNTL_STATUS"},
675254885Sdumbbell	{RADEON_RE_MISC, 1, "RADEON_RE_MISC"},
676254885Sdumbbell	{RADEON_PP_TXFILTER_0, 6, "RADEON_PP_TXFILTER_0"},
677254885Sdumbbell	{RADEON_PP_BORDER_COLOR_0, 1, "RADEON_PP_BORDER_COLOR_0"},
678254885Sdumbbell	{RADEON_PP_TXFILTER_1, 6, "RADEON_PP_TXFILTER_1"},
679254885Sdumbbell	{RADEON_PP_BORDER_COLOR_1, 1, "RADEON_PP_BORDER_COLOR_1"},
680254885Sdumbbell	{RADEON_PP_TXFILTER_2, 6, "RADEON_PP_TXFILTER_2"},
681254885Sdumbbell	{RADEON_PP_BORDER_COLOR_2, 1, "RADEON_PP_BORDER_COLOR_2"},
682254885Sdumbbell	{RADEON_SE_ZBIAS_FACTOR, 2, "RADEON_SE_ZBIAS_FACTOR"},
683254885Sdumbbell	{RADEON_SE_TCL_OUTPUT_VTX_FMT, 11, "RADEON_SE_TCL_OUTPUT_VTX_FMT"},
684254885Sdumbbell	{RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED, 17,
685254885Sdumbbell		    "RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED"},
686254885Sdumbbell	{R200_PP_TXCBLEND_0, 4, "R200_PP_TXCBLEND_0"},
687254885Sdumbbell	{R200_PP_TXCBLEND_1, 4, "R200_PP_TXCBLEND_1"},
688254885Sdumbbell	{R200_PP_TXCBLEND_2, 4, "R200_PP_TXCBLEND_2"},
689254885Sdumbbell	{R200_PP_TXCBLEND_3, 4, "R200_PP_TXCBLEND_3"},
690254885Sdumbbell	{R200_PP_TXCBLEND_4, 4, "R200_PP_TXCBLEND_4"},
691254885Sdumbbell	{R200_PP_TXCBLEND_5, 4, "R200_PP_TXCBLEND_5"},
692254885Sdumbbell	{R200_PP_TXCBLEND_6, 4, "R200_PP_TXCBLEND_6"},
693254885Sdumbbell	{R200_PP_TXCBLEND_7, 4, "R200_PP_TXCBLEND_7"},
694254885Sdumbbell	{R200_SE_TCL_LIGHT_MODEL_CTL_0, 6, "R200_SE_TCL_LIGHT_MODEL_CTL_0"},
695254885Sdumbbell	{R200_PP_TFACTOR_0, 6, "R200_PP_TFACTOR_0"},
696254885Sdumbbell	{R200_SE_VTX_FMT_0, 4, "R200_SE_VTX_FMT_0"},
697254885Sdumbbell	{R200_SE_VAP_CNTL, 1, "R200_SE_VAP_CNTL"},
698254885Sdumbbell	{R200_SE_TCL_MATRIX_SEL_0, 5, "R200_SE_TCL_MATRIX_SEL_0"},
699254885Sdumbbell	{R200_SE_TCL_TEX_PROC_CTL_2, 5, "R200_SE_TCL_TEX_PROC_CTL_2"},
700254885Sdumbbell	{R200_SE_TCL_UCP_VERT_BLEND_CTL, 1, "R200_SE_TCL_UCP_VERT_BLEND_CTL"},
701254885Sdumbbell	{R200_PP_TXFILTER_0, 6, "R200_PP_TXFILTER_0"},
702254885Sdumbbell	{R200_PP_TXFILTER_1, 6, "R200_PP_TXFILTER_1"},
703254885Sdumbbell	{R200_PP_TXFILTER_2, 6, "R200_PP_TXFILTER_2"},
704254885Sdumbbell	{R200_PP_TXFILTER_3, 6, "R200_PP_TXFILTER_3"},
705254885Sdumbbell	{R200_PP_TXFILTER_4, 6, "R200_PP_TXFILTER_4"},
706254885Sdumbbell	{R200_PP_TXFILTER_5, 6, "R200_PP_TXFILTER_5"},
707254885Sdumbbell	{R200_PP_TXOFFSET_0, 1, "R200_PP_TXOFFSET_0"},
708254885Sdumbbell	{R200_PP_TXOFFSET_1, 1, "R200_PP_TXOFFSET_1"},
709254885Sdumbbell	{R200_PP_TXOFFSET_2, 1, "R200_PP_TXOFFSET_2"},
710254885Sdumbbell	{R200_PP_TXOFFSET_3, 1, "R200_PP_TXOFFSET_3"},
711254885Sdumbbell	{R200_PP_TXOFFSET_4, 1, "R200_PP_TXOFFSET_4"},
712254885Sdumbbell	{R200_PP_TXOFFSET_5, 1, "R200_PP_TXOFFSET_5"},
713254885Sdumbbell	{R200_SE_VTE_CNTL, 1, "R200_SE_VTE_CNTL"},
714254885Sdumbbell	{R200_SE_TCL_OUTPUT_VTX_COMP_SEL, 1,
715254885Sdumbbell	 "R200_SE_TCL_OUTPUT_VTX_COMP_SEL"},
716254885Sdumbbell	{R200_PP_TAM_DEBUG3, 1, "R200_PP_TAM_DEBUG3"},
717254885Sdumbbell	{R200_PP_CNTL_X, 1, "R200_PP_CNTL_X"},
718254885Sdumbbell	{R200_RB3D_DEPTHXY_OFFSET, 1, "R200_RB3D_DEPTHXY_OFFSET"},
719254885Sdumbbell	{R200_RE_AUX_SCISSOR_CNTL, 1, "R200_RE_AUX_SCISSOR_CNTL"},
720254885Sdumbbell	{R200_RE_SCISSOR_TL_0, 2, "R200_RE_SCISSOR_TL_0"},
721254885Sdumbbell	{R200_RE_SCISSOR_TL_1, 2, "R200_RE_SCISSOR_TL_1"},
722254885Sdumbbell	{R200_RE_SCISSOR_TL_2, 2, "R200_RE_SCISSOR_TL_2"},
723254885Sdumbbell	{R200_SE_VAP_CNTL_STATUS, 1, "R200_SE_VAP_CNTL_STATUS"},
724254885Sdumbbell	{R200_SE_VTX_STATE_CNTL, 1, "R200_SE_VTX_STATE_CNTL"},
725254885Sdumbbell	{R200_RE_POINTSIZE, 1, "R200_RE_POINTSIZE"},
726254885Sdumbbell	{R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0, 4,
727254885Sdumbbell		    "R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0"},
728254885Sdumbbell	{R200_PP_CUBIC_FACES_0, 1, "R200_PP_CUBIC_FACES_0"},	/* 61 */
729254885Sdumbbell	{R200_PP_CUBIC_OFFSET_F1_0, 5, "R200_PP_CUBIC_OFFSET_F1_0"}, /* 62 */
730254885Sdumbbell	{R200_PP_CUBIC_FACES_1, 1, "R200_PP_CUBIC_FACES_1"},
731254885Sdumbbell	{R200_PP_CUBIC_OFFSET_F1_1, 5, "R200_PP_CUBIC_OFFSET_F1_1"},
732254885Sdumbbell	{R200_PP_CUBIC_FACES_2, 1, "R200_PP_CUBIC_FACES_2"},
733254885Sdumbbell	{R200_PP_CUBIC_OFFSET_F1_2, 5, "R200_PP_CUBIC_OFFSET_F1_2"},
734254885Sdumbbell	{R200_PP_CUBIC_FACES_3, 1, "R200_PP_CUBIC_FACES_3"},
735254885Sdumbbell	{R200_PP_CUBIC_OFFSET_F1_3, 5, "R200_PP_CUBIC_OFFSET_F1_3"},
736254885Sdumbbell	{R200_PP_CUBIC_FACES_4, 1, "R200_PP_CUBIC_FACES_4"},
737254885Sdumbbell	{R200_PP_CUBIC_OFFSET_F1_4, 5, "R200_PP_CUBIC_OFFSET_F1_4"},
738254885Sdumbbell	{R200_PP_CUBIC_FACES_5, 1, "R200_PP_CUBIC_FACES_5"},
739254885Sdumbbell	{R200_PP_CUBIC_OFFSET_F1_5, 5, "R200_PP_CUBIC_OFFSET_F1_5"},
740254885Sdumbbell	{RADEON_PP_TEX_SIZE_0, 2, "RADEON_PP_TEX_SIZE_0"},
741254885Sdumbbell	{RADEON_PP_TEX_SIZE_1, 2, "RADEON_PP_TEX_SIZE_1"},
742254885Sdumbbell	{RADEON_PP_TEX_SIZE_2, 2, "RADEON_PP_TEX_SIZE_2"},
743254885Sdumbbell	{R200_RB3D_BLENDCOLOR, 3, "R200_RB3D_BLENDCOLOR"},
744254885Sdumbbell	{R200_SE_TCL_POINT_SPRITE_CNTL, 1, "R200_SE_TCL_POINT_SPRITE_CNTL"},
745254885Sdumbbell	{RADEON_PP_CUBIC_FACES_0, 1, "RADEON_PP_CUBIC_FACES_0"},
746254885Sdumbbell	{RADEON_PP_CUBIC_OFFSET_T0_0, 5, "RADEON_PP_CUBIC_OFFSET_T0_0"},
747254885Sdumbbell	{RADEON_PP_CUBIC_FACES_1, 1, "RADEON_PP_CUBIC_FACES_1"},
748254885Sdumbbell	{RADEON_PP_CUBIC_OFFSET_T1_0, 5, "RADEON_PP_CUBIC_OFFSET_T1_0"},
749254885Sdumbbell	{RADEON_PP_CUBIC_FACES_2, 1, "RADEON_PP_CUBIC_FACES_2"},
750254885Sdumbbell	{RADEON_PP_CUBIC_OFFSET_T2_0, 5, "RADEON_PP_CUBIC_OFFSET_T2_0"},
751254885Sdumbbell	{R200_PP_TRI_PERF, 2, "R200_PP_TRI_PERF"},
752254885Sdumbbell	{R200_PP_AFS_0, 32, "R200_PP_AFS_0"},     /* 85 */
753254885Sdumbbell	{R200_PP_AFS_1, 32, "R200_PP_AFS_1"},
754254885Sdumbbell	{R200_PP_TFACTOR_0, 8, "R200_ATF_TFACTOR"},
755254885Sdumbbell	{R200_PP_TXFILTER_0, 8, "R200_PP_TXCTLALL_0"},
756254885Sdumbbell	{R200_PP_TXFILTER_1, 8, "R200_PP_TXCTLALL_1"},
757254885Sdumbbell	{R200_PP_TXFILTER_2, 8, "R200_PP_TXCTLALL_2"},
758254885Sdumbbell	{R200_PP_TXFILTER_3, 8, "R200_PP_TXCTLALL_3"},
759254885Sdumbbell	{R200_PP_TXFILTER_4, 8, "R200_PP_TXCTLALL_4"},
760254885Sdumbbell	{R200_PP_TXFILTER_5, 8, "R200_PP_TXCTLALL_5"},
761254885Sdumbbell	{R200_VAP_PVS_CNTL_1, 2, "R200_VAP_PVS_CNTL"},
762254885Sdumbbell};
763254885Sdumbbell
764254885Sdumbbell/* ================================================================
765254885Sdumbbell * Performance monitoring functions
766254885Sdumbbell */
767254885Sdumbbell
768254885Sdumbbellstatic void radeon_clear_box(drm_radeon_private_t * dev_priv,
769254885Sdumbbell			     struct drm_radeon_master_private *master_priv,
770254885Sdumbbell			     int x, int y, int w, int h, int r, int g, int b)
771254885Sdumbbell{
772254885Sdumbbell	u32 color;
773254885Sdumbbell	RING_LOCALS;
774254885Sdumbbell
775254885Sdumbbell	x += master_priv->sarea_priv->boxes[0].x1;
776254885Sdumbbell	y += master_priv->sarea_priv->boxes[0].y1;
777254885Sdumbbell
778254885Sdumbbell	switch (dev_priv->color_fmt) {
779254885Sdumbbell	case RADEON_COLOR_FORMAT_RGB565:
780254885Sdumbbell		color = (((r & 0xf8) << 8) |
781254885Sdumbbell			 ((g & 0xfc) << 3) | ((b & 0xf8) >> 3));
782254885Sdumbbell		break;
783254885Sdumbbell	case RADEON_COLOR_FORMAT_ARGB8888:
784254885Sdumbbell	default:
785254885Sdumbbell		color = (((0xff) << 24) | (r << 16) | (g << 8) | b);
786254885Sdumbbell		break;
787254885Sdumbbell	}
788254885Sdumbbell
789254885Sdumbbell	BEGIN_RING(4);
790254885Sdumbbell	RADEON_WAIT_UNTIL_3D_IDLE();
791254885Sdumbbell	OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0));
792254885Sdumbbell	OUT_RING(0xffffffff);
793254885Sdumbbell	ADVANCE_RING();
794254885Sdumbbell
795254885Sdumbbell	BEGIN_RING(6);
796254885Sdumbbell
797254885Sdumbbell	OUT_RING(CP_PACKET3(RADEON_CNTL_PAINT_MULTI, 4));
798254885Sdumbbell	OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
799254885Sdumbbell		 RADEON_GMC_BRUSH_SOLID_COLOR |
800254885Sdumbbell		 (dev_priv->color_fmt << 8) |
801254885Sdumbbell		 RADEON_GMC_SRC_DATATYPE_COLOR |
802254885Sdumbbell		 RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS);
803254885Sdumbbell
804254885Sdumbbell	if (master_priv->sarea_priv->pfCurrentPage == 1) {
805254885Sdumbbell		OUT_RING(dev_priv->front_pitch_offset);
806254885Sdumbbell	} else {
807254885Sdumbbell		OUT_RING(dev_priv->back_pitch_offset);
808254885Sdumbbell	}
809254885Sdumbbell
810254885Sdumbbell	OUT_RING(color);
811254885Sdumbbell
812254885Sdumbbell	OUT_RING((x << 16) | y);
813254885Sdumbbell	OUT_RING((w << 16) | h);
814254885Sdumbbell
815254885Sdumbbell	ADVANCE_RING();
816254885Sdumbbell}
817254885Sdumbbell
818254885Sdumbbellstatic void radeon_cp_performance_boxes(drm_radeon_private_t *dev_priv, struct drm_radeon_master_private *master_priv)
819254885Sdumbbell{
820254885Sdumbbell	/* Collapse various things into a wait flag -- trying to
821254885Sdumbbell	 * guess if userspase slept -- better just to have them tell us.
822254885Sdumbbell	 */
823254885Sdumbbell	if (dev_priv->stats.last_frame_reads > 1 ||
824254885Sdumbbell	    dev_priv->stats.last_clear_reads > dev_priv->stats.clears) {
825254885Sdumbbell		dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
826254885Sdumbbell	}
827254885Sdumbbell
828254885Sdumbbell	if (dev_priv->stats.freelist_loops) {
829254885Sdumbbell		dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
830254885Sdumbbell	}
831254885Sdumbbell
832254885Sdumbbell	/* Purple box for page flipping
833254885Sdumbbell	 */
834254885Sdumbbell	if (dev_priv->stats.boxes & RADEON_BOX_FLIP)
835254885Sdumbbell		radeon_clear_box(dev_priv, master_priv, 4, 4, 8, 8, 255, 0, 255);
836254885Sdumbbell
837254885Sdumbbell	/* Red box if we have to wait for idle at any point
838254885Sdumbbell	 */
839254885Sdumbbell	if (dev_priv->stats.boxes & RADEON_BOX_WAIT_IDLE)
840254885Sdumbbell		radeon_clear_box(dev_priv, master_priv, 16, 4, 8, 8, 255, 0, 0);
841254885Sdumbbell
842254885Sdumbbell	/* Blue box: lost context?
843254885Sdumbbell	 */
844254885Sdumbbell
845254885Sdumbbell	/* Yellow box for texture swaps
846254885Sdumbbell	 */
847254885Sdumbbell	if (dev_priv->stats.boxes & RADEON_BOX_TEXTURE_LOAD)
848254885Sdumbbell		radeon_clear_box(dev_priv, master_priv, 40, 4, 8, 8, 255, 255, 0);
849254885Sdumbbell
850254885Sdumbbell	/* Green box if hardware never idles (as far as we can tell)
851254885Sdumbbell	 */
852254885Sdumbbell	if (!(dev_priv->stats.boxes & RADEON_BOX_DMA_IDLE))
853254885Sdumbbell		radeon_clear_box(dev_priv, master_priv, 64, 4, 8, 8, 0, 255, 0);
854254885Sdumbbell
855254885Sdumbbell	/* Draw bars indicating number of buffers allocated
856254885Sdumbbell	 * (not a great measure, easily confused)
857254885Sdumbbell	 */
858254885Sdumbbell	if (dev_priv->stats.requested_bufs) {
859254885Sdumbbell		if (dev_priv->stats.requested_bufs > 100)
860254885Sdumbbell			dev_priv->stats.requested_bufs = 100;
861254885Sdumbbell
862254885Sdumbbell		radeon_clear_box(dev_priv, master_priv, 4, 16,
863254885Sdumbbell				 dev_priv->stats.requested_bufs, 4,
864254885Sdumbbell				 196, 128, 128);
865254885Sdumbbell	}
866254885Sdumbbell
867254885Sdumbbell	memset(&dev_priv->stats, 0, sizeof(dev_priv->stats));
868254885Sdumbbell
869254885Sdumbbell}
870254885Sdumbbell
871254885Sdumbbell/* ================================================================
872254885Sdumbbell * CP command dispatch functions
873254885Sdumbbell */
874254885Sdumbbell
875254885Sdumbbellstatic void radeon_cp_dispatch_clear(struct drm_device * dev,
876254885Sdumbbell				     struct drm_master *master,
877254885Sdumbbell				     drm_radeon_clear_t * clear,
878254885Sdumbbell				     drm_radeon_clear_rect_t * depth_boxes)
879254885Sdumbbell{
880254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
881254885Sdumbbell	struct drm_radeon_master_private *master_priv = master->driver_priv;
882254885Sdumbbell	drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;
883254885Sdumbbell	drm_radeon_depth_clear_t *depth_clear = &dev_priv->depth_clear;
884254885Sdumbbell	int nbox = sarea_priv->nbox;
885254885Sdumbbell	struct drm_clip_rect *pbox = sarea_priv->boxes;
886254885Sdumbbell	unsigned int flags = clear->flags;
887254885Sdumbbell	u32 rb3d_cntl = 0, rb3d_stencilrefmask = 0;
888254885Sdumbbell	int i;
889254885Sdumbbell	RING_LOCALS;
890254885Sdumbbell	DRM_DEBUG("flags = 0x%x\n", flags);
891254885Sdumbbell
892254885Sdumbbell	dev_priv->stats.clears++;
893254885Sdumbbell
894254885Sdumbbell	if (sarea_priv->pfCurrentPage == 1) {
895254885Sdumbbell		unsigned int tmp = flags;
896254885Sdumbbell
897254885Sdumbbell		flags &= ~(RADEON_FRONT | RADEON_BACK);
898254885Sdumbbell		if (tmp & RADEON_FRONT)
899254885Sdumbbell			flags |= RADEON_BACK;
900254885Sdumbbell		if (tmp & RADEON_BACK)
901254885Sdumbbell			flags |= RADEON_FRONT;
902254885Sdumbbell	}
903254885Sdumbbell	if (flags & (RADEON_DEPTH|RADEON_STENCIL)) {
904254885Sdumbbell		if (!dev_priv->have_z_offset) {
905254885Sdumbbell			DRM_ERROR("radeon: illegal depth clear request. Buggy mesa detected - please update.\n");
906254885Sdumbbell			flags &= ~(RADEON_DEPTH | RADEON_STENCIL);
907254885Sdumbbell		}
908254885Sdumbbell	}
909254885Sdumbbell
910254885Sdumbbell	if (flags & (RADEON_FRONT | RADEON_BACK)) {
911254885Sdumbbell
912254885Sdumbbell		BEGIN_RING(4);
913254885Sdumbbell
914254885Sdumbbell		/* Ensure the 3D stream is idle before doing a
915254885Sdumbbell		 * 2D fill to clear the front or back buffer.
916254885Sdumbbell		 */
917254885Sdumbbell		RADEON_WAIT_UNTIL_3D_IDLE();
918254885Sdumbbell
919254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0));
920254885Sdumbbell		OUT_RING(clear->color_mask);
921254885Sdumbbell
922254885Sdumbbell		ADVANCE_RING();
923254885Sdumbbell
924254885Sdumbbell		/* Make sure we restore the 3D state next time.
925254885Sdumbbell		 */
926254885Sdumbbell		sarea_priv->ctx_owner = 0;
927254885Sdumbbell
928254885Sdumbbell		for (i = 0; i < nbox; i++) {
929254885Sdumbbell			int x = pbox[i].x1;
930254885Sdumbbell			int y = pbox[i].y1;
931254885Sdumbbell			int w = pbox[i].x2 - x;
932254885Sdumbbell			int h = pbox[i].y2 - y;
933254885Sdumbbell
934254885Sdumbbell			DRM_DEBUG("%d,%d-%d,%d flags 0x%x\n",
935254885Sdumbbell				  x, y, w, h, flags);
936254885Sdumbbell
937254885Sdumbbell			if (flags & RADEON_FRONT) {
938254885Sdumbbell				BEGIN_RING(6);
939254885Sdumbbell
940254885Sdumbbell				OUT_RING(CP_PACKET3
941254885Sdumbbell					 (RADEON_CNTL_PAINT_MULTI, 4));
942254885Sdumbbell				OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
943254885Sdumbbell					 RADEON_GMC_BRUSH_SOLID_COLOR |
944254885Sdumbbell					 (dev_priv->
945254885Sdumbbell					  color_fmt << 8) |
946254885Sdumbbell					 RADEON_GMC_SRC_DATATYPE_COLOR |
947254885Sdumbbell					 RADEON_ROP3_P |
948254885Sdumbbell					 RADEON_GMC_CLR_CMP_CNTL_DIS);
949254885Sdumbbell
950254885Sdumbbell				OUT_RING(dev_priv->front_pitch_offset);
951254885Sdumbbell				OUT_RING(clear->clear_color);
952254885Sdumbbell
953254885Sdumbbell				OUT_RING((x << 16) | y);
954254885Sdumbbell				OUT_RING((w << 16) | h);
955254885Sdumbbell
956254885Sdumbbell				ADVANCE_RING();
957254885Sdumbbell			}
958254885Sdumbbell
959254885Sdumbbell			if (flags & RADEON_BACK) {
960254885Sdumbbell				BEGIN_RING(6);
961254885Sdumbbell
962254885Sdumbbell				OUT_RING(CP_PACKET3
963254885Sdumbbell					 (RADEON_CNTL_PAINT_MULTI, 4));
964254885Sdumbbell				OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
965254885Sdumbbell					 RADEON_GMC_BRUSH_SOLID_COLOR |
966254885Sdumbbell					 (dev_priv->
967254885Sdumbbell					  color_fmt << 8) |
968254885Sdumbbell					 RADEON_GMC_SRC_DATATYPE_COLOR |
969254885Sdumbbell					 RADEON_ROP3_P |
970254885Sdumbbell					 RADEON_GMC_CLR_CMP_CNTL_DIS);
971254885Sdumbbell
972254885Sdumbbell				OUT_RING(dev_priv->back_pitch_offset);
973254885Sdumbbell				OUT_RING(clear->clear_color);
974254885Sdumbbell
975254885Sdumbbell				OUT_RING((x << 16) | y);
976254885Sdumbbell				OUT_RING((w << 16) | h);
977254885Sdumbbell
978254885Sdumbbell				ADVANCE_RING();
979254885Sdumbbell			}
980254885Sdumbbell		}
981254885Sdumbbell	}
982254885Sdumbbell
983254885Sdumbbell	/* hyper z clear */
984254885Sdumbbell	/* no docs available, based on reverse engineering by Stephane Marchesin */
985254885Sdumbbell	if ((flags & (RADEON_DEPTH | RADEON_STENCIL))
986254885Sdumbbell	    && (flags & RADEON_CLEAR_FASTZ)) {
987254885Sdumbbell
988254885Sdumbbell		int i;
989254885Sdumbbell		int depthpixperline =
990254885Sdumbbell		    dev_priv->depth_fmt ==
991254885Sdumbbell		    RADEON_DEPTH_FORMAT_16BIT_INT_Z ? (dev_priv->depth_pitch /
992254885Sdumbbell						       2) : (dev_priv->
993254885Sdumbbell							     depth_pitch / 4);
994254885Sdumbbell
995254885Sdumbbell		u32 clearmask;
996254885Sdumbbell
997254885Sdumbbell		u32 tempRB3D_DEPTHCLEARVALUE = clear->clear_depth |
998254885Sdumbbell		    ((clear->depth_mask & 0xff) << 24);
999254885Sdumbbell
1000254885Sdumbbell		/* Make sure we restore the 3D state next time.
1001254885Sdumbbell		 * we haven't touched any "normal" state - still need this?
1002254885Sdumbbell		 */
1003254885Sdumbbell		sarea_priv->ctx_owner = 0;
1004254885Sdumbbell
1005254885Sdumbbell		if ((dev_priv->flags & RADEON_HAS_HIERZ)
1006254885Sdumbbell		    && (flags & RADEON_USE_HIERZ)) {
1007254885Sdumbbell			/* FIXME : reverse engineer that for Rx00 cards */
1008254885Sdumbbell			/* FIXME : the mask supposedly contains low-res z values. So can't set
1009254885Sdumbbell			   just to the max (0xff? or actually 0x3fff?), need to take z clear
1010254885Sdumbbell			   value into account? */
1011254885Sdumbbell			/* pattern seems to work for r100, though get slight
1012254885Sdumbbell			   rendering errors with glxgears. If hierz is not enabled for r100,
1013254885Sdumbbell			   only 4 bits which indicate clear (15,16,31,32, all zero) matter, the
1014254885Sdumbbell			   other ones are ignored, and the same clear mask can be used. That's
1015254885Sdumbbell			   very different behaviour than R200 which needs different clear mask
1016254885Sdumbbell			   and different number of tiles to clear if hierz is enabled or not !?!
1017254885Sdumbbell			 */
1018254885Sdumbbell			clearmask = (0xff << 22) | (0xff << 6) | 0x003f003f;
1019254885Sdumbbell		} else {
1020254885Sdumbbell			/* clear mask : chooses the clearing pattern.
1021254885Sdumbbell			   rv250: could be used to clear only parts of macrotiles
1022254885Sdumbbell			   (but that would get really complicated...)?
1023254885Sdumbbell			   bit 0 and 1 (either or both of them ?!?!) are used to
1024254885Sdumbbell			   not clear tile (or maybe one of the bits indicates if the tile is
1025254885Sdumbbell			   compressed or not), bit 2 and 3 to not clear tile 1,...,.
1026254885Sdumbbell			   Pattern is as follows:
1027254885Sdumbbell			   | 0,1 | 4,5 | 8,9 |12,13|16,17|20,21|24,25|28,29|
1028254885Sdumbbell			   bits -------------------------------------------------
1029254885Sdumbbell			   | 2,3 | 6,7 |10,11|14,15|18,19|22,23|26,27|30,31|
1030254885Sdumbbell			   rv100: clearmask covers 2x8 4x1 tiles, but one clear still
1031254885Sdumbbell			   covers 256 pixels ?!?
1032254885Sdumbbell			 */
1033254885Sdumbbell			clearmask = 0x0;
1034254885Sdumbbell		}
1035254885Sdumbbell
1036254885Sdumbbell		BEGIN_RING(8);
1037254885Sdumbbell		RADEON_WAIT_UNTIL_2D_IDLE();
1038254885Sdumbbell		OUT_RING_REG(RADEON_RB3D_DEPTHCLEARVALUE,
1039254885Sdumbbell			     tempRB3D_DEPTHCLEARVALUE);
1040254885Sdumbbell		/* what offset is this exactly ? */
1041254885Sdumbbell		OUT_RING_REG(RADEON_RB3D_ZMASKOFFSET, 0);
1042254885Sdumbbell		/* need ctlstat, otherwise get some strange black flickering */
1043254885Sdumbbell		OUT_RING_REG(RADEON_RB3D_ZCACHE_CTLSTAT,
1044254885Sdumbbell			     RADEON_RB3D_ZC_FLUSH_ALL);
1045254885Sdumbbell		ADVANCE_RING();
1046254885Sdumbbell
1047254885Sdumbbell		for (i = 0; i < nbox; i++) {
1048254885Sdumbbell			int tileoffset, nrtilesx, nrtilesy, j;
1049254885Sdumbbell			/* it looks like r200 needs rv-style clears, at least if hierz is not enabled? */
1050254885Sdumbbell			if ((dev_priv->flags & RADEON_HAS_HIERZ)
1051254885Sdumbbell			    && !(dev_priv->microcode_version == UCODE_R200)) {
1052254885Sdumbbell				/* FIXME : figure this out for r200 (when hierz is enabled). Or
1053254885Sdumbbell				   maybe r200 actually doesn't need to put the low-res z value into
1054254885Sdumbbell				   the tile cache like r100, but just needs to clear the hi-level z-buffer?
1055254885Sdumbbell				   Works for R100, both with hierz and without.
1056254885Sdumbbell				   R100 seems to operate on 2x1 8x8 tiles, but...
1057254885Sdumbbell				   odd: offset/nrtiles need to be 64 pix (4 block) aligned? Potentially
1058254885Sdumbbell				   problematic with resolutions which are not 64 pix aligned? */
1059254885Sdumbbell				tileoffset =
1060254885Sdumbbell				    ((pbox[i].y1 >> 3) * depthpixperline +
1061254885Sdumbbell				     pbox[i].x1) >> 6;
1062254885Sdumbbell				nrtilesx =
1063254885Sdumbbell				    ((pbox[i].x2 & ~63) -
1064254885Sdumbbell				     (pbox[i].x1 & ~63)) >> 4;
1065254885Sdumbbell				nrtilesy =
1066254885Sdumbbell				    (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3);
1067254885Sdumbbell				for (j = 0; j <= nrtilesy; j++) {
1068254885Sdumbbell					BEGIN_RING(4);
1069254885Sdumbbell					OUT_RING(CP_PACKET3
1070254885Sdumbbell						 (RADEON_3D_CLEAR_ZMASK, 2));
1071254885Sdumbbell					/* first tile */
1072254885Sdumbbell					OUT_RING(tileoffset * 8);
1073254885Sdumbbell					/* the number of tiles to clear */
1074254885Sdumbbell					OUT_RING(nrtilesx + 4);
1075254885Sdumbbell					/* clear mask : chooses the clearing pattern. */
1076254885Sdumbbell					OUT_RING(clearmask);
1077254885Sdumbbell					ADVANCE_RING();
1078254885Sdumbbell					tileoffset += depthpixperline >> 6;
1079254885Sdumbbell				}
1080254885Sdumbbell			} else if (dev_priv->microcode_version == UCODE_R200) {
1081254885Sdumbbell				/* works for rv250. */
1082254885Sdumbbell				/* find first macro tile (8x2 4x4 z-pixels on rv250) */
1083254885Sdumbbell				tileoffset =
1084254885Sdumbbell				    ((pbox[i].y1 >> 3) * depthpixperline +
1085254885Sdumbbell				     pbox[i].x1) >> 5;
1086254885Sdumbbell				nrtilesx =
1087254885Sdumbbell				    (pbox[i].x2 >> 5) - (pbox[i].x1 >> 5);
1088254885Sdumbbell				nrtilesy =
1089254885Sdumbbell				    (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3);
1090254885Sdumbbell				for (j = 0; j <= nrtilesy; j++) {
1091254885Sdumbbell					BEGIN_RING(4);
1092254885Sdumbbell					OUT_RING(CP_PACKET3
1093254885Sdumbbell						 (RADEON_3D_CLEAR_ZMASK, 2));
1094254885Sdumbbell					/* first tile */
1095254885Sdumbbell					/* judging by the first tile offset needed, could possibly
1096254885Sdumbbell					   directly address/clear 4x4 tiles instead of 8x2 * 4x4
1097254885Sdumbbell					   macro tiles, though would still need clear mask for
1098254885Sdumbbell					   right/bottom if truly 4x4 granularity is desired ? */
1099254885Sdumbbell					OUT_RING(tileoffset * 16);
1100254885Sdumbbell					/* the number of tiles to clear */
1101254885Sdumbbell					OUT_RING(nrtilesx + 1);
1102254885Sdumbbell					/* clear mask : chooses the clearing pattern. */
1103254885Sdumbbell					OUT_RING(clearmask);
1104254885Sdumbbell					ADVANCE_RING();
1105254885Sdumbbell					tileoffset += depthpixperline >> 5;
1106254885Sdumbbell				}
1107254885Sdumbbell			} else {	/* rv 100 */
1108254885Sdumbbell				/* rv100 might not need 64 pix alignment, who knows */
1109254885Sdumbbell				/* offsets are, hmm, weird */
1110254885Sdumbbell				tileoffset =
1111254885Sdumbbell				    ((pbox[i].y1 >> 4) * depthpixperline +
1112254885Sdumbbell				     pbox[i].x1) >> 6;
1113254885Sdumbbell				nrtilesx =
1114254885Sdumbbell				    ((pbox[i].x2 & ~63) -
1115254885Sdumbbell				     (pbox[i].x1 & ~63)) >> 4;
1116254885Sdumbbell				nrtilesy =
1117254885Sdumbbell				    (pbox[i].y2 >> 4) - (pbox[i].y1 >> 4);
1118254885Sdumbbell				for (j = 0; j <= nrtilesy; j++) {
1119254885Sdumbbell					BEGIN_RING(4);
1120254885Sdumbbell					OUT_RING(CP_PACKET3
1121254885Sdumbbell						 (RADEON_3D_CLEAR_ZMASK, 2));
1122254885Sdumbbell					OUT_RING(tileoffset * 128);
1123254885Sdumbbell					/* the number of tiles to clear */
1124254885Sdumbbell					OUT_RING(nrtilesx + 4);
1125254885Sdumbbell					/* clear mask : chooses the clearing pattern. */
1126254885Sdumbbell					OUT_RING(clearmask);
1127254885Sdumbbell					ADVANCE_RING();
1128254885Sdumbbell					tileoffset += depthpixperline >> 6;
1129254885Sdumbbell				}
1130254885Sdumbbell			}
1131254885Sdumbbell		}
1132254885Sdumbbell
1133254885Sdumbbell		/* TODO don't always clear all hi-level z tiles */
1134254885Sdumbbell		if ((dev_priv->flags & RADEON_HAS_HIERZ)
1135254885Sdumbbell		    && (dev_priv->microcode_version == UCODE_R200)
1136254885Sdumbbell		    && (flags & RADEON_USE_HIERZ))
1137254885Sdumbbell			/* r100 and cards without hierarchical z-buffer have no high-level z-buffer */
1138254885Sdumbbell			/* FIXME : the mask supposedly contains low-res z values. So can't set
1139254885Sdumbbell			   just to the max (0xff? or actually 0x3fff?), need to take z clear
1140254885Sdumbbell			   value into account? */
1141254885Sdumbbell		{
1142254885Sdumbbell			BEGIN_RING(4);
1143254885Sdumbbell			OUT_RING(CP_PACKET3(RADEON_3D_CLEAR_HIZ, 2));
1144254885Sdumbbell			OUT_RING(0x0);	/* First tile */
1145254885Sdumbbell			OUT_RING(0x3cc0);
1146254885Sdumbbell			OUT_RING((0xff << 22) | (0xff << 6) | 0x003f003f);
1147254885Sdumbbell			ADVANCE_RING();
1148254885Sdumbbell		}
1149254885Sdumbbell	}
1150254885Sdumbbell
1151254885Sdumbbell	/* We have to clear the depth and/or stencil buffers by
1152254885Sdumbbell	 * rendering a quad into just those buffers.  Thus, we have to
1153254885Sdumbbell	 * make sure the 3D engine is configured correctly.
1154254885Sdumbbell	 */
1155254885Sdumbbell	else if ((dev_priv->microcode_version == UCODE_R200) &&
1156254885Sdumbbell		(flags & (RADEON_DEPTH | RADEON_STENCIL))) {
1157254885Sdumbbell
1158254885Sdumbbell		int tempPP_CNTL;
1159254885Sdumbbell		int tempRE_CNTL;
1160254885Sdumbbell		int tempRB3D_CNTL;
1161254885Sdumbbell		int tempRB3D_ZSTENCILCNTL;
1162254885Sdumbbell		int tempRB3D_STENCILREFMASK;
1163254885Sdumbbell		int tempRB3D_PLANEMASK;
1164254885Sdumbbell		int tempSE_CNTL;
1165254885Sdumbbell		int tempSE_VTE_CNTL;
1166254885Sdumbbell		int tempSE_VTX_FMT_0;
1167254885Sdumbbell		int tempSE_VTX_FMT_1;
1168254885Sdumbbell		int tempSE_VAP_CNTL;
1169254885Sdumbbell		int tempRE_AUX_SCISSOR_CNTL;
1170254885Sdumbbell
1171254885Sdumbbell		tempPP_CNTL = 0;
1172254885Sdumbbell		tempRE_CNTL = 0;
1173254885Sdumbbell
1174254885Sdumbbell		tempRB3D_CNTL = depth_clear->rb3d_cntl;
1175254885Sdumbbell
1176254885Sdumbbell		tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl;
1177254885Sdumbbell		tempRB3D_STENCILREFMASK = 0x0;
1178254885Sdumbbell
1179254885Sdumbbell		tempSE_CNTL = depth_clear->se_cntl;
1180254885Sdumbbell
1181254885Sdumbbell		/* Disable TCL */
1182254885Sdumbbell
1183254885Sdumbbell		tempSE_VAP_CNTL = (	/* SE_VAP_CNTL__FORCE_W_TO_ONE_MASK |  */
1184254885Sdumbbell					  (0x9 <<
1185254885Sdumbbell					   SE_VAP_CNTL__VF_MAX_VTX_NUM__SHIFT));
1186254885Sdumbbell
1187254885Sdumbbell		tempRB3D_PLANEMASK = 0x0;
1188254885Sdumbbell
1189254885Sdumbbell		tempRE_AUX_SCISSOR_CNTL = 0x0;
1190254885Sdumbbell
1191254885Sdumbbell		tempSE_VTE_CNTL =
1192254885Sdumbbell		    SE_VTE_CNTL__VTX_XY_FMT_MASK | SE_VTE_CNTL__VTX_Z_FMT_MASK;
1193254885Sdumbbell
1194254885Sdumbbell		/* Vertex format (X, Y, Z, W) */
1195254885Sdumbbell		tempSE_VTX_FMT_0 =
1196254885Sdumbbell		    SE_VTX_FMT_0__VTX_Z0_PRESENT_MASK |
1197254885Sdumbbell		    SE_VTX_FMT_0__VTX_W0_PRESENT_MASK;
1198254885Sdumbbell		tempSE_VTX_FMT_1 = 0x0;
1199254885Sdumbbell
1200254885Sdumbbell		/*
1201254885Sdumbbell		 * Depth buffer specific enables
1202254885Sdumbbell		 */
1203254885Sdumbbell		if (flags & RADEON_DEPTH) {
1204254885Sdumbbell			/* Enable depth buffer */
1205254885Sdumbbell			tempRB3D_CNTL |= RADEON_Z_ENABLE;
1206254885Sdumbbell		} else {
1207254885Sdumbbell			/* Disable depth buffer */
1208254885Sdumbbell			tempRB3D_CNTL &= ~RADEON_Z_ENABLE;
1209254885Sdumbbell		}
1210254885Sdumbbell
1211254885Sdumbbell		/*
1212254885Sdumbbell		 * Stencil buffer specific enables
1213254885Sdumbbell		 */
1214254885Sdumbbell		if (flags & RADEON_STENCIL) {
1215254885Sdumbbell			tempRB3D_CNTL |= RADEON_STENCIL_ENABLE;
1216254885Sdumbbell			tempRB3D_STENCILREFMASK = clear->depth_mask;
1217254885Sdumbbell		} else {
1218254885Sdumbbell			tempRB3D_CNTL &= ~RADEON_STENCIL_ENABLE;
1219254885Sdumbbell			tempRB3D_STENCILREFMASK = 0x00000000;
1220254885Sdumbbell		}
1221254885Sdumbbell
1222254885Sdumbbell		if (flags & RADEON_USE_COMP_ZBUF) {
1223254885Sdumbbell			tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE |
1224254885Sdumbbell			    RADEON_Z_DECOMPRESSION_ENABLE;
1225254885Sdumbbell		}
1226254885Sdumbbell		if (flags & RADEON_USE_HIERZ) {
1227254885Sdumbbell			tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE;
1228254885Sdumbbell		}
1229254885Sdumbbell
1230254885Sdumbbell		BEGIN_RING(26);
1231254885Sdumbbell		RADEON_WAIT_UNTIL_2D_IDLE();
1232254885Sdumbbell
1233254885Sdumbbell		OUT_RING_REG(RADEON_PP_CNTL, tempPP_CNTL);
1234254885Sdumbbell		OUT_RING_REG(R200_RE_CNTL, tempRE_CNTL);
1235254885Sdumbbell		OUT_RING_REG(RADEON_RB3D_CNTL, tempRB3D_CNTL);
1236254885Sdumbbell		OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL);
1237254885Sdumbbell		OUT_RING_REG(RADEON_RB3D_STENCILREFMASK,
1238254885Sdumbbell			     tempRB3D_STENCILREFMASK);
1239254885Sdumbbell		OUT_RING_REG(RADEON_RB3D_PLANEMASK, tempRB3D_PLANEMASK);
1240254885Sdumbbell		OUT_RING_REG(RADEON_SE_CNTL, tempSE_CNTL);
1241254885Sdumbbell		OUT_RING_REG(R200_SE_VTE_CNTL, tempSE_VTE_CNTL);
1242254885Sdumbbell		OUT_RING_REG(R200_SE_VTX_FMT_0, tempSE_VTX_FMT_0);
1243254885Sdumbbell		OUT_RING_REG(R200_SE_VTX_FMT_1, tempSE_VTX_FMT_1);
1244254885Sdumbbell		OUT_RING_REG(R200_SE_VAP_CNTL, tempSE_VAP_CNTL);
1245254885Sdumbbell		OUT_RING_REG(R200_RE_AUX_SCISSOR_CNTL, tempRE_AUX_SCISSOR_CNTL);
1246254885Sdumbbell		ADVANCE_RING();
1247254885Sdumbbell
1248254885Sdumbbell		/* Make sure we restore the 3D state next time.
1249254885Sdumbbell		 */
1250254885Sdumbbell		sarea_priv->ctx_owner = 0;
1251254885Sdumbbell
1252254885Sdumbbell		for (i = 0; i < nbox; i++) {
1253254885Sdumbbell
1254254885Sdumbbell			/* Funny that this should be required --
1255254885Sdumbbell			 *  sets top-left?
1256254885Sdumbbell			 */
1257254885Sdumbbell			radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
1258254885Sdumbbell
1259254885Sdumbbell			BEGIN_RING(14);
1260254885Sdumbbell			OUT_RING(CP_PACKET3(R200_3D_DRAW_IMMD_2, 12));
1261254885Sdumbbell			OUT_RING((RADEON_PRIM_TYPE_RECT_LIST |
1262254885Sdumbbell				  RADEON_PRIM_WALK_RING |
1263254885Sdumbbell				  (3 << RADEON_NUM_VERTICES_SHIFT)));
1264254885Sdumbbell			OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1265254885Sdumbbell			OUT_RING(depth_boxes[i].ui[CLEAR_Y1]);
1266254885Sdumbbell			OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1267254885Sdumbbell			OUT_RING(0x3f800000);
1268254885Sdumbbell			OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1269254885Sdumbbell			OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1270254885Sdumbbell			OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1271254885Sdumbbell			OUT_RING(0x3f800000);
1272254885Sdumbbell			OUT_RING(depth_boxes[i].ui[CLEAR_X2]);
1273254885Sdumbbell			OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1274254885Sdumbbell			OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1275254885Sdumbbell			OUT_RING(0x3f800000);
1276254885Sdumbbell			ADVANCE_RING();
1277254885Sdumbbell		}
1278254885Sdumbbell	} else if ((flags & (RADEON_DEPTH | RADEON_STENCIL))) {
1279254885Sdumbbell
1280254885Sdumbbell		int tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl;
1281254885Sdumbbell
1282254885Sdumbbell		rb3d_cntl = depth_clear->rb3d_cntl;
1283254885Sdumbbell
1284254885Sdumbbell		if (flags & RADEON_DEPTH) {
1285254885Sdumbbell			rb3d_cntl |= RADEON_Z_ENABLE;
1286254885Sdumbbell		} else {
1287254885Sdumbbell			rb3d_cntl &= ~RADEON_Z_ENABLE;
1288254885Sdumbbell		}
1289254885Sdumbbell
1290254885Sdumbbell		if (flags & RADEON_STENCIL) {
1291254885Sdumbbell			rb3d_cntl |= RADEON_STENCIL_ENABLE;
1292254885Sdumbbell			rb3d_stencilrefmask = clear->depth_mask;	/* misnamed field */
1293254885Sdumbbell		} else {
1294254885Sdumbbell			rb3d_cntl &= ~RADEON_STENCIL_ENABLE;
1295254885Sdumbbell			rb3d_stencilrefmask = 0x00000000;
1296254885Sdumbbell		}
1297254885Sdumbbell
1298254885Sdumbbell		if (flags & RADEON_USE_COMP_ZBUF) {
1299254885Sdumbbell			tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE |
1300254885Sdumbbell			    RADEON_Z_DECOMPRESSION_ENABLE;
1301254885Sdumbbell		}
1302254885Sdumbbell		if (flags & RADEON_USE_HIERZ) {
1303254885Sdumbbell			tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE;
1304254885Sdumbbell		}
1305254885Sdumbbell
1306254885Sdumbbell		BEGIN_RING(13);
1307254885Sdumbbell		RADEON_WAIT_UNTIL_2D_IDLE();
1308254885Sdumbbell
1309254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 1));
1310254885Sdumbbell		OUT_RING(0x00000000);
1311254885Sdumbbell		OUT_RING(rb3d_cntl);
1312254885Sdumbbell
1313254885Sdumbbell		OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL);
1314254885Sdumbbell		OUT_RING_REG(RADEON_RB3D_STENCILREFMASK, rb3d_stencilrefmask);
1315254885Sdumbbell		OUT_RING_REG(RADEON_RB3D_PLANEMASK, 0x00000000);
1316254885Sdumbbell		OUT_RING_REG(RADEON_SE_CNTL, depth_clear->se_cntl);
1317254885Sdumbbell		ADVANCE_RING();
1318254885Sdumbbell
1319254885Sdumbbell		/* Make sure we restore the 3D state next time.
1320254885Sdumbbell		 */
1321254885Sdumbbell		sarea_priv->ctx_owner = 0;
1322254885Sdumbbell
1323254885Sdumbbell		for (i = 0; i < nbox; i++) {
1324254885Sdumbbell
1325254885Sdumbbell			/* Funny that this should be required --
1326254885Sdumbbell			 *  sets top-left?
1327254885Sdumbbell			 */
1328254885Sdumbbell			radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
1329254885Sdumbbell
1330254885Sdumbbell			BEGIN_RING(15);
1331254885Sdumbbell
1332254885Sdumbbell			OUT_RING(CP_PACKET3(RADEON_3D_DRAW_IMMD, 13));
1333254885Sdumbbell			OUT_RING(RADEON_VTX_Z_PRESENT |
1334254885Sdumbbell				 RADEON_VTX_PKCOLOR_PRESENT);
1335254885Sdumbbell			OUT_RING((RADEON_PRIM_TYPE_RECT_LIST |
1336254885Sdumbbell				  RADEON_PRIM_WALK_RING |
1337254885Sdumbbell				  RADEON_MAOS_ENABLE |
1338254885Sdumbbell				  RADEON_VTX_FMT_RADEON_MODE |
1339254885Sdumbbell				  (3 << RADEON_NUM_VERTICES_SHIFT)));
1340254885Sdumbbell
1341254885Sdumbbell			OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1342254885Sdumbbell			OUT_RING(depth_boxes[i].ui[CLEAR_Y1]);
1343254885Sdumbbell			OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1344254885Sdumbbell			OUT_RING(0x0);
1345254885Sdumbbell
1346254885Sdumbbell			OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1347254885Sdumbbell			OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1348254885Sdumbbell			OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1349254885Sdumbbell			OUT_RING(0x0);
1350254885Sdumbbell
1351254885Sdumbbell			OUT_RING(depth_boxes[i].ui[CLEAR_X2]);
1352254885Sdumbbell			OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1353254885Sdumbbell			OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1354254885Sdumbbell			OUT_RING(0x0);
1355254885Sdumbbell
1356254885Sdumbbell			ADVANCE_RING();
1357254885Sdumbbell		}
1358254885Sdumbbell	}
1359254885Sdumbbell
1360254885Sdumbbell	/* Increment the clear counter.  The client-side 3D driver must
1361254885Sdumbbell	 * wait on this value before performing the clear ioctl.  We
1362254885Sdumbbell	 * need this because the card's so damned fast...
1363254885Sdumbbell	 */
1364254885Sdumbbell	sarea_priv->last_clear++;
1365254885Sdumbbell
1366254885Sdumbbell	BEGIN_RING(4);
1367254885Sdumbbell
1368254885Sdumbbell	RADEON_CLEAR_AGE(sarea_priv->last_clear);
1369254885Sdumbbell	RADEON_WAIT_UNTIL_IDLE();
1370254885Sdumbbell
1371254885Sdumbbell	ADVANCE_RING();
1372254885Sdumbbell}
1373254885Sdumbbell
1374254885Sdumbbellstatic void radeon_cp_dispatch_swap(struct drm_device *dev, struct drm_master *master)
1375254885Sdumbbell{
1376254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
1377254885Sdumbbell	struct drm_radeon_master_private *master_priv = master->driver_priv;
1378254885Sdumbbell	drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;
1379254885Sdumbbell	int nbox = sarea_priv->nbox;
1380254885Sdumbbell	struct drm_clip_rect *pbox = sarea_priv->boxes;
1381254885Sdumbbell	int i;
1382254885Sdumbbell	RING_LOCALS;
1383254885Sdumbbell	DRM_DEBUG("\n");
1384254885Sdumbbell
1385254885Sdumbbell	/* Do some trivial performance monitoring...
1386254885Sdumbbell	 */
1387254885Sdumbbell	if (dev_priv->do_boxes)
1388254885Sdumbbell		radeon_cp_performance_boxes(dev_priv, master_priv);
1389254885Sdumbbell
1390254885Sdumbbell	/* Wait for the 3D stream to idle before dispatching the bitblt.
1391254885Sdumbbell	 * This will prevent data corruption between the two streams.
1392254885Sdumbbell	 */
1393254885Sdumbbell	BEGIN_RING(2);
1394254885Sdumbbell
1395254885Sdumbbell	RADEON_WAIT_UNTIL_3D_IDLE();
1396254885Sdumbbell
1397254885Sdumbbell	ADVANCE_RING();
1398254885Sdumbbell
1399254885Sdumbbell	for (i = 0; i < nbox; i++) {
1400254885Sdumbbell		int x = pbox[i].x1;
1401254885Sdumbbell		int y = pbox[i].y1;
1402254885Sdumbbell		int w = pbox[i].x2 - x;
1403254885Sdumbbell		int h = pbox[i].y2 - y;
1404254885Sdumbbell
1405254885Sdumbbell		DRM_DEBUG("%d,%d-%d,%d\n", x, y, w, h);
1406254885Sdumbbell
1407254885Sdumbbell		BEGIN_RING(9);
1408254885Sdumbbell
1409254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_DP_GUI_MASTER_CNTL, 0));
1410254885Sdumbbell		OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
1411254885Sdumbbell			 RADEON_GMC_DST_PITCH_OFFSET_CNTL |
1412254885Sdumbbell			 RADEON_GMC_BRUSH_NONE |
1413254885Sdumbbell			 (dev_priv->color_fmt << 8) |
1414254885Sdumbbell			 RADEON_GMC_SRC_DATATYPE_COLOR |
1415254885Sdumbbell			 RADEON_ROP3_S |
1416254885Sdumbbell			 RADEON_DP_SRC_SOURCE_MEMORY |
1417254885Sdumbbell			 RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
1418254885Sdumbbell
1419254885Sdumbbell		/* Make this work even if front & back are flipped:
1420254885Sdumbbell		 */
1421254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1));
1422254885Sdumbbell		if (sarea_priv->pfCurrentPage == 0) {
1423254885Sdumbbell			OUT_RING(dev_priv->back_pitch_offset);
1424254885Sdumbbell			OUT_RING(dev_priv->front_pitch_offset);
1425254885Sdumbbell		} else {
1426254885Sdumbbell			OUT_RING(dev_priv->front_pitch_offset);
1427254885Sdumbbell			OUT_RING(dev_priv->back_pitch_offset);
1428254885Sdumbbell		}
1429254885Sdumbbell
1430254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_SRC_X_Y, 2));
1431254885Sdumbbell		OUT_RING((x << 16) | y);
1432254885Sdumbbell		OUT_RING((x << 16) | y);
1433254885Sdumbbell		OUT_RING((w << 16) | h);
1434254885Sdumbbell
1435254885Sdumbbell		ADVANCE_RING();
1436254885Sdumbbell	}
1437254885Sdumbbell
1438254885Sdumbbell	/* Increment the frame counter.  The client-side 3D driver must
1439254885Sdumbbell	 * throttle the framerate by waiting for this value before
1440254885Sdumbbell	 * performing the swapbuffer ioctl.
1441254885Sdumbbell	 */
1442254885Sdumbbell	sarea_priv->last_frame++;
1443254885Sdumbbell
1444254885Sdumbbell	BEGIN_RING(4);
1445254885Sdumbbell
1446254885Sdumbbell	RADEON_FRAME_AGE(sarea_priv->last_frame);
1447254885Sdumbbell	RADEON_WAIT_UNTIL_2D_IDLE();
1448254885Sdumbbell
1449254885Sdumbbell	ADVANCE_RING();
1450254885Sdumbbell}
1451254885Sdumbbell
1452254885Sdumbbellvoid radeon_cp_dispatch_flip(struct drm_device *dev, struct drm_master *master)
1453254885Sdumbbell{
1454254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
1455254885Sdumbbell	struct drm_radeon_master_private *master_priv = master->driver_priv;
1456254885Sdumbbell	struct drm_sarea *sarea = (struct drm_sarea *)master_priv->sarea->handle;
1457254885Sdumbbell	int offset = (master_priv->sarea_priv->pfCurrentPage == 1)
1458254885Sdumbbell	    ? dev_priv->front_offset : dev_priv->back_offset;
1459254885Sdumbbell	RING_LOCALS;
1460254885Sdumbbell	DRM_DEBUG("pfCurrentPage=%d\n",
1461254885Sdumbbell		  master_priv->sarea_priv->pfCurrentPage);
1462254885Sdumbbell
1463254885Sdumbbell	/* Do some trivial performance monitoring...
1464254885Sdumbbell	 */
1465254885Sdumbbell	if (dev_priv->do_boxes) {
1466254885Sdumbbell		dev_priv->stats.boxes |= RADEON_BOX_FLIP;
1467254885Sdumbbell		radeon_cp_performance_boxes(dev_priv, master_priv);
1468254885Sdumbbell	}
1469254885Sdumbbell
1470254885Sdumbbell	/* Update the frame offsets for both CRTCs
1471254885Sdumbbell	 */
1472254885Sdumbbell	BEGIN_RING(6);
1473254885Sdumbbell
1474254885Sdumbbell	RADEON_WAIT_UNTIL_3D_IDLE();
1475254885Sdumbbell	OUT_RING_REG(RADEON_CRTC_OFFSET,
1476254885Sdumbbell		     ((sarea->frame.y * dev_priv->front_pitch +
1477254885Sdumbbell		       sarea->frame.x * (dev_priv->color_fmt - 2)) & ~7)
1478254885Sdumbbell		     + offset);
1479254885Sdumbbell	OUT_RING_REG(RADEON_CRTC2_OFFSET, master_priv->sarea_priv->crtc2_base
1480254885Sdumbbell		     + offset);
1481254885Sdumbbell
1482254885Sdumbbell	ADVANCE_RING();
1483254885Sdumbbell
1484254885Sdumbbell	/* Increment the frame counter.  The client-side 3D driver must
1485254885Sdumbbell	 * throttle the framerate by waiting for this value before
1486254885Sdumbbell	 * performing the swapbuffer ioctl.
1487254885Sdumbbell	 */
1488254885Sdumbbell	master_priv->sarea_priv->last_frame++;
1489254885Sdumbbell	master_priv->sarea_priv->pfCurrentPage =
1490254885Sdumbbell		1 - master_priv->sarea_priv->pfCurrentPage;
1491254885Sdumbbell
1492254885Sdumbbell	BEGIN_RING(2);
1493254885Sdumbbell
1494254885Sdumbbell	RADEON_FRAME_AGE(master_priv->sarea_priv->last_frame);
1495254885Sdumbbell
1496254885Sdumbbell	ADVANCE_RING();
1497254885Sdumbbell}
1498254885Sdumbbell
1499254885Sdumbbellstatic int bad_prim_vertex_nr(int primitive, int nr)
1500254885Sdumbbell{
1501254885Sdumbbell	switch (primitive & RADEON_PRIM_TYPE_MASK) {
1502254885Sdumbbell	case RADEON_PRIM_TYPE_NONE:
1503254885Sdumbbell	case RADEON_PRIM_TYPE_POINT:
1504254885Sdumbbell		return nr < 1;
1505254885Sdumbbell	case RADEON_PRIM_TYPE_LINE:
1506254885Sdumbbell		return (nr & 1) || nr == 0;
1507254885Sdumbbell	case RADEON_PRIM_TYPE_LINE_STRIP:
1508254885Sdumbbell		return nr < 2;
1509254885Sdumbbell	case RADEON_PRIM_TYPE_TRI_LIST:
1510254885Sdumbbell	case RADEON_PRIM_TYPE_3VRT_POINT_LIST:
1511254885Sdumbbell	case RADEON_PRIM_TYPE_3VRT_LINE_LIST:
1512254885Sdumbbell	case RADEON_PRIM_TYPE_RECT_LIST:
1513254885Sdumbbell		return nr % 3 || nr == 0;
1514254885Sdumbbell	case RADEON_PRIM_TYPE_TRI_FAN:
1515254885Sdumbbell	case RADEON_PRIM_TYPE_TRI_STRIP:
1516254885Sdumbbell		return nr < 3;
1517254885Sdumbbell	default:
1518254885Sdumbbell		return 1;
1519254885Sdumbbell	}
1520254885Sdumbbell}
1521254885Sdumbbell
1522254885Sdumbbelltypedef struct {
1523254885Sdumbbell	unsigned int start;
1524254885Sdumbbell	unsigned int finish;
1525254885Sdumbbell	unsigned int prim;
1526254885Sdumbbell	unsigned int numverts;
1527254885Sdumbbell	unsigned int offset;
1528254885Sdumbbell	unsigned int vc_format;
1529254885Sdumbbell} drm_radeon_tcl_prim_t;
1530254885Sdumbbell
1531254885Sdumbbellstatic void radeon_cp_dispatch_vertex(struct drm_device * dev,
1532254885Sdumbbell				      struct drm_file *file_priv,
1533254885Sdumbbell				      struct drm_buf * buf,
1534254885Sdumbbell				      drm_radeon_tcl_prim_t * prim)
1535254885Sdumbbell{
1536254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
1537254885Sdumbbell	struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv;
1538254885Sdumbbell	drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;
1539254885Sdumbbell	int offset = dev_priv->gart_buffers_offset + buf->offset + prim->start;
1540254885Sdumbbell	int numverts = (int)prim->numverts;
1541254885Sdumbbell	int nbox = sarea_priv->nbox;
1542254885Sdumbbell	int i = 0;
1543254885Sdumbbell	RING_LOCALS;
1544254885Sdumbbell
1545254885Sdumbbell	DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d %d verts\n",
1546254885Sdumbbell		  prim->prim,
1547254885Sdumbbell		  prim->vc_format, prim->start, prim->finish, prim->numverts);
1548254885Sdumbbell
1549254885Sdumbbell	if (bad_prim_vertex_nr(prim->prim, prim->numverts)) {
1550254885Sdumbbell		DRM_ERROR("bad prim %x numverts %d\n",
1551254885Sdumbbell			  prim->prim, prim->numverts);
1552254885Sdumbbell		return;
1553254885Sdumbbell	}
1554254885Sdumbbell
1555254885Sdumbbell	do {
1556254885Sdumbbell		/* Emit the next cliprect */
1557254885Sdumbbell		if (i < nbox) {
1558254885Sdumbbell			radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
1559254885Sdumbbell		}
1560254885Sdumbbell
1561254885Sdumbbell		/* Emit the vertex buffer rendering commands */
1562254885Sdumbbell		BEGIN_RING(5);
1563254885Sdumbbell
1564254885Sdumbbell		OUT_RING(CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, 3));
1565254885Sdumbbell		OUT_RING(offset);
1566254885Sdumbbell		OUT_RING(numverts);
1567254885Sdumbbell		OUT_RING(prim->vc_format);
1568254885Sdumbbell		OUT_RING(prim->prim | RADEON_PRIM_WALK_LIST |
1569254885Sdumbbell			 RADEON_COLOR_ORDER_RGBA |
1570254885Sdumbbell			 RADEON_VTX_FMT_RADEON_MODE |
1571254885Sdumbbell			 (numverts << RADEON_NUM_VERTICES_SHIFT));
1572254885Sdumbbell
1573254885Sdumbbell		ADVANCE_RING();
1574254885Sdumbbell
1575254885Sdumbbell		i++;
1576254885Sdumbbell	} while (i < nbox);
1577254885Sdumbbell}
1578254885Sdumbbell
1579254885Sdumbbellvoid radeon_cp_discard_buffer(struct drm_device *dev, struct drm_master *master, struct drm_buf *buf)
1580254885Sdumbbell{
1581254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
1582254885Sdumbbell	struct drm_radeon_master_private *master_priv = master->driver_priv;
1583254885Sdumbbell	drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
1584254885Sdumbbell	RING_LOCALS;
1585254885Sdumbbell
1586254885Sdumbbell	buf_priv->age = ++master_priv->sarea_priv->last_dispatch;
1587254885Sdumbbell
1588254885Sdumbbell	/* Emit the vertex buffer age */
1589254885Sdumbbell	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
1590254885Sdumbbell		BEGIN_RING(3);
1591254885Sdumbbell		R600_DISPATCH_AGE(buf_priv->age);
1592254885Sdumbbell		ADVANCE_RING();
1593254885Sdumbbell	} else {
1594254885Sdumbbell		BEGIN_RING(2);
1595254885Sdumbbell		RADEON_DISPATCH_AGE(buf_priv->age);
1596254885Sdumbbell		ADVANCE_RING();
1597254885Sdumbbell	}
1598254885Sdumbbell
1599254885Sdumbbell	buf->pending = 1;
1600254885Sdumbbell	buf->used = 0;
1601254885Sdumbbell}
1602254885Sdumbbell
1603254885Sdumbbellstatic void radeon_cp_dispatch_indirect(struct drm_device * dev,
1604254885Sdumbbell					struct drm_buf * buf, int start, int end)
1605254885Sdumbbell{
1606254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
1607254885Sdumbbell	RING_LOCALS;
1608254885Sdumbbell	DRM_DEBUG("buf=%d s=0x%x e=0x%x\n", buf->idx, start, end);
1609254885Sdumbbell
1610254885Sdumbbell	if (start != end) {
1611254885Sdumbbell		int offset = (dev_priv->gart_buffers_offset
1612254885Sdumbbell			      + buf->offset + start);
1613254885Sdumbbell		int dwords = (end - start + 3) / sizeof(u32);
1614254885Sdumbbell
1615254885Sdumbbell		/* Indirect buffer data must be an even number of
1616254885Sdumbbell		 * dwords, so if we've been given an odd number we must
1617254885Sdumbbell		 * pad the data with a Type-2 CP packet.
1618254885Sdumbbell		 */
1619254885Sdumbbell		if (dwords & 1) {
1620254885Sdumbbell			u32 *data = (u32 *)
1621254885Sdumbbell			    ((char *)dev->agp_buffer_map->handle
1622254885Sdumbbell			     + buf->offset + start);
1623254885Sdumbbell			data[dwords++] = RADEON_CP_PACKET2;
1624254885Sdumbbell		}
1625254885Sdumbbell
1626254885Sdumbbell		/* Fire off the indirect buffer */
1627254885Sdumbbell		BEGIN_RING(3);
1628254885Sdumbbell
1629254885Sdumbbell		OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1));
1630254885Sdumbbell		OUT_RING(offset);
1631254885Sdumbbell		OUT_RING(dwords);
1632254885Sdumbbell
1633254885Sdumbbell		ADVANCE_RING();
1634254885Sdumbbell	}
1635254885Sdumbbell}
1636254885Sdumbbell
1637254885Sdumbbellstatic void radeon_cp_dispatch_indices(struct drm_device *dev,
1638254885Sdumbbell				       struct drm_master *master,
1639254885Sdumbbell				       struct drm_buf * elt_buf,
1640254885Sdumbbell				       drm_radeon_tcl_prim_t * prim)
1641254885Sdumbbell{
1642254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
1643254885Sdumbbell	struct drm_radeon_master_private *master_priv = master->driver_priv;
1644254885Sdumbbell	drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;
1645254885Sdumbbell	int offset = dev_priv->gart_buffers_offset + prim->offset;
1646254885Sdumbbell	u32 *data;
1647254885Sdumbbell	int dwords;
1648254885Sdumbbell	int i = 0;
1649254885Sdumbbell	int start = prim->start + RADEON_INDEX_PRIM_OFFSET;
1650254885Sdumbbell	int count = (prim->finish - start) / sizeof(u16);
1651254885Sdumbbell	int nbox = sarea_priv->nbox;
1652254885Sdumbbell
1653254885Sdumbbell	DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d offset: %x nr %d\n",
1654254885Sdumbbell		  prim->prim,
1655254885Sdumbbell		  prim->vc_format,
1656254885Sdumbbell		  prim->start, prim->finish, prim->offset, prim->numverts);
1657254885Sdumbbell
1658254885Sdumbbell	if (bad_prim_vertex_nr(prim->prim, count)) {
1659254885Sdumbbell		DRM_ERROR("bad prim %x count %d\n", prim->prim, count);
1660254885Sdumbbell		return;
1661254885Sdumbbell	}
1662254885Sdumbbell
1663254885Sdumbbell	if (start >= prim->finish || (prim->start & 0x7)) {
1664254885Sdumbbell		DRM_ERROR("buffer prim %d\n", prim->prim);
1665254885Sdumbbell		return;
1666254885Sdumbbell	}
1667254885Sdumbbell
1668254885Sdumbbell	dwords = (prim->finish - prim->start + 3) / sizeof(u32);
1669254885Sdumbbell
1670254885Sdumbbell	data = (u32 *) ((char *)dev->agp_buffer_map->handle +
1671254885Sdumbbell			elt_buf->offset + prim->start);
1672254885Sdumbbell
1673254885Sdumbbell	data[0] = CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, dwords - 2);
1674254885Sdumbbell	data[1] = offset;
1675254885Sdumbbell	data[2] = prim->numverts;
1676254885Sdumbbell	data[3] = prim->vc_format;
1677254885Sdumbbell	data[4] = (prim->prim |
1678254885Sdumbbell		   RADEON_PRIM_WALK_IND |
1679254885Sdumbbell		   RADEON_COLOR_ORDER_RGBA |
1680254885Sdumbbell		   RADEON_VTX_FMT_RADEON_MODE |
1681254885Sdumbbell		   (count << RADEON_NUM_VERTICES_SHIFT));
1682254885Sdumbbell
1683254885Sdumbbell	do {
1684254885Sdumbbell		if (i < nbox)
1685254885Sdumbbell			radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
1686254885Sdumbbell
1687254885Sdumbbell		radeon_cp_dispatch_indirect(dev, elt_buf,
1688254885Sdumbbell					    prim->start, prim->finish);
1689254885Sdumbbell
1690254885Sdumbbell		i++;
1691254885Sdumbbell	} while (i < nbox);
1692254885Sdumbbell
1693254885Sdumbbell}
1694254885Sdumbbell
1695254885Sdumbbell#define RADEON_MAX_TEXTURE_SIZE RADEON_BUFFER_SIZE
1696254885Sdumbbell
1697254885Sdumbbellstatic int radeon_cp_dispatch_texture(struct drm_device * dev,
1698254885Sdumbbell				      struct drm_file *file_priv,
1699254885Sdumbbell				      drm_radeon_texture_t * tex,
1700254885Sdumbbell				      drm_radeon_tex_image_t * image)
1701254885Sdumbbell{
1702254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
1703254885Sdumbbell	struct drm_buf *buf;
1704254885Sdumbbell	u32 format;
1705254885Sdumbbell	u32 *buffer;
1706254885Sdumbbell	const u8 __user *data;
1707254885Sdumbbell	int size, dwords, tex_width, blit_width, spitch;
1708254885Sdumbbell	u32 height;
1709254885Sdumbbell	int i;
1710254885Sdumbbell	u32 texpitch, microtile;
1711254885Sdumbbell	u32 offset, byte_offset;
1712254885Sdumbbell	RING_LOCALS;
1713254885Sdumbbell
1714254885Sdumbbell	if (radeon_check_and_fixup_offset(dev_priv, file_priv, &tex->offset)) {
1715254885Sdumbbell		DRM_ERROR("Invalid destination offset\n");
1716254885Sdumbbell		return -EINVAL;
1717254885Sdumbbell	}
1718254885Sdumbbell
1719254885Sdumbbell	dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD;
1720254885Sdumbbell
1721254885Sdumbbell	/* Flush the pixel cache.  This ensures no pixel data gets mixed
1722254885Sdumbbell	 * up with the texture data from the host data blit, otherwise
1723254885Sdumbbell	 * part of the texture image may be corrupted.
1724254885Sdumbbell	 */
1725254885Sdumbbell	BEGIN_RING(4);
1726254885Sdumbbell	RADEON_FLUSH_CACHE();
1727254885Sdumbbell	RADEON_WAIT_UNTIL_IDLE();
1728254885Sdumbbell	ADVANCE_RING();
1729254885Sdumbbell
1730254885Sdumbbell	/* The compiler won't optimize away a division by a variable,
1731254885Sdumbbell	 * even if the only legal values are powers of two.  Thus, we'll
1732254885Sdumbbell	 * use a shift instead.
1733254885Sdumbbell	 */
1734254885Sdumbbell	switch (tex->format) {
1735254885Sdumbbell	case RADEON_TXFORMAT_ARGB8888:
1736254885Sdumbbell	case RADEON_TXFORMAT_RGBA8888:
1737254885Sdumbbell		format = RADEON_COLOR_FORMAT_ARGB8888;
1738254885Sdumbbell		tex_width = tex->width * 4;
1739254885Sdumbbell		blit_width = image->width * 4;
1740254885Sdumbbell		break;
1741254885Sdumbbell	case RADEON_TXFORMAT_AI88:
1742254885Sdumbbell	case RADEON_TXFORMAT_ARGB1555:
1743254885Sdumbbell	case RADEON_TXFORMAT_RGB565:
1744254885Sdumbbell	case RADEON_TXFORMAT_ARGB4444:
1745254885Sdumbbell	case RADEON_TXFORMAT_VYUY422:
1746254885Sdumbbell	case RADEON_TXFORMAT_YVYU422:
1747254885Sdumbbell		format = RADEON_COLOR_FORMAT_RGB565;
1748254885Sdumbbell		tex_width = tex->width * 2;
1749254885Sdumbbell		blit_width = image->width * 2;
1750254885Sdumbbell		break;
1751254885Sdumbbell	case RADEON_TXFORMAT_I8:
1752254885Sdumbbell	case RADEON_TXFORMAT_RGB332:
1753254885Sdumbbell		format = RADEON_COLOR_FORMAT_CI8;
1754254885Sdumbbell		tex_width = tex->width * 1;
1755254885Sdumbbell		blit_width = image->width * 1;
1756254885Sdumbbell		break;
1757254885Sdumbbell	default:
1758254885Sdumbbell		DRM_ERROR("invalid texture format %d\n", tex->format);
1759254885Sdumbbell		return -EINVAL;
1760254885Sdumbbell	}
1761254885Sdumbbell	spitch = blit_width >> 6;
1762254885Sdumbbell	if (spitch == 0 && image->height > 1)
1763254885Sdumbbell		return -EINVAL;
1764254885Sdumbbell
1765254885Sdumbbell	texpitch = tex->pitch;
1766254885Sdumbbell	if ((texpitch << 22) & RADEON_DST_TILE_MICRO) {
1767254885Sdumbbell		microtile = 1;
1768254885Sdumbbell		if (tex_width < 64) {
1769254885Sdumbbell			texpitch &= ~(RADEON_DST_TILE_MICRO >> 22);
1770254885Sdumbbell			/* we got tiled coordinates, untile them */
1771254885Sdumbbell			image->x *= 2;
1772254885Sdumbbell		}
1773254885Sdumbbell	} else
1774254885Sdumbbell		microtile = 0;
1775254885Sdumbbell
1776254885Sdumbbell	/* this might fail for zero-sized uploads - are those illegal? */
1777254885Sdumbbell	if (!radeon_check_offset(dev_priv, tex->offset + image->height *
1778254885Sdumbbell				blit_width - 1)) {
1779254885Sdumbbell		DRM_ERROR("Invalid final destination offset\n");
1780254885Sdumbbell		return -EINVAL;
1781254885Sdumbbell	}
1782254885Sdumbbell
1783254885Sdumbbell	DRM_DEBUG("tex=%dx%d blit=%d\n", tex_width, tex->height, blit_width);
1784254885Sdumbbell
1785254885Sdumbbell	do {
1786254885Sdumbbell		DRM_DEBUG("tex: ofs=0x%x p=%d f=%d x=%u y=%u w=%u h=%u\n",
1787254885Sdumbbell			  tex->offset >> 10, tex->pitch, tex->format,
1788254885Sdumbbell			  image->x, image->y, image->width, image->height);
1789254885Sdumbbell
1790254885Sdumbbell		/* Make a copy of some parameters in case we have to
1791254885Sdumbbell		 * update them for a multi-pass texture blit.
1792254885Sdumbbell		 */
1793254885Sdumbbell		height = image->height;
1794254885Sdumbbell		data = (const u8 __user *)image->data;
1795254885Sdumbbell
1796254885Sdumbbell		size = height * blit_width;
1797254885Sdumbbell
1798254885Sdumbbell		if (size > RADEON_MAX_TEXTURE_SIZE) {
1799254885Sdumbbell			height = RADEON_MAX_TEXTURE_SIZE / blit_width;
1800254885Sdumbbell			size = height * blit_width;
1801254885Sdumbbell		} else if (size < 4 && size > 0) {
1802254885Sdumbbell			size = 4;
1803254885Sdumbbell		} else if (size == 0) {
1804254885Sdumbbell			return 0;
1805254885Sdumbbell		}
1806254885Sdumbbell
1807254885Sdumbbell		buf = radeon_freelist_get(dev);
1808254885Sdumbbell		if (0 && !buf) {
1809254885Sdumbbell			radeon_do_cp_idle(dev_priv);
1810254885Sdumbbell			buf = radeon_freelist_get(dev);
1811254885Sdumbbell		}
1812254885Sdumbbell		if (!buf) {
1813254885Sdumbbell			DRM_DEBUG("EAGAIN\n");
1814254885Sdumbbell			if (DRM_COPY_TO_USER(tex->image, image, sizeof(*image)))
1815254885Sdumbbell				return -EFAULT;
1816254885Sdumbbell			return -EAGAIN;
1817254885Sdumbbell		}
1818254885Sdumbbell
1819254885Sdumbbell		/* Dispatch the indirect buffer.
1820254885Sdumbbell		 */
1821254885Sdumbbell		buffer =
1822254885Sdumbbell		    (u32 *) ((char *)dev->agp_buffer_map->handle + buf->offset);
1823254885Sdumbbell		dwords = size / 4;
1824254885Sdumbbell
1825254885Sdumbbell#define RADEON_COPY_MT(_buf, _data, _width) \
1826254885Sdumbbell	do { \
1827254885Sdumbbell		if (DRM_COPY_FROM_USER(_buf, _data, (_width))) {\
1828254885Sdumbbell			DRM_ERROR("EFAULT on pad, %d bytes\n", (_width)); \
1829254885Sdumbbell			return -EFAULT; \
1830254885Sdumbbell		} \
1831254885Sdumbbell	} while(0)
1832254885Sdumbbell
1833254885Sdumbbell		if (microtile) {
1834254885Sdumbbell			/* texture micro tiling in use, minimum texture width is thus 16 bytes.
1835254885Sdumbbell			   however, we cannot use blitter directly for texture width < 64 bytes,
1836254885Sdumbbell			   since minimum tex pitch is 64 bytes and we need this to match
1837254885Sdumbbell			   the texture width, otherwise the blitter will tile it wrong.
1838254885Sdumbbell			   Thus, tiling manually in this case. Additionally, need to special
1839254885Sdumbbell			   case tex height = 1, since our actual image will have height 2
1840254885Sdumbbell			   and we need to ensure we don't read beyond the texture size
1841254885Sdumbbell			   from user space. */
1842254885Sdumbbell			if (tex->height == 1) {
1843254885Sdumbbell				if (tex_width >= 64 || tex_width <= 16) {
1844254885Sdumbbell					RADEON_COPY_MT(buffer, data,
1845254885Sdumbbell						(int)(tex_width * sizeof(u32)));
1846254885Sdumbbell				} else if (tex_width == 32) {
1847254885Sdumbbell					RADEON_COPY_MT(buffer, data, 16);
1848254885Sdumbbell					RADEON_COPY_MT(buffer + 8,
1849254885Sdumbbell						       data + 16, 16);
1850254885Sdumbbell				}
1851254885Sdumbbell			} else if (tex_width >= 64 || tex_width == 16) {
1852254885Sdumbbell				RADEON_COPY_MT(buffer, data,
1853254885Sdumbbell					       (int)(dwords * sizeof(u32)));
1854254885Sdumbbell			} else if (tex_width < 16) {
1855254885Sdumbbell				for (i = 0; i < tex->height; i++) {
1856254885Sdumbbell					RADEON_COPY_MT(buffer, data, tex_width);
1857254885Sdumbbell					buffer += 4;
1858254885Sdumbbell					data += tex_width;
1859254885Sdumbbell				}
1860254885Sdumbbell			} else if (tex_width == 32) {
1861254885Sdumbbell				/* TODO: make sure this works when not fitting in one buffer
1862254885Sdumbbell				   (i.e. 32bytes x 2048...) */
1863254885Sdumbbell				for (i = 0; i < tex->height; i += 2) {
1864254885Sdumbbell					RADEON_COPY_MT(buffer, data, 16);
1865254885Sdumbbell					data += 16;
1866254885Sdumbbell					RADEON_COPY_MT(buffer + 8, data, 16);
1867254885Sdumbbell					data += 16;
1868254885Sdumbbell					RADEON_COPY_MT(buffer + 4, data, 16);
1869254885Sdumbbell					data += 16;
1870254885Sdumbbell					RADEON_COPY_MT(buffer + 12, data, 16);
1871254885Sdumbbell					data += 16;
1872254885Sdumbbell					buffer += 16;
1873254885Sdumbbell				}
1874254885Sdumbbell			}
1875254885Sdumbbell		} else {
1876254885Sdumbbell			if (tex_width >= 32) {
1877254885Sdumbbell				/* Texture image width is larger than the minimum, so we
1878254885Sdumbbell				 * can upload it directly.
1879254885Sdumbbell				 */
1880254885Sdumbbell				RADEON_COPY_MT(buffer, data,
1881254885Sdumbbell					       (int)(dwords * sizeof(u32)));
1882254885Sdumbbell			} else {
1883254885Sdumbbell				/* Texture image width is less than the minimum, so we
1884254885Sdumbbell				 * need to pad out each image scanline to the minimum
1885254885Sdumbbell				 * width.
1886254885Sdumbbell				 */
1887254885Sdumbbell				for (i = 0; i < tex->height; i++) {
1888254885Sdumbbell					RADEON_COPY_MT(buffer, data, tex_width);
1889254885Sdumbbell					buffer += 8;
1890254885Sdumbbell					data += tex_width;
1891254885Sdumbbell				}
1892254885Sdumbbell			}
1893254885Sdumbbell		}
1894254885Sdumbbell
1895254885Sdumbbell#undef RADEON_COPY_MT
1896254885Sdumbbell		byte_offset = (image->y & ~2047) * blit_width;
1897254885Sdumbbell		buf->file_priv = file_priv;
1898254885Sdumbbell		buf->used = size;
1899254885Sdumbbell		offset = dev_priv->gart_buffers_offset + buf->offset;
1900254885Sdumbbell		BEGIN_RING(9);
1901254885Sdumbbell		OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
1902254885Sdumbbell		OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
1903254885Sdumbbell			 RADEON_GMC_DST_PITCH_OFFSET_CNTL |
1904254885Sdumbbell			 RADEON_GMC_BRUSH_NONE |
1905254885Sdumbbell			 (format << 8) |
1906254885Sdumbbell			 RADEON_GMC_SRC_DATATYPE_COLOR |
1907254885Sdumbbell			 RADEON_ROP3_S |
1908254885Sdumbbell			 RADEON_DP_SRC_SOURCE_MEMORY |
1909254885Sdumbbell			 RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
1910254885Sdumbbell		OUT_RING((spitch << 22) | (offset >> 10));
1911254885Sdumbbell		OUT_RING((texpitch << 22) | ((tex->offset >> 10) + (byte_offset >> 10)));
1912254885Sdumbbell		OUT_RING(0);
1913254885Sdumbbell		OUT_RING((image->x << 16) | (image->y % 2048));
1914254885Sdumbbell		OUT_RING((image->width << 16) | height);
1915254885Sdumbbell		RADEON_WAIT_UNTIL_2D_IDLE();
1916254885Sdumbbell		ADVANCE_RING();
1917254885Sdumbbell		COMMIT_RING();
1918254885Sdumbbell
1919254885Sdumbbell		radeon_cp_discard_buffer(dev, file_priv->masterp, buf);
1920254885Sdumbbell
1921254885Sdumbbell		/* Update the input parameters for next time */
1922254885Sdumbbell		image->y += height;
1923254885Sdumbbell		image->height -= height;
1924254885Sdumbbell		image->data = (const u8 __user *)image->data + size;
1925254885Sdumbbell	} while (image->height > 0);
1926254885Sdumbbell
1927254885Sdumbbell	/* Flush the pixel cache after the blit completes.  This ensures
1928254885Sdumbbell	 * the texture data is written out to memory before rendering
1929254885Sdumbbell	 * continues.
1930254885Sdumbbell	 */
1931254885Sdumbbell	BEGIN_RING(4);
1932254885Sdumbbell	RADEON_FLUSH_CACHE();
1933254885Sdumbbell	RADEON_WAIT_UNTIL_2D_IDLE();
1934254885Sdumbbell	ADVANCE_RING();
1935254885Sdumbbell	COMMIT_RING();
1936254885Sdumbbell
1937254885Sdumbbell	return 0;
1938254885Sdumbbell}
1939254885Sdumbbell
1940254885Sdumbbellstatic void radeon_cp_dispatch_stipple(struct drm_device * dev, u32 * stipple)
1941254885Sdumbbell{
1942254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
1943254885Sdumbbell	int i;
1944254885Sdumbbell	RING_LOCALS;
1945254885Sdumbbell	DRM_DEBUG("\n");
1946254885Sdumbbell
1947254885Sdumbbell	BEGIN_RING(35);
1948254885Sdumbbell
1949254885Sdumbbell	OUT_RING(CP_PACKET0(RADEON_RE_STIPPLE_ADDR, 0));
1950254885Sdumbbell	OUT_RING(0x00000000);
1951254885Sdumbbell
1952254885Sdumbbell	OUT_RING(CP_PACKET0_TABLE(RADEON_RE_STIPPLE_DATA, 31));
1953254885Sdumbbell	for (i = 0; i < 32; i++) {
1954254885Sdumbbell		OUT_RING(stipple[i]);
1955254885Sdumbbell	}
1956254885Sdumbbell
1957254885Sdumbbell	ADVANCE_RING();
1958254885Sdumbbell}
1959254885Sdumbbell
1960254885Sdumbbellstatic void radeon_apply_surface_regs(int surf_index,
1961254885Sdumbbell				      drm_radeon_private_t *dev_priv)
1962254885Sdumbbell{
1963254885Sdumbbell	if (!dev_priv->mmio)
1964254885Sdumbbell		return;
1965254885Sdumbbell
1966254885Sdumbbell	radeon_do_cp_idle(dev_priv);
1967254885Sdumbbell
1968254885Sdumbbell	RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * surf_index,
1969254885Sdumbbell		     dev_priv->surfaces[surf_index].flags);
1970254885Sdumbbell	RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND + 16 * surf_index,
1971254885Sdumbbell		     dev_priv->surfaces[surf_index].lower);
1972254885Sdumbbell	RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND + 16 * surf_index,
1973254885Sdumbbell		     dev_priv->surfaces[surf_index].upper);
1974254885Sdumbbell}
1975254885Sdumbbell
1976254885Sdumbbell/* Allocates a virtual surface
1977254885Sdumbbell * doesn't always allocate a real surface, will stretch an existing
1978254885Sdumbbell * surface when possible.
1979254885Sdumbbell *
1980254885Sdumbbell * Note that refcount can be at most 2, since during a free refcount=3
1981254885Sdumbbell * might mean we have to allocate a new surface which might not always
1982254885Sdumbbell * be available.
1983254885Sdumbbell * For example : we allocate three contiguous surfaces ABC. If B is
1984254885Sdumbbell * freed, we suddenly need two surfaces to store A and C, which might
1985254885Sdumbbell * not always be available.
1986254885Sdumbbell */
1987254885Sdumbbellstatic int alloc_surface(drm_radeon_surface_alloc_t *new,
1988254885Sdumbbell			 drm_radeon_private_t *dev_priv,
1989254885Sdumbbell			 struct drm_file *file_priv)
1990254885Sdumbbell{
1991254885Sdumbbell	struct radeon_virt_surface *s;
1992254885Sdumbbell	int i;
1993254885Sdumbbell	int virt_surface_index;
1994254885Sdumbbell	uint32_t new_upper, new_lower;
1995254885Sdumbbell
1996254885Sdumbbell	new_lower = new->address;
1997254885Sdumbbell	new_upper = new_lower + new->size - 1;
1998254885Sdumbbell
1999254885Sdumbbell	/* sanity check */
2000254885Sdumbbell	if ((new_lower >= new_upper) || (new->flags == 0) || (new->size == 0) ||
2001254885Sdumbbell	    ((new_upper & RADEON_SURF_ADDRESS_FIXED_MASK) !=
2002254885Sdumbbell	     RADEON_SURF_ADDRESS_FIXED_MASK)
2003254885Sdumbbell	    || ((new_lower & RADEON_SURF_ADDRESS_FIXED_MASK) != 0))
2004254885Sdumbbell		return -1;
2005254885Sdumbbell
2006254885Sdumbbell	/* make sure there is no overlap with existing surfaces */
2007254885Sdumbbell	for (i = 0; i < RADEON_MAX_SURFACES; i++) {
2008254885Sdumbbell		if ((dev_priv->surfaces[i].refcount != 0) &&
2009254885Sdumbbell		    (((new_lower >= dev_priv->surfaces[i].lower) &&
2010254885Sdumbbell		      (new_lower < dev_priv->surfaces[i].upper)) ||
2011254885Sdumbbell		     ((new_lower < dev_priv->surfaces[i].lower) &&
2012254885Sdumbbell		      (new_upper > dev_priv->surfaces[i].lower)))) {
2013254885Sdumbbell			return -1;
2014254885Sdumbbell		}
2015254885Sdumbbell	}
2016254885Sdumbbell
2017254885Sdumbbell	/* find a virtual surface */
2018254885Sdumbbell	for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++)
2019254885Sdumbbell		if (dev_priv->virt_surfaces[i].file_priv == NULL)
2020254885Sdumbbell			break;
2021254885Sdumbbell	if (i == 2 * RADEON_MAX_SURFACES) {
2022254885Sdumbbell		return -1;
2023254885Sdumbbell	}
2024254885Sdumbbell	virt_surface_index = i;
2025254885Sdumbbell
2026254885Sdumbbell	/* try to reuse an existing surface */
2027254885Sdumbbell	for (i = 0; i < RADEON_MAX_SURFACES; i++) {
2028254885Sdumbbell		/* extend before */
2029254885Sdumbbell		if ((dev_priv->surfaces[i].refcount == 1) &&
2030254885Sdumbbell		    (new->flags == dev_priv->surfaces[i].flags) &&
2031254885Sdumbbell		    (new_upper + 1 == dev_priv->surfaces[i].lower)) {
2032254885Sdumbbell			s = &(dev_priv->virt_surfaces[virt_surface_index]);
2033254885Sdumbbell			s->surface_index = i;
2034254885Sdumbbell			s->lower = new_lower;
2035254885Sdumbbell			s->upper = new_upper;
2036254885Sdumbbell			s->flags = new->flags;
2037254885Sdumbbell			s->file_priv = file_priv;
2038254885Sdumbbell			dev_priv->surfaces[i].refcount++;
2039254885Sdumbbell			dev_priv->surfaces[i].lower = s->lower;
2040254885Sdumbbell			radeon_apply_surface_regs(s->surface_index, dev_priv);
2041254885Sdumbbell			return virt_surface_index;
2042254885Sdumbbell		}
2043254885Sdumbbell
2044254885Sdumbbell		/* extend after */
2045254885Sdumbbell		if ((dev_priv->surfaces[i].refcount == 1) &&
2046254885Sdumbbell		    (new->flags == dev_priv->surfaces[i].flags) &&
2047254885Sdumbbell		    (new_lower == dev_priv->surfaces[i].upper + 1)) {
2048254885Sdumbbell			s = &(dev_priv->virt_surfaces[virt_surface_index]);
2049254885Sdumbbell			s->surface_index = i;
2050254885Sdumbbell			s->lower = new_lower;
2051254885Sdumbbell			s->upper = new_upper;
2052254885Sdumbbell			s->flags = new->flags;
2053254885Sdumbbell			s->file_priv = file_priv;
2054254885Sdumbbell			dev_priv->surfaces[i].refcount++;
2055254885Sdumbbell			dev_priv->surfaces[i].upper = s->upper;
2056254885Sdumbbell			radeon_apply_surface_regs(s->surface_index, dev_priv);
2057254885Sdumbbell			return virt_surface_index;
2058254885Sdumbbell		}
2059254885Sdumbbell	}
2060254885Sdumbbell
2061254885Sdumbbell	/* okay, we need a new one */
2062254885Sdumbbell	for (i = 0; i < RADEON_MAX_SURFACES; i++) {
2063254885Sdumbbell		if (dev_priv->surfaces[i].refcount == 0) {
2064254885Sdumbbell			s = &(dev_priv->virt_surfaces[virt_surface_index]);
2065254885Sdumbbell			s->surface_index = i;
2066254885Sdumbbell			s->lower = new_lower;
2067254885Sdumbbell			s->upper = new_upper;
2068254885Sdumbbell			s->flags = new->flags;
2069254885Sdumbbell			s->file_priv = file_priv;
2070254885Sdumbbell			dev_priv->surfaces[i].refcount = 1;
2071254885Sdumbbell			dev_priv->surfaces[i].lower = s->lower;
2072254885Sdumbbell			dev_priv->surfaces[i].upper = s->upper;
2073254885Sdumbbell			dev_priv->surfaces[i].flags = s->flags;
2074254885Sdumbbell			radeon_apply_surface_regs(s->surface_index, dev_priv);
2075254885Sdumbbell			return virt_surface_index;
2076254885Sdumbbell		}
2077254885Sdumbbell	}
2078254885Sdumbbell
2079254885Sdumbbell	/* we didn't find anything */
2080254885Sdumbbell	return -1;
2081254885Sdumbbell}
2082254885Sdumbbell
2083254885Sdumbbellstatic int free_surface(struct drm_file *file_priv,
2084254885Sdumbbell			drm_radeon_private_t * dev_priv,
2085254885Sdumbbell			int lower)
2086254885Sdumbbell{
2087254885Sdumbbell	struct radeon_virt_surface *s;
2088254885Sdumbbell	int i;
2089254885Sdumbbell	/* find the virtual surface */
2090254885Sdumbbell	for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
2091254885Sdumbbell		s = &(dev_priv->virt_surfaces[i]);
2092254885Sdumbbell		if (s->file_priv) {
2093254885Sdumbbell			if ((lower == s->lower) && (file_priv == s->file_priv))
2094254885Sdumbbell			{
2095254885Sdumbbell				if (dev_priv->surfaces[s->surface_index].
2096254885Sdumbbell				    lower == s->lower)
2097254885Sdumbbell					dev_priv->surfaces[s->surface_index].
2098254885Sdumbbell					    lower = s->upper;
2099254885Sdumbbell
2100254885Sdumbbell				if (dev_priv->surfaces[s->surface_index].
2101254885Sdumbbell				    upper == s->upper)
2102254885Sdumbbell					dev_priv->surfaces[s->surface_index].
2103254885Sdumbbell					    upper = s->lower;
2104254885Sdumbbell
2105254885Sdumbbell				dev_priv->surfaces[s->surface_index].refcount--;
2106254885Sdumbbell				if (dev_priv->surfaces[s->surface_index].
2107254885Sdumbbell				    refcount == 0)
2108254885Sdumbbell					dev_priv->surfaces[s->surface_index].
2109254885Sdumbbell					    flags = 0;
2110254885Sdumbbell				s->file_priv = NULL;
2111254885Sdumbbell				radeon_apply_surface_regs(s->surface_index,
2112254885Sdumbbell							  dev_priv);
2113254885Sdumbbell				return 0;
2114254885Sdumbbell			}
2115254885Sdumbbell		}
2116254885Sdumbbell	}
2117254885Sdumbbell	return 1;
2118254885Sdumbbell}
2119254885Sdumbbell
2120254885Sdumbbellstatic void radeon_surfaces_release(struct drm_file *file_priv,
2121254885Sdumbbell				    drm_radeon_private_t * dev_priv)
2122254885Sdumbbell{
2123254885Sdumbbell	int i;
2124254885Sdumbbell	for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
2125254885Sdumbbell		if (dev_priv->virt_surfaces[i].file_priv == file_priv)
2126254885Sdumbbell			free_surface(file_priv, dev_priv,
2127254885Sdumbbell				     dev_priv->virt_surfaces[i].lower);
2128254885Sdumbbell	}
2129254885Sdumbbell}
2130254885Sdumbbell
2131254885Sdumbbell/* ================================================================
2132254885Sdumbbell * IOCTL functions
2133254885Sdumbbell */
2134254885Sdumbbellstatic int radeon_surface_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv)
2135254885Sdumbbell{
2136254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
2137254885Sdumbbell	drm_radeon_surface_alloc_t *alloc = data;
2138254885Sdumbbell
2139254885Sdumbbell	if (alloc_surface(alloc, dev_priv, file_priv) == -1)
2140254885Sdumbbell		return -EINVAL;
2141254885Sdumbbell	else
2142254885Sdumbbell		return 0;
2143254885Sdumbbell}
2144254885Sdumbbell
2145254885Sdumbbellstatic int radeon_surface_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
2146254885Sdumbbell{
2147254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
2148254885Sdumbbell	drm_radeon_surface_free_t *memfree = data;
2149254885Sdumbbell
2150254885Sdumbbell	if (free_surface(file_priv, dev_priv, memfree->address))
2151254885Sdumbbell		return -EINVAL;
2152254885Sdumbbell	else
2153254885Sdumbbell		return 0;
2154254885Sdumbbell}
2155254885Sdumbbell
2156254885Sdumbbellstatic int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file *file_priv)
2157254885Sdumbbell{
2158254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
2159254885Sdumbbell	struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv;
2160254885Sdumbbell	drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;
2161254885Sdumbbell	drm_radeon_clear_t *clear = data;
2162254885Sdumbbell	drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
2163254885Sdumbbell	DRM_DEBUG("\n");
2164254885Sdumbbell
2165254885Sdumbbell	LOCK_TEST_WITH_RETURN(dev, file_priv);
2166254885Sdumbbell
2167254885Sdumbbell	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2168254885Sdumbbell
2169254885Sdumbbell	if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
2170254885Sdumbbell		sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
2171254885Sdumbbell
2172254885Sdumbbell	if (DRM_COPY_FROM_USER(&depth_boxes, clear->depth_boxes,
2173254885Sdumbbell			       sarea_priv->nbox * sizeof(depth_boxes[0])))
2174254885Sdumbbell		return -EFAULT;
2175254885Sdumbbell
2176254885Sdumbbell	radeon_cp_dispatch_clear(dev, file_priv->masterp, clear, depth_boxes);
2177254885Sdumbbell
2178254885Sdumbbell	COMMIT_RING();
2179254885Sdumbbell	return 0;
2180254885Sdumbbell}
2181254885Sdumbbell
2182254885Sdumbbell/* Not sure why this isn't set all the time:
2183254885Sdumbbell */
2184254885Sdumbbellstatic int radeon_do_init_pageflip(struct drm_device *dev, struct drm_master *master)
2185254885Sdumbbell{
2186254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
2187254885Sdumbbell	struct drm_radeon_master_private *master_priv = master->driver_priv;
2188254885Sdumbbell	RING_LOCALS;
2189254885Sdumbbell
2190254885Sdumbbell	DRM_DEBUG("\n");
2191254885Sdumbbell
2192254885Sdumbbell	BEGIN_RING(6);
2193254885Sdumbbell	RADEON_WAIT_UNTIL_3D_IDLE();
2194254885Sdumbbell	OUT_RING(CP_PACKET0(RADEON_CRTC_OFFSET_CNTL, 0));
2195254885Sdumbbell	OUT_RING(RADEON_READ(RADEON_CRTC_OFFSET_CNTL) |
2196254885Sdumbbell		 RADEON_CRTC_OFFSET_FLIP_CNTL);
2197254885Sdumbbell	OUT_RING(CP_PACKET0(RADEON_CRTC2_OFFSET_CNTL, 0));
2198254885Sdumbbell	OUT_RING(RADEON_READ(RADEON_CRTC2_OFFSET_CNTL) |
2199254885Sdumbbell		 RADEON_CRTC_OFFSET_FLIP_CNTL);
2200254885Sdumbbell	ADVANCE_RING();
2201254885Sdumbbell
2202254885Sdumbbell	dev_priv->page_flipping = 1;
2203254885Sdumbbell
2204254885Sdumbbell	if (master_priv->sarea_priv->pfCurrentPage != 1)
2205254885Sdumbbell		master_priv->sarea_priv->pfCurrentPage = 0;
2206254885Sdumbbell
2207254885Sdumbbell	return 0;
2208254885Sdumbbell}
2209254885Sdumbbell
2210254885Sdumbbell/* Swapping and flipping are different operations, need different ioctls.
2211254885Sdumbbell * They can & should be intermixed to support multiple 3d windows.
2212254885Sdumbbell */
2213254885Sdumbbellstatic int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *file_priv)
2214254885Sdumbbell{
2215254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
2216254885Sdumbbell	DRM_DEBUG("\n");
2217254885Sdumbbell
2218254885Sdumbbell	LOCK_TEST_WITH_RETURN(dev, file_priv);
2219254885Sdumbbell
2220254885Sdumbbell	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2221254885Sdumbbell
2222254885Sdumbbell	if (!dev_priv->page_flipping)
2223254885Sdumbbell		radeon_do_init_pageflip(dev, file_priv->masterp);
2224254885Sdumbbell
2225254885Sdumbbell	radeon_cp_dispatch_flip(dev, file_priv->masterp);
2226254885Sdumbbell
2227254885Sdumbbell	COMMIT_RING();
2228254885Sdumbbell	return 0;
2229254885Sdumbbell}
2230254885Sdumbbell
2231254885Sdumbbellstatic int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *file_priv)
2232254885Sdumbbell{
2233254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
2234254885Sdumbbell	struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv;
2235254885Sdumbbell	drm_radeon_sarea_t *sarea_priv = master_priv->sarea_priv;
2236254885Sdumbbell
2237254885Sdumbbell	DRM_DEBUG("\n");
2238254885Sdumbbell
2239254885Sdumbbell	LOCK_TEST_WITH_RETURN(dev, file_priv);
2240254885Sdumbbell
2241254885Sdumbbell	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2242254885Sdumbbell
2243254885Sdumbbell	if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
2244254885Sdumbbell		sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
2245254885Sdumbbell
2246254885Sdumbbell	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
2247254885Sdumbbell		r600_cp_dispatch_swap(dev, file_priv);
2248254885Sdumbbell	else
2249254885Sdumbbell		radeon_cp_dispatch_swap(dev, file_priv->masterp);
2250254885Sdumbbell	sarea_priv->ctx_owner = 0;
2251254885Sdumbbell
2252254885Sdumbbell	COMMIT_RING();
2253254885Sdumbbell	return 0;
2254254885Sdumbbell}
2255254885Sdumbbell
2256254885Sdumbbellstatic int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv)
2257254885Sdumbbell{
2258254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
2259254885Sdumbbell	struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv;
2260254885Sdumbbell	drm_radeon_sarea_t *sarea_priv;
2261254885Sdumbbell	struct drm_device_dma *dma = dev->dma;
2262254885Sdumbbell	struct drm_buf *buf;
2263254885Sdumbbell	drm_radeon_vertex_t *vertex = data;
2264254885Sdumbbell	drm_radeon_tcl_prim_t prim;
2265254885Sdumbbell
2266254885Sdumbbell	LOCK_TEST_WITH_RETURN(dev, file_priv);
2267254885Sdumbbell
2268254885Sdumbbell	sarea_priv = master_priv->sarea_priv;
2269254885Sdumbbell
2270254885Sdumbbell	DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n",
2271254885Sdumbbell		  DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard);
2272254885Sdumbbell
2273254885Sdumbbell	if (vertex->idx < 0 || vertex->idx >= dma->buf_count) {
2274254885Sdumbbell		DRM_ERROR("buffer index %d (of %d max)\n",
2275254885Sdumbbell			  vertex->idx, dma->buf_count - 1);
2276254885Sdumbbell		return -EINVAL;
2277254885Sdumbbell	}
2278254885Sdumbbell	if (vertex->prim < 0 || vertex->prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
2279254885Sdumbbell		DRM_ERROR("buffer prim %d\n", vertex->prim);
2280254885Sdumbbell		return -EINVAL;
2281254885Sdumbbell	}
2282254885Sdumbbell
2283254885Sdumbbell	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2284254885Sdumbbell	VB_AGE_TEST_WITH_RETURN(dev_priv);
2285254885Sdumbbell
2286254885Sdumbbell	buf = dma->buflist[vertex->idx];
2287254885Sdumbbell
2288254885Sdumbbell	if (buf->file_priv != file_priv) {
2289254885Sdumbbell		DRM_ERROR("process %d using buffer owned by %p\n",
2290254885Sdumbbell			  DRM_CURRENTPID, buf->file_priv);
2291254885Sdumbbell		return -EINVAL;
2292254885Sdumbbell	}
2293254885Sdumbbell	if (buf->pending) {
2294254885Sdumbbell		DRM_ERROR("sending pending buffer %d\n", vertex->idx);
2295254885Sdumbbell		return -EINVAL;
2296254885Sdumbbell	}
2297254885Sdumbbell
2298254885Sdumbbell	/* Build up a prim_t record:
2299254885Sdumbbell	 */
2300254885Sdumbbell	if (vertex->count) {
2301254885Sdumbbell		buf->used = vertex->count;	/* not used? */
2302254885Sdumbbell
2303254885Sdumbbell		if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
2304254885Sdumbbell			if (radeon_emit_state(dev_priv, file_priv,
2305254885Sdumbbell					      &sarea_priv->context_state,
2306254885Sdumbbell					      sarea_priv->tex_state,
2307254885Sdumbbell					      sarea_priv->dirty)) {
2308254885Sdumbbell				DRM_ERROR("radeon_emit_state failed\n");
2309254885Sdumbbell				return -EINVAL;
2310254885Sdumbbell			}
2311254885Sdumbbell
2312254885Sdumbbell			sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
2313254885Sdumbbell					       RADEON_UPLOAD_TEX1IMAGES |
2314254885Sdumbbell					       RADEON_UPLOAD_TEX2IMAGES |
2315254885Sdumbbell					       RADEON_REQUIRE_QUIESCENCE);
2316254885Sdumbbell		}
2317254885Sdumbbell
2318254885Sdumbbell		prim.start = 0;
2319254885Sdumbbell		prim.finish = vertex->count;	/* unused */
2320254885Sdumbbell		prim.prim = vertex->prim;
2321254885Sdumbbell		prim.numverts = vertex->count;
2322254885Sdumbbell		prim.vc_format = sarea_priv->vc_format;
2323254885Sdumbbell
2324254885Sdumbbell		radeon_cp_dispatch_vertex(dev, file_priv, buf, &prim);
2325254885Sdumbbell	}
2326254885Sdumbbell
2327254885Sdumbbell	if (vertex->discard) {
2328254885Sdumbbell		radeon_cp_discard_buffer(dev, file_priv->masterp, buf);
2329254885Sdumbbell	}
2330254885Sdumbbell
2331254885Sdumbbell	COMMIT_RING();
2332254885Sdumbbell	return 0;
2333254885Sdumbbell}
2334254885Sdumbbell
2335254885Sdumbbellstatic int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file *file_priv)
2336254885Sdumbbell{
2337254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
2338254885Sdumbbell	struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv;
2339254885Sdumbbell	drm_radeon_sarea_t *sarea_priv;
2340254885Sdumbbell	struct drm_device_dma *dma = dev->dma;
2341254885Sdumbbell	struct drm_buf *buf;
2342254885Sdumbbell	drm_radeon_indices_t *elts = data;
2343254885Sdumbbell	drm_radeon_tcl_prim_t prim;
2344254885Sdumbbell	int count;
2345254885Sdumbbell
2346254885Sdumbbell	LOCK_TEST_WITH_RETURN(dev, file_priv);
2347254885Sdumbbell
2348254885Sdumbbell	sarea_priv = master_priv->sarea_priv;
2349254885Sdumbbell
2350254885Sdumbbell	DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n",
2351254885Sdumbbell		  DRM_CURRENTPID, elts->idx, elts->start, elts->end,
2352254885Sdumbbell		  elts->discard);
2353254885Sdumbbell
2354254885Sdumbbell	if (elts->idx < 0 || elts->idx >= dma->buf_count) {
2355254885Sdumbbell		DRM_ERROR("buffer index %d (of %d max)\n",
2356254885Sdumbbell			  elts->idx, dma->buf_count - 1);
2357254885Sdumbbell		return -EINVAL;
2358254885Sdumbbell	}
2359254885Sdumbbell	if (elts->prim < 0 || elts->prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
2360254885Sdumbbell		DRM_ERROR("buffer prim %d\n", elts->prim);
2361254885Sdumbbell		return -EINVAL;
2362254885Sdumbbell	}
2363254885Sdumbbell
2364254885Sdumbbell	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2365254885Sdumbbell	VB_AGE_TEST_WITH_RETURN(dev_priv);
2366254885Sdumbbell
2367254885Sdumbbell	buf = dma->buflist[elts->idx];
2368254885Sdumbbell
2369254885Sdumbbell	if (buf->file_priv != file_priv) {
2370254885Sdumbbell		DRM_ERROR("process %d using buffer owned by %p\n",
2371254885Sdumbbell			  DRM_CURRENTPID, buf->file_priv);
2372254885Sdumbbell		return -EINVAL;
2373254885Sdumbbell	}
2374254885Sdumbbell	if (buf->pending) {
2375254885Sdumbbell		DRM_ERROR("sending pending buffer %d\n", elts->idx);
2376254885Sdumbbell		return -EINVAL;
2377254885Sdumbbell	}
2378254885Sdumbbell
2379254885Sdumbbell	count = (elts->end - elts->start) / sizeof(u16);
2380254885Sdumbbell	elts->start -= RADEON_INDEX_PRIM_OFFSET;
2381254885Sdumbbell
2382254885Sdumbbell	if (elts->start & 0x7) {
2383254885Sdumbbell		DRM_ERROR("misaligned buffer 0x%x\n", elts->start);
2384254885Sdumbbell		return -EINVAL;
2385254885Sdumbbell	}
2386254885Sdumbbell	if (elts->start < buf->used) {
2387254885Sdumbbell		DRM_ERROR("no header 0x%x - 0x%x\n", elts->start, buf->used);
2388254885Sdumbbell		return -EINVAL;
2389254885Sdumbbell	}
2390254885Sdumbbell
2391254885Sdumbbell	buf->used = elts->end;
2392254885Sdumbbell
2393254885Sdumbbell	if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
2394254885Sdumbbell		if (radeon_emit_state(dev_priv, file_priv,
2395254885Sdumbbell				      &sarea_priv->context_state,
2396254885Sdumbbell				      sarea_priv->tex_state,
2397254885Sdumbbell				      sarea_priv->dirty)) {
2398254885Sdumbbell			DRM_ERROR("radeon_emit_state failed\n");
2399254885Sdumbbell			return -EINVAL;
2400254885Sdumbbell		}
2401254885Sdumbbell
2402254885Sdumbbell		sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
2403254885Sdumbbell				       RADEON_UPLOAD_TEX1IMAGES |
2404254885Sdumbbell				       RADEON_UPLOAD_TEX2IMAGES |
2405254885Sdumbbell				       RADEON_REQUIRE_QUIESCENCE);
2406254885Sdumbbell	}
2407254885Sdumbbell
2408254885Sdumbbell	/* Build up a prim_t record:
2409254885Sdumbbell	 */
2410254885Sdumbbell	prim.start = elts->start;
2411254885Sdumbbell	prim.finish = elts->end;
2412254885Sdumbbell	prim.prim = elts->prim;
2413254885Sdumbbell	prim.offset = 0;	/* offset from start of dma buffers */
2414254885Sdumbbell	prim.numverts = RADEON_MAX_VB_VERTS;	/* duh */
2415254885Sdumbbell	prim.vc_format = sarea_priv->vc_format;
2416254885Sdumbbell
2417254885Sdumbbell	radeon_cp_dispatch_indices(dev, file_priv->masterp, buf, &prim);
2418254885Sdumbbell	if (elts->discard) {
2419254885Sdumbbell		radeon_cp_discard_buffer(dev, file_priv->masterp, buf);
2420254885Sdumbbell	}
2421254885Sdumbbell
2422254885Sdumbbell	COMMIT_RING();
2423254885Sdumbbell	return 0;
2424254885Sdumbbell}
2425254885Sdumbbell
2426254885Sdumbbellstatic int radeon_cp_texture(struct drm_device *dev, void *data, struct drm_file *file_priv)
2427254885Sdumbbell{
2428254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
2429254885Sdumbbell	drm_radeon_texture_t *tex = data;
2430254885Sdumbbell	drm_radeon_tex_image_t image;
2431254885Sdumbbell	int ret;
2432254885Sdumbbell
2433254885Sdumbbell	LOCK_TEST_WITH_RETURN(dev, file_priv);
2434254885Sdumbbell
2435254885Sdumbbell	if (tex->image == NULL) {
2436254885Sdumbbell		DRM_ERROR("null texture image!\n");
2437254885Sdumbbell		return -EINVAL;
2438254885Sdumbbell	}
2439254885Sdumbbell
2440254885Sdumbbell	if (DRM_COPY_FROM_USER(&image,
2441254885Sdumbbell			       (drm_radeon_tex_image_t __user *) tex->image,
2442254885Sdumbbell			       sizeof(image)))
2443254885Sdumbbell		return -EFAULT;
2444254885Sdumbbell
2445254885Sdumbbell	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2446254885Sdumbbell	VB_AGE_TEST_WITH_RETURN(dev_priv);
2447254885Sdumbbell
2448254885Sdumbbell	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
2449254885Sdumbbell		ret = r600_cp_dispatch_texture(dev, file_priv, tex, &image);
2450254885Sdumbbell	else
2451254885Sdumbbell		ret = radeon_cp_dispatch_texture(dev, file_priv, tex, &image);
2452254885Sdumbbell
2453254885Sdumbbell	return ret;
2454254885Sdumbbell}
2455254885Sdumbbell
2456254885Sdumbbellstatic int radeon_cp_stipple(struct drm_device *dev, void *data, struct drm_file *file_priv)
2457254885Sdumbbell{
2458254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
2459254885Sdumbbell	drm_radeon_stipple_t *stipple = data;
2460254885Sdumbbell	u32 mask[32];
2461254885Sdumbbell
2462254885Sdumbbell	LOCK_TEST_WITH_RETURN(dev, file_priv);
2463254885Sdumbbell
2464254885Sdumbbell	if (DRM_COPY_FROM_USER(&mask, stipple->mask, 32 * sizeof(u32)))
2465254885Sdumbbell		return -EFAULT;
2466254885Sdumbbell
2467254885Sdumbbell	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2468254885Sdumbbell
2469254885Sdumbbell	radeon_cp_dispatch_stipple(dev, mask);
2470254885Sdumbbell
2471254885Sdumbbell	COMMIT_RING();
2472254885Sdumbbell	return 0;
2473254885Sdumbbell}
2474254885Sdumbbell
2475254885Sdumbbellstatic int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_file *file_priv)
2476254885Sdumbbell{
2477254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
2478254885Sdumbbell	struct drm_device_dma *dma = dev->dma;
2479254885Sdumbbell	struct drm_buf *buf;
2480254885Sdumbbell	drm_radeon_indirect_t *indirect = data;
2481254885Sdumbbell	RING_LOCALS;
2482254885Sdumbbell
2483254885Sdumbbell	LOCK_TEST_WITH_RETURN(dev, file_priv);
2484254885Sdumbbell
2485254885Sdumbbell	DRM_DEBUG("idx=%d s=%d e=%d d=%d\n",
2486254885Sdumbbell		  indirect->idx, indirect->start, indirect->end,
2487254885Sdumbbell		  indirect->discard);
2488254885Sdumbbell
2489254885Sdumbbell	if (indirect->idx < 0 || indirect->idx >= dma->buf_count) {
2490254885Sdumbbell		DRM_ERROR("buffer index %d (of %d max)\n",
2491254885Sdumbbell			  indirect->idx, dma->buf_count - 1);
2492254885Sdumbbell		return -EINVAL;
2493254885Sdumbbell	}
2494254885Sdumbbell
2495254885Sdumbbell	buf = dma->buflist[indirect->idx];
2496254885Sdumbbell
2497254885Sdumbbell	if (buf->file_priv != file_priv) {
2498254885Sdumbbell		DRM_ERROR("process %d using buffer owned by %p\n",
2499254885Sdumbbell			  DRM_CURRENTPID, buf->file_priv);
2500254885Sdumbbell		return -EINVAL;
2501254885Sdumbbell	}
2502254885Sdumbbell	if (buf->pending) {
2503254885Sdumbbell		DRM_ERROR("sending pending buffer %d\n", indirect->idx);
2504254885Sdumbbell		return -EINVAL;
2505254885Sdumbbell	}
2506254885Sdumbbell
2507254885Sdumbbell	if (indirect->start < buf->used) {
2508254885Sdumbbell		DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n",
2509254885Sdumbbell			  indirect->start, buf->used);
2510254885Sdumbbell		return -EINVAL;
2511254885Sdumbbell	}
2512254885Sdumbbell
2513254885Sdumbbell	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2514254885Sdumbbell	VB_AGE_TEST_WITH_RETURN(dev_priv);
2515254885Sdumbbell
2516254885Sdumbbell	buf->used = indirect->end;
2517254885Sdumbbell
2518254885Sdumbbell	/* Dispatch the indirect buffer full of commands from the
2519254885Sdumbbell	 * X server.  This is insecure and is thus only available to
2520254885Sdumbbell	 * privileged clients.
2521254885Sdumbbell	 */
2522254885Sdumbbell	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
2523254885Sdumbbell		r600_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end);
2524254885Sdumbbell	else {
2525254885Sdumbbell		/* Wait for the 3D stream to idle before the indirect buffer
2526254885Sdumbbell		 * containing 2D acceleration commands is processed.
2527254885Sdumbbell		 */
2528254885Sdumbbell		BEGIN_RING(2);
2529254885Sdumbbell		RADEON_WAIT_UNTIL_3D_IDLE();
2530254885Sdumbbell		ADVANCE_RING();
2531254885Sdumbbell		radeon_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end);
2532254885Sdumbbell	}
2533254885Sdumbbell
2534254885Sdumbbell	if (indirect->discard) {
2535254885Sdumbbell		radeon_cp_discard_buffer(dev, file_priv->masterp, buf);
2536254885Sdumbbell	}
2537254885Sdumbbell
2538254885Sdumbbell	COMMIT_RING();
2539254885Sdumbbell	return 0;
2540254885Sdumbbell}
2541254885Sdumbbell
2542254885Sdumbbellstatic int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file *file_priv)
2543254885Sdumbbell{
2544254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
2545254885Sdumbbell	struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv;
2546254885Sdumbbell	drm_radeon_sarea_t *sarea_priv;
2547254885Sdumbbell	struct drm_device_dma *dma = dev->dma;
2548254885Sdumbbell	struct drm_buf *buf;
2549254885Sdumbbell	drm_radeon_vertex2_t *vertex = data;
2550254885Sdumbbell	int i;
2551254885Sdumbbell	unsigned char laststate;
2552254885Sdumbbell
2553254885Sdumbbell	LOCK_TEST_WITH_RETURN(dev, file_priv);
2554254885Sdumbbell
2555254885Sdumbbell	sarea_priv = master_priv->sarea_priv;
2556254885Sdumbbell
2557254885Sdumbbell	DRM_DEBUG("pid=%d index=%d discard=%d\n",
2558254885Sdumbbell		  DRM_CURRENTPID, vertex->idx, vertex->discard);
2559254885Sdumbbell
2560254885Sdumbbell	if (vertex->idx < 0 || vertex->idx >= dma->buf_count) {
2561254885Sdumbbell		DRM_ERROR("buffer index %d (of %d max)\n",
2562254885Sdumbbell			  vertex->idx, dma->buf_count - 1);
2563254885Sdumbbell		return -EINVAL;
2564254885Sdumbbell	}
2565254885Sdumbbell
2566254885Sdumbbell	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2567254885Sdumbbell	VB_AGE_TEST_WITH_RETURN(dev_priv);
2568254885Sdumbbell
2569254885Sdumbbell	buf = dma->buflist[vertex->idx];
2570254885Sdumbbell
2571254885Sdumbbell	if (buf->file_priv != file_priv) {
2572254885Sdumbbell		DRM_ERROR("process %d using buffer owned by %p\n",
2573254885Sdumbbell			  DRM_CURRENTPID, buf->file_priv);
2574254885Sdumbbell		return -EINVAL;
2575254885Sdumbbell	}
2576254885Sdumbbell
2577254885Sdumbbell	if (buf->pending) {
2578254885Sdumbbell		DRM_ERROR("sending pending buffer %d\n", vertex->idx);
2579254885Sdumbbell		return -EINVAL;
2580254885Sdumbbell	}
2581254885Sdumbbell
2582254885Sdumbbell	if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
2583254885Sdumbbell		return -EINVAL;
2584254885Sdumbbell
2585254885Sdumbbell	for (laststate = 0xff, i = 0; i < vertex->nr_prims; i++) {
2586254885Sdumbbell		drm_radeon_prim_t prim;
2587254885Sdumbbell		drm_radeon_tcl_prim_t tclprim;
2588254885Sdumbbell
2589254885Sdumbbell		if (DRM_COPY_FROM_USER(&prim, &vertex->prim[i], sizeof(prim)))
2590254885Sdumbbell			return -EFAULT;
2591254885Sdumbbell
2592254885Sdumbbell		if (prim.stateidx != laststate) {
2593254885Sdumbbell			drm_radeon_state_t state;
2594254885Sdumbbell
2595254885Sdumbbell			if (DRM_COPY_FROM_USER(&state,
2596254885Sdumbbell					       &vertex->state[prim.stateidx],
2597254885Sdumbbell					       sizeof(state)))
2598254885Sdumbbell				return -EFAULT;
2599254885Sdumbbell
2600254885Sdumbbell			if (radeon_emit_state2(dev_priv, file_priv, &state)) {
2601254885Sdumbbell				DRM_ERROR("radeon_emit_state2 failed\n");
2602254885Sdumbbell				return -EINVAL;
2603254885Sdumbbell			}
2604254885Sdumbbell
2605254885Sdumbbell			laststate = prim.stateidx;
2606254885Sdumbbell		}
2607254885Sdumbbell
2608254885Sdumbbell		tclprim.start = prim.start;
2609254885Sdumbbell		tclprim.finish = prim.finish;
2610254885Sdumbbell		tclprim.prim = prim.prim;
2611254885Sdumbbell		tclprim.vc_format = prim.vc_format;
2612254885Sdumbbell
2613254885Sdumbbell		if (prim.prim & RADEON_PRIM_WALK_IND) {
2614254885Sdumbbell			tclprim.offset = prim.numverts * 64;
2615254885Sdumbbell			tclprim.numverts = RADEON_MAX_VB_VERTS;	/* duh */
2616254885Sdumbbell
2617254885Sdumbbell			radeon_cp_dispatch_indices(dev, file_priv->masterp, buf, &tclprim);
2618254885Sdumbbell		} else {
2619254885Sdumbbell			tclprim.numverts = prim.numverts;
2620254885Sdumbbell			tclprim.offset = 0;	/* not used */
2621254885Sdumbbell
2622254885Sdumbbell			radeon_cp_dispatch_vertex(dev, file_priv, buf, &tclprim);
2623254885Sdumbbell		}
2624254885Sdumbbell
2625254885Sdumbbell		if (sarea_priv->nbox == 1)
2626254885Sdumbbell			sarea_priv->nbox = 0;
2627254885Sdumbbell	}
2628254885Sdumbbell
2629254885Sdumbbell	if (vertex->discard) {
2630254885Sdumbbell		radeon_cp_discard_buffer(dev, file_priv->masterp, buf);
2631254885Sdumbbell	}
2632254885Sdumbbell
2633254885Sdumbbell	COMMIT_RING();
2634254885Sdumbbell	return 0;
2635254885Sdumbbell}
2636254885Sdumbbell
2637254885Sdumbbellstatic int radeon_emit_packets(drm_radeon_private_t * dev_priv,
2638254885Sdumbbell			       struct drm_file *file_priv,
2639254885Sdumbbell			       drm_radeon_cmd_header_t header,
2640254885Sdumbbell			       drm_radeon_kcmd_buffer_t *cmdbuf)
2641254885Sdumbbell{
2642254885Sdumbbell	int id = (int)header.packet.packet_id;
2643254885Sdumbbell	int sz, reg;
2644254885Sdumbbell	RING_LOCALS;
2645254885Sdumbbell
2646254885Sdumbbell	if (id >= RADEON_MAX_STATE_PACKETS)
2647254885Sdumbbell		return -EINVAL;
2648254885Sdumbbell
2649254885Sdumbbell	sz = packet[id].len;
2650254885Sdumbbell	reg = packet[id].start;
2651254885Sdumbbell
2652254885Sdumbbell	if (sz * sizeof(u32) > drm_buffer_unprocessed(cmdbuf->buffer)) {
2653254885Sdumbbell		DRM_ERROR("Packet size provided larger than data provided\n");
2654254885Sdumbbell		return -EINVAL;
2655254885Sdumbbell	}
2656254885Sdumbbell
2657254885Sdumbbell	if (radeon_check_and_fixup_packets(dev_priv, file_priv, id,
2658254885Sdumbbell				cmdbuf->buffer)) {
2659254885Sdumbbell		DRM_ERROR("Packet verification failed\n");
2660254885Sdumbbell		return -EINVAL;
2661254885Sdumbbell	}
2662254885Sdumbbell
2663254885Sdumbbell	BEGIN_RING(sz + 1);
2664254885Sdumbbell	OUT_RING(CP_PACKET0(reg, (sz - 1)));
2665254885Sdumbbell	OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz);
2666254885Sdumbbell	ADVANCE_RING();
2667254885Sdumbbell
2668254885Sdumbbell	return 0;
2669254885Sdumbbell}
2670254885Sdumbbell
2671254885Sdumbbellstatic __inline__ int radeon_emit_scalars(drm_radeon_private_t *dev_priv,
2672254885Sdumbbell					  drm_radeon_cmd_header_t header,
2673254885Sdumbbell					  drm_radeon_kcmd_buffer_t *cmdbuf)
2674254885Sdumbbell{
2675254885Sdumbbell	int sz = header.scalars.count;
2676254885Sdumbbell	int start = header.scalars.offset;
2677254885Sdumbbell	int stride = header.scalars.stride;
2678254885Sdumbbell	RING_LOCALS;
2679254885Sdumbbell
2680254885Sdumbbell	BEGIN_RING(3 + sz);
2681254885Sdumbbell	OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
2682254885Sdumbbell	OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
2683254885Sdumbbell	OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
2684254885Sdumbbell	OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz);
2685254885Sdumbbell	ADVANCE_RING();
2686254885Sdumbbell	return 0;
2687254885Sdumbbell}
2688254885Sdumbbell
2689254885Sdumbbell/* God this is ugly
2690254885Sdumbbell */
2691254885Sdumbbellstatic __inline__ int radeon_emit_scalars2(drm_radeon_private_t *dev_priv,
2692254885Sdumbbell					   drm_radeon_cmd_header_t header,
2693254885Sdumbbell					   drm_radeon_kcmd_buffer_t *cmdbuf)
2694254885Sdumbbell{
2695254885Sdumbbell	int sz = header.scalars.count;
2696254885Sdumbbell	int start = ((unsigned int)header.scalars.offset) + 0x100;
2697254885Sdumbbell	int stride = header.scalars.stride;
2698254885Sdumbbell	RING_LOCALS;
2699254885Sdumbbell
2700254885Sdumbbell	BEGIN_RING(3 + sz);
2701254885Sdumbbell	OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
2702254885Sdumbbell	OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
2703254885Sdumbbell	OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
2704254885Sdumbbell	OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz);
2705254885Sdumbbell	ADVANCE_RING();
2706254885Sdumbbell	return 0;
2707254885Sdumbbell}
2708254885Sdumbbell
2709254885Sdumbbellstatic __inline__ int radeon_emit_vectors(drm_radeon_private_t *dev_priv,
2710254885Sdumbbell					  drm_radeon_cmd_header_t header,
2711254885Sdumbbell					  drm_radeon_kcmd_buffer_t *cmdbuf)
2712254885Sdumbbell{
2713254885Sdumbbell	int sz = header.vectors.count;
2714254885Sdumbbell	int start = header.vectors.offset;
2715254885Sdumbbell	int stride = header.vectors.stride;
2716254885Sdumbbell	RING_LOCALS;
2717254885Sdumbbell
2718254885Sdumbbell	BEGIN_RING(5 + sz);
2719254885Sdumbbell	OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
2720254885Sdumbbell	OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
2721254885Sdumbbell	OUT_RING(start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
2722254885Sdumbbell	OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
2723254885Sdumbbell	OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz);
2724254885Sdumbbell	ADVANCE_RING();
2725254885Sdumbbell
2726254885Sdumbbell	return 0;
2727254885Sdumbbell}
2728254885Sdumbbell
2729254885Sdumbbellstatic __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv,
2730254885Sdumbbell					  drm_radeon_cmd_header_t header,
2731254885Sdumbbell					  drm_radeon_kcmd_buffer_t *cmdbuf)
2732254885Sdumbbell{
2733254885Sdumbbell	int sz = header.veclinear.count * 4;
2734254885Sdumbbell	int start = header.veclinear.addr_lo | (header.veclinear.addr_hi << 8);
2735254885Sdumbbell	RING_LOCALS;
2736254885Sdumbbell
2737254885Sdumbbell        if (!sz)
2738254885Sdumbbell                return 0;
2739254885Sdumbbell	if (sz * 4 > drm_buffer_unprocessed(cmdbuf->buffer))
2740254885Sdumbbell                return -EINVAL;
2741254885Sdumbbell
2742254885Sdumbbell	BEGIN_RING(5 + sz);
2743254885Sdumbbell	OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
2744254885Sdumbbell	OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
2745254885Sdumbbell	OUT_RING(start | (1 << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
2746254885Sdumbbell	OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
2747254885Sdumbbell	OUT_RING_DRM_BUFFER(cmdbuf->buffer, sz);
2748254885Sdumbbell	ADVANCE_RING();
2749254885Sdumbbell
2750254885Sdumbbell	return 0;
2751254885Sdumbbell}
2752254885Sdumbbell
2753254885Sdumbbellstatic int radeon_emit_packet3(struct drm_device * dev,
2754254885Sdumbbell			       struct drm_file *file_priv,
2755254885Sdumbbell			       drm_radeon_kcmd_buffer_t *cmdbuf)
2756254885Sdumbbell{
2757254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
2758254885Sdumbbell	unsigned int cmdsz;
2759254885Sdumbbell	int ret;
2760254885Sdumbbell	RING_LOCALS;
2761254885Sdumbbell
2762254885Sdumbbell	DRM_DEBUG("\n");
2763254885Sdumbbell
2764254885Sdumbbell	if ((ret = radeon_check_and_fixup_packet3(dev_priv, file_priv,
2765254885Sdumbbell						  cmdbuf, &cmdsz))) {
2766254885Sdumbbell		DRM_ERROR("Packet verification failed\n");
2767254885Sdumbbell		return ret;
2768254885Sdumbbell	}
2769254885Sdumbbell
2770254885Sdumbbell	BEGIN_RING(cmdsz);
2771254885Sdumbbell	OUT_RING_DRM_BUFFER(cmdbuf->buffer, cmdsz);
2772254885Sdumbbell	ADVANCE_RING();
2773254885Sdumbbell
2774254885Sdumbbell	return 0;
2775254885Sdumbbell}
2776254885Sdumbbell
2777254885Sdumbbellstatic int radeon_emit_packet3_cliprect(struct drm_device *dev,
2778254885Sdumbbell					struct drm_file *file_priv,
2779254885Sdumbbell					drm_radeon_kcmd_buffer_t *cmdbuf,
2780254885Sdumbbell					int orig_nbox)
2781254885Sdumbbell{
2782254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
2783254885Sdumbbell	struct drm_clip_rect box;
2784254885Sdumbbell	unsigned int cmdsz;
2785254885Sdumbbell	int ret;
2786254885Sdumbbell	struct drm_clip_rect __user *boxes = cmdbuf->boxes;
2787254885Sdumbbell	int i = 0;
2788254885Sdumbbell	RING_LOCALS;
2789254885Sdumbbell
2790254885Sdumbbell	DRM_DEBUG("\n");
2791254885Sdumbbell
2792254885Sdumbbell	if ((ret = radeon_check_and_fixup_packet3(dev_priv, file_priv,
2793254885Sdumbbell						  cmdbuf, &cmdsz))) {
2794254885Sdumbbell		DRM_ERROR("Packet verification failed\n");
2795254885Sdumbbell		return ret;
2796254885Sdumbbell	}
2797254885Sdumbbell
2798254885Sdumbbell	if (!orig_nbox)
2799254885Sdumbbell		goto out;
2800254885Sdumbbell
2801254885Sdumbbell	do {
2802254885Sdumbbell		if (i < cmdbuf->nbox) {
2803254885Sdumbbell			if (DRM_COPY_FROM_USER(&box, &boxes[i], sizeof(box)))
2804254885Sdumbbell				return -EFAULT;
2805254885Sdumbbell			/* FIXME The second and subsequent times round
2806254885Sdumbbell			 * this loop, send a WAIT_UNTIL_3D_IDLE before
2807254885Sdumbbell			 * calling emit_clip_rect(). This fixes a
2808254885Sdumbbell			 * lockup on fast machines when sending
2809254885Sdumbbell			 * several cliprects with a cmdbuf, as when
2810254885Sdumbbell			 * waving a 2D window over a 3D
2811254885Sdumbbell			 * window. Something in the commands from user
2812254885Sdumbbell			 * space seems to hang the card when they're
2813254885Sdumbbell			 * sent several times in a row. That would be
2814254885Sdumbbell			 * the correct place to fix it but this works
2815254885Sdumbbell			 * around it until I can figure that out - Tim
2816254885Sdumbbell			 * Smith */
2817254885Sdumbbell			if (i) {
2818254885Sdumbbell				BEGIN_RING(2);
2819254885Sdumbbell				RADEON_WAIT_UNTIL_3D_IDLE();
2820254885Sdumbbell				ADVANCE_RING();
2821254885Sdumbbell			}
2822254885Sdumbbell			radeon_emit_clip_rect(dev_priv, &box);
2823254885Sdumbbell		}
2824254885Sdumbbell
2825254885Sdumbbell		BEGIN_RING(cmdsz);
2826254885Sdumbbell		OUT_RING_DRM_BUFFER(cmdbuf->buffer, cmdsz);
2827254885Sdumbbell		ADVANCE_RING();
2828254885Sdumbbell
2829254885Sdumbbell	} while (++i < cmdbuf->nbox);
2830254885Sdumbbell	if (cmdbuf->nbox == 1)
2831254885Sdumbbell		cmdbuf->nbox = 0;
2832254885Sdumbbell
2833254885Sdumbbell	return 0;
2834254885Sdumbbell      out:
2835254885Sdumbbell	drm_buffer_advance(cmdbuf->buffer, cmdsz * 4);
2836254885Sdumbbell	return 0;
2837254885Sdumbbell}
2838254885Sdumbbell
2839254885Sdumbbellstatic int radeon_emit_wait(struct drm_device * dev, int flags)
2840254885Sdumbbell{
2841254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
2842254885Sdumbbell	RING_LOCALS;
2843254885Sdumbbell
2844254885Sdumbbell	DRM_DEBUG("%x\n", flags);
2845254885Sdumbbell	switch (flags) {
2846254885Sdumbbell	case RADEON_WAIT_2D:
2847254885Sdumbbell		BEGIN_RING(2);
2848254885Sdumbbell		RADEON_WAIT_UNTIL_2D_IDLE();
2849254885Sdumbbell		ADVANCE_RING();
2850254885Sdumbbell		break;
2851254885Sdumbbell	case RADEON_WAIT_3D:
2852254885Sdumbbell		BEGIN_RING(2);
2853254885Sdumbbell		RADEON_WAIT_UNTIL_3D_IDLE();
2854254885Sdumbbell		ADVANCE_RING();
2855254885Sdumbbell		break;
2856254885Sdumbbell	case RADEON_WAIT_2D | RADEON_WAIT_3D:
2857254885Sdumbbell		BEGIN_RING(2);
2858254885Sdumbbell		RADEON_WAIT_UNTIL_IDLE();
2859254885Sdumbbell		ADVANCE_RING();
2860254885Sdumbbell		break;
2861254885Sdumbbell	default:
2862254885Sdumbbell		return -EINVAL;
2863254885Sdumbbell	}
2864254885Sdumbbell
2865254885Sdumbbell	return 0;
2866254885Sdumbbell}
2867254885Sdumbbell
2868254885Sdumbbellstatic int radeon_cp_cmdbuf(struct drm_device *dev, void *data,
2869254885Sdumbbell		struct drm_file *file_priv)
2870254885Sdumbbell{
2871254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
2872254885Sdumbbell	struct drm_device_dma *dma = dev->dma;
2873254885Sdumbbell	struct drm_buf *buf = NULL;
2874254885Sdumbbell	drm_radeon_cmd_header_t stack_header;
2875254885Sdumbbell	int idx;
2876254885Sdumbbell	drm_radeon_kcmd_buffer_t *cmdbuf = data;
2877254885Sdumbbell	int orig_nbox;
2878254885Sdumbbell
2879254885Sdumbbell	LOCK_TEST_WITH_RETURN(dev, file_priv);
2880254885Sdumbbell
2881254885Sdumbbell	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2882254885Sdumbbell	VB_AGE_TEST_WITH_RETURN(dev_priv);
2883254885Sdumbbell
2884254885Sdumbbell	if (cmdbuf->bufsz > 64 * 1024 || cmdbuf->bufsz < 0) {
2885254885Sdumbbell		return -EINVAL;
2886254885Sdumbbell	}
2887254885Sdumbbell
2888254885Sdumbbell	/* Allocate an in-kernel area and copy in the cmdbuf.  Do this to avoid
2889254885Sdumbbell	 * races between checking values and using those values in other code,
2890254885Sdumbbell	 * and simply to avoid a lot of function calls to copy in data.
2891254885Sdumbbell	 */
2892254885Sdumbbell	if (cmdbuf->bufsz != 0) {
2893254885Sdumbbell		int rv;
2894254885Sdumbbell		void __user *buffer = cmdbuf->buffer;
2895254885Sdumbbell		rv = drm_buffer_alloc(&cmdbuf->buffer, cmdbuf->bufsz);
2896254885Sdumbbell		if (rv)
2897254885Sdumbbell			return rv;
2898254885Sdumbbell		rv = drm_buffer_copy_from_user(cmdbuf->buffer, buffer,
2899254885Sdumbbell						cmdbuf->bufsz);
2900254885Sdumbbell		if (rv) {
2901254885Sdumbbell			drm_buffer_free(cmdbuf->buffer);
2902254885Sdumbbell			return rv;
2903254885Sdumbbell		}
2904254885Sdumbbell	} else
2905254885Sdumbbell		goto done;
2906254885Sdumbbell
2907254885Sdumbbell	orig_nbox = cmdbuf->nbox;
2908254885Sdumbbell
2909254885Sdumbbell	if (dev_priv->microcode_version == UCODE_R300) {
2910254885Sdumbbell		int temp;
2911254885Sdumbbell		temp = r300_do_cp_cmdbuf(dev, file_priv, cmdbuf);
2912254885Sdumbbell
2913254885Sdumbbell		drm_buffer_free(cmdbuf->buffer);
2914254885Sdumbbell
2915254885Sdumbbell		return temp;
2916254885Sdumbbell	}
2917254885Sdumbbell
2918254885Sdumbbell	/* microcode_version != r300 */
2919254885Sdumbbell	while (drm_buffer_unprocessed(cmdbuf->buffer) >= sizeof(stack_header)) {
2920254885Sdumbbell
2921254885Sdumbbell		drm_radeon_cmd_header_t *header;
2922254885Sdumbbell		header = drm_buffer_read_object(cmdbuf->buffer,
2923254885Sdumbbell				sizeof(stack_header), &stack_header);
2924254885Sdumbbell
2925254885Sdumbbell		switch (header->header.cmd_type) {
2926254885Sdumbbell		case RADEON_CMD_PACKET:
2927254885Sdumbbell			DRM_DEBUG("RADEON_CMD_PACKET\n");
2928254885Sdumbbell			if (radeon_emit_packets
2929254885Sdumbbell			    (dev_priv, file_priv, *header, cmdbuf)) {
2930254885Sdumbbell				DRM_ERROR("radeon_emit_packets failed\n");
2931254885Sdumbbell				goto err;
2932254885Sdumbbell			}
2933254885Sdumbbell			break;
2934254885Sdumbbell
2935254885Sdumbbell		case RADEON_CMD_SCALARS:
2936254885Sdumbbell			DRM_DEBUG("RADEON_CMD_SCALARS\n");
2937254885Sdumbbell			if (radeon_emit_scalars(dev_priv, *header, cmdbuf)) {
2938254885Sdumbbell				DRM_ERROR("radeon_emit_scalars failed\n");
2939254885Sdumbbell				goto err;
2940254885Sdumbbell			}
2941254885Sdumbbell			break;
2942254885Sdumbbell
2943254885Sdumbbell		case RADEON_CMD_VECTORS:
2944254885Sdumbbell			DRM_DEBUG("RADEON_CMD_VECTORS\n");
2945254885Sdumbbell			if (radeon_emit_vectors(dev_priv, *header, cmdbuf)) {
2946254885Sdumbbell				DRM_ERROR("radeon_emit_vectors failed\n");
2947254885Sdumbbell				goto err;
2948254885Sdumbbell			}
2949254885Sdumbbell			break;
2950254885Sdumbbell
2951254885Sdumbbell		case RADEON_CMD_DMA_DISCARD:
2952254885Sdumbbell			DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n");
2953254885Sdumbbell			idx = header->dma.buf_idx;
2954254885Sdumbbell			if (idx < 0 || idx >= dma->buf_count) {
2955254885Sdumbbell				DRM_ERROR("buffer index %d (of %d max)\n",
2956254885Sdumbbell					  idx, dma->buf_count - 1);
2957254885Sdumbbell				goto err;
2958254885Sdumbbell			}
2959254885Sdumbbell
2960254885Sdumbbell			buf = dma->buflist[idx];
2961254885Sdumbbell			if (buf->file_priv != file_priv || buf->pending) {
2962254885Sdumbbell				DRM_ERROR("bad buffer %p %p %d\n",
2963254885Sdumbbell					  buf->file_priv, file_priv,
2964254885Sdumbbell					  buf->pending);
2965254885Sdumbbell				goto err;
2966254885Sdumbbell			}
2967254885Sdumbbell
2968254885Sdumbbell			radeon_cp_discard_buffer(dev, file_priv->masterp, buf);
2969254885Sdumbbell			break;
2970254885Sdumbbell
2971254885Sdumbbell		case RADEON_CMD_PACKET3:
2972254885Sdumbbell			DRM_DEBUG("RADEON_CMD_PACKET3\n");
2973254885Sdumbbell			if (radeon_emit_packet3(dev, file_priv, cmdbuf)) {
2974254885Sdumbbell				DRM_ERROR("radeon_emit_packet3 failed\n");
2975254885Sdumbbell				goto err;
2976254885Sdumbbell			}
2977254885Sdumbbell			break;
2978254885Sdumbbell
2979254885Sdumbbell		case RADEON_CMD_PACKET3_CLIP:
2980254885Sdumbbell			DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n");
2981254885Sdumbbell			if (radeon_emit_packet3_cliprect
2982254885Sdumbbell			    (dev, file_priv, cmdbuf, orig_nbox)) {
2983254885Sdumbbell				DRM_ERROR("radeon_emit_packet3_clip failed\n");
2984254885Sdumbbell				goto err;
2985254885Sdumbbell			}
2986254885Sdumbbell			break;
2987254885Sdumbbell
2988254885Sdumbbell		case RADEON_CMD_SCALARS2:
2989254885Sdumbbell			DRM_DEBUG("RADEON_CMD_SCALARS2\n");
2990254885Sdumbbell			if (radeon_emit_scalars2(dev_priv, *header, cmdbuf)) {
2991254885Sdumbbell				DRM_ERROR("radeon_emit_scalars2 failed\n");
2992254885Sdumbbell				goto err;
2993254885Sdumbbell			}
2994254885Sdumbbell			break;
2995254885Sdumbbell
2996254885Sdumbbell		case RADEON_CMD_WAIT:
2997254885Sdumbbell			DRM_DEBUG("RADEON_CMD_WAIT\n");
2998254885Sdumbbell			if (radeon_emit_wait(dev, header->wait.flags)) {
2999254885Sdumbbell				DRM_ERROR("radeon_emit_wait failed\n");
3000254885Sdumbbell				goto err;
3001254885Sdumbbell			}
3002254885Sdumbbell			break;
3003254885Sdumbbell		case RADEON_CMD_VECLINEAR:
3004254885Sdumbbell			DRM_DEBUG("RADEON_CMD_VECLINEAR\n");
3005254885Sdumbbell			if (radeon_emit_veclinear(dev_priv, *header, cmdbuf)) {
3006254885Sdumbbell				DRM_ERROR("radeon_emit_veclinear failed\n");
3007254885Sdumbbell				goto err;
3008254885Sdumbbell			}
3009254885Sdumbbell			break;
3010254885Sdumbbell
3011254885Sdumbbell		default:
3012254885Sdumbbell			DRM_ERROR("bad cmd_type %d at byte %d\n",
3013254885Sdumbbell				  header->header.cmd_type,
3014254885Sdumbbell				  cmdbuf->buffer->iterator);
3015254885Sdumbbell			goto err;
3016254885Sdumbbell		}
3017254885Sdumbbell	}
3018254885Sdumbbell
3019254885Sdumbbell	drm_buffer_free(cmdbuf->buffer);
3020254885Sdumbbell
3021254885Sdumbbell      done:
3022254885Sdumbbell	DRM_DEBUG("DONE\n");
3023254885Sdumbbell	COMMIT_RING();
3024254885Sdumbbell	return 0;
3025254885Sdumbbell
3026254885Sdumbbell      err:
3027254885Sdumbbell	drm_buffer_free(cmdbuf->buffer);
3028254885Sdumbbell	return -EINVAL;
3029254885Sdumbbell}
3030254885Sdumbbell
3031254885Sdumbbellstatic int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
3032254885Sdumbbell{
3033254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
3034254885Sdumbbell	drm_radeon_getparam_t *param = data;
3035254885Sdumbbell	int value;
3036254885Sdumbbell
3037254885Sdumbbell	DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
3038254885Sdumbbell
3039254885Sdumbbell	switch (param->param) {
3040254885Sdumbbell	case RADEON_PARAM_GART_BUFFER_OFFSET:
3041254885Sdumbbell		value = dev_priv->gart_buffers_offset;
3042254885Sdumbbell		break;
3043254885Sdumbbell	case RADEON_PARAM_LAST_FRAME:
3044254885Sdumbbell		dev_priv->stats.last_frame_reads++;
3045254885Sdumbbell		value = GET_SCRATCH(dev_priv, 0);
3046254885Sdumbbell		break;
3047254885Sdumbbell	case RADEON_PARAM_LAST_DISPATCH:
3048254885Sdumbbell		value = GET_SCRATCH(dev_priv, 1);
3049254885Sdumbbell		break;
3050254885Sdumbbell	case RADEON_PARAM_LAST_CLEAR:
3051254885Sdumbbell		dev_priv->stats.last_clear_reads++;
3052254885Sdumbbell		value = GET_SCRATCH(dev_priv, 2);
3053254885Sdumbbell		break;
3054254885Sdumbbell	case RADEON_PARAM_IRQ_NR:
3055254885Sdumbbell		if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
3056254885Sdumbbell			value = 0;
3057254885Sdumbbell		else
3058254885Sdumbbell			value = dev->irq;
3059254885Sdumbbell		break;
3060254885Sdumbbell	case RADEON_PARAM_GART_BASE:
3061254885Sdumbbell		value = dev_priv->gart_vm_start;
3062254885Sdumbbell		break;
3063254885Sdumbbell	case RADEON_PARAM_REGISTER_HANDLE:
3064254885Sdumbbell		value = dev_priv->mmio->offset;
3065254885Sdumbbell		break;
3066254885Sdumbbell	case RADEON_PARAM_STATUS_HANDLE:
3067254885Sdumbbell		value = dev_priv->ring_rptr_offset;
3068254885Sdumbbell		break;
3069254885Sdumbbell#ifndef __LP64__
3070254885Sdumbbell		/*
3071254885Sdumbbell		 * This ioctl() doesn't work on 64-bit platforms because hw_lock is a
3072254885Sdumbbell		 * pointer which can't fit into an int-sized variable.  According to
3073254885Sdumbbell		 * Michel D��nzer, the ioctl() is only used on embedded platforms, so
3074254885Sdumbbell		 * not supporting it shouldn't be a problem.  If the same functionality
3075254885Sdumbbell		 * is needed on 64-bit platforms, a new ioctl() would have to be added,
3076254885Sdumbbell		 * so backwards-compatibility for the embedded platforms can be
3077254885Sdumbbell		 * maintained.  --davidm 4-Feb-2004.
3078254885Sdumbbell		 */
3079254885Sdumbbell	case RADEON_PARAM_SAREA_HANDLE:
3080254885Sdumbbell		/* The lock is the first dword in the sarea. */
3081254885Sdumbbell		/* no users of this parameter */
3082254885Sdumbbell		break;
3083254885Sdumbbell#endif
3084254885Sdumbbell	case RADEON_PARAM_GART_TEX_HANDLE:
3085254885Sdumbbell		value = dev_priv->gart_textures_offset;
3086254885Sdumbbell		break;
3087254885Sdumbbell	case RADEON_PARAM_SCRATCH_OFFSET:
3088254885Sdumbbell		if (!dev_priv->writeback_works)
3089254885Sdumbbell			return -EINVAL;
3090254885Sdumbbell		if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
3091254885Sdumbbell			value = R600_SCRATCH_REG_OFFSET;
3092254885Sdumbbell		else
3093254885Sdumbbell			value = RADEON_SCRATCH_REG_OFFSET;
3094254885Sdumbbell		break;
3095254885Sdumbbell	case RADEON_PARAM_CARD_TYPE:
3096254885Sdumbbell		if (dev_priv->flags & RADEON_IS_PCIE)
3097254885Sdumbbell			value = RADEON_CARD_PCIE;
3098254885Sdumbbell		else if (dev_priv->flags & RADEON_IS_AGP)
3099254885Sdumbbell			value = RADEON_CARD_AGP;
3100254885Sdumbbell		else
3101254885Sdumbbell			value = RADEON_CARD_PCI;
3102254885Sdumbbell		break;
3103254885Sdumbbell	case RADEON_PARAM_VBLANK_CRTC:
3104254885Sdumbbell		value = radeon_vblank_crtc_get(dev);
3105254885Sdumbbell		break;
3106254885Sdumbbell	case RADEON_PARAM_FB_LOCATION:
3107254885Sdumbbell		value = radeon_read_fb_location(dev_priv);
3108254885Sdumbbell		break;
3109254885Sdumbbell	case RADEON_PARAM_NUM_GB_PIPES:
3110254885Sdumbbell		value = dev_priv->num_gb_pipes;
3111254885Sdumbbell		break;
3112254885Sdumbbell	case RADEON_PARAM_NUM_Z_PIPES:
3113254885Sdumbbell		value = dev_priv->num_z_pipes;
3114254885Sdumbbell		break;
3115254885Sdumbbell	default:
3116254885Sdumbbell		DRM_DEBUG("Invalid parameter %d\n", param->param);
3117254885Sdumbbell		return -EINVAL;
3118254885Sdumbbell	}
3119254885Sdumbbell
3120254885Sdumbbell	if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
3121254885Sdumbbell		DRM_ERROR("copy_to_user\n");
3122254885Sdumbbell		return -EFAULT;
3123254885Sdumbbell	}
3124254885Sdumbbell
3125254885Sdumbbell	return 0;
3126254885Sdumbbell}
3127254885Sdumbbell
3128254885Sdumbbellstatic int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
3129254885Sdumbbell{
3130254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
3131254885Sdumbbell	struct drm_radeon_master_private *master_priv = file_priv->masterp->driver_priv;
3132254885Sdumbbell	drm_radeon_setparam_t *sp = data;
3133254885Sdumbbell	struct drm_radeon_driver_file_fields *radeon_priv;
3134254885Sdumbbell
3135254885Sdumbbell	switch (sp->param) {
3136254885Sdumbbell	case RADEON_SETPARAM_FB_LOCATION:
3137254885Sdumbbell		radeon_priv = file_priv->driver_priv;
3138254885Sdumbbell		radeon_priv->radeon_fb_delta = dev_priv->fb_location -
3139254885Sdumbbell		    sp->value;
3140254885Sdumbbell		break;
3141254885Sdumbbell	case RADEON_SETPARAM_SWITCH_TILING:
3142254885Sdumbbell		if (sp->value == 0) {
3143254885Sdumbbell			DRM_DEBUG("color tiling disabled\n");
3144254885Sdumbbell			dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO;
3145254885Sdumbbell			dev_priv->back_pitch_offset &= ~RADEON_DST_TILE_MACRO;
3146254885Sdumbbell			if (master_priv->sarea_priv)
3147254885Sdumbbell				master_priv->sarea_priv->tiling_enabled = 0;
3148254885Sdumbbell		} else if (sp->value == 1) {
3149254885Sdumbbell			DRM_DEBUG("color tiling enabled\n");
3150254885Sdumbbell			dev_priv->front_pitch_offset |= RADEON_DST_TILE_MACRO;
3151254885Sdumbbell			dev_priv->back_pitch_offset |= RADEON_DST_TILE_MACRO;
3152254885Sdumbbell			if (master_priv->sarea_priv)
3153254885Sdumbbell				master_priv->sarea_priv->tiling_enabled = 1;
3154254885Sdumbbell		}
3155254885Sdumbbell		break;
3156254885Sdumbbell	case RADEON_SETPARAM_PCIGART_LOCATION:
3157254885Sdumbbell		dev_priv->pcigart_offset = sp->value;
3158254885Sdumbbell		dev_priv->pcigart_offset_set = 1;
3159254885Sdumbbell		break;
3160254885Sdumbbell	case RADEON_SETPARAM_NEW_MEMMAP:
3161254885Sdumbbell		dev_priv->new_memmap = sp->value;
3162254885Sdumbbell		break;
3163254885Sdumbbell	case RADEON_SETPARAM_PCIGART_TABLE_SIZE:
3164254885Sdumbbell		dev_priv->gart_info.table_size = sp->value;
3165254885Sdumbbell		if (dev_priv->gart_info.table_size < RADEON_PCIGART_TABLE_SIZE)
3166254885Sdumbbell			dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE;
3167254885Sdumbbell		break;
3168254885Sdumbbell	case RADEON_SETPARAM_VBLANK_CRTC:
3169254885Sdumbbell		return radeon_vblank_crtc_set(dev, sp->value);
3170254885Sdumbbell		break;
3171254885Sdumbbell	default:
3172254885Sdumbbell		DRM_DEBUG("Invalid parameter %d\n", sp->param);
3173254885Sdumbbell		return -EINVAL;
3174254885Sdumbbell	}
3175254885Sdumbbell
3176254885Sdumbbell	return 0;
3177254885Sdumbbell}
3178254885Sdumbbell
3179254885Sdumbbell/* When a client dies:
3180254885Sdumbbell *    - Check for and clean up flipped page state
3181254885Sdumbbell *    - Free any alloced GART memory.
3182254885Sdumbbell *    - Free any alloced radeon surfaces.
3183254885Sdumbbell *
3184254885Sdumbbell * DRM infrastructure takes care of reclaiming dma buffers.
3185254885Sdumbbell */
3186254885Sdumbbellvoid radeon_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
3187254885Sdumbbell{
3188254885Sdumbbell	if (dev->dev_private) {
3189254885Sdumbbell		drm_radeon_private_t *dev_priv = dev->dev_private;
3190254885Sdumbbell		dev_priv->page_flipping = 0;
3191254885Sdumbbell		radeon_mem_release(file_priv, dev_priv->gart_heap);
3192254885Sdumbbell		radeon_mem_release(file_priv, dev_priv->fb_heap);
3193254885Sdumbbell		radeon_surfaces_release(file_priv, dev_priv);
3194254885Sdumbbell	}
3195254885Sdumbbell}
3196254885Sdumbbell
3197254885Sdumbbellvoid radeon_driver_lastclose(struct drm_device *dev)
3198254885Sdumbbell{
3199254885Sdumbbell	radeon_surfaces_release(PCIGART_FILE_PRIV, dev->dev_private);
3200254885Sdumbbell	radeon_do_release(dev);
3201254885Sdumbbell}
3202254885Sdumbbell
3203254885Sdumbbellint radeon_driver_open(struct drm_device *dev, struct drm_file *file_priv)
3204254885Sdumbbell{
3205254885Sdumbbell	drm_radeon_private_t *dev_priv = dev->dev_private;
3206254885Sdumbbell	struct drm_radeon_driver_file_fields *radeon_priv;
3207254885Sdumbbell
3208254885Sdumbbell	DRM_DEBUG("\n");
3209254885Sdumbbell	radeon_priv = malloc(sizeof(*radeon_priv), DRM_MEM_DRIVER, M_WAITOK);
3210254885Sdumbbell
3211254885Sdumbbell	if (!radeon_priv)
3212254885Sdumbbell		return -ENOMEM;
3213254885Sdumbbell
3214254885Sdumbbell	file_priv->driver_priv = radeon_priv;
3215254885Sdumbbell
3216254885Sdumbbell	if (dev_priv)
3217254885Sdumbbell		radeon_priv->radeon_fb_delta = dev_priv->fb_location;
3218254885Sdumbbell	else
3219254885Sdumbbell		radeon_priv->radeon_fb_delta = 0;
3220254885Sdumbbell	return 0;
3221254885Sdumbbell}
3222254885Sdumbbell
3223254885Sdumbbellvoid radeon_driver_postclose(struct drm_device *dev, struct drm_file *file_priv)
3224254885Sdumbbell{
3225254885Sdumbbell	struct drm_radeon_driver_file_fields *radeon_priv =
3226254885Sdumbbell	    file_priv->driver_priv;
3227254885Sdumbbell
3228254885Sdumbbell	free(radeon_priv, DRM_MEM_DRIVER);
3229254885Sdumbbell}
3230254885Sdumbbell
3231254885Sdumbbellstruct drm_ioctl_desc radeon_ioctls[] = {
3232254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_CP_INIT, radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
3233254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_CP_START, radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
3234254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_CP_STOP, radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
3235254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_CP_RESET, radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
3236254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_CP_IDLE, radeon_cp_idle, DRM_AUTH),
3237254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_CP_RESUME, radeon_cp_resume, DRM_AUTH),
3238254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_RESET, radeon_engine_reset, DRM_AUTH),
3239254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_FULLSCREEN, radeon_fullscreen, DRM_AUTH),
3240254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_SWAP, radeon_cp_swap, DRM_AUTH),
3241254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_CLEAR, radeon_cp_clear, DRM_AUTH),
3242254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_VERTEX, radeon_cp_vertex, DRM_AUTH),
3243254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_INDICES, radeon_cp_indices, DRM_AUTH),
3244254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_TEXTURE, radeon_cp_texture, DRM_AUTH),
3245254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_STIPPLE, radeon_cp_stipple, DRM_AUTH),
3246254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_INDIRECT, radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
3247254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_VERTEX2, radeon_cp_vertex2, DRM_AUTH),
3248254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_CMDBUF, radeon_cp_cmdbuf, DRM_AUTH),
3249254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_GETPARAM, radeon_cp_getparam, DRM_AUTH),
3250254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_FLIP, radeon_cp_flip, DRM_AUTH),
3251254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_ALLOC, radeon_mem_alloc, DRM_AUTH),
3252254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_FREE, radeon_mem_free, DRM_AUTH),
3253254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_INIT_HEAP, radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
3254254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_IRQ_EMIT, radeon_irq_emit, DRM_AUTH),
3255254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_IRQ_WAIT, radeon_irq_wait, DRM_AUTH),
3256254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_SETPARAM, radeon_cp_setparam, DRM_AUTH),
3257254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_SURF_ALLOC, radeon_surface_alloc, DRM_AUTH),
3258254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH),
3259254885Sdumbbell	DRM_IOCTL_DEF_DRV(RADEON_CS, r600_cs_legacy_ioctl, DRM_AUTH)
3260254885Sdumbbell};
3261254885Sdumbbell
3262254885Sdumbbellint radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls);
3263