1139749Simp/*-
295584Sanholt * Copyright 2000 VA Linux Systems, Inc., Fremont, California.
395584Sanholt * All Rights Reserved.
495584Sanholt *
595584Sanholt * Permission is hereby granted, free of charge, to any person obtaining a
695584Sanholt * copy of this software and associated documentation files (the "Software"),
795584Sanholt * to deal in the Software without restriction, including without limitation
895584Sanholt * the rights to use, copy, modify, merge, publish, distribute, sublicense,
995584Sanholt * and/or sell copies of the Software, and to permit persons to whom the
1095584Sanholt * Software is furnished to do so, subject to the following conditions:
1195584Sanholt *
1295584Sanholt * The above copyright notice and this permission notice (including the next
1395584Sanholt * paragraph) shall be included in all copies or substantial portions of the
1495584Sanholt * Software.
1595584Sanholt *
1695584Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1795584Sanholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1895584Sanholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1995584Sanholt * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
2095584Sanholt * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2195584Sanholt * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2295584Sanholt * DEALINGS IN THE SOFTWARE.
2395584Sanholt *
2495584Sanholt * Authors:
2595584Sanholt *    Gareth Hughes <gareth@valinux.com>
2695584Sanholt *    Kevin E. Martin <martin@valinux.com>
2795584Sanholt */
2895584Sanholt
29152909Sanholt#include <sys/cdefs.h>
30152909Sanholt__FBSDID("$FreeBSD$");
31152909Sanholt
3295584Sanholt#include "dev/drm/drmP.h"
33112015Sanholt#include "dev/drm/drm.h"
34112015Sanholt#include "dev/drm/drm_sarea.h"
3595746Sanholt#include "dev/drm/radeon_drm.h"
3695584Sanholt#include "dev/drm/radeon_drv.h"
3795584Sanholt
3895584Sanholt/* ================================================================
39122580Sanholt * Helper functions for client state checking and fixup
40122580Sanholt */
41122580Sanholt
42145132Sanholtstatic __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
43145132Sanholt						    dev_priv,
44182080Srnoland						    struct drm_file *file_priv,
45189499Srnoland						    u32 *offset)
46145132Sanholt{
47162132Sanholt	u64 off = *offset;
48182080Srnoland	u32 fb_end = dev_priv->fb_location + dev_priv->fb_size - 1;
49145132Sanholt	struct drm_radeon_driver_file_fields *radeon_priv;
50122580Sanholt
51157617Sanholt	/* Hrm ... the story of the offset ... So this function converts
52157617Sanholt	 * the various ideas of what userland clients might have for an
53157617Sanholt	 * offset in the card address space into an offset into the card
54157617Sanholt	 * address space :) So with a sane client, it should just keep
55157617Sanholt	 * the value intact and just do some boundary checking. However,
56157617Sanholt	 * not all clients are sane. Some older clients pass us 0 based
57157617Sanholt	 * offsets relative to the start of the framebuffer and some may
58157617Sanholt	 * assume the AGP aperture it appended to the framebuffer, so we
59157617Sanholt	 * try to detect those cases and fix them up.
60157617Sanholt	 *
61157617Sanholt	 * Note: It might be a good idea here to make sure the offset lands
62157617Sanholt	 * in some "allowed" area to protect things like the PCIE GART...
63157617Sanholt	 */
64157617Sanholt
65157617Sanholt	/* First, the best case, the offset already lands in either the
66157617Sanholt	 * framebuffer or the GART mapped space
67157617Sanholt	 */
68182080Srnoland	if (radeon_check_offset(dev_priv, off))
69122580Sanholt		return 0;
70122580Sanholt
71157617Sanholt	/* Ok, that didn't happen... now check if we have a zero based
72157617Sanholt	 * offset that fits in the framebuffer + gart space, apply the
73157617Sanholt	 * magic offset we get from SETPARAM or calculated from fb_location
74157617Sanholt	 */
75157617Sanholt	if (off < (dev_priv->fb_size + dev_priv->gart_size)) {
76182080Srnoland		radeon_priv = file_priv->driver_priv;
77157617Sanholt		off += radeon_priv->radeon_fb_delta;
78157617Sanholt	}
79122580Sanholt
80157617Sanholt	/* Finally, assume we aimed at a GART offset if beyond the fb */
81162132Sanholt	if (off > fb_end)
82182080Srnoland		off = off - fb_end - 1 + dev_priv->gart_vm_start;
83122580Sanholt
84157617Sanholt	/* Now recheck and fail if out of bounds */
85182080Srnoland	if (radeon_check_offset(dev_priv, off)) {
86162132Sanholt		DRM_DEBUG("offset fixed up to 0x%x\n", (unsigned int)off);
87157617Sanholt		*offset = off;
88157617Sanholt		return 0;
89157617Sanholt	}
90182080Srnoland	return -EINVAL;
91122580Sanholt}
92122580Sanholt
93145132Sanholtstatic __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
94145132Sanholt						     dev_priv,
95182080Srnoland						     struct drm_file *file_priv,
96157617Sanholt						     int id, u32 *data)
97145132Sanholt{
98145132Sanholt	switch (id) {
99122580Sanholt
100130331Sanholt	case RADEON_EMIT_PP_MISC:
101182080Srnoland		if (radeon_check_and_fixup_offset(dev_priv, file_priv,
102145132Sanholt		    &data[(RADEON_RB3D_DEPTHOFFSET - RADEON_PP_MISC) / 4])) {
103145132Sanholt			DRM_ERROR("Invalid depth buffer offset\n");
104182080Srnoland			return -EINVAL;
105130331Sanholt		}
106130331Sanholt		break;
107130331Sanholt
108130331Sanholt	case RADEON_EMIT_PP_CNTL:
109182080Srnoland		if (radeon_check_and_fixup_offset(dev_priv, file_priv,
110145132Sanholt		    &data[(RADEON_RB3D_COLOROFFSET - RADEON_PP_CNTL) / 4])) {
111145132Sanholt			DRM_ERROR("Invalid colour buffer offset\n");
112182080Srnoland			return -EINVAL;
113130331Sanholt		}
114130331Sanholt		break;
115130331Sanholt
116130331Sanholt	case R200_EMIT_PP_TXOFFSET_0:
117130331Sanholt	case R200_EMIT_PP_TXOFFSET_1:
118130331Sanholt	case R200_EMIT_PP_TXOFFSET_2:
119130331Sanholt	case R200_EMIT_PP_TXOFFSET_3:
120130331Sanholt	case R200_EMIT_PP_TXOFFSET_4:
121130331Sanholt	case R200_EMIT_PP_TXOFFSET_5:
122182080Srnoland		if (radeon_check_and_fixup_offset(dev_priv, file_priv,
123145132Sanholt						  &data[0])) {
124145132Sanholt			DRM_ERROR("Invalid R200 texture offset\n");
125182080Srnoland			return -EINVAL;
126130331Sanholt		}
127130331Sanholt		break;
128130331Sanholt
129130331Sanholt	case RADEON_EMIT_PP_TXFILTER_0:
130130331Sanholt	case RADEON_EMIT_PP_TXFILTER_1:
131130331Sanholt	case RADEON_EMIT_PP_TXFILTER_2:
132182080Srnoland		if (radeon_check_and_fixup_offset(dev_priv, file_priv,
133145132Sanholt		    &data[(RADEON_PP_TXOFFSET_0 - RADEON_PP_TXFILTER_0) / 4])) {
134145132Sanholt			DRM_ERROR("Invalid R100 texture offset\n");
135182080Srnoland			return -EINVAL;
136130331Sanholt		}
137130331Sanholt		break;
138130331Sanholt
139130331Sanholt	case R200_EMIT_PP_CUBIC_OFFSETS_0:
140130331Sanholt	case R200_EMIT_PP_CUBIC_OFFSETS_1:
141130331Sanholt	case R200_EMIT_PP_CUBIC_OFFSETS_2:
142130331Sanholt	case R200_EMIT_PP_CUBIC_OFFSETS_3:
143130331Sanholt	case R200_EMIT_PP_CUBIC_OFFSETS_4:
144145132Sanholt	case R200_EMIT_PP_CUBIC_OFFSETS_5:{
145145132Sanholt			int i;
146145132Sanholt			for (i = 0; i < 5; i++) {
147145132Sanholt				if (radeon_check_and_fixup_offset(dev_priv,
148182080Srnoland								  file_priv,
149145132Sanholt								  &data[i])) {
150145132Sanholt					DRM_ERROR
151145132Sanholt					    ("Invalid R200 cubic texture offset\n");
152182080Srnoland					return -EINVAL;
153145132Sanholt				}
154122580Sanholt			}
155145132Sanholt			break;
156122580Sanholt		}
157145132Sanholt
158145132Sanholt	case RADEON_EMIT_PP_CUBIC_OFFSETS_T0:
159145132Sanholt	case RADEON_EMIT_PP_CUBIC_OFFSETS_T1:
160145132Sanholt	case RADEON_EMIT_PP_CUBIC_OFFSETS_T2:{
161145132Sanholt			int i;
162145132Sanholt			for (i = 0; i < 5; i++) {
163145132Sanholt				if (radeon_check_and_fixup_offset(dev_priv,
164182080Srnoland								  file_priv,
165145132Sanholt								  &data[i])) {
166145132Sanholt					DRM_ERROR
167145132Sanholt					    ("Invalid R100 cubic texture offset\n");
168182080Srnoland					return -EINVAL;
169145132Sanholt				}
170145132Sanholt			}
171145132Sanholt		}
172130331Sanholt		break;
173122580Sanholt
174182080Srnoland	case R200_EMIT_VAP_CTL: {
175182080Srnoland			RING_LOCALS;
176182080Srnoland			BEGIN_RING(2);
177182080Srnoland			OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
178182080Srnoland			ADVANCE_RING();
179182080Srnoland		}
180182080Srnoland		break;
181182080Srnoland
182130331Sanholt	case RADEON_EMIT_RB3D_COLORPITCH:
183130331Sanholt	case RADEON_EMIT_RE_LINE_PATTERN:
184130331Sanholt	case RADEON_EMIT_SE_LINE_WIDTH:
185130331Sanholt	case RADEON_EMIT_PP_LUM_MATRIX:
186130331Sanholt	case RADEON_EMIT_PP_ROT_MATRIX_0:
187130331Sanholt	case RADEON_EMIT_RB3D_STENCILREFMASK:
188130331Sanholt	case RADEON_EMIT_SE_VPORT_XSCALE:
189130331Sanholt	case RADEON_EMIT_SE_CNTL:
190130331Sanholt	case RADEON_EMIT_SE_CNTL_STATUS:
191130331Sanholt	case RADEON_EMIT_RE_MISC:
192130331Sanholt	case RADEON_EMIT_PP_BORDER_COLOR_0:
193130331Sanholt	case RADEON_EMIT_PP_BORDER_COLOR_1:
194130331Sanholt	case RADEON_EMIT_PP_BORDER_COLOR_2:
195130331Sanholt	case RADEON_EMIT_SE_ZBIAS_FACTOR:
196130331Sanholt	case RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT:
197130331Sanholt	case RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED:
198130331Sanholt	case R200_EMIT_PP_TXCBLEND_0:
199130331Sanholt	case R200_EMIT_PP_TXCBLEND_1:
200130331Sanholt	case R200_EMIT_PP_TXCBLEND_2:
201130331Sanholt	case R200_EMIT_PP_TXCBLEND_3:
202130331Sanholt	case R200_EMIT_PP_TXCBLEND_4:
203130331Sanholt	case R200_EMIT_PP_TXCBLEND_5:
204130331Sanholt	case R200_EMIT_PP_TXCBLEND_6:
205130331Sanholt	case R200_EMIT_PP_TXCBLEND_7:
206130331Sanholt	case R200_EMIT_TCL_LIGHT_MODEL_CTL_0:
207130331Sanholt	case R200_EMIT_TFACTOR_0:
208130331Sanholt	case R200_EMIT_VTX_FMT_0:
209130331Sanholt	case R200_EMIT_MATRIX_SELECT_0:
210130331Sanholt	case R200_EMIT_TEX_PROC_CTL_2:
211130331Sanholt	case R200_EMIT_TCL_UCP_VERT_BLEND_CTL:
212130331Sanholt	case R200_EMIT_PP_TXFILTER_0:
213130331Sanholt	case R200_EMIT_PP_TXFILTER_1:
214130331Sanholt	case R200_EMIT_PP_TXFILTER_2:
215130331Sanholt	case R200_EMIT_PP_TXFILTER_3:
216130331Sanholt	case R200_EMIT_PP_TXFILTER_4:
217130331Sanholt	case R200_EMIT_PP_TXFILTER_5:
218130331Sanholt	case R200_EMIT_VTE_CNTL:
219130331Sanholt	case R200_EMIT_OUTPUT_VTX_COMP_SEL:
220130331Sanholt	case R200_EMIT_PP_TAM_DEBUG3:
221130331Sanholt	case R200_EMIT_PP_CNTL_X:
222130331Sanholt	case R200_EMIT_RB3D_DEPTHXY_OFFSET:
223130331Sanholt	case R200_EMIT_RE_AUX_SCISSOR_CNTL:
224130331Sanholt	case R200_EMIT_RE_SCISSOR_TL_0:
225130331Sanholt	case R200_EMIT_RE_SCISSOR_TL_1:
226130331Sanholt	case R200_EMIT_RE_SCISSOR_TL_2:
227130331Sanholt	case R200_EMIT_SE_VAP_CNTL_STATUS:
228130331Sanholt	case R200_EMIT_SE_VTX_STATE_CNTL:
229130331Sanholt	case R200_EMIT_RE_POINTSIZE:
230130331Sanholt	case R200_EMIT_TCL_INPUT_VTX_VECTOR_ADDR_0:
231130331Sanholt	case R200_EMIT_PP_CUBIC_FACES_0:
232130331Sanholt	case R200_EMIT_PP_CUBIC_FACES_1:
233130331Sanholt	case R200_EMIT_PP_CUBIC_FACES_2:
234130331Sanholt	case R200_EMIT_PP_CUBIC_FACES_3:
235130331Sanholt	case R200_EMIT_PP_CUBIC_FACES_4:
236130331Sanholt	case R200_EMIT_PP_CUBIC_FACES_5:
237130331Sanholt	case RADEON_EMIT_PP_TEX_SIZE_0:
238130331Sanholt	case RADEON_EMIT_PP_TEX_SIZE_1:
239130331Sanholt	case RADEON_EMIT_PP_TEX_SIZE_2:
240130331Sanholt	case R200_EMIT_RB3D_BLENDCOLOR:
241145132Sanholt	case R200_EMIT_TCL_POINT_SPRITE_CNTL:
242145132Sanholt	case RADEON_EMIT_PP_CUBIC_FACES_0:
243145132Sanholt	case RADEON_EMIT_PP_CUBIC_FACES_1:
244145132Sanholt	case RADEON_EMIT_PP_CUBIC_FACES_2:
245145132Sanholt	case R200_EMIT_PP_TRI_PERF_CNTL:
246152909Sanholt	case R200_EMIT_PP_AFS_0:
247152909Sanholt	case R200_EMIT_PP_AFS_1:
248152909Sanholt	case R200_EMIT_ATF_TFACTOR:
249152909Sanholt	case R200_EMIT_PP_TXCTLALL_0:
250152909Sanholt	case R200_EMIT_PP_TXCTLALL_1:
251152909Sanholt	case R200_EMIT_PP_TXCTLALL_2:
252152909Sanholt	case R200_EMIT_PP_TXCTLALL_3:
253152909Sanholt	case R200_EMIT_PP_TXCTLALL_4:
254152909Sanholt	case R200_EMIT_PP_TXCTLALL_5:
255162132Sanholt	case R200_EMIT_VAP_PVS_CNTL:
256130331Sanholt		/* These packets don't contain memory offsets */
257130331Sanholt		break;
258130331Sanholt
259130331Sanholt	default:
260145132Sanholt		DRM_ERROR("Unknown state packet ID %d\n", id);
261182080Srnoland		return -EINVAL;
262130331Sanholt	}
263130331Sanholt
264122580Sanholt	return 0;
265122580Sanholt}
266122580Sanholt
267145132Sanholtstatic __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
268145132Sanholt						     dev_priv,
269182080Srnoland						     struct drm_file *file_priv,
270157617Sanholt						     drm_radeon_kcmd_buffer_t *
271145132Sanholt						     cmdbuf,
272145132Sanholt						     unsigned int *cmdsz)
273145132Sanholt{
274145132Sanholt	u32 *cmd = (u32 *) cmdbuf->buf;
275182080Srnoland	u32 offset, narrays;
276182080Srnoland	int count, i, k;
277122580Sanholt
278145132Sanholt	*cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16);
279122580Sanholt
280145132Sanholt	if ((cmd[0] & 0xc0000000) != RADEON_CP_PACKET3) {
281145132Sanholt		DRM_ERROR("Not a type 3 packet\n");
282182080Srnoland		return -EINVAL;
283122580Sanholt	}
284122580Sanholt
285145132Sanholt	if (4 * *cmdsz > cmdbuf->bufsz) {
286145132Sanholt		DRM_ERROR("Packet size larger than size of data provided\n");
287182080Srnoland		return -EINVAL;
288122580Sanholt	}
289122580Sanholt
290182080Srnoland	switch(cmd[0] & 0xff00) {
291182080Srnoland	/* XXX Are there old drivers needing other packets? */
292122580Sanholt
293182080Srnoland	case RADEON_3D_DRAW_IMMD:
294182080Srnoland	case RADEON_3D_DRAW_VBUF:
295182080Srnoland	case RADEON_3D_DRAW_INDX:
296182080Srnoland	case RADEON_WAIT_FOR_IDLE:
297182080Srnoland	case RADEON_CP_NOP:
298182080Srnoland	case RADEON_3D_CLEAR_ZMASK:
299182080Srnoland/*	case RADEON_CP_NEXT_CHAR:
300182080Srnoland	case RADEON_CP_PLY_NEXTSCAN:
301182080Srnoland	case RADEON_CP_SET_SCISSORS: */ /* probably safe but will never need them? */
302182080Srnoland		/* these packets are safe */
303182080Srnoland		break;
304182080Srnoland
305182080Srnoland	case RADEON_CP_3D_DRAW_IMMD_2:
306182080Srnoland	case RADEON_CP_3D_DRAW_VBUF_2:
307182080Srnoland	case RADEON_CP_3D_DRAW_INDX_2:
308182080Srnoland	case RADEON_3D_CLEAR_HIZ:
309182080Srnoland		/* safe but r200 only */
310189499Srnoland		if (dev_priv->microcode_version != UCODE_R200) {
311189499Srnoland			DRM_ERROR("Invalid 3d packet for r100-class chip\n");
312182080Srnoland			return -EINVAL;
313182080Srnoland		}
314182080Srnoland		break;
315182080Srnoland
316182080Srnoland	case RADEON_3D_LOAD_VBPNTR:
317182080Srnoland		count = (cmd[0] >> 16) & 0x3fff;
318182080Srnoland
319182080Srnoland		if (count > 18) { /* 12 arrays max */
320182080Srnoland			DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n",
321182080Srnoland				  count);
322182080Srnoland			return -EINVAL;
323182080Srnoland		}
324182080Srnoland
325182080Srnoland		/* carefully check packet contents */
326182080Srnoland		narrays = cmd[1] & ~0xc000;
327182080Srnoland		k = 0;
328182080Srnoland		i = 2;
329182080Srnoland		while ((k < narrays) && (i < (count + 2))) {
330182080Srnoland			i++;		/* skip attribute field */
331182080Srnoland			if (radeon_check_and_fixup_offset(dev_priv, file_priv,
332182080Srnoland							  &cmd[i])) {
333182080Srnoland				DRM_ERROR
334182080Srnoland				    ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
335182080Srnoland				     k, i);
336182080Srnoland				return -EINVAL;
337182080Srnoland			}
338182080Srnoland			k++;
339182080Srnoland			i++;
340182080Srnoland			if (k == narrays)
341182080Srnoland				break;
342182080Srnoland			/* have one more to process, they come in pairs */
343182080Srnoland			if (radeon_check_and_fixup_offset(dev_priv,
344182080Srnoland							  file_priv, &cmd[i]))
345182080Srnoland			{
346182080Srnoland				DRM_ERROR
347182080Srnoland				    ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
348182080Srnoland				     k, i);
349182080Srnoland				return -EINVAL;
350182080Srnoland			}
351182080Srnoland			k++;
352182080Srnoland			i++;
353182080Srnoland		}
354182080Srnoland		/* do the counts match what we expect ? */
355182080Srnoland		if ((k != narrays) || (i != (count + 2))) {
356182080Srnoland			DRM_ERROR
357182080Srnoland			    ("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n",
358182080Srnoland			      k, i, narrays, count + 1);
359182080Srnoland			return -EINVAL;
360182080Srnoland		}
361182080Srnoland		break;
362182080Srnoland
363182080Srnoland	case RADEON_3D_RNDR_GEN_INDX_PRIM:
364189499Srnoland		if (dev_priv->microcode_version != UCODE_R100) {
365189499Srnoland			DRM_ERROR("Invalid 3d packet for r200-class chip\n");
366182080Srnoland			return -EINVAL;
367182080Srnoland		}
368182080Srnoland		if (radeon_check_and_fixup_offset(dev_priv, file_priv, &cmd[1])) {
369182080Srnoland				DRM_ERROR("Invalid rndr_gen_indx offset\n");
370182080Srnoland				return -EINVAL;
371182080Srnoland		}
372182080Srnoland		break;
373182080Srnoland
374182080Srnoland	case RADEON_CP_INDX_BUFFER:
375189499Srnoland		if (dev_priv->microcode_version != UCODE_R200) {
376189499Srnoland			DRM_ERROR("Invalid 3d packet for r100-class chip\n");
377182080Srnoland			return -EINVAL;
378182080Srnoland		}
379182080Srnoland		if ((cmd[1] & 0x8000ffff) != 0x80000810) {
380182080Srnoland			DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
381182080Srnoland			return -EINVAL;
382182080Srnoland		}
383182080Srnoland		if (radeon_check_and_fixup_offset(dev_priv, file_priv, &cmd[2])) {
384182080Srnoland			DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
385182080Srnoland			return -EINVAL;
386182080Srnoland		}
387182080Srnoland		break;
388182080Srnoland
389182080Srnoland	case RADEON_CNTL_HOSTDATA_BLT:
390182080Srnoland	case RADEON_CNTL_PAINT_MULTI:
391182080Srnoland	case RADEON_CNTL_BITBLT_MULTI:
392182080Srnoland		/* MSB of opcode: next DWORD GUI_CNTL */
393145132Sanholt		if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
394145132Sanholt			      | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
395145132Sanholt			offset = cmd[2] << 10;
396145132Sanholt			if (radeon_check_and_fixup_offset
397182080Srnoland			    (dev_priv, file_priv, &offset)) {
398145132Sanholt				DRM_ERROR("Invalid first packet offset\n");
399182080Srnoland				return -EINVAL;
400122580Sanholt			}
401145132Sanholt			cmd[2] = (cmd[2] & 0xffc00000) | offset >> 10;
402122580Sanholt		}
403122580Sanholt
404145132Sanholt		if ((cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&
405145132Sanholt		    (cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
406145132Sanholt			offset = cmd[3] << 10;
407145132Sanholt			if (radeon_check_and_fixup_offset
408182080Srnoland			    (dev_priv, file_priv, &offset)) {
409145132Sanholt				DRM_ERROR("Invalid second packet offset\n");
410182080Srnoland				return -EINVAL;
411122580Sanholt			}
412145132Sanholt			cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10;
413122580Sanholt		}
414182080Srnoland		break;
415182080Srnoland
416182080Srnoland	default:
417182080Srnoland		DRM_ERROR("Invalid packet type %x\n", cmd[0] & 0xff00);
418182080Srnoland		return -EINVAL;
419122580Sanholt	}
420122580Sanholt
421122580Sanholt	return 0;
422122580Sanholt}
423122580Sanholt
424122580Sanholt/* ================================================================
42595584Sanholt * CP hardware state programming functions
42695584Sanholt */
42795584Sanholt
428145132Sanholtstatic __inline__ void radeon_emit_clip_rect(drm_radeon_private_t * dev_priv,
429182080Srnoland					     struct drm_clip_rect * box)
43095584Sanholt{
43195584Sanholt	RING_LOCALS;
43295584Sanholt
433145132Sanholt	DRM_DEBUG("   box:  x1=%d y1=%d  x2=%d y2=%d\n",
434145132Sanholt		  box->x1, box->y1, box->x2, box->y2);
43595584Sanholt
436145132Sanholt	BEGIN_RING(4);
437145132Sanholt	OUT_RING(CP_PACKET0(RADEON_RE_TOP_LEFT, 0));
438145132Sanholt	OUT_RING((box->y1 << 16) | box->x1);
439145132Sanholt	OUT_RING(CP_PACKET0(RADEON_RE_WIDTH_HEIGHT, 0));
440145132Sanholt	OUT_RING(((box->y2 - 1) << 16) | (box->x2 - 1));
44195584Sanholt	ADVANCE_RING();
44295584Sanholt}
44395584Sanholt
444112015Sanholt/* Emit 1.1 state
445112015Sanholt */
446145132Sanholtstatic int radeon_emit_state(drm_radeon_private_t * dev_priv,
447182080Srnoland			     struct drm_file *file_priv,
448145132Sanholt			     drm_radeon_context_regs_t * ctx,
449145132Sanholt			     drm_radeon_texture_regs_t * tex,
450145132Sanholt			     unsigned int dirty)
45195584Sanholt{
45295584Sanholt	RING_LOCALS;
453145132Sanholt	DRM_DEBUG("dirty=0x%08x\n", dirty);
45495584Sanholt
455145132Sanholt	if (dirty & RADEON_UPLOAD_CONTEXT) {
456182080Srnoland		if (radeon_check_and_fixup_offset(dev_priv, file_priv,
457145132Sanholt						  &ctx->rb3d_depthoffset)) {
458145132Sanholt			DRM_ERROR("Invalid depth buffer offset\n");
459182080Srnoland			return -EINVAL;
460122580Sanholt		}
461122580Sanholt
462182080Srnoland		if (radeon_check_and_fixup_offset(dev_priv, file_priv,
463145132Sanholt						  &ctx->rb3d_coloroffset)) {
464145132Sanholt			DRM_ERROR("Invalid depth buffer offset\n");
465182080Srnoland			return -EINVAL;
466122580Sanholt		}
467122580Sanholt
468145132Sanholt		BEGIN_RING(14);
469145132Sanholt		OUT_RING(CP_PACKET0(RADEON_PP_MISC, 6));
470145132Sanholt		OUT_RING(ctx->pp_misc);
471145132Sanholt		OUT_RING(ctx->pp_fog_color);
472145132Sanholt		OUT_RING(ctx->re_solid_color);
473145132Sanholt		OUT_RING(ctx->rb3d_blendcntl);
474145132Sanholt		OUT_RING(ctx->rb3d_depthoffset);
475145132Sanholt		OUT_RING(ctx->rb3d_depthpitch);
476145132Sanholt		OUT_RING(ctx->rb3d_zstencilcntl);
477145132Sanholt		OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 2));
478145132Sanholt		OUT_RING(ctx->pp_cntl);
479145132Sanholt		OUT_RING(ctx->rb3d_cntl);
480145132Sanholt		OUT_RING(ctx->rb3d_coloroffset);
481145132Sanholt		OUT_RING(CP_PACKET0(RADEON_RB3D_COLORPITCH, 0));
482145132Sanholt		OUT_RING(ctx->rb3d_colorpitch);
483112015Sanholt		ADVANCE_RING();
48495584Sanholt	}
48595584Sanholt
486145132Sanholt	if (dirty & RADEON_UPLOAD_VERTFMT) {
487145132Sanholt		BEGIN_RING(2);
488145132Sanholt		OUT_RING(CP_PACKET0(RADEON_SE_COORD_FMT, 0));
489145132Sanholt		OUT_RING(ctx->se_coord_fmt);
490112015Sanholt		ADVANCE_RING();
49195584Sanholt	}
49295584Sanholt
493145132Sanholt	if (dirty & RADEON_UPLOAD_LINE) {
494145132Sanholt		BEGIN_RING(5);
495145132Sanholt		OUT_RING(CP_PACKET0(RADEON_RE_LINE_PATTERN, 1));
496145132Sanholt		OUT_RING(ctx->re_line_pattern);
497145132Sanholt		OUT_RING(ctx->re_line_state);
498145132Sanholt		OUT_RING(CP_PACKET0(RADEON_SE_LINE_WIDTH, 0));
499145132Sanholt		OUT_RING(ctx->se_line_width);
500112015Sanholt		ADVANCE_RING();
50195584Sanholt	}
50295584Sanholt
503145132Sanholt	if (dirty & RADEON_UPLOAD_BUMPMAP) {
504145132Sanholt		BEGIN_RING(5);
505145132Sanholt		OUT_RING(CP_PACKET0(RADEON_PP_LUM_MATRIX, 0));
506145132Sanholt		OUT_RING(ctx->pp_lum_matrix);
507145132Sanholt		OUT_RING(CP_PACKET0(RADEON_PP_ROT_MATRIX_0, 1));
508145132Sanholt		OUT_RING(ctx->pp_rot_matrix_0);
509145132Sanholt		OUT_RING(ctx->pp_rot_matrix_1);
510112015Sanholt		ADVANCE_RING();
51195584Sanholt	}
51295584Sanholt
513145132Sanholt	if (dirty & RADEON_UPLOAD_MASKS) {
514145132Sanholt		BEGIN_RING(4);
515145132Sanholt		OUT_RING(CP_PACKET0(RADEON_RB3D_STENCILREFMASK, 2));
516145132Sanholt		OUT_RING(ctx->rb3d_stencilrefmask);
517145132Sanholt		OUT_RING(ctx->rb3d_ropcntl);
518145132Sanholt		OUT_RING(ctx->rb3d_planemask);
519112015Sanholt		ADVANCE_RING();
52095584Sanholt	}
52195584Sanholt
522145132Sanholt	if (dirty & RADEON_UPLOAD_VIEWPORT) {
523145132Sanholt		BEGIN_RING(7);
524145132Sanholt		OUT_RING(CP_PACKET0(RADEON_SE_VPORT_XSCALE, 5));
525145132Sanholt		OUT_RING(ctx->se_vport_xscale);
526145132Sanholt		OUT_RING(ctx->se_vport_xoffset);
527145132Sanholt		OUT_RING(ctx->se_vport_yscale);
528145132Sanholt		OUT_RING(ctx->se_vport_yoffset);
529145132Sanholt		OUT_RING(ctx->se_vport_zscale);
530145132Sanholt		OUT_RING(ctx->se_vport_zoffset);
531112015Sanholt		ADVANCE_RING();
53295584Sanholt	}
53395584Sanholt
534145132Sanholt	if (dirty & RADEON_UPLOAD_SETUP) {
535145132Sanholt		BEGIN_RING(4);
536145132Sanholt		OUT_RING(CP_PACKET0(RADEON_SE_CNTL, 0));
537145132Sanholt		OUT_RING(ctx->se_cntl);
538145132Sanholt		OUT_RING(CP_PACKET0(RADEON_SE_CNTL_STATUS, 0));
539145132Sanholt		OUT_RING(ctx->se_cntl_status);
540112015Sanholt		ADVANCE_RING();
54195584Sanholt	}
54295584Sanholt
543145132Sanholt	if (dirty & RADEON_UPLOAD_MISC) {
544145132Sanholt		BEGIN_RING(2);
545145132Sanholt		OUT_RING(CP_PACKET0(RADEON_RE_MISC, 0));
546145132Sanholt		OUT_RING(ctx->re_misc);
547112015Sanholt		ADVANCE_RING();
54895584Sanholt	}
54995584Sanholt
550145132Sanholt	if (dirty & RADEON_UPLOAD_TEX0) {
551182080Srnoland		if (radeon_check_and_fixup_offset(dev_priv, file_priv,
552145132Sanholt						  &tex[0].pp_txoffset)) {
553145132Sanholt			DRM_ERROR("Invalid texture offset for unit 0\n");
554182080Srnoland			return -EINVAL;
555122580Sanholt		}
556122580Sanholt
557145132Sanholt		BEGIN_RING(9);
558145132Sanholt		OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_0, 5));
559145132Sanholt		OUT_RING(tex[0].pp_txfilter);
560145132Sanholt		OUT_RING(tex[0].pp_txformat);
561145132Sanholt		OUT_RING(tex[0].pp_txoffset);
562145132Sanholt		OUT_RING(tex[0].pp_txcblend);
563145132Sanholt		OUT_RING(tex[0].pp_txablend);
564145132Sanholt		OUT_RING(tex[0].pp_tfactor);
565145132Sanholt		OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_0, 0));
566145132Sanholt		OUT_RING(tex[0].pp_border_color);
567112015Sanholt		ADVANCE_RING();
56895584Sanholt	}
56995584Sanholt
570145132Sanholt	if (dirty & RADEON_UPLOAD_TEX1) {
571182080Srnoland		if (radeon_check_and_fixup_offset(dev_priv, file_priv,
572145132Sanholt						  &tex[1].pp_txoffset)) {
573145132Sanholt			DRM_ERROR("Invalid texture offset for unit 1\n");
574182080Srnoland			return -EINVAL;
575122580Sanholt		}
576122580Sanholt
577145132Sanholt		BEGIN_RING(9);
578145132Sanholt		OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_1, 5));
579145132Sanholt		OUT_RING(tex[1].pp_txfilter);
580145132Sanholt		OUT_RING(tex[1].pp_txformat);
581145132Sanholt		OUT_RING(tex[1].pp_txoffset);
582145132Sanholt		OUT_RING(tex[1].pp_txcblend);
583145132Sanholt		OUT_RING(tex[1].pp_txablend);
584145132Sanholt		OUT_RING(tex[1].pp_tfactor);
585145132Sanholt		OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_1, 0));
586145132Sanholt		OUT_RING(tex[1].pp_border_color);
587112015Sanholt		ADVANCE_RING();
58895584Sanholt	}
58995584Sanholt
590145132Sanholt	if (dirty & RADEON_UPLOAD_TEX2) {
591182080Srnoland		if (radeon_check_and_fixup_offset(dev_priv, file_priv,
592145132Sanholt						  &tex[2].pp_txoffset)) {
593145132Sanholt			DRM_ERROR("Invalid texture offset for unit 2\n");
594182080Srnoland			return -EINVAL;
595122580Sanholt		}
596122580Sanholt
597145132Sanholt		BEGIN_RING(9);
598145132Sanholt		OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_2, 5));
599145132Sanholt		OUT_RING(tex[2].pp_txfilter);
600145132Sanholt		OUT_RING(tex[2].pp_txformat);
601145132Sanholt		OUT_RING(tex[2].pp_txoffset);
602145132Sanholt		OUT_RING(tex[2].pp_txcblend);
603145132Sanholt		OUT_RING(tex[2].pp_txablend);
604145132Sanholt		OUT_RING(tex[2].pp_tfactor);
605145132Sanholt		OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_2, 0));
606145132Sanholt		OUT_RING(tex[2].pp_border_color);
607112015Sanholt		ADVANCE_RING();
60895584Sanholt	}
609122580Sanholt
610122580Sanholt	return 0;
611112015Sanholt}
61295584Sanholt
613112015Sanholt/* Emit 1.2 state
614112015Sanholt */
615145132Sanholtstatic int radeon_emit_state2(drm_radeon_private_t * dev_priv,
616182080Srnoland			      struct drm_file *file_priv,
617145132Sanholt			      drm_radeon_state_t * state)
618112015Sanholt{
619112015Sanholt	RING_LOCALS;
620112015Sanholt
621112015Sanholt	if (state->dirty & RADEON_UPLOAD_ZBIAS) {
622145132Sanholt		BEGIN_RING(3);
623145132Sanholt		OUT_RING(CP_PACKET0(RADEON_SE_ZBIAS_FACTOR, 1));
624145132Sanholt		OUT_RING(state->context2.se_zbias_factor);
625145132Sanholt		OUT_RING(state->context2.se_zbias_constant);
626112015Sanholt		ADVANCE_RING();
627112015Sanholt	}
628112015Sanholt
629182080Srnoland	return radeon_emit_state(dev_priv, file_priv, &state->context,
630145132Sanholt				 state->tex, state->dirty);
63195584Sanholt}
63295584Sanholt
633112015Sanholt/* New (1.3) state mechanism.  3 commands (packet, scalar, vector) in
634112015Sanholt * 1.3 cmdbuffers allow all previous state to be updated as well as
635145132Sanholt * the tcl scalar and vector areas.
636112015Sanholt */
637145132Sanholtstatic struct {
638145132Sanholt	int start;
639145132Sanholt	int len;
640112015Sanholt	const char *name;
641112015Sanholt} packet[RADEON_MAX_STATE_PACKETS] = {
642152909Sanholt	{RADEON_PP_MISC, 7, "RADEON_PP_MISC"},
643152909Sanholt	{RADEON_PP_CNTL, 3, "RADEON_PP_CNTL"},
644152909Sanholt	{RADEON_RB3D_COLORPITCH, 1, "RADEON_RB3D_COLORPITCH"},
645152909Sanholt	{RADEON_RE_LINE_PATTERN, 2, "RADEON_RE_LINE_PATTERN"},
646152909Sanholt	{RADEON_SE_LINE_WIDTH, 1, "RADEON_SE_LINE_WIDTH"},
647152909Sanholt	{RADEON_PP_LUM_MATRIX, 1, "RADEON_PP_LUM_MATRIX"},
648152909Sanholt	{RADEON_PP_ROT_MATRIX_0, 2, "RADEON_PP_ROT_MATRIX_0"},
649152909Sanholt	{RADEON_RB3D_STENCILREFMASK, 3, "RADEON_RB3D_STENCILREFMASK"},
650152909Sanholt	{RADEON_SE_VPORT_XSCALE, 6, "RADEON_SE_VPORT_XSCALE"},
651152909Sanholt	{RADEON_SE_CNTL, 2, "RADEON_SE_CNTL"},
652152909Sanholt	{RADEON_SE_CNTL_STATUS, 1, "RADEON_SE_CNTL_STATUS"},
653152909Sanholt	{RADEON_RE_MISC, 1, "RADEON_RE_MISC"},
654152909Sanholt	{RADEON_PP_TXFILTER_0, 6, "RADEON_PP_TXFILTER_0"},
655152909Sanholt	{RADEON_PP_BORDER_COLOR_0, 1, "RADEON_PP_BORDER_COLOR_0"},
656152909Sanholt	{RADEON_PP_TXFILTER_1, 6, "RADEON_PP_TXFILTER_1"},
657152909Sanholt	{RADEON_PP_BORDER_COLOR_1, 1, "RADEON_PP_BORDER_COLOR_1"},
658152909Sanholt	{RADEON_PP_TXFILTER_2, 6, "RADEON_PP_TXFILTER_2"},
659152909Sanholt	{RADEON_PP_BORDER_COLOR_2, 1, "RADEON_PP_BORDER_COLOR_2"},
660152909Sanholt	{RADEON_SE_ZBIAS_FACTOR, 2, "RADEON_SE_ZBIAS_FACTOR"},
661152909Sanholt	{RADEON_SE_TCL_OUTPUT_VTX_FMT, 11, "RADEON_SE_TCL_OUTPUT_VTX_FMT"},
662152909Sanholt	{RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED, 17,
663157617Sanholt		    "RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED"},
664152909Sanholt	{R200_PP_TXCBLEND_0, 4, "R200_PP_TXCBLEND_0"},
665152909Sanholt	{R200_PP_TXCBLEND_1, 4, "R200_PP_TXCBLEND_1"},
666152909Sanholt	{R200_PP_TXCBLEND_2, 4, "R200_PP_TXCBLEND_2"},
667152909Sanholt	{R200_PP_TXCBLEND_3, 4, "R200_PP_TXCBLEND_3"},
668152909Sanholt	{R200_PP_TXCBLEND_4, 4, "R200_PP_TXCBLEND_4"},
669152909Sanholt	{R200_PP_TXCBLEND_5, 4, "R200_PP_TXCBLEND_5"},
670152909Sanholt	{R200_PP_TXCBLEND_6, 4, "R200_PP_TXCBLEND_6"},
671152909Sanholt	{R200_PP_TXCBLEND_7, 4, "R200_PP_TXCBLEND_7"},
672152909Sanholt	{R200_SE_TCL_LIGHT_MODEL_CTL_0, 6, "R200_SE_TCL_LIGHT_MODEL_CTL_0"},
673152909Sanholt	{R200_PP_TFACTOR_0, 6, "R200_PP_TFACTOR_0"},
674152909Sanholt	{R200_SE_VTX_FMT_0, 4, "R200_SE_VTX_FMT_0"},
675152909Sanholt	{R200_SE_VAP_CNTL, 1, "R200_SE_VAP_CNTL"},
676152909Sanholt	{R200_SE_TCL_MATRIX_SEL_0, 5, "R200_SE_TCL_MATRIX_SEL_0"},
677152909Sanholt	{R200_SE_TCL_TEX_PROC_CTL_2, 5, "R200_SE_TCL_TEX_PROC_CTL_2"},
678152909Sanholt	{R200_SE_TCL_UCP_VERT_BLEND_CTL, 1, "R200_SE_TCL_UCP_VERT_BLEND_CTL"},
679152909Sanholt	{R200_PP_TXFILTER_0, 6, "R200_PP_TXFILTER_0"},
680152909Sanholt	{R200_PP_TXFILTER_1, 6, "R200_PP_TXFILTER_1"},
681152909Sanholt	{R200_PP_TXFILTER_2, 6, "R200_PP_TXFILTER_2"},
682152909Sanholt	{R200_PP_TXFILTER_3, 6, "R200_PP_TXFILTER_3"},
683152909Sanholt	{R200_PP_TXFILTER_4, 6, "R200_PP_TXFILTER_4"},
684152909Sanholt	{R200_PP_TXFILTER_5, 6, "R200_PP_TXFILTER_5"},
685152909Sanholt	{R200_PP_TXOFFSET_0, 1, "R200_PP_TXOFFSET_0"},
686152909Sanholt	{R200_PP_TXOFFSET_1, 1, "R200_PP_TXOFFSET_1"},
687152909Sanholt	{R200_PP_TXOFFSET_2, 1, "R200_PP_TXOFFSET_2"},
688152909Sanholt	{R200_PP_TXOFFSET_3, 1, "R200_PP_TXOFFSET_3"},
689152909Sanholt	{R200_PP_TXOFFSET_4, 1, "R200_PP_TXOFFSET_4"},
690152909Sanholt	{R200_PP_TXOFFSET_5, 1, "R200_PP_TXOFFSET_5"},
691152909Sanholt	{R200_SE_VTE_CNTL, 1, "R200_SE_VTE_CNTL"},
692152909Sanholt	{R200_SE_TCL_OUTPUT_VTX_COMP_SEL, 1,
693152909Sanholt	 "R200_SE_TCL_OUTPUT_VTX_COMP_SEL"},
694152909Sanholt	{R200_PP_TAM_DEBUG3, 1, "R200_PP_TAM_DEBUG3"},
695152909Sanholt	{R200_PP_CNTL_X, 1, "R200_PP_CNTL_X"},
696152909Sanholt	{R200_RB3D_DEPTHXY_OFFSET, 1, "R200_RB3D_DEPTHXY_OFFSET"},
697152909Sanholt	{R200_RE_AUX_SCISSOR_CNTL, 1, "R200_RE_AUX_SCISSOR_CNTL"},
698152909Sanholt	{R200_RE_SCISSOR_TL_0, 2, "R200_RE_SCISSOR_TL_0"},
699152909Sanholt	{R200_RE_SCISSOR_TL_1, 2, "R200_RE_SCISSOR_TL_1"},
700152909Sanholt	{R200_RE_SCISSOR_TL_2, 2, "R200_RE_SCISSOR_TL_2"},
701152909Sanholt	{R200_SE_VAP_CNTL_STATUS, 1, "R200_SE_VAP_CNTL_STATUS"},
702152909Sanholt	{R200_SE_VTX_STATE_CNTL, 1, "R200_SE_VTX_STATE_CNTL"},
703152909Sanholt	{R200_RE_POINTSIZE, 1, "R200_RE_POINTSIZE"},
704152909Sanholt	{R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0, 4,
705157617Sanholt		    "R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0"},
706152909Sanholt	{R200_PP_CUBIC_FACES_0, 1, "R200_PP_CUBIC_FACES_0"},	/* 61 */
707152909Sanholt	{R200_PP_CUBIC_OFFSET_F1_0, 5, "R200_PP_CUBIC_OFFSET_F1_0"}, /* 62 */
708152909Sanholt	{R200_PP_CUBIC_FACES_1, 1, "R200_PP_CUBIC_FACES_1"},
709152909Sanholt	{R200_PP_CUBIC_OFFSET_F1_1, 5, "R200_PP_CUBIC_OFFSET_F1_1"},
710152909Sanholt	{R200_PP_CUBIC_FACES_2, 1, "R200_PP_CUBIC_FACES_2"},
711152909Sanholt	{R200_PP_CUBIC_OFFSET_F1_2, 5, "R200_PP_CUBIC_OFFSET_F1_2"},
712152909Sanholt	{R200_PP_CUBIC_FACES_3, 1, "R200_PP_CUBIC_FACES_3"},
713152909Sanholt	{R200_PP_CUBIC_OFFSET_F1_3, 5, "R200_PP_CUBIC_OFFSET_F1_3"},
714152909Sanholt	{R200_PP_CUBIC_FACES_4, 1, "R200_PP_CUBIC_FACES_4"},
715152909Sanholt	{R200_PP_CUBIC_OFFSET_F1_4, 5, "R200_PP_CUBIC_OFFSET_F1_4"},
716152909Sanholt	{R200_PP_CUBIC_FACES_5, 1, "R200_PP_CUBIC_FACES_5"},
717152909Sanholt	{R200_PP_CUBIC_OFFSET_F1_5, 5, "R200_PP_CUBIC_OFFSET_F1_5"},
718152909Sanholt	{RADEON_PP_TEX_SIZE_0, 2, "RADEON_PP_TEX_SIZE_0"},
719152909Sanholt	{RADEON_PP_TEX_SIZE_1, 2, "RADEON_PP_TEX_SIZE_1"},
720152909Sanholt	{RADEON_PP_TEX_SIZE_2, 2, "RADEON_PP_TEX_SIZE_2"},
721152909Sanholt	{R200_RB3D_BLENDCOLOR, 3, "R200_RB3D_BLENDCOLOR"},
722152909Sanholt	{R200_SE_TCL_POINT_SPRITE_CNTL, 1, "R200_SE_TCL_POINT_SPRITE_CNTL"},
723152909Sanholt	{RADEON_PP_CUBIC_FACES_0, 1, "RADEON_PP_CUBIC_FACES_0"},
724152909Sanholt	{RADEON_PP_CUBIC_OFFSET_T0_0, 5, "RADEON_PP_CUBIC_OFFSET_T0_0"},
725152909Sanholt	{RADEON_PP_CUBIC_FACES_1, 1, "RADEON_PP_CUBIC_FACES_1"},
726152909Sanholt	{RADEON_PP_CUBIC_OFFSET_T1_0, 5, "RADEON_PP_CUBIC_OFFSET_T1_0"},
727152909Sanholt	{RADEON_PP_CUBIC_FACES_2, 1, "RADEON_PP_CUBIC_FACES_2"},
728152909Sanholt	{RADEON_PP_CUBIC_OFFSET_T2_0, 5, "RADEON_PP_CUBIC_OFFSET_T2_0"},
729152909Sanholt	{R200_PP_TRI_PERF, 2, "R200_PP_TRI_PERF"},
730152909Sanholt	{R200_PP_AFS_0, 32, "R200_PP_AFS_0"},     /* 85 */
731152909Sanholt	{R200_PP_AFS_1, 32, "R200_PP_AFS_1"},
732152909Sanholt	{R200_PP_TFACTOR_0, 8, "R200_ATF_TFACTOR"},
733152909Sanholt	{R200_PP_TXFILTER_0, 8, "R200_PP_TXCTLALL_0"},
734152909Sanholt	{R200_PP_TXFILTER_1, 8, "R200_PP_TXCTLALL_1"},
735152909Sanholt	{R200_PP_TXFILTER_2, 8, "R200_PP_TXCTLALL_2"},
736152909Sanholt	{R200_PP_TXFILTER_3, 8, "R200_PP_TXCTLALL_3"},
737152909Sanholt	{R200_PP_TXFILTER_4, 8, "R200_PP_TXCTLALL_4"},
738152909Sanholt	{R200_PP_TXFILTER_5, 8, "R200_PP_TXCTLALL_5"},
739162132Sanholt	{R200_VAP_PVS_CNTL_1, 2, "R200_VAP_PVS_CNTL"},
740112015Sanholt};
74195584Sanholt
74295584Sanholt/* ================================================================
74395584Sanholt * Performance monitoring functions
74495584Sanholt */
74595584Sanholt
746145132Sanholtstatic void radeon_clear_box(drm_radeon_private_t * dev_priv,
747145132Sanholt			     int x, int y, int w, int h, int r, int g, int b)
74895584Sanholt{
74995584Sanholt	u32 color;
75095584Sanholt	RING_LOCALS;
75195584Sanholt
752112015Sanholt	x += dev_priv->sarea_priv->boxes[0].x1;
753112015Sanholt	y += dev_priv->sarea_priv->boxes[0].y1;
754112015Sanholt
755145132Sanholt	switch (dev_priv->color_fmt) {
75695584Sanholt	case RADEON_COLOR_FORMAT_RGB565:
75795584Sanholt		color = (((r & 0xf8) << 8) |
758145132Sanholt			 ((g & 0xfc) << 3) | ((b & 0xf8) >> 3));
75995584Sanholt		break;
76095584Sanholt	case RADEON_COLOR_FORMAT_ARGB8888:
76195584Sanholt	default:
762145132Sanholt		color = (((0xff) << 24) | (r << 16) | (g << 8) | b);
76395584Sanholt		break;
76495584Sanholt	}
76595584Sanholt
766145132Sanholt	BEGIN_RING(4);
767145132Sanholt	RADEON_WAIT_UNTIL_3D_IDLE();
768145132Sanholt	OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0));
769145132Sanholt	OUT_RING(0xffffffff);
770112015Sanholt	ADVANCE_RING();
77195584Sanholt
772145132Sanholt	BEGIN_RING(6);
77395584Sanholt
774145132Sanholt	OUT_RING(CP_PACKET3(RADEON_CNTL_PAINT_MULTI, 4));
775145132Sanholt	OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
776145132Sanholt		 RADEON_GMC_BRUSH_SOLID_COLOR |
777145132Sanholt		 (dev_priv->color_fmt << 8) |
778145132Sanholt		 RADEON_GMC_SRC_DATATYPE_COLOR |
779145132Sanholt		 RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS);
78095584Sanholt
781182080Srnoland	if (dev_priv->sarea_priv->pfCurrentPage == 1) {
782145132Sanholt		OUT_RING(dev_priv->front_pitch_offset);
783145132Sanholt	} else {
784145132Sanholt		OUT_RING(dev_priv->back_pitch_offset);
785145132Sanholt	}
786112015Sanholt
787145132Sanholt	OUT_RING(color);
78895584Sanholt
789145132Sanholt	OUT_RING((x << 16) | y);
790145132Sanholt	OUT_RING((w << 16) | h);
79195584Sanholt
79295584Sanholt	ADVANCE_RING();
79395584Sanholt}
79495584Sanholt
795189499Srnolandstatic void radeon_cp_performance_boxes(drm_radeon_private_t *dev_priv)
79695584Sanholt{
797112015Sanholt	/* Collapse various things into a wait flag -- trying to
798112015Sanholt	 * guess if userspase slept -- better just to have them tell us.
799112015Sanholt	 */
800112015Sanholt	if (dev_priv->stats.last_frame_reads > 1 ||
801112015Sanholt	    dev_priv->stats.last_clear_reads > dev_priv->stats.clears) {
802112015Sanholt		dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
803112015Sanholt	}
804112015Sanholt
805112015Sanholt	if (dev_priv->stats.freelist_loops) {
806112015Sanholt		dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
807112015Sanholt	}
808112015Sanholt
809112015Sanholt	/* Purple box for page flipping
810112015Sanholt	 */
811145132Sanholt	if (dev_priv->stats.boxes & RADEON_BOX_FLIP)
812145132Sanholt		radeon_clear_box(dev_priv, 4, 4, 8, 8, 255, 0, 255);
813112015Sanholt
814112015Sanholt	/* Red box if we have to wait for idle at any point
815112015Sanholt	 */
816145132Sanholt	if (dev_priv->stats.boxes & RADEON_BOX_WAIT_IDLE)
817145132Sanholt		radeon_clear_box(dev_priv, 16, 4, 8, 8, 255, 0, 0);
818112015Sanholt
819112015Sanholt	/* Blue box: lost context?
820112015Sanholt	 */
821112015Sanholt
822112015Sanholt	/* Yellow box for texture swaps
823112015Sanholt	 */
824145132Sanholt	if (dev_priv->stats.boxes & RADEON_BOX_TEXTURE_LOAD)
825145132Sanholt		radeon_clear_box(dev_priv, 40, 4, 8, 8, 255, 255, 0);
826112015Sanholt
827112015Sanholt	/* Green box if hardware never idles (as far as we can tell)
828112015Sanholt	 */
829145132Sanholt	if (!(dev_priv->stats.boxes & RADEON_BOX_DMA_IDLE))
830145132Sanholt		radeon_clear_box(dev_priv, 64, 4, 8, 8, 0, 255, 0);
831112015Sanholt
832145132Sanholt	/* Draw bars indicating number of buffers allocated
833112015Sanholt	 * (not a great measure, easily confused)
834112015Sanholt	 */
835112015Sanholt	if (dev_priv->stats.requested_bufs) {
836112015Sanholt		if (dev_priv->stats.requested_bufs > 100)
837112015Sanholt			dev_priv->stats.requested_bufs = 100;
838112015Sanholt
839145132Sanholt		radeon_clear_box(dev_priv, 4, 16,
840145132Sanholt				 dev_priv->stats.requested_bufs, 4,
841145132Sanholt				 196, 128, 128);
84295584Sanholt	}
84395584Sanholt
844145132Sanholt	memset(&dev_priv->stats, 0, sizeof(dev_priv->stats));
84595584Sanholt
846112015Sanholt}
847145132Sanholt
84895584Sanholt/* ================================================================
84995584Sanholt * CP command dispatch functions
85095584Sanholt */
85195584Sanholt
852182080Srnolandstatic void radeon_cp_dispatch_clear(struct drm_device * dev,
853145132Sanholt				     drm_radeon_clear_t * clear,
854145132Sanholt				     drm_radeon_clear_rect_t * depth_boxes)
85595584Sanholt{
85695584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
85795584Sanholt	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
858112015Sanholt	drm_radeon_depth_clear_t *depth_clear = &dev_priv->depth_clear;
85995584Sanholt	int nbox = sarea_priv->nbox;
860182080Srnoland	struct drm_clip_rect *pbox = sarea_priv->boxes;
86195584Sanholt	unsigned int flags = clear->flags;
862145132Sanholt	u32 rb3d_cntl = 0, rb3d_stencilrefmask = 0;
86395584Sanholt	int i;
86495584Sanholt	RING_LOCALS;
865145132Sanholt	DRM_DEBUG("flags = 0x%x\n", flags);
86695584Sanholt
867112015Sanholt	dev_priv->stats.clears++;
868112015Sanholt
869189499Srnoland	if (sarea_priv->pfCurrentPage == 1) {
87095584Sanholt		unsigned int tmp = flags;
87195584Sanholt
87295584Sanholt		flags &= ~(RADEON_FRONT | RADEON_BACK);
873145132Sanholt		if (tmp & RADEON_FRONT)
874145132Sanholt			flags |= RADEON_BACK;
875145132Sanholt		if (tmp & RADEON_BACK)
876145132Sanholt			flags |= RADEON_FRONT;
87795584Sanholt	}
87895584Sanholt
879145132Sanholt	if (flags & (RADEON_FRONT | RADEON_BACK)) {
88095584Sanholt
881145132Sanholt		BEGIN_RING(4);
88295584Sanholt
883112015Sanholt		/* Ensure the 3D stream is idle before doing a
884112015Sanholt		 * 2D fill to clear the front or back buffer.
885112015Sanholt		 */
886112015Sanholt		RADEON_WAIT_UNTIL_3D_IDLE();
88795584Sanholt
888145132Sanholt		OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0));
889145132Sanholt		OUT_RING(clear->color_mask);
890145132Sanholt
891112015Sanholt		ADVANCE_RING();
89295584Sanholt
893112015Sanholt		/* Make sure we restore the 3D state next time.
894112015Sanholt		 */
895189499Srnoland		sarea_priv->ctx_owner = 0;
89695584Sanholt
897145132Sanholt		for (i = 0; i < nbox; i++) {
898112015Sanholt			int x = pbox[i].x1;
899112015Sanholt			int y = pbox[i].y1;
900112015Sanholt			int w = pbox[i].x2 - x;
901112015Sanholt			int h = pbox[i].y2 - y;
90295584Sanholt
903182080Srnoland			DRM_DEBUG("%d,%d-%d,%d flags 0x%x\n",
904145132Sanholt				  x, y, w, h, flags);
905112015Sanholt
906145132Sanholt			if (flags & RADEON_FRONT) {
907145132Sanholt				BEGIN_RING(6);
908112015Sanholt
909145132Sanholt				OUT_RING(CP_PACKET3
910145132Sanholt					 (RADEON_CNTL_PAINT_MULTI, 4));
911145132Sanholt				OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
912145132Sanholt					 RADEON_GMC_BRUSH_SOLID_COLOR |
913145132Sanholt					 (dev_priv->
914145132Sanholt					  color_fmt << 8) |
915145132Sanholt					 RADEON_GMC_SRC_DATATYPE_COLOR |
916145132Sanholt					 RADEON_ROP3_P |
917145132Sanholt					 RADEON_GMC_CLR_CMP_CNTL_DIS);
918145132Sanholt
919145132Sanholt				OUT_RING(dev_priv->front_pitch_offset);
920145132Sanholt				OUT_RING(clear->clear_color);
921145132Sanholt
922145132Sanholt				OUT_RING((x << 16) | y);
923145132Sanholt				OUT_RING((w << 16) | h);
924145132Sanholt
925112015Sanholt				ADVANCE_RING();
926112015Sanholt			}
927112015Sanholt
928145132Sanholt			if (flags & RADEON_BACK) {
929145132Sanholt				BEGIN_RING(6);
930112015Sanholt
931145132Sanholt				OUT_RING(CP_PACKET3
932145132Sanholt					 (RADEON_CNTL_PAINT_MULTI, 4));
933145132Sanholt				OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
934145132Sanholt					 RADEON_GMC_BRUSH_SOLID_COLOR |
935145132Sanholt					 (dev_priv->
936145132Sanholt					  color_fmt << 8) |
937145132Sanholt					 RADEON_GMC_SRC_DATATYPE_COLOR |
938145132Sanholt					 RADEON_ROP3_P |
939145132Sanholt					 RADEON_GMC_CLR_CMP_CNTL_DIS);
940145132Sanholt
941145132Sanholt				OUT_RING(dev_priv->back_pitch_offset);
942145132Sanholt				OUT_RING(clear->clear_color);
943145132Sanholt
944145132Sanholt				OUT_RING((x << 16) | y);
945145132Sanholt				OUT_RING((w << 16) | h);
946145132Sanholt
947112015Sanholt				ADVANCE_RING();
948112015Sanholt			}
94995584Sanholt		}
950112015Sanholt	}
95195584Sanholt
952145132Sanholt	/* hyper z clear */
953145132Sanholt	/* no docs available, based on reverse engeneering by Stephane Marchesin */
954157617Sanholt	if ((flags & (RADEON_DEPTH | RADEON_STENCIL))
955157617Sanholt	    && (flags & RADEON_CLEAR_FASTZ)) {
956145132Sanholt
957145132Sanholt		int i;
958157617Sanholt		int depthpixperline =
959157617Sanholt		    dev_priv->depth_fmt ==
960157617Sanholt		    RADEON_DEPTH_FORMAT_16BIT_INT_Z ? (dev_priv->depth_pitch /
961157617Sanholt						       2) : (dev_priv->
962157617Sanholt							     depth_pitch / 4);
963157617Sanholt
964145132Sanholt		u32 clearmask;
965145132Sanholt
966145132Sanholt		u32 tempRB3D_DEPTHCLEARVALUE = clear->clear_depth |
967157617Sanholt		    ((clear->depth_mask & 0xff) << 24);
968157617Sanholt
969145132Sanholt		/* Make sure we restore the 3D state next time.
970145132Sanholt		 * we haven't touched any "normal" state - still need this?
971145132Sanholt		 */
972189499Srnoland		sarea_priv->ctx_owner = 0;
973145132Sanholt
974182080Srnoland		if ((dev_priv->flags & RADEON_HAS_HIERZ)
975157617Sanholt		    && (flags & RADEON_USE_HIERZ)) {
976157617Sanholt			/* FIXME : reverse engineer that for Rx00 cards */
977157617Sanholt			/* FIXME : the mask supposedly contains low-res z values. So can't set
978157617Sanholt			   just to the max (0xff? or actually 0x3fff?), need to take z clear
979157617Sanholt			   value into account? */
980157617Sanholt			/* pattern seems to work for r100, though get slight
981157617Sanholt			   rendering errors with glxgears. If hierz is not enabled for r100,
982157617Sanholt			   only 4 bits which indicate clear (15,16,31,32, all zero) matter, the
983157617Sanholt			   other ones are ignored, and the same clear mask can be used. That's
984157617Sanholt			   very different behaviour than R200 which needs different clear mask
985157617Sanholt			   and different number of tiles to clear if hierz is enabled or not !?!
986157617Sanholt			 */
987157617Sanholt			clearmask = (0xff << 22) | (0xff << 6) | 0x003f003f;
988157617Sanholt		} else {
989157617Sanholt			/* clear mask : chooses the clearing pattern.
990157617Sanholt			   rv250: could be used to clear only parts of macrotiles
991157617Sanholt			   (but that would get really complicated...)?
992157617Sanholt			   bit 0 and 1 (either or both of them ?!?!) are used to
993157617Sanholt			   not clear tile (or maybe one of the bits indicates if the tile is
994157617Sanholt			   compressed or not), bit 2 and 3 to not clear tile 1,...,.
995157617Sanholt			   Pattern is as follows:
996157617Sanholt			   | 0,1 | 4,5 | 8,9 |12,13|16,17|20,21|24,25|28,29|
997157617Sanholt			   bits -------------------------------------------------
998157617Sanholt			   | 2,3 | 6,7 |10,11|14,15|18,19|22,23|26,27|30,31|
999157617Sanholt			   rv100: clearmask covers 2x8 4x1 tiles, but one clear still
1000157617Sanholt			   covers 256 pixels ?!?
1001157617Sanholt			 */
1002145132Sanholt			clearmask = 0x0;
1003145132Sanholt		}
1004145132Sanholt
1005157617Sanholt		BEGIN_RING(8);
1006145132Sanholt		RADEON_WAIT_UNTIL_2D_IDLE();
1007157617Sanholt		OUT_RING_REG(RADEON_RB3D_DEPTHCLEARVALUE,
1008157617Sanholt			     tempRB3D_DEPTHCLEARVALUE);
1009145132Sanholt		/* what offset is this exactly ? */
1010157617Sanholt		OUT_RING_REG(RADEON_RB3D_ZMASKOFFSET, 0);
1011145132Sanholt		/* need ctlstat, otherwise get some strange black flickering */
1012157617Sanholt		OUT_RING_REG(RADEON_RB3D_ZCACHE_CTLSTAT,
1013157617Sanholt			     RADEON_RB3D_ZC_FLUSH_ALL);
1014145132Sanholt		ADVANCE_RING();
1015145132Sanholt
1016145132Sanholt		for (i = 0; i < nbox; i++) {
1017145132Sanholt			int tileoffset, nrtilesx, nrtilesy, j;
1018145132Sanholt			/* it looks like r200 needs rv-style clears, at least if hierz is not enabled? */
1019182080Srnoland			if ((dev_priv->flags & RADEON_HAS_HIERZ)
1020189499Srnoland			    && !(dev_priv->microcode_version == UCODE_R200)) {
1021145132Sanholt				/* FIXME : figure this out for r200 (when hierz is enabled). Or
1022145132Sanholt				   maybe r200 actually doesn't need to put the low-res z value into
1023145132Sanholt				   the tile cache like r100, but just needs to clear the hi-level z-buffer?
1024145132Sanholt				   Works for R100, both with hierz and without.
1025145132Sanholt				   R100 seems to operate on 2x1 8x8 tiles, but...
1026145132Sanholt				   odd: offset/nrtiles need to be 64 pix (4 block) aligned? Potentially
1027145132Sanholt				   problematic with resolutions which are not 64 pix aligned? */
1028157617Sanholt				tileoffset =
1029157617Sanholt				    ((pbox[i].y1 >> 3) * depthpixperline +
1030157617Sanholt				     pbox[i].x1) >> 6;
1031157617Sanholt				nrtilesx =
1032157617Sanholt				    ((pbox[i].x2 & ~63) -
1033157617Sanholt				     (pbox[i].x1 & ~63)) >> 4;
1034157617Sanholt				nrtilesy =
1035157617Sanholt				    (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3);
1036145132Sanholt				for (j = 0; j <= nrtilesy; j++) {
1037157617Sanholt					BEGIN_RING(4);
1038157617Sanholt					OUT_RING(CP_PACKET3
1039157617Sanholt						 (RADEON_3D_CLEAR_ZMASK, 2));
1040145132Sanholt					/* first tile */
1041157617Sanholt					OUT_RING(tileoffset * 8);
1042145132Sanholt					/* the number of tiles to clear */
1043157617Sanholt					OUT_RING(nrtilesx + 4);
1044145132Sanholt					/* clear mask : chooses the clearing pattern. */
1045157617Sanholt					OUT_RING(clearmask);
1046145132Sanholt					ADVANCE_RING();
1047145132Sanholt					tileoffset += depthpixperline >> 6;
1048145132Sanholt				}
1049189499Srnoland			} else if (dev_priv->microcode_version == UCODE_R200) {
1050145132Sanholt				/* works for rv250. */
1051145132Sanholt				/* find first macro tile (8x2 4x4 z-pixels on rv250) */
1052157617Sanholt				tileoffset =
1053157617Sanholt				    ((pbox[i].y1 >> 3) * depthpixperline +
1054157617Sanholt				     pbox[i].x1) >> 5;
1055157617Sanholt				nrtilesx =
1056157617Sanholt				    (pbox[i].x2 >> 5) - (pbox[i].x1 >> 5);
1057157617Sanholt				nrtilesy =
1058157617Sanholt				    (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3);
1059145132Sanholt				for (j = 0; j <= nrtilesy; j++) {
1060157617Sanholt					BEGIN_RING(4);
1061157617Sanholt					OUT_RING(CP_PACKET3
1062157617Sanholt						 (RADEON_3D_CLEAR_ZMASK, 2));
1063145132Sanholt					/* first tile */
1064145132Sanholt					/* judging by the first tile offset needed, could possibly
1065145132Sanholt					   directly address/clear 4x4 tiles instead of 8x2 * 4x4
1066145132Sanholt					   macro tiles, though would still need clear mask for
1067145132Sanholt					   right/bottom if truely 4x4 granularity is desired ? */
1068157617Sanholt					OUT_RING(tileoffset * 16);
1069145132Sanholt					/* the number of tiles to clear */
1070157617Sanholt					OUT_RING(nrtilesx + 1);
1071145132Sanholt					/* clear mask : chooses the clearing pattern. */
1072157617Sanholt					OUT_RING(clearmask);
1073145132Sanholt					ADVANCE_RING();
1074145132Sanholt					tileoffset += depthpixperline >> 5;
1075145132Sanholt				}
1076157617Sanholt			} else {	/* rv 100 */
1077145132Sanholt				/* rv100 might not need 64 pix alignment, who knows */
1078145132Sanholt				/* offsets are, hmm, weird */
1079157617Sanholt				tileoffset =
1080157617Sanholt				    ((pbox[i].y1 >> 4) * depthpixperline +
1081157617Sanholt				     pbox[i].x1) >> 6;
1082157617Sanholt				nrtilesx =
1083157617Sanholt				    ((pbox[i].x2 & ~63) -
1084157617Sanholt				     (pbox[i].x1 & ~63)) >> 4;
1085157617Sanholt				nrtilesy =
1086157617Sanholt				    (pbox[i].y2 >> 4) - (pbox[i].y1 >> 4);
1087145132Sanholt				for (j = 0; j <= nrtilesy; j++) {
1088157617Sanholt					BEGIN_RING(4);
1089157617Sanholt					OUT_RING(CP_PACKET3
1090157617Sanholt						 (RADEON_3D_CLEAR_ZMASK, 2));
1091157617Sanholt					OUT_RING(tileoffset * 128);
1092145132Sanholt					/* the number of tiles to clear */
1093157617Sanholt					OUT_RING(nrtilesx + 4);
1094145132Sanholt					/* clear mask : chooses the clearing pattern. */
1095157617Sanholt					OUT_RING(clearmask);
1096145132Sanholt					ADVANCE_RING();
1097145132Sanholt					tileoffset += depthpixperline >> 6;
1098145132Sanholt				}
1099145132Sanholt			}
1100145132Sanholt		}
1101145132Sanholt
1102145132Sanholt		/* TODO don't always clear all hi-level z tiles */
1103182080Srnoland		if ((dev_priv->flags & RADEON_HAS_HIERZ)
1104189499Srnoland		    && (dev_priv->microcode_version == UCODE_R200)
1105157617Sanholt		    && (flags & RADEON_USE_HIERZ))
1106157617Sanholt			/* r100 and cards without hierarchical z-buffer have no high-level z-buffer */
1107157617Sanholt			/* FIXME : the mask supposedly contains low-res z values. So can't set
1108157617Sanholt			   just to the max (0xff? or actually 0x3fff?), need to take z clear
1109157617Sanholt			   value into account? */
1110145132Sanholt		{
1111157617Sanholt			BEGIN_RING(4);
1112157617Sanholt			OUT_RING(CP_PACKET3(RADEON_3D_CLEAR_HIZ, 2));
1113157617Sanholt			OUT_RING(0x0);	/* First tile */
1114157617Sanholt			OUT_RING(0x3cc0);
1115157617Sanholt			OUT_RING((0xff << 22) | (0xff << 6) | 0x003f003f);
1116145132Sanholt			ADVANCE_RING();
1117145132Sanholt		}
1118145132Sanholt	}
1119145132Sanholt
1120112015Sanholt	/* We have to clear the depth and/or stencil buffers by
1121112015Sanholt	 * rendering a quad into just those buffers.  Thus, we have to
1122112015Sanholt	 * make sure the 3D engine is configured correctly.
1123112015Sanholt	 */
1124189499Srnoland	else if ((dev_priv->microcode_version == UCODE_R200) &&
1125189499Srnoland		(flags & (RADEON_DEPTH | RADEON_STENCIL))) {
112695584Sanholt
1127112015Sanholt		int tempPP_CNTL;
1128112015Sanholt		int tempRE_CNTL;
1129112015Sanholt		int tempRB3D_CNTL;
1130112015Sanholt		int tempRB3D_ZSTENCILCNTL;
1131112015Sanholt		int tempRB3D_STENCILREFMASK;
1132112015Sanholt		int tempRB3D_PLANEMASK;
1133112015Sanholt		int tempSE_CNTL;
1134112015Sanholt		int tempSE_VTE_CNTL;
1135112015Sanholt		int tempSE_VTX_FMT_0;
1136112015Sanholt		int tempSE_VTX_FMT_1;
1137112015Sanholt		int tempSE_VAP_CNTL;
1138112015Sanholt		int tempRE_AUX_SCISSOR_CNTL;
113995584Sanholt
1140112015Sanholt		tempPP_CNTL = 0;
1141112015Sanholt		tempRE_CNTL = 0;
114295584Sanholt
1143112015Sanholt		tempRB3D_CNTL = depth_clear->rb3d_cntl;
114495584Sanholt
1145112015Sanholt		tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl;
1146112015Sanholt		tempRB3D_STENCILREFMASK = 0x0;
1147112015Sanholt
1148112015Sanholt		tempSE_CNTL = depth_clear->se_cntl;
1149112015Sanholt
1150112015Sanholt		/* Disable TCL */
1151112015Sanholt
1152145132Sanholt		tempSE_VAP_CNTL = (	/* SE_VAP_CNTL__FORCE_W_TO_ONE_MASK |  */
1153145132Sanholt					  (0x9 <<
1154145132Sanholt					   SE_VAP_CNTL__VF_MAX_VTX_NUM__SHIFT));
1155112015Sanholt
1156112015Sanholt		tempRB3D_PLANEMASK = 0x0;
1157112015Sanholt
1158112015Sanholt		tempRE_AUX_SCISSOR_CNTL = 0x0;
1159112015Sanholt
1160112015Sanholt		tempSE_VTE_CNTL =
1161145132Sanholt		    SE_VTE_CNTL__VTX_XY_FMT_MASK | SE_VTE_CNTL__VTX_Z_FMT_MASK;
1162112015Sanholt
1163145132Sanholt		/* Vertex format (X, Y, Z, W) */
1164112015Sanholt		tempSE_VTX_FMT_0 =
1165145132Sanholt		    SE_VTX_FMT_0__VTX_Z0_PRESENT_MASK |
1166145132Sanholt		    SE_VTX_FMT_0__VTX_W0_PRESENT_MASK;
1167112015Sanholt		tempSE_VTX_FMT_1 = 0x0;
1168112015Sanholt
1169145132Sanholt		/*
1170145132Sanholt		 * Depth buffer specific enables
1171112015Sanholt		 */
1172112015Sanholt		if (flags & RADEON_DEPTH) {
1173112015Sanholt			/* Enable depth buffer */
1174112015Sanholt			tempRB3D_CNTL |= RADEON_Z_ENABLE;
1175112015Sanholt		} else {
1176112015Sanholt			/* Disable depth buffer */
1177112015Sanholt			tempRB3D_CNTL &= ~RADEON_Z_ENABLE;
117895584Sanholt		}
117995584Sanholt
1180145132Sanholt		/*
1181112015Sanholt		 * Stencil buffer specific enables
1182112015Sanholt		 */
1183145132Sanholt		if (flags & RADEON_STENCIL) {
1184145132Sanholt			tempRB3D_CNTL |= RADEON_STENCIL_ENABLE;
1185145132Sanholt			tempRB3D_STENCILREFMASK = clear->depth_mask;
1186112015Sanholt		} else {
1187112015Sanholt			tempRB3D_CNTL &= ~RADEON_STENCIL_ENABLE;
1188112015Sanholt			tempRB3D_STENCILREFMASK = 0x00000000;
1189112015Sanholt		}
119095584Sanholt
1191145132Sanholt		if (flags & RADEON_USE_COMP_ZBUF) {
1192145132Sanholt			tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE |
1193157617Sanholt			    RADEON_Z_DECOMPRESSION_ENABLE;
1194145132Sanholt		}
1195145132Sanholt		if (flags & RADEON_USE_HIERZ) {
1196145132Sanholt			tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE;
1197145132Sanholt		}
1198145132Sanholt
1199145132Sanholt		BEGIN_RING(26);
1200112015Sanholt		RADEON_WAIT_UNTIL_2D_IDLE();
120195584Sanholt
1202145132Sanholt		OUT_RING_REG(RADEON_PP_CNTL, tempPP_CNTL);
1203145132Sanholt		OUT_RING_REG(R200_RE_CNTL, tempRE_CNTL);
1204145132Sanholt		OUT_RING_REG(RADEON_RB3D_CNTL, tempRB3D_CNTL);
1205145132Sanholt		OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL);
1206145132Sanholt		OUT_RING_REG(RADEON_RB3D_STENCILREFMASK,
1207145132Sanholt			     tempRB3D_STENCILREFMASK);
1208145132Sanholt		OUT_RING_REG(RADEON_RB3D_PLANEMASK, tempRB3D_PLANEMASK);
1209145132Sanholt		OUT_RING_REG(RADEON_SE_CNTL, tempSE_CNTL);
1210145132Sanholt		OUT_RING_REG(R200_SE_VTE_CNTL, tempSE_VTE_CNTL);
1211145132Sanholt		OUT_RING_REG(R200_SE_VTX_FMT_0, tempSE_VTX_FMT_0);
1212145132Sanholt		OUT_RING_REG(R200_SE_VTX_FMT_1, tempSE_VTX_FMT_1);
1213145132Sanholt		OUT_RING_REG(R200_SE_VAP_CNTL, tempSE_VAP_CNTL);
1214145132Sanholt		OUT_RING_REG(R200_RE_AUX_SCISSOR_CNTL, tempRE_AUX_SCISSOR_CNTL);
1215112015Sanholt		ADVANCE_RING();
121695584Sanholt
1217112015Sanholt		/* Make sure we restore the 3D state next time.
1218112015Sanholt		 */
1219189499Srnoland		sarea_priv->ctx_owner = 0;
122095584Sanholt
1221145132Sanholt		for (i = 0; i < nbox; i++) {
1222145132Sanholt
1223145132Sanholt			/* Funny that this should be required --
1224112015Sanholt			 *  sets top-left?
1225112015Sanholt			 */
1226145132Sanholt			radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
1227112015Sanholt
1228145132Sanholt			BEGIN_RING(14);
1229145132Sanholt			OUT_RING(CP_PACKET3(R200_3D_DRAW_IMMD_2, 12));
1230145132Sanholt			OUT_RING((RADEON_PRIM_TYPE_RECT_LIST |
1231145132Sanholt				  RADEON_PRIM_WALK_RING |
1232145132Sanholt				  (3 << RADEON_NUM_VERTICES_SHIFT)));
1233145132Sanholt			OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1234145132Sanholt			OUT_RING(depth_boxes[i].ui[CLEAR_Y1]);
1235145132Sanholt			OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1236145132Sanholt			OUT_RING(0x3f800000);
1237145132Sanholt			OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1238145132Sanholt			OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1239145132Sanholt			OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1240145132Sanholt			OUT_RING(0x3f800000);
1241145132Sanholt			OUT_RING(depth_boxes[i].ui[CLEAR_X2]);
1242145132Sanholt			OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1243145132Sanholt			OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1244145132Sanholt			OUT_RING(0x3f800000);
124595584Sanholt			ADVANCE_RING();
124695584Sanholt		}
1247145132Sanholt	} else if ((flags & (RADEON_DEPTH | RADEON_STENCIL))) {
124895584Sanholt
1249145132Sanholt		int tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl;
1250157617Sanholt
1251112015Sanholt		rb3d_cntl = depth_clear->rb3d_cntl;
1252112015Sanholt
1253145132Sanholt		if (flags & RADEON_DEPTH) {
1254145132Sanholt			rb3d_cntl |= RADEON_Z_ENABLE;
1255112015Sanholt		} else {
1256112015Sanholt			rb3d_cntl &= ~RADEON_Z_ENABLE;
1257112015Sanholt		}
125895584Sanholt
1259145132Sanholt		if (flags & RADEON_STENCIL) {
1260145132Sanholt			rb3d_cntl |= RADEON_STENCIL_ENABLE;
1261145132Sanholt			rb3d_stencilrefmask = clear->depth_mask;	/* misnamed field */
1262112015Sanholt		} else {
1263112015Sanholt			rb3d_cntl &= ~RADEON_STENCIL_ENABLE;
1264112015Sanholt			rb3d_stencilrefmask = 0x00000000;
1265112015Sanholt		}
126695584Sanholt
1267145132Sanholt		if (flags & RADEON_USE_COMP_ZBUF) {
1268145132Sanholt			tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE |
1269157617Sanholt			    RADEON_Z_DECOMPRESSION_ENABLE;
1270145132Sanholt		}
1271145132Sanholt		if (flags & RADEON_USE_HIERZ) {
1272145132Sanholt			tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE;
1273145132Sanholt		}
1274145132Sanholt
1275145132Sanholt		BEGIN_RING(13);
1276112015Sanholt		RADEON_WAIT_UNTIL_2D_IDLE();
1277112015Sanholt
1278145132Sanholt		OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 1));
1279145132Sanholt		OUT_RING(0x00000000);
1280145132Sanholt		OUT_RING(rb3d_cntl);
1281145132Sanholt
1282145132Sanholt		OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL);
1283145132Sanholt		OUT_RING_REG(RADEON_RB3D_STENCILREFMASK, rb3d_stencilrefmask);
1284145132Sanholt		OUT_RING_REG(RADEON_RB3D_PLANEMASK, 0x00000000);
1285145132Sanholt		OUT_RING_REG(RADEON_SE_CNTL, depth_clear->se_cntl);
1286112015Sanholt		ADVANCE_RING();
1287112015Sanholt
1288112015Sanholt		/* Make sure we restore the 3D state next time.
1289112015Sanholt		 */
1290189499Srnoland		sarea_priv->ctx_owner = 0;
1291112015Sanholt
1292145132Sanholt		for (i = 0; i < nbox; i++) {
1293145132Sanholt
1294145132Sanholt			/* Funny that this should be required --
1295112015Sanholt			 *  sets top-left?
129695584Sanholt			 */
1297145132Sanholt			radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
129895584Sanholt
1299145132Sanholt			BEGIN_RING(15);
130095584Sanholt
1301145132Sanholt			OUT_RING(CP_PACKET3(RADEON_3D_DRAW_IMMD, 13));
1302145132Sanholt			OUT_RING(RADEON_VTX_Z_PRESENT |
1303145132Sanholt				 RADEON_VTX_PKCOLOR_PRESENT);
1304145132Sanholt			OUT_RING((RADEON_PRIM_TYPE_RECT_LIST |
1305145132Sanholt				  RADEON_PRIM_WALK_RING |
1306145132Sanholt				  RADEON_MAOS_ENABLE |
1307145132Sanholt				  RADEON_VTX_FMT_RADEON_MODE |
1308145132Sanholt				  (3 << RADEON_NUM_VERTICES_SHIFT)));
130995584Sanholt
1310145132Sanholt			OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1311145132Sanholt			OUT_RING(depth_boxes[i].ui[CLEAR_Y1]);
1312145132Sanholt			OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1313145132Sanholt			OUT_RING(0x0);
1314112015Sanholt
1315145132Sanholt			OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1316145132Sanholt			OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1317145132Sanholt			OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1318145132Sanholt			OUT_RING(0x0);
131995584Sanholt
1320145132Sanholt			OUT_RING(depth_boxes[i].ui[CLEAR_X2]);
1321145132Sanholt			OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1322145132Sanholt			OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1323145132Sanholt			OUT_RING(0x0);
132495584Sanholt
132595584Sanholt			ADVANCE_RING();
132695584Sanholt		}
132795584Sanholt	}
132895584Sanholt
132995584Sanholt	/* Increment the clear counter.  The client-side 3D driver must
133095584Sanholt	 * wait on this value before performing the clear ioctl.  We
133195584Sanholt	 * need this because the card's so damned fast...
133295584Sanholt	 */
1333189499Srnoland	sarea_priv->last_clear++;
133495584Sanholt
1335145132Sanholt	BEGIN_RING(4);
133695584Sanholt
1337189499Srnoland	RADEON_CLEAR_AGE(sarea_priv->last_clear);
133895584Sanholt	RADEON_WAIT_UNTIL_IDLE();
133995584Sanholt
134095584Sanholt	ADVANCE_RING();
134195584Sanholt}
134295584Sanholt
1343189499Srnolandstatic void radeon_cp_dispatch_swap(struct drm_device *dev)
134495584Sanholt{
134595584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
134695584Sanholt	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
134795584Sanholt	int nbox = sarea_priv->nbox;
1348182080Srnoland	struct drm_clip_rect *pbox = sarea_priv->boxes;
134995584Sanholt	int i;
135095584Sanholt	RING_LOCALS;
1351145132Sanholt	DRM_DEBUG("\n");
135295584Sanholt
135395584Sanholt	/* Do some trivial performance monitoring...
135495584Sanholt	 */
1355112015Sanholt	if (dev_priv->do_boxes)
1356145132Sanholt		radeon_cp_performance_boxes(dev_priv);
135795584Sanholt
135895584Sanholt	/* Wait for the 3D stream to idle before dispatching the bitblt.
135995584Sanholt	 * This will prevent data corruption between the two streams.
136095584Sanholt	 */
1361145132Sanholt	BEGIN_RING(2);
136295584Sanholt
136395584Sanholt	RADEON_WAIT_UNTIL_3D_IDLE();
136495584Sanholt
136595584Sanholt	ADVANCE_RING();
136695584Sanholt
1367145132Sanholt	for (i = 0; i < nbox; i++) {
136895584Sanholt		int x = pbox[i].x1;
136995584Sanholt		int y = pbox[i].y1;
137095584Sanholt		int w = pbox[i].x2 - x;
137195584Sanholt		int h = pbox[i].y2 - y;
137295584Sanholt
1373182080Srnoland		DRM_DEBUG("%d,%d-%d,%d\n", x, y, w, h);
137495584Sanholt
1375182080Srnoland		BEGIN_RING(9);
137695584Sanholt
1377182080Srnoland		OUT_RING(CP_PACKET0(RADEON_DP_GUI_MASTER_CNTL, 0));
1378145132Sanholt		OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
1379145132Sanholt			 RADEON_GMC_DST_PITCH_OFFSET_CNTL |
1380145132Sanholt			 RADEON_GMC_BRUSH_NONE |
1381145132Sanholt			 (dev_priv->color_fmt << 8) |
1382145132Sanholt			 RADEON_GMC_SRC_DATATYPE_COLOR |
1383145132Sanholt			 RADEON_ROP3_S |
1384145132Sanholt			 RADEON_DP_SRC_SOURCE_MEMORY |
1385145132Sanholt			 RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
1386145132Sanholt
1387112015Sanholt		/* Make this work even if front & back are flipped:
1388112015Sanholt		 */
1389182080Srnoland		OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1));
1390189499Srnoland		if (sarea_priv->pfCurrentPage == 0) {
1391145132Sanholt			OUT_RING(dev_priv->back_pitch_offset);
1392145132Sanholt			OUT_RING(dev_priv->front_pitch_offset);
1393145132Sanholt		} else {
1394145132Sanholt			OUT_RING(dev_priv->front_pitch_offset);
1395145132Sanholt			OUT_RING(dev_priv->back_pitch_offset);
1396112015Sanholt		}
139795584Sanholt
1398182080Srnoland		OUT_RING(CP_PACKET0(RADEON_SRC_X_Y, 2));
1399145132Sanholt		OUT_RING((x << 16) | y);
1400145132Sanholt		OUT_RING((x << 16) | y);
1401145132Sanholt		OUT_RING((w << 16) | h);
140295584Sanholt
140395584Sanholt		ADVANCE_RING();
140495584Sanholt	}
140595584Sanholt
140695584Sanholt	/* Increment the frame counter.  The client-side 3D driver must
140795584Sanholt	 * throttle the framerate by waiting for this value before
140895584Sanholt	 * performing the swapbuffer ioctl.
140995584Sanholt	 */
1410189499Srnoland	sarea_priv->last_frame++;
141195584Sanholt
1412145132Sanholt	BEGIN_RING(4);
141395584Sanholt
1414189499Srnoland	RADEON_FRAME_AGE(sarea_priv->last_frame);
141595584Sanholt	RADEON_WAIT_UNTIL_2D_IDLE();
141695584Sanholt
141795584Sanholt	ADVANCE_RING();
141895584Sanholt}
141995584Sanholt
1420189499Srnolandstatic void radeon_cp_dispatch_flip(struct drm_device *dev)
142195584Sanholt{
142295584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
1423207066Srnoland	struct drm_sarea *sarea = (struct drm_sarea *)dev_priv->sarea->virtual;
1424182080Srnoland	int offset = (dev_priv->sarea_priv->pfCurrentPage == 1)
1425145132Sanholt	    ? dev_priv->front_offset : dev_priv->back_offset;
142695584Sanholt	RING_LOCALS;
1427182080Srnoland	DRM_DEBUG("pfCurrentPage=%d\n",
1428182080Srnoland		  dev_priv->sarea_priv->pfCurrentPage);
142995584Sanholt
143095584Sanholt	/* Do some trivial performance monitoring...
143195584Sanholt	 */
1432112015Sanholt	if (dev_priv->do_boxes) {
1433112015Sanholt		dev_priv->stats.boxes |= RADEON_BOX_FLIP;
1434145132Sanholt		radeon_cp_performance_boxes(dev_priv);
1435112015Sanholt	}
143695584Sanholt
1437112015Sanholt	/* Update the frame offsets for both CRTCs
1438112015Sanholt	 */
1439145132Sanholt	BEGIN_RING(6);
144095584Sanholt
144195584Sanholt	RADEON_WAIT_UNTIL_3D_IDLE();
1442145132Sanholt	OUT_RING_REG(RADEON_CRTC_OFFSET,
1443145132Sanholt		     ((sarea->frame.y * dev_priv->front_pitch +
1444145132Sanholt		       sarea->frame.x * (dev_priv->color_fmt - 2)) & ~7)
1445145132Sanholt		     + offset);
1446145132Sanholt	OUT_RING_REG(RADEON_CRTC2_OFFSET, dev_priv->sarea_priv->crtc2_base
1447145132Sanholt		     + offset);
144895584Sanholt
144995584Sanholt	ADVANCE_RING();
145095584Sanholt
145195584Sanholt	/* Increment the frame counter.  The client-side 3D driver must
145295584Sanholt	 * throttle the framerate by waiting for this value before
145395584Sanholt	 * performing the swapbuffer ioctl.
145495584Sanholt	 */
145595584Sanholt	dev_priv->sarea_priv->last_frame++;
1456182080Srnoland	dev_priv->sarea_priv->pfCurrentPage =
1457182080Srnoland		1 - dev_priv->sarea_priv->pfCurrentPage;
145895584Sanholt
1459145132Sanholt	BEGIN_RING(2);
146095584Sanholt
1461145132Sanholt	RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame);
146295584Sanholt
146395584Sanholt	ADVANCE_RING();
146495584Sanholt}
146595584Sanholt
1466145132Sanholtstatic int bad_prim_vertex_nr(int primitive, int nr)
1467112015Sanholt{
1468112015Sanholt	switch (primitive & RADEON_PRIM_TYPE_MASK) {
1469112015Sanholt	case RADEON_PRIM_TYPE_NONE:
1470112015Sanholt	case RADEON_PRIM_TYPE_POINT:
1471112015Sanholt		return nr < 1;
1472112015Sanholt	case RADEON_PRIM_TYPE_LINE:
1473112015Sanholt		return (nr & 1) || nr == 0;
1474112015Sanholt	case RADEON_PRIM_TYPE_LINE_STRIP:
1475112015Sanholt		return nr < 2;
1476112015Sanholt	case RADEON_PRIM_TYPE_TRI_LIST:
1477112015Sanholt	case RADEON_PRIM_TYPE_3VRT_POINT_LIST:
1478112015Sanholt	case RADEON_PRIM_TYPE_3VRT_LINE_LIST:
1479112015Sanholt	case RADEON_PRIM_TYPE_RECT_LIST:
1480112015Sanholt		return nr % 3 || nr == 0;
1481112015Sanholt	case RADEON_PRIM_TYPE_TRI_FAN:
1482112015Sanholt	case RADEON_PRIM_TYPE_TRI_STRIP:
1483112015Sanholt		return nr < 3;
1484112015Sanholt	default:
1485112015Sanholt		return 1;
1486145132Sanholt	}
1487112015Sanholt}
1488112015Sanholt
1489112015Sanholttypedef struct {
1490112015Sanholt	unsigned int start;
1491112015Sanholt	unsigned int finish;
1492112015Sanholt	unsigned int prim;
1493112015Sanholt	unsigned int numverts;
1494145132Sanholt	unsigned int offset;
1495145132Sanholt	unsigned int vc_format;
1496112015Sanholt} drm_radeon_tcl_prim_t;
1497112015Sanholt
1498182080Srnolandstatic void radeon_cp_dispatch_vertex(struct drm_device * dev,
1499182080Srnoland				      struct drm_buf * buf,
1500145132Sanholt				      drm_radeon_tcl_prim_t * prim)
150195584Sanholt{
150295584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
1503119098Sanholt	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
1504119895Sanholt	int offset = dev_priv->gart_buffers_offset + buf->offset + prim->start;
1505112015Sanholt	int numverts = (int)prim->numverts;
1506119098Sanholt	int nbox = sarea_priv->nbox;
150795584Sanholt	int i = 0;
150895584Sanholt	RING_LOCALS;
150995584Sanholt
1510112015Sanholt	DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d %d verts\n",
1511112015Sanholt		  prim->prim,
1512145132Sanholt		  prim->vc_format, prim->start, prim->finish, prim->numverts);
151395584Sanholt
1514145132Sanholt	if (bad_prim_vertex_nr(prim->prim, prim->numverts)) {
1515145132Sanholt		DRM_ERROR("bad prim %x numverts %d\n",
1516145132Sanholt			  prim->prim, prim->numverts);
1517112015Sanholt		return;
1518112015Sanholt	}
151995584Sanholt
1520112015Sanholt	do {
1521112015Sanholt		/* Emit the next cliprect */
1522145132Sanholt		if (i < nbox) {
1523145132Sanholt			radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
152495584Sanholt		}
152595584Sanholt
1526112015Sanholt		/* Emit the vertex buffer rendering commands */
1527145132Sanholt		BEGIN_RING(5);
152895584Sanholt
1529145132Sanholt		OUT_RING(CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, 3));
1530145132Sanholt		OUT_RING(offset);
1531145132Sanholt		OUT_RING(numverts);
1532145132Sanholt		OUT_RING(prim->vc_format);
1533145132Sanholt		OUT_RING(prim->prim | RADEON_PRIM_WALK_LIST |
1534145132Sanholt			 RADEON_COLOR_ORDER_RGBA |
1535145132Sanholt			 RADEON_VTX_FMT_RADEON_MODE |
1536145132Sanholt			 (numverts << RADEON_NUM_VERTICES_SHIFT));
153795584Sanholt
1538112015Sanholt		ADVANCE_RING();
153995584Sanholt
1540112015Sanholt		i++;
1541145132Sanholt	} while (i < nbox);
1542112015Sanholt}
154395584Sanholt
1544196470Srnolandvoid radeon_cp_discard_buffer(struct drm_device *dev, struct drm_buf *buf)
1545112015Sanholt{
1546112015Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
1547112015Sanholt	drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
1548112015Sanholt	RING_LOCALS;
154995584Sanholt
1550112015Sanholt	buf_priv->age = ++dev_priv->sarea_priv->last_dispatch;
155195584Sanholt
1552112015Sanholt	/* Emit the vertex buffer age */
1553189499Srnoland	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
1554189499Srnoland		BEGIN_RING(3);
1555189499Srnoland		R600_DISPATCH_AGE(buf_priv->age);
1556189499Srnoland		ADVANCE_RING();
1557189499Srnoland	} else {
1558189499Srnoland		BEGIN_RING(2);
1559189499Srnoland		RADEON_DISPATCH_AGE(buf_priv->age);
1560189499Srnoland		ADVANCE_RING();
1561189499Srnoland	}
156295584Sanholt
1563112015Sanholt	buf->pending = 1;
1564112015Sanholt	buf->used = 0;
156595584Sanholt}
156695584Sanholt
1567182080Srnolandstatic void radeon_cp_dispatch_indirect(struct drm_device * dev,
1568182080Srnoland					struct drm_buf * buf, int start, int end)
156995584Sanholt{
157095584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
157195584Sanholt	RING_LOCALS;
1572182080Srnoland	DRM_DEBUG("buf=%d s=0x%x e=0x%x\n", buf->idx, start, end);
157395584Sanholt
1574145132Sanholt	if (start != end) {
1575119895Sanholt		int offset = (dev_priv->gart_buffers_offset
157695584Sanholt			      + buf->offset + start);
157795584Sanholt		int dwords = (end - start + 3) / sizeof(u32);
157895584Sanholt
157995584Sanholt		/* Indirect buffer data must be an even number of
158095584Sanholt		 * dwords, so if we've been given an odd number we must
158195584Sanholt		 * pad the data with a Type-2 CP packet.
158295584Sanholt		 */
1583145132Sanholt		if (dwords & 1) {
158495584Sanholt			u32 *data = (u32 *)
1585207066Srnoland			    ((char *)dev->agp_buffer_map->virtual
1586145132Sanholt			     + buf->offset + start);
158795584Sanholt			data[dwords++] = RADEON_CP_PACKET2;
158895584Sanholt		}
158995584Sanholt
159095584Sanholt		/* Fire off the indirect buffer */
1591145132Sanholt		BEGIN_RING(3);
159295584Sanholt
1593145132Sanholt		OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1));
1594145132Sanholt		OUT_RING(offset);
1595145132Sanholt		OUT_RING(dwords);
159695584Sanholt
159795584Sanholt		ADVANCE_RING();
159895584Sanholt	}
1599112015Sanholt}
160095584Sanholt
1601189499Srnolandstatic void radeon_cp_dispatch_indices(struct drm_device *dev,
1602182080Srnoland				       struct drm_buf * elt_buf,
1603145132Sanholt				       drm_radeon_tcl_prim_t * prim)
160495584Sanholt{
160595584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
1606119098Sanholt	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
1607119895Sanholt	int offset = dev_priv->gart_buffers_offset + prim->offset;
160895584Sanholt	u32 *data;
160995584Sanholt	int dwords;
161095584Sanholt	int i = 0;
1611112015Sanholt	int start = prim->start + RADEON_INDEX_PRIM_OFFSET;
1612112015Sanholt	int count = (prim->finish - start) / sizeof(u16);
1613119098Sanholt	int nbox = sarea_priv->nbox;
161495584Sanholt
1615112015Sanholt	DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d offset: %x nr %d\n",
1616112015Sanholt		  prim->prim,
1617112015Sanholt		  prim->vc_format,
1618145132Sanholt		  prim->start, prim->finish, prim->offset, prim->numverts);
161995584Sanholt
1620145132Sanholt	if (bad_prim_vertex_nr(prim->prim, count)) {
1621145132Sanholt		DRM_ERROR("bad prim %x count %d\n", prim->prim, count);
1622112015Sanholt		return;
1623112015Sanholt	}
162495584Sanholt
1625145132Sanholt	if (start >= prim->finish || (prim->start & 0x7)) {
1626145132Sanholt		DRM_ERROR("buffer prim %d\n", prim->prim);
1627112015Sanholt		return;
1628112015Sanholt	}
162995584Sanholt
1630112015Sanholt	dwords = (prim->finish - prim->start + 3) / sizeof(u32);
163195584Sanholt
1632207066Srnoland	data = (u32 *) ((char *)dev->agp_buffer_map->virtual +
1633145132Sanholt			elt_buf->offset + prim->start);
163495584Sanholt
1635145132Sanholt	data[0] = CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, dwords - 2);
1636112015Sanholt	data[1] = offset;
1637112015Sanholt	data[2] = prim->numverts;
1638112015Sanholt	data[3] = prim->vc_format;
1639112015Sanholt	data[4] = (prim->prim |
1640112015Sanholt		   RADEON_PRIM_WALK_IND |
1641112015Sanholt		   RADEON_COLOR_ORDER_RGBA |
1642112015Sanholt		   RADEON_VTX_FMT_RADEON_MODE |
1643145132Sanholt		   (count << RADEON_NUM_VERTICES_SHIFT));
164495584Sanholt
1645112015Sanholt	do {
1646145132Sanholt		if (i < nbox)
1647145132Sanholt			radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
164895584Sanholt
1649145132Sanholt		radeon_cp_dispatch_indirect(dev, elt_buf,
1650145132Sanholt					    prim->start, prim->finish);
165195584Sanholt
1652112015Sanholt		i++;
1653145132Sanholt	} while (i < nbox);
165495584Sanholt
165595584Sanholt}
165695584Sanholt
1657148211Sanholt#define RADEON_MAX_TEXTURE_SIZE RADEON_BUFFER_SIZE
165895584Sanholt
1659182080Srnolandstatic int radeon_cp_dispatch_texture(struct drm_device * dev,
1660182080Srnoland				      struct drm_file *file_priv,
1661145132Sanholt				      drm_radeon_texture_t * tex,
1662145132Sanholt				      drm_radeon_tex_image_t * image)
166395584Sanholt{
166495584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
1665182080Srnoland	struct drm_buf *buf;
166695584Sanholt	u32 format;
166795584Sanholt	u32 *buffer;
1668145132Sanholt	const u8 __user *data;
1669148211Sanholt	int size, dwords, tex_width, blit_width, spitch;
1670112015Sanholt	u32 height;
1671112015Sanholt	int i;
1672145132Sanholt	u32 texpitch, microtile;
1673182080Srnoland	u32 offset, byte_offset;
167495584Sanholt	RING_LOCALS;
167595584Sanholt
1676182080Srnoland	if (radeon_check_and_fixup_offset(dev_priv, file_priv, &tex->offset)) {
1677145132Sanholt		DRM_ERROR("Invalid destination offset\n");
1678182080Srnoland		return -EINVAL;
1679122580Sanholt	}
1680122580Sanholt
1681112015Sanholt	dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD;
1682112015Sanholt
1683112015Sanholt	/* Flush the pixel cache.  This ensures no pixel data gets mixed
1684112015Sanholt	 * up with the texture data from the host data blit, otherwise
1685112015Sanholt	 * part of the texture image may be corrupted.
168695584Sanholt	 */
1687145132Sanholt	BEGIN_RING(4);
1688112015Sanholt	RADEON_FLUSH_CACHE();
1689112015Sanholt	RADEON_WAIT_UNTIL_IDLE();
1690112015Sanholt	ADVANCE_RING();
169195584Sanholt
169295584Sanholt	/* The compiler won't optimize away a division by a variable,
169395584Sanholt	 * even if the only legal values are powers of two.  Thus, we'll
169495584Sanholt	 * use a shift instead.
169595584Sanholt	 */
1696145132Sanholt	switch (tex->format) {
169795584Sanholt	case RADEON_TXFORMAT_ARGB8888:
169895584Sanholt	case RADEON_TXFORMAT_RGBA8888:
169995584Sanholt		format = RADEON_COLOR_FORMAT_ARGB8888;
170095584Sanholt		tex_width = tex->width * 4;
170195584Sanholt		blit_width = image->width * 4;
170295584Sanholt		break;
170395584Sanholt	case RADEON_TXFORMAT_AI88:
170495584Sanholt	case RADEON_TXFORMAT_ARGB1555:
170595584Sanholt	case RADEON_TXFORMAT_RGB565:
170695584Sanholt	case RADEON_TXFORMAT_ARGB4444:
1707112015Sanholt	case RADEON_TXFORMAT_VYUY422:
1708112015Sanholt	case RADEON_TXFORMAT_YVYU422:
170995584Sanholt		format = RADEON_COLOR_FORMAT_RGB565;
171095584Sanholt		tex_width = tex->width * 2;
171195584Sanholt		blit_width = image->width * 2;
171295584Sanholt		break;
171395584Sanholt	case RADEON_TXFORMAT_I8:
171495584Sanholt	case RADEON_TXFORMAT_RGB332:
171595584Sanholt		format = RADEON_COLOR_FORMAT_CI8;
171695584Sanholt		tex_width = tex->width * 1;
171795584Sanholt		blit_width = image->width * 1;
171895584Sanholt		break;
171995584Sanholt	default:
1720145132Sanholt		DRM_ERROR("invalid texture format %d\n", tex->format);
1721182080Srnoland		return -EINVAL;
172295584Sanholt	}
1723148211Sanholt	spitch = blit_width >> 6;
1724148211Sanholt	if (spitch == 0 && image->height > 1)
1725182080Srnoland		return -EINVAL;
1726148211Sanholt
1727145132Sanholt	texpitch = tex->pitch;
1728145132Sanholt	if ((texpitch << 22) & RADEON_DST_TILE_MICRO) {
1729145132Sanholt		microtile = 1;
1730145132Sanholt		if (tex_width < 64) {
1731145132Sanholt			texpitch &= ~(RADEON_DST_TILE_MICRO >> 22);
1732145132Sanholt			/* we got tiled coordinates, untile them */
1733145132Sanholt			image->x *= 2;
1734145132Sanholt		}
1735157617Sanholt	} else
1736157617Sanholt		microtile = 0;
173795584Sanholt
1738182080Srnoland	/* this might fail for zero-sized uploads - are those illegal? */
1739182080Srnoland	if (!radeon_check_offset(dev_priv, tex->offset + image->height *
1740182080Srnoland				blit_width - 1)) {
1741182080Srnoland		DRM_ERROR("Invalid final destination offset\n");
1742182080Srnoland		return -EINVAL;
1743182080Srnoland	}
1744182080Srnoland
1745145132Sanholt	DRM_DEBUG("tex=%dx%d blit=%d\n", tex_width, tex->height, blit_width);
174695584Sanholt
1747112015Sanholt	do {
1748228979Sdim		DRM_DEBUG("tex: ofs=0x%x p=%d f=%d x=%d y=%d w=%d h=%d\n",
1749145132Sanholt			  tex->offset >> 10, tex->pitch, tex->format,
1750145132Sanholt			  image->x, image->y, image->width, image->height);
175195584Sanholt
1752112015Sanholt		/* Make a copy of some parameters in case we have to
1753112015Sanholt		 * update them for a multi-pass texture blit.
1754112015Sanholt		 */
1755112015Sanholt		height = image->height;
1756145132Sanholt		data = (const u8 __user *)image->data;
1757145132Sanholt
175895584Sanholt		size = height * blit_width;
175995584Sanholt
1760145132Sanholt		if (size > RADEON_MAX_TEXTURE_SIZE) {
1761112015Sanholt			height = RADEON_MAX_TEXTURE_SIZE / blit_width;
1762112015Sanholt			size = height * blit_width;
1763145132Sanholt		} else if (size < 4 && size > 0) {
1764112015Sanholt			size = 4;
1765145132Sanholt		} else if (size == 0) {
1766112015Sanholt			return 0;
1767112015Sanholt		}
176895584Sanholt
1769145132Sanholt		buf = radeon_freelist_get(dev);
1770145132Sanholt		if (0 && !buf) {
1771145132Sanholt			radeon_do_cp_idle(dev_priv);
1772145132Sanholt			buf = radeon_freelist_get(dev);
177395584Sanholt		}
1774145132Sanholt		if (!buf) {
1775182080Srnoland			DRM_DEBUG("EAGAIN\n");
1776145132Sanholt			if (DRM_COPY_TO_USER(tex->image, image, sizeof(*image)))
1777182080Srnoland				return -EFAULT;
1778182080Srnoland			return -EAGAIN;
1779112015Sanholt		}
178095584Sanholt
1781112015Sanholt		/* Dispatch the indirect buffer.
1782112015Sanholt		 */
1783145132Sanholt		buffer =
1784207066Srnoland		    (u32 *) ((char *)dev->agp_buffer_map->virtual + buf->offset);
1785112015Sanholt		dwords = size / 4;
1786145132Sanholt
1787157617Sanholt#define RADEON_COPY_MT(_buf, _data, _width) \
1788157617Sanholt	do { \
1789157617Sanholt		if (DRM_COPY_FROM_USER(_buf, _data, (_width))) {\
1790157617Sanholt			DRM_ERROR("EFAULT on pad, %d bytes\n", (_width)); \
1791182080Srnoland			return -EFAULT; \
1792157617Sanholt		} \
1793157617Sanholt	} while(0)
1794157617Sanholt
1795145132Sanholt		if (microtile) {
1796145132Sanholt			/* texture micro tiling in use, minimum texture width is thus 16 bytes.
1797145132Sanholt			   however, we cannot use blitter directly for texture width < 64 bytes,
1798145132Sanholt			   since minimum tex pitch is 64 bytes and we need this to match
1799145132Sanholt			   the texture width, otherwise the blitter will tile it wrong.
1800145132Sanholt			   Thus, tiling manually in this case. Additionally, need to special
1801145132Sanholt			   case tex height = 1, since our actual image will have height 2
1802145132Sanholt			   and we need to ensure we don't read beyond the texture size
1803145132Sanholt			   from user space. */
1804145132Sanholt			if (tex->height == 1) {
1805145132Sanholt				if (tex_width >= 64 || tex_width <= 16) {
1806157617Sanholt					RADEON_COPY_MT(buffer, data,
1807157617Sanholt						(int)(tex_width * sizeof(u32)));
1808145132Sanholt				} else if (tex_width == 32) {
1809157617Sanholt					RADEON_COPY_MT(buffer, data, 16);
1810157617Sanholt					RADEON_COPY_MT(buffer + 8,
1811157617Sanholt						       data + 16, 16);
1812145132Sanholt				}
1813145132Sanholt			} else if (tex_width >= 64 || tex_width == 16) {
1814157617Sanholt				RADEON_COPY_MT(buffer, data,
1815157617Sanholt					       (int)(dwords * sizeof(u32)));
1816145132Sanholt			} else if (tex_width < 16) {
1817145132Sanholt				for (i = 0; i < tex->height; i++) {
1818157617Sanholt					RADEON_COPY_MT(buffer, data, tex_width);
1819145132Sanholt					buffer += 4;
1820145132Sanholt					data += tex_width;
1821145132Sanholt				}
1822145132Sanholt			} else if (tex_width == 32) {
1823157617Sanholt				/* TODO: make sure this works when not fitting in one buffer
1824157617Sanholt				   (i.e. 32bytes x 2048...) */
1825145132Sanholt				for (i = 0; i < tex->height; i += 2) {
1826157617Sanholt					RADEON_COPY_MT(buffer, data, 16);
1827145132Sanholt					data += 16;
1828157617Sanholt					RADEON_COPY_MT(buffer + 8, data, 16);
1829145132Sanholt					data += 16;
1830157617Sanholt					RADEON_COPY_MT(buffer + 4, data, 16);
1831145132Sanholt					data += 16;
1832157617Sanholt					RADEON_COPY_MT(buffer + 12, data, 16);
1833145132Sanholt					data += 16;
1834145132Sanholt					buffer += 16;
1835145132Sanholt				}
183695584Sanholt			}
1837157617Sanholt		} else {
1838145132Sanholt			if (tex_width >= 32) {
1839145132Sanholt				/* Texture image width is larger than the minimum, so we
1840145132Sanholt				 * can upload it directly.
1841145132Sanholt				 */
1842157617Sanholt				RADEON_COPY_MT(buffer, data,
1843157617Sanholt					       (int)(dwords * sizeof(u32)));
1844145132Sanholt			} else {
1845145132Sanholt				/* Texture image width is less than the minimum, so we
1846145132Sanholt				 * need to pad out each image scanline to the minimum
1847145132Sanholt				 * width.
1848145132Sanholt				 */
1849145132Sanholt				for (i = 0; i < tex->height; i++) {
1850157617Sanholt					RADEON_COPY_MT(buffer, data, tex_width);
1851145132Sanholt					buffer += 8;
1852145132Sanholt					data += tex_width;
1853145132Sanholt				}
1854112015Sanholt			}
185595584Sanholt		}
185695584Sanholt
1857157617Sanholt#undef RADEON_COPY_MT
1858182080Srnoland		byte_offset = (image->y & ~2047) * blit_width;
1859182080Srnoland		buf->file_priv = file_priv;
1860148211Sanholt		buf->used = size;
1861148211Sanholt		offset = dev_priv->gart_buffers_offset + buf->offset;
1862148211Sanholt		BEGIN_RING(9);
1863148211Sanholt		OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
1864148211Sanholt		OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
1865148211Sanholt			 RADEON_GMC_DST_PITCH_OFFSET_CNTL |
1866148211Sanholt			 RADEON_GMC_BRUSH_NONE |
1867148211Sanholt			 (format << 8) |
1868148211Sanholt			 RADEON_GMC_SRC_DATATYPE_COLOR |
1869148211Sanholt			 RADEON_ROP3_S |
1870148211Sanholt			 RADEON_DP_SRC_SOURCE_MEMORY |
1871157617Sanholt			 RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
1872148211Sanholt		OUT_RING((spitch << 22) | (offset >> 10));
1873182080Srnoland		OUT_RING((texpitch << 22) | ((tex->offset >> 10) + (byte_offset >> 10)));
1874148211Sanholt		OUT_RING(0);
1875182080Srnoland		OUT_RING((image->x << 16) | (image->y % 2048));
1876148211Sanholt		OUT_RING((image->width << 16) | height);
1877148211Sanholt		RADEON_WAIT_UNTIL_2D_IDLE();
1878148211Sanholt		ADVANCE_RING();
1879182080Srnoland		COMMIT_RING();
1880148211Sanholt
1881145132Sanholt		radeon_cp_discard_buffer(dev, buf);
188295584Sanholt
1883112015Sanholt		/* Update the input parameters for next time */
1884112015Sanholt		image->y += height;
1885112015Sanholt		image->height -= height;
1886145132Sanholt		image->data = (const u8 __user *)image->data + size;
1887112015Sanholt	} while (image->height > 0);
188895584Sanholt
188995584Sanholt	/* Flush the pixel cache after the blit completes.  This ensures
189095584Sanholt	 * the texture data is written out to memory before rendering
189195584Sanholt	 * continues.
189295584Sanholt	 */
1893145132Sanholt	BEGIN_RING(4);
189495584Sanholt	RADEON_FLUSH_CACHE();
189595584Sanholt	RADEON_WAIT_UNTIL_2D_IDLE();
189695584Sanholt	ADVANCE_RING();
1897182080Srnoland	COMMIT_RING();
1898182080Srnoland
1899112015Sanholt	return 0;
190095584Sanholt}
190195584Sanholt
1902182080Srnolandstatic void radeon_cp_dispatch_stipple(struct drm_device * dev, u32 * stipple)
190395584Sanholt{
190495584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
190595584Sanholt	int i;
190695584Sanholt	RING_LOCALS;
1907145132Sanholt	DRM_DEBUG("\n");
190895584Sanholt
1909145132Sanholt	BEGIN_RING(35);
191095584Sanholt
1911145132Sanholt	OUT_RING(CP_PACKET0(RADEON_RE_STIPPLE_ADDR, 0));
1912145132Sanholt	OUT_RING(0x00000000);
191395584Sanholt
1914145132Sanholt	OUT_RING(CP_PACKET0_TABLE(RADEON_RE_STIPPLE_DATA, 31));
1915145132Sanholt	for (i = 0; i < 32; i++) {
1916145132Sanholt		OUT_RING(stipple[i]);
191795584Sanholt	}
191895584Sanholt
191995584Sanholt	ADVANCE_RING();
192095584Sanholt}
192195584Sanholt
1922157617Sanholtstatic void radeon_apply_surface_regs(int surf_index,
1923157617Sanholt				      drm_radeon_private_t *dev_priv)
1924145132Sanholt{
1925145132Sanholt	if (!dev_priv->mmio)
1926145132Sanholt		return;
192795584Sanholt
1928145132Sanholt	radeon_do_cp_idle(dev_priv);
1929145132Sanholt
1930157617Sanholt	RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * surf_index,
1931157617Sanholt		     dev_priv->surfaces[surf_index].flags);
1932157617Sanholt	RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND + 16 * surf_index,
1933157617Sanholt		     dev_priv->surfaces[surf_index].lower);
1934157617Sanholt	RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND + 16 * surf_index,
1935157617Sanholt		     dev_priv->surfaces[surf_index].upper);
1936145132Sanholt}
1937145132Sanholt
1938145132Sanholt/* Allocates a virtual surface
1939157617Sanholt * doesn't always allocate a real surface, will stretch an existing
1940145132Sanholt * surface when possible.
1941145132Sanholt *
1942145132Sanholt * Note that refcount can be at most 2, since during a free refcount=3
1943145132Sanholt * might mean we have to allocate a new surface which might not always
1944145132Sanholt * be available.
1945157617Sanholt * For example : we allocate three contigous surfaces ABC. If B is
1946145132Sanholt * freed, we suddenly need two surfaces to store A and C, which might
1947145132Sanholt * not always be available.
1948145132Sanholt */
1949157617Sanholtstatic int alloc_surface(drm_radeon_surface_alloc_t *new,
1950182080Srnoland			 drm_radeon_private_t *dev_priv,
1951182080Srnoland			 struct drm_file *file_priv)
1952145132Sanholt{
1953145132Sanholt	struct radeon_virt_surface *s;
1954145132Sanholt	int i;
1955145132Sanholt	int virt_surface_index;
1956145132Sanholt	uint32_t new_upper, new_lower;
1957145132Sanholt
1958145132Sanholt	new_lower = new->address;
1959145132Sanholt	new_upper = new_lower + new->size - 1;
1960145132Sanholt
1961145132Sanholt	/* sanity check */
1962145132Sanholt	if ((new_lower >= new_upper) || (new->flags == 0) || (new->size == 0) ||
1963157617Sanholt	    ((new_upper & RADEON_SURF_ADDRESS_FIXED_MASK) !=
1964157617Sanholt	     RADEON_SURF_ADDRESS_FIXED_MASK)
1965157617Sanholt	    || ((new_lower & RADEON_SURF_ADDRESS_FIXED_MASK) != 0))
1966145132Sanholt		return -1;
1967145132Sanholt
1968145132Sanholt	/* make sure there is no overlap with existing surfaces */
1969145132Sanholt	for (i = 0; i < RADEON_MAX_SURFACES; i++) {
1970145132Sanholt		if ((dev_priv->surfaces[i].refcount != 0) &&
1971157617Sanholt		    (((new_lower >= dev_priv->surfaces[i].lower) &&
1972157617Sanholt		      (new_lower < dev_priv->surfaces[i].upper)) ||
1973157617Sanholt		     ((new_lower < dev_priv->surfaces[i].lower) &&
1974157617Sanholt		      (new_upper > dev_priv->surfaces[i].lower)))) {
1975157617Sanholt			return -1;
1976157617Sanholt		}
1977145132Sanholt	}
1978145132Sanholt
1979145132Sanholt	/* find a virtual surface */
1980157617Sanholt	for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++)
1981182080Srnoland		if (dev_priv->virt_surfaces[i].file_priv == 0)
1982145132Sanholt			break;
1983157617Sanholt	if (i == 2 * RADEON_MAX_SURFACES) {
1984157617Sanholt		return -1;
1985157617Sanholt	}
1986145132Sanholt	virt_surface_index = i;
1987145132Sanholt
1988145132Sanholt	/* try to reuse an existing surface */
1989145132Sanholt	for (i = 0; i < RADEON_MAX_SURFACES; i++) {
1990145132Sanholt		/* extend before */
1991145132Sanholt		if ((dev_priv->surfaces[i].refcount == 1) &&
1992157617Sanholt		    (new->flags == dev_priv->surfaces[i].flags) &&
1993157617Sanholt		    (new_upper + 1 == dev_priv->surfaces[i].lower)) {
1994145132Sanholt			s = &(dev_priv->virt_surfaces[virt_surface_index]);
1995145132Sanholt			s->surface_index = i;
1996145132Sanholt			s->lower = new_lower;
1997145132Sanholt			s->upper = new_upper;
1998145132Sanholt			s->flags = new->flags;
1999182080Srnoland			s->file_priv = file_priv;
2000145132Sanholt			dev_priv->surfaces[i].refcount++;
2001145132Sanholt			dev_priv->surfaces[i].lower = s->lower;
2002145132Sanholt			radeon_apply_surface_regs(s->surface_index, dev_priv);
2003145132Sanholt			return virt_surface_index;
2004145132Sanholt		}
2005145132Sanholt
2006145132Sanholt		/* extend after */
2007145132Sanholt		if ((dev_priv->surfaces[i].refcount == 1) &&
2008157617Sanholt		    (new->flags == dev_priv->surfaces[i].flags) &&
2009157617Sanholt		    (new_lower == dev_priv->surfaces[i].upper + 1)) {
2010145132Sanholt			s = &(dev_priv->virt_surfaces[virt_surface_index]);
2011145132Sanholt			s->surface_index = i;
2012145132Sanholt			s->lower = new_lower;
2013145132Sanholt			s->upper = new_upper;
2014145132Sanholt			s->flags = new->flags;
2015182080Srnoland			s->file_priv = file_priv;
2016145132Sanholt			dev_priv->surfaces[i].refcount++;
2017145132Sanholt			dev_priv->surfaces[i].upper = s->upper;
2018145132Sanholt			radeon_apply_surface_regs(s->surface_index, dev_priv);
2019145132Sanholt			return virt_surface_index;
2020145132Sanholt		}
2021145132Sanholt	}
2022145132Sanholt
2023145132Sanholt	/* okay, we need a new one */
2024145132Sanholt	for (i = 0; i < RADEON_MAX_SURFACES; i++) {
2025145132Sanholt		if (dev_priv->surfaces[i].refcount == 0) {
2026145132Sanholt			s = &(dev_priv->virt_surfaces[virt_surface_index]);
2027145132Sanholt			s->surface_index = i;
2028145132Sanholt			s->lower = new_lower;
2029145132Sanholt			s->upper = new_upper;
2030145132Sanholt			s->flags = new->flags;
2031182080Srnoland			s->file_priv = file_priv;
2032145132Sanholt			dev_priv->surfaces[i].refcount = 1;
2033145132Sanholt			dev_priv->surfaces[i].lower = s->lower;
2034145132Sanholt			dev_priv->surfaces[i].upper = s->upper;
2035145132Sanholt			dev_priv->surfaces[i].flags = s->flags;
2036145132Sanholt			radeon_apply_surface_regs(s->surface_index, dev_priv);
2037145132Sanholt			return virt_surface_index;
2038145132Sanholt		}
2039145132Sanholt	}
2040145132Sanholt
2041145132Sanholt	/* we didn't find anything */
2042145132Sanholt	return -1;
2043145132Sanholt}
2044145132Sanholt
2045182080Srnolandstatic int free_surface(struct drm_file *file_priv,
2046182080Srnoland			drm_radeon_private_t * dev_priv,
2047157617Sanholt			int lower)
2048145132Sanholt{
2049145132Sanholt	struct radeon_virt_surface *s;
2050145132Sanholt	int i;
2051145132Sanholt	/* find the virtual surface */
2052157617Sanholt	for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
2053145132Sanholt		s = &(dev_priv->virt_surfaces[i]);
2054182080Srnoland		if (s->file_priv) {
2055182080Srnoland			if ((lower == s->lower) && (file_priv == s->file_priv))
2056182080Srnoland			{
2057157617Sanholt				if (dev_priv->surfaces[s->surface_index].
2058157617Sanholt				    lower == s->lower)
2059157617Sanholt					dev_priv->surfaces[s->surface_index].
2060157617Sanholt					    lower = s->upper;
2061145132Sanholt
2062157617Sanholt				if (dev_priv->surfaces[s->surface_index].
2063157617Sanholt				    upper == s->upper)
2064157617Sanholt					dev_priv->surfaces[s->surface_index].
2065157617Sanholt					    upper = s->lower;
2066145132Sanholt
2067145132Sanholt				dev_priv->surfaces[s->surface_index].refcount--;
2068157617Sanholt				if (dev_priv->surfaces[s->surface_index].
2069157617Sanholt				    refcount == 0)
2070157617Sanholt					dev_priv->surfaces[s->surface_index].
2071157617Sanholt					    flags = 0;
2072182080Srnoland				s->file_priv = NULL;
2073157617Sanholt				radeon_apply_surface_regs(s->surface_index,
2074157617Sanholt							  dev_priv);
2075145132Sanholt				return 0;
2076145132Sanholt			}
2077145132Sanholt		}
2078145132Sanholt	}
2079145132Sanholt	return 1;
2080145132Sanholt}
2081145132Sanholt
2082182080Srnolandstatic void radeon_surfaces_release(struct drm_file *file_priv,
2083157617Sanholt				    drm_radeon_private_t * dev_priv)
2084145132Sanholt{
2085145132Sanholt	int i;
2086157617Sanholt	for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
2087182080Srnoland		if (dev_priv->virt_surfaces[i].file_priv == file_priv)
2088182080Srnoland			free_surface(file_priv, dev_priv,
2089157617Sanholt				     dev_priv->virt_surfaces[i].lower);
2090145132Sanholt	}
2091145132Sanholt}
2092145132Sanholt
209395584Sanholt/* ================================================================
209495584Sanholt * IOCTL functions
209595584Sanholt */
2096182080Srnolandstatic int radeon_surface_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv)
209795584Sanholt{
209895584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
2099182080Srnoland	drm_radeon_surface_alloc_t *alloc = data;
2100145132Sanholt
2101182080Srnoland	if (alloc_surface(alloc, dev_priv, file_priv) == -1)
2102182080Srnoland		return -EINVAL;
2103145132Sanholt	else
2104145132Sanholt		return 0;
2105145132Sanholt}
2106145132Sanholt
2107182080Srnolandstatic int radeon_surface_free(struct drm_device *dev, void *data, struct drm_file *file_priv)
2108145132Sanholt{
2109145132Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
2110182080Srnoland	drm_radeon_surface_free_t *memfree = data;
2111145132Sanholt
2112182080Srnoland	if (free_surface(file_priv, dev_priv, memfree->address))
2113182080Srnoland		return -EINVAL;
2114145132Sanholt	else
2115145132Sanholt		return 0;
2116145132Sanholt}
2117145132Sanholt
2118182080Srnolandstatic int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file *file_priv)
2119145132Sanholt{
2120145132Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
212195584Sanholt	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2122182080Srnoland	drm_radeon_clear_t *clear = data;
212395584Sanholt	drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
2124145132Sanholt	DRM_DEBUG("\n");
212595584Sanholt
2126182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
212795584Sanholt
2128145132Sanholt	RING_SPACE_TEST_WITH_RETURN(dev_priv);
212995584Sanholt
2130145132Sanholt	if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
213195584Sanholt		sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
213295584Sanholt
2133182080Srnoland	if (DRM_COPY_FROM_USER(&depth_boxes, clear->depth_boxes,
2134145132Sanholt			       sarea_priv->nbox * sizeof(depth_boxes[0])))
2135182080Srnoland		return -EFAULT;
213695584Sanholt
2137182080Srnoland	radeon_cp_dispatch_clear(dev, clear, depth_boxes);
213895584Sanholt
2139112015Sanholt	COMMIT_RING();
214095584Sanholt	return 0;
214195584Sanholt}
214295584Sanholt
2143112015Sanholt/* Not sure why this isn't set all the time:
2144145132Sanholt */
2145189499Srnolandstatic int radeon_do_init_pageflip(struct drm_device *dev)
214695584Sanholt{
214795584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
2148112015Sanholt	RING_LOCALS;
2149112015Sanholt
2150145132Sanholt	DRM_DEBUG("\n");
2151112015Sanholt
2152145132Sanholt	BEGIN_RING(6);
2153112015Sanholt	RADEON_WAIT_UNTIL_3D_IDLE();
2154145132Sanholt	OUT_RING(CP_PACKET0(RADEON_CRTC_OFFSET_CNTL, 0));
2155145132Sanholt	OUT_RING(RADEON_READ(RADEON_CRTC_OFFSET_CNTL) |
2156145132Sanholt		 RADEON_CRTC_OFFSET_FLIP_CNTL);
2157145132Sanholt	OUT_RING(CP_PACKET0(RADEON_CRTC2_OFFSET_CNTL, 0));
2158145132Sanholt	OUT_RING(RADEON_READ(RADEON_CRTC2_OFFSET_CNTL) |
2159145132Sanholt		 RADEON_CRTC_OFFSET_FLIP_CNTL);
2160112015Sanholt	ADVANCE_RING();
2161112015Sanholt
2162112015Sanholt	dev_priv->page_flipping = 1;
2163112015Sanholt
2164182080Srnoland	if (dev_priv->sarea_priv->pfCurrentPage != 1)
2165182080Srnoland		dev_priv->sarea_priv->pfCurrentPage = 0;
2166112015Sanholt
2167112015Sanholt	return 0;
2168112015Sanholt}
2169112015Sanholt
2170112015Sanholt/* Swapping and flipping are different operations, need different ioctls.
2171145132Sanholt * They can & should be intermixed to support multiple 3d windows.
2172112015Sanholt */
2173182080Srnolandstatic int radeon_cp_flip(struct drm_device *dev, void *data, struct drm_file *file_priv)
2174112015Sanholt{
2175112015Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
2176145132Sanholt	DRM_DEBUG("\n");
2177112015Sanholt
2178182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
2179112015Sanholt
2180145132Sanholt	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2181112015Sanholt
2182145132Sanholt	if (!dev_priv->page_flipping)
2183145132Sanholt		radeon_do_init_pageflip(dev);
2184112015Sanholt
2185145132Sanholt	radeon_cp_dispatch_flip(dev);
2186145132Sanholt
2187112015Sanholt	COMMIT_RING();
2188112015Sanholt	return 0;
2189112015Sanholt}
2190112015Sanholt
2191182080Srnolandstatic int radeon_cp_swap(struct drm_device *dev, void *data, struct drm_file *file_priv)
2192112015Sanholt{
2193112015Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
219495584Sanholt	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2195189499Srnoland
2196145132Sanholt	DRM_DEBUG("\n");
219795584Sanholt
2198182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
219995584Sanholt
2200145132Sanholt	RING_SPACE_TEST_WITH_RETURN(dev_priv);
220195584Sanholt
2202145132Sanholt	if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
220395584Sanholt		sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
220495584Sanholt
2205196470Srnoland	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
2206196470Srnoland		r600_cp_dispatch_swap(dev);
2207196470Srnoland	else
2208196470Srnoland		radeon_cp_dispatch_swap(dev);
2209189499Srnoland	sarea_priv->ctx_owner = 0;
221095584Sanholt
2211112015Sanholt	COMMIT_RING();
221295584Sanholt	return 0;
221395584Sanholt}
221495584Sanholt
2215182080Srnolandstatic int radeon_cp_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv)
221695584Sanholt{
221795584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
2218157617Sanholt	drm_radeon_sarea_t *sarea_priv;
2219182080Srnoland	struct drm_device_dma *dma = dev->dma;
2220182080Srnoland	struct drm_buf *buf;
2221182080Srnoland	drm_radeon_vertex_t *vertex = data;
2222112015Sanholt	drm_radeon_tcl_prim_t prim;
222395584Sanholt
2224182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
222595584Sanholt
2226157617Sanholt	sarea_priv = dev_priv->sarea_priv;
2227157617Sanholt
2228145132Sanholt	DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n",
2229182080Srnoland		  DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard);
223095584Sanholt
2231182080Srnoland	if (vertex->idx < 0 || vertex->idx >= dma->buf_count) {
2232145132Sanholt		DRM_ERROR("buffer index %d (of %d max)\n",
2233182080Srnoland			  vertex->idx, dma->buf_count - 1);
2234182080Srnoland		return -EINVAL;
223595584Sanholt	}
2236182080Srnoland	if (vertex->prim < 0 || vertex->prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
2237182080Srnoland		DRM_ERROR("buffer prim %d\n", vertex->prim);
2238182080Srnoland		return -EINVAL;
223995584Sanholt	}
224095584Sanholt
2241145132Sanholt	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2242145132Sanholt	VB_AGE_TEST_WITH_RETURN(dev_priv);
224395584Sanholt
2244182080Srnoland	buf = dma->buflist[vertex->idx];
224595584Sanholt
2246182080Srnoland	if (buf->file_priv != file_priv) {
2247145132Sanholt		DRM_ERROR("process %d using buffer owned by %p\n",
2248182080Srnoland			  DRM_CURRENTPID, buf->file_priv);
2249182080Srnoland		return -EINVAL;
225095584Sanholt	}
2251145132Sanholt	if (buf->pending) {
2252182080Srnoland		DRM_ERROR("sending pending buffer %d\n", vertex->idx);
2253182080Srnoland		return -EINVAL;
225495584Sanholt	}
225595584Sanholt
2256112015Sanholt	/* Build up a prim_t record:
2257112015Sanholt	 */
2258182080Srnoland	if (vertex->count) {
2259182080Srnoland		buf->used = vertex->count;	/* not used? */
226095584Sanholt
2261145132Sanholt		if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
2262182080Srnoland			if (radeon_emit_state(dev_priv, file_priv,
2263145132Sanholt					      &sarea_priv->context_state,
2264145132Sanholt					      sarea_priv->tex_state,
2265145132Sanholt					      sarea_priv->dirty)) {
2266145132Sanholt				DRM_ERROR("radeon_emit_state failed\n");
2267182080Srnoland				return -EINVAL;
2268122580Sanholt			}
2269122580Sanholt
2270112015Sanholt			sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
2271112015Sanholt					       RADEON_UPLOAD_TEX1IMAGES |
2272112015Sanholt					       RADEON_UPLOAD_TEX2IMAGES |
2273112015Sanholt					       RADEON_REQUIRE_QUIESCENCE);
2274112015Sanholt		}
227595584Sanholt
2276112015Sanholt		prim.start = 0;
2277182080Srnoland		prim.finish = vertex->count;	/* unused */
2278182080Srnoland		prim.prim = vertex->prim;
2279182080Srnoland		prim.numverts = vertex->count;
2280189499Srnoland		prim.vc_format = sarea_priv->vc_format;
2281145132Sanholt
2282145132Sanholt		radeon_cp_dispatch_vertex(dev, buf, &prim);
2283112015Sanholt	}
2284112015Sanholt
2285182080Srnoland	if (vertex->discard) {
2286145132Sanholt		radeon_cp_discard_buffer(dev, buf);
2287112015Sanholt	}
2288112015Sanholt
2289112015Sanholt	COMMIT_RING();
229095584Sanholt	return 0;
229195584Sanholt}
229295584Sanholt
2293182080Srnolandstatic int radeon_cp_indices(struct drm_device *dev, void *data, struct drm_file *file_priv)
229495584Sanholt{
229595584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
2296157617Sanholt	drm_radeon_sarea_t *sarea_priv;
2297182080Srnoland	struct drm_device_dma *dma = dev->dma;
2298182080Srnoland	struct drm_buf *buf;
2299182080Srnoland	drm_radeon_indices_t *elts = data;
2300112015Sanholt	drm_radeon_tcl_prim_t prim;
230195584Sanholt	int count;
230295584Sanholt
2303182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
230495584Sanholt
2305157617Sanholt	sarea_priv = dev_priv->sarea_priv;
230695584Sanholt
2307145132Sanholt	DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n",
2308182080Srnoland		  DRM_CURRENTPID, elts->idx, elts->start, elts->end,
2309182080Srnoland		  elts->discard);
231095584Sanholt
2311182080Srnoland	if (elts->idx < 0 || elts->idx >= dma->buf_count) {
2312145132Sanholt		DRM_ERROR("buffer index %d (of %d max)\n",
2313182080Srnoland			  elts->idx, dma->buf_count - 1);
2314182080Srnoland		return -EINVAL;
231595584Sanholt	}
2316182080Srnoland	if (elts->prim < 0 || elts->prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
2317182080Srnoland		DRM_ERROR("buffer prim %d\n", elts->prim);
2318182080Srnoland		return -EINVAL;
231995584Sanholt	}
232095584Sanholt
2321145132Sanholt	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2322145132Sanholt	VB_AGE_TEST_WITH_RETURN(dev_priv);
232395584Sanholt
2324182080Srnoland	buf = dma->buflist[elts->idx];
232595584Sanholt
2326182080Srnoland	if (buf->file_priv != file_priv) {
2327145132Sanholt		DRM_ERROR("process %d using buffer owned by %p\n",
2328182080Srnoland			  DRM_CURRENTPID, buf->file_priv);
2329182080Srnoland		return -EINVAL;
233095584Sanholt	}
2331145132Sanholt	if (buf->pending) {
2332182080Srnoland		DRM_ERROR("sending pending buffer %d\n", elts->idx);
2333182080Srnoland		return -EINVAL;
233495584Sanholt	}
233595584Sanholt
2336182080Srnoland	count = (elts->end - elts->start) / sizeof(u16);
2337182080Srnoland	elts->start -= RADEON_INDEX_PRIM_OFFSET;
233895584Sanholt
2339182080Srnoland	if (elts->start & 0x7) {
2340182080Srnoland		DRM_ERROR("misaligned buffer 0x%x\n", elts->start);
2341182080Srnoland		return -EINVAL;
234295584Sanholt	}
2343182080Srnoland	if (elts->start < buf->used) {
2344182080Srnoland		DRM_ERROR("no header 0x%x - 0x%x\n", elts->start, buf->used);
2345182080Srnoland		return -EINVAL;
234695584Sanholt	}
234795584Sanholt
2348182080Srnoland	buf->used = elts->end;
234995584Sanholt
2350145132Sanholt	if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
2351182080Srnoland		if (radeon_emit_state(dev_priv, file_priv,
2352145132Sanholt				      &sarea_priv->context_state,
2353145132Sanholt				      sarea_priv->tex_state,
2354145132Sanholt				      sarea_priv->dirty)) {
2355145132Sanholt			DRM_ERROR("radeon_emit_state failed\n");
2356182080Srnoland			return -EINVAL;
2357122580Sanholt		}
235895584Sanholt
2359112015Sanholt		sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
2360112015Sanholt				       RADEON_UPLOAD_TEX1IMAGES |
2361112015Sanholt				       RADEON_UPLOAD_TEX2IMAGES |
2362112015Sanholt				       RADEON_REQUIRE_QUIESCENCE);
2363112015Sanholt	}
2364112015Sanholt
2365112015Sanholt	/* Build up a prim_t record:
2366112015Sanholt	 */
2367182080Srnoland	prim.start = elts->start;
2368182080Srnoland	prim.finish = elts->end;
2369182080Srnoland	prim.prim = elts->prim;
2370112015Sanholt	prim.offset = 0;	/* offset from start of dma buffers */
2371145132Sanholt	prim.numverts = RADEON_MAX_VB_VERTS;	/* duh */
2372189499Srnoland	prim.vc_format = sarea_priv->vc_format;
2373145132Sanholt
2374145132Sanholt	radeon_cp_dispatch_indices(dev, buf, &prim);
2375182080Srnoland	if (elts->discard) {
2376145132Sanholt		radeon_cp_discard_buffer(dev, buf);
2377112015Sanholt	}
2378112015Sanholt
2379112015Sanholt	COMMIT_RING();
238095584Sanholt	return 0;
238195584Sanholt}
238295584Sanholt
2383182080Srnolandstatic int radeon_cp_texture(struct drm_device *dev, void *data, struct drm_file *file_priv)
238495584Sanholt{
238595584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
2386182080Srnoland	drm_radeon_texture_t *tex = data;
238795584Sanholt	drm_radeon_tex_image_t image;
2388112015Sanholt	int ret;
238995584Sanholt
2390182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
239195584Sanholt
2392182080Srnoland	if (tex->image == NULL) {
2393145132Sanholt		DRM_ERROR("null texture image!\n");
2394182080Srnoland		return -EINVAL;
239595584Sanholt	}
239695584Sanholt
2397145132Sanholt	if (DRM_COPY_FROM_USER(&image,
2398182080Srnoland			       (drm_radeon_tex_image_t __user *) tex->image,
2399145132Sanholt			       sizeof(image)))
2400182080Srnoland		return -EFAULT;
240195584Sanholt
2402145132Sanholt	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2403145132Sanholt	VB_AGE_TEST_WITH_RETURN(dev_priv);
240495584Sanholt
2405196470Srnoland	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
2406196470Srnoland		ret = r600_cp_dispatch_texture(dev, file_priv, tex, &image);
2407196470Srnoland	else
2408196470Srnoland		ret = radeon_cp_dispatch_texture(dev, file_priv, tex, &image);
2409112015Sanholt
2410112015Sanholt	return ret;
241195584Sanholt}
241295584Sanholt
2413182080Srnolandstatic int radeon_cp_stipple(struct drm_device *dev, void *data, struct drm_file *file_priv)
241495584Sanholt{
241595584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
2416182080Srnoland	drm_radeon_stipple_t *stipple = data;
241795584Sanholt	u32 mask[32];
241895584Sanholt
2419182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
242095584Sanholt
2421182080Srnoland	if (DRM_COPY_FROM_USER(&mask, stipple->mask, 32 * sizeof(u32)))
2422182080Srnoland		return -EFAULT;
242395584Sanholt
2424145132Sanholt	RING_SPACE_TEST_WITH_RETURN(dev_priv);
242595584Sanholt
2426145132Sanholt	radeon_cp_dispatch_stipple(dev, mask);
242795584Sanholt
2428112015Sanholt	COMMIT_RING();
242995584Sanholt	return 0;
243095584Sanholt}
243195584Sanholt
2432182080Srnolandstatic int radeon_cp_indirect(struct drm_device *dev, void *data, struct drm_file *file_priv)
243395584Sanholt{
243495584Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
2435182080Srnoland	struct drm_device_dma *dma = dev->dma;
2436182080Srnoland	struct drm_buf *buf;
2437182080Srnoland	drm_radeon_indirect_t *indirect = data;
243895584Sanholt	RING_LOCALS;
243995584Sanholt
2440182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
244195584Sanholt
2442145132Sanholt	if (!dev_priv) {
2443182080Srnoland		DRM_ERROR("called with no initialization\n");
2444182080Srnoland		return -EINVAL;
244595584Sanholt	}
244695584Sanholt
2447182080Srnoland	DRM_DEBUG("idx=%d s=%d e=%d d=%d\n",
2448182080Srnoland		  indirect->idx, indirect->start, indirect->end,
2449182080Srnoland		  indirect->discard);
245095584Sanholt
2451182080Srnoland	if (indirect->idx < 0 || indirect->idx >= dma->buf_count) {
2452145132Sanholt		DRM_ERROR("buffer index %d (of %d max)\n",
2453182080Srnoland			  indirect->idx, dma->buf_count - 1);
2454182080Srnoland		return -EINVAL;
245595584Sanholt	}
245695584Sanholt
2457182080Srnoland	buf = dma->buflist[indirect->idx];
245895584Sanholt
2459182080Srnoland	if (buf->file_priv != file_priv) {
2460145132Sanholt		DRM_ERROR("process %d using buffer owned by %p\n",
2461182080Srnoland			  DRM_CURRENTPID, buf->file_priv);
2462182080Srnoland		return -EINVAL;
246395584Sanholt	}
2464145132Sanholt	if (buf->pending) {
2465182080Srnoland		DRM_ERROR("sending pending buffer %d\n", indirect->idx);
2466182080Srnoland		return -EINVAL;
246795584Sanholt	}
246895584Sanholt
2469182080Srnoland	if (indirect->start < buf->used) {
2470145132Sanholt		DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n",
2471182080Srnoland			  indirect->start, buf->used);
2472182080Srnoland		return -EINVAL;
247395584Sanholt	}
247495584Sanholt
2475145132Sanholt	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2476145132Sanholt	VB_AGE_TEST_WITH_RETURN(dev_priv);
247795584Sanholt
2478182080Srnoland	buf->used = indirect->end;
247995584Sanholt
248095584Sanholt	/* Dispatch the indirect buffer full of commands from the
248195584Sanholt	 * X server.  This is insecure and is thus only available to
248295584Sanholt	 * privileged clients.
248395584Sanholt	 */
2484189499Srnoland	if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
2485189499Srnoland		r600_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end);
2486189499Srnoland	else {
2487189499Srnoland		/* Wait for the 3D stream to idle before the indirect buffer
2488189499Srnoland		 * containing 2D acceleration commands is processed.
2489189499Srnoland		 */
2490189499Srnoland		BEGIN_RING(2);
2491189499Srnoland		RADEON_WAIT_UNTIL_3D_IDLE();
2492189499Srnoland		ADVANCE_RING();
2493189499Srnoland		radeon_cp_dispatch_indirect(dev, buf, indirect->start, indirect->end);
2494112015Sanholt	}
249595584Sanholt
2496189499Srnoland	if (indirect->discard)
2497189499Srnoland		radeon_cp_discard_buffer(dev, buf);
2498189499Srnoland
2499112015Sanholt	COMMIT_RING();
250095584Sanholt	return 0;
250195584Sanholt}
2502112015Sanholt
2503182080Srnolandstatic int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file *file_priv)
2504112015Sanholt{
2505112015Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
2506157617Sanholt	drm_radeon_sarea_t *sarea_priv;
2507182080Srnoland	struct drm_device_dma *dma = dev->dma;
2508182080Srnoland	struct drm_buf *buf;
2509182080Srnoland	drm_radeon_vertex2_t *vertex = data;
2510112015Sanholt	int i;
2511112015Sanholt	unsigned char laststate;
2512112015Sanholt
2513182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
2514112015Sanholt
2515157617Sanholt	sarea_priv = dev_priv->sarea_priv;
2516157617Sanholt
2517145132Sanholt	DRM_DEBUG("pid=%d index=%d discard=%d\n",
2518182080Srnoland		  DRM_CURRENTPID, vertex->idx, vertex->discard);
2519112015Sanholt
2520182080Srnoland	if (vertex->idx < 0 || vertex->idx >= dma->buf_count) {
2521145132Sanholt		DRM_ERROR("buffer index %d (of %d max)\n",
2522182080Srnoland			  vertex->idx, dma->buf_count - 1);
2523182080Srnoland		return -EINVAL;
2524112015Sanholt	}
2525112015Sanholt
2526145132Sanholt	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2527145132Sanholt	VB_AGE_TEST_WITH_RETURN(dev_priv);
2528112015Sanholt
2529182080Srnoland	buf = dma->buflist[vertex->idx];
2530112015Sanholt
2531182080Srnoland	if (buf->file_priv != file_priv) {
2532145132Sanholt		DRM_ERROR("process %d using buffer owned by %p\n",
2533182080Srnoland			  DRM_CURRENTPID, buf->file_priv);
2534182080Srnoland		return -EINVAL;
2535112015Sanholt	}
2536112015Sanholt
2537145132Sanholt	if (buf->pending) {
2538182080Srnoland		DRM_ERROR("sending pending buffer %d\n", vertex->idx);
2539182080Srnoland		return -EINVAL;
2540112015Sanholt	}
2541145132Sanholt
2542112015Sanholt	if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
2543182080Srnoland		return -EINVAL;
2544112015Sanholt
2545182080Srnoland	for (laststate = 0xff, i = 0; i < vertex->nr_prims; i++) {
2546112015Sanholt		drm_radeon_prim_t prim;
2547112015Sanholt		drm_radeon_tcl_prim_t tclprim;
2548145132Sanholt
2549182080Srnoland		if (DRM_COPY_FROM_USER(&prim, &vertex->prim[i], sizeof(prim)))
2550182080Srnoland			return -EFAULT;
2551145132Sanholt
2552145132Sanholt		if (prim.stateidx != laststate) {
2553145132Sanholt			drm_radeon_state_t state;
2554145132Sanholt
2555145132Sanholt			if (DRM_COPY_FROM_USER(&state,
2556182080Srnoland					       &vertex->state[prim.stateidx],
2557145132Sanholt					       sizeof(state)))
2558182080Srnoland				return -EFAULT;
2559112015Sanholt
2560182080Srnoland			if (radeon_emit_state2(dev_priv, file_priv, &state)) {
2561145132Sanholt				DRM_ERROR("radeon_emit_state2 failed\n");
2562182080Srnoland				return -EINVAL;
2563122580Sanholt			}
2564112015Sanholt
2565112015Sanholt			laststate = prim.stateidx;
2566112015Sanholt		}
2567112015Sanholt
2568112015Sanholt		tclprim.start = prim.start;
2569112015Sanholt		tclprim.finish = prim.finish;
2570112015Sanholt		tclprim.prim = prim.prim;
2571112015Sanholt		tclprim.vc_format = prim.vc_format;
2572112015Sanholt
2573145132Sanholt		if (prim.prim & RADEON_PRIM_WALK_IND) {
2574112015Sanholt			tclprim.offset = prim.numverts * 64;
2575145132Sanholt			tclprim.numverts = RADEON_MAX_VB_VERTS;	/* duh */
2576112015Sanholt
2577145132Sanholt			radeon_cp_dispatch_indices(dev, buf, &tclprim);
2578112015Sanholt		} else {
2579112015Sanholt			tclprim.numverts = prim.numverts;
2580145132Sanholt			tclprim.offset = 0;	/* not used */
2581112015Sanholt
2582145132Sanholt			radeon_cp_dispatch_vertex(dev, buf, &tclprim);
2583112015Sanholt		}
2584145132Sanholt
2585112015Sanholt		if (sarea_priv->nbox == 1)
2586112015Sanholt			sarea_priv->nbox = 0;
2587112015Sanholt	}
2588112015Sanholt
2589182080Srnoland	if (vertex->discard) {
2590145132Sanholt		radeon_cp_discard_buffer(dev, buf);
2591112015Sanholt	}
2592112015Sanholt
2593112015Sanholt	COMMIT_RING();
2594112015Sanholt	return 0;
2595112015Sanholt}
2596112015Sanholt
2597145132Sanholtstatic int radeon_emit_packets(drm_radeon_private_t * dev_priv,
2598182080Srnoland			       struct drm_file *file_priv,
2599145132Sanholt			       drm_radeon_cmd_header_t header,
2600157617Sanholt			       drm_radeon_kcmd_buffer_t *cmdbuf)
2601112015Sanholt{
2602112015Sanholt	int id = (int)header.packet.packet_id;
2603112015Sanholt	int sz, reg;
2604112015Sanholt	int *data = (int *)cmdbuf->buf;
2605112015Sanholt	RING_LOCALS;
2606145132Sanholt
2607112015Sanholt	if (id >= RADEON_MAX_STATE_PACKETS)
2608182080Srnoland		return -EINVAL;
2609112015Sanholt
2610112015Sanholt	sz = packet[id].len;
2611112015Sanholt	reg = packet[id].start;
2612112015Sanholt
2613122580Sanholt	if (sz * sizeof(int) > cmdbuf->bufsz) {
2614145132Sanholt		DRM_ERROR("Packet size provided larger than data provided\n");
2615182080Srnoland		return -EINVAL;
2616122580Sanholt	}
2617112015Sanholt
2618182080Srnoland	if (radeon_check_and_fixup_packets(dev_priv, file_priv, id, data)) {
2619145132Sanholt		DRM_ERROR("Packet verification failed\n");
2620182080Srnoland		return -EINVAL;
2621122580Sanholt	}
2622122580Sanholt
2623145132Sanholt	BEGIN_RING(sz + 1);
2624145132Sanholt	OUT_RING(CP_PACKET0(reg, (sz - 1)));
2625145132Sanholt	OUT_RING_TABLE(data, sz);
2626112015Sanholt	ADVANCE_RING();
2627112015Sanholt
2628112015Sanholt	cmdbuf->buf += sz * sizeof(int);
2629112015Sanholt	cmdbuf->bufsz -= sz * sizeof(int);
2630112015Sanholt	return 0;
2631112015Sanholt}
2632112015Sanholt
2633157617Sanholtstatic __inline__ int radeon_emit_scalars(drm_radeon_private_t *dev_priv,
2634145132Sanholt					  drm_radeon_cmd_header_t header,
2635157617Sanholt					  drm_radeon_kcmd_buffer_t *cmdbuf)
2636112015Sanholt{
2637112015Sanholt	int sz = header.scalars.count;
2638112015Sanholt	int start = header.scalars.offset;
2639112015Sanholt	int stride = header.scalars.stride;
2640112015Sanholt	RING_LOCALS;
2641112015Sanholt
2642145132Sanholt	BEGIN_RING(3 + sz);
2643145132Sanholt	OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
2644145132Sanholt	OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
2645145132Sanholt	OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
2646145132Sanholt	OUT_RING_TABLE(cmdbuf->buf, sz);
2647112015Sanholt	ADVANCE_RING();
2648112015Sanholt	cmdbuf->buf += sz * sizeof(int);
2649112015Sanholt	cmdbuf->bufsz -= sz * sizeof(int);
2650112015Sanholt	return 0;
2651112015Sanholt}
2652112015Sanholt
2653112015Sanholt/* God this is ugly
2654112015Sanholt */
2655157617Sanholtstatic __inline__ int radeon_emit_scalars2(drm_radeon_private_t *dev_priv,
2656145132Sanholt					   drm_radeon_cmd_header_t header,
2657157617Sanholt					   drm_radeon_kcmd_buffer_t *cmdbuf)
2658112015Sanholt{
2659112015Sanholt	int sz = header.scalars.count;
2660112015Sanholt	int start = ((unsigned int)header.scalars.offset) + 0x100;
2661112015Sanholt	int stride = header.scalars.stride;
2662112015Sanholt	RING_LOCALS;
2663112015Sanholt
2664145132Sanholt	BEGIN_RING(3 + sz);
2665145132Sanholt	OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
2666145132Sanholt	OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
2667145132Sanholt	OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
2668145132Sanholt	OUT_RING_TABLE(cmdbuf->buf, sz);
2669112015Sanholt	ADVANCE_RING();
2670112015Sanholt	cmdbuf->buf += sz * sizeof(int);
2671112015Sanholt	cmdbuf->bufsz -= sz * sizeof(int);
2672112015Sanholt	return 0;
2673112015Sanholt}
2674112015Sanholt
2675157617Sanholtstatic __inline__ int radeon_emit_vectors(drm_radeon_private_t *dev_priv,
2676145132Sanholt					  drm_radeon_cmd_header_t header,
2677157617Sanholt					  drm_radeon_kcmd_buffer_t *cmdbuf)
2678112015Sanholt{
2679112015Sanholt	int sz = header.vectors.count;
2680112015Sanholt	int start = header.vectors.offset;
2681112015Sanholt	int stride = header.vectors.stride;
2682112015Sanholt	RING_LOCALS;
2683112015Sanholt
2684162132Sanholt	BEGIN_RING(5 + sz);
2685162132Sanholt	OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
2686145132Sanholt	OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
2687145132Sanholt	OUT_RING(start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
2688145132Sanholt	OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
2689145132Sanholt	OUT_RING_TABLE(cmdbuf->buf, sz);
2690112015Sanholt	ADVANCE_RING();
2691112015Sanholt
2692112015Sanholt	cmdbuf->buf += sz * sizeof(int);
2693112015Sanholt	cmdbuf->bufsz -= sz * sizeof(int);
2694112015Sanholt	return 0;
2695112015Sanholt}
2696112015Sanholt
2697162132Sanholtstatic __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv,
2698162132Sanholt					  drm_radeon_cmd_header_t header,
2699162132Sanholt					  drm_radeon_kcmd_buffer_t *cmdbuf)
2700162132Sanholt{
2701162132Sanholt	int sz = header.veclinear.count * 4;
2702162132Sanholt	int start = header.veclinear.addr_lo | (header.veclinear.addr_hi << 8);
2703162132Sanholt	RING_LOCALS;
2704162132Sanholt
2705189499Srnoland        if (!sz)
2706189499Srnoland                return 0;
2707189499Srnoland        if (sz * 4 > cmdbuf->bufsz)
2708189499Srnoland                return -EINVAL;
2709162132Sanholt
2710162132Sanholt	BEGIN_RING(5 + sz);
2711162132Sanholt	OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
2712162132Sanholt	OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
2713162132Sanholt	OUT_RING(start | (1 << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
2714162132Sanholt	OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
2715162132Sanholt	OUT_RING_TABLE(cmdbuf->buf, sz);
2716162132Sanholt	ADVANCE_RING();
2717162132Sanholt
2718162132Sanholt	cmdbuf->buf += sz * sizeof(int);
2719162132Sanholt	cmdbuf->bufsz -= sz * sizeof(int);
2720162132Sanholt	return 0;
2721162132Sanholt}
2722162132Sanholt
2723182080Srnolandstatic int radeon_emit_packet3(struct drm_device * dev,
2724182080Srnoland			       struct drm_file *file_priv,
2725157617Sanholt			       drm_radeon_kcmd_buffer_t *cmdbuf)
2726112015Sanholt{
2727112015Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
2728122580Sanholt	unsigned int cmdsz;
2729145132Sanholt	int ret;
2730112015Sanholt	RING_LOCALS;
2731112015Sanholt
2732112015Sanholt	DRM_DEBUG("\n");
2733112015Sanholt
2734182080Srnoland	if ((ret = radeon_check_and_fixup_packet3(dev_priv, file_priv,
2735145132Sanholt						  cmdbuf, &cmdsz))) {
2736145132Sanholt		DRM_ERROR("Packet verification failed\n");
2737122580Sanholt		return ret;
2738122580Sanholt	}
2739112015Sanholt
2740145132Sanholt	BEGIN_RING(cmdsz);
2741145132Sanholt	OUT_RING_TABLE(cmdbuf->buf, cmdsz);
2742112015Sanholt	ADVANCE_RING();
2743112015Sanholt
2744112015Sanholt	cmdbuf->buf += cmdsz * 4;
2745112015Sanholt	cmdbuf->bufsz -= cmdsz * 4;
2746112015Sanholt	return 0;
2747112015Sanholt}
2748112015Sanholt
2749182080Srnolandstatic int radeon_emit_packet3_cliprect(struct drm_device *dev,
2750182080Srnoland					struct drm_file *file_priv,
2751157617Sanholt					drm_radeon_kcmd_buffer_t *cmdbuf,
2752145132Sanholt					int orig_nbox)
2753112015Sanholt{
2754112015Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
2755182080Srnoland	struct drm_clip_rect box;
2756122580Sanholt	unsigned int cmdsz;
2757145132Sanholt	int ret;
2758182080Srnoland	struct drm_clip_rect __user *boxes = cmdbuf->boxes;
2759112015Sanholt	int i = 0;
2760112015Sanholt	RING_LOCALS;
2761112015Sanholt
2762112015Sanholt	DRM_DEBUG("\n");
2763112015Sanholt
2764182080Srnoland	if ((ret = radeon_check_and_fixup_packet3(dev_priv, file_priv,
2765145132Sanholt						  cmdbuf, &cmdsz))) {
2766145132Sanholt		DRM_ERROR("Packet verification failed\n");
2767122580Sanholt		return ret;
2768122580Sanholt	}
2769112015Sanholt
2770112015Sanholt	if (!orig_nbox)
2771112015Sanholt		goto out;
2772112015Sanholt
2773112015Sanholt	do {
2774145132Sanholt		if (i < cmdbuf->nbox) {
2775145132Sanholt			if (DRM_COPY_FROM_USER(&box, &boxes[i], sizeof(box)))
2776182080Srnoland				return -EFAULT;
2777112015Sanholt			/* FIXME The second and subsequent times round
2778112015Sanholt			 * this loop, send a WAIT_UNTIL_3D_IDLE before
2779112015Sanholt			 * calling emit_clip_rect(). This fixes a
2780112015Sanholt			 * lockup on fast machines when sending
2781112015Sanholt			 * several cliprects with a cmdbuf, as when
2782112015Sanholt			 * waving a 2D window over a 3D
2783112015Sanholt			 * window. Something in the commands from user
2784112015Sanholt			 * space seems to hang the card when they're
2785112015Sanholt			 * sent several times in a row. That would be
2786112015Sanholt			 * the correct place to fix it but this works
2787112015Sanholt			 * around it until I can figure that out - Tim
2788112015Sanholt			 * Smith */
2789145132Sanholt			if (i) {
2790145132Sanholt				BEGIN_RING(2);
2791112015Sanholt				RADEON_WAIT_UNTIL_3D_IDLE();
2792112015Sanholt				ADVANCE_RING();
2793112015Sanholt			}
2794145132Sanholt			radeon_emit_clip_rect(dev_priv, &box);
2795112015Sanholt		}
2796145132Sanholt
2797145132Sanholt		BEGIN_RING(cmdsz);
2798145132Sanholt		OUT_RING_TABLE(cmdbuf->buf, cmdsz);
2799112015Sanholt		ADVANCE_RING();
2800112015Sanholt
2801145132Sanholt	} while (++i < cmdbuf->nbox);
2802145132Sanholt	if (cmdbuf->nbox == 1)
2803112015Sanholt		cmdbuf->nbox = 0;
2804112015Sanholt
2805145132Sanholt      out:
2806112015Sanholt	cmdbuf->buf += cmdsz * 4;
2807112015Sanholt	cmdbuf->bufsz -= cmdsz * 4;
2808112015Sanholt	return 0;
2809112015Sanholt}
2810112015Sanholt
2811182080Srnolandstatic int radeon_emit_wait(struct drm_device * dev, int flags)
2812112015Sanholt{
2813112015Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
2814112015Sanholt	RING_LOCALS;
2815112015Sanholt
2816182080Srnoland	DRM_DEBUG("%x\n", flags);
2817112015Sanholt	switch (flags) {
2818112015Sanholt	case RADEON_WAIT_2D:
2819145132Sanholt		BEGIN_RING(2);
2820145132Sanholt		RADEON_WAIT_UNTIL_2D_IDLE();
2821112015Sanholt		ADVANCE_RING();
2822112015Sanholt		break;
2823112015Sanholt	case RADEON_WAIT_3D:
2824145132Sanholt		BEGIN_RING(2);
2825145132Sanholt		RADEON_WAIT_UNTIL_3D_IDLE();
2826112015Sanholt		ADVANCE_RING();
2827112015Sanholt		break;
2828145132Sanholt	case RADEON_WAIT_2D | RADEON_WAIT_3D:
2829145132Sanholt		BEGIN_RING(2);
2830145132Sanholt		RADEON_WAIT_UNTIL_IDLE();
2831112015Sanholt		ADVANCE_RING();
2832112015Sanholt		break;
2833112015Sanholt	default:
2834182080Srnoland		return -EINVAL;
2835112015Sanholt	}
2836112015Sanholt
2837112015Sanholt	return 0;
2838112015Sanholt}
2839112015Sanholt
2840182080Srnolandstatic int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_priv)
2841112015Sanholt{
2842112015Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
2843182080Srnoland	struct drm_device_dma *dma = dev->dma;
2844182080Srnoland	struct drm_buf *buf = NULL;
2845112015Sanholt	int idx;
2846182080Srnoland	drm_radeon_kcmd_buffer_t *cmdbuf = data;
2847112015Sanholt	drm_radeon_cmd_header_t header;
2848145132Sanholt	int orig_nbox, orig_bufsz;
2849145132Sanholt	char *kbuf = NULL;
2850112015Sanholt
2851182080Srnoland	LOCK_TEST_WITH_RETURN(dev, file_priv);
2852112015Sanholt
2853145132Sanholt	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2854145132Sanholt	VB_AGE_TEST_WITH_RETURN(dev_priv);
2855112015Sanholt
2856182080Srnoland	if (cmdbuf->bufsz > 64 * 1024 || cmdbuf->bufsz < 0) {
2857182080Srnoland		return -EINVAL;
2858145132Sanholt	}
2859112015Sanholt
2860145132Sanholt	/* Allocate an in-kernel area and copy in the cmdbuf.  Do this to avoid
2861145132Sanholt	 * races between checking values and using those values in other code,
2862145132Sanholt	 * and simply to avoid a lot of function calls to copy in data.
2863145132Sanholt	 */
2864182080Srnoland	orig_bufsz = cmdbuf->bufsz;
2865145132Sanholt	if (orig_bufsz != 0) {
2866182080Srnoland		kbuf = drm_alloc(cmdbuf->bufsz, DRM_MEM_DRIVER);
2867145132Sanholt		if (kbuf == NULL)
2868182080Srnoland			return -ENOMEM;
2869182080Srnoland		if (DRM_COPY_FROM_USER(kbuf, (void __user *)cmdbuf->buf,
2870182080Srnoland				       cmdbuf->bufsz)) {
2871145132Sanholt			drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
2872182080Srnoland			return -EFAULT;
2873145132Sanholt		}
2874182080Srnoland		cmdbuf->buf = kbuf;
2875145132Sanholt	}
2876112015Sanholt
2877182080Srnoland	orig_nbox = cmdbuf->nbox;
2878157617Sanholt
2879189499Srnoland	if (dev_priv->microcode_version == UCODE_R300) {
2880148211Sanholt		int temp;
2881182080Srnoland		temp = r300_do_cp_cmdbuf(dev, file_priv, cmdbuf);
2882157617Sanholt
2883148211Sanholt		if (orig_bufsz != 0)
2884148211Sanholt			drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
2885157617Sanholt
2886148211Sanholt		return temp;
2887148211Sanholt	}
2888157617Sanholt
2889148211Sanholt	/* microcode_version != r300 */
2890182080Srnoland	while (cmdbuf->bufsz >= sizeof(header)) {
2891157617Sanholt
2892182080Srnoland		header.i = *(int *)cmdbuf->buf;
2893182080Srnoland		cmdbuf->buf += sizeof(header);
2894182080Srnoland		cmdbuf->bufsz -= sizeof(header);
2895112015Sanholt
2896112015Sanholt		switch (header.header.cmd_type) {
2897145132Sanholt		case RADEON_CMD_PACKET:
2898112015Sanholt			DRM_DEBUG("RADEON_CMD_PACKET\n");
2899145132Sanholt			if (radeon_emit_packets
2900182080Srnoland			    (dev_priv, file_priv, header, cmdbuf)) {
2901112015Sanholt				DRM_ERROR("radeon_emit_packets failed\n");
2902145132Sanholt				goto err;
2903112015Sanholt			}
2904112015Sanholt			break;
2905112015Sanholt
2906112015Sanholt		case RADEON_CMD_SCALARS:
2907112015Sanholt			DRM_DEBUG("RADEON_CMD_SCALARS\n");
2908182080Srnoland			if (radeon_emit_scalars(dev_priv, header, cmdbuf)) {
2909112015Sanholt				DRM_ERROR("radeon_emit_scalars failed\n");
2910145132Sanholt				goto err;
2911112015Sanholt			}
2912112015Sanholt			break;
2913112015Sanholt
2914112015Sanholt		case RADEON_CMD_VECTORS:
2915112015Sanholt			DRM_DEBUG("RADEON_CMD_VECTORS\n");
2916182080Srnoland			if (radeon_emit_vectors(dev_priv, header, cmdbuf)) {
2917112015Sanholt				DRM_ERROR("radeon_emit_vectors failed\n");
2918145132Sanholt				goto err;
2919112015Sanholt			}
2920112015Sanholt			break;
2921112015Sanholt
2922112015Sanholt		case RADEON_CMD_DMA_DISCARD:
2923112015Sanholt			DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n");
2924112015Sanholt			idx = header.dma.buf_idx;
2925145132Sanholt			if (idx < 0 || idx >= dma->buf_count) {
2926145132Sanholt				DRM_ERROR("buffer index %d (of %d max)\n",
2927145132Sanholt					  idx, dma->buf_count - 1);
2928145132Sanholt				goto err;
2929112015Sanholt			}
2930112015Sanholt
2931112015Sanholt			buf = dma->buflist[idx];
2932182080Srnoland			if (buf->file_priv != file_priv || buf->pending) {
2933145132Sanholt				DRM_ERROR("bad buffer %p %p %d\n",
2934182080Srnoland					  buf->file_priv, file_priv,
2935182080Srnoland					  buf->pending);
2936145132Sanholt				goto err;
2937112015Sanholt			}
2938112015Sanholt
2939145132Sanholt			radeon_cp_discard_buffer(dev, buf);
2940112015Sanholt			break;
2941112015Sanholt
2942112015Sanholt		case RADEON_CMD_PACKET3:
2943112015Sanholt			DRM_DEBUG("RADEON_CMD_PACKET3\n");
2944182080Srnoland			if (radeon_emit_packet3(dev, file_priv, cmdbuf)) {
2945112015Sanholt				DRM_ERROR("radeon_emit_packet3 failed\n");
2946145132Sanholt				goto err;
2947112015Sanholt			}
2948112015Sanholt			break;
2949112015Sanholt
2950112015Sanholt		case RADEON_CMD_PACKET3_CLIP:
2951112015Sanholt			DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n");
2952145132Sanholt			if (radeon_emit_packet3_cliprect
2953182080Srnoland			    (dev, file_priv, cmdbuf, orig_nbox)) {
2954112015Sanholt				DRM_ERROR("radeon_emit_packet3_clip failed\n");
2955145132Sanholt				goto err;
2956112015Sanholt			}
2957112015Sanholt			break;
2958112015Sanholt
2959112015Sanholt		case RADEON_CMD_SCALARS2:
2960112015Sanholt			DRM_DEBUG("RADEON_CMD_SCALARS2\n");
2961182080Srnoland			if (radeon_emit_scalars2(dev_priv, header, cmdbuf)) {
2962112015Sanholt				DRM_ERROR("radeon_emit_scalars2 failed\n");
2963145132Sanholt				goto err;
2964112015Sanholt			}
2965112015Sanholt			break;
2966112015Sanholt
2967112015Sanholt		case RADEON_CMD_WAIT:
2968112015Sanholt			DRM_DEBUG("RADEON_CMD_WAIT\n");
2969145132Sanholt			if (radeon_emit_wait(dev, header.wait.flags)) {
2970112015Sanholt				DRM_ERROR("radeon_emit_wait failed\n");
2971145132Sanholt				goto err;
2972112015Sanholt			}
2973112015Sanholt			break;
2974162132Sanholt		case RADEON_CMD_VECLINEAR:
2975162132Sanholt			DRM_DEBUG("RADEON_CMD_VECLINEAR\n");
2976182080Srnoland			if (radeon_emit_veclinear(dev_priv, header, cmdbuf)) {
2977162132Sanholt				DRM_ERROR("radeon_emit_veclinear failed\n");
2978162132Sanholt				goto err;
2979162132Sanholt			}
2980162132Sanholt			break;
2981162132Sanholt
2982112015Sanholt		default:
2983145132Sanholt			DRM_ERROR("bad cmd_type %d at %p\n",
2984112015Sanholt				  header.header.cmd_type,
2985182080Srnoland				  cmdbuf->buf - sizeof(header));
2986145132Sanholt			goto err;
2987112015Sanholt		}
2988112015Sanholt	}
2989112015Sanholt
2990145132Sanholt	if (orig_bufsz != 0)
2991145132Sanholt		drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
2992157617Sanholt
2993112015Sanholt	DRM_DEBUG("DONE\n");
2994112015Sanholt	COMMIT_RING();
2995112015Sanholt	return 0;
2996145132Sanholt
2997157617Sanholt      err:
2998145132Sanholt	if (orig_bufsz != 0)
2999145132Sanholt		drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
3000182080Srnoland	return -EINVAL;
3001112015Sanholt}
3002112015Sanholt
3003182080Srnolandstatic int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
3004112015Sanholt{
3005112015Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
3006182080Srnoland	drm_radeon_getparam_t *param = data;
3007112015Sanholt	int value;
3008112015Sanholt
3009145132Sanholt	DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
3010112015Sanholt
3011182080Srnoland	switch (param->param) {
3012119895Sanholt	case RADEON_PARAM_GART_BUFFER_OFFSET:
3013119895Sanholt		value = dev_priv->gart_buffers_offset;
3014112015Sanholt		break;
3015112015Sanholt	case RADEON_PARAM_LAST_FRAME:
3016112015Sanholt		dev_priv->stats.last_frame_reads++;
3017189499Srnoland		value = GET_SCRATCH(dev_priv, 0);
3018112015Sanholt		break;
3019112015Sanholt	case RADEON_PARAM_LAST_DISPATCH:
3020189499Srnoland		value = GET_SCRATCH(dev_priv, 1);
3021112015Sanholt		break;
3022112015Sanholt	case RADEON_PARAM_LAST_CLEAR:
3023112015Sanholt		dev_priv->stats.last_clear_reads++;
3024189499Srnoland		value = GET_SCRATCH(dev_priv, 2);
3025112015Sanholt		break;
3026112015Sanholt	case RADEON_PARAM_IRQ_NR:
3027197603Srnoland		if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
3028197603Srnoland			value = 0;
3029197603Srnoland		else
3030197603Srnoland			value = dev->irq;
3031112015Sanholt		break;
3032119895Sanholt	case RADEON_PARAM_GART_BASE:
3033119895Sanholt		value = dev_priv->gart_vm_start;
3034112015Sanholt		break;
3035113995Sanholt	case RADEON_PARAM_REGISTER_HANDLE:
3036152909Sanholt		value = dev_priv->mmio->offset;
3037113995Sanholt		break;
3038113995Sanholt	case RADEON_PARAM_STATUS_HANDLE:
3039113995Sanholt		value = dev_priv->ring_rptr_offset;
3040113995Sanholt		break;
3041157719Sru#ifndef __LP64__
3042145132Sanholt		/*
3043145132Sanholt		 * This ioctl() doesn't work on 64-bit platforms because hw_lock is a
3044145132Sanholt		 * pointer which can't fit into an int-sized variable.  According to
3045145132Sanholt		 * Michel D��nzer, the ioctl() is only used on embedded platforms, so
3046145132Sanholt		 * not supporting it shouldn't be a problem.  If the same functionality
3047145132Sanholt		 * is needed on 64-bit platforms, a new ioctl() would have to be added,
3048145132Sanholt		 * so backwards-compatibility for the embedded platforms can be
3049145132Sanholt		 * maintained.  --davidm 4-Feb-2004.
3050145132Sanholt		 */
3051153087Sru	case RADEON_PARAM_SAREA_HANDLE:
3052113995Sanholt		/* The lock is the first dword in the sarea. */
3053145132Sanholt		value = (long)dev->lock.hw_lock;
3054145132Sanholt		break;
3055153087Sru#endif
3056119895Sanholt	case RADEON_PARAM_GART_TEX_HANDLE:
3057119895Sanholt		value = dev_priv->gart_textures_offset;
3058113995Sanholt		break;
3059162132Sanholt	case RADEON_PARAM_SCRATCH_OFFSET:
3060162132Sanholt		if (!dev_priv->writeback_works)
3061182080Srnoland			return -EINVAL;
3062189499Srnoland		if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
3063189499Srnoland			value = R600_SCRATCH_REG_OFFSET;
3064189499Srnoland		else
3065189499Srnoland			value = RADEON_SCRATCH_REG_OFFSET;
3066162132Sanholt		break;
3067157617Sanholt	case RADEON_PARAM_CARD_TYPE:
3068182080Srnoland		if (dev_priv->flags & RADEON_IS_PCIE)
3069157617Sanholt			value = RADEON_CARD_PCIE;
3070182080Srnoland		else if (dev_priv->flags & RADEON_IS_AGP)
3071157617Sanholt			value = RADEON_CARD_AGP;
3072157617Sanholt		else
3073157617Sanholt			value = RADEON_CARD_PCI;
3074157617Sanholt		break;
3075182080Srnoland	case RADEON_PARAM_VBLANK_CRTC:
3076182080Srnoland		value = radeon_vblank_crtc_get(dev);
3077182080Srnoland		break;
3078182080Srnoland	case RADEON_PARAM_FB_LOCATION:
3079182080Srnoland		value = radeon_read_fb_location(dev_priv);
3080182080Srnoland		break;
3081182080Srnoland	case RADEON_PARAM_NUM_GB_PIPES:
3082182080Srnoland		value = dev_priv->num_gb_pipes;
3083182080Srnoland		break;
3084196471Srnoland	case RADEON_PARAM_NUM_Z_PIPES:
3085196471Srnoland		value = dev_priv->num_z_pipes;
3086196471Srnoland		break;
3087112015Sanholt	default:
3088189499Srnoland		DRM_DEBUG("Invalid parameter %d\n", param->param);
3089182080Srnoland		return -EINVAL;
3090112015Sanholt	}
3091112015Sanholt
3092182080Srnoland	if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
3093145132Sanholt		DRM_ERROR("copy_to_user\n");
3094182080Srnoland		return -EFAULT;
3095112015Sanholt	}
3096145132Sanholt
3097112015Sanholt	return 0;
3098112015Sanholt}
3099122580Sanholt
3100182080Srnolandstatic int radeon_cp_setparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
3101145132Sanholt{
3102122580Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
3103182080Srnoland	drm_radeon_setparam_t *sp = data;
3104145132Sanholt	struct drm_radeon_driver_file_fields *radeon_priv;
3105122580Sanholt
3106182080Srnoland	switch (sp->param) {
3107122580Sanholt	case RADEON_SETPARAM_FB_LOCATION:
3108182080Srnoland		radeon_priv = file_priv->driver_priv;
3109182080Srnoland		radeon_priv->radeon_fb_delta = dev_priv->fb_location -
3110182080Srnoland		    sp->value;
3111122580Sanholt		break;
3112145132Sanholt	case RADEON_SETPARAM_SWITCH_TILING:
3113182080Srnoland		if (sp->value == 0) {
3114157617Sanholt			DRM_DEBUG("color tiling disabled\n");
3115145132Sanholt			dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO;
3116145132Sanholt			dev_priv->back_pitch_offset &= ~RADEON_DST_TILE_MACRO;
3117182080Srnoland			if (dev_priv->sarea_priv)
3118182080Srnoland				dev_priv->sarea_priv->tiling_enabled = 0;
3119182080Srnoland		} else if (sp->value == 1) {
3120157617Sanholt			DRM_DEBUG("color tiling enabled\n");
3121145132Sanholt			dev_priv->front_pitch_offset |= RADEON_DST_TILE_MACRO;
3122145132Sanholt			dev_priv->back_pitch_offset |= RADEON_DST_TILE_MACRO;
3123182080Srnoland			if (dev_priv->sarea_priv)
3124182080Srnoland				dev_priv->sarea_priv->tiling_enabled = 1;
3125145132Sanholt		}
3126145132Sanholt		break;
3127152909Sanholt	case RADEON_SETPARAM_PCIGART_LOCATION:
3128182080Srnoland		dev_priv->pcigart_offset = sp->value;
3129182080Srnoland		dev_priv->pcigart_offset_set = 1;
3130152909Sanholt		break;
3131157617Sanholt	case RADEON_SETPARAM_NEW_MEMMAP:
3132182080Srnoland		dev_priv->new_memmap = sp->value;
3133157617Sanholt		break;
3134182080Srnoland	case RADEON_SETPARAM_PCIGART_TABLE_SIZE:
3135182080Srnoland		dev_priv->gart_info.table_size = sp->value;
3136182080Srnoland		if (dev_priv->gart_info.table_size < RADEON_PCIGART_TABLE_SIZE)
3137182080Srnoland			dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE;
3138182080Srnoland		break;
3139182080Srnoland	case RADEON_SETPARAM_VBLANK_CRTC:
3140182080Srnoland		return radeon_vblank_crtc_set(dev, sp->value);
3141182080Srnoland		break;
3142122580Sanholt	default:
3143182080Srnoland		DRM_DEBUG("Invalid parameter %d\n", sp->param);
3144182080Srnoland		return -EINVAL;
3145122580Sanholt	}
3146122580Sanholt
3147122580Sanholt	return 0;
3148122580Sanholt}
3149145132Sanholt
3150145132Sanholt/* When a client dies:
3151145132Sanholt *    - Check for and clean up flipped page state
3152145132Sanholt *    - Free any alloced GART memory.
3153145132Sanholt *    - Free any alloced radeon surfaces.
3154145132Sanholt *
3155145132Sanholt * DRM infrastructure takes care of reclaiming dma buffers.
3156145132Sanholt */
3157189499Srnolandvoid radeon_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
3158145132Sanholt{
3159145132Sanholt	if (dev->dev_private) {
3160145132Sanholt		drm_radeon_private_t *dev_priv = dev->dev_private;
3161182080Srnoland		dev_priv->page_flipping = 0;
3162182080Srnoland		radeon_mem_release(file_priv, dev_priv->gart_heap);
3163182080Srnoland		radeon_mem_release(file_priv, dev_priv->fb_heap);
3164182080Srnoland		radeon_surfaces_release(file_priv, dev_priv);
3165145132Sanholt	}
3166145132Sanholt}
3167145132Sanholt
3168182080Srnolandvoid radeon_driver_lastclose(struct drm_device *dev)
3169145132Sanholt{
3170189499Srnoland	radeon_surfaces_release(PCIGART_FILE_PRIV, dev->dev_private);
3171196470Srnoland	if (dev->dev_private) {
3172196470Srnoland		drm_radeon_private_t *dev_priv = dev->dev_private;
3173196470Srnoland
3174196470Srnoland		if (dev_priv->sarea_priv &&
3175196470Srnoland		    dev_priv->sarea_priv->pfCurrentPage != 0)
3176196470Srnoland			radeon_cp_dispatch_flip(dev);
3177196470Srnoland	}
3178196470Srnoland
3179145132Sanholt	radeon_do_release(dev);
3180145132Sanholt}
3181145132Sanholt
3182182080Srnolandint radeon_driver_open(struct drm_device *dev, struct drm_file *file_priv)
3183145132Sanholt{
3184145132Sanholt	drm_radeon_private_t *dev_priv = dev->dev_private;
3185145132Sanholt	struct drm_radeon_driver_file_fields *radeon_priv;
3186145132Sanholt
3187145132Sanholt	DRM_DEBUG("\n");
3188145132Sanholt	radeon_priv =
3189145132Sanholt	    (struct drm_radeon_driver_file_fields *)
3190145132Sanholt	    drm_alloc(sizeof(*radeon_priv), DRM_MEM_FILES);
3191145132Sanholt
3192145132Sanholt	if (!radeon_priv)
3193145132Sanholt		return -ENOMEM;
3194145132Sanholt
3195182080Srnoland	file_priv->driver_priv = radeon_priv;
3196145132Sanholt
3197145132Sanholt	if (dev_priv)
3198145132Sanholt		radeon_priv->radeon_fb_delta = dev_priv->fb_location;
3199145132Sanholt	else
3200145132Sanholt		radeon_priv->radeon_fb_delta = 0;
3201145132Sanholt	return 0;
3202145132Sanholt}
3203145132Sanholt
3204182080Srnolandvoid radeon_driver_postclose(struct drm_device *dev, struct drm_file *file_priv)
3205145132Sanholt{
3206145132Sanholt	struct drm_radeon_driver_file_fields *radeon_priv =
3207182080Srnoland	    file_priv->driver_priv;
3208145132Sanholt
3209145132Sanholt	drm_free(radeon_priv, sizeof(*radeon_priv), DRM_MEM_FILES);
3210145132Sanholt}
3211145132Sanholt
3212182080Srnolandstruct drm_ioctl_desc radeon_ioctls[] = {
3213182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_CP_INIT, radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
3214182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_CP_START, radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
3215182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_CP_STOP, radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
3216182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_CP_RESET, radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
3217182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_CP_IDLE, radeon_cp_idle, DRM_AUTH),
3218182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_CP_RESUME, radeon_cp_resume, DRM_AUTH),
3219182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_RESET, radeon_engine_reset, DRM_AUTH),
3220182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_FULLSCREEN, radeon_fullscreen, DRM_AUTH),
3221182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_SWAP, radeon_cp_swap, DRM_AUTH),
3222182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_CLEAR, radeon_cp_clear, DRM_AUTH),
3223182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_VERTEX, radeon_cp_vertex, DRM_AUTH),
3224182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_INDICES, radeon_cp_indices, DRM_AUTH),
3225182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_TEXTURE, radeon_cp_texture, DRM_AUTH),
3226182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_STIPPLE, radeon_cp_stipple, DRM_AUTH),
3227189499Srnoland	DRM_IOCTL_DEF(DRM_RADEON_INDIRECT, radeon_cp_indirect, DRM_AUTH|DRM_ROOT_ONLY),
3228182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_VERTEX2, radeon_cp_vertex2, DRM_AUTH),
3229182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_CMDBUF, radeon_cp_cmdbuf, DRM_AUTH),
3230182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_GETPARAM, radeon_cp_getparam, DRM_AUTH),
3231182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_FLIP, radeon_cp_flip, DRM_AUTH),
3232182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_ALLOC, radeon_mem_alloc, DRM_AUTH),
3233182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_FREE, radeon_mem_free, DRM_AUTH),
3234182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_INIT_HEAP, radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
3235182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_IRQ_EMIT, radeon_irq_emit, DRM_AUTH),
3236182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_IRQ_WAIT, radeon_irq_wait, DRM_AUTH),
3237182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_SETPARAM, radeon_cp_setparam, DRM_AUTH),
3238182080Srnoland	DRM_IOCTL_DEF(DRM_RADEON_SURF_ALLOC, radeon_surface_alloc, DRM_AUTH),
3239196470Srnoland	DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free, DRM_AUTH),
3240196470Srnoland	DRM_IOCTL_DEF(DRM_RADEON_CS, radeon_cs_ioctl, DRM_AUTH)
3241145132Sanholt};
3242145132Sanholt
3243145132Sanholtint radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls);
3244