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(¶m32,
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(¶m,
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