xref: /titanic_41/usr/src/uts/intel/io/drm/radeon_state.c (revision 0bdffa0f07e70f45f6810116ca9d547631a4c3f8)
1e57b9183Scg149915 
2e57b9183Scg149915 /*
3e57b9183Scg149915  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
4e57b9183Scg149915  * Use is subject to license terms.
5e57b9183Scg149915  */
6e57b9183Scg149915 /* radeon_state.c -- State support for Radeon -*- linux-c -*- */
7e57b9183Scg149915 /*
8e57b9183Scg149915  * Copyright 2000 VA Linux Systems, Inc., Fremont, California.
9e57b9183Scg149915  * All Rights Reserved.
10e57b9183Scg149915  *
11e57b9183Scg149915  * Permission is hereby granted, free of charge, to any person obtaining a
12e57b9183Scg149915  * copy of this software and associated documentation files (the "Software"),
13e57b9183Scg149915  * to deal in the Software without restriction, including without limitation
14e57b9183Scg149915  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15e57b9183Scg149915  * and/or sell copies of the Software, and to permit persons to whom the
16e57b9183Scg149915  * Software is furnished to do so, subject to the following conditions:
17e57b9183Scg149915  *
18e57b9183Scg149915  * The above copyright notice and this permission notice (including the next
19e57b9183Scg149915  * paragraph) shall be included in all copies or substantial portions of the
20e57b9183Scg149915  * Software.
21e57b9183Scg149915  *
22e57b9183Scg149915  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23e57b9183Scg149915  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24e57b9183Scg149915  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
25e57b9183Scg149915  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
26e57b9183Scg149915  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27e57b9183Scg149915  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28e57b9183Scg149915  * DEALINGS IN THE SOFTWARE.
29e57b9183Scg149915  *
30e57b9183Scg149915  * Authors:
31e57b9183Scg149915  *    Gareth Hughes <gareth@valinux.com>
32e57b9183Scg149915  *    Kevin E. Martin <martin@valinux.com>
33e57b9183Scg149915  */
34e57b9183Scg149915 
35e57b9183Scg149915 #pragma ident	"%Z%%M%	%I%	%E% SMI"
36e57b9183Scg149915 
37e57b9183Scg149915 #include "drmP.h"
38e57b9183Scg149915 #include "drm.h"
39e57b9183Scg149915 #include "drm_sarea.h"
40e57b9183Scg149915 #include "radeon_drm.h"
41e57b9183Scg149915 #include "radeon_drv.h"
42e57b9183Scg149915 #include "radeon_io32.h"
43e57b9183Scg149915 
44e57b9183Scg149915 /*
45e57b9183Scg149915  * Helper functions for client state checking and fixup
46e57b9183Scg149915  */
47e57b9183Scg149915 
48e57b9183Scg149915 static inline int
radeon_check_and_fixup_offset(drm_radeon_private_t * dev_priv,drm_file_t * filp_priv,u32 * offset)49e57b9183Scg149915 radeon_check_and_fixup_offset(drm_radeon_private_t *dev_priv,
50e57b9183Scg149915     drm_file_t *filp_priv, u32 *offset)
51e57b9183Scg149915 {
52e57b9183Scg149915 	u64 off = *offset;
53e57b9183Scg149915 	u32 fb_end = dev_priv->fb_location + dev_priv->fb_size - 1;
54e57b9183Scg149915 	struct drm_radeon_driver_file_fields *radeon_priv;
55e57b9183Scg149915 
56e57b9183Scg149915 	/*
57e57b9183Scg149915 	 * Hrm ... the story of the offset ... So this function converts
58e57b9183Scg149915 	 * the various ideas of what userland clients might have for an
59e57b9183Scg149915 	 * offset in the card address space into an offset into the card
60e57b9183Scg149915 	 * address space :) So with a sane client, it should just keep
61e57b9183Scg149915 	 * the value intact and just do some boundary checking. However,
62e57b9183Scg149915 	 * not all clients are sane. Some older clients pass us 0 based
63e57b9183Scg149915 	 * offsets relative to the start of the framebuffer and some may
64e57b9183Scg149915 	 * assume the AGP aperture it appended to the framebuffer, so we
65e57b9183Scg149915 	 * try to detect those cases and fix them up.
66e57b9183Scg149915 	 *
67e57b9183Scg149915 	 * Note: It might be a good idea here to make sure the offset lands
68e57b9183Scg149915 	 * in some "allowed" area to protect things like the PCIE GART...
69e57b9183Scg149915 	 */
70e57b9183Scg149915 
71e57b9183Scg149915 	/*
72e57b9183Scg149915 	 * First, the best case, the offset already lands in either the
73e57b9183Scg149915 	 * framebuffer or the GART mapped space
74e57b9183Scg149915 	 */
75e57b9183Scg149915 
76*0bdffa0fShh224818 	if (RADEON_CHECK_OFFSET(dev_priv, off))
77e57b9183Scg149915 		return (0);
78e57b9183Scg149915 
79e57b9183Scg149915 	/*
80e57b9183Scg149915 	 * Ok, that didn't happen... now check if we have a zero based
81e57b9183Scg149915 	 * offset that fits in the framebuffer + gart space, apply the
82e57b9183Scg149915 	 * magic offset we get from SETPARAM or calculated from fb_location
83e57b9183Scg149915 	 */
84e57b9183Scg149915 	if (off < (dev_priv->fb_size + dev_priv->gart_size)) {
85e57b9183Scg149915 		radeon_priv = filp_priv->driver_priv;
86e57b9183Scg149915 		off += radeon_priv->radeon_fb_delta;
87e57b9183Scg149915 	}
88e57b9183Scg149915 
89e57b9183Scg149915 	/* Finally, assume we aimed at a GART offset if beyond the fb */
90e57b9183Scg149915 	if (off > fb_end)
91e57b9183Scg149915 		off = off - fb_end - 1 + dev_priv->gart_vm_start;
92e57b9183Scg149915 
93e57b9183Scg149915 	/* Now recheck and fail if out of bounds */
94*0bdffa0fShh224818 	if (RADEON_CHECK_OFFSET(dev_priv, off)) {
95e57b9183Scg149915 		DRM_DEBUG("offset fixed up to 0x%x\n", off);
96e57b9183Scg149915 		*offset = (uint32_t)off;
97e57b9183Scg149915 		return (0);
98e57b9183Scg149915 	}
99e57b9183Scg149915 	return (EINVAL);
100e57b9183Scg149915 }
101e57b9183Scg149915 
102e57b9183Scg149915 static inline int
radeon_check_and_fixup_packets(drm_radeon_private_t * dev_priv,drm_file_t * filp_priv,int id,u32 * data)103e57b9183Scg149915 radeon_check_and_fixup_packets(drm_radeon_private_t *dev_priv,
104e57b9183Scg149915     drm_file_t *filp_priv, int id, u32 *data)
105e57b9183Scg149915 {
106e57b9183Scg149915 	switch (id) {
107e57b9183Scg149915 
108e57b9183Scg149915 	case RADEON_EMIT_PP_MISC:
109e57b9183Scg149915 		if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
110e57b9183Scg149915 		    &data[(RADEON_RB3D_DEPTHOFFSET - RADEON_PP_MISC) / 4])) {
111e57b9183Scg149915 			DRM_ERROR("Invalid depth buffer offset\n");
112e57b9183Scg149915 			return (EINVAL);
113e57b9183Scg149915 		}
114e57b9183Scg149915 		break;
115e57b9183Scg149915 
116e57b9183Scg149915 	case RADEON_EMIT_PP_CNTL:
117e57b9183Scg149915 		if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
118e57b9183Scg149915 		    &data[(RADEON_RB3D_COLOROFFSET - RADEON_PP_CNTL) / 4])) {
119e57b9183Scg149915 			DRM_ERROR("Invalid colour buffer offset\n");
120e57b9183Scg149915 			return (EINVAL);
121e57b9183Scg149915 		}
122e57b9183Scg149915 		break;
123e57b9183Scg149915 
124e57b9183Scg149915 	case R200_EMIT_PP_TXOFFSET_0:
125e57b9183Scg149915 	case R200_EMIT_PP_TXOFFSET_1:
126e57b9183Scg149915 	case R200_EMIT_PP_TXOFFSET_2:
127e57b9183Scg149915 	case R200_EMIT_PP_TXOFFSET_3:
128e57b9183Scg149915 	case R200_EMIT_PP_TXOFFSET_4:
129e57b9183Scg149915 	case R200_EMIT_PP_TXOFFSET_5:
130e57b9183Scg149915 		if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
131e57b9183Scg149915 		    &data[0])) {
132e57b9183Scg149915 			DRM_ERROR("Invalid R200 texture offset\n");
133e57b9183Scg149915 			return (EINVAL);
134e57b9183Scg149915 		}
135e57b9183Scg149915 		break;
136e57b9183Scg149915 
137e57b9183Scg149915 	case RADEON_EMIT_PP_TXFILTER_0:
138e57b9183Scg149915 	case RADEON_EMIT_PP_TXFILTER_1:
139e57b9183Scg149915 	case RADEON_EMIT_PP_TXFILTER_2:
140e57b9183Scg149915 		if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
141e57b9183Scg149915 		    &data[(RADEON_PP_TXOFFSET_0 - RADEON_PP_TXFILTER_0) / 4])) {
142e57b9183Scg149915 			DRM_ERROR("Invalid R100 texture offset\n");
143e57b9183Scg149915 			return (EINVAL);
144e57b9183Scg149915 		}
145e57b9183Scg149915 		break;
146e57b9183Scg149915 
147e57b9183Scg149915 	case R200_EMIT_PP_CUBIC_OFFSETS_0:
148e57b9183Scg149915 	case R200_EMIT_PP_CUBIC_OFFSETS_1:
149e57b9183Scg149915 	case R200_EMIT_PP_CUBIC_OFFSETS_2:
150e57b9183Scg149915 	case R200_EMIT_PP_CUBIC_OFFSETS_3:
151e57b9183Scg149915 	case R200_EMIT_PP_CUBIC_OFFSETS_4:
152e57b9183Scg149915 	case R200_EMIT_PP_CUBIC_OFFSETS_5: {
153e57b9183Scg149915 			int i;
154e57b9183Scg149915 			for (i = 0; i < 5; i++) {
155e57b9183Scg149915 				if (radeon_check_and_fixup_offset(dev_priv,
156e57b9183Scg149915 				    filp_priv, &data[i])) {
157e57b9183Scg149915 					DRM_ERROR("Invalid R200 cubic"
158e57b9183Scg149915 					    " texture offset\n");
159e57b9183Scg149915 					return (EINVAL);
160e57b9183Scg149915 				}
161e57b9183Scg149915 			}
162e57b9183Scg149915 			break;
163e57b9183Scg149915 		}
164e57b9183Scg149915 
165e57b9183Scg149915 	case RADEON_EMIT_PP_CUBIC_OFFSETS_T0:
166e57b9183Scg149915 	case RADEON_EMIT_PP_CUBIC_OFFSETS_T1:
167e57b9183Scg149915 	case RADEON_EMIT_PP_CUBIC_OFFSETS_T2:
168e57b9183Scg149915 	{
169e57b9183Scg149915 			int i;
170e57b9183Scg149915 			for (i = 0; i < 5; i++) {
171e57b9183Scg149915 				if (radeon_check_and_fixup_offset(dev_priv,
172e57b9183Scg149915 				    filp_priv, &data[i])) {
173e57b9183Scg149915 					DRM_ERROR("Invalid R100 cubic"
174e57b9183Scg149915 					    " texture offset\n");
175e57b9183Scg149915 					return (EINVAL);
176e57b9183Scg149915 				}
177e57b9183Scg149915 			}
178e57b9183Scg149915 	}
179e57b9183Scg149915 		break;
180e57b9183Scg149915 
181e57b9183Scg149915 	case R200_EMIT_VAP_CTL:
182e57b9183Scg149915 	{
183e57b9183Scg149915 		RING_LOCALS;
184e57b9183Scg149915 		BEGIN_RING(2);
185e57b9183Scg149915 		OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
186e57b9183Scg149915 		ADVANCE_RING();
187e57b9183Scg149915 	}
188e57b9183Scg149915 		break;
189e57b9183Scg149915 
190e57b9183Scg149915 	case RADEON_EMIT_RB3D_COLORPITCH:
191e57b9183Scg149915 	case RADEON_EMIT_RE_LINE_PATTERN:
192e57b9183Scg149915 	case RADEON_EMIT_SE_LINE_WIDTH:
193e57b9183Scg149915 	case RADEON_EMIT_PP_LUM_MATRIX:
194e57b9183Scg149915 	case RADEON_EMIT_PP_ROT_MATRIX_0:
195e57b9183Scg149915 	case RADEON_EMIT_RB3D_STENCILREFMASK:
196e57b9183Scg149915 	case RADEON_EMIT_SE_VPORT_XSCALE:
197e57b9183Scg149915 	case RADEON_EMIT_SE_CNTL:
198e57b9183Scg149915 	case RADEON_EMIT_SE_CNTL_STATUS:
199e57b9183Scg149915 	case RADEON_EMIT_RE_MISC:
200e57b9183Scg149915 	case RADEON_EMIT_PP_BORDER_COLOR_0:
201e57b9183Scg149915 	case RADEON_EMIT_PP_BORDER_COLOR_1:
202e57b9183Scg149915 	case RADEON_EMIT_PP_BORDER_COLOR_2:
203e57b9183Scg149915 	case RADEON_EMIT_SE_ZBIAS_FACTOR:
204e57b9183Scg149915 	case RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT:
205e57b9183Scg149915 	case RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED:
206e57b9183Scg149915 	case R200_EMIT_PP_TXCBLEND_0:
207e57b9183Scg149915 	case R200_EMIT_PP_TXCBLEND_1:
208e57b9183Scg149915 	case R200_EMIT_PP_TXCBLEND_2:
209e57b9183Scg149915 	case R200_EMIT_PP_TXCBLEND_3:
210e57b9183Scg149915 	case R200_EMIT_PP_TXCBLEND_4:
211e57b9183Scg149915 	case R200_EMIT_PP_TXCBLEND_5:
212e57b9183Scg149915 	case R200_EMIT_PP_TXCBLEND_6:
213e57b9183Scg149915 	case R200_EMIT_PP_TXCBLEND_7:
214e57b9183Scg149915 	case R200_EMIT_TCL_LIGHT_MODEL_CTL_0:
215e57b9183Scg149915 	case R200_EMIT_TFACTOR_0:
216e57b9183Scg149915 	case R200_EMIT_VTX_FMT_0:
217e57b9183Scg149915 	case R200_EMIT_MATRIX_SELECT_0:
218e57b9183Scg149915 	case R200_EMIT_TEX_PROC_CTL_2:
219e57b9183Scg149915 	case R200_EMIT_TCL_UCP_VERT_BLEND_CTL:
220e57b9183Scg149915 	case R200_EMIT_PP_TXFILTER_0:
221e57b9183Scg149915 	case R200_EMIT_PP_TXFILTER_1:
222e57b9183Scg149915 	case R200_EMIT_PP_TXFILTER_2:
223e57b9183Scg149915 	case R200_EMIT_PP_TXFILTER_3:
224e57b9183Scg149915 	case R200_EMIT_PP_TXFILTER_4:
225e57b9183Scg149915 	case R200_EMIT_PP_TXFILTER_5:
226e57b9183Scg149915 	case R200_EMIT_VTE_CNTL:
227e57b9183Scg149915 	case R200_EMIT_OUTPUT_VTX_COMP_SEL:
228e57b9183Scg149915 	case R200_EMIT_PP_TAM_DEBUG3:
229e57b9183Scg149915 	case R200_EMIT_PP_CNTL_X:
230e57b9183Scg149915 	case R200_EMIT_RB3D_DEPTHXY_OFFSET:
231e57b9183Scg149915 	case R200_EMIT_RE_AUX_SCISSOR_CNTL:
232e57b9183Scg149915 	case R200_EMIT_RE_SCISSOR_TL_0:
233e57b9183Scg149915 	case R200_EMIT_RE_SCISSOR_TL_1:
234e57b9183Scg149915 	case R200_EMIT_RE_SCISSOR_TL_2:
235e57b9183Scg149915 	case R200_EMIT_SE_VAP_CNTL_STATUS:
236e57b9183Scg149915 	case R200_EMIT_SE_VTX_STATE_CNTL:
237e57b9183Scg149915 	case R200_EMIT_RE_POINTSIZE:
238e57b9183Scg149915 	case R200_EMIT_TCL_INPUT_VTX_VECTOR_ADDR_0:
239e57b9183Scg149915 	case R200_EMIT_PP_CUBIC_FACES_0:
240e57b9183Scg149915 	case R200_EMIT_PP_CUBIC_FACES_1:
241e57b9183Scg149915 	case R200_EMIT_PP_CUBIC_FACES_2:
242e57b9183Scg149915 	case R200_EMIT_PP_CUBIC_FACES_3:
243e57b9183Scg149915 	case R200_EMIT_PP_CUBIC_FACES_4:
244e57b9183Scg149915 	case R200_EMIT_PP_CUBIC_FACES_5:
245e57b9183Scg149915 	case RADEON_EMIT_PP_TEX_SIZE_0:
246e57b9183Scg149915 	case RADEON_EMIT_PP_TEX_SIZE_1:
247e57b9183Scg149915 	case RADEON_EMIT_PP_TEX_SIZE_2:
248e57b9183Scg149915 	case R200_EMIT_RB3D_BLENDCOLOR:
249e57b9183Scg149915 	case R200_EMIT_TCL_POINT_SPRITE_CNTL:
250e57b9183Scg149915 	case RADEON_EMIT_PP_CUBIC_FACES_0:
251e57b9183Scg149915 	case RADEON_EMIT_PP_CUBIC_FACES_1:
252e57b9183Scg149915 	case RADEON_EMIT_PP_CUBIC_FACES_2:
253e57b9183Scg149915 	case R200_EMIT_PP_TRI_PERF_CNTL:
254e57b9183Scg149915 	case R200_EMIT_PP_AFS_0:
255e57b9183Scg149915 	case R200_EMIT_PP_AFS_1:
256e57b9183Scg149915 	case R200_EMIT_ATF_TFACTOR:
257e57b9183Scg149915 	case R200_EMIT_PP_TXCTLALL_0:
258e57b9183Scg149915 	case R200_EMIT_PP_TXCTLALL_1:
259e57b9183Scg149915 	case R200_EMIT_PP_TXCTLALL_2:
260e57b9183Scg149915 	case R200_EMIT_PP_TXCTLALL_3:
261e57b9183Scg149915 	case R200_EMIT_PP_TXCTLALL_4:
262e57b9183Scg149915 	case R200_EMIT_PP_TXCTLALL_5:
263e57b9183Scg149915 	case R200_EMIT_VAP_PVS_CNTL:
264e57b9183Scg149915 		/* These packets don't contain memory offsets */
265e57b9183Scg149915 		break;
266e57b9183Scg149915 
267e57b9183Scg149915 	default:
268e57b9183Scg149915 		DRM_ERROR("Unknown state packet ID %d\n", id);
269e57b9183Scg149915 		return (EINVAL);
270e57b9183Scg149915 	}
271e57b9183Scg149915 
272e57b9183Scg149915 	return (0);
273e57b9183Scg149915 }
274e57b9183Scg149915 
275e57b9183Scg149915 static inline int
radeon_check_and_fixup_packet3(drm_radeon_private_t * dev_priv,drm_file_t * filp_priv,drm_radeon_kcmd_buffer_t * cmdbuf,unsigned int * cmdsz)276e57b9183Scg149915 radeon_check_and_fixup_packet3(drm_radeon_private_t *dev_priv,
277e57b9183Scg149915     drm_file_t *filp_priv, drm_radeon_kcmd_buffer_t *cmdbuf,
278e57b9183Scg149915     unsigned int *cmdsz)
279e57b9183Scg149915 {
280e57b9183Scg149915 	u32 *cmd = (u32 *)(uintptr_t)cmdbuf->buf;
281e57b9183Scg149915 	u32 offset, narrays;
282e57b9183Scg149915 	int count, i, k;
283e57b9183Scg149915 
284e57b9183Scg149915 	*cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16);
285e57b9183Scg149915 
286e57b9183Scg149915 	if ((cmd[0] & 0xc0000000) != RADEON_CP_PACKET3) {
287e57b9183Scg149915 		DRM_ERROR("Not a type 3 packet\n");
288e57b9183Scg149915 		return (EINVAL);
289e57b9183Scg149915 	}
290e57b9183Scg149915 
291e57b9183Scg149915 	if (4 * *cmdsz > cmdbuf->bufsz) {
292e57b9183Scg149915 		DRM_ERROR("Packet size larger than size of data provided\n");
293e57b9183Scg149915 		return (EINVAL);
294e57b9183Scg149915 	}
295e57b9183Scg149915 
296e57b9183Scg149915 
297e57b9183Scg149915 	switch (cmd[0] & 0xff00) {
298e57b9183Scg149915 	/* XXX Are there old drivers needing other packets? */
299e57b9183Scg149915 
300e57b9183Scg149915 	case RADEON_3D_DRAW_IMMD:
301e57b9183Scg149915 	case RADEON_3D_DRAW_VBUF:
302e57b9183Scg149915 	case RADEON_3D_DRAW_INDX:
303e57b9183Scg149915 	case RADEON_WAIT_FOR_IDLE:
304e57b9183Scg149915 	case RADEON_CP_NOP:
305e57b9183Scg149915 	case RADEON_3D_CLEAR_ZMASK:
306e57b9183Scg149915 #if 0
307e57b9183Scg149915 	case RADEON_CP_NEXT_CHAR:
308e57b9183Scg149915 	case RADEON_CP_PLY_NEXTSCAN:
309e57b9183Scg149915 	case RADEON_CP_SET_SCISSORS:
310e57b9183Scg149915 	/* probably safe but will never need them? */
311e57b9183Scg149915 #endif
312e57b9183Scg149915 /* these packets are safe */
313e57b9183Scg149915 		break;
314e57b9183Scg149915 
315e57b9183Scg149915 	case RADEON_CP_3D_DRAW_IMMD_2:
316e57b9183Scg149915 	case RADEON_CP_3D_DRAW_VBUF_2:
317e57b9183Scg149915 	case RADEON_CP_3D_DRAW_INDX_2:
318e57b9183Scg149915 	case RADEON_3D_CLEAR_HIZ:
319e57b9183Scg149915 		/* safe but r200 only */
320e57b9183Scg149915 		if (dev_priv->microcode_version != UCODE_R200) {
321e57b9183Scg149915 			DRM_ERROR("Invalid 3d packet for r100-class chip\n");
322e57b9183Scg149915 			return (EINVAL);
323e57b9183Scg149915 		}
324e57b9183Scg149915 		break;
325e57b9183Scg149915 
326e57b9183Scg149915 	case RADEON_3D_LOAD_VBPNTR:
327e57b9183Scg149915 		count = (cmd[0] >> 16) & 0x3fff;
328e57b9183Scg149915 
329e57b9183Scg149915 		if (count > 18) { /* 12 arrays max */
330e57b9183Scg149915 			DRM_ERROR(
331e57b9183Scg149915 			    "Too large payload in 3D_LOAD_VBPNTR (count=%d)\n",
332e57b9183Scg149915 			    count);
333e57b9183Scg149915 			return (EINVAL);
334e57b9183Scg149915 		}
335e57b9183Scg149915 
336e57b9183Scg149915 		/* carefully check packet contents */
337e57b9183Scg149915 		narrays = cmd[1] & ~0xc000;
338e57b9183Scg149915 		k = 0;
339e57b9183Scg149915 		i = 2;
340e57b9183Scg149915 		while ((k < narrays) && (i < (count + 2))) {
341e57b9183Scg149915 			i++;		/* skip attribute field */
342e57b9183Scg149915 			if (radeon_check_and_fixup_offset(dev_priv,
343e57b9183Scg149915 			    filp_priv, &cmd[i])) {
344e57b9183Scg149915 				DRM_ERROR(
345e57b9183Scg149915 				    "Invalid offset (k=%d i=%d) ini"
346e57b9183Scg149915 				    " 3D_LOAD_VBPNTR packet.\n", k, i);
347e57b9183Scg149915 				return (EINVAL);
348e57b9183Scg149915 			}
349e57b9183Scg149915 			k++;
350e57b9183Scg149915 			i++;
351e57b9183Scg149915 			if (k == narrays)
352e57b9183Scg149915 				break;
353e57b9183Scg149915 			/* have one more to process, they come in pairs */
354e57b9183Scg149915 			if (radeon_check_and_fixup_offset(dev_priv,
355e57b9183Scg149915 			    filp_priv, &cmd[i])) {
356e57b9183Scg149915 				DRM_ERROR(
357e57b9183Scg149915 				    "Invalid offset (k=%d i=%d) in"
358e57b9183Scg149915 				    " 3D_LOAD_VBPNTR packet.\n", k, i);
359e57b9183Scg149915 				return (EINVAL);
360e57b9183Scg149915 			}
361e57b9183Scg149915 			k++;
362e57b9183Scg149915 			i++;
363e57b9183Scg149915 		}
364e57b9183Scg149915 		/* do the counts match what we expect ? */
365e57b9183Scg149915 		if ((k != narrays) || (i != (count + 2))) {
366e57b9183Scg149915 			DRM_ERROR(
367e57b9183Scg149915 			    "Malformed 3D_LOAD_VBPNTR packet"
368e57b9183Scg149915 			    "(k=%d i=%d narrays=%d count+1=%d).\n",
369e57b9183Scg149915 			    k, i, narrays, count + 1);
370e57b9183Scg149915 			return (EINVAL);
371e57b9183Scg149915 		}
372e57b9183Scg149915 		break;
373e57b9183Scg149915 
374e57b9183Scg149915 	case RADEON_3D_RNDR_GEN_INDX_PRIM:
375e57b9183Scg149915 		if (dev_priv->microcode_version != UCODE_R100) {
376e57b9183Scg149915 			DRM_ERROR("Invalid 3d packet for r200-class chip\n");
377e57b9183Scg149915 			return (EINVAL);
378e57b9183Scg149915 		}
379e57b9183Scg149915 		if (radeon_check_and_fixup_offset(dev_priv,
380e57b9183Scg149915 		    filp_priv, &cmd[1])) {
381e57b9183Scg149915 				DRM_ERROR("Invalid rndr_gen_indx offset\n");
382e57b9183Scg149915 				return (EINVAL);
383e57b9183Scg149915 		}
384e57b9183Scg149915 		break;
385e57b9183Scg149915 
386e57b9183Scg149915 	case RADEON_CP_INDX_BUFFER:
387e57b9183Scg149915 		if (dev_priv->microcode_version != UCODE_R200) {
388e57b9183Scg149915 			DRM_ERROR("Invalid 3d packet for r100-class chip\n");
389e57b9183Scg149915 			return (EINVAL);
390e57b9183Scg149915 		}
391e57b9183Scg149915 		if ((cmd[1] & 0x8000ffff) != 0x80000810) {
392e57b9183Scg149915 			DRM_ERROR(
393e57b9183Scg149915 			    "Invalid indx_buffer reg address %08X\n", cmd[1]);
394e57b9183Scg149915 			return (EINVAL);
395e57b9183Scg149915 		}
396e57b9183Scg149915 		if (radeon_check_and_fixup_offset(dev_priv,
397e57b9183Scg149915 		    filp_priv, &cmd[2])) {
398e57b9183Scg149915 			DRM_ERROR(
399e57b9183Scg149915 			    "Invalid indx_buffer offset is %08X\n", cmd[2]);
400e57b9183Scg149915 			return (EINVAL);
401e57b9183Scg149915 		}
402e57b9183Scg149915 		break;
403e57b9183Scg149915 
404e57b9183Scg149915 	case RADEON_CNTL_HOSTDATA_BLT:
405e57b9183Scg149915 	case RADEON_CNTL_PAINT_MULTI:
406e57b9183Scg149915 	case RADEON_CNTL_BITBLT_MULTI:
407e57b9183Scg149915 		/* MSB of opcode: next DWORD GUI_CNTL */
408e57b9183Scg149915 		if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
409e57b9183Scg149915 		    RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
410e57b9183Scg149915 			offset = cmd[2] << 10;
411e57b9183Scg149915 			if (radeon_check_and_fixup_offset
412e57b9183Scg149915 			    (dev_priv, filp_priv, &offset)) {
413e57b9183Scg149915 				DRM_ERROR("Invalid first packet offset\n");
414e57b9183Scg149915 				return (EINVAL);
415e57b9183Scg149915 			}
416e57b9183Scg149915 			cmd[2] = (cmd[2] & 0xffc00000) | offset >> 10;
417e57b9183Scg149915 		}
418e57b9183Scg149915 
419e57b9183Scg149915 		if ((cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&
420e57b9183Scg149915 		    (cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
421e57b9183Scg149915 			offset = cmd[3] << 10;
422e57b9183Scg149915 			if (radeon_check_and_fixup_offset
423e57b9183Scg149915 			    (dev_priv, filp_priv, &offset)) {
424e57b9183Scg149915 				DRM_ERROR("Invalid second packet offset\n");
425e57b9183Scg149915 				return (EINVAL);
426e57b9183Scg149915 			}
427e57b9183Scg149915 			cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10;
428e57b9183Scg149915 		}
429e57b9183Scg149915 		break;
430e57b9183Scg149915 
431e57b9183Scg149915 	default:
432e57b9183Scg149915 		DRM_ERROR("Invalid packet type %x\n", cmd[0] & 0xff00);
433e57b9183Scg149915 		return (EINVAL);
434e57b9183Scg149915 	}
435e57b9183Scg149915 
436e57b9183Scg149915 	return (0);
437e57b9183Scg149915 }
438e57b9183Scg149915 
439e57b9183Scg149915 /*
440e57b9183Scg149915  * CP hardware state programming functions
441e57b9183Scg149915  */
442e57b9183Scg149915 
radeon_emit_clip_rect(drm_radeon_private_t * dev_priv,drm_clip_rect_t * box)443e57b9183Scg149915 static inline void radeon_emit_clip_rect(drm_radeon_private_t *dev_priv,
444e57b9183Scg149915     drm_clip_rect_t *box)
445e57b9183Scg149915 {
446e57b9183Scg149915 	RING_LOCALS;
447e57b9183Scg149915 
448e57b9183Scg149915 	DRM_DEBUG("   box:  x1=%d y1=%d  x2=%d y2=%d\n",
449e57b9183Scg149915 	    box->x1, box->y1, box->x2, box->y2);
450e57b9183Scg149915 
451e57b9183Scg149915 	BEGIN_RING(4);
452e57b9183Scg149915 	OUT_RING(CP_PACKET0(RADEON_RE_TOP_LEFT, 0));
453e57b9183Scg149915 	OUT_RING((box->y1 << 16) | box->x1);
454e57b9183Scg149915 	OUT_RING(CP_PACKET0(RADEON_RE_WIDTH_HEIGHT, 0));
455e57b9183Scg149915 	OUT_RING(((box->y2 - 1) << 16) | (box->x2 - 1));
456e57b9183Scg149915 	ADVANCE_RING();
457e57b9183Scg149915 }
458e57b9183Scg149915 
459e57b9183Scg149915 /* Emit 1.1 state */
radeon_emit_state(drm_radeon_private_t * dev_priv,drm_file_t * filp_priv,drm_radeon_context_regs_t * ctx,drm_radeon_texture_regs_t * tex,unsigned int dirty)460e57b9183Scg149915 static int radeon_emit_state(drm_radeon_private_t *dev_priv,
461e57b9183Scg149915     drm_file_t *filp_priv, drm_radeon_context_regs_t *ctx,
462e57b9183Scg149915     drm_radeon_texture_regs_t *tex, unsigned int dirty)
463e57b9183Scg149915 {
464e57b9183Scg149915 	RING_LOCALS;
465e57b9183Scg149915 	DRM_DEBUG("dirty=0x%08x\n", dirty);
466e57b9183Scg149915 
467e57b9183Scg149915 	if (dirty & RADEON_UPLOAD_CONTEXT) {
468e57b9183Scg149915 		if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
469e57b9183Scg149915 		    &ctx->rb3d_depthoffset)) {
470e57b9183Scg149915 			DRM_ERROR("Invalid depth buffer offset\n");
471e57b9183Scg149915 			return (EINVAL);
472e57b9183Scg149915 		}
473e57b9183Scg149915 
474e57b9183Scg149915 		if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
475e57b9183Scg149915 		    &ctx->rb3d_coloroffset)) {
476e57b9183Scg149915 			DRM_ERROR("Invalid depth buffer offset\n");
477e57b9183Scg149915 			return (EINVAL);
478e57b9183Scg149915 		}
479e57b9183Scg149915 
480e57b9183Scg149915 		BEGIN_RING(14);
481e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_PP_MISC, 6));
482e57b9183Scg149915 		OUT_RING(ctx->pp_misc);
483e57b9183Scg149915 		OUT_RING(ctx->pp_fog_color);
484e57b9183Scg149915 		OUT_RING(ctx->re_solid_color);
485e57b9183Scg149915 		OUT_RING(ctx->rb3d_blendcntl);
486e57b9183Scg149915 		OUT_RING(ctx->rb3d_depthoffset);
487e57b9183Scg149915 		OUT_RING(ctx->rb3d_depthpitch);
488e57b9183Scg149915 		OUT_RING(ctx->rb3d_zstencilcntl);
489e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 2));
490e57b9183Scg149915 		OUT_RING(ctx->pp_cntl);
491e57b9183Scg149915 		OUT_RING(ctx->rb3d_cntl);
492e57b9183Scg149915 		OUT_RING(ctx->rb3d_coloroffset);
493e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_RB3D_COLORPITCH, 0));
494e57b9183Scg149915 		OUT_RING(ctx->rb3d_colorpitch);
495e57b9183Scg149915 		ADVANCE_RING();
496e57b9183Scg149915 	}
497e57b9183Scg149915 
498e57b9183Scg149915 	if (dirty & RADEON_UPLOAD_VERTFMT) {
499e57b9183Scg149915 		BEGIN_RING(2);
500e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_SE_COORD_FMT, 0));
501e57b9183Scg149915 		OUT_RING(ctx->se_coord_fmt);
502e57b9183Scg149915 		ADVANCE_RING();
503e57b9183Scg149915 	}
504e57b9183Scg149915 
505e57b9183Scg149915 	if (dirty & RADEON_UPLOAD_LINE) {
506e57b9183Scg149915 		BEGIN_RING(5);
507e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_RE_LINE_PATTERN, 1));
508e57b9183Scg149915 		OUT_RING(ctx->re_line_pattern);
509e57b9183Scg149915 		OUT_RING(ctx->re_line_state);
510e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_SE_LINE_WIDTH, 0));
511e57b9183Scg149915 		OUT_RING(ctx->se_line_width);
512e57b9183Scg149915 		ADVANCE_RING();
513e57b9183Scg149915 	}
514e57b9183Scg149915 
515e57b9183Scg149915 	if (dirty & RADEON_UPLOAD_BUMPMAP) {
516e57b9183Scg149915 		BEGIN_RING(5);
517e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_PP_LUM_MATRIX, 0));
518e57b9183Scg149915 		OUT_RING(ctx->pp_lum_matrix);
519e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_PP_ROT_MATRIX_0, 1));
520e57b9183Scg149915 		OUT_RING(ctx->pp_rot_matrix_0);
521e57b9183Scg149915 		OUT_RING(ctx->pp_rot_matrix_1);
522e57b9183Scg149915 		ADVANCE_RING();
523e57b9183Scg149915 	}
524e57b9183Scg149915 
525e57b9183Scg149915 	if (dirty & RADEON_UPLOAD_MASKS) {
526e57b9183Scg149915 		BEGIN_RING(4);
527e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_RB3D_STENCILREFMASK, 2));
528e57b9183Scg149915 		OUT_RING(ctx->rb3d_stencilrefmask);
529e57b9183Scg149915 		OUT_RING(ctx->rb3d_ropcntl);
530e57b9183Scg149915 		OUT_RING(ctx->rb3d_planemask);
531e57b9183Scg149915 		ADVANCE_RING();
532e57b9183Scg149915 	}
533e57b9183Scg149915 
534e57b9183Scg149915 	if (dirty & RADEON_UPLOAD_VIEWPORT) {
535e57b9183Scg149915 		BEGIN_RING(7);
536e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_SE_VPORT_XSCALE, 5));
537e57b9183Scg149915 		OUT_RING(ctx->se_vport_xscale);
538e57b9183Scg149915 		OUT_RING(ctx->se_vport_xoffset);
539e57b9183Scg149915 		OUT_RING(ctx->se_vport_yscale);
540e57b9183Scg149915 		OUT_RING(ctx->se_vport_yoffset);
541e57b9183Scg149915 		OUT_RING(ctx->se_vport_zscale);
542e57b9183Scg149915 		OUT_RING(ctx->se_vport_zoffset);
543e57b9183Scg149915 		ADVANCE_RING();
544e57b9183Scg149915 	}
545e57b9183Scg149915 
546e57b9183Scg149915 	if (dirty & RADEON_UPLOAD_SETUP) {
547e57b9183Scg149915 		BEGIN_RING(4);
548e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_SE_CNTL, 0));
549e57b9183Scg149915 		OUT_RING(ctx->se_cntl);
550e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_SE_CNTL_STATUS, 0));
551e57b9183Scg149915 		OUT_RING(ctx->se_cntl_status);
552e57b9183Scg149915 		ADVANCE_RING();
553e57b9183Scg149915 	}
554e57b9183Scg149915 
555e57b9183Scg149915 	if (dirty & RADEON_UPLOAD_MISC) {
556e57b9183Scg149915 		BEGIN_RING(2);
557e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_RE_MISC, 0));
558e57b9183Scg149915 		OUT_RING(ctx->re_misc);
559e57b9183Scg149915 		ADVANCE_RING();
560e57b9183Scg149915 	}
561e57b9183Scg149915 
562e57b9183Scg149915 	if (dirty & RADEON_UPLOAD_TEX0) {
563e57b9183Scg149915 		if (radeon_check_and_fixup_offset(dev_priv,
564e57b9183Scg149915 		    filp_priv, &tex[0].pp_txoffset)) {
565e57b9183Scg149915 			DRM_ERROR("Invalid texture offset for unit 0\n");
566e57b9183Scg149915 			return (EINVAL);
567e57b9183Scg149915 		}
568e57b9183Scg149915 
569e57b9183Scg149915 		BEGIN_RING(9);
570e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_0, 5));
571e57b9183Scg149915 		OUT_RING(tex[0].pp_txfilter);
572e57b9183Scg149915 		OUT_RING(tex[0].pp_txformat);
573e57b9183Scg149915 		OUT_RING(tex[0].pp_txoffset);
574e57b9183Scg149915 		OUT_RING(tex[0].pp_txcblend);
575e57b9183Scg149915 		OUT_RING(tex[0].pp_txablend);
576e57b9183Scg149915 		OUT_RING(tex[0].pp_tfactor);
577e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_0, 0));
578e57b9183Scg149915 		OUT_RING(tex[0].pp_border_color);
579e57b9183Scg149915 		ADVANCE_RING();
580e57b9183Scg149915 	}
581e57b9183Scg149915 
582e57b9183Scg149915 	if (dirty & RADEON_UPLOAD_TEX1) {
583e57b9183Scg149915 		if (radeon_check_and_fixup_offset(dev_priv,
584e57b9183Scg149915 		    filp_priv, &tex[1].pp_txoffset)) {
585e57b9183Scg149915 			DRM_ERROR("Invalid texture offset for unit 1\n");
586e57b9183Scg149915 			return (EINVAL);
587e57b9183Scg149915 		}
588e57b9183Scg149915 
589e57b9183Scg149915 		BEGIN_RING(9);
590e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_1, 5));
591e57b9183Scg149915 		OUT_RING(tex[1].pp_txfilter);
592e57b9183Scg149915 		OUT_RING(tex[1].pp_txformat);
593e57b9183Scg149915 		OUT_RING(tex[1].pp_txoffset);
594e57b9183Scg149915 		OUT_RING(tex[1].pp_txcblend);
595e57b9183Scg149915 		OUT_RING(tex[1].pp_txablend);
596e57b9183Scg149915 		OUT_RING(tex[1].pp_tfactor);
597e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_1, 0));
598e57b9183Scg149915 		OUT_RING(tex[1].pp_border_color);
599e57b9183Scg149915 		ADVANCE_RING();
600e57b9183Scg149915 	}
601e57b9183Scg149915 
602e57b9183Scg149915 	if (dirty & RADEON_UPLOAD_TEX2) {
603e57b9183Scg149915 		if (radeon_check_and_fixup_offset(dev_priv,
604e57b9183Scg149915 		    filp_priv, &tex[2].pp_txoffset)) {
605e57b9183Scg149915 			DRM_ERROR("Invalid texture offset for unit 2\n");
606e57b9183Scg149915 			return (EINVAL);
607e57b9183Scg149915 		}
608e57b9183Scg149915 
609e57b9183Scg149915 		BEGIN_RING(9);
610e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_2, 5));
611e57b9183Scg149915 		OUT_RING(tex[2].pp_txfilter);
612e57b9183Scg149915 		OUT_RING(tex[2].pp_txformat);
613e57b9183Scg149915 		OUT_RING(tex[2].pp_txoffset);
614e57b9183Scg149915 		OUT_RING(tex[2].pp_txcblend);
615e57b9183Scg149915 		OUT_RING(tex[2].pp_txablend);
616e57b9183Scg149915 		OUT_RING(tex[2].pp_tfactor);
617e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_2, 0));
618e57b9183Scg149915 		OUT_RING(tex[2].pp_border_color);
619e57b9183Scg149915 		ADVANCE_RING();
620e57b9183Scg149915 	}
621e57b9183Scg149915 
622e57b9183Scg149915 	return (0);
623e57b9183Scg149915 }
624e57b9183Scg149915 
625e57b9183Scg149915 /* Emit 1.2 state */
radeon_emit_state2(drm_radeon_private_t * dev_priv,drm_file_t * filp_priv,drm_radeon_state_t * state)626e57b9183Scg149915 static int radeon_emit_state2(drm_radeon_private_t *dev_priv,
627e57b9183Scg149915     drm_file_t *filp_priv, drm_radeon_state_t *state)
628e57b9183Scg149915 {
629e57b9183Scg149915 	RING_LOCALS;
630e57b9183Scg149915 
631e57b9183Scg149915 	if (state->dirty & RADEON_UPLOAD_ZBIAS) {
632e57b9183Scg149915 		BEGIN_RING(3);
633e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_SE_ZBIAS_FACTOR, 1));
634e57b9183Scg149915 		OUT_RING(state->context2.se_zbias_factor);
635e57b9183Scg149915 		OUT_RING(state->context2.se_zbias_constant);
636e57b9183Scg149915 		ADVANCE_RING();
637e57b9183Scg149915 	}
638e57b9183Scg149915 
639e57b9183Scg149915 	return (radeon_emit_state(dev_priv, filp_priv,
640e57b9183Scg149915 	    &state->context, state->tex, state->dirty));
641e57b9183Scg149915 }
642e57b9183Scg149915 
643e57b9183Scg149915 /*
644e57b9183Scg149915  * New (1.3) state mechanism.  3 commands (packet, scalar, vector) in
645e57b9183Scg149915  * 1.3 cmdbuffers allow all previous state to be updated as well as
646e57b9183Scg149915  * the tcl scalar and vector areas.
647e57b9183Scg149915  */
648e57b9183Scg149915 static struct {
649e57b9183Scg149915 	int start;
650e57b9183Scg149915 	int len;
651e57b9183Scg149915 	const char *name;
652e57b9183Scg149915 } packet[RADEON_MAX_STATE_PACKETS] = {
653e57b9183Scg149915 	{RADEON_PP_MISC, 7, "RADEON_PP_MISC"},
654e57b9183Scg149915 	{RADEON_PP_CNTL, 3, "RADEON_PP_CNTL"},
655e57b9183Scg149915 	{RADEON_RB3D_COLORPITCH, 1, "RADEON_RB3D_COLORPITCH"},
656e57b9183Scg149915 	{RADEON_RE_LINE_PATTERN, 2, "RADEON_RE_LINE_PATTERN"},
657e57b9183Scg149915 	{RADEON_SE_LINE_WIDTH, 1, "RADEON_SE_LINE_WIDTH"},
658e57b9183Scg149915 	{RADEON_PP_LUM_MATRIX, 1, "RADEON_PP_LUM_MATRIX"},
659e57b9183Scg149915 	{RADEON_PP_ROT_MATRIX_0, 2, "RADEON_PP_ROT_MATRIX_0"},
660e57b9183Scg149915 	{RADEON_RB3D_STENCILREFMASK, 3, "RADEON_RB3D_STENCILREFMASK"},
661e57b9183Scg149915 	{RADEON_SE_VPORT_XSCALE, 6, "RADEON_SE_VPORT_XSCALE"},
662e57b9183Scg149915 	{RADEON_SE_CNTL, 2, "RADEON_SE_CNTL"},
663e57b9183Scg149915 	{RADEON_SE_CNTL_STATUS, 1, "RADEON_SE_CNTL_STATUS"},
664e57b9183Scg149915 	{RADEON_RE_MISC, 1, "RADEON_RE_MISC"},
665e57b9183Scg149915 	{RADEON_PP_TXFILTER_0, 6, "RADEON_PP_TXFILTER_0"},
666e57b9183Scg149915 	{RADEON_PP_BORDER_COLOR_0, 1, "RADEON_PP_BORDER_COLOR_0"},
667e57b9183Scg149915 	{RADEON_PP_TXFILTER_1, 6, "RADEON_PP_TXFILTER_1"},
668e57b9183Scg149915 	{RADEON_PP_BORDER_COLOR_1, 1, "RADEON_PP_BORDER_COLOR_1"},
669e57b9183Scg149915 	{RADEON_PP_TXFILTER_2, 6, "RADEON_PP_TXFILTER_2"},
670e57b9183Scg149915 	{RADEON_PP_BORDER_COLOR_2, 1, "RADEON_PP_BORDER_COLOR_2"},
671e57b9183Scg149915 	{RADEON_SE_ZBIAS_FACTOR, 2, "RADEON_SE_ZBIAS_FACTOR"},
672e57b9183Scg149915 	{RADEON_SE_TCL_OUTPUT_VTX_FMT, 11, "RADEON_SE_TCL_OUTPUT_VTX_FMT"},
673e57b9183Scg149915 	{RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED, 17,
674e57b9183Scg149915 		    "RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED"},
675e57b9183Scg149915 	{R200_PP_TXCBLEND_0, 4, "R200_PP_TXCBLEND_0"},
676e57b9183Scg149915 	{R200_PP_TXCBLEND_1, 4, "R200_PP_TXCBLEND_1"},
677e57b9183Scg149915 	{R200_PP_TXCBLEND_2, 4, "R200_PP_TXCBLEND_2"},
678e57b9183Scg149915 	{R200_PP_TXCBLEND_3, 4, "R200_PP_TXCBLEND_3"},
679e57b9183Scg149915 	{R200_PP_TXCBLEND_4, 4, "R200_PP_TXCBLEND_4"},
680e57b9183Scg149915 	{R200_PP_TXCBLEND_5, 4, "R200_PP_TXCBLEND_5"},
681e57b9183Scg149915 	{R200_PP_TXCBLEND_6, 4, "R200_PP_TXCBLEND_6"},
682e57b9183Scg149915 	{R200_PP_TXCBLEND_7, 4, "R200_PP_TXCBLEND_7"},
683e57b9183Scg149915 	{R200_SE_TCL_LIGHT_MODEL_CTL_0, 6, "R200_SE_TCL_LIGHT_MODEL_CTL_0"},
684e57b9183Scg149915 	{R200_PP_TFACTOR_0, 6, "R200_PP_TFACTOR_0"},
685e57b9183Scg149915 	{R200_SE_VTX_FMT_0, 4, "R200_SE_VTX_FMT_0"},
686e57b9183Scg149915 	{R200_SE_VAP_CNTL, 1, "R200_SE_VAP_CNTL"},
687e57b9183Scg149915 	{R200_SE_TCL_MATRIX_SEL_0, 5, "R200_SE_TCL_MATRIX_SEL_0"},
688e57b9183Scg149915 	{R200_SE_TCL_TEX_PROC_CTL_2, 5, "R200_SE_TCL_TEX_PROC_CTL_2"},
689e57b9183Scg149915 	{R200_SE_TCL_UCP_VERT_BLEND_CTL, 1, "R200_SE_TCL_UCP_VERT_BLEND_CTL"},
690e57b9183Scg149915 	{R200_PP_TXFILTER_0, 6, "R200_PP_TXFILTER_0"},
691e57b9183Scg149915 	{R200_PP_TXFILTER_1, 6, "R200_PP_TXFILTER_1"},
692e57b9183Scg149915 	{R200_PP_TXFILTER_2, 6, "R200_PP_TXFILTER_2"},
693e57b9183Scg149915 	{R200_PP_TXFILTER_3, 6, "R200_PP_TXFILTER_3"},
694e57b9183Scg149915 	{R200_PP_TXFILTER_4, 6, "R200_PP_TXFILTER_4"},
695e57b9183Scg149915 	{R200_PP_TXFILTER_5, 6, "R200_PP_TXFILTER_5"},
696e57b9183Scg149915 	{R200_PP_TXOFFSET_0, 1, "R200_PP_TXOFFSET_0"},
697e57b9183Scg149915 	{R200_PP_TXOFFSET_1, 1, "R200_PP_TXOFFSET_1"},
698e57b9183Scg149915 	{R200_PP_TXOFFSET_2, 1, "R200_PP_TXOFFSET_2"},
699e57b9183Scg149915 	{R200_PP_TXOFFSET_3, 1, "R200_PP_TXOFFSET_3"},
700e57b9183Scg149915 	{R200_PP_TXOFFSET_4, 1, "R200_PP_TXOFFSET_4"},
701e57b9183Scg149915 	{R200_PP_TXOFFSET_5, 1, "R200_PP_TXOFFSET_5"},
702e57b9183Scg149915 	{R200_SE_VTE_CNTL, 1, "R200_SE_VTE_CNTL"},
703e57b9183Scg149915 	{R200_SE_TCL_OUTPUT_VTX_COMP_SEL, 1,
704e57b9183Scg149915 	"R200_SE_TCL_OUTPUT_VTX_COMP_SEL"},
705e57b9183Scg149915 	{R200_PP_TAM_DEBUG3, 1, "R200_PP_TAM_DEBUG3"},
706e57b9183Scg149915 	{R200_PP_CNTL_X, 1, "R200_PP_CNTL_X"},
707e57b9183Scg149915 	{R200_RB3D_DEPTHXY_OFFSET, 1, "R200_RB3D_DEPTHXY_OFFSET"},
708e57b9183Scg149915 	{R200_RE_AUX_SCISSOR_CNTL, 1, "R200_RE_AUX_SCISSOR_CNTL"},
709e57b9183Scg149915 	{R200_RE_SCISSOR_TL_0, 2, "R200_RE_SCISSOR_TL_0"},
710e57b9183Scg149915 	{R200_RE_SCISSOR_TL_1, 2, "R200_RE_SCISSOR_TL_1"},
711e57b9183Scg149915 	{R200_RE_SCISSOR_TL_2, 2, "R200_RE_SCISSOR_TL_2"},
712e57b9183Scg149915 	{R200_SE_VAP_CNTL_STATUS, 1, "R200_SE_VAP_CNTL_STATUS"},
713e57b9183Scg149915 	{R200_SE_VTX_STATE_CNTL, 1, "R200_SE_VTX_STATE_CNTL"},
714e57b9183Scg149915 	{R200_RE_POINTSIZE, 1, "R200_RE_POINTSIZE"},
715e57b9183Scg149915 	{R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0, 4,
716e57b9183Scg149915 		    "R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0"},
717e57b9183Scg149915 	{R200_PP_CUBIC_FACES_0, 1, "R200_PP_CUBIC_FACES_0"},	/* 61 */
718e57b9183Scg149915 	{R200_PP_CUBIC_OFFSET_F1_0, 5, "R200_PP_CUBIC_OFFSET_F1_0"}, /* 62 */
719e57b9183Scg149915 	{R200_PP_CUBIC_FACES_1, 1, "R200_PP_CUBIC_FACES_1"},
720e57b9183Scg149915 	{R200_PP_CUBIC_OFFSET_F1_1, 5, "R200_PP_CUBIC_OFFSET_F1_1"},
721e57b9183Scg149915 	{R200_PP_CUBIC_FACES_2, 1, "R200_PP_CUBIC_FACES_2"},
722e57b9183Scg149915 	{R200_PP_CUBIC_OFFSET_F1_2, 5, "R200_PP_CUBIC_OFFSET_F1_2"},
723e57b9183Scg149915 	{R200_PP_CUBIC_FACES_3, 1, "R200_PP_CUBIC_FACES_3"},
724e57b9183Scg149915 	{R200_PP_CUBIC_OFFSET_F1_3, 5, "R200_PP_CUBIC_OFFSET_F1_3"},
725e57b9183Scg149915 	{R200_PP_CUBIC_FACES_4, 1, "R200_PP_CUBIC_FACES_4"},
726e57b9183Scg149915 	{R200_PP_CUBIC_OFFSET_F1_4, 5, "R200_PP_CUBIC_OFFSET_F1_4"},
727e57b9183Scg149915 	{R200_PP_CUBIC_FACES_5, 1, "R200_PP_CUBIC_FACES_5"},
728e57b9183Scg149915 	{R200_PP_CUBIC_OFFSET_F1_5, 5, "R200_PP_CUBIC_OFFSET_F1_5"},
729e57b9183Scg149915 	{RADEON_PP_TEX_SIZE_0, 2, "RADEON_PP_TEX_SIZE_0"},
730e57b9183Scg149915 	{RADEON_PP_TEX_SIZE_1, 2, "RADEON_PP_TEX_SIZE_1"},
731e57b9183Scg149915 	{RADEON_PP_TEX_SIZE_2, 2, "RADEON_PP_TEX_SIZE_2"},
732e57b9183Scg149915 	{R200_RB3D_BLENDCOLOR, 3, "R200_RB3D_BLENDCOLOR"},
733e57b9183Scg149915 	{R200_SE_TCL_POINT_SPRITE_CNTL, 1, "R200_SE_TCL_POINT_SPRITE_CNTL"},
734e57b9183Scg149915 	{RADEON_PP_CUBIC_FACES_0, 1, "RADEON_PP_CUBIC_FACES_0"},
735e57b9183Scg149915 	{RADEON_PP_CUBIC_OFFSET_T0_0, 5, "RADEON_PP_CUBIC_OFFSET_T0_0"},
736e57b9183Scg149915 	{RADEON_PP_CUBIC_FACES_1, 1, "RADEON_PP_CUBIC_FACES_1"},
737e57b9183Scg149915 	{RADEON_PP_CUBIC_OFFSET_T1_0, 5, "RADEON_PP_CUBIC_OFFSET_T1_0"},
738e57b9183Scg149915 	{RADEON_PP_CUBIC_FACES_2, 1, "RADEON_PP_CUBIC_FACES_2"},
739e57b9183Scg149915 	{RADEON_PP_CUBIC_OFFSET_T2_0, 5, "RADEON_PP_CUBIC_OFFSET_T2_0"},
740e57b9183Scg149915 	{R200_PP_TRI_PERF, 2, "R200_PP_TRI_PERF"},
741e57b9183Scg149915 	{R200_PP_AFS_0, 32, "R200_PP_AFS_0"},	/* 85 */
742e57b9183Scg149915 	{R200_PP_AFS_1, 32, "R200_PP_AFS_1"},
743e57b9183Scg149915 	{R200_PP_TFACTOR_0, 8, "R200_ATF_TFACTOR"},
744e57b9183Scg149915 	{R200_PP_TXFILTER_0, 8, "R200_PP_TXCTLALL_0"},
745e57b9183Scg149915 	{R200_PP_TXFILTER_1, 8, "R200_PP_TXCTLALL_1"},
746e57b9183Scg149915 	{R200_PP_TXFILTER_2, 8, "R200_PP_TXCTLALL_2"},
747e57b9183Scg149915 	{R200_PP_TXFILTER_3, 8, "R200_PP_TXCTLALL_3"},
748e57b9183Scg149915 	{R200_PP_TXFILTER_4, 8, "R200_PP_TXCTLALL_4"},
749e57b9183Scg149915 	{R200_PP_TXFILTER_5, 8, "R200_PP_TXCTLALL_5"},
750e57b9183Scg149915 	{R200_VAP_PVS_CNTL_1, 2, "R200_VAP_PVS_CNTL"},
751e57b9183Scg149915 };
752e57b9183Scg149915 
753e57b9183Scg149915 /*
754e57b9183Scg149915  * Performance monitoring functions
755e57b9183Scg149915  */
756e57b9183Scg149915 
radeon_clear_box(drm_radeon_private_t * dev_priv,int x,int y,int w,int h,int r,int g,int b)757e57b9183Scg149915 static void radeon_clear_box(drm_radeon_private_t *dev_priv,
758e57b9183Scg149915     int x, int y, int w, int h, int r, int g, int b)
759e57b9183Scg149915 {
760e57b9183Scg149915 	u32 color;
761e57b9183Scg149915 	RING_LOCALS;
762e57b9183Scg149915 
763e57b9183Scg149915 	x += dev_priv->sarea_priv->boxes[0].x1;
764e57b9183Scg149915 	y += dev_priv->sarea_priv->boxes[0].y1;
765e57b9183Scg149915 
766e57b9183Scg149915 	switch (dev_priv->color_fmt) {
767e57b9183Scg149915 	case RADEON_COLOR_FORMAT_RGB565:
768e57b9183Scg149915 		color = (((r & 0xf8) << 8) |
769e57b9183Scg149915 		    ((g & 0xfc) << 3) | ((b & 0xf8) >> 3));
770e57b9183Scg149915 		break;
771e57b9183Scg149915 	case RADEON_COLOR_FORMAT_ARGB8888:
772e57b9183Scg149915 	default:
773e57b9183Scg149915 		color = (((0xfful) << 24) | (r << 16) | (g << 8) | b);
774e57b9183Scg149915 		break;
775e57b9183Scg149915 	}
776e57b9183Scg149915 
777e57b9183Scg149915 	BEGIN_RING(4);
778e57b9183Scg149915 	RADEON_WAIT_UNTIL_3D_IDLE();
779e57b9183Scg149915 	OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0));
780e57b9183Scg149915 	OUT_RING(0xffffffff);
781e57b9183Scg149915 	ADVANCE_RING();
782e57b9183Scg149915 
783e57b9183Scg149915 	BEGIN_RING(6);
784e57b9183Scg149915 
785e57b9183Scg149915 	OUT_RING(CP_PACKET3(RADEON_CNTL_PAINT_MULTI, 4));
786e57b9183Scg149915 	OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
787e57b9183Scg149915 	    RADEON_GMC_BRUSH_SOLID_COLOR |
788e57b9183Scg149915 	    (dev_priv->color_fmt << 8) |
789e57b9183Scg149915 	    RADEON_GMC_SRC_DATATYPE_COLOR |
790e57b9183Scg149915 	    RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS);
791e57b9183Scg149915 
792e57b9183Scg149915 	if (dev_priv->page_flipping && dev_priv->current_page == 1) {
793e57b9183Scg149915 		OUT_RING(dev_priv->front_pitch_offset);
794e57b9183Scg149915 	} else {
795e57b9183Scg149915 		OUT_RING(dev_priv->back_pitch_offset);
796e57b9183Scg149915 	}
797e57b9183Scg149915 
798e57b9183Scg149915 	OUT_RING(color);
799e57b9183Scg149915 
800e57b9183Scg149915 	OUT_RING((x << 16) | y);
801e57b9183Scg149915 	OUT_RING((w << 16) | h);
802e57b9183Scg149915 
803e57b9183Scg149915 	ADVANCE_RING();
804e57b9183Scg149915 }
805e57b9183Scg149915 
radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv)806e57b9183Scg149915 static void radeon_cp_performance_boxes(drm_radeon_private_t *dev_priv)
807e57b9183Scg149915 {
808e57b9183Scg149915 	/*
809e57b9183Scg149915 	 * Collapse various things into a wait flag -- trying to
810e57b9183Scg149915 	 * guess if userspase slept -- better just to have them tell us.
811e57b9183Scg149915 	 */
812e57b9183Scg149915 	if (dev_priv->stats.last_frame_reads > 1 ||
813e57b9183Scg149915 	    dev_priv->stats.last_clear_reads > dev_priv->stats.clears) {
814e57b9183Scg149915 		dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
815e57b9183Scg149915 	}
816e57b9183Scg149915 
817e57b9183Scg149915 	if (dev_priv->stats.freelist_loops) {
818e57b9183Scg149915 		dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
819e57b9183Scg149915 	}
820e57b9183Scg149915 
821e57b9183Scg149915 	/* Purple box for page flipping */
822e57b9183Scg149915 	if (dev_priv->stats.boxes & RADEON_BOX_FLIP)
823e57b9183Scg149915 		radeon_clear_box(dev_priv, 4, 4, 8, 8, 255, 0, 255);
824e57b9183Scg149915 
825e57b9183Scg149915 	/* Red box if we have to wait for idle at any point */
826e57b9183Scg149915 	if (dev_priv->stats.boxes & RADEON_BOX_WAIT_IDLE)
827e57b9183Scg149915 		radeon_clear_box(dev_priv, 16, 4, 8, 8, 255, 0, 0);
828e57b9183Scg149915 
829e57b9183Scg149915 	/* Blue box: lost context? */
830e57b9183Scg149915 
831e57b9183Scg149915 	/* Yellow box for texture swaps */
832e57b9183Scg149915 	if (dev_priv->stats.boxes & RADEON_BOX_TEXTURE_LOAD)
833e57b9183Scg149915 		radeon_clear_box(dev_priv, 40, 4, 8, 8, 255, 255, 0);
834e57b9183Scg149915 
835e57b9183Scg149915 	/* Green box if hardware never idles (as far as we can tell) */
836e57b9183Scg149915 	if (!(dev_priv->stats.boxes & RADEON_BOX_DMA_IDLE))
837e57b9183Scg149915 		radeon_clear_box(dev_priv, 64, 4, 8, 8, 0, 255, 0);
838e57b9183Scg149915 
839e57b9183Scg149915 	/*
840e57b9183Scg149915 	 * Draw bars indicating number of buffers allocated
841e57b9183Scg149915 	 * (not a great measure, easily confused)
842e57b9183Scg149915 	 */
843e57b9183Scg149915 	if (dev_priv->stats.requested_bufs) {
844e57b9183Scg149915 		if (dev_priv->stats.requested_bufs > 100)
845e57b9183Scg149915 			dev_priv->stats.requested_bufs = 100;
846e57b9183Scg149915 
847e57b9183Scg149915 		radeon_clear_box(dev_priv, 4, 16,
848e57b9183Scg149915 		    dev_priv->stats.requested_bufs, 4, 196, 128, 128);
849e57b9183Scg149915 	}
850e57b9183Scg149915 
851e57b9183Scg149915 	(void) memset(&dev_priv->stats, 0, sizeof (dev_priv->stats));
852e57b9183Scg149915 
853e57b9183Scg149915 }
854e57b9183Scg149915 
855e57b9183Scg149915 /*
856e57b9183Scg149915  * CP command dispatch functions
857e57b9183Scg149915  */
858e57b9183Scg149915 
radeon_cp_dispatch_clear(drm_device_t * dev,drm_radeon_clear_t * clear,drm_radeon_clear_rect_t * depth_boxes)859e57b9183Scg149915 static void radeon_cp_dispatch_clear(drm_device_t *dev,
860e57b9183Scg149915     drm_radeon_clear_t *clear, drm_radeon_clear_rect_t *depth_boxes)
861e57b9183Scg149915 {
862e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
863e57b9183Scg149915 	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
864e57b9183Scg149915 	drm_radeon_depth_clear_t *depth_clear = &dev_priv->depth_clear;
865e57b9183Scg149915 	int nbox = sarea_priv->nbox;
866e57b9183Scg149915 	drm_clip_rect_t *pbox = sarea_priv->boxes;
867e57b9183Scg149915 	unsigned int flags = clear->flags;
868e57b9183Scg149915 	u32 rb3d_cntl = 0, rb3d_stencilrefmask = 0;
869e57b9183Scg149915 	int i;
870e57b9183Scg149915 	RING_LOCALS;
871e57b9183Scg149915 	DRM_DEBUG("flags = 0x%x\n", flags);
872e57b9183Scg149915 
873e57b9183Scg149915 	dev_priv->stats.clears++;
874e57b9183Scg149915 
875e57b9183Scg149915 	if (dev_priv->page_flipping && dev_priv->current_page == 1) {
876e57b9183Scg149915 		unsigned int tmp = flags;
877e57b9183Scg149915 
878e57b9183Scg149915 		flags &= ~(RADEON_FRONT | RADEON_BACK);
879e57b9183Scg149915 		if (tmp & RADEON_FRONT)
880e57b9183Scg149915 			flags |= RADEON_BACK;
881e57b9183Scg149915 		if (tmp & RADEON_BACK)
882e57b9183Scg149915 			flags |= RADEON_FRONT;
883e57b9183Scg149915 	}
884e57b9183Scg149915 
885e57b9183Scg149915 	if (flags & (RADEON_FRONT | RADEON_BACK)) {
886e57b9183Scg149915 
887e57b9183Scg149915 		BEGIN_RING(4);
888e57b9183Scg149915 
889e57b9183Scg149915 		/*
890e57b9183Scg149915 		 * Ensure the 3D stream is idle before doing a
891e57b9183Scg149915 		 * 2D fill to clear the front or back buffer.
892e57b9183Scg149915 		 */
893e57b9183Scg149915 		RADEON_WAIT_UNTIL_3D_IDLE();
894e57b9183Scg149915 
895e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0));
896e57b9183Scg149915 		OUT_RING(clear->color_mask);
897e57b9183Scg149915 
898e57b9183Scg149915 		ADVANCE_RING();
899e57b9183Scg149915 
900e57b9183Scg149915 		/* Make sure we restore the 3D state next time.  */
901e57b9183Scg149915 		dev_priv->sarea_priv->ctx_owner = 0;
902e57b9183Scg149915 
903e57b9183Scg149915 		for (i = 0; i < nbox; i++) {
904e57b9183Scg149915 			int x = pbox[i].x1;
905e57b9183Scg149915 			int y = pbox[i].y1;
906e57b9183Scg149915 			int w = pbox[i].x2 - x;
907e57b9183Scg149915 			int h = pbox[i].y2 - y;
908e57b9183Scg149915 
909e57b9183Scg149915 			DRM_DEBUG("dispatch clear %d,%d-%d,%d flags 0x%x\n",
910e57b9183Scg149915 			    x, y, w, h, flags);
911e57b9183Scg149915 
912e57b9183Scg149915 			if (flags & RADEON_FRONT) {
913e57b9183Scg149915 				BEGIN_RING(6);
914e57b9183Scg149915 
915e57b9183Scg149915 				OUT_RING(CP_PACKET3
916e57b9183Scg149915 				    (RADEON_CNTL_PAINT_MULTI, 4));
917e57b9183Scg149915 				OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
918e57b9183Scg149915 				    RADEON_GMC_BRUSH_SOLID_COLOR |
919e57b9183Scg149915 				    (dev_priv-> color_fmt << 8) |
920e57b9183Scg149915 				    RADEON_GMC_SRC_DATATYPE_COLOR |
921e57b9183Scg149915 				    RADEON_ROP3_P |
922e57b9183Scg149915 				    RADEON_GMC_CLR_CMP_CNTL_DIS);
923e57b9183Scg149915 
924e57b9183Scg149915 				OUT_RING(dev_priv->front_pitch_offset);
925e57b9183Scg149915 				OUT_RING(clear->clear_color);
926e57b9183Scg149915 
927e57b9183Scg149915 				OUT_RING((x << 16) | y);
928e57b9183Scg149915 				OUT_RING((w << 16) | h);
929e57b9183Scg149915 
930e57b9183Scg149915 				ADVANCE_RING();
931e57b9183Scg149915 			}
932e57b9183Scg149915 
933e57b9183Scg149915 			if (flags & RADEON_BACK) {
934e57b9183Scg149915 				BEGIN_RING(6);
935e57b9183Scg149915 
936e57b9183Scg149915 				OUT_RING(CP_PACKET3
937e57b9183Scg149915 				    (RADEON_CNTL_PAINT_MULTI, 4));
938e57b9183Scg149915 				OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
939e57b9183Scg149915 				    RADEON_GMC_BRUSH_SOLID_COLOR |
940e57b9183Scg149915 				    (dev_priv-> color_fmt << 8) |
941e57b9183Scg149915 				    RADEON_GMC_SRC_DATATYPE_COLOR |
942e57b9183Scg149915 				    RADEON_ROP3_P |
943e57b9183Scg149915 				    RADEON_GMC_CLR_CMP_CNTL_DIS);
944e57b9183Scg149915 
945e57b9183Scg149915 				OUT_RING(dev_priv->back_pitch_offset);
946e57b9183Scg149915 				OUT_RING(clear->clear_color);
947e57b9183Scg149915 
948e57b9183Scg149915 				OUT_RING((x << 16) | y);
949e57b9183Scg149915 				OUT_RING((w << 16) | h);
950e57b9183Scg149915 
951e57b9183Scg149915 				ADVANCE_RING();
952e57b9183Scg149915 			}
953e57b9183Scg149915 		}
954e57b9183Scg149915 	}
955e57b9183Scg149915 
956e57b9183Scg149915 	/* hyper z clear */
957e57b9183Scg149915 	/*
958e57b9183Scg149915 	 * no docs available, based on reverse engeneering
959e57b9183Scg149915 	 * by Stephane Marchesin
960e57b9183Scg149915 	 */
961e57b9183Scg149915 	if ((flags & (RADEON_DEPTH | RADEON_STENCIL)) &&
962e57b9183Scg149915 	    (flags & RADEON_CLEAR_FASTZ)) {
963e57b9183Scg149915 
964e57b9183Scg149915 		int i;
965e57b9183Scg149915 		int depthpixperline =
966e57b9183Scg149915 		    dev_priv->depth_fmt ==
967e57b9183Scg149915 		    RADEON_DEPTH_FORMAT_16BIT_INT_Z ?
968e57b9183Scg149915 		    (dev_priv->depth_pitch / 2) :
969e57b9183Scg149915 		    (dev_priv-> depth_pitch / 4);
970e57b9183Scg149915 
971e57b9183Scg149915 		u32 clearmask;
972e57b9183Scg149915 
973e57b9183Scg149915 		u32 tempRB3D_DEPTHCLEARVALUE = clear->clear_depth |
974e57b9183Scg149915 		    ((clear->depth_mask & 0xff) << 24);
975e57b9183Scg149915 
976e57b9183Scg149915 		/*
977e57b9183Scg149915 		 * Make sure we restore the 3D state next time.
978e57b9183Scg149915 		 * we haven't touched any "normal" state - still
979e57b9183Scg149915 		 * need this?
980e57b9183Scg149915 		 */
981e57b9183Scg149915 		dev_priv->sarea_priv->ctx_owner = 0;
982e57b9183Scg149915 
983e57b9183Scg149915 		if ((dev_priv->flags & RADEON_HAS_HIERZ) &&
984e57b9183Scg149915 		    (flags & RADEON_USE_HIERZ)) {
985e57b9183Scg149915 			/* FIXME : reverse engineer that for Rx00 cards */
986e57b9183Scg149915 			/*
987e57b9183Scg149915 			 * FIXME : the mask supposedly contains low-res
988e57b9183Scg149915 			 * z values. So can't set just to the max (0xff?
989e57b9183Scg149915 			 * or actually 0x3fff?), need to take z clear
990e57b9183Scg149915 			 * value into account?
991e57b9183Scg149915 			 */
992e57b9183Scg149915 			/*
993e57b9183Scg149915 			 * pattern seems to work for r100, though get
994e57b9183Scg149915 			 * slight rendering errors with glxgears. If
995e57b9183Scg149915 			 * hierz is not enabled for r100, only 4 bits
996e57b9183Scg149915 			 * which indicate clear (15,16,31,32, all zero)
997e57b9183Scg149915 			 * matter, the other ones are ignored, and the
998e57b9183Scg149915 			 * same clear mask can be used. That's very
999e57b9183Scg149915 			 * different behaviour than R200 which needs
1000e57b9183Scg149915 			 * different clear mask and different number
1001e57b9183Scg149915 			 * of tiles to clear if hierz is enabled or not !?!
1002e57b9183Scg149915 			 */
1003e57b9183Scg149915 			clearmask = (0xff << 22) | (0xff << 6) | 0x003f003f;
1004e57b9183Scg149915 		} else {
1005e57b9183Scg149915 		/*
1006e57b9183Scg149915 		 * clear mask : chooses the clearing pattern.
1007e57b9183Scg149915 		 * rv250: could be used to clear only parts of macrotiles
1008e57b9183Scg149915 		 * (but that would get really complicated...)?
1009e57b9183Scg149915 		 * bit 0 and 1 (either or both of them ?!?!) are used to
1010e57b9183Scg149915 		 * not clear tile (or maybe one of the bits indicates if
1011e57b9183Scg149915 		 * the tile is compressed or not), bit 2 and 3 to not
1012e57b9183Scg149915 		 * clear tile 1,...,.
1013e57b9183Scg149915 		 * Pattern is as follows:
1014e57b9183Scg149915 		 * | 0,1 | 4,5 | 8,9 |12,13|16,17|20,21|24,25|28,29|
1015e57b9183Scg149915 		 * bits -------------------------------------------------
1016e57b9183Scg149915 		 * | 2,3 | 6,7 |10,11|14,15|18,19|22,23|26,27|30,31|
1017e57b9183Scg149915 		 * rv100: clearmask covers 2x8 4x1 tiles, but one clear
1018e57b9183Scg149915 		 * still covers 256 pixels ?!?
1019e57b9183Scg149915 		 */
1020e57b9183Scg149915 			clearmask = 0x0;
1021e57b9183Scg149915 		}
1022e57b9183Scg149915 
1023e57b9183Scg149915 		BEGIN_RING(8);
1024e57b9183Scg149915 		RADEON_WAIT_UNTIL_2D_IDLE();
1025e57b9183Scg149915 		OUT_RING_REG(RADEON_RB3D_DEPTHCLEARVALUE,
1026e57b9183Scg149915 		    tempRB3D_DEPTHCLEARVALUE);
1027e57b9183Scg149915 		/* what offset is this exactly ? */
1028e57b9183Scg149915 		OUT_RING_REG(RADEON_RB3D_ZMASKOFFSET, 0);
1029e57b9183Scg149915 		/* need ctlstat, otherwise get some strange black flickering */
1030e57b9183Scg149915 		OUT_RING_REG(RADEON_RB3D_ZCACHE_CTLSTAT,
1031e57b9183Scg149915 		    RADEON_RB3D_ZC_FLUSH_ALL);
1032e57b9183Scg149915 		ADVANCE_RING();
1033e57b9183Scg149915 
1034e57b9183Scg149915 		for (i = 0; i < nbox; i++) {
1035e57b9183Scg149915 			int tileoffset, nrtilesx, nrtilesy, j;
1036e57b9183Scg149915 			/*
1037e57b9183Scg149915 			 * it looks like r200 needs rv-style clears, at
1038e57b9183Scg149915 			 * least if hierz is not enabled?
1039e57b9183Scg149915 			 */
1040e57b9183Scg149915 			if ((dev_priv->flags & RADEON_HAS_HIERZ) &&
1041e57b9183Scg149915 			    !(dev_priv->microcode_version == UCODE_R200)) {
1042e57b9183Scg149915 				/*
1043e57b9183Scg149915 				 * FIXME : figure this out for r200 (when hierz
1044e57b9183Scg149915 				 * is enabled). Or maybe r200 actually doesn't
1045e57b9183Scg149915 				 * need to put the low-res z value into the tile
1046e57b9183Scg149915 				 * cache like r100, but just needs to clear the
1047e57b9183Scg149915 				 * hi-level z-buffer? Works for R100, both with
1048e57b9183Scg149915 				 * hierz and without.R100 seems to operate on
1049e57b9183Scg149915 				 * 2x1 8x8 tiles, but... odd: offset/nrtiles
1050e57b9183Scg149915 				 * need to be 64 pix (4 blocka) aligned?
1051e57b9183Scg149915 				 * Potentially problematic with resolutions
1052e57b9183Scg149915 				 * which are not 64 pix aligned?
1053e57b9183Scg149915 				 */
1054e57b9183Scg149915 				tileoffset =
1055e57b9183Scg149915 				    ((pbox[i].y1 >> 3) * depthpixperline +
1056e57b9183Scg149915 				    pbox[i].x1) >> 6;
1057e57b9183Scg149915 				nrtilesx =
1058e57b9183Scg149915 				    ((pbox[i].x2 & ~63) -
1059e57b9183Scg149915 				    (pbox[i].x1 & ~63)) >> 4;
1060e57b9183Scg149915 				nrtilesy =
1061e57b9183Scg149915 				    (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3);
1062e57b9183Scg149915 				for (j = 0; j <= nrtilesy; j++) {
1063e57b9183Scg149915 					BEGIN_RING(4);
1064e57b9183Scg149915 					OUT_RING(CP_PACKET3
1065e57b9183Scg149915 					    (RADEON_3D_CLEAR_ZMASK, 2));
1066e57b9183Scg149915 					/* first tile */
1067e57b9183Scg149915 					OUT_RING(tileoffset * 8);
1068e57b9183Scg149915 					/* the number of tiles to clear */
1069e57b9183Scg149915 					OUT_RING(nrtilesx + 4);
1070e57b9183Scg149915 					/*
1071e57b9183Scg149915 					 * clear mask :
1072e57b9183Scg149915 					 * chooses the clearing pattern.
1073e57b9183Scg149915 					 */
1074e57b9183Scg149915 					OUT_RING(clearmask);
1075e57b9183Scg149915 					ADVANCE_RING();
1076e57b9183Scg149915 					tileoffset += depthpixperline >> 6;
1077e57b9183Scg149915 				}
1078e57b9183Scg149915 			} else if (dev_priv->microcode_version == UCODE_R200) {
1079e57b9183Scg149915 				/* works for rv250. */
1080e57b9183Scg149915 				/*
1081e57b9183Scg149915 				 * find first macro tile
1082e57b9183Scg149915 				 * (8x2 4x4 z-pixels on rv250)
1083e57b9183Scg149915 				 */
1084e57b9183Scg149915 				tileoffset =
1085e57b9183Scg149915 				    ((pbox[i].y1 >> 3) * depthpixperline +
1086e57b9183Scg149915 				    pbox[i].x1) >> 5;
1087e57b9183Scg149915 				nrtilesx =
1088e57b9183Scg149915 				    (pbox[i].x2 >> 5) - (pbox[i].x1 >> 5);
1089e57b9183Scg149915 				nrtilesy =
1090e57b9183Scg149915 				    (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3);
1091e57b9183Scg149915 				for (j = 0; j <= nrtilesy; j++) {
1092e57b9183Scg149915 					BEGIN_RING(4);
1093e57b9183Scg149915 					OUT_RING(CP_PACKET3
1094e57b9183Scg149915 					    (RADEON_3D_CLEAR_ZMASK, 2));
1095e57b9183Scg149915 					/* first tile */
1096e57b9183Scg149915 					/*
1097e57b9183Scg149915 					 * judging by the first tile
1098e57b9183Scg149915 					 * offset needed, could possibly
1099e57b9183Scg149915 					 * directly address/clear 4x4
1100e57b9183Scg149915 					 * tiles instead of 8x2 * 4x4
1101e57b9183Scg149915 					 * macro tiles, though would
1102e57b9183Scg149915 					 * still need clear mask for
1103e57b9183Scg149915 					 * right/bottom if truely 4x4
1104e57b9183Scg149915 					 * granularity is desired ?
1105e57b9183Scg149915 					 */
1106e57b9183Scg149915 					OUT_RING(tileoffset * 16);
1107e57b9183Scg149915 					/* the number of tiles to clear */
1108e57b9183Scg149915 					OUT_RING(nrtilesx + 1);
1109e57b9183Scg149915 					/*
1110e57b9183Scg149915 					 * clear mask :
1111e57b9183Scg149915 					 * chooses the clearing pattern.
1112e57b9183Scg149915 					 */
1113e57b9183Scg149915 					OUT_RING(clearmask);
1114e57b9183Scg149915 					ADVANCE_RING();
1115e57b9183Scg149915 					tileoffset += depthpixperline >> 5;
1116e57b9183Scg149915 				}
1117e57b9183Scg149915 			} else {	/* rv 100 */
1118e57b9183Scg149915 				/* rv100 might not need 64 pix alignment */
1119e57b9183Scg149915 				/* offsets are, hmm, weird */
1120e57b9183Scg149915 				tileoffset =
1121e57b9183Scg149915 				    ((pbox[i].y1 >> 4) * depthpixperline +
1122e57b9183Scg149915 				    pbox[i].x1) >> 6;
1123e57b9183Scg149915 				nrtilesx =
1124e57b9183Scg149915 				    ((pbox[i].x2 & ~63) -
1125e57b9183Scg149915 				    (pbox[i].x1 & ~63)) >> 4;
1126e57b9183Scg149915 				nrtilesy =
1127e57b9183Scg149915 				    (pbox[i].y2 >> 4) - (pbox[i].y1 >> 4);
1128e57b9183Scg149915 				for (j = 0; j <= nrtilesy; j++) {
1129e57b9183Scg149915 					BEGIN_RING(4);
1130e57b9183Scg149915 					OUT_RING(CP_PACKET3
1131e57b9183Scg149915 					    (RADEON_3D_CLEAR_ZMASK, 2));
1132e57b9183Scg149915 					OUT_RING(tileoffset * 128);
1133e57b9183Scg149915 					/* the number of tiles to clear */
1134e57b9183Scg149915 					OUT_RING(nrtilesx + 4);
1135e57b9183Scg149915 					/*
1136e57b9183Scg149915 					 * clear mask :
1137e57b9183Scg149915 					 * chooses the clearing pattern.
1138e57b9183Scg149915 					 */
1139e57b9183Scg149915 					OUT_RING(clearmask);
1140e57b9183Scg149915 					ADVANCE_RING();
1141e57b9183Scg149915 					tileoffset += depthpixperline >> 6;
1142e57b9183Scg149915 				}
1143e57b9183Scg149915 			}
1144e57b9183Scg149915 		}
1145e57b9183Scg149915 
1146e57b9183Scg149915 		/* TODO don't always clear all hi-level z tiles */
1147e57b9183Scg149915 		if ((dev_priv->flags & RADEON_HAS_HIERZ) &&
1148e57b9183Scg149915 		    (dev_priv->microcode_version == UCODE_R200) &&
1149e57b9183Scg149915 		    (flags & RADEON_USE_HIERZ))
1150e57b9183Scg149915 			/*
1151e57b9183Scg149915 			 * r100 and cards without hierarchical z-buffer
1152e57b9183Scg149915 			 * have no high-level z-buffer
1153e57b9183Scg149915 			 */
1154e57b9183Scg149915 			/*
1155e57b9183Scg149915 			 * FIXME : the mask supposedly contains low-res
1156e57b9183Scg149915 			 * z values. So can't set just to the max (0xff?
1157e57b9183Scg149915 			 * or actually 0x3fff?), need to take z clear value
1158e57b9183Scg149915 			 * into account?
1159e57b9183Scg149915 			 */
1160e57b9183Scg149915 		{
1161e57b9183Scg149915 			BEGIN_RING(4);
1162e57b9183Scg149915 			OUT_RING(CP_PACKET3(RADEON_3D_CLEAR_HIZ, 2));
1163e57b9183Scg149915 			OUT_RING(0x0);	/* First tile */
1164e57b9183Scg149915 			OUT_RING(0x3cc0);
1165e57b9183Scg149915 			OUT_RING((0xff << 22) | (0xff << 6) | 0x003f003f);
1166e57b9183Scg149915 			ADVANCE_RING();
1167e57b9183Scg149915 		}
1168e57b9183Scg149915 	}
1169e57b9183Scg149915 
1170e57b9183Scg149915 	/*
1171e57b9183Scg149915 	 * We have to clear the depth and/or stencil buffers by
1172e57b9183Scg149915 	 * rendering a quad into just those buffers.  Thus, we have to
1173e57b9183Scg149915 	 * make sure the 3D engine is configured correctly.
1174e57b9183Scg149915 	 */
1175e57b9183Scg149915 	else if ((dev_priv->microcode_version == UCODE_R200) &&
1176e57b9183Scg149915 	    (flags & (RADEON_DEPTH | RADEON_STENCIL))) {
1177e57b9183Scg149915 
1178e57b9183Scg149915 		int tempPP_CNTL;
1179e57b9183Scg149915 		int tempRE_CNTL;
1180e57b9183Scg149915 		int tempRB3D_CNTL;
1181e57b9183Scg149915 		int tempRB3D_ZSTENCILCNTL;
1182e57b9183Scg149915 		int tempRB3D_STENCILREFMASK;
1183e57b9183Scg149915 		int tempRB3D_PLANEMASK;
1184e57b9183Scg149915 		int tempSE_CNTL;
1185e57b9183Scg149915 		int tempSE_VTE_CNTL;
1186e57b9183Scg149915 		int tempSE_VTX_FMT_0;
1187e57b9183Scg149915 		int tempSE_VTX_FMT_1;
1188e57b9183Scg149915 		int tempSE_VAP_CNTL;
1189e57b9183Scg149915 		int tempRE_AUX_SCISSOR_CNTL;
1190e57b9183Scg149915 
1191e57b9183Scg149915 		tempPP_CNTL = 0;
1192e57b9183Scg149915 		tempRE_CNTL = 0;
1193e57b9183Scg149915 
1194e57b9183Scg149915 		tempRB3D_CNTL = depth_clear->rb3d_cntl;
1195e57b9183Scg149915 
1196e57b9183Scg149915 		tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl;
1197e57b9183Scg149915 		tempRB3D_STENCILREFMASK = 0x0;
1198e57b9183Scg149915 
1199e57b9183Scg149915 		tempSE_CNTL = depth_clear->se_cntl;
1200e57b9183Scg149915 
1201e57b9183Scg149915 		/* Disable TCL */
1202e57b9183Scg149915 
1203e57b9183Scg149915 		tempSE_VAP_CNTL =
1204e57b9183Scg149915 		    (/* SE_VAP_CNTL__FORCE_W_TO_ONE_MASK |  */
1205e57b9183Scg149915 		    (0x9 << SE_VAP_CNTL__VF_MAX_VTX_NUM__SHIFT));
1206e57b9183Scg149915 
1207e57b9183Scg149915 		tempRB3D_PLANEMASK = 0x0;
1208e57b9183Scg149915 
1209e57b9183Scg149915 		tempRE_AUX_SCISSOR_CNTL = 0x0;
1210e57b9183Scg149915 
1211e57b9183Scg149915 		tempSE_VTE_CNTL =
1212e57b9183Scg149915 		    SE_VTE_CNTL__VTX_XY_FMT_MASK | SE_VTE_CNTL__VTX_Z_FMT_MASK;
1213e57b9183Scg149915 
1214e57b9183Scg149915 		/* Vertex format (X, Y, Z, W) */
1215e57b9183Scg149915 		tempSE_VTX_FMT_0 =
1216e57b9183Scg149915 		    SE_VTX_FMT_0__VTX_Z0_PRESENT_MASK |
1217e57b9183Scg149915 		    SE_VTX_FMT_0__VTX_W0_PRESENT_MASK;
1218e57b9183Scg149915 		tempSE_VTX_FMT_1 = 0x0;
1219e57b9183Scg149915 
1220e57b9183Scg149915 		/*
1221e57b9183Scg149915 		 * Depth buffer specific enables
1222e57b9183Scg149915 		 */
1223e57b9183Scg149915 		if (flags & RADEON_DEPTH) {
1224e57b9183Scg149915 			/* Enable depth buffer */
1225e57b9183Scg149915 			tempRB3D_CNTL |= RADEON_Z_ENABLE;
1226e57b9183Scg149915 		} else {
1227e57b9183Scg149915 			/* Disable depth buffer */
1228e57b9183Scg149915 			tempRB3D_CNTL &= ~RADEON_Z_ENABLE;
1229e57b9183Scg149915 		}
1230e57b9183Scg149915 
1231e57b9183Scg149915 		/*
1232e57b9183Scg149915 		 * Stencil buffer specific enables
1233e57b9183Scg149915 		 */
1234e57b9183Scg149915 		if (flags & RADEON_STENCIL) {
1235e57b9183Scg149915 			tempRB3D_CNTL |= RADEON_STENCIL_ENABLE;
1236e57b9183Scg149915 			tempRB3D_STENCILREFMASK = clear->depth_mask;
1237e57b9183Scg149915 		} else {
1238e57b9183Scg149915 			tempRB3D_CNTL &= ~RADEON_STENCIL_ENABLE;
1239e57b9183Scg149915 			tempRB3D_STENCILREFMASK = 0x00000000;
1240e57b9183Scg149915 		}
1241e57b9183Scg149915 
1242e57b9183Scg149915 		if (flags & RADEON_USE_COMP_ZBUF) {
1243e57b9183Scg149915 			tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE |
1244e57b9183Scg149915 			    RADEON_Z_DECOMPRESSION_ENABLE;
1245e57b9183Scg149915 		}
1246e57b9183Scg149915 		if (flags & RADEON_USE_HIERZ) {
1247e57b9183Scg149915 			tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE;
1248e57b9183Scg149915 		}
1249e57b9183Scg149915 
1250e57b9183Scg149915 		BEGIN_RING(26);
1251e57b9183Scg149915 		RADEON_WAIT_UNTIL_2D_IDLE();
1252e57b9183Scg149915 
1253e57b9183Scg149915 		OUT_RING_REG(RADEON_PP_CNTL, tempPP_CNTL);
1254e57b9183Scg149915 		OUT_RING_REG(R200_RE_CNTL, tempRE_CNTL);
1255e57b9183Scg149915 		OUT_RING_REG(RADEON_RB3D_CNTL, tempRB3D_CNTL);
1256e57b9183Scg149915 		OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL);
1257e57b9183Scg149915 		OUT_RING_REG(RADEON_RB3D_STENCILREFMASK,
1258e57b9183Scg149915 		    tempRB3D_STENCILREFMASK);
1259e57b9183Scg149915 		OUT_RING_REG(RADEON_RB3D_PLANEMASK, tempRB3D_PLANEMASK);
1260e57b9183Scg149915 		OUT_RING_REG(RADEON_SE_CNTL, tempSE_CNTL);
1261e57b9183Scg149915 		OUT_RING_REG(R200_SE_VTE_CNTL, tempSE_VTE_CNTL);
1262e57b9183Scg149915 		OUT_RING_REG(R200_SE_VTX_FMT_0, tempSE_VTX_FMT_0);
1263e57b9183Scg149915 		OUT_RING_REG(R200_SE_VTX_FMT_1, tempSE_VTX_FMT_1);
1264e57b9183Scg149915 		OUT_RING_REG(R200_SE_VAP_CNTL, tempSE_VAP_CNTL);
1265e57b9183Scg149915 		OUT_RING_REG(R200_RE_AUX_SCISSOR_CNTL, tempRE_AUX_SCISSOR_CNTL);
1266e57b9183Scg149915 		ADVANCE_RING();
1267e57b9183Scg149915 
1268e57b9183Scg149915 		/* Make sure we restore the 3D state next time. */
1269e57b9183Scg149915 		dev_priv->sarea_priv->ctx_owner = 0;
1270e57b9183Scg149915 
1271e57b9183Scg149915 		for (i = 0; i < nbox; i++) {
1272e57b9183Scg149915 
1273e57b9183Scg149915 			/*
1274e57b9183Scg149915 			 * Funny that this should be required --
1275e57b9183Scg149915 			 *  sets top-left?
1276e57b9183Scg149915 			 */
1277e57b9183Scg149915 			radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
1278e57b9183Scg149915 
1279e57b9183Scg149915 			BEGIN_RING(14);
1280e57b9183Scg149915 			OUT_RING(CP_PACKET3(R200_3D_DRAW_IMMD_2, 12));
1281e57b9183Scg149915 			OUT_RING((RADEON_PRIM_TYPE_RECT_LIST |
1282e57b9183Scg149915 			    RADEON_PRIM_WALK_RING |
1283e57b9183Scg149915 			    (3 << RADEON_NUM_VERTICES_SHIFT)));
1284e57b9183Scg149915 			OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1285e57b9183Scg149915 			OUT_RING(depth_boxes[i].ui[CLEAR_Y1]);
1286e57b9183Scg149915 			OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1287e57b9183Scg149915 			OUT_RING(0x3f800000);
1288e57b9183Scg149915 			OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1289e57b9183Scg149915 			OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1290e57b9183Scg149915 			OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1291e57b9183Scg149915 			OUT_RING(0x3f800000);
1292e57b9183Scg149915 			OUT_RING(depth_boxes[i].ui[CLEAR_X2]);
1293e57b9183Scg149915 			OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1294e57b9183Scg149915 			OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1295e57b9183Scg149915 			OUT_RING(0x3f800000);
1296e57b9183Scg149915 			ADVANCE_RING();
1297e57b9183Scg149915 		}
1298e57b9183Scg149915 	} else if ((flags & (RADEON_DEPTH | RADEON_STENCIL))) {
1299e57b9183Scg149915 
1300e57b9183Scg149915 		int tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl;
1301e57b9183Scg149915 
1302e57b9183Scg149915 		rb3d_cntl = depth_clear->rb3d_cntl;
1303e57b9183Scg149915 
1304e57b9183Scg149915 		if (flags & RADEON_DEPTH) {
1305e57b9183Scg149915 			rb3d_cntl |= RADEON_Z_ENABLE;
1306e57b9183Scg149915 		} else {
1307e57b9183Scg149915 			rb3d_cntl &= ~RADEON_Z_ENABLE;
1308e57b9183Scg149915 		}
1309e57b9183Scg149915 
1310e57b9183Scg149915 		if (flags & RADEON_STENCIL) {
1311e57b9183Scg149915 			rb3d_cntl |= RADEON_STENCIL_ENABLE;
1312e57b9183Scg149915 
1313e57b9183Scg149915 			/* misnamed field */
1314e57b9183Scg149915 			rb3d_stencilrefmask = clear->depth_mask;
1315e57b9183Scg149915 
1316e57b9183Scg149915 		} else {
1317e57b9183Scg149915 			rb3d_cntl &= ~RADEON_STENCIL_ENABLE;
1318e57b9183Scg149915 			rb3d_stencilrefmask = 0x00000000;
1319e57b9183Scg149915 		}
1320e57b9183Scg149915 
1321e57b9183Scg149915 		if (flags & RADEON_USE_COMP_ZBUF) {
1322e57b9183Scg149915 			tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE |
1323e57b9183Scg149915 			    RADEON_Z_DECOMPRESSION_ENABLE;
1324e57b9183Scg149915 		}
1325e57b9183Scg149915 		if (flags & RADEON_USE_HIERZ) {
1326e57b9183Scg149915 			tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE;
1327e57b9183Scg149915 		}
1328e57b9183Scg149915 
1329e57b9183Scg149915 		BEGIN_RING(13);
1330e57b9183Scg149915 		RADEON_WAIT_UNTIL_2D_IDLE();
1331e57b9183Scg149915 
1332e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 1));
1333e57b9183Scg149915 		OUT_RING(0x00000000);
1334e57b9183Scg149915 		OUT_RING(rb3d_cntl);
1335e57b9183Scg149915 
1336e57b9183Scg149915 		OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL);
1337e57b9183Scg149915 		OUT_RING_REG(RADEON_RB3D_STENCILREFMASK, rb3d_stencilrefmask);
1338e57b9183Scg149915 		OUT_RING_REG(RADEON_RB3D_PLANEMASK, 0x00000000);
1339e57b9183Scg149915 		OUT_RING_REG(RADEON_SE_CNTL, depth_clear->se_cntl);
1340e57b9183Scg149915 		ADVANCE_RING();
1341e57b9183Scg149915 
1342e57b9183Scg149915 		/* Make sure we restore the 3D state next time.  */
1343e57b9183Scg149915 		dev_priv->sarea_priv->ctx_owner = 0;
1344e57b9183Scg149915 
1345e57b9183Scg149915 		for (i = 0; i < nbox; i++) {
1346e57b9183Scg149915 
1347e57b9183Scg149915 			/*
1348e57b9183Scg149915 			 * Funny that this should be required --
1349e57b9183Scg149915 			 *  sets top-left?
1350e57b9183Scg149915 			 */
1351e57b9183Scg149915 			radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
1352e57b9183Scg149915 
1353e57b9183Scg149915 			BEGIN_RING(15);
1354e57b9183Scg149915 
1355e57b9183Scg149915 			OUT_RING(CP_PACKET3(RADEON_3D_DRAW_IMMD, 13));
1356e57b9183Scg149915 			OUT_RING(RADEON_VTX_Z_PRESENT |
1357e57b9183Scg149915 			    RADEON_VTX_PKCOLOR_PRESENT);
1358e57b9183Scg149915 			OUT_RING((RADEON_PRIM_TYPE_RECT_LIST |
1359e57b9183Scg149915 			    RADEON_PRIM_WALK_RING |
1360e57b9183Scg149915 			    RADEON_MAOS_ENABLE |
1361e57b9183Scg149915 			    RADEON_VTX_FMT_RADEON_MODE |
1362e57b9183Scg149915 			    (3 << RADEON_NUM_VERTICES_SHIFT)));
1363e57b9183Scg149915 
1364e57b9183Scg149915 			OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1365e57b9183Scg149915 			OUT_RING(depth_boxes[i].ui[CLEAR_Y1]);
1366e57b9183Scg149915 			OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1367e57b9183Scg149915 			OUT_RING(0x0);
1368e57b9183Scg149915 
1369e57b9183Scg149915 			OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1370e57b9183Scg149915 			OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1371e57b9183Scg149915 			OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1372e57b9183Scg149915 			OUT_RING(0x0);
1373e57b9183Scg149915 
1374e57b9183Scg149915 			OUT_RING(depth_boxes[i].ui[CLEAR_X2]);
1375e57b9183Scg149915 			OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1376e57b9183Scg149915 			OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1377e57b9183Scg149915 			OUT_RING(0x0);
1378e57b9183Scg149915 
1379e57b9183Scg149915 			ADVANCE_RING();
1380e57b9183Scg149915 		}
1381e57b9183Scg149915 	}
1382e57b9183Scg149915 
1383e57b9183Scg149915 	/*
1384e57b9183Scg149915 	 * Increment the clear counter.  The client-side 3D driver must
1385e57b9183Scg149915 	 * wait on this value before performing the clear ioctl.  We
1386e57b9183Scg149915 	 * need this because the card's so damned fast...
1387e57b9183Scg149915 	 */
1388e57b9183Scg149915 	dev_priv->sarea_priv->last_clear++;
1389e57b9183Scg149915 
1390e57b9183Scg149915 	BEGIN_RING(4);
1391e57b9183Scg149915 
1392e57b9183Scg149915 	RADEON_CLEAR_AGE(dev_priv->sarea_priv->last_clear);
1393e57b9183Scg149915 	RADEON_WAIT_UNTIL_IDLE();
1394e57b9183Scg149915 
1395e57b9183Scg149915 	ADVANCE_RING();
1396e57b9183Scg149915 }
1397e57b9183Scg149915 
radeon_cp_dispatch_swap(drm_device_t * dev)1398e57b9183Scg149915 static void radeon_cp_dispatch_swap(drm_device_t *dev)
1399e57b9183Scg149915 {
1400e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
1401e57b9183Scg149915 	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
1402e57b9183Scg149915 	int nbox = sarea_priv->nbox;
1403e57b9183Scg149915 	drm_clip_rect_t *pbox = sarea_priv->boxes;
1404e57b9183Scg149915 	int i;
1405e57b9183Scg149915 	RING_LOCALS;
1406e57b9183Scg149915 
1407e57b9183Scg149915 	/* Do some trivial performance monitoring... */
1408e57b9183Scg149915 	if (dev_priv->do_boxes)
1409e57b9183Scg149915 		radeon_cp_performance_boxes(dev_priv);
1410e57b9183Scg149915 
1411e57b9183Scg149915 	/*
1412e57b9183Scg149915 	 * Wait for the 3D stream to idle before dispatching the bitblt.
1413e57b9183Scg149915 	 * This will prevent data corruption between the two streams.
1414e57b9183Scg149915 	 */
1415e57b9183Scg149915 	BEGIN_RING(2);
1416e57b9183Scg149915 
1417e57b9183Scg149915 	RADEON_WAIT_UNTIL_3D_IDLE();
1418e57b9183Scg149915 
1419e57b9183Scg149915 	ADVANCE_RING();
1420e57b9183Scg149915 
1421e57b9183Scg149915 	for (i = 0; i < nbox; i++) {
1422e57b9183Scg149915 		int x = pbox[i].x1;
1423e57b9183Scg149915 		int y = pbox[i].y1;
1424e57b9183Scg149915 		int w = pbox[i].x2 - x;
1425e57b9183Scg149915 		int h = pbox[i].y2 - y;
1426e57b9183Scg149915 
1427e57b9183Scg149915 		DRM_DEBUG("dispatch swap %d,%d-%d,%d\n", x, y, w, h);
1428e57b9183Scg149915 
1429e57b9183Scg149915 		BEGIN_RING(9);
1430e57b9183Scg149915 
1431e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_DP_GUI_MASTER_CNTL, 0));
1432e57b9183Scg149915 		OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
1433e57b9183Scg149915 		    RADEON_GMC_DST_PITCH_OFFSET_CNTL |
1434e57b9183Scg149915 		    RADEON_GMC_BRUSH_NONE |
1435e57b9183Scg149915 		    (dev_priv->color_fmt << 8) |
1436e57b9183Scg149915 		    RADEON_GMC_SRC_DATATYPE_COLOR |
1437e57b9183Scg149915 		    RADEON_ROP3_S |
1438e57b9183Scg149915 		    RADEON_DP_SRC_SOURCE_MEMORY |
1439e57b9183Scg149915 		    RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
1440e57b9183Scg149915 
1441e57b9183Scg149915 		/* Make this work even if front & back are flipped: */
1442e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1));
1443e57b9183Scg149915 		if (dev_priv->current_page == 0) {
1444e57b9183Scg149915 			OUT_RING(dev_priv->back_pitch_offset);
1445e57b9183Scg149915 			OUT_RING(dev_priv->front_pitch_offset);
1446e57b9183Scg149915 		} else {
1447e57b9183Scg149915 			OUT_RING(dev_priv->front_pitch_offset);
1448e57b9183Scg149915 			OUT_RING(dev_priv->back_pitch_offset);
1449e57b9183Scg149915 		}
1450e57b9183Scg149915 
1451e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_SRC_X_Y, 2));
1452e57b9183Scg149915 		OUT_RING((x << 16) | y);
1453e57b9183Scg149915 		OUT_RING((x << 16) | y);
1454e57b9183Scg149915 		OUT_RING((w << 16) | h);
1455e57b9183Scg149915 
1456e57b9183Scg149915 		ADVANCE_RING();
1457e57b9183Scg149915 	}
1458e57b9183Scg149915 
1459e57b9183Scg149915 	/*
1460e57b9183Scg149915 	 * Increment the frame counter.  The client-side 3D driver must
1461e57b9183Scg149915 	 * throttle the framerate by waiting for this value before
1462e57b9183Scg149915 	 * performing the swapbuffer ioctl.
1463e57b9183Scg149915 	 */
1464e57b9183Scg149915 	dev_priv->sarea_priv->last_frame ++;
1465e57b9183Scg149915 
1466e57b9183Scg149915 	BEGIN_RING(4);
1467e57b9183Scg149915 
1468e57b9183Scg149915 	RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame);
1469e57b9183Scg149915 	RADEON_WAIT_UNTIL_2D_IDLE();
1470e57b9183Scg149915 
1471e57b9183Scg149915 	ADVANCE_RING();
1472e57b9183Scg149915 }
1473e57b9183Scg149915 
radeon_cp_dispatch_flip(drm_device_t * dev)1474e57b9183Scg149915 static void radeon_cp_dispatch_flip(drm_device_t *dev)
1475e57b9183Scg149915 {
1476e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
1477e57b9183Scg149915 	drm_sarea_t *sarea = (drm_sarea_t *)dev_priv->sarea->handle;
1478e57b9183Scg149915 	int offset = (dev_priv->current_page == 1)
1479e57b9183Scg149915 	    ? dev_priv->front_offset : dev_priv->back_offset;
1480e57b9183Scg149915 	RING_LOCALS;
1481e57b9183Scg149915 	DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
1482e57b9183Scg149915 	    __FUNCTION__,
1483e57b9183Scg149915 	    dev_priv->current_page, dev_priv->sarea_priv->pfCurrentPage);
1484e57b9183Scg149915 
1485e57b9183Scg149915 	/* Do some trivial performance monitoring... */
1486e57b9183Scg149915 	if (dev_priv->do_boxes) {
1487e57b9183Scg149915 		dev_priv->stats.boxes |= RADEON_BOX_FLIP;
1488e57b9183Scg149915 		radeon_cp_performance_boxes(dev_priv);
1489e57b9183Scg149915 	}
1490e57b9183Scg149915 
1491e57b9183Scg149915 	/* Update the frame offsets for both CRTCs */
1492e57b9183Scg149915 	BEGIN_RING(6);
1493e57b9183Scg149915 
1494e57b9183Scg149915 	RADEON_WAIT_UNTIL_3D_IDLE();
1495e57b9183Scg149915 	OUT_RING_REG(RADEON_CRTC_OFFSET,
1496e57b9183Scg149915 	    ((sarea->frame.y * dev_priv->front_pitch +
1497e57b9183Scg149915 	    sarea->frame.x * (dev_priv->color_fmt - 2)) & ~7) + offset);
1498e57b9183Scg149915 	OUT_RING_REG(RADEON_CRTC2_OFFSET,
1499e57b9183Scg149915 	    dev_priv->sarea_priv->crtc2_base + offset);
1500e57b9183Scg149915 
1501e57b9183Scg149915 	ADVANCE_RING();
1502e57b9183Scg149915 
1503e57b9183Scg149915 	/*
1504e57b9183Scg149915 	 * Increment the frame counter.  The client-side 3D driver must
1505e57b9183Scg149915 	 * throttle the framerate by waiting for this value before
1506e57b9183Scg149915 	 * performing the swapbuffer ioctl.
1507e57b9183Scg149915 	 */
1508e57b9183Scg149915 	dev_priv->sarea_priv->last_frame ++;
1509e57b9183Scg149915 	dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page =
1510e57b9183Scg149915 	    1 - dev_priv->current_page;
1511e57b9183Scg149915 
1512e57b9183Scg149915 	BEGIN_RING(2);
1513e57b9183Scg149915 
1514e57b9183Scg149915 	RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame);
1515e57b9183Scg149915 
1516e57b9183Scg149915 	ADVANCE_RING();
1517e57b9183Scg149915 }
1518e57b9183Scg149915 
bad_prim_vertex_nr(int primitive,int nr)1519e57b9183Scg149915 static int bad_prim_vertex_nr(int primitive, int nr)
1520e57b9183Scg149915 {
1521e57b9183Scg149915 	switch (primitive & RADEON_PRIM_TYPE_MASK) {
1522e57b9183Scg149915 	case RADEON_PRIM_TYPE_NONE:
1523e57b9183Scg149915 	case RADEON_PRIM_TYPE_POINT:
1524e57b9183Scg149915 		return (nr < 1);
1525e57b9183Scg149915 	case RADEON_PRIM_TYPE_LINE:
1526e57b9183Scg149915 		return ((nr & 1) || nr == 0);
1527e57b9183Scg149915 	case RADEON_PRIM_TYPE_LINE_STRIP:
1528e57b9183Scg149915 		return (nr < 2);
1529e57b9183Scg149915 	case RADEON_PRIM_TYPE_TRI_LIST:
1530e57b9183Scg149915 	case RADEON_PRIM_TYPE_3VRT_POINT_LIST:
1531e57b9183Scg149915 	case RADEON_PRIM_TYPE_3VRT_LINE_LIST:
1532e57b9183Scg149915 	case RADEON_PRIM_TYPE_RECT_LIST:
1533e57b9183Scg149915 		return (nr % 3 || nr == 0);
1534e57b9183Scg149915 	case RADEON_PRIM_TYPE_TRI_FAN:
1535e57b9183Scg149915 	case RADEON_PRIM_TYPE_TRI_STRIP:
1536e57b9183Scg149915 		return (nr < 3);
1537e57b9183Scg149915 	default:
1538e57b9183Scg149915 		return (1);
1539e57b9183Scg149915 	}
1540e57b9183Scg149915 }
1541e57b9183Scg149915 
1542e57b9183Scg149915 typedef struct {
1543e57b9183Scg149915 	unsigned int start;
1544e57b9183Scg149915 	unsigned int finish;
1545e57b9183Scg149915 	unsigned int prim;
1546e57b9183Scg149915 	unsigned int numverts;
1547e57b9183Scg149915 	unsigned int offset;
1548e57b9183Scg149915 	unsigned int vc_format;
1549e57b9183Scg149915 } drm_radeon_tcl_prim_t;
1550e57b9183Scg149915 
radeon_cp_dispatch_vertex(drm_device_t * dev,drm_buf_t * buf,drm_radeon_tcl_prim_t * prim)1551e57b9183Scg149915 static void radeon_cp_dispatch_vertex(drm_device_t *dev,
1552e57b9183Scg149915     drm_buf_t *buf, drm_radeon_tcl_prim_t *prim)
1553e57b9183Scg149915 {
1554e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
1555e57b9183Scg149915 	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
1556e57b9183Scg149915 	int offset = dev_priv->gart_buffers_offset + buf->offset + prim->start;
1557e57b9183Scg149915 	int numverts = (int)prim->numverts;
1558e57b9183Scg149915 	int nbox = sarea_priv->nbox;
1559e57b9183Scg149915 	int i = 0;
1560e57b9183Scg149915 	RING_LOCALS;
1561e57b9183Scg149915 
1562e57b9183Scg149915 	DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d %d verts\n",
1563e57b9183Scg149915 	    prim->prim, prim->vc_format, prim->start,
1564e57b9183Scg149915 	    prim->finish, prim->numverts);
1565e57b9183Scg149915 
1566e57b9183Scg149915 	if (bad_prim_vertex_nr(prim->prim, prim->numverts)) {
1567e57b9183Scg149915 		DRM_ERROR("bad prim %x numverts %d\n",
1568e57b9183Scg149915 		    prim->prim, prim->numverts);
1569e57b9183Scg149915 		return;
1570e57b9183Scg149915 	}
1571e57b9183Scg149915 
1572e57b9183Scg149915 	do {
1573e57b9183Scg149915 		/* Emit the next cliprect */
1574e57b9183Scg149915 		if (i < nbox) {
1575e57b9183Scg149915 			radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
1576e57b9183Scg149915 		}
1577e57b9183Scg149915 
1578e57b9183Scg149915 		/* Emit the vertex buffer rendering commands */
1579e57b9183Scg149915 		BEGIN_RING(5);
1580e57b9183Scg149915 
1581e57b9183Scg149915 		OUT_RING(CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, 3));
1582e57b9183Scg149915 		OUT_RING(offset);
1583e57b9183Scg149915 		OUT_RING(numverts);
1584e57b9183Scg149915 		OUT_RING(prim->vc_format);
1585e57b9183Scg149915 		OUT_RING(prim->prim | RADEON_PRIM_WALK_LIST |
1586e57b9183Scg149915 		    RADEON_COLOR_ORDER_RGBA |
1587e57b9183Scg149915 		    RADEON_VTX_FMT_RADEON_MODE |
1588e57b9183Scg149915 		    (numverts << RADEON_NUM_VERTICES_SHIFT));
1589e57b9183Scg149915 
1590e57b9183Scg149915 		ADVANCE_RING();
1591e57b9183Scg149915 
1592e57b9183Scg149915 		i++;
1593e57b9183Scg149915 	} while (i < nbox);
1594e57b9183Scg149915 }
1595e57b9183Scg149915 
radeon_cp_discard_buffer(drm_device_t * dev,drm_buf_t * buf)1596e57b9183Scg149915 static void radeon_cp_discard_buffer(drm_device_t *dev, drm_buf_t *buf)
1597e57b9183Scg149915 {
1598e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
1599e57b9183Scg149915 	drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
1600e57b9183Scg149915 	RING_LOCALS;
1601e57b9183Scg149915 
1602e57b9183Scg149915 	buf_priv->age = ++dev_priv->sarea_priv->last_dispatch;
1603e57b9183Scg149915 
1604e57b9183Scg149915 	/* Emit the vertex buffer age */
1605e57b9183Scg149915 	BEGIN_RING(2);
1606e57b9183Scg149915 	RADEON_DISPATCH_AGE(buf_priv->age);
1607e57b9183Scg149915 	ADVANCE_RING();
1608e57b9183Scg149915 
1609e57b9183Scg149915 	buf->pending = 1;
1610e57b9183Scg149915 	buf->used = 0;
1611e57b9183Scg149915 }
1612e57b9183Scg149915 
radeon_cp_dispatch_indirect(drm_device_t * dev,drm_buf_t * buf,int start,int end)1613e57b9183Scg149915 static void radeon_cp_dispatch_indirect(drm_device_t *dev,
1614e57b9183Scg149915     drm_buf_t *buf, int start, int end)
1615e57b9183Scg149915 {
1616e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
1617e57b9183Scg149915 	RING_LOCALS;
1618e57b9183Scg149915 	DRM_DEBUG("indirect: buf=%d s=0x%x e=0x%x\n", buf->idx, start, end);
1619e57b9183Scg149915 
1620e57b9183Scg149915 	if (start != end) {
1621e57b9183Scg149915 		int offset = (dev_priv->gart_buffers_offset +
1622e57b9183Scg149915 		    buf->offset + start);
1623e57b9183Scg149915 		int dwords = (end - start + 3) / sizeof (u32);
1624e57b9183Scg149915 
1625e57b9183Scg149915 		/*
1626e57b9183Scg149915 		 * Indirect buffer data must be an even number of
1627e57b9183Scg149915 		 * dwords, so if we've been given an odd number we must
1628e57b9183Scg149915 		 * pad the data with a Type-2 CP packet.
1629e57b9183Scg149915 		 */
1630e57b9183Scg149915 		if (dwords & 1) {
1631e57b9183Scg149915 			u32 *data = (u32 *)(uintptr_t)
1632e57b9183Scg149915 			    ((char *)dev->agp_buffer_map->handle
1633e57b9183Scg149915 			    + buf->offset + start);
1634e57b9183Scg149915 			data[dwords++] = RADEON_CP_PACKET2;
1635e57b9183Scg149915 		}
1636e57b9183Scg149915 
1637e57b9183Scg149915 		/* Fire off the indirect buffer */
1638e57b9183Scg149915 		BEGIN_RING(3);
1639e57b9183Scg149915 
1640e57b9183Scg149915 		OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1));
1641e57b9183Scg149915 		OUT_RING(offset);
1642e57b9183Scg149915 		OUT_RING(dwords);
1643e57b9183Scg149915 
1644e57b9183Scg149915 		ADVANCE_RING();
1645e57b9183Scg149915 	}
1646e57b9183Scg149915 }
1647e57b9183Scg149915 
radeon_cp_dispatch_indices(drm_device_t * dev,drm_buf_t * elt_buf,drm_radeon_tcl_prim_t * prim)1648e57b9183Scg149915 static void radeon_cp_dispatch_indices(drm_device_t *dev,
1649e57b9183Scg149915     drm_buf_t *elt_buf, drm_radeon_tcl_prim_t *prim)
1650e57b9183Scg149915 {
1651e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
1652e57b9183Scg149915 	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
1653e57b9183Scg149915 	int offset = dev_priv->gart_buffers_offset + prim->offset;
1654e57b9183Scg149915 	u32 *data;
1655e57b9183Scg149915 	int dwords;
1656e57b9183Scg149915 	int i = 0;
1657e57b9183Scg149915 	int start = prim->start + RADEON_INDEX_PRIM_OFFSET;
1658e57b9183Scg149915 	int count = (prim->finish - start) / sizeof (u16);
1659e57b9183Scg149915 	int nbox = sarea_priv->nbox;
1660e57b9183Scg149915 
1661e57b9183Scg149915 	DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d offset: %x nr %d\n",
1662e57b9183Scg149915 	    prim->prim, prim->vc_format, prim->start,
1663e57b9183Scg149915 	    prim->finish, prim->offset, prim->numverts);
1664e57b9183Scg149915 
1665e57b9183Scg149915 	if (bad_prim_vertex_nr(prim->prim, count)) {
1666e57b9183Scg149915 		DRM_ERROR("bad prim %x count %d\n", prim->prim, count);
1667e57b9183Scg149915 		return;
1668e57b9183Scg149915 	}
1669e57b9183Scg149915 
1670e57b9183Scg149915 	if (start >= prim->finish || (prim->start & 0x7)) {
1671e57b9183Scg149915 		DRM_ERROR("buffer prim %d\n", prim->prim);
1672e57b9183Scg149915 		return;
1673e57b9183Scg149915 	}
1674e57b9183Scg149915 
1675e57b9183Scg149915 	dwords = (prim->finish - prim->start + 3) / sizeof (u32);
1676e57b9183Scg149915 
1677e57b9183Scg149915 	data = (u32 *)(uintptr_t)((char *)dev->agp_buffer_map->handle +
1678e57b9183Scg149915 	    elt_buf->offset + prim->start);
1679e57b9183Scg149915 
1680e57b9183Scg149915 	data[0] = CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, dwords - 2);
1681e57b9183Scg149915 	data[1] = offset;
1682e57b9183Scg149915 	data[2] = prim->numverts;
1683e57b9183Scg149915 	data[3] = prim->vc_format;
1684e57b9183Scg149915 	data[4] = (prim->prim |
1685e57b9183Scg149915 	    RADEON_PRIM_WALK_IND |
1686e57b9183Scg149915 	    RADEON_COLOR_ORDER_RGBA |
1687e57b9183Scg149915 	    RADEON_VTX_FMT_RADEON_MODE |
1688e57b9183Scg149915 	    (count << RADEON_NUM_VERTICES_SHIFT));
1689e57b9183Scg149915 
1690e57b9183Scg149915 	do {
1691e57b9183Scg149915 		if (i < nbox)
1692e57b9183Scg149915 			radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
1693e57b9183Scg149915 
1694e57b9183Scg149915 		radeon_cp_dispatch_indirect(dev, elt_buf,
1695e57b9183Scg149915 		    prim->start, prim->finish);
1696e57b9183Scg149915 
1697e57b9183Scg149915 		i++;
1698e57b9183Scg149915 	} while (i < nbox);
1699e57b9183Scg149915 
1700e57b9183Scg149915 }
1701e57b9183Scg149915 
1702e57b9183Scg149915 #define	RADEON_MAX_TEXTURE_SIZE RADEON_BUFFER_SIZE
1703e57b9183Scg149915 
1704e57b9183Scg149915 /*ARGSUSED*/
radeon_cp_dispatch_texture(drm_file_t * fpriv,drm_device_t * dev,drm_radeon_texture_t * tex,drm_radeon_tex_image_t * image,int mode)1705e57b9183Scg149915 static int radeon_cp_dispatch_texture(drm_file_t *fpriv,
1706e57b9183Scg149915     drm_device_t *dev, drm_radeon_texture_t *tex,
1707e57b9183Scg149915     drm_radeon_tex_image_t *image, int mode)
1708e57b9183Scg149915 {
1709e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
1710e57b9183Scg149915 	drm_buf_t *buf;
1711e57b9183Scg149915 	u32 format;
1712e57b9183Scg149915 	u32 *buffer;
1713e57b9183Scg149915 	const u8 __user *data;
1714e57b9183Scg149915 	int size, dwords, tex_width, blit_width, spitch;
1715e57b9183Scg149915 	u32 height;
1716e57b9183Scg149915 	int i;
1717e57b9183Scg149915 	u32 texpitch, microtile;
1718e57b9183Scg149915 	u32 offset;
1719e57b9183Scg149915 	RING_LOCALS;
1720e57b9183Scg149915 
1721e57b9183Scg149915 
1722e57b9183Scg149915 	if (radeon_check_and_fixup_offset(dev_priv, fpriv, &tex->offset)) {
1723e57b9183Scg149915 		DRM_ERROR("Invalid destination offset\n");
1724e57b9183Scg149915 		return (EINVAL);
1725e57b9183Scg149915 	}
1726e57b9183Scg149915 
1727e57b9183Scg149915 	dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD;
1728e57b9183Scg149915 
1729e57b9183Scg149915 	/*
1730e57b9183Scg149915 	 * Flush the pixel cache.  This ensures no pixel data gets mixed
1731e57b9183Scg149915 	 * up with the texture data from the host data blit, otherwise
1732e57b9183Scg149915 	 * part of the texture image may be corrupted.
1733e57b9183Scg149915 	 */
1734e57b9183Scg149915 	BEGIN_RING(4);
1735e57b9183Scg149915 	RADEON_FLUSH_CACHE();
1736e57b9183Scg149915 	RADEON_WAIT_UNTIL_IDLE();
1737e57b9183Scg149915 	ADVANCE_RING();
1738e57b9183Scg149915 
1739e57b9183Scg149915 	/*
1740e57b9183Scg149915 	 * The compiler won't optimize away a division by a variable,
1741e57b9183Scg149915 	 * even if the only legal values are powers of two.  Thus, we'll
1742e57b9183Scg149915 	 * use a shift instead.
1743e57b9183Scg149915 	 */
1744e57b9183Scg149915 	switch (tex->format) {
1745e57b9183Scg149915 	case RADEON_TXFORMAT_ARGB8888:
1746e57b9183Scg149915 	case RADEON_TXFORMAT_RGBA8888:
1747e57b9183Scg149915 		format = RADEON_COLOR_FORMAT_ARGB8888;
1748e57b9183Scg149915 		tex_width = tex->width * 4;
1749e57b9183Scg149915 		blit_width = image->width * 4;
1750e57b9183Scg149915 		break;
1751e57b9183Scg149915 	case RADEON_TXFORMAT_AI88:
1752e57b9183Scg149915 	case RADEON_TXFORMAT_ARGB1555:
1753e57b9183Scg149915 	case RADEON_TXFORMAT_RGB565:
1754e57b9183Scg149915 	case RADEON_TXFORMAT_ARGB4444:
1755e57b9183Scg149915 	case RADEON_TXFORMAT_VYUY422:
1756e57b9183Scg149915 	case RADEON_TXFORMAT_YVYU422:
1757e57b9183Scg149915 		format = RADEON_COLOR_FORMAT_RGB565;
1758e57b9183Scg149915 		tex_width = tex->width * 2;
1759e57b9183Scg149915 		blit_width = image->width * 2;
1760e57b9183Scg149915 		break;
1761e57b9183Scg149915 	case RADEON_TXFORMAT_I8:
1762e57b9183Scg149915 	case RADEON_TXFORMAT_RGB332:
1763e57b9183Scg149915 		format = RADEON_COLOR_FORMAT_CI8;
1764e57b9183Scg149915 		tex_width = tex->width * 1;
1765e57b9183Scg149915 		blit_width = image->width * 1;
1766e57b9183Scg149915 		break;
1767e57b9183Scg149915 	default:
1768e57b9183Scg149915 		DRM_ERROR("invalid texture format %d\n", tex->format);
1769e57b9183Scg149915 		return (EINVAL);
1770e57b9183Scg149915 	}
1771e57b9183Scg149915 	spitch = blit_width >> 6;
1772e57b9183Scg149915 	if (spitch == 0 && image->height > 1)
1773e57b9183Scg149915 		return (EINVAL);
1774e57b9183Scg149915 
1775e57b9183Scg149915 	texpitch = tex->pitch;
1776e57b9183Scg149915 	if ((texpitch << 22) & RADEON_DST_TILE_MICRO) {
1777e57b9183Scg149915 		microtile = 1;
1778e57b9183Scg149915 		if (tex_width < 64) {
1779e57b9183Scg149915 			texpitch &= ~(RADEON_DST_TILE_MICRO >> 22);
1780e57b9183Scg149915 			/* we got tiled coordinates, untile them */
1781e57b9183Scg149915 			image->x *= 2;
1782e57b9183Scg149915 		}
1783e57b9183Scg149915 	} else
1784e57b9183Scg149915 		microtile = 0;
1785e57b9183Scg149915 
1786e57b9183Scg149915 	DRM_DEBUG("tex=%dx%d blit=%d\n", tex_width, tex->height, blit_width);
1787e57b9183Scg149915 
1788e57b9183Scg149915 	do {
1789e57b9183Scg149915 		DRM_DEBUG("tex: ofs=0x%x p=%d f=%d x=%hd y=%hd w=%hd h=%hd\n",
1790e57b9183Scg149915 		    tex->offset >> 10, tex->pitch, tex->format,
1791e57b9183Scg149915 		    image->x, image->y, image->width, image->height);
1792e57b9183Scg149915 
1793e57b9183Scg149915 		/*
1794e57b9183Scg149915 		 * Make a copy of some parameters in case we have to
1795e57b9183Scg149915 		 * update them for a multi-pass texture blit.
1796e57b9183Scg149915 		 */
1797e57b9183Scg149915 		height = image->height;
1798e57b9183Scg149915 		data = (const u8 __user *)image->data;
1799e57b9183Scg149915 
1800e57b9183Scg149915 		size = height * blit_width;
1801e57b9183Scg149915 
1802e57b9183Scg149915 		if (size > RADEON_MAX_TEXTURE_SIZE) {
1803e57b9183Scg149915 			height = RADEON_MAX_TEXTURE_SIZE / blit_width;
1804e57b9183Scg149915 			size = height * blit_width;
1805e57b9183Scg149915 		} else if (size < 4 && size > 0) {
1806e57b9183Scg149915 			size = 4;
1807e57b9183Scg149915 		} else if (size == 0) {
1808e57b9183Scg149915 			return (0);
1809e57b9183Scg149915 		}
1810e57b9183Scg149915 
1811e57b9183Scg149915 		buf = radeon_freelist_get(dev);
1812e57b9183Scg149915 #if 0
1813e57b9183Scg149915 		if (0 && !buf) {
1814e57b9183Scg149915 			radeon_do_cp_idle(dev_priv);
1815e57b9183Scg149915 			buf = radeon_freelist_get(dev);
1816e57b9183Scg149915 		}
1817e57b9183Scg149915 #endif
1818e57b9183Scg149915 		if (!buf) {
1819e57b9183Scg149915 			DRM_DEBUG("radeon_cp_dispatch_texture: EAGAIN\n");
1820e57b9183Scg149915 
1821e57b9183Scg149915 #ifdef _MULTI_DATAMODEL
1822e57b9183Scg149915 			if (ddi_model_convert_from(mode & FMODELS) ==
1823e57b9183Scg149915 			    DDI_MODEL_ILP32) {
1824e57b9183Scg149915 				drm_radeon_tex_image_32_t image32;
1825e57b9183Scg149915 				image32.x = image->x;
1826e57b9183Scg149915 				image32.y = image->y;
1827e57b9183Scg149915 				image32.width = image->width;
1828e57b9183Scg149915 				image32.height = image->height;
1829e57b9183Scg149915 				image32.data = (uint32_t)(uintptr_t)image->data;
1830e57b9183Scg149915 				DRM_COPYTO_WITH_RETURN(tex->image, &image32,
1831e57b9183Scg149915 				    sizeof (image32));
1832e57b9183Scg149915 			} else {
1833e57b9183Scg149915 #endif
1834e57b9183Scg149915 				DRM_COPYTO_WITH_RETURN(tex->image, image,
1835e57b9183Scg149915 				    sizeof (*image));
1836e57b9183Scg149915 #ifdef _MULTI_DATAMODEL
1837e57b9183Scg149915 			}
1838e57b9183Scg149915 #endif
1839e57b9183Scg149915 			return (EAGAIN);
1840e57b9183Scg149915 		}
1841e57b9183Scg149915 
1842e57b9183Scg149915 		/*
1843e57b9183Scg149915 		 * Dispatch the indirect buffer.
1844e57b9183Scg149915 		 */
1845e57b9183Scg149915 		buffer = (u32 *)(uintptr_t)
1846e57b9183Scg149915 		    ((char *)dev->agp_buffer_map->handle + buf->offset);
1847e57b9183Scg149915 
1848e57b9183Scg149915 		dwords = size / 4;
1849e57b9183Scg149915 
1850e57b9183Scg149915 #define	RADEON_COPY_MT(_buf, _data, _width) \
1851e57b9183Scg149915 	do { \
1852e57b9183Scg149915 		if (DRM_COPY_FROM_USER(_buf, _data, (_width))) {\
1853e57b9183Scg149915 			DRM_ERROR("%d: EFAULT on pad, %d bytes\n", \
1854e57b9183Scg149915 			    __LINE__, (_width)); \
1855e57b9183Scg149915 			return (EFAULT); \
1856e57b9183Scg149915 		} \
1857e57b9183Scg149915 	} while (*"\0")
1858e57b9183Scg149915 
1859e57b9183Scg149915 		if (microtile) {
1860e57b9183Scg149915 			/*
1861e57b9183Scg149915 			 * texture micro tiling in use, minimum texture
1862e57b9183Scg149915 			 * width is thus 16 bytes. however, we cannot use
1863e57b9183Scg149915 			 * blitter directly for texture width < 64 bytes,
1864e57b9183Scg149915 			 * since minimum tex pitch is 64 bytes and we need
1865e57b9183Scg149915 			 * this to match the texture width, otherwise the
1866e57b9183Scg149915 			 * blitter will tile it wrong. Thus, tiling manually
1867e57b9183Scg149915 			 * in this case. Additionally, need to special case
1868e57b9183Scg149915 			 * tex height = 1, since our actual image will have
1869e57b9183Scg149915 			 * height 2 and we need to ensure we don't read
1870e57b9183Scg149915 			 * beyond the texture size from user space.
1871e57b9183Scg149915 			 */
1872e57b9183Scg149915 			if (tex->height == 1) {
1873e57b9183Scg149915 				if (tex_width >= 64 || tex_width <= 16) {
1874e57b9183Scg149915 					RADEON_COPY_MT(buffer, data,
1875e57b9183Scg149915 					    (int)(tex_width * sizeof (u32)));
1876e57b9183Scg149915 				} else if (tex_width == 32) {
1877e57b9183Scg149915 					RADEON_COPY_MT(buffer, data, 16);
1878e57b9183Scg149915 					RADEON_COPY_MT(buffer + 8,
1879e57b9183Scg149915 					    data + 16, 16);
1880e57b9183Scg149915 				}
1881e57b9183Scg149915 			} else if (tex_width >= 64 || tex_width == 16) {
1882e57b9183Scg149915 				RADEON_COPY_MT(buffer, data,
1883e57b9183Scg149915 				    (int)(dwords * sizeof (u32)));
1884e57b9183Scg149915 			} else if (tex_width < 16) {
1885e57b9183Scg149915 				for (i = 0; i < tex->height; i++) {
1886e57b9183Scg149915 					RADEON_COPY_MT(buffer, data, tex_width);
1887e57b9183Scg149915 					buffer += 4;
1888e57b9183Scg149915 					data += tex_width;
1889e57b9183Scg149915 				}
1890e57b9183Scg149915 			} else if (tex_width == 32) {
1891e57b9183Scg149915 				/*
1892e57b9183Scg149915 				 * TODO: make sure this works when not
1893e57b9183Scg149915 				 * fitting in one buffer
1894e57b9183Scg149915 				 *  (i.e. 32bytes x 2048...)
1895e57b9183Scg149915 				 */
1896e57b9183Scg149915 				for (i = 0; i < tex->height; i += 2) {
1897e57b9183Scg149915 					RADEON_COPY_MT(buffer, data, 16);
1898e57b9183Scg149915 					data += 16;
1899e57b9183Scg149915 					RADEON_COPY_MT(buffer + 8, data, 16);
1900e57b9183Scg149915 					data += 16;
1901e57b9183Scg149915 					RADEON_COPY_MT(buffer + 4, data, 16);
1902e57b9183Scg149915 					data += 16;
1903e57b9183Scg149915 					RADEON_COPY_MT(buffer + 12, data, 16);
1904e57b9183Scg149915 					data += 16;
1905e57b9183Scg149915 					buffer += 16;
1906e57b9183Scg149915 				}
1907e57b9183Scg149915 			}
1908e57b9183Scg149915 		} else {
1909e57b9183Scg149915 			if (tex_width >= 32) {
1910e57b9183Scg149915 				/*
1911e57b9183Scg149915 				 * Texture image width is larger than the
1912e57b9183Scg149915 				 * minimum, so we can upload it directly.
1913e57b9183Scg149915 				 */
1914e57b9183Scg149915 				RADEON_COPY_MT(buffer, data,
1915e57b9183Scg149915 				    (int)(dwords * sizeof (u32)));
1916e57b9183Scg149915 			} else {
1917e57b9183Scg149915 				/*
1918e57b9183Scg149915 				 * Texture image width is less than the minimum,
1919e57b9183Scg149915 				 * so we need to pad out each image scanline to
1920e57b9183Scg149915 				 * the minimum width.
1921e57b9183Scg149915 				 */
1922e57b9183Scg149915 				for (i = 0; i < tex->height; i++) {
1923e57b9183Scg149915 					RADEON_COPY_MT(buffer, data, tex_width);
1924e57b9183Scg149915 					buffer += 8;
1925e57b9183Scg149915 					data += tex_width;
1926e57b9183Scg149915 				}
1927e57b9183Scg149915 			}
1928e57b9183Scg149915 		}
1929e57b9183Scg149915 
1930e57b9183Scg149915 #undef RADEON_COPY_MT
1931e57b9183Scg149915 		buf->filp = fpriv;
1932e57b9183Scg149915 		buf->used = size;
1933e57b9183Scg149915 		offset = dev_priv->gart_buffers_offset + buf->offset;
1934e57b9183Scg149915 
1935e57b9183Scg149915 		BEGIN_RING(9);
1936e57b9183Scg149915 		OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
1937e57b9183Scg149915 		OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
1938e57b9183Scg149915 		    RADEON_GMC_DST_PITCH_OFFSET_CNTL |
1939e57b9183Scg149915 		    RADEON_GMC_BRUSH_NONE |
1940e57b9183Scg149915 		    (format << 8) |
1941e57b9183Scg149915 		    RADEON_GMC_SRC_DATATYPE_COLOR |
1942e57b9183Scg149915 		    RADEON_ROP3_S |
1943e57b9183Scg149915 		    RADEON_DP_SRC_SOURCE_MEMORY |
1944e57b9183Scg149915 		    RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
1945e57b9183Scg149915 		OUT_RING((spitch << 22) | (offset >> 10));
1946e57b9183Scg149915 		OUT_RING((texpitch << 22) | (tex->offset >> 10));
1947e57b9183Scg149915 		OUT_RING(0);
1948e57b9183Scg149915 		OUT_RING((image->x << 16) | image->y);
1949e57b9183Scg149915 		OUT_RING((image->width << 16) | height);
1950e57b9183Scg149915 		RADEON_WAIT_UNTIL_2D_IDLE();
1951e57b9183Scg149915 		ADVANCE_RING();
1952e57b9183Scg149915 		COMMIT_RING();
1953e57b9183Scg149915 
1954e57b9183Scg149915 
1955e57b9183Scg149915 		radeon_cp_discard_buffer(dev, buf);
1956e57b9183Scg149915 
1957e57b9183Scg149915 		/* Update the input parameters for next time */
1958e57b9183Scg149915 		image->y += height;
1959e57b9183Scg149915 		image->height -= height;
1960e57b9183Scg149915 		image->data = (const u8 __user *)image->data + size;
1961e57b9183Scg149915 	} while (image->height > 0);
1962e57b9183Scg149915 
1963e57b9183Scg149915 	/*
1964e57b9183Scg149915 	 * Flush the pixel cache after the blit completes.  This ensures
1965e57b9183Scg149915 	 * the texture data is written out to memory before rendering
1966e57b9183Scg149915 	 * continues.
1967e57b9183Scg149915 	 */
1968e57b9183Scg149915 	BEGIN_RING(4);
1969e57b9183Scg149915 	RADEON_FLUSH_CACHE();
1970e57b9183Scg149915 	RADEON_WAIT_UNTIL_2D_IDLE();
1971e57b9183Scg149915 	ADVANCE_RING();
1972e57b9183Scg149915 	COMMIT_RING();
1973e57b9183Scg149915 	return (0);
1974e57b9183Scg149915 }
1975e57b9183Scg149915 
radeon_cp_dispatch_stipple(drm_device_t * dev,u32 * stipple)1976e57b9183Scg149915 static void radeon_cp_dispatch_stipple(drm_device_t *dev, u32 *stipple)
1977e57b9183Scg149915 {
1978e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
1979e57b9183Scg149915 	int i;
1980e57b9183Scg149915 	RING_LOCALS;
1981e57b9183Scg149915 	DRM_DEBUG("\n");
1982e57b9183Scg149915 
1983e57b9183Scg149915 	BEGIN_RING(35);
1984e57b9183Scg149915 
1985e57b9183Scg149915 	OUT_RING(CP_PACKET0(RADEON_RE_STIPPLE_ADDR, 0));
1986e57b9183Scg149915 	OUT_RING(0x00000000);
1987e57b9183Scg149915 
1988e57b9183Scg149915 	OUT_RING(CP_PACKET0_TABLE(RADEON_RE_STIPPLE_DATA, 31));
1989e57b9183Scg149915 	for (i = 0; i < 32; i++) {
1990e57b9183Scg149915 		OUT_RING(stipple[i]);
1991e57b9183Scg149915 	}
1992e57b9183Scg149915 
1993e57b9183Scg149915 	ADVANCE_RING();
1994e57b9183Scg149915 }
1995e57b9183Scg149915 
radeon_apply_surface_regs(int surf_index,drm_radeon_private_t * dev_priv)1996e57b9183Scg149915 static void radeon_apply_surface_regs(int surf_index,
1997e57b9183Scg149915     drm_radeon_private_t *dev_priv)
1998e57b9183Scg149915 {
1999e57b9183Scg149915 	if (!dev_priv->mmio)
2000e57b9183Scg149915 		return;
2001e57b9183Scg149915 
2002e57b9183Scg149915 	(void) radeon_do_cp_idle(dev_priv);
2003e57b9183Scg149915 
2004e57b9183Scg149915 	RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * surf_index,
2005e57b9183Scg149915 	    dev_priv->surfaces[surf_index].flags);
2006e57b9183Scg149915 	RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND + 16 * surf_index,
2007e57b9183Scg149915 	    dev_priv->surfaces[surf_index].lower);
2008e57b9183Scg149915 	RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND + 16 * surf_index,
2009e57b9183Scg149915 	    dev_priv->surfaces[surf_index].upper);
2010e57b9183Scg149915 }
2011e57b9183Scg149915 
2012e57b9183Scg149915 /*
2013e57b9183Scg149915  * Allocates a virtual surface
2014e57b9183Scg149915  * doesn't always allocate a real surface, will stretch an existing
2015e57b9183Scg149915  * surface when possible.
2016e57b9183Scg149915  *
2017e57b9183Scg149915  * Note that refcount can be at most 2, since during a free refcount=3
2018e57b9183Scg149915  * might mean we have to allocate a new surface which might not always
2019e57b9183Scg149915  * be available.
2020e57b9183Scg149915  * For example : we allocate three contigous surfaces ABC. If B is
2021e57b9183Scg149915  * freed, we suddenly need two surfaces to store A and C, which might
2022e57b9183Scg149915  * not always be available.
2023e57b9183Scg149915  */
alloc_surface(drm_radeon_surface_alloc_t * new,drm_radeon_private_t * dev_priv,drm_file_t * filp)2024e57b9183Scg149915 static int alloc_surface(drm_radeon_surface_alloc_t *new,
2025e57b9183Scg149915     drm_radeon_private_t *dev_priv, drm_file_t *filp)
2026e57b9183Scg149915 {
2027e57b9183Scg149915 	struct radeon_virt_surface *s;
2028e57b9183Scg149915 	int i;
2029e57b9183Scg149915 	int virt_surface_index;
2030e57b9183Scg149915 	uint32_t new_upper, new_lower;
2031e57b9183Scg149915 
2032e57b9183Scg149915 	new_lower = new->address;
2033e57b9183Scg149915 	new_upper = new_lower + new->size - 1;
2034e57b9183Scg149915 
2035e57b9183Scg149915 	/* sanity check */
2036e57b9183Scg149915 	if ((new_lower >= new_upper) || (new->flags == 0) || (new->size == 0) ||
2037e57b9183Scg149915 	    ((new_upper & RADEON_SURF_ADDRESS_FIXED_MASK) !=
2038e57b9183Scg149915 	    RADEON_SURF_ADDRESS_FIXED_MASK) ||
2039e57b9183Scg149915 	    ((new_lower & RADEON_SURF_ADDRESS_FIXED_MASK) != 0))
2040e57b9183Scg149915 		return (-1);
2041e57b9183Scg149915 
2042e57b9183Scg149915 	/* make sure there is no overlap with existing surfaces */
2043e57b9183Scg149915 	for (i = 0; i < RADEON_MAX_SURFACES; i++) {
2044e57b9183Scg149915 		if ((dev_priv->surfaces[i].refcount != 0) &&
2045e57b9183Scg149915 		    (((new_lower >= dev_priv->surfaces[i].lower) &&
2046e57b9183Scg149915 		    (new_lower < dev_priv->surfaces[i].upper)) ||
2047e57b9183Scg149915 		    ((new_lower < dev_priv->surfaces[i].lower) &&
2048e57b9183Scg149915 		    (new_upper > dev_priv->surfaces[i].lower)))) {
2049e57b9183Scg149915 			return (-1);
2050e57b9183Scg149915 		}
2051e57b9183Scg149915 	}
2052e57b9183Scg149915 
2053e57b9183Scg149915 	/* find a virtual surface */
2054e57b9183Scg149915 	for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++)
2055e57b9183Scg149915 		if (dev_priv->virt_surfaces[i].filp == 0)
2056e57b9183Scg149915 			break;
2057e57b9183Scg149915 	if (i == 2 * RADEON_MAX_SURFACES) {
2058e57b9183Scg149915 		return (-1);
2059e57b9183Scg149915 	}
2060e57b9183Scg149915 	virt_surface_index = i;
2061e57b9183Scg149915 
2062e57b9183Scg149915 	/* try to reuse an existing surface */
2063e57b9183Scg149915 	for (i = 0; i < RADEON_MAX_SURFACES; i++) {
2064e57b9183Scg149915 		/* extend before */
2065e57b9183Scg149915 		if ((dev_priv->surfaces[i].refcount == 1) &&
2066e57b9183Scg149915 		    (new->flags == dev_priv->surfaces[i].flags) &&
2067e57b9183Scg149915 		    (new_upper + 1 == dev_priv->surfaces[i].lower)) {
2068e57b9183Scg149915 			s = &(dev_priv->virt_surfaces[virt_surface_index]);
2069e57b9183Scg149915 			s->surface_index = i;
2070e57b9183Scg149915 			s->lower = new_lower;
2071e57b9183Scg149915 			s->upper = new_upper;
2072e57b9183Scg149915 			s->flags = new->flags;
2073e57b9183Scg149915 			s->filp = filp;
2074e57b9183Scg149915 			dev_priv->surfaces[i].refcount++;
2075e57b9183Scg149915 			dev_priv->surfaces[i].lower = s->lower;
2076e57b9183Scg149915 			radeon_apply_surface_regs(s->surface_index, dev_priv);
2077e57b9183Scg149915 			return (virt_surface_index);
2078e57b9183Scg149915 		}
2079e57b9183Scg149915 
2080e57b9183Scg149915 		/* extend after */
2081e57b9183Scg149915 		if ((dev_priv->surfaces[i].refcount == 1) &&
2082e57b9183Scg149915 		    (new->flags == dev_priv->surfaces[i].flags) &&
2083e57b9183Scg149915 		    (new_lower == dev_priv->surfaces[i].upper + 1)) {
2084e57b9183Scg149915 			s = &(dev_priv->virt_surfaces[virt_surface_index]);
2085e57b9183Scg149915 			s->surface_index = i;
2086e57b9183Scg149915 			s->lower = new_lower;
2087e57b9183Scg149915 			s->upper = new_upper;
2088e57b9183Scg149915 			s->flags = new->flags;
2089e57b9183Scg149915 			s->filp = filp;
2090e57b9183Scg149915 			dev_priv->surfaces[i].refcount++;
2091e57b9183Scg149915 			dev_priv->surfaces[i].upper = s->upper;
2092e57b9183Scg149915 			radeon_apply_surface_regs(s->surface_index, dev_priv);
2093e57b9183Scg149915 			return (virt_surface_index);
2094e57b9183Scg149915 		}
2095e57b9183Scg149915 	}
2096e57b9183Scg149915 
2097e57b9183Scg149915 	/* okay, we need a new one */
2098e57b9183Scg149915 	for (i = 0; i < RADEON_MAX_SURFACES; i++) {
2099e57b9183Scg149915 		if (dev_priv->surfaces[i].refcount == 0) {
2100e57b9183Scg149915 			s = &(dev_priv->virt_surfaces[virt_surface_index]);
2101e57b9183Scg149915 			s->surface_index = i;
2102e57b9183Scg149915 			s->lower = new_lower;
2103e57b9183Scg149915 			s->upper = new_upper;
2104e57b9183Scg149915 			s->flags = new->flags;
2105e57b9183Scg149915 			s->filp = filp;
2106e57b9183Scg149915 			dev_priv->surfaces[i].refcount = 1;
2107e57b9183Scg149915 			dev_priv->surfaces[i].lower = s->lower;
2108e57b9183Scg149915 			dev_priv->surfaces[i].upper = s->upper;
2109e57b9183Scg149915 			dev_priv->surfaces[i].flags = s->flags;
2110e57b9183Scg149915 			radeon_apply_surface_regs(s->surface_index, dev_priv);
2111e57b9183Scg149915 			return (virt_surface_index);
2112e57b9183Scg149915 		}
2113e57b9183Scg149915 	}
2114e57b9183Scg149915 
2115e57b9183Scg149915 	/* we didn't find anything */
2116e57b9183Scg149915 	return (-1);
2117e57b9183Scg149915 }
2118e57b9183Scg149915 
2119e57b9183Scg149915 static int
free_surface(drm_file_t * filp,drm_radeon_private_t * dev_priv,int lower)2120e57b9183Scg149915 free_surface(drm_file_t *filp, drm_radeon_private_t *dev_priv, int lower)
2121e57b9183Scg149915 {
2122e57b9183Scg149915 	struct radeon_virt_surface *s;
2123e57b9183Scg149915 	int i;
2124e57b9183Scg149915 
2125e57b9183Scg149915 	/* find the virtual surface */
2126e57b9183Scg149915 	for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
2127e57b9183Scg149915 		s = &(dev_priv->virt_surfaces[i]);
2128e57b9183Scg149915 		if (s->filp) {
2129e57b9183Scg149915 			if ((lower == s->lower) && (filp == s->filp)) {
2130e57b9183Scg149915 				if (dev_priv->surfaces[s->surface_index].
2131e57b9183Scg149915 				    lower == s->lower)
2132e57b9183Scg149915 					dev_priv->surfaces[s->surface_index].
2133e57b9183Scg149915 					    lower = s->upper;
2134e57b9183Scg149915 
2135e57b9183Scg149915 				if (dev_priv->surfaces[s->surface_index].
2136e57b9183Scg149915 				    upper == s->upper)
2137e57b9183Scg149915 					dev_priv->surfaces[s->surface_index].
2138e57b9183Scg149915 					    upper = s->lower;
2139e57b9183Scg149915 
2140e57b9183Scg149915 				dev_priv->surfaces[s->surface_index].refcount--;
2141e57b9183Scg149915 				if (dev_priv->surfaces[s->surface_index].
2142e57b9183Scg149915 				    refcount == 0)
2143e57b9183Scg149915 					dev_priv->surfaces[s->surface_index].
2144e57b9183Scg149915 					    flags = 0;
2145e57b9183Scg149915 				s->filp = NULL;
2146e57b9183Scg149915 				radeon_apply_surface_regs(s->surface_index,
2147e57b9183Scg149915 				    dev_priv);
2148e57b9183Scg149915 				return (0);
2149e57b9183Scg149915 			}
2150e57b9183Scg149915 		}
2151e57b9183Scg149915 	}
2152e57b9183Scg149915 
2153e57b9183Scg149915 	return (1);
2154e57b9183Scg149915 }
2155e57b9183Scg149915 
radeon_surfaces_release(drm_file_t * filp,drm_radeon_private_t * dev_priv)2156e57b9183Scg149915 static void radeon_surfaces_release(drm_file_t *filp,
2157e57b9183Scg149915     drm_radeon_private_t *dev_priv)
2158e57b9183Scg149915 {
2159e57b9183Scg149915 	int i;
2160e57b9183Scg149915 
2161e57b9183Scg149915 	for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
2162e57b9183Scg149915 		if (dev_priv->virt_surfaces[i].filp == filp)
2163e57b9183Scg149915 			(void) free_surface(filp, dev_priv,
2164e57b9183Scg149915 			    dev_priv->virt_surfaces[i].lower);
2165e57b9183Scg149915 	}
2166e57b9183Scg149915 }
2167e57b9183Scg149915 
2168e57b9183Scg149915 /*
2169e57b9183Scg149915  * IOCTL functions
2170e57b9183Scg149915  */
2171e57b9183Scg149915 /*ARGSUSED*/
radeon_surface_alloc(DRM_IOCTL_ARGS)2172e57b9183Scg149915 static int radeon_surface_alloc(DRM_IOCTL_ARGS)
2173e57b9183Scg149915 {
2174e57b9183Scg149915 	DRM_DEVICE;
2175e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
2176e57b9183Scg149915 	drm_radeon_surface_alloc_t alloc;
2177e57b9183Scg149915 
2178e57b9183Scg149915 	if (!dev_priv) {
2179e57b9183Scg149915 		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
2180e57b9183Scg149915 		return (EINVAL);
2181e57b9183Scg149915 	}
2182e57b9183Scg149915 
2183e57b9183Scg149915 	DRM_COPYFROM_WITH_RETURN(&alloc, (void *)data, sizeof (alloc));
2184e57b9183Scg149915 
2185e57b9183Scg149915 	if (alloc_surface(&alloc, dev_priv, fpriv) == -1)
2186e57b9183Scg149915 		return (EINVAL);
2187e57b9183Scg149915 	else
2188e57b9183Scg149915 		return (0);
2189e57b9183Scg149915 }
2190e57b9183Scg149915 
2191e57b9183Scg149915 /*ARGSUSED*/
radeon_surface_free(DRM_IOCTL_ARGS)2192e57b9183Scg149915 static int radeon_surface_free(DRM_IOCTL_ARGS)
2193e57b9183Scg149915 {
2194e57b9183Scg149915 	DRM_DEVICE;
2195e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
2196e57b9183Scg149915 	drm_radeon_surface_free_t memfree;
2197e57b9183Scg149915 
2198e57b9183Scg149915 	if (!dev_priv) {
2199e57b9183Scg149915 		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
2200e57b9183Scg149915 		return (EINVAL);
2201e57b9183Scg149915 	}
2202e57b9183Scg149915 
2203e57b9183Scg149915 	DRM_COPYFROM_WITH_RETURN(&memfree, (void *)data, sizeof (memfree));
2204e57b9183Scg149915 	if (free_surface(fpriv, dev_priv, memfree.address)) {
2205e57b9183Scg149915 		return (EINVAL);
2206e57b9183Scg149915 	}
2207e57b9183Scg149915 	else
2208e57b9183Scg149915 		return (0);
2209e57b9183Scg149915 }
2210e57b9183Scg149915 
2211e57b9183Scg149915 /*ARGSUSED*/
radeon_cp_clear(DRM_IOCTL_ARGS)2212e57b9183Scg149915 static int radeon_cp_clear(DRM_IOCTL_ARGS)
2213e57b9183Scg149915 {
2214e57b9183Scg149915 	DRM_DEVICE;
2215e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
2216e57b9183Scg149915 	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2217e57b9183Scg149915 	drm_radeon_clear_t clear;
2218e57b9183Scg149915 	drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
2219e57b9183Scg149915 
2220e57b9183Scg149915 	LOCK_TEST_WITH_RETURN(dev, fpriv);
2221e57b9183Scg149915 
2222e57b9183Scg149915 #ifdef _MULTI_DATAMODEL
2223e57b9183Scg149915 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
2224e57b9183Scg149915 		drm_radeon_clear_32_t	clear32;
2225e57b9183Scg149915 		DRM_COPYFROM_WITH_RETURN(&clear32, (void *)data,
2226e57b9183Scg149915 		    sizeof (clear32));
2227e57b9183Scg149915 		clear.flags = clear32.flags;
2228e57b9183Scg149915 		clear.clear_color = clear32.clear_color;
2229e57b9183Scg149915 		clear.clear_depth = clear32.clear_depth;
2230e57b9183Scg149915 		clear.color_mask = clear32.color_mask;
2231e57b9183Scg149915 		clear.depth_mask = clear32.depth_mask;
2232e57b9183Scg149915 		clear.depth_boxes = (void*)(uintptr_t)clear32.depth_boxes;
2233e57b9183Scg149915 	} else {
2234e57b9183Scg149915 #endif
2235e57b9183Scg149915 		DRM_COPYFROM_WITH_RETURN(&clear, (void *)data, sizeof (clear));
2236e57b9183Scg149915 #ifdef _MULTI_DATAMODEL
2237e57b9183Scg149915 	}
2238e57b9183Scg149915 #endif
2239e57b9183Scg149915 
2240e57b9183Scg149915 	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2241e57b9183Scg149915 
2242e57b9183Scg149915 	if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
2243e57b9183Scg149915 		sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
2244e57b9183Scg149915 
2245e57b9183Scg149915 	if (DRM_COPY_FROM_USER(&depth_boxes, clear.depth_boxes,
2246e57b9183Scg149915 	    sarea_priv->nbox * sizeof (depth_boxes[0])))
2247e57b9183Scg149915 	return (EFAULT);
2248e57b9183Scg149915 
2249e57b9183Scg149915 	radeon_cp_dispatch_clear(dev, &clear, depth_boxes);
2250e57b9183Scg149915 
2251e57b9183Scg149915 	COMMIT_RING();
2252e57b9183Scg149915 	return (0);
2253e57b9183Scg149915 }
2254e57b9183Scg149915 
2255e57b9183Scg149915 /*
2256e57b9183Scg149915  * Not sure why this isn't set all the time:
2257e57b9183Scg149915  */
radeon_do_init_pageflip(drm_device_t * dev)2258e57b9183Scg149915 static int radeon_do_init_pageflip(drm_device_t *dev)
2259e57b9183Scg149915 {
2260e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
2261e57b9183Scg149915 	RING_LOCALS;
2262e57b9183Scg149915 
2263e57b9183Scg149915 	BEGIN_RING(6);
2264e57b9183Scg149915 	RADEON_WAIT_UNTIL_3D_IDLE();
2265e57b9183Scg149915 	OUT_RING(CP_PACKET0(RADEON_CRTC_OFFSET_CNTL, 0));
2266e57b9183Scg149915 	OUT_RING(RADEON_READ(RADEON_CRTC_OFFSET_CNTL) |
2267e57b9183Scg149915 	    RADEON_CRTC_OFFSET_FLIP_CNTL);
2268e57b9183Scg149915 	OUT_RING(CP_PACKET0(RADEON_CRTC2_OFFSET_CNTL, 0));
2269e57b9183Scg149915 	OUT_RING(RADEON_READ(RADEON_CRTC2_OFFSET_CNTL) |
2270e57b9183Scg149915 	    RADEON_CRTC_OFFSET_FLIP_CNTL);
2271e57b9183Scg149915 	ADVANCE_RING();
2272e57b9183Scg149915 
2273e57b9183Scg149915 	dev_priv->page_flipping = 1;
2274e57b9183Scg149915 	dev_priv->current_page = 0;
2275e57b9183Scg149915 	dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page;
2276e57b9183Scg149915 
2277e57b9183Scg149915 	return (0);
2278e57b9183Scg149915 }
2279e57b9183Scg149915 
2280e57b9183Scg149915 /*
2281e57b9183Scg149915  * Called whenever a client dies, from drm_release.
2282e57b9183Scg149915  * NOTE:  Lock isn't necessarily held when this is called!
2283e57b9183Scg149915  */
radeon_do_cleanup_pageflip(drm_device_t * dev)2284e57b9183Scg149915 static int radeon_do_cleanup_pageflip(drm_device_t *dev)
2285e57b9183Scg149915 {
2286e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
2287e57b9183Scg149915 
2288e57b9183Scg149915 	if (dev_priv->current_page != 0)
2289e57b9183Scg149915 		radeon_cp_dispatch_flip(dev);
2290e57b9183Scg149915 
2291e57b9183Scg149915 	dev_priv->page_flipping = 0;
2292e57b9183Scg149915 	return (0);
2293e57b9183Scg149915 }
2294e57b9183Scg149915 
2295e57b9183Scg149915 /*
2296e57b9183Scg149915  * Swapping and flipping are different operations, need different ioctls.
2297e57b9183Scg149915  * They can & should be intermixed to support multiple 3d windows.
2298e57b9183Scg149915  */
2299e57b9183Scg149915 /*ARGSUSED*/
radeon_cp_flip(DRM_IOCTL_ARGS)2300e57b9183Scg149915 static int radeon_cp_flip(DRM_IOCTL_ARGS)
2301e57b9183Scg149915 {
2302e57b9183Scg149915 	DRM_DEVICE;
2303e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
2304e57b9183Scg149915 
2305e57b9183Scg149915 	LOCK_TEST_WITH_RETURN(dev, fpriv);
2306e57b9183Scg149915 
2307e57b9183Scg149915 	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2308e57b9183Scg149915 
2309e57b9183Scg149915 	if (!dev_priv->page_flipping)
2310e57b9183Scg149915 		(void) radeon_do_init_pageflip(dev);
2311e57b9183Scg149915 
2312e57b9183Scg149915 	radeon_cp_dispatch_flip(dev);
2313e57b9183Scg149915 
2314e57b9183Scg149915 	COMMIT_RING();
2315e57b9183Scg149915 	return (0);
2316e57b9183Scg149915 }
2317e57b9183Scg149915 
2318e57b9183Scg149915 /*ARGSUSED*/
radeon_cp_swap(DRM_IOCTL_ARGS)2319e57b9183Scg149915 static int radeon_cp_swap(DRM_IOCTL_ARGS)
2320e57b9183Scg149915 {
2321e57b9183Scg149915 	DRM_DEVICE;
2322e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
2323e57b9183Scg149915 	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2324e57b9183Scg149915 
2325e57b9183Scg149915 	LOCK_TEST_WITH_RETURN(dev, fpriv);
2326e57b9183Scg149915 
2327e57b9183Scg149915 	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2328e57b9183Scg149915 
2329e57b9183Scg149915 	if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
2330e57b9183Scg149915 		sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
2331e57b9183Scg149915 
2332e57b9183Scg149915 	radeon_cp_dispatch_swap(dev);
2333e57b9183Scg149915 	dev_priv->sarea_priv->ctx_owner = 0;
2334e57b9183Scg149915 
2335e57b9183Scg149915 	COMMIT_RING();
2336e57b9183Scg149915 	return (0);
2337e57b9183Scg149915 }
2338e57b9183Scg149915 
2339e57b9183Scg149915 /*ARGSUSED*/
radeon_cp_vertex(DRM_IOCTL_ARGS)2340e57b9183Scg149915 static int radeon_cp_vertex(DRM_IOCTL_ARGS)
2341e57b9183Scg149915 {
2342e57b9183Scg149915 	DRM_DEVICE;
2343e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
2344e57b9183Scg149915 	drm_radeon_sarea_t *sarea_priv;
2345e57b9183Scg149915 	drm_device_dma_t *dma = dev->dma;
2346e57b9183Scg149915 	drm_buf_t *buf;
2347e57b9183Scg149915 	drm_radeon_vertex_t vertex;
2348e57b9183Scg149915 	drm_radeon_tcl_prim_t prim;
2349e57b9183Scg149915 
2350e57b9183Scg149915 	LOCK_TEST_WITH_RETURN(dev, fpriv);
2351e57b9183Scg149915 
2352e57b9183Scg149915 	if (!dev_priv) {
2353e57b9183Scg149915 		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
2354e57b9183Scg149915 		return (EINVAL);
2355e57b9183Scg149915 	}
2356e57b9183Scg149915 
2357e57b9183Scg149915 	sarea_priv = dev_priv->sarea_priv;
2358e57b9183Scg149915 
2359e57b9183Scg149915 	DRM_COPYFROM_WITH_RETURN(&vertex, (void *)data, sizeof (vertex));
2360e57b9183Scg149915 
2361e57b9183Scg149915 	DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n",
2362e57b9183Scg149915 	    DRM_CURRENTPID, vertex.idx, vertex.count, vertex.discard);
2363e57b9183Scg149915 
2364e57b9183Scg149915 	if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
2365e57b9183Scg149915 		DRM_ERROR("buffer index %d (of %d max)\n",
2366e57b9183Scg149915 		    vertex.idx, dma->buf_count - 1);
2367e57b9183Scg149915 		return (EINVAL);
2368e57b9183Scg149915 	}
2369e57b9183Scg149915 	if (vertex.prim < 0 || vertex.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
2370e57b9183Scg149915 		DRM_ERROR("buffer prim %d\n", vertex.prim);
2371e57b9183Scg149915 		return (EINVAL);
2372e57b9183Scg149915 	}
2373e57b9183Scg149915 
2374e57b9183Scg149915 	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2375e57b9183Scg149915 	VB_AGE_TEST_WITH_RETURN(dev_priv);
2376e57b9183Scg149915 
2377e57b9183Scg149915 	buf = dma->buflist[vertex.idx];
2378e57b9183Scg149915 
2379e57b9183Scg149915 	if (buf->filp != fpriv) {
2380e57b9183Scg149915 		DRM_ERROR("process %d using buffer owned by %p\n",
2381e57b9183Scg149915 		    DRM_CURRENTPID, buf->filp);
2382e57b9183Scg149915 		return (EINVAL);
2383e57b9183Scg149915 	}
2384e57b9183Scg149915 	if (buf->pending) {
2385e57b9183Scg149915 		DRM_ERROR("sending pending buffer %d\n", vertex.idx);
2386e57b9183Scg149915 		return (EINVAL);
2387e57b9183Scg149915 	}
2388e57b9183Scg149915 
2389e57b9183Scg149915 	/*
2390e57b9183Scg149915 	 * Build up a prim_t record:
2391e57b9183Scg149915 	 */
2392e57b9183Scg149915 	if (vertex.count) {
2393e57b9183Scg149915 		buf->used = vertex.count;	/* not used? */
2394e57b9183Scg149915 
2395e57b9183Scg149915 		if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
2396e57b9183Scg149915 			if (radeon_emit_state(dev_priv, fpriv,
2397e57b9183Scg149915 			    &sarea_priv->context_state,
2398e57b9183Scg149915 			    sarea_priv->tex_state,
2399e57b9183Scg149915 			    sarea_priv->dirty)) {
2400e57b9183Scg149915 				DRM_ERROR("radeon_emit_state failed\n");
2401e57b9183Scg149915 				return (EINVAL);
2402e57b9183Scg149915 			}
2403e57b9183Scg149915 
2404e57b9183Scg149915 			sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
2405e57b9183Scg149915 			    RADEON_UPLOAD_TEX1IMAGES |
2406e57b9183Scg149915 			    RADEON_UPLOAD_TEX2IMAGES |
2407e57b9183Scg149915 			    RADEON_REQUIRE_QUIESCENCE);
2408e57b9183Scg149915 		}
2409e57b9183Scg149915 
2410e57b9183Scg149915 		prim.start = 0;
2411e57b9183Scg149915 		prim.finish = vertex.count;	/* unused */
2412e57b9183Scg149915 		prim.prim = vertex.prim;
2413e57b9183Scg149915 		prim.numverts = vertex.count;
2414e57b9183Scg149915 		prim.vc_format = dev_priv->sarea_priv->vc_format;
2415e57b9183Scg149915 
2416e57b9183Scg149915 		radeon_cp_dispatch_vertex(dev, buf, &prim);
2417e57b9183Scg149915 	}
2418e57b9183Scg149915 
2419e57b9183Scg149915 	if (vertex.discard) {
2420e57b9183Scg149915 		radeon_cp_discard_buffer(dev, buf);
2421e57b9183Scg149915 	}
2422e57b9183Scg149915 
2423e57b9183Scg149915 	COMMIT_RING();
2424e57b9183Scg149915 	return (0);
2425e57b9183Scg149915 }
2426e57b9183Scg149915 
2427e57b9183Scg149915 /*ARGSUSED*/
radeon_cp_indices(DRM_IOCTL_ARGS)2428e57b9183Scg149915 static int radeon_cp_indices(DRM_IOCTL_ARGS)
2429e57b9183Scg149915 {
2430e57b9183Scg149915 	DRM_DEVICE;
2431e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
2432e57b9183Scg149915 	drm_radeon_sarea_t *sarea_priv;
2433e57b9183Scg149915 	drm_device_dma_t *dma = dev->dma;
2434e57b9183Scg149915 	drm_buf_t *buf;
2435e57b9183Scg149915 	drm_radeon_indices_t elts;
2436e57b9183Scg149915 	drm_radeon_tcl_prim_t prim;
2437e57b9183Scg149915 /*	int count; */
2438e57b9183Scg149915 
2439e57b9183Scg149915 	LOCK_TEST_WITH_RETURN(dev, fpriv);
2440e57b9183Scg149915 
2441e57b9183Scg149915 	if (!dev_priv) {
2442e57b9183Scg149915 		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
2443e57b9183Scg149915 		return (EINVAL);
2444e57b9183Scg149915 	}
2445e57b9183Scg149915 	sarea_priv = dev_priv->sarea_priv;
2446e57b9183Scg149915 
2447e57b9183Scg149915 	DRM_COPYFROM_WITH_RETURN(&elts, (void *)data, sizeof (elts));
2448e57b9183Scg149915 
2449e57b9183Scg149915 	DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n",
2450e57b9183Scg149915 	    DRM_CURRENTPID, elts.idx, elts.start, elts.end, elts.discard);
2451e57b9183Scg149915 
2452e57b9183Scg149915 	if (elts.idx < 0 || elts.idx >= dma->buf_count) {
2453e57b9183Scg149915 		DRM_ERROR("buffer index %d (of %d max)\n",
2454e57b9183Scg149915 		    elts.idx, dma->buf_count - 1);
2455e57b9183Scg149915 		return (EINVAL);
2456e57b9183Scg149915 	}
2457e57b9183Scg149915 	if (elts.prim < 0 || elts.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
2458e57b9183Scg149915 		DRM_ERROR("buffer prim %d\n", elts.prim);
2459e57b9183Scg149915 		return (EINVAL);
2460e57b9183Scg149915 	}
2461e57b9183Scg149915 
2462e57b9183Scg149915 	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2463e57b9183Scg149915 	VB_AGE_TEST_WITH_RETURN(dev_priv);
2464e57b9183Scg149915 
2465e57b9183Scg149915 	buf = dma->buflist[elts.idx];
2466e57b9183Scg149915 
2467e57b9183Scg149915 	if (buf->filp != fpriv) {
2468e57b9183Scg149915 		DRM_ERROR("process %d using buffer owned by %p\n",
2469e57b9183Scg149915 		    DRM_CURRENTPID, buf->filp);
2470e57b9183Scg149915 		return (EINVAL);
2471e57b9183Scg149915 	}
2472e57b9183Scg149915 	if (buf->pending) {
2473e57b9183Scg149915 		DRM_ERROR("sending pending buffer %d\n", elts.idx);
2474e57b9183Scg149915 		return (EINVAL);
2475e57b9183Scg149915 	}
2476e57b9183Scg149915 
2477e57b9183Scg149915 /*	count = (elts.end - elts.start) / sizeof(u16); */
2478e57b9183Scg149915 	elts.start -= RADEON_INDEX_PRIM_OFFSET;
2479e57b9183Scg149915 
2480e57b9183Scg149915 	if (elts.start & 0x7) {
2481e57b9183Scg149915 		DRM_ERROR("misaligned buffer 0x%x\n", elts.start);
2482e57b9183Scg149915 		return (EINVAL);
2483e57b9183Scg149915 	}
2484e57b9183Scg149915 	if (elts.start < buf->used) {
2485e57b9183Scg149915 		DRM_ERROR("no header 0x%x - 0x%x\n", elts.start, buf->used);
2486e57b9183Scg149915 		return (EINVAL);
2487e57b9183Scg149915 	}
2488e57b9183Scg149915 
2489e57b9183Scg149915 	buf->used = elts.end;
2490e57b9183Scg149915 
2491e57b9183Scg149915 	if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
2492e57b9183Scg149915 		if (radeon_emit_state(dev_priv, fpriv,
2493e57b9183Scg149915 		    &sarea_priv->context_state,
2494e57b9183Scg149915 		    sarea_priv->tex_state,
2495e57b9183Scg149915 		    sarea_priv->dirty)) {
2496e57b9183Scg149915 			DRM_ERROR("radeon_emit_state failed\n");
2497e57b9183Scg149915 			return (EINVAL);
2498e57b9183Scg149915 		}
2499e57b9183Scg149915 
2500e57b9183Scg149915 		sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
2501e57b9183Scg149915 		    RADEON_UPLOAD_TEX1IMAGES |
2502e57b9183Scg149915 		    RADEON_UPLOAD_TEX2IMAGES |
2503e57b9183Scg149915 		    RADEON_REQUIRE_QUIESCENCE);
2504e57b9183Scg149915 	}
2505e57b9183Scg149915 
2506e57b9183Scg149915 	/*
2507e57b9183Scg149915 	 * Build up a prim_t record:
2508e57b9183Scg149915 	 */
2509e57b9183Scg149915 	prim.start = elts.start;
2510e57b9183Scg149915 	prim.finish = elts.end;
2511e57b9183Scg149915 	prim.prim = elts.prim;
2512e57b9183Scg149915 	prim.offset = 0;	/* offset from start of dma buffers */
2513e57b9183Scg149915 	prim.numverts = RADEON_MAX_VB_VERTS;	/* duh */
2514e57b9183Scg149915 	prim.vc_format = dev_priv->sarea_priv->vc_format;
2515e57b9183Scg149915 
2516e57b9183Scg149915 	radeon_cp_dispatch_indices(dev, buf, &prim);
2517e57b9183Scg149915 	if (elts.discard) {
2518e57b9183Scg149915 		radeon_cp_discard_buffer(dev, buf);
2519e57b9183Scg149915 	}
2520e57b9183Scg149915 
2521e57b9183Scg149915 	COMMIT_RING();
2522e57b9183Scg149915 	return (0);
2523e57b9183Scg149915 }
2524e57b9183Scg149915 
2525e57b9183Scg149915 /*ARGSUSED*/
radeon_cp_texture(DRM_IOCTL_ARGS)2526e57b9183Scg149915 static int radeon_cp_texture(DRM_IOCTL_ARGS)
2527e57b9183Scg149915 {
2528e57b9183Scg149915 	DRM_DEVICE;
2529e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
2530e57b9183Scg149915 	drm_radeon_texture_t tex;
2531e57b9183Scg149915 	drm_radeon_tex_image_t image;
2532e57b9183Scg149915 	int ret;
2533e57b9183Scg149915 
2534e57b9183Scg149915 	LOCK_TEST_WITH_RETURN(dev, fpriv);
2535e57b9183Scg149915 
2536e57b9183Scg149915 #ifdef _MULTI_DATAMODEL
2537e57b9183Scg149915 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
2538e57b9183Scg149915 		drm_radeon_texture_32_t tex32;
2539e57b9183Scg149915 		drm_radeon_tex_image_32_t image32;
2540e57b9183Scg149915 
2541e57b9183Scg149915 		DRM_COPYFROM_WITH_RETURN(&tex32, (void *)data, sizeof (tex32));
2542e57b9183Scg149915 		if (tex32.image == 0) {
2543e57b9183Scg149915 			DRM_ERROR("null texture image!\n");
2544e57b9183Scg149915 			return (EINVAL);
2545e57b9183Scg149915 		}
2546e57b9183Scg149915 		if (DRM_COPY_FROM_USER(&image32,
2547e57b9183Scg149915 		    (void *)(uintptr_t)tex32.image, sizeof (image32))) {
2548e57b9183Scg149915 			cmn_err(CE_WARN, "copyin32 failed");
2549e57b9183Scg149915 			return (EFAULT);
2550e57b9183Scg149915 		}
2551e57b9183Scg149915 
2552e57b9183Scg149915 		tex.offset = tex32.offset;
2553e57b9183Scg149915 		tex.pitch = tex32.pitch;
2554e57b9183Scg149915 		tex.format = tex32.format;
2555e57b9183Scg149915 		tex.width = tex32.width;
2556e57b9183Scg149915 		tex.height = tex32.height;
2557e57b9183Scg149915 		tex.image = (void*)(uintptr_t)tex32.image;
2558e57b9183Scg149915 
2559e57b9183Scg149915 		image.x = image32.x;
2560e57b9183Scg149915 		image.y = image32.y;
2561e57b9183Scg149915 		image.width = image32.width;
2562e57b9183Scg149915 		image.height = image32.height;
2563e57b9183Scg149915 		image.data = (void*)(uintptr_t)image32.data;
2564e57b9183Scg149915 
2565e57b9183Scg149915 	} else {
2566e57b9183Scg149915 #endif
2567e57b9183Scg149915 		DRM_COPYFROM_WITH_RETURN(&tex, (void *)data, sizeof (tex));
2568e57b9183Scg149915 		if (tex.image == NULL) {
2569e57b9183Scg149915 			return (EINVAL);
2570e57b9183Scg149915 		}
2571e57b9183Scg149915 		if (DRM_COPY_FROM_USER(&image,
2572e57b9183Scg149915 		    (drm_radeon_tex_image_t *)tex.image, sizeof (image))) {
2573e57b9183Scg149915 			return (EFAULT);
2574e57b9183Scg149915 		}
2575e57b9183Scg149915 #ifdef _MULTI_DATAMODEL
2576e57b9183Scg149915 	}
2577e57b9183Scg149915 #endif
2578e57b9183Scg149915 
2579e57b9183Scg149915 	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2580e57b9183Scg149915 	VB_AGE_TEST_WITH_RETURN(dev_priv);
2581e57b9183Scg149915 
2582e57b9183Scg149915 	ret = radeon_cp_dispatch_texture(fpriv, dev, &tex, &image, mode);
2583e57b9183Scg149915 
2584e57b9183Scg149915 	COMMIT_RING();
2585e57b9183Scg149915 	return (ret);
2586e57b9183Scg149915 }
2587e57b9183Scg149915 
2588e57b9183Scg149915 /*ARGSUSED*/
radeon_cp_stipple(DRM_IOCTL_ARGS)2589e57b9183Scg149915 static int radeon_cp_stipple(DRM_IOCTL_ARGS)
2590e57b9183Scg149915 {
2591e57b9183Scg149915 	DRM_DEVICE;
2592e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
2593e57b9183Scg149915 	drm_radeon_stipple_t stipple;
2594e57b9183Scg149915 	u32 mask[32];
2595e57b9183Scg149915 
2596e57b9183Scg149915 	LOCK_TEST_WITH_RETURN(dev, fpriv);
2597e57b9183Scg149915 
2598e57b9183Scg149915 #ifdef _MULTI_DATAMODEL
2599e57b9183Scg149915 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
2600e57b9183Scg149915 		drm_radeon_stipple_32_t stipple32;
2601e57b9183Scg149915 		DRM_COPYFROM_WITH_RETURN(&stipple32, (void *)data,
2602e57b9183Scg149915 		    sizeof (stipple32));
2603e57b9183Scg149915 		stipple.mask = (void *)(uintptr_t)stipple32.mask;
2604e57b9183Scg149915 	} else {
2605e57b9183Scg149915 #endif
2606e57b9183Scg149915 		DRM_COPYFROM_WITH_RETURN(&stipple, (void *)data,
2607e57b9183Scg149915 		    sizeof (stipple));
2608e57b9183Scg149915 #ifdef _MULTI_DATAMODEL
2609e57b9183Scg149915 	}
2610e57b9183Scg149915 #endif
2611e57b9183Scg149915 	if (DRM_COPY_FROM_USER(&mask, stipple.mask, 32 * sizeof (u32)))
2612e57b9183Scg149915 		return (EFAULT);
2613e57b9183Scg149915 
2614e57b9183Scg149915 
2615e57b9183Scg149915 	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2616e57b9183Scg149915 
2617e57b9183Scg149915 	radeon_cp_dispatch_stipple(dev, mask);
2618e57b9183Scg149915 
2619e57b9183Scg149915 	COMMIT_RING();
2620e57b9183Scg149915 	return (0);
2621e57b9183Scg149915 }
2622e57b9183Scg149915 
2623e57b9183Scg149915 /*ARGSUSED*/
radeon_cp_indirect(DRM_IOCTL_ARGS)2624e57b9183Scg149915 static int radeon_cp_indirect(DRM_IOCTL_ARGS)
2625e57b9183Scg149915 {
2626e57b9183Scg149915 	DRM_DEVICE;
2627e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
2628e57b9183Scg149915 	drm_device_dma_t *dma = dev->dma;
2629e57b9183Scg149915 	drm_buf_t *buf;
2630e57b9183Scg149915 	drm_radeon_indirect_t indirect;
2631e57b9183Scg149915 	RING_LOCALS;
2632e57b9183Scg149915 
2633e57b9183Scg149915 	LOCK_TEST_WITH_RETURN(dev, fpriv);
2634e57b9183Scg149915 
2635e57b9183Scg149915 	if (!dev_priv) {
2636e57b9183Scg149915 		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
2637e57b9183Scg149915 		return (EINVAL);
2638e57b9183Scg149915 	}
2639e57b9183Scg149915 
2640e57b9183Scg149915 	DRM_COPYFROM_WITH_RETURN(&indirect, (void *) data, sizeof (indirect));
2641e57b9183Scg149915 
2642e57b9183Scg149915 	DRM_DEBUG("indirect: idx=%d s=%d e=%d d=%d\n",
2643e57b9183Scg149915 	    indirect.idx, indirect.start, indirect.end, indirect.discard);
2644e57b9183Scg149915 
2645e57b9183Scg149915 	if (indirect.idx < 0 || indirect.idx >= dma->buf_count) {
2646e57b9183Scg149915 		DRM_ERROR("buffer index %d (of %d max)\n",
2647e57b9183Scg149915 		    indirect.idx, dma->buf_count - 1);
2648e57b9183Scg149915 		return (EINVAL);
2649e57b9183Scg149915 	}
2650e57b9183Scg149915 
2651e57b9183Scg149915 	buf = dma->buflist[indirect.idx];
2652e57b9183Scg149915 
2653e57b9183Scg149915 	if (buf->filp != fpriv) {
2654e57b9183Scg149915 		DRM_ERROR("process %d using buffer owned by %p\n",
2655e57b9183Scg149915 		    DRM_CURRENTPID, buf->filp);
2656e57b9183Scg149915 		return (EINVAL);
2657e57b9183Scg149915 	}
2658e57b9183Scg149915 	if (buf->pending) {
2659e57b9183Scg149915 		DRM_ERROR("sending pending buffer %d\n", indirect.idx);
2660e57b9183Scg149915 		return (EINVAL);
2661e57b9183Scg149915 	}
2662e57b9183Scg149915 
2663e57b9183Scg149915 	if (indirect.start < buf->used) {
2664e57b9183Scg149915 		DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n",
2665e57b9183Scg149915 		    indirect.start, buf->used);
2666e57b9183Scg149915 		return (EINVAL);
2667e57b9183Scg149915 	}
2668e57b9183Scg149915 
2669e57b9183Scg149915 	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2670e57b9183Scg149915 	VB_AGE_TEST_WITH_RETURN(dev_priv);
2671e57b9183Scg149915 
2672e57b9183Scg149915 	buf->used = indirect.end;
2673e57b9183Scg149915 
2674e57b9183Scg149915 	/*
2675e57b9183Scg149915 	 * Wait for the 3D stream to idle before the indirect buffer
2676e57b9183Scg149915 	 * containing 2D acceleration commands is processed.
2677e57b9183Scg149915 	 */
2678e57b9183Scg149915 	BEGIN_RING(2);
2679e57b9183Scg149915 
2680e57b9183Scg149915 	RADEON_WAIT_UNTIL_3D_IDLE();
2681e57b9183Scg149915 
2682e57b9183Scg149915 	ADVANCE_RING();
2683e57b9183Scg149915 
2684e57b9183Scg149915 	/*
2685e57b9183Scg149915 	 * Dispatch the indirect buffer full of commands from the
2686e57b9183Scg149915 	 * X server.  This is insecure and is thus only available to
2687e57b9183Scg149915 	 * privileged clients.
2688e57b9183Scg149915 	 */
2689e57b9183Scg149915 	radeon_cp_dispatch_indirect(dev, buf, indirect.start, indirect.end);
2690e57b9183Scg149915 	if (indirect.discard) {
2691e57b9183Scg149915 		radeon_cp_discard_buffer(dev, buf);
2692e57b9183Scg149915 	}
2693e57b9183Scg149915 
2694e57b9183Scg149915 	COMMIT_RING();
2695e57b9183Scg149915 	return (0);
2696e57b9183Scg149915 }
2697e57b9183Scg149915 
2698e57b9183Scg149915 /*ARGSUSED*/
radeon_cp_vertex2(DRM_IOCTL_ARGS)2699e57b9183Scg149915 static int radeon_cp_vertex2(DRM_IOCTL_ARGS)
2700e57b9183Scg149915 {
2701e57b9183Scg149915 	DRM_DEVICE;
2702e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
2703e57b9183Scg149915 	drm_radeon_sarea_t *sarea_priv;
2704e57b9183Scg149915 	drm_device_dma_t *dma = dev->dma;
2705e57b9183Scg149915 	drm_buf_t *buf;
2706e57b9183Scg149915 	drm_radeon_vertex2_t vertex;
2707e57b9183Scg149915 	int i;
2708e57b9183Scg149915 	unsigned char laststate;
2709e57b9183Scg149915 
2710e57b9183Scg149915 	LOCK_TEST_WITH_RETURN(dev, fpriv);
2711e57b9183Scg149915 
2712e57b9183Scg149915 	if (!dev_priv) {
2713e57b9183Scg149915 		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
2714e57b9183Scg149915 		return (EINVAL);
2715e57b9183Scg149915 	}
2716e57b9183Scg149915 
2717e57b9183Scg149915 	sarea_priv = dev_priv->sarea_priv;
2718e57b9183Scg149915 
2719e57b9183Scg149915 
2720e57b9183Scg149915 #ifdef _MULTI_DATAMODEL
2721e57b9183Scg149915 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
2722e57b9183Scg149915 		drm_radeon_vertex2_32_t	vertex32;
2723e57b9183Scg149915 
2724e57b9183Scg149915 		DRM_COPYFROM_WITH_RETURN(&vertex32, (void *) data,
2725e57b9183Scg149915 		    sizeof (vertex32));
2726e57b9183Scg149915 		vertex.idx = vertex32.idx;
2727e57b9183Scg149915 		vertex.discard = vertex32.discard;
2728e57b9183Scg149915 		vertex.nr_states = vertex32.nr_states;
2729e57b9183Scg149915 		vertex.state = (void *) (uintptr_t)vertex32.state;
2730e57b9183Scg149915 		vertex.nr_prims = vertex32.nr_prims;
2731e57b9183Scg149915 		vertex.prim = (void *)(uintptr_t)vertex32.prim;
2732e57b9183Scg149915 	} else {
2733e57b9183Scg149915 #endif
2734e57b9183Scg149915 		DRM_COPYFROM_WITH_RETURN(&vertex, (void *) data,
2735e57b9183Scg149915 		    sizeof (vertex));
2736e57b9183Scg149915 #ifdef _MULTI_DATAMODEL
2737e57b9183Scg149915 	}
2738e57b9183Scg149915 #endif
2739e57b9183Scg149915 
2740e57b9183Scg149915 	DRM_DEBUG("pid=%d index=%d discard=%d\n",
2741e57b9183Scg149915 	    DRM_CURRENTPID, vertex.idx, vertex.discard);
2742e57b9183Scg149915 
2743e57b9183Scg149915 	if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
2744e57b9183Scg149915 		DRM_ERROR("buffer index %d (of %d max)\n",
2745e57b9183Scg149915 		    vertex.idx, dma->buf_count - 1);
2746e57b9183Scg149915 		return (EINVAL);
2747e57b9183Scg149915 	}
2748e57b9183Scg149915 
2749e57b9183Scg149915 	RING_SPACE_TEST_WITH_RETURN(dev_priv);
2750e57b9183Scg149915 	VB_AGE_TEST_WITH_RETURN(dev_priv);
2751e57b9183Scg149915 
2752e57b9183Scg149915 	buf = dma->buflist[vertex.idx];
2753e57b9183Scg149915 
2754e57b9183Scg149915 	if (buf->filp != fpriv) {
2755e57b9183Scg149915 		DRM_ERROR("process %d using buffer owned by %p\n",
2756e57b9183Scg149915 		    DRM_CURRENTPID, buf->filp);
2757e57b9183Scg149915 		return (EINVAL);
2758e57b9183Scg149915 	}
2759e57b9183Scg149915 
2760e57b9183Scg149915 	if (buf->pending) {
2761e57b9183Scg149915 		DRM_ERROR("sending pending buffer %d\n", vertex.idx);
2762e57b9183Scg149915 		return (EINVAL);
2763e57b9183Scg149915 	}
2764e57b9183Scg149915 
2765e57b9183Scg149915 	if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
2766e57b9183Scg149915 		return (EINVAL);
2767e57b9183Scg149915 
2768e57b9183Scg149915 	for (laststate = 0xff, i = 0; i < vertex.nr_prims; i++) {
2769e57b9183Scg149915 		drm_radeon_prim_t prim;
2770e57b9183Scg149915 		drm_radeon_tcl_prim_t tclprim;
2771e57b9183Scg149915 
2772e57b9183Scg149915 		if (DRM_COPY_FROM_USER(&prim, &vertex.prim[i], sizeof (prim)))
2773e57b9183Scg149915 			return (EFAULT);
2774e57b9183Scg149915 
2775e57b9183Scg149915 		if (prim.stateidx != laststate) {
2776e57b9183Scg149915 			drm_radeon_state_t state;
2777e57b9183Scg149915 
2778e57b9183Scg149915 			if (DRM_COPY_FROM_USER(&state,
2779e57b9183Scg149915 			    &vertex.state[prim.stateidx], sizeof (state)))
2780e57b9183Scg149915 				return (EFAULT);
2781e57b9183Scg149915 
2782e57b9183Scg149915 			if (radeon_emit_state2(dev_priv, fpriv, &state)) {
2783e57b9183Scg149915 				DRM_ERROR("radeon_emit_state2 failed\n");
2784e57b9183Scg149915 				return (EINVAL);
2785e57b9183Scg149915 			}
2786e57b9183Scg149915 
2787e57b9183Scg149915 			laststate = prim.stateidx;
2788e57b9183Scg149915 		}
2789e57b9183Scg149915 
2790e57b9183Scg149915 		tclprim.start = prim.start;
2791e57b9183Scg149915 		tclprim.finish = prim.finish;
2792e57b9183Scg149915 		tclprim.prim = prim.prim;
2793e57b9183Scg149915 		tclprim.vc_format = prim.vc_format;
2794e57b9183Scg149915 
2795e57b9183Scg149915 		if (prim.prim & RADEON_PRIM_WALK_IND) {
2796e57b9183Scg149915 			tclprim.offset = prim.numverts * 64;
2797e57b9183Scg149915 			tclprim.numverts = RADEON_MAX_VB_VERTS;	/* duh */
2798e57b9183Scg149915 
2799e57b9183Scg149915 			radeon_cp_dispatch_indices(dev, buf, &tclprim);
2800e57b9183Scg149915 		} else {
2801e57b9183Scg149915 			tclprim.numverts = prim.numverts;
2802e57b9183Scg149915 			tclprim.offset = 0;	/* not used */
2803e57b9183Scg149915 
2804e57b9183Scg149915 			radeon_cp_dispatch_vertex(dev, buf, &tclprim);
2805e57b9183Scg149915 		}
2806e57b9183Scg149915 
2807e57b9183Scg149915 		if (sarea_priv->nbox == 1)
2808e57b9183Scg149915 			sarea_priv->nbox = 0;
2809e57b9183Scg149915 	}
2810e57b9183Scg149915 
2811e57b9183Scg149915 	if (vertex.discard) {
2812e57b9183Scg149915 		radeon_cp_discard_buffer(dev, buf);
2813e57b9183Scg149915 	}
2814e57b9183Scg149915 
2815e57b9183Scg149915 	COMMIT_RING();
2816e57b9183Scg149915 	return (0);
2817e57b9183Scg149915 }
2818e57b9183Scg149915 
radeon_emit_packets(drm_radeon_private_t * dev_priv,drm_file_t * filp_priv,drm_radeon_cmd_header_t header,drm_radeon_kcmd_buffer_t * cmdbuf)2819e57b9183Scg149915 static int radeon_emit_packets(drm_radeon_private_t *dev_priv,
2820e57b9183Scg149915     drm_file_t *filp_priv, drm_radeon_cmd_header_t header,
2821e57b9183Scg149915     drm_radeon_kcmd_buffer_t *cmdbuf)
2822e57b9183Scg149915 {
2823e57b9183Scg149915 	int id = (int)header.packet.packet_id;
2824e57b9183Scg149915 	int sz, reg;
2825e57b9183Scg149915 	u32 *data = (u32 *)(uintptr_t)cmdbuf->buf;
2826e57b9183Scg149915 	RING_LOCALS;
2827e57b9183Scg149915 
2828e57b9183Scg149915 	if (id >= RADEON_MAX_STATE_PACKETS)
2829e57b9183Scg149915 		return (EINVAL);
2830e57b9183Scg149915 
2831e57b9183Scg149915 	sz = packet[id].len;
2832e57b9183Scg149915 	reg = packet[id].start;
2833e57b9183Scg149915 
2834e57b9183Scg149915 	if (sz * sizeof (int) > cmdbuf->bufsz) {
2835e57b9183Scg149915 		DRM_ERROR("Packet size provided larger than data provided\n");
2836e57b9183Scg149915 		return (EINVAL);
2837e57b9183Scg149915 	}
2838e57b9183Scg149915 
2839e57b9183Scg149915 	if (radeon_check_and_fixup_packets(dev_priv, filp_priv, id, data)) {
2840e57b9183Scg149915 		DRM_ERROR("Packet verification failed\n");
2841e57b9183Scg149915 		return (EINVAL);
2842e57b9183Scg149915 	}
2843e57b9183Scg149915 
2844e57b9183Scg149915 	BEGIN_RING(sz + 1);
2845e57b9183Scg149915 	OUT_RING(CP_PACKET0(reg, (sz - 1)));
2846e57b9183Scg149915 	OUT_RING_TABLE(data, sz);
2847e57b9183Scg149915 	ADVANCE_RING();
2848e57b9183Scg149915 
2849e57b9183Scg149915 	cmdbuf->buf += sz * sizeof (int);
2850e57b9183Scg149915 	cmdbuf->bufsz -= sz * sizeof (int);
2851e57b9183Scg149915 	return (0);
2852e57b9183Scg149915 }
2853e57b9183Scg149915 
2854e57b9183Scg149915 static inline int
radeon_emit_scalars(drm_radeon_private_t * dev_priv,drm_radeon_cmd_header_t header,drm_radeon_kcmd_buffer_t * cmdbuf)2855e57b9183Scg149915 radeon_emit_scalars(drm_radeon_private_t *dev_priv,
2856e57b9183Scg149915     drm_radeon_cmd_header_t header, drm_radeon_kcmd_buffer_t *cmdbuf)
2857e57b9183Scg149915 {
2858e57b9183Scg149915 	int sz = header.scalars.count;
2859e57b9183Scg149915 	int start = header.scalars.offset;
2860e57b9183Scg149915 	int stride = header.scalars.stride;
2861e57b9183Scg149915 	RING_LOCALS;
2862e57b9183Scg149915 
2863e57b9183Scg149915 	BEGIN_RING(3 + sz);
2864e57b9183Scg149915 	OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
2865e57b9183Scg149915 	OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
2866e57b9183Scg149915 	OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
2867e57b9183Scg149915 	OUT_RING_TABLE(cmdbuf->buf, sz);
2868e57b9183Scg149915 	ADVANCE_RING();
2869e57b9183Scg149915 	cmdbuf->buf += sz * sizeof (int);
2870e57b9183Scg149915 	cmdbuf->bufsz -= sz * sizeof (int);
2871e57b9183Scg149915 	return (0);
2872e57b9183Scg149915 }
2873e57b9183Scg149915 
2874e57b9183Scg149915 /*
2875e57b9183Scg149915  * God this is ugly
2876e57b9183Scg149915  */
2877e57b9183Scg149915 static inline int
radeon_emit_scalars2(drm_radeon_private_t * dev_priv,drm_radeon_cmd_header_t header,drm_radeon_kcmd_buffer_t * cmdbuf)2878e57b9183Scg149915 radeon_emit_scalars2(drm_radeon_private_t *dev_priv,
2879e57b9183Scg149915     drm_radeon_cmd_header_t header, drm_radeon_kcmd_buffer_t *cmdbuf)
2880e57b9183Scg149915 {
2881e57b9183Scg149915 	int sz = header.scalars.count;
2882e57b9183Scg149915 	int start = ((unsigned int)header.scalars.offset) + 0x100;
2883e57b9183Scg149915 	int stride = header.scalars.stride;
2884e57b9183Scg149915 	RING_LOCALS;
2885e57b9183Scg149915 
2886e57b9183Scg149915 	BEGIN_RING(3 + sz);
2887e57b9183Scg149915 	OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
2888e57b9183Scg149915 	OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
2889e57b9183Scg149915 	OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
2890e57b9183Scg149915 	OUT_RING_TABLE(cmdbuf->buf, sz);
2891e57b9183Scg149915 	ADVANCE_RING();
2892e57b9183Scg149915 	cmdbuf->buf += sz * sizeof (int);
2893e57b9183Scg149915 	cmdbuf->bufsz -= sz * sizeof (int);
2894e57b9183Scg149915 	return (0);
2895e57b9183Scg149915 }
2896e57b9183Scg149915 
2897e57b9183Scg149915 static inline int
radeon_emit_vectors(drm_radeon_private_t * dev_priv,drm_radeon_cmd_header_t header,drm_radeon_kcmd_buffer_t * cmdbuf)2898e57b9183Scg149915 radeon_emit_vectors(drm_radeon_private_t *dev_priv,
2899e57b9183Scg149915     drm_radeon_cmd_header_t header, drm_radeon_kcmd_buffer_t *cmdbuf)
2900e57b9183Scg149915 {
2901e57b9183Scg149915 	int sz = header.vectors.count;
2902e57b9183Scg149915 	int start = header.vectors.offset;
2903e57b9183Scg149915 	int stride = header.vectors.stride;
2904e57b9183Scg149915 	RING_LOCALS;
2905e57b9183Scg149915 
2906e57b9183Scg149915 	BEGIN_RING(5 + sz);
2907e57b9183Scg149915 	OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
2908e57b9183Scg149915 	OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
2909e57b9183Scg149915 	OUT_RING(start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
2910e57b9183Scg149915 	OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
2911e57b9183Scg149915 	OUT_RING_TABLE(cmdbuf->buf, sz);
2912e57b9183Scg149915 	ADVANCE_RING();
2913e57b9183Scg149915 
2914e57b9183Scg149915 	cmdbuf->buf += sz * sizeof (int);
2915e57b9183Scg149915 	cmdbuf->bufsz -= sz * sizeof (int);
2916e57b9183Scg149915 	return (0);
2917e57b9183Scg149915 }
2918e57b9183Scg149915 
2919e57b9183Scg149915 static inline int
radeon_emit_veclinear(drm_radeon_private_t * dev_priv,drm_radeon_cmd_header_t header,drm_radeon_kcmd_buffer_t * cmdbuf)2920e57b9183Scg149915 radeon_emit_veclinear(drm_radeon_private_t *dev_priv,
2921e57b9183Scg149915     drm_radeon_cmd_header_t header, drm_radeon_kcmd_buffer_t *cmdbuf)
2922e57b9183Scg149915 {
2923e57b9183Scg149915 	int sz = header.veclinear.count * 4;
2924e57b9183Scg149915 	int start = header.veclinear.addr_lo | (header.veclinear.addr_hi << 8);
2925e57b9183Scg149915 	RING_LOCALS;
2926e57b9183Scg149915 
2927e57b9183Scg149915 		if (!sz)
2928e57b9183Scg149915 			return (0);
2929e57b9183Scg149915 		if (sz * 4 > cmdbuf->bufsz)
2930e57b9183Scg149915 			return (EINVAL);
2931e57b9183Scg149915 
2932e57b9183Scg149915 	BEGIN_RING(5 + sz);
2933e57b9183Scg149915 	OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
2934e57b9183Scg149915 	OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
2935e57b9183Scg149915 	OUT_RING(start | (1 << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
2936e57b9183Scg149915 	OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
2937e57b9183Scg149915 	OUT_RING_TABLE(cmdbuf->buf, sz);
2938e57b9183Scg149915 	ADVANCE_RING();
2939e57b9183Scg149915 
2940e57b9183Scg149915 	cmdbuf->buf += sz * sizeof (int);
2941e57b9183Scg149915 	cmdbuf->bufsz -= sz * sizeof (int);
2942e57b9183Scg149915 	return (0);
2943e57b9183Scg149915 }
2944e57b9183Scg149915 
2945e57b9183Scg149915 static int
radeon_emit_packet3(drm_device_t * dev,drm_file_t * filp_priv,drm_radeon_kcmd_buffer_t * cmdbuf)2946e57b9183Scg149915 radeon_emit_packet3(drm_device_t *dev, drm_file_t *filp_priv,
2947e57b9183Scg149915     drm_radeon_kcmd_buffer_t *cmdbuf)
2948e57b9183Scg149915 {
2949e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
2950e57b9183Scg149915 	unsigned int cmdsz;
2951e57b9183Scg149915 	int ret;
2952e57b9183Scg149915 	RING_LOCALS;
2953e57b9183Scg149915 
2954e57b9183Scg149915 
2955e57b9183Scg149915 	if ((ret = radeon_check_and_fixup_packet3(dev_priv,
2956e57b9183Scg149915 	    filp_priv, cmdbuf, &cmdsz))) {
2957e57b9183Scg149915 		DRM_ERROR("Packet verification failed\n");
2958e57b9183Scg149915 		return (ret);
2959e57b9183Scg149915 	}
2960e57b9183Scg149915 
2961e57b9183Scg149915 	BEGIN_RING(cmdsz);
2962e57b9183Scg149915 	OUT_RING_TABLE(cmdbuf->buf, cmdsz);
2963e57b9183Scg149915 	ADVANCE_RING();
2964e57b9183Scg149915 
2965e57b9183Scg149915 	cmdbuf->buf += cmdsz * 4;
2966e57b9183Scg149915 	cmdbuf->bufsz -= cmdsz * 4;
2967e57b9183Scg149915 	return (0);
2968e57b9183Scg149915 }
2969e57b9183Scg149915 
radeon_emit_packet3_cliprect(drm_device_t * dev,drm_file_t * filp_priv,drm_radeon_kcmd_buffer_t * cmdbuf,int orig_nbox)2970e57b9183Scg149915 static int radeon_emit_packet3_cliprect(drm_device_t *dev,
2971e57b9183Scg149915 					drm_file_t *filp_priv,
2972e57b9183Scg149915 					drm_radeon_kcmd_buffer_t *cmdbuf,
2973e57b9183Scg149915 					int orig_nbox)
2974e57b9183Scg149915 {
2975e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
2976e57b9183Scg149915 	drm_clip_rect_t box;
2977e57b9183Scg149915 	unsigned int cmdsz;
2978e57b9183Scg149915 	int ret;
2979e57b9183Scg149915 	drm_clip_rect_t __user *boxes = cmdbuf->boxes;
2980e57b9183Scg149915 	int i = 0;
2981e57b9183Scg149915 	RING_LOCALS;
2982e57b9183Scg149915 
2983e57b9183Scg149915 	if ((ret = radeon_check_and_fixup_packet3(dev_priv,
2984e57b9183Scg149915 	    filp_priv, cmdbuf, &cmdsz))) {
2985e57b9183Scg149915 		DRM_ERROR("Packet verification failed\n");
2986e57b9183Scg149915 		return (ret);
2987e57b9183Scg149915 	}
2988e57b9183Scg149915 
2989e57b9183Scg149915 	if (!orig_nbox)
2990e57b9183Scg149915 		goto out;
2991e57b9183Scg149915 
2992e57b9183Scg149915 	do {
2993e57b9183Scg149915 		if (i < cmdbuf->nbox) {
2994e57b9183Scg149915 			if (DRM_COPY_FROM_USER(&box, &boxes[i], sizeof (box)))
2995e57b9183Scg149915 				return (EFAULT);
2996e57b9183Scg149915 			/*
2997e57b9183Scg149915 			 * FIXME The second and subsequent times round
2998e57b9183Scg149915 			 * this loop, send a WAIT_UNTIL_3D_IDLE before
2999e57b9183Scg149915 			 * calling emit_clip_rect(). This fixes a
3000e57b9183Scg149915 			 * lockup on fast machines when sending
3001e57b9183Scg149915 			 * several cliprects with a cmdbuf, as when
3002e57b9183Scg149915 			 * waving a 2D window over a 3D
3003e57b9183Scg149915 			 * window. Something in the commands from user
3004e57b9183Scg149915 			 * space seems to hang the card when they're
3005e57b9183Scg149915 			 * sent several times in a row. That would be
3006e57b9183Scg149915 			 * the correct place to fix it but this works
3007e57b9183Scg149915 			 * around it until I can figure that out - Tim
3008e57b9183Scg149915 			 * Smith
3009e57b9183Scg149915 			 */
3010e57b9183Scg149915 			if (i) {
3011e57b9183Scg149915 				BEGIN_RING(2);
3012e57b9183Scg149915 				RADEON_WAIT_UNTIL_3D_IDLE();
3013e57b9183Scg149915 				ADVANCE_RING();
3014e57b9183Scg149915 			}
3015e57b9183Scg149915 			radeon_emit_clip_rect(dev_priv, &box);
3016e57b9183Scg149915 		}
3017e57b9183Scg149915 
3018e57b9183Scg149915 		BEGIN_RING(cmdsz);
3019e57b9183Scg149915 		OUT_RING_TABLE(cmdbuf->buf, cmdsz);
3020e57b9183Scg149915 		ADVANCE_RING();
3021e57b9183Scg149915 
3022e57b9183Scg149915 	} while (++i < cmdbuf->nbox);
3023e57b9183Scg149915 	if (cmdbuf->nbox == 1)
3024e57b9183Scg149915 		cmdbuf->nbox = 0;
3025e57b9183Scg149915 
3026e57b9183Scg149915 out:
3027e57b9183Scg149915 	cmdbuf->buf += cmdsz * 4;
3028e57b9183Scg149915 	cmdbuf->bufsz -= cmdsz * 4;
3029e57b9183Scg149915 	return (0);
3030e57b9183Scg149915 }
3031e57b9183Scg149915 
3032e57b9183Scg149915 static int
radeon_emit_wait(drm_device_t * dev,int flags)3033e57b9183Scg149915 radeon_emit_wait(drm_device_t *dev, int flags)
3034e57b9183Scg149915 {
3035e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
3036e57b9183Scg149915 	RING_LOCALS;
3037e57b9183Scg149915 
3038e57b9183Scg149915 	DRM_DEBUG("%s: %x\n", __FUNCTION__, flags);
3039e57b9183Scg149915 	switch (flags) {
3040e57b9183Scg149915 	case RADEON_WAIT_2D:
3041e57b9183Scg149915 		BEGIN_RING(2);
3042e57b9183Scg149915 		RADEON_WAIT_UNTIL_2D_IDLE();
3043e57b9183Scg149915 		ADVANCE_RING();
3044e57b9183Scg149915 		break;
3045e57b9183Scg149915 	case RADEON_WAIT_3D:
3046e57b9183Scg149915 		BEGIN_RING(2);
3047e57b9183Scg149915 		RADEON_WAIT_UNTIL_3D_IDLE();
3048e57b9183Scg149915 		ADVANCE_RING();
3049e57b9183Scg149915 		break;
3050e57b9183Scg149915 	case RADEON_WAIT_2D | RADEON_WAIT_3D:
3051e57b9183Scg149915 		BEGIN_RING(2);
3052e57b9183Scg149915 		RADEON_WAIT_UNTIL_IDLE();
3053e57b9183Scg149915 		ADVANCE_RING();
3054e57b9183Scg149915 		break;
3055e57b9183Scg149915 	default:
3056e57b9183Scg149915 		return (EINVAL);
3057e57b9183Scg149915 	}
3058e57b9183Scg149915 
3059e57b9183Scg149915 	return (0);
3060e57b9183Scg149915 }
3061e57b9183Scg149915 
3062e57b9183Scg149915 /*ARGSUSED*/
radeon_cp_cmdbuf(DRM_IOCTL_ARGS)3063e57b9183Scg149915 static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
3064e57b9183Scg149915 {
3065e57b9183Scg149915 	DRM_DEVICE;
3066e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
3067e57b9183Scg149915 	drm_device_dma_t *dma = dev->dma;
3068e57b9183Scg149915 	drm_buf_t *buf = NULL;
3069e57b9183Scg149915 	int idx;
3070e57b9183Scg149915 	drm_radeon_kcmd_buffer_t cmdbuf;
3071e57b9183Scg149915 	drm_radeon_cmd_header_t header;
3072e57b9183Scg149915 	int orig_nbox, orig_bufsz;
3073e57b9183Scg149915 	char *kbuf = NULL;
3074e57b9183Scg149915 
3075e57b9183Scg149915 	LOCK_TEST_WITH_RETURN(dev, fpriv);
3076e57b9183Scg149915 
3077e57b9183Scg149915 	if (!dev_priv) {
3078e57b9183Scg149915 		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
3079e57b9183Scg149915 		return (EINVAL);
3080e57b9183Scg149915 	}
3081e57b9183Scg149915 
3082e57b9183Scg149915 #ifdef _MULTI_DATAMODEL
3083e57b9183Scg149915 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
3084e57b9183Scg149915 		drm_radeon_kcmd_buffer_32_t cmdbuf32;
3085e57b9183Scg149915 
3086e57b9183Scg149915 		DRM_COPYFROM_WITH_RETURN(&cmdbuf32, (void *)data,
3087e57b9183Scg149915 		    sizeof (cmdbuf32));
3088e57b9183Scg149915 		cmdbuf.bufsz = cmdbuf32.bufsz;
3089e57b9183Scg149915 		cmdbuf.buf = (void *)(uintptr_t)cmdbuf32.buf;
3090e57b9183Scg149915 		cmdbuf.nbox = cmdbuf32.nbox;
3091e57b9183Scg149915 		cmdbuf.boxes = (void *)(uintptr_t)cmdbuf32.boxes;
3092e57b9183Scg149915 	} else {
3093e57b9183Scg149915 #endif
3094e57b9183Scg149915 		DRM_COPYFROM_WITH_RETURN(&cmdbuf, (void *) data,
3095e57b9183Scg149915 		    sizeof (cmdbuf));
3096e57b9183Scg149915 #ifdef _MULTI_DATAMODEL
3097e57b9183Scg149915 	}
3098e57b9183Scg149915 #endif
3099e57b9183Scg149915 	RING_SPACE_TEST_WITH_RETURN(dev_priv);
3100e57b9183Scg149915 	VB_AGE_TEST_WITH_RETURN(dev_priv);
3101e57b9183Scg149915 
3102e57b9183Scg149915 	if (cmdbuf.bufsz > 64 * 1024 || cmdbuf.bufsz < 0) {
3103e57b9183Scg149915 		return (EINVAL);
3104e57b9183Scg149915 	}
3105e57b9183Scg149915 
3106e57b9183Scg149915 	/*
3107e57b9183Scg149915 	 * Allocate an in-kernel area and copy in the cmdbuf. Do this
3108e57b9183Scg149915 	 * to avoid races between checking values and using those values
3109e57b9183Scg149915 	 * in other code, and simply to avoid a lot of function calls
3110e57b9183Scg149915 	 * to copy in data.
3111e57b9183Scg149915 	 */
3112e57b9183Scg149915 	orig_bufsz = cmdbuf.bufsz;
3113e57b9183Scg149915 	if (orig_bufsz != 0) {
3114e57b9183Scg149915 		kbuf = drm_alloc(cmdbuf.bufsz, DRM_MEM_DRIVER);
3115e57b9183Scg149915 		if (kbuf == NULL)
3116e57b9183Scg149915 			return (ENOMEM);
3117e57b9183Scg149915 		if (DRM_COPY_FROM_USER(kbuf, (void *)cmdbuf.buf,
3118e57b9183Scg149915 		    cmdbuf.bufsz)) {
3119e57b9183Scg149915 			drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
3120e57b9183Scg149915 			return (EFAULT);
3121e57b9183Scg149915 		}
3122e57b9183Scg149915 		cmdbuf.buf = kbuf;
3123e57b9183Scg149915 	}
3124e57b9183Scg149915 
3125e57b9183Scg149915 	orig_nbox = cmdbuf.nbox;
3126e57b9183Scg149915 
3127e57b9183Scg149915 	if (dev_priv->microcode_version == UCODE_R300) {
3128e57b9183Scg149915 		int temp;
3129e57b9183Scg149915 		temp = r300_do_cp_cmdbuf(dev, fpriv, &cmdbuf);
3130e57b9183Scg149915 
3131e57b9183Scg149915 		if (orig_bufsz != 0)
3132e57b9183Scg149915 			drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
3133e57b9183Scg149915 
3134e57b9183Scg149915 		return (temp);
3135e57b9183Scg149915 	}
3136e57b9183Scg149915 
3137e57b9183Scg149915 	/* microcode_version != r300 */
3138e57b9183Scg149915 	while (cmdbuf.bufsz >= sizeof (header)) {
3139e57b9183Scg149915 
3140e57b9183Scg149915 		header.i = *(int *)(uintptr_t)cmdbuf.buf;
3141e57b9183Scg149915 		cmdbuf.buf += sizeof (header);
3142e57b9183Scg149915 		cmdbuf.bufsz -= sizeof (header);
3143e57b9183Scg149915 
3144e57b9183Scg149915 		switch (header.header.cmd_type) {
3145e57b9183Scg149915 		case RADEON_CMD_PACKET:
3146e57b9183Scg149915 			DRM_DEBUG("RADEON_CMD_PACKET\n");
3147e57b9183Scg149915 			if (radeon_emit_packets
3148e57b9183Scg149915 			    (dev_priv, fpriv, header, &cmdbuf)) {
3149e57b9183Scg149915 				DRM_ERROR("radeon_emit_packets failed\n");
3150e57b9183Scg149915 				goto err;
3151e57b9183Scg149915 			}
3152e57b9183Scg149915 			break;
3153e57b9183Scg149915 
3154e57b9183Scg149915 		case RADEON_CMD_SCALARS:
3155e57b9183Scg149915 			DRM_DEBUG("RADEON_CMD_SCALARS\n");
3156e57b9183Scg149915 			if (radeon_emit_scalars(dev_priv, header, &cmdbuf)) {
3157e57b9183Scg149915 				DRM_ERROR("radeon_emit_scalars failed\n");
3158e57b9183Scg149915 				goto err;
3159e57b9183Scg149915 			}
3160e57b9183Scg149915 			break;
3161e57b9183Scg149915 
3162e57b9183Scg149915 		case RADEON_CMD_VECTORS:
3163e57b9183Scg149915 			DRM_DEBUG("RADEON_CMD_VECTORS\n");
3164e57b9183Scg149915 			if (radeon_emit_vectors(dev_priv, header, &cmdbuf)) {
3165e57b9183Scg149915 				DRM_ERROR("radeon_emit_vectors failed\n");
3166e57b9183Scg149915 				goto err;
3167e57b9183Scg149915 			}
3168e57b9183Scg149915 			break;
3169e57b9183Scg149915 
3170e57b9183Scg149915 		case RADEON_CMD_DMA_DISCARD:
3171e57b9183Scg149915 			DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n");
3172e57b9183Scg149915 			idx = header.dma.buf_idx;
3173e57b9183Scg149915 			if (idx < 0 || idx >= dma->buf_count) {
3174e57b9183Scg149915 				DRM_ERROR("buffer index %d (of %d max)\n",
3175e57b9183Scg149915 				    idx, dma->buf_count - 1);
3176e57b9183Scg149915 				goto err;
3177e57b9183Scg149915 			}
3178e57b9183Scg149915 
3179e57b9183Scg149915 			buf = dma->buflist[idx];
3180e57b9183Scg149915 			if (buf->filp != fpriv || buf->pending) {
3181e57b9183Scg149915 				DRM_ERROR("bad buffer %p %p %d\n",
3182e57b9183Scg149915 				    buf->filp, fpriv, buf->pending);
3183e57b9183Scg149915 				goto err;
3184e57b9183Scg149915 			}
3185e57b9183Scg149915 
3186e57b9183Scg149915 			radeon_cp_discard_buffer(dev, buf);
3187e57b9183Scg149915 			break;
3188e57b9183Scg149915 
3189e57b9183Scg149915 		case RADEON_CMD_PACKET3:
3190e57b9183Scg149915 			DRM_DEBUG("RADEON_CMD_PACKET3\n");
3191e57b9183Scg149915 			if (radeon_emit_packet3(dev, fpriv, &cmdbuf)) {
3192e57b9183Scg149915 				DRM_ERROR("radeon_emit_packet3 failed\n");
3193e57b9183Scg149915 				goto err;
3194e57b9183Scg149915 			}
3195e57b9183Scg149915 			break;
3196e57b9183Scg149915 
3197e57b9183Scg149915 		case RADEON_CMD_PACKET3_CLIP:
3198e57b9183Scg149915 			DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n");
3199e57b9183Scg149915 			if (radeon_emit_packet3_cliprect
3200e57b9183Scg149915 			    (dev, fpriv, &cmdbuf, orig_nbox)) {
3201e57b9183Scg149915 				DRM_ERROR("radeon_emit_packet3_clip failed\n");
3202e57b9183Scg149915 				goto err;
3203e57b9183Scg149915 			}
3204e57b9183Scg149915 			break;
3205e57b9183Scg149915 
3206e57b9183Scg149915 		case RADEON_CMD_SCALARS2:
3207e57b9183Scg149915 			DRM_DEBUG("RADEON_CMD_SCALARS2\n");
3208e57b9183Scg149915 			if (radeon_emit_scalars2(dev_priv, header, &cmdbuf)) {
3209e57b9183Scg149915 				DRM_ERROR("radeon_emit_scalars2 failed\n");
3210e57b9183Scg149915 				goto err;
3211e57b9183Scg149915 			}
3212e57b9183Scg149915 			break;
3213e57b9183Scg149915 
3214e57b9183Scg149915 		case RADEON_CMD_WAIT:
3215e57b9183Scg149915 			DRM_DEBUG("RADEON_CMD_WAIT\n");
3216e57b9183Scg149915 			if (radeon_emit_wait(dev, header.wait.flags)) {
3217e57b9183Scg149915 				DRM_ERROR("radeon_emit_wait failed\n");
3218e57b9183Scg149915 				goto err;
3219e57b9183Scg149915 			}
3220e57b9183Scg149915 			break;
3221e57b9183Scg149915 		case RADEON_CMD_VECLINEAR:
3222e57b9183Scg149915 			DRM_DEBUG("RADEON_CMD_VECLINEAR\n");
3223e57b9183Scg149915 			if (radeon_emit_veclinear(dev_priv, header, &cmdbuf)) {
3224e57b9183Scg149915 				DRM_ERROR("radeon_emit_veclinear failed\n");
3225e57b9183Scg149915 				goto err;
3226e57b9183Scg149915 			}
3227e57b9183Scg149915 			break;
3228e57b9183Scg149915 
3229e57b9183Scg149915 		default:
3230e57b9183Scg149915 			DRM_ERROR("bad cmd_type %d at %p\n",
3231e57b9183Scg149915 			    header.header.cmd_type,
3232e57b9183Scg149915 			    cmdbuf.buf - sizeof (header));
3233e57b9183Scg149915 			goto err;
3234e57b9183Scg149915 		}
3235e57b9183Scg149915 	}
3236e57b9183Scg149915 
3237e57b9183Scg149915 	if (orig_bufsz != 0)
3238e57b9183Scg149915 		drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
3239e57b9183Scg149915 
3240e57b9183Scg149915 	COMMIT_RING();
3241e57b9183Scg149915 	return (0);
3242e57b9183Scg149915 
3243e57b9183Scg149915 err:
3244e57b9183Scg149915 	if (orig_bufsz != 0)
3245e57b9183Scg149915 		drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
3246e57b9183Scg149915 	return (EINVAL);
3247e57b9183Scg149915 }
3248e57b9183Scg149915 
3249e57b9183Scg149915 /*ARGSUSED*/
radeon_cp_getparam(DRM_IOCTL_ARGS)3250e57b9183Scg149915 static int radeon_cp_getparam(DRM_IOCTL_ARGS)
3251e57b9183Scg149915 {
3252e57b9183Scg149915 	DRM_DEVICE;
3253e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
3254e57b9183Scg149915 	drm_radeon_getparam_t param;
3255e57b9183Scg149915 	int value;
3256e57b9183Scg149915 
3257e57b9183Scg149915 	if (!dev_priv) {
3258e57b9183Scg149915 		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
3259e57b9183Scg149915 		return (EINVAL);
3260e57b9183Scg149915 	}
3261e57b9183Scg149915 
3262e57b9183Scg149915 #ifdef _MULTI_DATAMODEL
3263e57b9183Scg149915 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
3264e57b9183Scg149915 		drm_radeon_getparam_32_t param32;
3265e57b9183Scg149915 
3266e57b9183Scg149915 		DRM_COPYFROM_WITH_RETURN(&param32,
3267e57b9183Scg149915 		    (drm_radeon_getparam_32_t *)data, sizeof (param32));
3268e57b9183Scg149915 		param.param = param32.param;
3269e57b9183Scg149915 		param.value = (void *)(uintptr_t)param32.value;
3270e57b9183Scg149915 	} else {
3271e57b9183Scg149915 #endif
3272e57b9183Scg149915 		DRM_COPYFROM_WITH_RETURN(&param,
3273e57b9183Scg149915 		    (drm_radeon_getparam_t *)data, sizeof (param));
3274e57b9183Scg149915 #ifdef _MULTI_DATAMODEL
3275e57b9183Scg149915 	}
3276e57b9183Scg149915 #endif
3277e57b9183Scg149915 	DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
3278e57b9183Scg149915 
3279e57b9183Scg149915 	switch (param.param) {
3280e57b9183Scg149915 	case RADEON_PARAM_GART_BUFFER_OFFSET:
3281e57b9183Scg149915 		value = dev_priv->gart_buffers_offset;
3282e57b9183Scg149915 		break;
3283e57b9183Scg149915 	case RADEON_PARAM_LAST_FRAME:
3284e57b9183Scg149915 		dev_priv->stats.last_frame_reads++;
3285e57b9183Scg149915 		value = GET_SCRATCH(0);
3286e57b9183Scg149915 		break;
3287e57b9183Scg149915 	case RADEON_PARAM_LAST_DISPATCH:
3288e57b9183Scg149915 		value = GET_SCRATCH(1);
3289e57b9183Scg149915 		break;
3290e57b9183Scg149915 	case RADEON_PARAM_LAST_CLEAR:
3291e57b9183Scg149915 		dev_priv->stats.last_clear_reads++;
3292e57b9183Scg149915 		value = GET_SCRATCH(2);
3293e57b9183Scg149915 		break;
3294e57b9183Scg149915 	case RADEON_PARAM_IRQ_NR:
3295e57b9183Scg149915 		value = dev->irq;
3296e57b9183Scg149915 		break;
3297e57b9183Scg149915 	case RADEON_PARAM_GART_BASE:
3298e57b9183Scg149915 		value = dev_priv->gart_vm_start;
3299e57b9183Scg149915 		break;
3300e57b9183Scg149915 	case RADEON_PARAM_REGISTER_HANDLE:
3301e57b9183Scg149915 		value = dev_priv->mmio->offset;
3302e57b9183Scg149915 		break;
3303e57b9183Scg149915 	case RADEON_PARAM_STATUS_HANDLE:
3304e57b9183Scg149915 		value = dev_priv->ring_rptr_offset;
3305e57b9183Scg149915 		break;
3306e57b9183Scg149915 #ifndef __LP64__
3307e57b9183Scg149915 		/*
3308e57b9183Scg149915 		 * This ioctl() doesn't work on 64-bit platforms because
3309e57b9183Scg149915 		 * hw_lock is a pointer which can't fit into an int-sized
3310e57b9183Scg149915 		 * variable.  According to Michel Dänzer, the ioctl) is
3311e57b9183Scg149915 		 * only used on embedded platforms, so not supporting it
3312e57b9183Scg149915 		 * shouldn't be a problem.  If the same functionality is
3313e57b9183Scg149915 		 * needed on 64-bit platforms, a new ioctl() would have
3314e57b9183Scg149915 		 * to be added, so backwards-compatibility for the embedded
3315e57b9183Scg149915 		 * platforms can be maintained.  --davidm 4-Feb-2004.
3316e57b9183Scg149915 		 */
3317e57b9183Scg149915 	case RADEON_PARAM_SAREA_HANDLE:
3318e57b9183Scg149915 		/* The lock is the first dword in the sarea. */
3319e57b9183Scg149915 		value = (long)dev->lock.hw_lock;
3320e57b9183Scg149915 		break;
3321e57b9183Scg149915 #endif
3322e57b9183Scg149915 	case RADEON_PARAM_GART_TEX_HANDLE:
3323e57b9183Scg149915 		value = dev_priv->gart_textures_offset;
3324e57b9183Scg149915 		break;
3325e57b9183Scg149915 	case RADEON_PARAM_SCRATCH_OFFSET:
3326e57b9183Scg149915 		if (!dev_priv->writeback_works)
3327e57b9183Scg149915 			return (EINVAL);
3328e57b9183Scg149915 		value = RADEON_SCRATCH_REG_OFFSET;
3329e57b9183Scg149915 		break;
3330e57b9183Scg149915 
3331e57b9183Scg149915 	case RADEON_PARAM_CARD_TYPE:
3332e57b9183Scg149915 		if (dev_priv->flags & RADEON_IS_PCIE)
3333e57b9183Scg149915 			value = RADEON_CARD_PCIE;
3334e57b9183Scg149915 		else if (dev_priv->flags & RADEON_IS_AGP)
3335e57b9183Scg149915 			value = RADEON_CARD_AGP;
3336e57b9183Scg149915 		else
3337e57b9183Scg149915 			value = RADEON_CARD_PCI;
3338e57b9183Scg149915 		break;
3339e57b9183Scg149915 	case RADEON_PARAM_VBLANK_CRTC:
3340e57b9183Scg149915 		value = radeon_vblank_crtc_get(dev);
3341e57b9183Scg149915 		break;
3342e57b9183Scg149915 	default:
3343e57b9183Scg149915 		return (EINVAL);
3344e57b9183Scg149915 	}
3345e57b9183Scg149915 
3346e57b9183Scg149915 	if (DRM_COPY_TO_USER(param.value, &value, sizeof (int))) {
3347e57b9183Scg149915 		DRM_ERROR("copy_to_user\n");
3348e57b9183Scg149915 		return (EFAULT);
3349e57b9183Scg149915 	}
3350e57b9183Scg149915 	return (0);
3351e57b9183Scg149915 }
3352e57b9183Scg149915 
3353e57b9183Scg149915 /*ARGSUSED*/
radeon_cp_setparam(DRM_IOCTL_ARGS)3354e57b9183Scg149915 static int radeon_cp_setparam(DRM_IOCTL_ARGS)
3355e57b9183Scg149915 {
3356e57b9183Scg149915 	DRM_DEVICE;
3357e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
3358e57b9183Scg149915 	drm_radeon_setparam_t sp;
3359e57b9183Scg149915 	struct drm_radeon_driver_file_fields *radeon_priv;
3360e57b9183Scg149915 
3361e57b9183Scg149915 	if (!dev_priv) {
3362e57b9183Scg149915 		DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
3363e57b9183Scg149915 		return (EINVAL);
3364e57b9183Scg149915 	}
3365e57b9183Scg149915 
3366e57b9183Scg149915 #ifdef _MULTI_DATAMODEL
3367e57b9183Scg149915 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
3368e57b9183Scg149915 		drm_radeon_setparam_32_t sp32;
3369e57b9183Scg149915 
3370e57b9183Scg149915 		DRM_COPYFROM_WITH_RETURN(&sp32, (void *) data, sizeof (sp32));
3371e57b9183Scg149915 		sp.param = sp32.param;
3372e57b9183Scg149915 		sp.value = sp32.value;
3373e57b9183Scg149915 	} else {
3374e57b9183Scg149915 #endif
3375e57b9183Scg149915 	DRM_COPYFROM_WITH_RETURN(&sp, (void *) data, sizeof (sp));
3376e57b9183Scg149915 #ifdef _MULTI_DATAMODEL
3377e57b9183Scg149915 	}
3378e57b9183Scg149915 #endif
3379e57b9183Scg149915 	switch (sp.param) {
3380e57b9183Scg149915 	case RADEON_SETPARAM_FB_LOCATION:
3381e57b9183Scg149915 		radeon_priv = fpriv->driver_priv;
3382e57b9183Scg149915 		radeon_priv->radeon_fb_delta = dev_priv->fb_location - sp.value;
3383e57b9183Scg149915 		break;
3384e57b9183Scg149915 	case RADEON_SETPARAM_SWITCH_TILING:
3385e57b9183Scg149915 		if (sp.value == 0) {
3386e57b9183Scg149915 			DRM_DEBUG("color tiling disabled\n");
3387e57b9183Scg149915 			dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO;
3388e57b9183Scg149915 			dev_priv->back_pitch_offset &= ~RADEON_DST_TILE_MACRO;
3389e57b9183Scg149915 			dev_priv->sarea_priv->tiling_enabled = 0;
3390e57b9183Scg149915 		} else if (sp.value == 1) {
3391e57b9183Scg149915 			DRM_DEBUG("color tiling enabled\n");
3392e57b9183Scg149915 			dev_priv->front_pitch_offset |= RADEON_DST_TILE_MACRO;
3393e57b9183Scg149915 			dev_priv->back_pitch_offset |= RADEON_DST_TILE_MACRO;
3394e57b9183Scg149915 			dev_priv->sarea_priv->tiling_enabled = 1;
3395e57b9183Scg149915 		}
3396e57b9183Scg149915 		break;
3397e57b9183Scg149915 	case RADEON_SETPARAM_PCIGART_LOCATION:
3398e57b9183Scg149915 		dev_priv->pcigart_offset = (unsigned long)sp.value;
3399e57b9183Scg149915 		break;
3400e57b9183Scg149915 	case RADEON_SETPARAM_NEW_MEMMAP:
3401e57b9183Scg149915 		dev_priv->new_memmap = (int)sp.value;
3402e57b9183Scg149915 		break;
3403e57b9183Scg149915 	case RADEON_SETPARAM_VBLANK_CRTC:
3404e57b9183Scg149915 		return (radeon_vblank_crtc_set(dev, sp.value));
3405e57b9183Scg149915 	default:
3406e57b9183Scg149915 		DRM_DEBUG("Invalid parameter %d\n", sp.param);
3407e57b9183Scg149915 		return (EINVAL);
3408e57b9183Scg149915 	}
3409e57b9183Scg149915 
3410e57b9183Scg149915 	return (0);
3411e57b9183Scg149915 }
3412e57b9183Scg149915 
3413e57b9183Scg149915 /*
3414e57b9183Scg149915  * When a client dies:
3415e57b9183Scg149915  *    - Check for and clean up flipped page state
3416e57b9183Scg149915  *    - Free any alloced GART memory.
3417e57b9183Scg149915  *    - Free any alloced radeon surfaces.
3418e57b9183Scg149915  *
3419e57b9183Scg149915  * DRM infrastructure takes care of reclaiming dma buffers.
3420e57b9183Scg149915  */
3421e57b9183Scg149915 void
radeon_driver_preclose(drm_device_t * dev,drm_file_t * filp)3422e57b9183Scg149915 radeon_driver_preclose(drm_device_t *dev, drm_file_t *filp)
3423e57b9183Scg149915 {
3424e57b9183Scg149915 	if (dev->dev_private) {
3425e57b9183Scg149915 		drm_radeon_private_t *dev_priv = dev->dev_private;
3426e57b9183Scg149915 		if (dev_priv->page_flipping) {
3427e57b9183Scg149915 			(void) radeon_do_cleanup_pageflip(dev);
3428e57b9183Scg149915 		}
3429e57b9183Scg149915 		radeon_mem_release(filp, dev_priv->gart_heap);
3430e57b9183Scg149915 		radeon_mem_release(filp, dev_priv->fb_heap);
3431e57b9183Scg149915 		radeon_surfaces_release(filp, dev_priv);
3432e57b9183Scg149915 	}
3433e57b9183Scg149915 }
3434e57b9183Scg149915 
3435e57b9183Scg149915 void
radeon_driver_lastclose(drm_device_t * dev)3436e57b9183Scg149915 radeon_driver_lastclose(drm_device_t *dev)
3437e57b9183Scg149915 {
3438e57b9183Scg149915 	radeon_do_release(dev);
3439e57b9183Scg149915 }
3440e57b9183Scg149915 
3441e57b9183Scg149915 int
radeon_driver_open(drm_device_t * dev,drm_file_t * filp_priv)3442e57b9183Scg149915 radeon_driver_open(drm_device_t *dev, drm_file_t *filp_priv)
3443e57b9183Scg149915 {
3444e57b9183Scg149915 	drm_radeon_private_t *dev_priv = dev->dev_private;
3445e57b9183Scg149915 	struct drm_radeon_driver_file_fields *radeon_priv;
3446e57b9183Scg149915 
3447e57b9183Scg149915 	radeon_priv =
3448e57b9183Scg149915 	    (struct drm_radeon_driver_file_fields *)
3449e57b9183Scg149915 	    drm_alloc(sizeof (*radeon_priv), DRM_MEM_FILES);
3450e57b9183Scg149915 
3451e57b9183Scg149915 	if (!radeon_priv)
3452e57b9183Scg149915 		return (-ENOMEM);
3453e57b9183Scg149915 
3454e57b9183Scg149915 	filp_priv->driver_priv = radeon_priv;
3455e57b9183Scg149915 
3456e57b9183Scg149915 	if (dev_priv)
3457e57b9183Scg149915 		radeon_priv->radeon_fb_delta = dev_priv->fb_location;
3458e57b9183Scg149915 	else
3459e57b9183Scg149915 		radeon_priv->radeon_fb_delta = 0;
3460e57b9183Scg149915 	return (0);
3461e57b9183Scg149915 }
3462e57b9183Scg149915 
3463e57b9183Scg149915 /*ARGSUSED*/
3464e57b9183Scg149915 void
radeon_driver_postclose(drm_device_t * dev,drm_file_t * filp_priv)3465e57b9183Scg149915 radeon_driver_postclose(drm_device_t *dev, drm_file_t *filp_priv)
3466e57b9183Scg149915 {
3467e57b9183Scg149915 	struct drm_radeon_driver_file_fields *radeon_priv =
3468e57b9183Scg149915 	    filp_priv->driver_priv;
3469e57b9183Scg149915 
3470e57b9183Scg149915 	drm_free(radeon_priv, sizeof (* radeon_priv), DRM_MEM_FILES);
3471e57b9183Scg149915 }
3472e57b9183Scg149915 
3473e57b9183Scg149915 drm_ioctl_desc_t radeon_ioctls[] = {
3474e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_CP_INIT)] =
3475e57b9183Scg149915 	    {radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3476e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_CP_START)] =
3477e57b9183Scg149915 	    {radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3478e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_CP_STOP)] =
3479e57b9183Scg149915 	    {radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3480e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_CP_RESET)] =
3481e57b9183Scg149915 	    {radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3482e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_CP_IDLE)] =
3483e57b9183Scg149915 	    {radeon_cp_idle, DRM_AUTH},
3484e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_CP_RESUME)] =
3485e57b9183Scg149915 	    {radeon_cp_resume, DRM_AUTH},
3486e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_RESET)] =
3487e57b9183Scg149915 	    {radeon_engine_reset, DRM_AUTH},
3488e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_FULLSCREEN)] =
3489e57b9183Scg149915 	    {radeon_fullscreen, DRM_AUTH},
3490e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_SWAP)] =
3491e57b9183Scg149915 	    {radeon_cp_swap, DRM_AUTH},
3492e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_CLEAR)] =
3493e57b9183Scg149915 	    {radeon_cp_clear, DRM_AUTH},
3494e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_VERTEX)] =
3495e57b9183Scg149915 	    {radeon_cp_vertex, DRM_AUTH},
3496e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_INDICES)] =
3497e57b9183Scg149915 	    {radeon_cp_indices, DRM_AUTH},
3498e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_TEXTURE)] =
3499e57b9183Scg149915 	    {radeon_cp_texture, DRM_AUTH},
3500e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_STIPPLE)] =
3501e57b9183Scg149915 	    {radeon_cp_stipple, DRM_AUTH},
3502e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_INDIRECT)] =
3503e57b9183Scg149915 	    {radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3504e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_VERTEX2)] =
3505e57b9183Scg149915 	    {radeon_cp_vertex2, DRM_AUTH},
3506e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_CMDBUF)] =
3507e57b9183Scg149915 	    {radeon_cp_cmdbuf, DRM_AUTH},
3508e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_GETPARAM)] =
3509e57b9183Scg149915 	    {radeon_cp_getparam, DRM_AUTH},
3510e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_FLIP)] =
3511e57b9183Scg149915 	    {radeon_cp_flip, DRM_AUTH},
3512e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_ALLOC)] =
3513e57b9183Scg149915 	    {radeon_mem_alloc, DRM_AUTH},
3514e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_FREE)] =
3515e57b9183Scg149915 	    {radeon_mem_free, DRM_AUTH},
3516e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_INIT_HEAP)] =
3517e57b9183Scg149915 	    {radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3518e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_IRQ_EMIT)] =
3519e57b9183Scg149915 	    {radeon_irq_emit, DRM_AUTH},
3520e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_IRQ_WAIT)] =
3521e57b9183Scg149915 	    {radeon_irq_wait, DRM_AUTH},
3522e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_SETPARAM)] =
3523e57b9183Scg149915 	    {radeon_cp_setparam, DRM_AUTH},
3524e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_SURF_ALLOC)] =
3525e57b9183Scg149915 	    {radeon_surface_alloc, DRM_AUTH},
3526e57b9183Scg149915 	[DRM_IOCTL_NR(DRM_RADEON_SURF_FREE)] =
3527e57b9183Scg149915 	    {radeon_surface_free, DRM_AUTH}
3528e57b9183Scg149915 };
3529e57b9183Scg149915 
3530e57b9183Scg149915 int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls);
3531