blob: 56e56b873616076ba3d93699bbc6eab66c0c1c57 [file] [log] [blame]
Dave Airlied985c102006-01-02 21:32:48 +11001/* radeon_state.c -- State support for Radeon -*- linux-c -*- */
2/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * Copyright 2000 VA Linux Systems, Inc., Fremont, California.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 * Authors:
26 * Gareth Hughes <gareth@valinux.com>
27 * Kevin E. Martin <martin@valinux.com>
28 */
29
30#include "drmP.h"
31#include "drm.h"
32#include "drm_sarea.h"
33#include "radeon_drm.h"
34#include "radeon_drv.h"
35
36/* ================================================================
37 * Helper functions for client state checking and fixup
38 */
39
Dave Airlieb5e89ed2005-09-25 14:28:13 +100040static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
41 dev_priv,
42 drm_file_t * filp_priv,
Dave Airlieb3a83632005-09-30 18:37:36 +100043 u32 *offset)
Dave Airlieb5e89ed2005-09-25 14:28:13 +100044{
Linus Torvalds1da177e2005-04-16 15:20:36 -070045 u32 off = *offset;
46 struct drm_radeon_driver_file_fields *radeon_priv;
47
Dave Airlied5ea7022006-03-19 19:37:55 +110048 /* Hrm ... the story of the offset ... So this function converts
49 * the various ideas of what userland clients might have for an
50 * offset in the card address space into an offset into the card
51 * address space :) So with a sane client, it should just keep
52 * the value intact and just do some boundary checking. However,
53 * not all clients are sane. Some older clients pass us 0 based
54 * offsets relative to the start of the framebuffer and some may
55 * assume the AGP aperture it appended to the framebuffer, so we
56 * try to detect those cases and fix them up.
57 *
58 * Note: It might be a good idea here to make sure the offset lands
59 * in some "allowed" area to protect things like the PCIE GART...
60 */
61
62 /* First, the best case, the offset already lands in either the
63 * framebuffer or the GART mapped space
64 */
65 if ((off >= dev_priv->fb_location &&
66 off < (dev_priv->fb_location + dev_priv->fb_size)) ||
67 (off >= dev_priv->gart_vm_start &&
68 off < (dev_priv->gart_vm_start + dev_priv->gart_size)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 return 0;
70
Dave Airlied5ea7022006-03-19 19:37:55 +110071 /* Ok, that didn't happen... now check if we have a zero based
72 * offset that fits in the framebuffer + gart space, apply the
73 * magic offset we get from SETPARAM or calculated from fb_location
74 */
75 if (off < (dev_priv->fb_size + dev_priv->gart_size)) {
76 radeon_priv = filp_priv->driver_priv;
77 off += radeon_priv->radeon_fb_delta;
78 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Dave Airlied5ea7022006-03-19 19:37:55 +110080 /* Finally, assume we aimed at a GART offset if beyond the fb */
81 if (off > (dev_priv->fb_location + dev_priv->fb_size))
82 off = off - (dev_priv->fb_location + dev_priv->fb_size) +
83 dev_priv->gart_vm_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
Dave Airlied5ea7022006-03-19 19:37:55 +110085 /* Now recheck and fail if out of bounds */
86 if ((off >= dev_priv->fb_location &&
87 off < (dev_priv->fb_location + dev_priv->fb_size)) ||
88 (off >= dev_priv->gart_vm_start &&
89 off < (dev_priv->gart_vm_start + dev_priv->gart_size))) {
90 DRM_DEBUG("offset fixed up to 0x%x\n", off);
91 *offset = off;
92 return 0;
93 }
94 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095}
96
Dave Airlieb5e89ed2005-09-25 14:28:13 +100097static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
98 dev_priv,
99 drm_file_t * filp_priv,
Dave Airlieb3a83632005-09-30 18:37:36 +1000100 int id, u32 *data)
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000101{
102 switch (id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
104 case RADEON_EMIT_PP_MISC:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000105 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
Dave Airlied985c102006-01-02 21:32:48 +1100106 &data[(RADEON_RB3D_DEPTHOFFSET - RADEON_PP_MISC) / 4])) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000107 DRM_ERROR("Invalid depth buffer offset\n");
108 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 }
110 break;
111
112 case RADEON_EMIT_PP_CNTL:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000113 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
Dave Airlied985c102006-01-02 21:32:48 +1100114 &data[(RADEON_RB3D_COLOROFFSET - RADEON_PP_CNTL) / 4])) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000115 DRM_ERROR("Invalid colour buffer offset\n");
116 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 }
118 break;
119
120 case R200_EMIT_PP_TXOFFSET_0:
121 case R200_EMIT_PP_TXOFFSET_1:
122 case R200_EMIT_PP_TXOFFSET_2:
123 case R200_EMIT_PP_TXOFFSET_3:
124 case R200_EMIT_PP_TXOFFSET_4:
125 case R200_EMIT_PP_TXOFFSET_5:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000126 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
127 &data[0])) {
128 DRM_ERROR("Invalid R200 texture offset\n");
129 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 }
131 break;
132
133 case RADEON_EMIT_PP_TXFILTER_0:
134 case RADEON_EMIT_PP_TXFILTER_1:
135 case RADEON_EMIT_PP_TXFILTER_2:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000136 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
Dave Airlied985c102006-01-02 21:32:48 +1100137 &data[(RADEON_PP_TXOFFSET_0 - RADEON_PP_TXFILTER_0) / 4])) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000138 DRM_ERROR("Invalid R100 texture offset\n");
139 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 }
141 break;
142
143 case R200_EMIT_PP_CUBIC_OFFSETS_0:
144 case R200_EMIT_PP_CUBIC_OFFSETS_1:
145 case R200_EMIT_PP_CUBIC_OFFSETS_2:
146 case R200_EMIT_PP_CUBIC_OFFSETS_3:
147 case R200_EMIT_PP_CUBIC_OFFSETS_4:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000148 case R200_EMIT_PP_CUBIC_OFFSETS_5:{
149 int i;
150 for (i = 0; i < 5; i++) {
Dave Airlied985c102006-01-02 21:32:48 +1100151 if (radeon_check_and_fixup_offset(dev_priv,
152 filp_priv,
153 &data[i])) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000154 DRM_ERROR
155 ("Invalid R200 cubic texture offset\n");
156 return DRM_ERR(EINVAL);
157 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000159 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
162 case RADEON_EMIT_PP_CUBIC_OFFSETS_T0:
163 case RADEON_EMIT_PP_CUBIC_OFFSETS_T1:
164 case RADEON_EMIT_PP_CUBIC_OFFSETS_T2:{
165 int i;
166 for (i = 0; i < 5; i++) {
167 if (radeon_check_and_fixup_offset(dev_priv,
168 filp_priv,
169 &data[i])) {
170 DRM_ERROR
171 ("Invalid R100 cubic texture offset\n");
172 return DRM_ERR(EINVAL);
173 }
174 }
175 }
176 break;
177
178 case RADEON_EMIT_RB3D_COLORPITCH:
179 case RADEON_EMIT_RE_LINE_PATTERN:
180 case RADEON_EMIT_SE_LINE_WIDTH:
181 case RADEON_EMIT_PP_LUM_MATRIX:
182 case RADEON_EMIT_PP_ROT_MATRIX_0:
183 case RADEON_EMIT_RB3D_STENCILREFMASK:
184 case RADEON_EMIT_SE_VPORT_XSCALE:
185 case RADEON_EMIT_SE_CNTL:
186 case RADEON_EMIT_SE_CNTL_STATUS:
187 case RADEON_EMIT_RE_MISC:
188 case RADEON_EMIT_PP_BORDER_COLOR_0:
189 case RADEON_EMIT_PP_BORDER_COLOR_1:
190 case RADEON_EMIT_PP_BORDER_COLOR_2:
191 case RADEON_EMIT_SE_ZBIAS_FACTOR:
192 case RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT:
193 case RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED:
194 case R200_EMIT_PP_TXCBLEND_0:
195 case R200_EMIT_PP_TXCBLEND_1:
196 case R200_EMIT_PP_TXCBLEND_2:
197 case R200_EMIT_PP_TXCBLEND_3:
198 case R200_EMIT_PP_TXCBLEND_4:
199 case R200_EMIT_PP_TXCBLEND_5:
200 case R200_EMIT_PP_TXCBLEND_6:
201 case R200_EMIT_PP_TXCBLEND_7:
202 case R200_EMIT_TCL_LIGHT_MODEL_CTL_0:
203 case R200_EMIT_TFACTOR_0:
204 case R200_EMIT_VTX_FMT_0:
205 case R200_EMIT_VAP_CTL:
206 case R200_EMIT_MATRIX_SELECT_0:
207 case R200_EMIT_TEX_PROC_CTL_2:
208 case R200_EMIT_TCL_UCP_VERT_BLEND_CTL:
209 case R200_EMIT_PP_TXFILTER_0:
210 case R200_EMIT_PP_TXFILTER_1:
211 case R200_EMIT_PP_TXFILTER_2:
212 case R200_EMIT_PP_TXFILTER_3:
213 case R200_EMIT_PP_TXFILTER_4:
214 case R200_EMIT_PP_TXFILTER_5:
215 case R200_EMIT_VTE_CNTL:
216 case R200_EMIT_OUTPUT_VTX_COMP_SEL:
217 case R200_EMIT_PP_TAM_DEBUG3:
218 case R200_EMIT_PP_CNTL_X:
219 case R200_EMIT_RB3D_DEPTHXY_OFFSET:
220 case R200_EMIT_RE_AUX_SCISSOR_CNTL:
221 case R200_EMIT_RE_SCISSOR_TL_0:
222 case R200_EMIT_RE_SCISSOR_TL_1:
223 case R200_EMIT_RE_SCISSOR_TL_2:
224 case R200_EMIT_SE_VAP_CNTL_STATUS:
225 case R200_EMIT_SE_VTX_STATE_CNTL:
226 case R200_EMIT_RE_POINTSIZE:
227 case R200_EMIT_TCL_INPUT_VTX_VECTOR_ADDR_0:
228 case R200_EMIT_PP_CUBIC_FACES_0:
229 case R200_EMIT_PP_CUBIC_FACES_1:
230 case R200_EMIT_PP_CUBIC_FACES_2:
231 case R200_EMIT_PP_CUBIC_FACES_3:
232 case R200_EMIT_PP_CUBIC_FACES_4:
233 case R200_EMIT_PP_CUBIC_FACES_5:
234 case RADEON_EMIT_PP_TEX_SIZE_0:
235 case RADEON_EMIT_PP_TEX_SIZE_1:
236 case RADEON_EMIT_PP_TEX_SIZE_2:
237 case R200_EMIT_RB3D_BLENDCOLOR:
238 case R200_EMIT_TCL_POINT_SPRITE_CNTL:
239 case RADEON_EMIT_PP_CUBIC_FACES_0:
240 case RADEON_EMIT_PP_CUBIC_FACES_1:
241 case RADEON_EMIT_PP_CUBIC_FACES_2:
242 case R200_EMIT_PP_TRI_PERF_CNTL:
Dave Airlie9d176012005-09-11 19:55:53 +1000243 case R200_EMIT_PP_AFS_0:
244 case R200_EMIT_PP_AFS_1:
245 case R200_EMIT_ATF_TFACTOR:
246 case R200_EMIT_PP_TXCTLALL_0:
247 case R200_EMIT_PP_TXCTLALL_1:
248 case R200_EMIT_PP_TXCTLALL_2:
249 case R200_EMIT_PP_TXCTLALL_3:
250 case R200_EMIT_PP_TXCTLALL_4:
251 case R200_EMIT_PP_TXCTLALL_5:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 /* These packets don't contain memory offsets */
253 break;
254
255 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000256 DRM_ERROR("Unknown state packet ID %d\n", id);
257 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 }
259
260 return 0;
261}
262
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000263static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
264 dev_priv,
Dave Airlied985c102006-01-02 21:32:48 +1100265 drm_file_t *filp_priv,
266 drm_radeon_kcmd_buffer_t *
267 cmdbuf,
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000268 unsigned int *cmdsz)
269{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 u32 *cmd = (u32 *) cmdbuf->buf;
271
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000272 *cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000274 if ((cmd[0] & 0xc0000000) != RADEON_CP_PACKET3) {
275 DRM_ERROR("Not a type 3 packet\n");
276 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 }
278
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000279 if (4 * *cmdsz > cmdbuf->bufsz) {
280 DRM_ERROR("Packet size larger than size of data provided\n");
281 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 }
283
284 /* Check client state and fix it up if necessary */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000285 if (cmd[0] & 0x8000) { /* MSB of opcode: next DWORD GUI_CNTL */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 u32 offset;
287
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000288 if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
289 | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 offset = cmd[2] << 10;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000291 if (radeon_check_and_fixup_offset
292 (dev_priv, filp_priv, &offset)) {
293 DRM_ERROR("Invalid first packet offset\n");
294 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000296 cmd[2] = (cmd[2] & 0xffc00000) | offset >> 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 }
298
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000299 if ((cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&
300 (cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 offset = cmd[3] << 10;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000302 if (radeon_check_and_fixup_offset
303 (dev_priv, filp_priv, &offset)) {
304 DRM_ERROR("Invalid second packet offset\n");
305 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000307 cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 }
309 }
310
311 return 0;
312}
313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314/* ================================================================
315 * CP hardware state programming functions
316 */
317
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000318static __inline__ void radeon_emit_clip_rect(drm_radeon_private_t * dev_priv,
319 drm_clip_rect_t * box)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320{
321 RING_LOCALS;
322
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000323 DRM_DEBUG(" box: x1=%d y1=%d x2=%d y2=%d\n",
324 box->x1, box->y1, box->x2, box->y2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000326 BEGIN_RING(4);
327 OUT_RING(CP_PACKET0(RADEON_RE_TOP_LEFT, 0));
328 OUT_RING((box->y1 << 16) | box->x1);
329 OUT_RING(CP_PACKET0(RADEON_RE_WIDTH_HEIGHT, 0));
330 OUT_RING(((box->y2 - 1) << 16) | (box->x2 - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 ADVANCE_RING();
332}
333
334/* Emit 1.1 state
335 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000336static int radeon_emit_state(drm_radeon_private_t * dev_priv,
337 drm_file_t * filp_priv,
338 drm_radeon_context_regs_t * ctx,
339 drm_radeon_texture_regs_t * tex,
340 unsigned int dirty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341{
342 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000343 DRM_DEBUG("dirty=0x%08x\n", dirty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000345 if (dirty & RADEON_UPLOAD_CONTEXT) {
346 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
347 &ctx->rb3d_depthoffset)) {
348 DRM_ERROR("Invalid depth buffer offset\n");
349 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 }
351
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000352 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
353 &ctx->rb3d_coloroffset)) {
354 DRM_ERROR("Invalid depth buffer offset\n");
355 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 }
357
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000358 BEGIN_RING(14);
359 OUT_RING(CP_PACKET0(RADEON_PP_MISC, 6));
360 OUT_RING(ctx->pp_misc);
361 OUT_RING(ctx->pp_fog_color);
362 OUT_RING(ctx->re_solid_color);
363 OUT_RING(ctx->rb3d_blendcntl);
364 OUT_RING(ctx->rb3d_depthoffset);
365 OUT_RING(ctx->rb3d_depthpitch);
366 OUT_RING(ctx->rb3d_zstencilcntl);
367 OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 2));
368 OUT_RING(ctx->pp_cntl);
369 OUT_RING(ctx->rb3d_cntl);
370 OUT_RING(ctx->rb3d_coloroffset);
371 OUT_RING(CP_PACKET0(RADEON_RB3D_COLORPITCH, 0));
372 OUT_RING(ctx->rb3d_colorpitch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 ADVANCE_RING();
374 }
375
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000376 if (dirty & RADEON_UPLOAD_VERTFMT) {
377 BEGIN_RING(2);
378 OUT_RING(CP_PACKET0(RADEON_SE_COORD_FMT, 0));
379 OUT_RING(ctx->se_coord_fmt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 ADVANCE_RING();
381 }
382
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000383 if (dirty & RADEON_UPLOAD_LINE) {
384 BEGIN_RING(5);
385 OUT_RING(CP_PACKET0(RADEON_RE_LINE_PATTERN, 1));
386 OUT_RING(ctx->re_line_pattern);
387 OUT_RING(ctx->re_line_state);
388 OUT_RING(CP_PACKET0(RADEON_SE_LINE_WIDTH, 0));
389 OUT_RING(ctx->se_line_width);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 ADVANCE_RING();
391 }
392
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000393 if (dirty & RADEON_UPLOAD_BUMPMAP) {
394 BEGIN_RING(5);
395 OUT_RING(CP_PACKET0(RADEON_PP_LUM_MATRIX, 0));
396 OUT_RING(ctx->pp_lum_matrix);
397 OUT_RING(CP_PACKET0(RADEON_PP_ROT_MATRIX_0, 1));
398 OUT_RING(ctx->pp_rot_matrix_0);
399 OUT_RING(ctx->pp_rot_matrix_1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 ADVANCE_RING();
401 }
402
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000403 if (dirty & RADEON_UPLOAD_MASKS) {
404 BEGIN_RING(4);
405 OUT_RING(CP_PACKET0(RADEON_RB3D_STENCILREFMASK, 2));
406 OUT_RING(ctx->rb3d_stencilrefmask);
407 OUT_RING(ctx->rb3d_ropcntl);
408 OUT_RING(ctx->rb3d_planemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 ADVANCE_RING();
410 }
411
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000412 if (dirty & RADEON_UPLOAD_VIEWPORT) {
413 BEGIN_RING(7);
414 OUT_RING(CP_PACKET0(RADEON_SE_VPORT_XSCALE, 5));
415 OUT_RING(ctx->se_vport_xscale);
416 OUT_RING(ctx->se_vport_xoffset);
417 OUT_RING(ctx->se_vport_yscale);
418 OUT_RING(ctx->se_vport_yoffset);
419 OUT_RING(ctx->se_vport_zscale);
420 OUT_RING(ctx->se_vport_zoffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 ADVANCE_RING();
422 }
423
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000424 if (dirty & RADEON_UPLOAD_SETUP) {
425 BEGIN_RING(4);
426 OUT_RING(CP_PACKET0(RADEON_SE_CNTL, 0));
427 OUT_RING(ctx->se_cntl);
428 OUT_RING(CP_PACKET0(RADEON_SE_CNTL_STATUS, 0));
429 OUT_RING(ctx->se_cntl_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 ADVANCE_RING();
431 }
432
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000433 if (dirty & RADEON_UPLOAD_MISC) {
434 BEGIN_RING(2);
435 OUT_RING(CP_PACKET0(RADEON_RE_MISC, 0));
436 OUT_RING(ctx->re_misc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 ADVANCE_RING();
438 }
439
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000440 if (dirty & RADEON_UPLOAD_TEX0) {
441 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
442 &tex[0].pp_txoffset)) {
443 DRM_ERROR("Invalid texture offset for unit 0\n");
444 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 }
446
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000447 BEGIN_RING(9);
448 OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_0, 5));
449 OUT_RING(tex[0].pp_txfilter);
450 OUT_RING(tex[0].pp_txformat);
451 OUT_RING(tex[0].pp_txoffset);
452 OUT_RING(tex[0].pp_txcblend);
453 OUT_RING(tex[0].pp_txablend);
454 OUT_RING(tex[0].pp_tfactor);
455 OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_0, 0));
456 OUT_RING(tex[0].pp_border_color);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 ADVANCE_RING();
458 }
459
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000460 if (dirty & RADEON_UPLOAD_TEX1) {
461 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
462 &tex[1].pp_txoffset)) {
463 DRM_ERROR("Invalid texture offset for unit 1\n");
464 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 }
466
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000467 BEGIN_RING(9);
468 OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_1, 5));
469 OUT_RING(tex[1].pp_txfilter);
470 OUT_RING(tex[1].pp_txformat);
471 OUT_RING(tex[1].pp_txoffset);
472 OUT_RING(tex[1].pp_txcblend);
473 OUT_RING(tex[1].pp_txablend);
474 OUT_RING(tex[1].pp_tfactor);
475 OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_1, 0));
476 OUT_RING(tex[1].pp_border_color);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 ADVANCE_RING();
478 }
479
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000480 if (dirty & RADEON_UPLOAD_TEX2) {
481 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
482 &tex[2].pp_txoffset)) {
483 DRM_ERROR("Invalid texture offset for unit 2\n");
484 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 }
486
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000487 BEGIN_RING(9);
488 OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_2, 5));
489 OUT_RING(tex[2].pp_txfilter);
490 OUT_RING(tex[2].pp_txformat);
491 OUT_RING(tex[2].pp_txoffset);
492 OUT_RING(tex[2].pp_txcblend);
493 OUT_RING(tex[2].pp_txablend);
494 OUT_RING(tex[2].pp_tfactor);
495 OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_2, 0));
496 OUT_RING(tex[2].pp_border_color);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 ADVANCE_RING();
498 }
499
500 return 0;
501}
502
503/* Emit 1.2 state
504 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000505static int radeon_emit_state2(drm_radeon_private_t * dev_priv,
506 drm_file_t * filp_priv,
507 drm_radeon_state_t * state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508{
509 RING_LOCALS;
510
511 if (state->dirty & RADEON_UPLOAD_ZBIAS) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000512 BEGIN_RING(3);
513 OUT_RING(CP_PACKET0(RADEON_SE_ZBIAS_FACTOR, 1));
514 OUT_RING(state->context2.se_zbias_factor);
515 OUT_RING(state->context2.se_zbias_constant);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 ADVANCE_RING();
517 }
518
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000519 return radeon_emit_state(dev_priv, filp_priv, &state->context,
520 state->tex, state->dirty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521}
522
523/* New (1.3) state mechanism. 3 commands (packet, scalar, vector) in
524 * 1.3 cmdbuffers allow all previous state to be updated as well as
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000525 * the tcl scalar and vector areas.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000527static struct {
528 int start;
529 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 const char *name;
531} packet[RADEON_MAX_STATE_PACKETS] = {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000532 {RADEON_PP_MISC, 7, "RADEON_PP_MISC"},
533 {RADEON_PP_CNTL, 3, "RADEON_PP_CNTL"},
534 {RADEON_RB3D_COLORPITCH, 1, "RADEON_RB3D_COLORPITCH"},
535 {RADEON_RE_LINE_PATTERN, 2, "RADEON_RE_LINE_PATTERN"},
536 {RADEON_SE_LINE_WIDTH, 1, "RADEON_SE_LINE_WIDTH"},
537 {RADEON_PP_LUM_MATRIX, 1, "RADEON_PP_LUM_MATRIX"},
538 {RADEON_PP_ROT_MATRIX_0, 2, "RADEON_PP_ROT_MATRIX_0"},
539 {RADEON_RB3D_STENCILREFMASK, 3, "RADEON_RB3D_STENCILREFMASK"},
540 {RADEON_SE_VPORT_XSCALE, 6, "RADEON_SE_VPORT_XSCALE"},
541 {RADEON_SE_CNTL, 2, "RADEON_SE_CNTL"},
542 {RADEON_SE_CNTL_STATUS, 1, "RADEON_SE_CNTL_STATUS"},
543 {RADEON_RE_MISC, 1, "RADEON_RE_MISC"},
544 {RADEON_PP_TXFILTER_0, 6, "RADEON_PP_TXFILTER_0"},
545 {RADEON_PP_BORDER_COLOR_0, 1, "RADEON_PP_BORDER_COLOR_0"},
546 {RADEON_PP_TXFILTER_1, 6, "RADEON_PP_TXFILTER_1"},
547 {RADEON_PP_BORDER_COLOR_1, 1, "RADEON_PP_BORDER_COLOR_1"},
548 {RADEON_PP_TXFILTER_2, 6, "RADEON_PP_TXFILTER_2"},
549 {RADEON_PP_BORDER_COLOR_2, 1, "RADEON_PP_BORDER_COLOR_2"},
550 {RADEON_SE_ZBIAS_FACTOR, 2, "RADEON_SE_ZBIAS_FACTOR"},
551 {RADEON_SE_TCL_OUTPUT_VTX_FMT, 11, "RADEON_SE_TCL_OUTPUT_VTX_FMT"},
552 {RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED, 17,
553 "RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED"},
554 {R200_PP_TXCBLEND_0, 4, "R200_PP_TXCBLEND_0"},
555 {R200_PP_TXCBLEND_1, 4, "R200_PP_TXCBLEND_1"},
556 {R200_PP_TXCBLEND_2, 4, "R200_PP_TXCBLEND_2"},
557 {R200_PP_TXCBLEND_3, 4, "R200_PP_TXCBLEND_3"},
558 {R200_PP_TXCBLEND_4, 4, "R200_PP_TXCBLEND_4"},
559 {R200_PP_TXCBLEND_5, 4, "R200_PP_TXCBLEND_5"},
560 {R200_PP_TXCBLEND_6, 4, "R200_PP_TXCBLEND_6"},
561 {R200_PP_TXCBLEND_7, 4, "R200_PP_TXCBLEND_7"},
562 {R200_SE_TCL_LIGHT_MODEL_CTL_0, 6, "R200_SE_TCL_LIGHT_MODEL_CTL_0"},
563 {R200_PP_TFACTOR_0, 6, "R200_PP_TFACTOR_0"},
564 {R200_SE_VTX_FMT_0, 4, "R200_SE_VTX_FMT_0"},
565 {R200_SE_VAP_CNTL, 1, "R200_SE_VAP_CNTL"},
566 {R200_SE_TCL_MATRIX_SEL_0, 5, "R200_SE_TCL_MATRIX_SEL_0"},
567 {R200_SE_TCL_TEX_PROC_CTL_2, 5, "R200_SE_TCL_TEX_PROC_CTL_2"},
568 {R200_SE_TCL_UCP_VERT_BLEND_CTL, 1, "R200_SE_TCL_UCP_VERT_BLEND_CTL"},
569 {R200_PP_TXFILTER_0, 6, "R200_PP_TXFILTER_0"},
570 {R200_PP_TXFILTER_1, 6, "R200_PP_TXFILTER_1"},
571 {R200_PP_TXFILTER_2, 6, "R200_PP_TXFILTER_2"},
572 {R200_PP_TXFILTER_3, 6, "R200_PP_TXFILTER_3"},
573 {R200_PP_TXFILTER_4, 6, "R200_PP_TXFILTER_4"},
574 {R200_PP_TXFILTER_5, 6, "R200_PP_TXFILTER_5"},
575 {R200_PP_TXOFFSET_0, 1, "R200_PP_TXOFFSET_0"},
576 {R200_PP_TXOFFSET_1, 1, "R200_PP_TXOFFSET_1"},
577 {R200_PP_TXOFFSET_2, 1, "R200_PP_TXOFFSET_2"},
578 {R200_PP_TXOFFSET_3, 1, "R200_PP_TXOFFSET_3"},
579 {R200_PP_TXOFFSET_4, 1, "R200_PP_TXOFFSET_4"},
580 {R200_PP_TXOFFSET_5, 1, "R200_PP_TXOFFSET_5"},
581 {R200_SE_VTE_CNTL, 1, "R200_SE_VTE_CNTL"},
Dave Airlied985c102006-01-02 21:32:48 +1100582 {R200_SE_TCL_OUTPUT_VTX_COMP_SEL, 1,
583 "R200_SE_TCL_OUTPUT_VTX_COMP_SEL"},
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000584 {R200_PP_TAM_DEBUG3, 1, "R200_PP_TAM_DEBUG3"},
585 {R200_PP_CNTL_X, 1, "R200_PP_CNTL_X"},
586 {R200_RB3D_DEPTHXY_OFFSET, 1, "R200_RB3D_DEPTHXY_OFFSET"},
587 {R200_RE_AUX_SCISSOR_CNTL, 1, "R200_RE_AUX_SCISSOR_CNTL"},
588 {R200_RE_SCISSOR_TL_0, 2, "R200_RE_SCISSOR_TL_0"},
589 {R200_RE_SCISSOR_TL_1, 2, "R200_RE_SCISSOR_TL_1"},
590 {R200_RE_SCISSOR_TL_2, 2, "R200_RE_SCISSOR_TL_2"},
591 {R200_SE_VAP_CNTL_STATUS, 1, "R200_SE_VAP_CNTL_STATUS"},
592 {R200_SE_VTX_STATE_CNTL, 1, "R200_SE_VTX_STATE_CNTL"},
593 {R200_RE_POINTSIZE, 1, "R200_RE_POINTSIZE"},
594 {R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0, 4,
595 "R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0"},
596 {R200_PP_CUBIC_FACES_0, 1, "R200_PP_CUBIC_FACES_0"}, /* 61 */
Dave Airlied985c102006-01-02 21:32:48 +1100597 {R200_PP_CUBIC_OFFSET_F1_0, 5, "R200_PP_CUBIC_OFFSET_F1_0"}, /* 62 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000598 {R200_PP_CUBIC_FACES_1, 1, "R200_PP_CUBIC_FACES_1"},
599 {R200_PP_CUBIC_OFFSET_F1_1, 5, "R200_PP_CUBIC_OFFSET_F1_1"},
600 {R200_PP_CUBIC_FACES_2, 1, "R200_PP_CUBIC_FACES_2"},
601 {R200_PP_CUBIC_OFFSET_F1_2, 5, "R200_PP_CUBIC_OFFSET_F1_2"},
602 {R200_PP_CUBIC_FACES_3, 1, "R200_PP_CUBIC_FACES_3"},
603 {R200_PP_CUBIC_OFFSET_F1_3, 5, "R200_PP_CUBIC_OFFSET_F1_3"},
604 {R200_PP_CUBIC_FACES_4, 1, "R200_PP_CUBIC_FACES_4"},
605 {R200_PP_CUBIC_OFFSET_F1_4, 5, "R200_PP_CUBIC_OFFSET_F1_4"},
606 {R200_PP_CUBIC_FACES_5, 1, "R200_PP_CUBIC_FACES_5"},
607 {R200_PP_CUBIC_OFFSET_F1_5, 5, "R200_PP_CUBIC_OFFSET_F1_5"},
608 {RADEON_PP_TEX_SIZE_0, 2, "RADEON_PP_TEX_SIZE_0"},
609 {RADEON_PP_TEX_SIZE_1, 2, "RADEON_PP_TEX_SIZE_1"},
610 {RADEON_PP_TEX_SIZE_2, 2, "RADEON_PP_TEX_SIZE_2"},
611 {R200_RB3D_BLENDCOLOR, 3, "R200_RB3D_BLENDCOLOR"},
612 {R200_SE_TCL_POINT_SPRITE_CNTL, 1, "R200_SE_TCL_POINT_SPRITE_CNTL"},
613 {RADEON_PP_CUBIC_FACES_0, 1, "RADEON_PP_CUBIC_FACES_0"},
614 {RADEON_PP_CUBIC_OFFSET_T0_0, 5, "RADEON_PP_CUBIC_OFFSET_T0_0"},
615 {RADEON_PP_CUBIC_FACES_1, 1, "RADEON_PP_CUBIC_FACES_1"},
616 {RADEON_PP_CUBIC_OFFSET_T1_0, 5, "RADEON_PP_CUBIC_OFFSET_T1_0"},
617 {RADEON_PP_CUBIC_FACES_2, 1, "RADEON_PP_CUBIC_FACES_2"},
618 {RADEON_PP_CUBIC_OFFSET_T2_0, 5, "RADEON_PP_CUBIC_OFFSET_T2_0"},
619 {R200_PP_TRI_PERF, 2, "R200_PP_TRI_PERF"},
Dave Airlied985c102006-01-02 21:32:48 +1100620 {R200_PP_AFS_0, 32, "R200_PP_AFS_0"}, /* 85 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000621 {R200_PP_AFS_1, 32, "R200_PP_AFS_1"},
622 {R200_PP_TFACTOR_0, 8, "R200_ATF_TFACTOR"},
623 {R200_PP_TXFILTER_0, 8, "R200_PP_TXCTLALL_0"},
624 {R200_PP_TXFILTER_1, 8, "R200_PP_TXCTLALL_1"},
625 {R200_PP_TXFILTER_2, 8, "R200_PP_TXCTLALL_2"},
626 {R200_PP_TXFILTER_3, 8, "R200_PP_TXCTLALL_3"},
627 {R200_PP_TXFILTER_4, 8, "R200_PP_TXCTLALL_4"},
628 {R200_PP_TXFILTER_5, 8, "R200_PP_TXCTLALL_5"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629};
630
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631/* ================================================================
632 * Performance monitoring functions
633 */
634
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000635static void radeon_clear_box(drm_radeon_private_t * dev_priv,
636 int x, int y, int w, int h, int r, int g, int b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637{
638 u32 color;
639 RING_LOCALS;
640
641 x += dev_priv->sarea_priv->boxes[0].x1;
642 y += dev_priv->sarea_priv->boxes[0].y1;
643
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000644 switch (dev_priv->color_fmt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 case RADEON_COLOR_FORMAT_RGB565:
646 color = (((r & 0xf8) << 8) |
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000647 ((g & 0xfc) << 3) | ((b & 0xf8) >> 3));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 break;
649 case RADEON_COLOR_FORMAT_ARGB8888:
650 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000651 color = (((0xff) << 24) | (r << 16) | (g << 8) | b);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 break;
653 }
654
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000655 BEGIN_RING(4);
656 RADEON_WAIT_UNTIL_3D_IDLE();
657 OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0));
658 OUT_RING(0xffffffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 ADVANCE_RING();
660
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000661 BEGIN_RING(6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000663 OUT_RING(CP_PACKET3(RADEON_CNTL_PAINT_MULTI, 4));
664 OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
665 RADEON_GMC_BRUSH_SOLID_COLOR |
666 (dev_priv->color_fmt << 8) |
667 RADEON_GMC_SRC_DATATYPE_COLOR |
668 RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000670 if (dev_priv->page_flipping && dev_priv->current_page == 1) {
671 OUT_RING(dev_priv->front_pitch_offset);
672 } else {
673 OUT_RING(dev_priv->back_pitch_offset);
674 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000676 OUT_RING(color);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000678 OUT_RING((x << 16) | y);
679 OUT_RING((w << 16) | h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
681 ADVANCE_RING();
682}
683
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000684static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685{
686 /* Collapse various things into a wait flag -- trying to
687 * guess if userspase slept -- better just to have them tell us.
688 */
689 if (dev_priv->stats.last_frame_reads > 1 ||
690 dev_priv->stats.last_clear_reads > dev_priv->stats.clears) {
691 dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
692 }
693
694 if (dev_priv->stats.freelist_loops) {
695 dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
696 }
697
698 /* Purple box for page flipping
699 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000700 if (dev_priv->stats.boxes & RADEON_BOX_FLIP)
701 radeon_clear_box(dev_priv, 4, 4, 8, 8, 255, 0, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
703 /* Red box if we have to wait for idle at any point
704 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000705 if (dev_priv->stats.boxes & RADEON_BOX_WAIT_IDLE)
706 radeon_clear_box(dev_priv, 16, 4, 8, 8, 255, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
708 /* Blue box: lost context?
709 */
710
711 /* Yellow box for texture swaps
712 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000713 if (dev_priv->stats.boxes & RADEON_BOX_TEXTURE_LOAD)
714 radeon_clear_box(dev_priv, 40, 4, 8, 8, 255, 255, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
716 /* Green box if hardware never idles (as far as we can tell)
717 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000718 if (!(dev_priv->stats.boxes & RADEON_BOX_DMA_IDLE))
719 radeon_clear_box(dev_priv, 64, 4, 8, 8, 0, 255, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000721 /* Draw bars indicating number of buffers allocated
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 * (not a great measure, easily confused)
723 */
724 if (dev_priv->stats.requested_bufs) {
725 if (dev_priv->stats.requested_bufs > 100)
726 dev_priv->stats.requested_bufs = 100;
727
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000728 radeon_clear_box(dev_priv, 4, 16,
729 dev_priv->stats.requested_bufs, 4,
730 196, 128, 128);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 }
732
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000733 memset(&dev_priv->stats, 0, sizeof(dev_priv->stats));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
735}
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000736
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737/* ================================================================
738 * CP command dispatch functions
739 */
740
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000741static void radeon_cp_dispatch_clear(drm_device_t * dev,
742 drm_radeon_clear_t * clear,
743 drm_radeon_clear_rect_t * depth_boxes)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744{
745 drm_radeon_private_t *dev_priv = dev->dev_private;
746 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
747 drm_radeon_depth_clear_t *depth_clear = &dev_priv->depth_clear;
748 int nbox = sarea_priv->nbox;
749 drm_clip_rect_t *pbox = sarea_priv->boxes;
750 unsigned int flags = clear->flags;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000751 u32 rb3d_cntl = 0, rb3d_stencilrefmask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 int i;
753 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000754 DRM_DEBUG("flags = 0x%x\n", flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
756 dev_priv->stats.clears++;
757
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000758 if (dev_priv->page_flipping && dev_priv->current_page == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 unsigned int tmp = flags;
760
761 flags &= ~(RADEON_FRONT | RADEON_BACK);
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000762 if (tmp & RADEON_FRONT)
763 flags |= RADEON_BACK;
764 if (tmp & RADEON_BACK)
765 flags |= RADEON_FRONT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 }
767
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000768 if (flags & (RADEON_FRONT | RADEON_BACK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000770 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
772 /* Ensure the 3D stream is idle before doing a
773 * 2D fill to clear the front or back buffer.
774 */
775 RADEON_WAIT_UNTIL_3D_IDLE();
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000776
777 OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0));
778 OUT_RING(clear->color_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
780 ADVANCE_RING();
781
782 /* Make sure we restore the 3D state next time.
783 */
784 dev_priv->sarea_priv->ctx_owner = 0;
785
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000786 for (i = 0; i < nbox; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 int x = pbox[i].x1;
788 int y = pbox[i].y1;
789 int w = pbox[i].x2 - x;
790 int h = pbox[i].y2 - y;
791
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000792 DRM_DEBUG("dispatch clear %d,%d-%d,%d flags 0x%x\n",
793 x, y, w, h, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000795 if (flags & RADEON_FRONT) {
796 BEGIN_RING(6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000798 OUT_RING(CP_PACKET3
799 (RADEON_CNTL_PAINT_MULTI, 4));
800 OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
801 RADEON_GMC_BRUSH_SOLID_COLOR |
802 (dev_priv->
803 color_fmt << 8) |
804 RADEON_GMC_SRC_DATATYPE_COLOR |
805 RADEON_ROP3_P |
806 RADEON_GMC_CLR_CMP_CNTL_DIS);
807
808 OUT_RING(dev_priv->front_pitch_offset);
809 OUT_RING(clear->clear_color);
810
811 OUT_RING((x << 16) | y);
812 OUT_RING((w << 16) | h);
813
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 ADVANCE_RING();
815 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000817 if (flags & RADEON_BACK) {
818 BEGIN_RING(6);
819
820 OUT_RING(CP_PACKET3
821 (RADEON_CNTL_PAINT_MULTI, 4));
822 OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
823 RADEON_GMC_BRUSH_SOLID_COLOR |
824 (dev_priv->
825 color_fmt << 8) |
826 RADEON_GMC_SRC_DATATYPE_COLOR |
827 RADEON_ROP3_P |
828 RADEON_GMC_CLR_CMP_CNTL_DIS);
829
830 OUT_RING(dev_priv->back_pitch_offset);
831 OUT_RING(clear->clear_color);
832
833 OUT_RING((x << 16) | y);
834 OUT_RING((w << 16) | h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
836 ADVANCE_RING();
837 }
838 }
839 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000840
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 /* hyper z clear */
842 /* no docs available, based on reverse engeneering by Stephane Marchesin */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000843 if ((flags & (RADEON_DEPTH | RADEON_STENCIL))
844 && (flags & RADEON_CLEAR_FASTZ)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
846 int i;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000847 int depthpixperline =
848 dev_priv->depth_fmt ==
849 RADEON_DEPTH_FORMAT_16BIT_INT_Z ? (dev_priv->depth_pitch /
850 2) : (dev_priv->
851 depth_pitch / 4);
852
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 u32 clearmask;
854
855 u32 tempRB3D_DEPTHCLEARVALUE = clear->clear_depth |
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000856 ((clear->depth_mask & 0xff) << 24);
857
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 /* Make sure we restore the 3D state next time.
859 * we haven't touched any "normal" state - still need this?
860 */
861 dev_priv->sarea_priv->ctx_owner = 0;
862
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000863 if ((dev_priv->flags & CHIP_HAS_HIERZ)
864 && (flags & RADEON_USE_HIERZ)) {
865 /* FIXME : reverse engineer that for Rx00 cards */
866 /* FIXME : the mask supposedly contains low-res z values. So can't set
867 just to the max (0xff? or actually 0x3fff?), need to take z clear
868 value into account? */
869 /* pattern seems to work for r100, though get slight
870 rendering errors with glxgears. If hierz is not enabled for r100,
871 only 4 bits which indicate clear (15,16,31,32, all zero) matter, the
872 other ones are ignored, and the same clear mask can be used. That's
873 very different behaviour than R200 which needs different clear mask
874 and different number of tiles to clear if hierz is enabled or not !?!
875 */
876 clearmask = (0xff << 22) | (0xff << 6) | 0x003f003f;
877 } else {
878 /* clear mask : chooses the clearing pattern.
879 rv250: could be used to clear only parts of macrotiles
880 (but that would get really complicated...)?
881 bit 0 and 1 (either or both of them ?!?!) are used to
882 not clear tile (or maybe one of the bits indicates if the tile is
883 compressed or not), bit 2 and 3 to not clear tile 1,...,.
884 Pattern is as follows:
885 | 0,1 | 4,5 | 8,9 |12,13|16,17|20,21|24,25|28,29|
886 bits -------------------------------------------------
887 | 2,3 | 6,7 |10,11|14,15|18,19|22,23|26,27|30,31|
888 rv100: clearmask covers 2x8 4x1 tiles, but one clear still
889 covers 256 pixels ?!?
890 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 clearmask = 0x0;
892 }
893
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000894 BEGIN_RING(8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 RADEON_WAIT_UNTIL_2D_IDLE();
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000896 OUT_RING_REG(RADEON_RB3D_DEPTHCLEARVALUE,
897 tempRB3D_DEPTHCLEARVALUE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 /* what offset is this exactly ? */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000899 OUT_RING_REG(RADEON_RB3D_ZMASKOFFSET, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 /* need ctlstat, otherwise get some strange black flickering */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000901 OUT_RING_REG(RADEON_RB3D_ZCACHE_CTLSTAT,
902 RADEON_RB3D_ZC_FLUSH_ALL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 ADVANCE_RING();
904
905 for (i = 0; i < nbox; i++) {
906 int tileoffset, nrtilesx, nrtilesy, j;
907 /* it looks like r200 needs rv-style clears, at least if hierz is not enabled? */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000908 if ((dev_priv->flags & CHIP_HAS_HIERZ)
909 && !(dev_priv->microcode_version == UCODE_R200)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 /* FIXME : figure this out for r200 (when hierz is enabled). Or
911 maybe r200 actually doesn't need to put the low-res z value into
912 the tile cache like r100, but just needs to clear the hi-level z-buffer?
913 Works for R100, both with hierz and without.
914 R100 seems to operate on 2x1 8x8 tiles, but...
915 odd: offset/nrtiles need to be 64 pix (4 block) aligned? Potentially
916 problematic with resolutions which are not 64 pix aligned? */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000917 tileoffset =
918 ((pbox[i].y1 >> 3) * depthpixperline +
919 pbox[i].x1) >> 6;
920 nrtilesx =
921 ((pbox[i].x2 & ~63) -
922 (pbox[i].x1 & ~63)) >> 4;
923 nrtilesy =
924 (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 for (j = 0; j <= nrtilesy; j++) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000926 BEGIN_RING(4);
927 OUT_RING(CP_PACKET3
928 (RADEON_3D_CLEAR_ZMASK, 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 /* first tile */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000930 OUT_RING(tileoffset * 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 /* the number of tiles to clear */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000932 OUT_RING(nrtilesx + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 /* clear mask : chooses the clearing pattern. */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000934 OUT_RING(clearmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 ADVANCE_RING();
936 tileoffset += depthpixperline >> 6;
937 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000938 } else if (dev_priv->microcode_version == UCODE_R200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 /* works for rv250. */
940 /* find first macro tile (8x2 4x4 z-pixels on rv250) */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000941 tileoffset =
942 ((pbox[i].y1 >> 3) * depthpixperline +
943 pbox[i].x1) >> 5;
944 nrtilesx =
945 (pbox[i].x2 >> 5) - (pbox[i].x1 >> 5);
946 nrtilesy =
947 (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 for (j = 0; j <= nrtilesy; j++) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000949 BEGIN_RING(4);
950 OUT_RING(CP_PACKET3
951 (RADEON_3D_CLEAR_ZMASK, 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 /* first tile */
953 /* judging by the first tile offset needed, could possibly
954 directly address/clear 4x4 tiles instead of 8x2 * 4x4
955 macro tiles, though would still need clear mask for
956 right/bottom if truely 4x4 granularity is desired ? */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000957 OUT_RING(tileoffset * 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 /* the number of tiles to clear */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000959 OUT_RING(nrtilesx + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 /* clear mask : chooses the clearing pattern. */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000961 OUT_RING(clearmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 ADVANCE_RING();
963 tileoffset += depthpixperline >> 5;
964 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000965 } else { /* rv 100 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 /* rv100 might not need 64 pix alignment, who knows */
967 /* offsets are, hmm, weird */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000968 tileoffset =
969 ((pbox[i].y1 >> 4) * depthpixperline +
970 pbox[i].x1) >> 6;
971 nrtilesx =
972 ((pbox[i].x2 & ~63) -
973 (pbox[i].x1 & ~63)) >> 4;
974 nrtilesy =
975 (pbox[i].y2 >> 4) - (pbox[i].y1 >> 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 for (j = 0; j <= nrtilesy; j++) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000977 BEGIN_RING(4);
978 OUT_RING(CP_PACKET3
979 (RADEON_3D_CLEAR_ZMASK, 2));
980 OUT_RING(tileoffset * 128);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 /* the number of tiles to clear */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000982 OUT_RING(nrtilesx + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 /* clear mask : chooses the clearing pattern. */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000984 OUT_RING(clearmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 ADVANCE_RING();
986 tileoffset += depthpixperline >> 6;
987 }
988 }
989 }
990
991 /* TODO don't always clear all hi-level z tiles */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000992 if ((dev_priv->flags & CHIP_HAS_HIERZ)
993 && (dev_priv->microcode_version == UCODE_R200)
994 && (flags & RADEON_USE_HIERZ))
995 /* r100 and cards without hierarchical z-buffer have no high-level z-buffer */
996 /* FIXME : the mask supposedly contains low-res z values. So can't set
997 just to the max (0xff? or actually 0x3fff?), need to take z clear
998 value into account? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001000 BEGIN_RING(4);
1001 OUT_RING(CP_PACKET3(RADEON_3D_CLEAR_HIZ, 2));
1002 OUT_RING(0x0); /* First tile */
1003 OUT_RING(0x3cc0);
1004 OUT_RING((0xff << 22) | (0xff << 6) | 0x003f003f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 ADVANCE_RING();
1006 }
1007 }
1008
1009 /* We have to clear the depth and/or stencil buffers by
1010 * rendering a quad into just those buffers. Thus, we have to
1011 * make sure the 3D engine is configured correctly.
1012 */
Dave Airlied985c102006-01-02 21:32:48 +11001013 else if ((dev_priv->microcode_version == UCODE_R200) &&
1014 (flags & (RADEON_DEPTH | RADEON_STENCIL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
1016 int tempPP_CNTL;
1017 int tempRE_CNTL;
1018 int tempRB3D_CNTL;
1019 int tempRB3D_ZSTENCILCNTL;
1020 int tempRB3D_STENCILREFMASK;
1021 int tempRB3D_PLANEMASK;
1022 int tempSE_CNTL;
1023 int tempSE_VTE_CNTL;
1024 int tempSE_VTX_FMT_0;
1025 int tempSE_VTX_FMT_1;
1026 int tempSE_VAP_CNTL;
1027 int tempRE_AUX_SCISSOR_CNTL;
1028
1029 tempPP_CNTL = 0;
1030 tempRE_CNTL = 0;
1031
1032 tempRB3D_CNTL = depth_clear->rb3d_cntl;
1033
1034 tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl;
1035 tempRB3D_STENCILREFMASK = 0x0;
1036
1037 tempSE_CNTL = depth_clear->se_cntl;
1038
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 /* Disable TCL */
1040
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001041 tempSE_VAP_CNTL = ( /* SE_VAP_CNTL__FORCE_W_TO_ONE_MASK | */
1042 (0x9 <<
1043 SE_VAP_CNTL__VF_MAX_VTX_NUM__SHIFT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
1045 tempRB3D_PLANEMASK = 0x0;
1046
1047 tempRE_AUX_SCISSOR_CNTL = 0x0;
1048
1049 tempSE_VTE_CNTL =
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001050 SE_VTE_CNTL__VTX_XY_FMT_MASK | SE_VTE_CNTL__VTX_Z_FMT_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001052 /* Vertex format (X, Y, Z, W) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 tempSE_VTX_FMT_0 =
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001054 SE_VTX_FMT_0__VTX_Z0_PRESENT_MASK |
1055 SE_VTX_FMT_0__VTX_W0_PRESENT_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 tempSE_VTX_FMT_1 = 0x0;
1057
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001058 /*
1059 * Depth buffer specific enables
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 */
1061 if (flags & RADEON_DEPTH) {
1062 /* Enable depth buffer */
1063 tempRB3D_CNTL |= RADEON_Z_ENABLE;
1064 } else {
1065 /* Disable depth buffer */
1066 tempRB3D_CNTL &= ~RADEON_Z_ENABLE;
1067 }
1068
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001069 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 * Stencil buffer specific enables
1071 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001072 if (flags & RADEON_STENCIL) {
1073 tempRB3D_CNTL |= RADEON_STENCIL_ENABLE;
1074 tempRB3D_STENCILREFMASK = clear->depth_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 } else {
1076 tempRB3D_CNTL &= ~RADEON_STENCIL_ENABLE;
1077 tempRB3D_STENCILREFMASK = 0x00000000;
1078 }
1079
1080 if (flags & RADEON_USE_COMP_ZBUF) {
1081 tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE |
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001082 RADEON_Z_DECOMPRESSION_ENABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 }
1084 if (flags & RADEON_USE_HIERZ) {
1085 tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE;
1086 }
1087
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001088 BEGIN_RING(26);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 RADEON_WAIT_UNTIL_2D_IDLE();
1090
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001091 OUT_RING_REG(RADEON_PP_CNTL, tempPP_CNTL);
1092 OUT_RING_REG(R200_RE_CNTL, tempRE_CNTL);
1093 OUT_RING_REG(RADEON_RB3D_CNTL, tempRB3D_CNTL);
1094 OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL);
1095 OUT_RING_REG(RADEON_RB3D_STENCILREFMASK,
1096 tempRB3D_STENCILREFMASK);
1097 OUT_RING_REG(RADEON_RB3D_PLANEMASK, tempRB3D_PLANEMASK);
1098 OUT_RING_REG(RADEON_SE_CNTL, tempSE_CNTL);
1099 OUT_RING_REG(R200_SE_VTE_CNTL, tempSE_VTE_CNTL);
1100 OUT_RING_REG(R200_SE_VTX_FMT_0, tempSE_VTX_FMT_0);
1101 OUT_RING_REG(R200_SE_VTX_FMT_1, tempSE_VTX_FMT_1);
1102 OUT_RING_REG(R200_SE_VAP_CNTL, tempSE_VAP_CNTL);
1103 OUT_RING_REG(R200_RE_AUX_SCISSOR_CNTL, tempRE_AUX_SCISSOR_CNTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 ADVANCE_RING();
1105
1106 /* Make sure we restore the 3D state next time.
1107 */
1108 dev_priv->sarea_priv->ctx_owner = 0;
1109
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001110 for (i = 0; i < nbox; i++) {
1111
1112 /* Funny that this should be required --
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 * sets top-left?
1114 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001115 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001117 BEGIN_RING(14);
1118 OUT_RING(CP_PACKET3(R200_3D_DRAW_IMMD_2, 12));
1119 OUT_RING((RADEON_PRIM_TYPE_RECT_LIST |
1120 RADEON_PRIM_WALK_RING |
1121 (3 << RADEON_NUM_VERTICES_SHIFT)));
1122 OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1123 OUT_RING(depth_boxes[i].ui[CLEAR_Y1]);
1124 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1125 OUT_RING(0x3f800000);
1126 OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1127 OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1128 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1129 OUT_RING(0x3f800000);
1130 OUT_RING(depth_boxes[i].ui[CLEAR_X2]);
1131 OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1132 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1133 OUT_RING(0x3f800000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 ADVANCE_RING();
1135 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001136 } else if ((flags & (RADEON_DEPTH | RADEON_STENCIL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137
1138 int tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl;
1139
1140 rb3d_cntl = depth_clear->rb3d_cntl;
1141
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001142 if (flags & RADEON_DEPTH) {
1143 rb3d_cntl |= RADEON_Z_ENABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 } else {
1145 rb3d_cntl &= ~RADEON_Z_ENABLE;
1146 }
1147
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001148 if (flags & RADEON_STENCIL) {
1149 rb3d_cntl |= RADEON_STENCIL_ENABLE;
1150 rb3d_stencilrefmask = clear->depth_mask; /* misnamed field */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 } else {
1152 rb3d_cntl &= ~RADEON_STENCIL_ENABLE;
1153 rb3d_stencilrefmask = 0x00000000;
1154 }
1155
1156 if (flags & RADEON_USE_COMP_ZBUF) {
1157 tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE |
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001158 RADEON_Z_DECOMPRESSION_ENABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 }
1160 if (flags & RADEON_USE_HIERZ) {
1161 tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE;
1162 }
1163
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001164 BEGIN_RING(13);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 RADEON_WAIT_UNTIL_2D_IDLE();
1166
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001167 OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 1));
1168 OUT_RING(0x00000000);
1169 OUT_RING(rb3d_cntl);
1170
1171 OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL);
1172 OUT_RING_REG(RADEON_RB3D_STENCILREFMASK, rb3d_stencilrefmask);
1173 OUT_RING_REG(RADEON_RB3D_PLANEMASK, 0x00000000);
1174 OUT_RING_REG(RADEON_SE_CNTL, depth_clear->se_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 ADVANCE_RING();
1176
1177 /* Make sure we restore the 3D state next time.
1178 */
1179 dev_priv->sarea_priv->ctx_owner = 0;
1180
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001181 for (i = 0; i < nbox; i++) {
1182
1183 /* Funny that this should be required --
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 * sets top-left?
1185 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001186 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001188 BEGIN_RING(15);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001190 OUT_RING(CP_PACKET3(RADEON_3D_DRAW_IMMD, 13));
1191 OUT_RING(RADEON_VTX_Z_PRESENT |
1192 RADEON_VTX_PKCOLOR_PRESENT);
1193 OUT_RING((RADEON_PRIM_TYPE_RECT_LIST |
1194 RADEON_PRIM_WALK_RING |
1195 RADEON_MAOS_ENABLE |
1196 RADEON_VTX_FMT_RADEON_MODE |
1197 (3 << RADEON_NUM_VERTICES_SHIFT)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001199 OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1200 OUT_RING(depth_boxes[i].ui[CLEAR_Y1]);
1201 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1202 OUT_RING(0x0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001204 OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1205 OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1206 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1207 OUT_RING(0x0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001209 OUT_RING(depth_boxes[i].ui[CLEAR_X2]);
1210 OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1211 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1212 OUT_RING(0x0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213
1214 ADVANCE_RING();
1215 }
1216 }
1217
1218 /* Increment the clear counter. The client-side 3D driver must
1219 * wait on this value before performing the clear ioctl. We
1220 * need this because the card's so damned fast...
1221 */
1222 dev_priv->sarea_priv->last_clear++;
1223
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001224 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001226 RADEON_CLEAR_AGE(dev_priv->sarea_priv->last_clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 RADEON_WAIT_UNTIL_IDLE();
1228
1229 ADVANCE_RING();
1230}
1231
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001232static void radeon_cp_dispatch_swap(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233{
1234 drm_radeon_private_t *dev_priv = dev->dev_private;
1235 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
1236 int nbox = sarea_priv->nbox;
1237 drm_clip_rect_t *pbox = sarea_priv->boxes;
1238 int i;
1239 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001240 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241
1242 /* Do some trivial performance monitoring...
1243 */
1244 if (dev_priv->do_boxes)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001245 radeon_cp_performance_boxes(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
1247 /* Wait for the 3D stream to idle before dispatching the bitblt.
1248 * This will prevent data corruption between the two streams.
1249 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001250 BEGIN_RING(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
1252 RADEON_WAIT_UNTIL_3D_IDLE();
1253
1254 ADVANCE_RING();
1255
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001256 for (i = 0; i < nbox; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 int x = pbox[i].x1;
1258 int y = pbox[i].y1;
1259 int w = pbox[i].x2 - x;
1260 int h = pbox[i].y2 - y;
1261
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001262 DRM_DEBUG("dispatch swap %d,%d-%d,%d\n", x, y, w, h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001264 BEGIN_RING(7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001266 OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
1267 OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
1268 RADEON_GMC_DST_PITCH_OFFSET_CNTL |
1269 RADEON_GMC_BRUSH_NONE |
1270 (dev_priv->color_fmt << 8) |
1271 RADEON_GMC_SRC_DATATYPE_COLOR |
1272 RADEON_ROP3_S |
1273 RADEON_DP_SRC_SOURCE_MEMORY |
1274 RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
1275
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 /* Make this work even if front & back are flipped:
1277 */
1278 if (dev_priv->current_page == 0) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001279 OUT_RING(dev_priv->back_pitch_offset);
1280 OUT_RING(dev_priv->front_pitch_offset);
1281 } else {
1282 OUT_RING(dev_priv->front_pitch_offset);
1283 OUT_RING(dev_priv->back_pitch_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 }
1285
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001286 OUT_RING((x << 16) | y);
1287 OUT_RING((x << 16) | y);
1288 OUT_RING((w << 16) | h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
1290 ADVANCE_RING();
1291 }
1292
1293 /* Increment the frame counter. The client-side 3D driver must
1294 * throttle the framerate by waiting for this value before
1295 * performing the swapbuffer ioctl.
1296 */
1297 dev_priv->sarea_priv->last_frame++;
1298
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001299 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001301 RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 RADEON_WAIT_UNTIL_2D_IDLE();
1303
1304 ADVANCE_RING();
1305}
1306
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001307static void radeon_cp_dispatch_flip(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308{
1309 drm_radeon_private_t *dev_priv = dev->dev_private;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001310 drm_sarea_t *sarea = (drm_sarea_t *) dev_priv->sarea->handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 int offset = (dev_priv->current_page == 1)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001312 ? dev_priv->front_offset : dev_priv->back_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001314 DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
1315 __FUNCTION__,
1316 dev_priv->current_page, dev_priv->sarea_priv->pfCurrentPage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
1318 /* Do some trivial performance monitoring...
1319 */
1320 if (dev_priv->do_boxes) {
1321 dev_priv->stats.boxes |= RADEON_BOX_FLIP;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001322 radeon_cp_performance_boxes(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 }
1324
1325 /* Update the frame offsets for both CRTCs
1326 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001327 BEGIN_RING(6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
1329 RADEON_WAIT_UNTIL_3D_IDLE();
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001330 OUT_RING_REG(RADEON_CRTC_OFFSET,
1331 ((sarea->frame.y * dev_priv->front_pitch +
1332 sarea->frame.x * (dev_priv->color_fmt - 2)) & ~7)
1333 + offset);
1334 OUT_RING_REG(RADEON_CRTC2_OFFSET, dev_priv->sarea_priv->crtc2_base
1335 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336
1337 ADVANCE_RING();
1338
1339 /* Increment the frame counter. The client-side 3D driver must
1340 * throttle the framerate by waiting for this value before
1341 * performing the swapbuffer ioctl.
1342 */
1343 dev_priv->sarea_priv->last_frame++;
1344 dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page =
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001345 1 - dev_priv->current_page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001347 BEGIN_RING(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001349 RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350
1351 ADVANCE_RING();
1352}
1353
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001354static int bad_prim_vertex_nr(int primitive, int nr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355{
1356 switch (primitive & RADEON_PRIM_TYPE_MASK) {
1357 case RADEON_PRIM_TYPE_NONE:
1358 case RADEON_PRIM_TYPE_POINT:
1359 return nr < 1;
1360 case RADEON_PRIM_TYPE_LINE:
1361 return (nr & 1) || nr == 0;
1362 case RADEON_PRIM_TYPE_LINE_STRIP:
1363 return nr < 2;
1364 case RADEON_PRIM_TYPE_TRI_LIST:
1365 case RADEON_PRIM_TYPE_3VRT_POINT_LIST:
1366 case RADEON_PRIM_TYPE_3VRT_LINE_LIST:
1367 case RADEON_PRIM_TYPE_RECT_LIST:
1368 return nr % 3 || nr == 0;
1369 case RADEON_PRIM_TYPE_TRI_FAN:
1370 case RADEON_PRIM_TYPE_TRI_STRIP:
1371 return nr < 3;
1372 default:
1373 return 1;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001374 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375}
1376
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377typedef struct {
1378 unsigned int start;
1379 unsigned int finish;
1380 unsigned int prim;
1381 unsigned int numverts;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001382 unsigned int offset;
1383 unsigned int vc_format;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384} drm_radeon_tcl_prim_t;
1385
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001386static void radeon_cp_dispatch_vertex(drm_device_t * dev,
1387 drm_buf_t * buf,
1388 drm_radeon_tcl_prim_t * prim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389{
1390 drm_radeon_private_t *dev_priv = dev->dev_private;
1391 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
1392 int offset = dev_priv->gart_buffers_offset + buf->offset + prim->start;
1393 int numverts = (int)prim->numverts;
1394 int nbox = sarea_priv->nbox;
1395 int i = 0;
1396 RING_LOCALS;
1397
1398 DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d %d verts\n",
1399 prim->prim,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001400 prim->vc_format, prim->start, prim->finish, prim->numverts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001402 if (bad_prim_vertex_nr(prim->prim, prim->numverts)) {
1403 DRM_ERROR("bad prim %x numverts %d\n",
1404 prim->prim, prim->numverts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 return;
1406 }
1407
1408 do {
1409 /* Emit the next cliprect */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001410 if (i < nbox) {
1411 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 }
1413
1414 /* Emit the vertex buffer rendering commands */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001415 BEGIN_RING(5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001417 OUT_RING(CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, 3));
1418 OUT_RING(offset);
1419 OUT_RING(numverts);
1420 OUT_RING(prim->vc_format);
1421 OUT_RING(prim->prim | RADEON_PRIM_WALK_LIST |
1422 RADEON_COLOR_ORDER_RGBA |
1423 RADEON_VTX_FMT_RADEON_MODE |
1424 (numverts << RADEON_NUM_VERTICES_SHIFT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425
1426 ADVANCE_RING();
1427
1428 i++;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001429 } while (i < nbox);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430}
1431
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001432static void radeon_cp_discard_buffer(drm_device_t * dev, drm_buf_t * buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433{
1434 drm_radeon_private_t *dev_priv = dev->dev_private;
1435 drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
1436 RING_LOCALS;
1437
1438 buf_priv->age = ++dev_priv->sarea_priv->last_dispatch;
1439
1440 /* Emit the vertex buffer age */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001441 BEGIN_RING(2);
1442 RADEON_DISPATCH_AGE(buf_priv->age);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 ADVANCE_RING();
1444
1445 buf->pending = 1;
1446 buf->used = 0;
1447}
1448
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001449static void radeon_cp_dispatch_indirect(drm_device_t * dev,
1450 drm_buf_t * buf, int start, int end)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451{
1452 drm_radeon_private_t *dev_priv = dev->dev_private;
1453 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001454 DRM_DEBUG("indirect: buf=%d s=0x%x e=0x%x\n", buf->idx, start, end);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001456 if (start != end) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 int offset = (dev_priv->gart_buffers_offset
1458 + buf->offset + start);
1459 int dwords = (end - start + 3) / sizeof(u32);
1460
1461 /* Indirect buffer data must be an even number of
1462 * dwords, so if we've been given an odd number we must
1463 * pad the data with a Type-2 CP packet.
1464 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001465 if (dwords & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 u32 *data = (u32 *)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001467 ((char *)dev->agp_buffer_map->handle
1468 + buf->offset + start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 data[dwords++] = RADEON_CP_PACKET2;
1470 }
1471
1472 /* Fire off the indirect buffer */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001473 BEGIN_RING(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001475 OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1));
1476 OUT_RING(offset);
1477 OUT_RING(dwords);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478
1479 ADVANCE_RING();
1480 }
1481}
1482
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001483static void radeon_cp_dispatch_indices(drm_device_t * dev,
1484 drm_buf_t * elt_buf,
1485 drm_radeon_tcl_prim_t * prim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486{
1487 drm_radeon_private_t *dev_priv = dev->dev_private;
1488 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
1489 int offset = dev_priv->gart_buffers_offset + prim->offset;
1490 u32 *data;
1491 int dwords;
1492 int i = 0;
1493 int start = prim->start + RADEON_INDEX_PRIM_OFFSET;
1494 int count = (prim->finish - start) / sizeof(u16);
1495 int nbox = sarea_priv->nbox;
1496
1497 DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d offset: %x nr %d\n",
1498 prim->prim,
1499 prim->vc_format,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001500 prim->start, prim->finish, prim->offset, prim->numverts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001502 if (bad_prim_vertex_nr(prim->prim, count)) {
1503 DRM_ERROR("bad prim %x count %d\n", prim->prim, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 return;
1505 }
1506
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001507 if (start >= prim->finish || (prim->start & 0x7)) {
1508 DRM_ERROR("buffer prim %d\n", prim->prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 return;
1510 }
1511
1512 dwords = (prim->finish - prim->start + 3) / sizeof(u32);
1513
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001514 data = (u32 *) ((char *)dev->agp_buffer_map->handle +
1515 elt_buf->offset + prim->start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001517 data[0] = CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, dwords - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 data[1] = offset;
1519 data[2] = prim->numverts;
1520 data[3] = prim->vc_format;
1521 data[4] = (prim->prim |
1522 RADEON_PRIM_WALK_IND |
1523 RADEON_COLOR_ORDER_RGBA |
1524 RADEON_VTX_FMT_RADEON_MODE |
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001525 (count << RADEON_NUM_VERTICES_SHIFT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526
1527 do {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001528 if (i < nbox)
1529 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001531 radeon_cp_dispatch_indirect(dev, elt_buf,
1532 prim->start, prim->finish);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533
1534 i++;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001535 } while (i < nbox);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536
1537}
1538
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001539#define RADEON_MAX_TEXTURE_SIZE RADEON_BUFFER_SIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001541static int radeon_cp_dispatch_texture(DRMFILE filp,
1542 drm_device_t * dev,
1543 drm_radeon_texture_t * tex,
1544 drm_radeon_tex_image_t * image)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545{
1546 drm_radeon_private_t *dev_priv = dev->dev_private;
1547 drm_file_t *filp_priv;
1548 drm_buf_t *buf;
1549 u32 format;
1550 u32 *buffer;
1551 const u8 __user *data;
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001552 int size, dwords, tex_width, blit_width, spitch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 u32 height;
1554 int i;
1555 u32 texpitch, microtile;
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001556 u32 offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 RING_LOCALS;
1558
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001559 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001561 if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &tex->offset)) {
1562 DRM_ERROR("Invalid destination offset\n");
1563 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 }
1565
1566 dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD;
1567
1568 /* Flush the pixel cache. This ensures no pixel data gets mixed
1569 * up with the texture data from the host data blit, otherwise
1570 * part of the texture image may be corrupted.
1571 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001572 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 RADEON_FLUSH_CACHE();
1574 RADEON_WAIT_UNTIL_IDLE();
1575 ADVANCE_RING();
1576
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 /* The compiler won't optimize away a division by a variable,
1578 * even if the only legal values are powers of two. Thus, we'll
1579 * use a shift instead.
1580 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001581 switch (tex->format) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 case RADEON_TXFORMAT_ARGB8888:
1583 case RADEON_TXFORMAT_RGBA8888:
1584 format = RADEON_COLOR_FORMAT_ARGB8888;
1585 tex_width = tex->width * 4;
1586 blit_width = image->width * 4;
1587 break;
1588 case RADEON_TXFORMAT_AI88:
1589 case RADEON_TXFORMAT_ARGB1555:
1590 case RADEON_TXFORMAT_RGB565:
1591 case RADEON_TXFORMAT_ARGB4444:
1592 case RADEON_TXFORMAT_VYUY422:
1593 case RADEON_TXFORMAT_YVYU422:
1594 format = RADEON_COLOR_FORMAT_RGB565;
1595 tex_width = tex->width * 2;
1596 blit_width = image->width * 2;
1597 break;
1598 case RADEON_TXFORMAT_I8:
1599 case RADEON_TXFORMAT_RGB332:
1600 format = RADEON_COLOR_FORMAT_CI8;
1601 tex_width = tex->width * 1;
1602 blit_width = image->width * 1;
1603 break;
1604 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001605 DRM_ERROR("invalid texture format %d\n", tex->format);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 return DRM_ERR(EINVAL);
1607 }
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001608 spitch = blit_width >> 6;
1609 if (spitch == 0 && image->height > 1)
1610 return DRM_ERR(EINVAL);
1611
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 texpitch = tex->pitch;
1613 if ((texpitch << 22) & RADEON_DST_TILE_MICRO) {
1614 microtile = 1;
1615 if (tex_width < 64) {
1616 texpitch &= ~(RADEON_DST_TILE_MICRO >> 22);
1617 /* we got tiled coordinates, untile them */
1618 image->x *= 2;
1619 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001620 } else
1621 microtile = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001623 DRM_DEBUG("tex=%dx%d blit=%d\n", tex_width, tex->height, blit_width);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624
1625 do {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001626 DRM_DEBUG("tex: ofs=0x%x p=%d f=%d x=%hd y=%hd w=%hd h=%hd\n",
1627 tex->offset >> 10, tex->pitch, tex->format,
1628 image->x, image->y, image->width, image->height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629
1630 /* Make a copy of some parameters in case we have to
1631 * update them for a multi-pass texture blit.
1632 */
1633 height = image->height;
1634 data = (const u8 __user *)image->data;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001635
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 size = height * blit_width;
1637
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001638 if (size > RADEON_MAX_TEXTURE_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 height = RADEON_MAX_TEXTURE_SIZE / blit_width;
1640 size = height * blit_width;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001641 } else if (size < 4 && size > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 size = 4;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001643 } else if (size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 return 0;
1645 }
1646
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001647 buf = radeon_freelist_get(dev);
1648 if (0 && !buf) {
1649 radeon_do_cp_idle(dev_priv);
1650 buf = radeon_freelist_get(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001652 if (!buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 DRM_DEBUG("radeon_cp_dispatch_texture: EAGAIN\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001654 if (DRM_COPY_TO_USER(tex->image, image, sizeof(*image)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 return DRM_ERR(EFAULT);
1656 return DRM_ERR(EAGAIN);
1657 }
1658
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 /* Dispatch the indirect buffer.
1660 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001661 buffer =
1662 (u32 *) ((char *)dev->agp_buffer_map->handle + buf->offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 dwords = size / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664
Dave Airlied985c102006-01-02 21:32:48 +11001665#define RADEON_COPY_MT(_buf, _data, _width) \
1666 do { \
1667 if (DRM_COPY_FROM_USER(_buf, _data, (_width))) {\
1668 DRM_ERROR("EFAULT on pad, %d bytes\n", (_width)); \
1669 return DRM_ERR(EFAULT); \
1670 } \
1671 } while(0)
1672
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 if (microtile) {
1674 /* texture micro tiling in use, minimum texture width is thus 16 bytes.
1675 however, we cannot use blitter directly for texture width < 64 bytes,
1676 since minimum tex pitch is 64 bytes and we need this to match
1677 the texture width, otherwise the blitter will tile it wrong.
1678 Thus, tiling manually in this case. Additionally, need to special
1679 case tex height = 1, since our actual image will have height 2
1680 and we need to ensure we don't read beyond the texture size
1681 from user space. */
1682 if (tex->height == 1) {
1683 if (tex_width >= 64 || tex_width <= 16) {
Dave Airlied985c102006-01-02 21:32:48 +11001684 RADEON_COPY_MT(buffer, data,
Dave Airlief8e0f292006-01-10 19:56:17 +11001685 (int)(tex_width * sizeof(u32)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 } else if (tex_width == 32) {
Dave Airlied985c102006-01-02 21:32:48 +11001687 RADEON_COPY_MT(buffer, data, 16);
1688 RADEON_COPY_MT(buffer + 8,
1689 data + 16, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 }
1691 } else if (tex_width >= 64 || tex_width == 16) {
Dave Airlied985c102006-01-02 21:32:48 +11001692 RADEON_COPY_MT(buffer, data,
Dave Airlief8e0f292006-01-10 19:56:17 +11001693 (int)(dwords * sizeof(u32)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 } else if (tex_width < 16) {
1695 for (i = 0; i < tex->height; i++) {
Dave Airlied985c102006-01-02 21:32:48 +11001696 RADEON_COPY_MT(buffer, data, tex_width);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 buffer += 4;
1698 data += tex_width;
1699 }
1700 } else if (tex_width == 32) {
1701 /* TODO: make sure this works when not fitting in one buffer
1702 (i.e. 32bytes x 2048...) */
1703 for (i = 0; i < tex->height; i += 2) {
Dave Airlied985c102006-01-02 21:32:48 +11001704 RADEON_COPY_MT(buffer, data, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 data += 16;
Dave Airlied985c102006-01-02 21:32:48 +11001706 RADEON_COPY_MT(buffer + 8, data, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 data += 16;
Dave Airlied985c102006-01-02 21:32:48 +11001708 RADEON_COPY_MT(buffer + 4, data, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 data += 16;
Dave Airlied985c102006-01-02 21:32:48 +11001710 RADEON_COPY_MT(buffer + 12, data, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 data += 16;
1712 buffer += 16;
1713 }
1714 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001715 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 if (tex_width >= 32) {
1717 /* Texture image width is larger than the minimum, so we
1718 * can upload it directly.
1719 */
Dave Airlied985c102006-01-02 21:32:48 +11001720 RADEON_COPY_MT(buffer, data,
Dave Airlief8e0f292006-01-10 19:56:17 +11001721 (int)(dwords * sizeof(u32)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 } else {
1723 /* Texture image width is less than the minimum, so we
1724 * need to pad out each image scanline to the minimum
1725 * width.
1726 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001727 for (i = 0; i < tex->height; i++) {
Dave Airlied985c102006-01-02 21:32:48 +11001728 RADEON_COPY_MT(buffer, data, tex_width);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 buffer += 8;
1730 data += tex_width;
1731 }
1732 }
1733 }
1734
Dave Airlied985c102006-01-02 21:32:48 +11001735#undef RADEON_COPY_MT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 buf->filp = filp;
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001737 buf->used = size;
1738 offset = dev_priv->gart_buffers_offset + buf->offset;
1739 BEGIN_RING(9);
1740 OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
1741 OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
1742 RADEON_GMC_DST_PITCH_OFFSET_CNTL |
1743 RADEON_GMC_BRUSH_NONE |
1744 (format << 8) |
1745 RADEON_GMC_SRC_DATATYPE_COLOR |
1746 RADEON_ROP3_S |
1747 RADEON_DP_SRC_SOURCE_MEMORY |
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001748 RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001749 OUT_RING((spitch << 22) | (offset >> 10));
1750 OUT_RING((texpitch << 22) | (tex->offset >> 10));
1751 OUT_RING(0);
1752 OUT_RING((image->x << 16) | image->y);
1753 OUT_RING((image->width << 16) | height);
1754 RADEON_WAIT_UNTIL_2D_IDLE();
1755 ADVANCE_RING();
1756
1757 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758
1759 /* Update the input parameters for next time */
1760 image->y += height;
1761 image->height -= height;
1762 image->data = (const u8 __user *)image->data + size;
1763 } while (image->height > 0);
1764
1765 /* Flush the pixel cache after the blit completes. This ensures
1766 * the texture data is written out to memory before rendering
1767 * continues.
1768 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001769 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 RADEON_FLUSH_CACHE();
1771 RADEON_WAIT_UNTIL_2D_IDLE();
1772 ADVANCE_RING();
1773 return 0;
1774}
1775
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001776static void radeon_cp_dispatch_stipple(drm_device_t * dev, u32 * stipple)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777{
1778 drm_radeon_private_t *dev_priv = dev->dev_private;
1779 int i;
1780 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001781 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001783 BEGIN_RING(35);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001785 OUT_RING(CP_PACKET0(RADEON_RE_STIPPLE_ADDR, 0));
1786 OUT_RING(0x00000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001788 OUT_RING(CP_PACKET0_TABLE(RADEON_RE_STIPPLE_DATA, 31));
1789 for (i = 0; i < 32; i++) {
1790 OUT_RING(stipple[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 }
1792
1793 ADVANCE_RING();
1794}
1795
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001796static void radeon_apply_surface_regs(int surf_index,
Dave Airlied985c102006-01-02 21:32:48 +11001797 drm_radeon_private_t *dev_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798{
1799 if (!dev_priv->mmio)
1800 return;
1801
1802 radeon_do_cp_idle(dev_priv);
1803
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001804 RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * surf_index,
1805 dev_priv->surfaces[surf_index].flags);
1806 RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND + 16 * surf_index,
1807 dev_priv->surfaces[surf_index].lower);
1808 RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND + 16 * surf_index,
1809 dev_priv->surfaces[surf_index].upper);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810}
1811
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812/* Allocates a virtual surface
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001813 * doesn't always allocate a real surface, will stretch an existing
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 * surface when possible.
1815 *
1816 * Note that refcount can be at most 2, since during a free refcount=3
1817 * might mean we have to allocate a new surface which might not always
1818 * be available.
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001819 * For example : we allocate three contigous surfaces ABC. If B is
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 * freed, we suddenly need two surfaces to store A and C, which might
1821 * not always be available.
1822 */
Dave Airlied985c102006-01-02 21:32:48 +11001823static int alloc_surface(drm_radeon_surface_alloc_t *new,
1824 drm_radeon_private_t *dev_priv, DRMFILE filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825{
1826 struct radeon_virt_surface *s;
1827 int i;
1828 int virt_surface_index;
1829 uint32_t new_upper, new_lower;
1830
1831 new_lower = new->address;
1832 new_upper = new_lower + new->size - 1;
1833
1834 /* sanity check */
1835 if ((new_lower >= new_upper) || (new->flags == 0) || (new->size == 0) ||
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001836 ((new_upper & RADEON_SURF_ADDRESS_FIXED_MASK) !=
1837 RADEON_SURF_ADDRESS_FIXED_MASK)
1838 || ((new_lower & RADEON_SURF_ADDRESS_FIXED_MASK) != 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 return -1;
1840
1841 /* make sure there is no overlap with existing surfaces */
1842 for (i = 0; i < RADEON_MAX_SURFACES; i++) {
1843 if ((dev_priv->surfaces[i].refcount != 0) &&
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001844 (((new_lower >= dev_priv->surfaces[i].lower) &&
1845 (new_lower < dev_priv->surfaces[i].upper)) ||
1846 ((new_lower < dev_priv->surfaces[i].lower) &&
1847 (new_upper > dev_priv->surfaces[i].lower)))) {
1848 return -1;
1849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 }
1851
1852 /* find a virtual surface */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001853 for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 if (dev_priv->virt_surfaces[i].filp == 0)
1855 break;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001856 if (i == 2 * RADEON_MAX_SURFACES) {
1857 return -1;
1858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 virt_surface_index = i;
1860
1861 /* try to reuse an existing surface */
1862 for (i = 0; i < RADEON_MAX_SURFACES; i++) {
1863 /* extend before */
1864 if ((dev_priv->surfaces[i].refcount == 1) &&
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001865 (new->flags == dev_priv->surfaces[i].flags) &&
1866 (new_upper + 1 == dev_priv->surfaces[i].lower)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 s = &(dev_priv->virt_surfaces[virt_surface_index]);
1868 s->surface_index = i;
1869 s->lower = new_lower;
1870 s->upper = new_upper;
1871 s->flags = new->flags;
1872 s->filp = filp;
1873 dev_priv->surfaces[i].refcount++;
1874 dev_priv->surfaces[i].lower = s->lower;
1875 radeon_apply_surface_regs(s->surface_index, dev_priv);
1876 return virt_surface_index;
1877 }
1878
1879 /* extend after */
1880 if ((dev_priv->surfaces[i].refcount == 1) &&
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001881 (new->flags == dev_priv->surfaces[i].flags) &&
1882 (new_lower == dev_priv->surfaces[i].upper + 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 s = &(dev_priv->virt_surfaces[virt_surface_index]);
1884 s->surface_index = i;
1885 s->lower = new_lower;
1886 s->upper = new_upper;
1887 s->flags = new->flags;
1888 s->filp = filp;
1889 dev_priv->surfaces[i].refcount++;
1890 dev_priv->surfaces[i].upper = s->upper;
1891 radeon_apply_surface_regs(s->surface_index, dev_priv);
1892 return virt_surface_index;
1893 }
1894 }
1895
1896 /* okay, we need a new one */
1897 for (i = 0; i < RADEON_MAX_SURFACES; i++) {
1898 if (dev_priv->surfaces[i].refcount == 0) {
1899 s = &(dev_priv->virt_surfaces[virt_surface_index]);
1900 s->surface_index = i;
1901 s->lower = new_lower;
1902 s->upper = new_upper;
1903 s->flags = new->flags;
1904 s->filp = filp;
1905 dev_priv->surfaces[i].refcount = 1;
1906 dev_priv->surfaces[i].lower = s->lower;
1907 dev_priv->surfaces[i].upper = s->upper;
1908 dev_priv->surfaces[i].flags = s->flags;
1909 radeon_apply_surface_regs(s->surface_index, dev_priv);
1910 return virt_surface_index;
1911 }
1912 }
1913
1914 /* we didn't find anything */
1915 return -1;
1916}
1917
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001918static int free_surface(DRMFILE filp, drm_radeon_private_t * dev_priv,
1919 int lower)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920{
1921 struct radeon_virt_surface *s;
1922 int i;
1923 /* find the virtual surface */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001924 for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 s = &(dev_priv->virt_surfaces[i]);
1926 if (s->filp) {
1927 if ((lower == s->lower) && (filp == s->filp)) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001928 if (dev_priv->surfaces[s->surface_index].
1929 lower == s->lower)
1930 dev_priv->surfaces[s->surface_index].
1931 lower = s->upper;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001933 if (dev_priv->surfaces[s->surface_index].
1934 upper == s->upper)
1935 dev_priv->surfaces[s->surface_index].
1936 upper = s->lower;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937
1938 dev_priv->surfaces[s->surface_index].refcount--;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001939 if (dev_priv->surfaces[s->surface_index].
1940 refcount == 0)
1941 dev_priv->surfaces[s->surface_index].
1942 flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 s->filp = NULL;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001944 radeon_apply_surface_regs(s->surface_index,
1945 dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 return 0;
1947 }
1948 }
1949 }
1950 return 1;
1951}
1952
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001953static void radeon_surfaces_release(DRMFILE filp,
1954 drm_radeon_private_t * dev_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955{
1956 int i;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001957 for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 if (dev_priv->virt_surfaces[i].filp == filp)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001959 free_surface(filp, dev_priv,
1960 dev_priv->virt_surfaces[i].lower);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 }
1962}
1963
1964/* ================================================================
1965 * IOCTL functions
1966 */
1967static int radeon_surface_alloc(DRM_IOCTL_ARGS)
1968{
1969 DRM_DEVICE;
1970 drm_radeon_private_t *dev_priv = dev->dev_private;
1971 drm_radeon_surface_alloc_t alloc;
1972
1973 if (!dev_priv) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001974 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 return DRM_ERR(EINVAL);
1976 }
1977
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001978 DRM_COPY_FROM_USER_IOCTL(alloc,
1979 (drm_radeon_surface_alloc_t __user *) data,
1980 sizeof(alloc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981
1982 if (alloc_surface(&alloc, dev_priv, filp) == -1)
1983 return DRM_ERR(EINVAL);
1984 else
1985 return 0;
1986}
1987
1988static int radeon_surface_free(DRM_IOCTL_ARGS)
1989{
1990 DRM_DEVICE;
1991 drm_radeon_private_t *dev_priv = dev->dev_private;
1992 drm_radeon_surface_free_t memfree;
1993
1994 if (!dev_priv) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001995 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 return DRM_ERR(EINVAL);
1997 }
1998
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001999 DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_mem_free_t __user *) data,
2000 sizeof(memfree));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001
2002 if (free_surface(filp, dev_priv, memfree.address))
2003 return DRM_ERR(EINVAL);
2004 else
2005 return 0;
2006}
2007
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002008static int radeon_cp_clear(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009{
2010 DRM_DEVICE;
2011 drm_radeon_private_t *dev_priv = dev->dev_private;
2012 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2013 drm_radeon_clear_t clear;
2014 drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002015 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002017 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002019 DRM_COPY_FROM_USER_IOCTL(clear, (drm_radeon_clear_t __user *) data,
2020 sizeof(clear));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002022 RING_SPACE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002024 if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
2026
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002027 if (DRM_COPY_FROM_USER(&depth_boxes, clear.depth_boxes,
2028 sarea_priv->nbox * sizeof(depth_boxes[0])))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 return DRM_ERR(EFAULT);
2030
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002031 radeon_cp_dispatch_clear(dev, &clear, depth_boxes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032
2033 COMMIT_RING();
2034 return 0;
2035}
2036
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037/* Not sure why this isn't set all the time:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002038 */
2039static int radeon_do_init_pageflip(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040{
2041 drm_radeon_private_t *dev_priv = dev->dev_private;
2042 RING_LOCALS;
2043
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002044 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002046 BEGIN_RING(6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 RADEON_WAIT_UNTIL_3D_IDLE();
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002048 OUT_RING(CP_PACKET0(RADEON_CRTC_OFFSET_CNTL, 0));
2049 OUT_RING(RADEON_READ(RADEON_CRTC_OFFSET_CNTL) |
2050 RADEON_CRTC_OFFSET_FLIP_CNTL);
2051 OUT_RING(CP_PACKET0(RADEON_CRTC2_OFFSET_CNTL, 0));
2052 OUT_RING(RADEON_READ(RADEON_CRTC2_OFFSET_CNTL) |
2053 RADEON_CRTC_OFFSET_FLIP_CNTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 ADVANCE_RING();
2055
2056 dev_priv->page_flipping = 1;
2057 dev_priv->current_page = 0;
2058 dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page;
2059
2060 return 0;
2061}
2062
2063/* Called whenever a client dies, from drm_release.
2064 * NOTE: Lock isn't necessarily held when this is called!
2065 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002066static int radeon_do_cleanup_pageflip(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067{
2068 drm_radeon_private_t *dev_priv = dev->dev_private;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002069 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070
2071 if (dev_priv->current_page != 0)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002072 radeon_cp_dispatch_flip(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073
2074 dev_priv->page_flipping = 0;
2075 return 0;
2076}
2077
2078/* Swapping and flipping are different operations, need different ioctls.
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002079 * They can & should be intermixed to support multiple 3d windows.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002081static int radeon_cp_flip(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082{
2083 DRM_DEVICE;
2084 drm_radeon_private_t *dev_priv = dev->dev_private;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002085 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002087 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002089 RING_SPACE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002091 if (!dev_priv->page_flipping)
2092 radeon_do_init_pageflip(dev);
2093
2094 radeon_cp_dispatch_flip(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095
2096 COMMIT_RING();
2097 return 0;
2098}
2099
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002100static int radeon_cp_swap(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101{
2102 DRM_DEVICE;
2103 drm_radeon_private_t *dev_priv = dev->dev_private;
2104 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002105 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002107 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002109 RING_SPACE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002111 if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
2113
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002114 radeon_cp_dispatch_swap(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 dev_priv->sarea_priv->ctx_owner = 0;
2116
2117 COMMIT_RING();
2118 return 0;
2119}
2120
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002121static int radeon_cp_vertex(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122{
2123 DRM_DEVICE;
2124 drm_radeon_private_t *dev_priv = dev->dev_private;
2125 drm_file_t *filp_priv;
2126 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2127 drm_device_dma_t *dma = dev->dma;
2128 drm_buf_t *buf;
2129 drm_radeon_vertex_t vertex;
2130 drm_radeon_tcl_prim_t prim;
2131
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002132 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133
Dave Airlied985c102006-01-02 21:32:48 +11002134 if (!dev_priv) {
2135 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
2136 return DRM_ERR(EINVAL);
2137 }
2138
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002139 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002141 DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex_t __user *) data,
2142 sizeof(vertex));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002144 DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n",
2145 DRM_CURRENTPID, vertex.idx, vertex.count, vertex.discard);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002147 if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
2148 DRM_ERROR("buffer index %d (of %d max)\n",
2149 vertex.idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 return DRM_ERR(EINVAL);
2151 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002152 if (vertex.prim < 0 || vertex.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
2153 DRM_ERROR("buffer prim %d\n", vertex.prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 return DRM_ERR(EINVAL);
2155 }
2156
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002157 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2158 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159
2160 buf = dma->buflist[vertex.idx];
2161
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002162 if (buf->filp != filp) {
2163 DRM_ERROR("process %d using buffer owned by %p\n",
2164 DRM_CURRENTPID, buf->filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 return DRM_ERR(EINVAL);
2166 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002167 if (buf->pending) {
2168 DRM_ERROR("sending pending buffer %d\n", vertex.idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 return DRM_ERR(EINVAL);
2170 }
2171
2172 /* Build up a prim_t record:
2173 */
2174 if (vertex.count) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002175 buf->used = vertex.count; /* not used? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002177 if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
2178 if (radeon_emit_state(dev_priv, filp_priv,
2179 &sarea_priv->context_state,
2180 sarea_priv->tex_state,
2181 sarea_priv->dirty)) {
2182 DRM_ERROR("radeon_emit_state failed\n");
2183 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 }
2185
2186 sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
2187 RADEON_UPLOAD_TEX1IMAGES |
2188 RADEON_UPLOAD_TEX2IMAGES |
2189 RADEON_REQUIRE_QUIESCENCE);
2190 }
2191
2192 prim.start = 0;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002193 prim.finish = vertex.count; /* unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 prim.prim = vertex.prim;
2195 prim.numverts = vertex.count;
2196 prim.vc_format = dev_priv->sarea_priv->vc_format;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002197
2198 radeon_cp_dispatch_vertex(dev, buf, &prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 }
2200
2201 if (vertex.discard) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002202 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 }
2204
2205 COMMIT_RING();
2206 return 0;
2207}
2208
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002209static int radeon_cp_indices(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210{
2211 DRM_DEVICE;
2212 drm_radeon_private_t *dev_priv = dev->dev_private;
2213 drm_file_t *filp_priv;
2214 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2215 drm_device_dma_t *dma = dev->dma;
2216 drm_buf_t *buf;
2217 drm_radeon_indices_t elts;
2218 drm_radeon_tcl_prim_t prim;
2219 int count;
2220
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002221 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002223 if (!dev_priv) {
2224 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 return DRM_ERR(EINVAL);
2226 }
2227
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002228 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002230 DRM_COPY_FROM_USER_IOCTL(elts, (drm_radeon_indices_t __user *) data,
2231 sizeof(elts));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002233 DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n",
2234 DRM_CURRENTPID, elts.idx, elts.start, elts.end, elts.discard);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002236 if (elts.idx < 0 || elts.idx >= dma->buf_count) {
2237 DRM_ERROR("buffer index %d (of %d max)\n",
2238 elts.idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 return DRM_ERR(EINVAL);
2240 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002241 if (elts.prim < 0 || elts.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
2242 DRM_ERROR("buffer prim %d\n", elts.prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 return DRM_ERR(EINVAL);
2244 }
2245
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002246 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2247 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248
2249 buf = dma->buflist[elts.idx];
2250
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002251 if (buf->filp != filp) {
2252 DRM_ERROR("process %d using buffer owned by %p\n",
2253 DRM_CURRENTPID, buf->filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 return DRM_ERR(EINVAL);
2255 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002256 if (buf->pending) {
2257 DRM_ERROR("sending pending buffer %d\n", elts.idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 return DRM_ERR(EINVAL);
2259 }
2260
2261 count = (elts.end - elts.start) / sizeof(u16);
2262 elts.start -= RADEON_INDEX_PRIM_OFFSET;
2263
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002264 if (elts.start & 0x7) {
2265 DRM_ERROR("misaligned buffer 0x%x\n", elts.start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 return DRM_ERR(EINVAL);
2267 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002268 if (elts.start < buf->used) {
2269 DRM_ERROR("no header 0x%x - 0x%x\n", elts.start, buf->used);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 return DRM_ERR(EINVAL);
2271 }
2272
2273 buf->used = elts.end;
2274
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002275 if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
2276 if (radeon_emit_state(dev_priv, filp_priv,
2277 &sarea_priv->context_state,
2278 sarea_priv->tex_state,
2279 sarea_priv->dirty)) {
2280 DRM_ERROR("radeon_emit_state failed\n");
2281 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 }
2283
2284 sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
2285 RADEON_UPLOAD_TEX1IMAGES |
2286 RADEON_UPLOAD_TEX2IMAGES |
2287 RADEON_REQUIRE_QUIESCENCE);
2288 }
2289
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 /* Build up a prim_t record:
2291 */
2292 prim.start = elts.start;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002293 prim.finish = elts.end;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294 prim.prim = elts.prim;
2295 prim.offset = 0; /* offset from start of dma buffers */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002296 prim.numverts = RADEON_MAX_VB_VERTS; /* duh */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 prim.vc_format = dev_priv->sarea_priv->vc_format;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002298
2299 radeon_cp_dispatch_indices(dev, buf, &prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 if (elts.discard) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002301 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 }
2303
2304 COMMIT_RING();
2305 return 0;
2306}
2307
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002308static int radeon_cp_texture(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309{
2310 DRM_DEVICE;
2311 drm_radeon_private_t *dev_priv = dev->dev_private;
2312 drm_radeon_texture_t tex;
2313 drm_radeon_tex_image_t image;
2314 int ret;
2315
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002316 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002318 DRM_COPY_FROM_USER_IOCTL(tex, (drm_radeon_texture_t __user *) data,
2319 sizeof(tex));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002321 if (tex.image == NULL) {
2322 DRM_ERROR("null texture image!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 return DRM_ERR(EINVAL);
2324 }
2325
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002326 if (DRM_COPY_FROM_USER(&image,
2327 (drm_radeon_tex_image_t __user *) tex.image,
2328 sizeof(image)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 return DRM_ERR(EFAULT);
2330
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002331 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2332 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002334 ret = radeon_cp_dispatch_texture(filp, dev, &tex, &image);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335
2336 COMMIT_RING();
2337 return ret;
2338}
2339
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002340static int radeon_cp_stipple(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341{
2342 DRM_DEVICE;
2343 drm_radeon_private_t *dev_priv = dev->dev_private;
2344 drm_radeon_stipple_t stipple;
2345 u32 mask[32];
2346
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002347 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002349 DRM_COPY_FROM_USER_IOCTL(stipple, (drm_radeon_stipple_t __user *) data,
2350 sizeof(stipple));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002352 if (DRM_COPY_FROM_USER(&mask, stipple.mask, 32 * sizeof(u32)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 return DRM_ERR(EFAULT);
2354
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002355 RING_SPACE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002357 radeon_cp_dispatch_stipple(dev, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358
2359 COMMIT_RING();
2360 return 0;
2361}
2362
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002363static int radeon_cp_indirect(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364{
2365 DRM_DEVICE;
2366 drm_radeon_private_t *dev_priv = dev->dev_private;
2367 drm_device_dma_t *dma = dev->dma;
2368 drm_buf_t *buf;
2369 drm_radeon_indirect_t indirect;
2370 RING_LOCALS;
2371
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002372 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002374 if (!dev_priv) {
2375 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 return DRM_ERR(EINVAL);
2377 }
2378
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002379 DRM_COPY_FROM_USER_IOCTL(indirect,
2380 (drm_radeon_indirect_t __user *) data,
2381 sizeof(indirect));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002383 DRM_DEBUG("indirect: idx=%d s=%d e=%d d=%d\n",
2384 indirect.idx, indirect.start, indirect.end, indirect.discard);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002386 if (indirect.idx < 0 || indirect.idx >= dma->buf_count) {
2387 DRM_ERROR("buffer index %d (of %d max)\n",
2388 indirect.idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 return DRM_ERR(EINVAL);
2390 }
2391
2392 buf = dma->buflist[indirect.idx];
2393
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002394 if (buf->filp != filp) {
2395 DRM_ERROR("process %d using buffer owned by %p\n",
2396 DRM_CURRENTPID, buf->filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 return DRM_ERR(EINVAL);
2398 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002399 if (buf->pending) {
2400 DRM_ERROR("sending pending buffer %d\n", indirect.idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 return DRM_ERR(EINVAL);
2402 }
2403
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002404 if (indirect.start < buf->used) {
2405 DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n",
2406 indirect.start, buf->used);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 return DRM_ERR(EINVAL);
2408 }
2409
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002410 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2411 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412
2413 buf->used = indirect.end;
2414
2415 /* Wait for the 3D stream to idle before the indirect buffer
2416 * containing 2D acceleration commands is processed.
2417 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002418 BEGIN_RING(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419
2420 RADEON_WAIT_UNTIL_3D_IDLE();
2421
2422 ADVANCE_RING();
2423
2424 /* Dispatch the indirect buffer full of commands from the
2425 * X server. This is insecure and is thus only available to
2426 * privileged clients.
2427 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002428 radeon_cp_dispatch_indirect(dev, buf, indirect.start, indirect.end);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 if (indirect.discard) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002430 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 }
2432
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 COMMIT_RING();
2434 return 0;
2435}
2436
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002437static int radeon_cp_vertex2(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438{
2439 DRM_DEVICE;
2440 drm_radeon_private_t *dev_priv = dev->dev_private;
2441 drm_file_t *filp_priv;
2442 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2443 drm_device_dma_t *dma = dev->dma;
2444 drm_buf_t *buf;
2445 drm_radeon_vertex2_t vertex;
2446 int i;
2447 unsigned char laststate;
2448
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002449 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002451 if (!dev_priv) {
2452 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 return DRM_ERR(EINVAL);
2454 }
2455
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002456 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002458 DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex2_t __user *) data,
2459 sizeof(vertex));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002461 DRM_DEBUG("pid=%d index=%d discard=%d\n",
2462 DRM_CURRENTPID, vertex.idx, vertex.discard);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002464 if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
2465 DRM_ERROR("buffer index %d (of %d max)\n",
2466 vertex.idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 return DRM_ERR(EINVAL);
2468 }
2469
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002470 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2471 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472
2473 buf = dma->buflist[vertex.idx];
2474
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002475 if (buf->filp != filp) {
2476 DRM_ERROR("process %d using buffer owned by %p\n",
2477 DRM_CURRENTPID, buf->filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 return DRM_ERR(EINVAL);
2479 }
2480
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002481 if (buf->pending) {
2482 DRM_ERROR("sending pending buffer %d\n", vertex.idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 return DRM_ERR(EINVAL);
2484 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002485
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
2487 return DRM_ERR(EINVAL);
2488
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002489 for (laststate = 0xff, i = 0; i < vertex.nr_prims; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 drm_radeon_prim_t prim;
2491 drm_radeon_tcl_prim_t tclprim;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002492
2493 if (DRM_COPY_FROM_USER(&prim, &vertex.prim[i], sizeof(prim)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 return DRM_ERR(EFAULT);
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002495
2496 if (prim.stateidx != laststate) {
2497 drm_radeon_state_t state;
2498
2499 if (DRM_COPY_FROM_USER(&state,
2500 &vertex.state[prim.stateidx],
2501 sizeof(state)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 return DRM_ERR(EFAULT);
2503
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002504 if (radeon_emit_state2(dev_priv, filp_priv, &state)) {
2505 DRM_ERROR("radeon_emit_state2 failed\n");
2506 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 }
2508
2509 laststate = prim.stateidx;
2510 }
2511
2512 tclprim.start = prim.start;
2513 tclprim.finish = prim.finish;
2514 tclprim.prim = prim.prim;
2515 tclprim.vc_format = prim.vc_format;
2516
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002517 if (prim.prim & RADEON_PRIM_WALK_IND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 tclprim.offset = prim.numverts * 64;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002519 tclprim.numverts = RADEON_MAX_VB_VERTS; /* duh */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002521 radeon_cp_dispatch_indices(dev, buf, &tclprim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 } else {
2523 tclprim.numverts = prim.numverts;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002524 tclprim.offset = 0; /* not used */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002526 radeon_cp_dispatch_vertex(dev, buf, &tclprim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002528
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 if (sarea_priv->nbox == 1)
2530 sarea_priv->nbox = 0;
2531 }
2532
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002533 if (vertex.discard) {
2534 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 }
2536
2537 COMMIT_RING();
2538 return 0;
2539}
2540
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002541static int radeon_emit_packets(drm_radeon_private_t * dev_priv,
2542 drm_file_t * filp_priv,
2543 drm_radeon_cmd_header_t header,
Dave Airlieb3a83632005-09-30 18:37:36 +10002544 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545{
2546 int id = (int)header.packet.packet_id;
2547 int sz, reg;
2548 int *data = (int *)cmdbuf->buf;
2549 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002550
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 if (id >= RADEON_MAX_STATE_PACKETS)
2552 return DRM_ERR(EINVAL);
2553
2554 sz = packet[id].len;
2555 reg = packet[id].start;
2556
2557 if (sz * sizeof(int) > cmdbuf->bufsz) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002558 DRM_ERROR("Packet size provided larger than data provided\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 return DRM_ERR(EINVAL);
2560 }
2561
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002562 if (radeon_check_and_fixup_packets(dev_priv, filp_priv, id, data)) {
2563 DRM_ERROR("Packet verification failed\n");
2564 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 }
2566
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002567 BEGIN_RING(sz + 1);
2568 OUT_RING(CP_PACKET0(reg, (sz - 1)));
2569 OUT_RING_TABLE(data, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 ADVANCE_RING();
2571
2572 cmdbuf->buf += sz * sizeof(int);
2573 cmdbuf->bufsz -= sz * sizeof(int);
2574 return 0;
2575}
2576
Dave Airlied985c102006-01-02 21:32:48 +11002577static __inline__ int radeon_emit_scalars(drm_radeon_private_t *dev_priv,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002578 drm_radeon_cmd_header_t header,
Dave Airlied985c102006-01-02 21:32:48 +11002579 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580{
2581 int sz = header.scalars.count;
2582 int start = header.scalars.offset;
2583 int stride = header.scalars.stride;
2584 RING_LOCALS;
2585
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002586 BEGIN_RING(3 + sz);
2587 OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
2588 OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
2589 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
2590 OUT_RING_TABLE(cmdbuf->buf, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 ADVANCE_RING();
2592 cmdbuf->buf += sz * sizeof(int);
2593 cmdbuf->bufsz -= sz * sizeof(int);
2594 return 0;
2595}
2596
2597/* God this is ugly
2598 */
Dave Airlied985c102006-01-02 21:32:48 +11002599static __inline__ int radeon_emit_scalars2(drm_radeon_private_t *dev_priv,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002600 drm_radeon_cmd_header_t header,
Dave Airlied985c102006-01-02 21:32:48 +11002601 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602{
2603 int sz = header.scalars.count;
2604 int start = ((unsigned int)header.scalars.offset) + 0x100;
2605 int stride = header.scalars.stride;
2606 RING_LOCALS;
2607
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002608 BEGIN_RING(3 + sz);
2609 OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
2610 OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
2611 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
2612 OUT_RING_TABLE(cmdbuf->buf, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 ADVANCE_RING();
2614 cmdbuf->buf += sz * sizeof(int);
2615 cmdbuf->bufsz -= sz * sizeof(int);
2616 return 0;
2617}
2618
Dave Airlied985c102006-01-02 21:32:48 +11002619static __inline__ int radeon_emit_vectors(drm_radeon_private_t *dev_priv,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002620 drm_radeon_cmd_header_t header,
Dave Airlied985c102006-01-02 21:32:48 +11002621 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622{
2623 int sz = header.vectors.count;
2624 int start = header.vectors.offset;
2625 int stride = header.vectors.stride;
2626 RING_LOCALS;
2627
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002628 BEGIN_RING(3 + sz);
2629 OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
2630 OUT_RING(start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
2631 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
2632 OUT_RING_TABLE(cmdbuf->buf, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 ADVANCE_RING();
2634
2635 cmdbuf->buf += sz * sizeof(int);
2636 cmdbuf->bufsz -= sz * sizeof(int);
2637 return 0;
2638}
2639
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002640static int radeon_emit_packet3(drm_device_t * dev,
2641 drm_file_t * filp_priv,
Dave Airlieb3a83632005-09-30 18:37:36 +10002642 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643{
2644 drm_radeon_private_t *dev_priv = dev->dev_private;
2645 unsigned int cmdsz;
2646 int ret;
2647 RING_LOCALS;
2648
2649 DRM_DEBUG("\n");
2650
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002651 if ((ret = radeon_check_and_fixup_packet3(dev_priv, filp_priv,
2652 cmdbuf, &cmdsz))) {
2653 DRM_ERROR("Packet verification failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 return ret;
2655 }
2656
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002657 BEGIN_RING(cmdsz);
2658 OUT_RING_TABLE(cmdbuf->buf, cmdsz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 ADVANCE_RING();
2660
2661 cmdbuf->buf += cmdsz * 4;
2662 cmdbuf->bufsz -= cmdsz * 4;
2663 return 0;
2664}
2665
Dave Airlied985c102006-01-02 21:32:48 +11002666static int radeon_emit_packet3_cliprect(drm_device_t *dev,
2667 drm_file_t *filp_priv,
Dave Airlieb3a83632005-09-30 18:37:36 +10002668 drm_radeon_kcmd_buffer_t *cmdbuf,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002669 int orig_nbox)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670{
2671 drm_radeon_private_t *dev_priv = dev->dev_private;
2672 drm_clip_rect_t box;
2673 unsigned int cmdsz;
2674 int ret;
2675 drm_clip_rect_t __user *boxes = cmdbuf->boxes;
2676 int i = 0;
2677 RING_LOCALS;
2678
2679 DRM_DEBUG("\n");
2680
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002681 if ((ret = radeon_check_and_fixup_packet3(dev_priv, filp_priv,
2682 cmdbuf, &cmdsz))) {
2683 DRM_ERROR("Packet verification failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 return ret;
2685 }
2686
2687 if (!orig_nbox)
2688 goto out;
2689
2690 do {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002691 if (i < cmdbuf->nbox) {
2692 if (DRM_COPY_FROM_USER(&box, &boxes[i], sizeof(box)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 return DRM_ERR(EFAULT);
2694 /* FIXME The second and subsequent times round
2695 * this loop, send a WAIT_UNTIL_3D_IDLE before
2696 * calling emit_clip_rect(). This fixes a
2697 * lockup on fast machines when sending
2698 * several cliprects with a cmdbuf, as when
2699 * waving a 2D window over a 3D
2700 * window. Something in the commands from user
2701 * space seems to hang the card when they're
2702 * sent several times in a row. That would be
2703 * the correct place to fix it but this works
2704 * around it until I can figure that out - Tim
2705 * Smith */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002706 if (i) {
2707 BEGIN_RING(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 RADEON_WAIT_UNTIL_3D_IDLE();
2709 ADVANCE_RING();
2710 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002711 radeon_emit_clip_rect(dev_priv, &box);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002713
2714 BEGIN_RING(cmdsz);
2715 OUT_RING_TABLE(cmdbuf->buf, cmdsz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 ADVANCE_RING();
2717
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002718 } while (++i < cmdbuf->nbox);
2719 if (cmdbuf->nbox == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 cmdbuf->nbox = 0;
2721
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002722 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 cmdbuf->buf += cmdsz * 4;
2724 cmdbuf->bufsz -= cmdsz * 4;
2725 return 0;
2726}
2727
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002728static int radeon_emit_wait(drm_device_t * dev, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729{
2730 drm_radeon_private_t *dev_priv = dev->dev_private;
2731 RING_LOCALS;
2732
2733 DRM_DEBUG("%s: %x\n", __FUNCTION__, flags);
2734 switch (flags) {
2735 case RADEON_WAIT_2D:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002736 BEGIN_RING(2);
2737 RADEON_WAIT_UNTIL_2D_IDLE();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 ADVANCE_RING();
2739 break;
2740 case RADEON_WAIT_3D:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002741 BEGIN_RING(2);
2742 RADEON_WAIT_UNTIL_3D_IDLE();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 ADVANCE_RING();
2744 break;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002745 case RADEON_WAIT_2D | RADEON_WAIT_3D:
2746 BEGIN_RING(2);
2747 RADEON_WAIT_UNTIL_IDLE();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 ADVANCE_RING();
2749 break;
2750 default:
2751 return DRM_ERR(EINVAL);
2752 }
2753
2754 return 0;
2755}
2756
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002757static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758{
2759 DRM_DEVICE;
2760 drm_radeon_private_t *dev_priv = dev->dev_private;
2761 drm_file_t *filp_priv;
2762 drm_device_dma_t *dma = dev->dma;
2763 drm_buf_t *buf = NULL;
2764 int idx;
Dave Airlieb3a83632005-09-30 18:37:36 +10002765 drm_radeon_kcmd_buffer_t cmdbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 drm_radeon_cmd_header_t header;
2767 int orig_nbox, orig_bufsz;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002768 char *kbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002770 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002772 if (!dev_priv) {
2773 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 return DRM_ERR(EINVAL);
2775 }
2776
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002777 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002779 DRM_COPY_FROM_USER_IOCTL(cmdbuf,
2780 (drm_radeon_cmd_buffer_t __user *) data,
2781 sizeof(cmdbuf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002783 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2784 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002786 if (cmdbuf.bufsz > 64 * 1024 || cmdbuf.bufsz < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 return DRM_ERR(EINVAL);
2788 }
2789
2790 /* Allocate an in-kernel area and copy in the cmdbuf. Do this to avoid
2791 * races between checking values and using those values in other code,
2792 * and simply to avoid a lot of function calls to copy in data.
2793 */
2794 orig_bufsz = cmdbuf.bufsz;
2795 if (orig_bufsz != 0) {
2796 kbuf = drm_alloc(cmdbuf.bufsz, DRM_MEM_DRIVER);
2797 if (kbuf == NULL)
2798 return DRM_ERR(ENOMEM);
Dave Airlied985c102006-01-02 21:32:48 +11002799 if (DRM_COPY_FROM_USER(kbuf, (void __user *)cmdbuf.buf,
2800 cmdbuf.bufsz)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
2802 return DRM_ERR(EFAULT);
2803 }
2804 cmdbuf.buf = kbuf;
2805 }
2806
2807 orig_nbox = cmdbuf.nbox;
2808
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002809 if (dev_priv->microcode_version == UCODE_R300) {
Dave Airlie414ed532005-08-16 20:43:16 +10002810 int temp;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002811 temp = r300_do_cp_cmdbuf(dev, filp, filp_priv, &cmdbuf);
2812
Dave Airlie414ed532005-08-16 20:43:16 +10002813 if (orig_bufsz != 0)
2814 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002815
Dave Airlie414ed532005-08-16 20:43:16 +10002816 return temp;
2817 }
2818
2819 /* microcode_version != r300 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002820 while (cmdbuf.bufsz >= sizeof(header)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821
2822 header.i = *(int *)cmdbuf.buf;
2823 cmdbuf.buf += sizeof(header);
2824 cmdbuf.bufsz -= sizeof(header);
2825
2826 switch (header.header.cmd_type) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002827 case RADEON_CMD_PACKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 DRM_DEBUG("RADEON_CMD_PACKET\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002829 if (radeon_emit_packets
2830 (dev_priv, filp_priv, header, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 DRM_ERROR("radeon_emit_packets failed\n");
2832 goto err;
2833 }
2834 break;
2835
2836 case RADEON_CMD_SCALARS:
2837 DRM_DEBUG("RADEON_CMD_SCALARS\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002838 if (radeon_emit_scalars(dev_priv, header, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 DRM_ERROR("radeon_emit_scalars failed\n");
2840 goto err;
2841 }
2842 break;
2843
2844 case RADEON_CMD_VECTORS:
2845 DRM_DEBUG("RADEON_CMD_VECTORS\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002846 if (radeon_emit_vectors(dev_priv, header, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 DRM_ERROR("radeon_emit_vectors failed\n");
2848 goto err;
2849 }
2850 break;
2851
2852 case RADEON_CMD_DMA_DISCARD:
2853 DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n");
2854 idx = header.dma.buf_idx;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002855 if (idx < 0 || idx >= dma->buf_count) {
2856 DRM_ERROR("buffer index %d (of %d max)\n",
2857 idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 goto err;
2859 }
2860
2861 buf = dma->buflist[idx];
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002862 if (buf->filp != filp || buf->pending) {
2863 DRM_ERROR("bad buffer %p %p %d\n",
2864 buf->filp, filp, buf->pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 goto err;
2866 }
2867
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002868 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 break;
2870
2871 case RADEON_CMD_PACKET3:
2872 DRM_DEBUG("RADEON_CMD_PACKET3\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002873 if (radeon_emit_packet3(dev, filp_priv, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 DRM_ERROR("radeon_emit_packet3 failed\n");
2875 goto err;
2876 }
2877 break;
2878
2879 case RADEON_CMD_PACKET3_CLIP:
2880 DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002881 if (radeon_emit_packet3_cliprect
2882 (dev, filp_priv, &cmdbuf, orig_nbox)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 DRM_ERROR("radeon_emit_packet3_clip failed\n");
2884 goto err;
2885 }
2886 break;
2887
2888 case RADEON_CMD_SCALARS2:
2889 DRM_DEBUG("RADEON_CMD_SCALARS2\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002890 if (radeon_emit_scalars2(dev_priv, header, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 DRM_ERROR("radeon_emit_scalars2 failed\n");
2892 goto err;
2893 }
2894 break;
2895
2896 case RADEON_CMD_WAIT:
2897 DRM_DEBUG("RADEON_CMD_WAIT\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002898 if (radeon_emit_wait(dev, header.wait.flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 DRM_ERROR("radeon_emit_wait failed\n");
2900 goto err;
2901 }
2902 break;
2903 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002904 DRM_ERROR("bad cmd_type %d at %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 header.header.cmd_type,
2906 cmdbuf.buf - sizeof(header));
2907 goto err;
2908 }
2909 }
2910
2911 if (orig_bufsz != 0)
2912 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
2913
2914 DRM_DEBUG("DONE\n");
2915 COMMIT_RING();
2916 return 0;
2917
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002918 err:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919 if (orig_bufsz != 0)
2920 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
2921 return DRM_ERR(EINVAL);
2922}
2923
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002924static int radeon_cp_getparam(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925{
2926 DRM_DEVICE;
2927 drm_radeon_private_t *dev_priv = dev->dev_private;
2928 drm_radeon_getparam_t param;
2929 int value;
2930
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002931 if (!dev_priv) {
2932 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 return DRM_ERR(EINVAL);
2934 }
2935
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002936 DRM_COPY_FROM_USER_IOCTL(param, (drm_radeon_getparam_t __user *) data,
2937 sizeof(param));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002939 DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002941 switch (param.param) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 case RADEON_PARAM_GART_BUFFER_OFFSET:
2943 value = dev_priv->gart_buffers_offset;
2944 break;
2945 case RADEON_PARAM_LAST_FRAME:
2946 dev_priv->stats.last_frame_reads++;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002947 value = GET_SCRATCH(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 break;
2949 case RADEON_PARAM_LAST_DISPATCH:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002950 value = GET_SCRATCH(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 break;
2952 case RADEON_PARAM_LAST_CLEAR:
2953 dev_priv->stats.last_clear_reads++;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002954 value = GET_SCRATCH(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 break;
2956 case RADEON_PARAM_IRQ_NR:
2957 value = dev->irq;
2958 break;
2959 case RADEON_PARAM_GART_BASE:
2960 value = dev_priv->gart_vm_start;
2961 break;
2962 case RADEON_PARAM_REGISTER_HANDLE:
Dave Airlied985c102006-01-02 21:32:48 +11002963 value = dev_priv->mmio->offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 break;
2965 case RADEON_PARAM_STATUS_HANDLE:
2966 value = dev_priv->ring_rptr_offset;
2967 break;
2968#if BITS_PER_LONG == 32
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002969 /*
2970 * This ioctl() doesn't work on 64-bit platforms because hw_lock is a
2971 * pointer which can't fit into an int-sized variable. According to
2972 * Michel Dänzer, the ioctl() is only used on embedded platforms, so
2973 * not supporting it shouldn't be a problem. If the same functionality
2974 * is needed on 64-bit platforms, a new ioctl() would have to be added,
2975 * so backwards-compatibility for the embedded platforms can be
2976 * maintained. --davidm 4-Feb-2004.
2977 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 case RADEON_PARAM_SAREA_HANDLE:
2979 /* The lock is the first dword in the sarea. */
2980 value = (long)dev->lock.hw_lock;
2981 break;
2982#endif
2983 case RADEON_PARAM_GART_TEX_HANDLE:
2984 value = dev_priv->gart_textures_offset;
2985 break;
Dave Airlied985c102006-01-02 21:32:48 +11002986
2987 case RADEON_PARAM_CARD_TYPE:
2988 if (dev_priv->flags & CHIP_IS_PCIE)
2989 value = RADEON_CARD_PCIE;
2990 else if (dev_priv->flags & CHIP_IS_AGP)
2991 value = RADEON_CARD_AGP;
2992 else
2993 value = RADEON_CARD_PCI;
2994 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995 default:
2996 return DRM_ERR(EINVAL);
2997 }
2998
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002999 if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
3000 DRM_ERROR("copy_to_user\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 return DRM_ERR(EFAULT);
3002 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003003
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 return 0;
3005}
3006
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003007static int radeon_cp_setparam(DRM_IOCTL_ARGS)
3008{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 DRM_DEVICE;
3010 drm_radeon_private_t *dev_priv = dev->dev_private;
3011 drm_file_t *filp_priv;
3012 drm_radeon_setparam_t sp;
3013 struct drm_radeon_driver_file_fields *radeon_priv;
3014
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003015 if (!dev_priv) {
3016 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
3017 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 }
3019
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003020 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003022 DRM_COPY_FROM_USER_IOCTL(sp, (drm_radeon_setparam_t __user *) data,
3023 sizeof(sp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003025 switch (sp.param) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 case RADEON_SETPARAM_FB_LOCATION:
3027 radeon_priv = filp_priv->driver_priv;
3028 radeon_priv->radeon_fb_delta = dev_priv->fb_location - sp.value;
3029 break;
3030 case RADEON_SETPARAM_SWITCH_TILING:
3031 if (sp.value == 0) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003032 DRM_DEBUG("color tiling disabled\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO;
3034 dev_priv->back_pitch_offset &= ~RADEON_DST_TILE_MACRO;
3035 dev_priv->sarea_priv->tiling_enabled = 0;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003036 } else if (sp.value == 1) {
3037 DRM_DEBUG("color tiling enabled\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 dev_priv->front_pitch_offset |= RADEON_DST_TILE_MACRO;
3039 dev_priv->back_pitch_offset |= RADEON_DST_TILE_MACRO;
3040 dev_priv->sarea_priv->tiling_enabled = 1;
3041 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003042 break;
Dave Airlieea98a922005-09-11 20:28:11 +10003043 case RADEON_SETPARAM_PCIGART_LOCATION:
3044 dev_priv->pcigart_offset = sp.value;
3045 break;
Dave Airlied5ea7022006-03-19 19:37:55 +11003046 case RADEON_SETPARAM_NEW_MEMMAP:
3047 dev_priv->new_memmap = sp.value;
3048 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003050 DRM_DEBUG("Invalid parameter %d\n", sp.param);
3051 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 }
3053
3054 return 0;
3055}
3056
3057/* When a client dies:
3058 * - Check for and clean up flipped page state
3059 * - Free any alloced GART memory.
Dave Airlied985c102006-01-02 21:32:48 +11003060 * - Free any alloced radeon surfaces.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 *
3062 * DRM infrastructure takes care of reclaiming dma buffers.
3063 */
Dave Airlie22eae942005-11-10 22:16:34 +11003064void radeon_driver_preclose(drm_device_t * dev, DRMFILE filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065{
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003066 if (dev->dev_private) {
3067 drm_radeon_private_t *dev_priv = dev->dev_private;
3068 if (dev_priv->page_flipping) {
3069 radeon_do_cleanup_pageflip(dev);
3070 }
3071 radeon_mem_release(filp, dev_priv->gart_heap);
3072 radeon_mem_release(filp, dev_priv->fb_heap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 radeon_surfaces_release(filp, dev_priv);
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003074 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075}
3076
Dave Airlie22eae942005-11-10 22:16:34 +11003077void radeon_driver_lastclose(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078{
3079 radeon_do_release(dev);
3080}
3081
Dave Airlie22eae942005-11-10 22:16:34 +11003082int radeon_driver_open(drm_device_t * dev, drm_file_t * filp_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083{
3084 drm_radeon_private_t *dev_priv = dev->dev_private;
3085 struct drm_radeon_driver_file_fields *radeon_priv;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003086
Dave Airlied985c102006-01-02 21:32:48 +11003087 DRM_DEBUG("\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003088 radeon_priv =
3089 (struct drm_radeon_driver_file_fields *)
3090 drm_alloc(sizeof(*radeon_priv), DRM_MEM_FILES);
3091
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 if (!radeon_priv)
3093 return -ENOMEM;
3094
3095 filp_priv->driver_priv = radeon_priv;
Dave Airlied985c102006-01-02 21:32:48 +11003096
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003097 if (dev_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 radeon_priv->radeon_fb_delta = dev_priv->fb_location;
3099 else
3100 radeon_priv->radeon_fb_delta = 0;
3101 return 0;
3102}
3103
Dave Airlie22eae942005-11-10 22:16:34 +11003104void radeon_driver_postclose(drm_device_t * dev, drm_file_t * filp_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105{
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003106 struct drm_radeon_driver_file_fields *radeon_priv =
3107 filp_priv->driver_priv;
3108
3109 drm_free(radeon_priv, sizeof(*radeon_priv), DRM_MEM_FILES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110}
3111
3112drm_ioctl_desc_t radeon_ioctls[] = {
Dave Airliea7a2cc32006-01-02 13:54:04 +11003113 [DRM_IOCTL_NR(DRM_RADEON_CP_INIT)] = {radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3114 [DRM_IOCTL_NR(DRM_RADEON_CP_START)] = {radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3115 [DRM_IOCTL_NR(DRM_RADEON_CP_STOP)] = {radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3116 [DRM_IOCTL_NR(DRM_RADEON_CP_RESET)] = {radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3117 [DRM_IOCTL_NR(DRM_RADEON_CP_IDLE)] = {radeon_cp_idle, DRM_AUTH},
3118 [DRM_IOCTL_NR(DRM_RADEON_CP_RESUME)] = {radeon_cp_resume, DRM_AUTH},
3119 [DRM_IOCTL_NR(DRM_RADEON_RESET)] = {radeon_engine_reset, DRM_AUTH},
3120 [DRM_IOCTL_NR(DRM_RADEON_FULLSCREEN)] = {radeon_fullscreen, DRM_AUTH},
3121 [DRM_IOCTL_NR(DRM_RADEON_SWAP)] = {radeon_cp_swap, DRM_AUTH},
3122 [DRM_IOCTL_NR(DRM_RADEON_CLEAR)] = {radeon_cp_clear, DRM_AUTH},
3123 [DRM_IOCTL_NR(DRM_RADEON_VERTEX)] = {radeon_cp_vertex, DRM_AUTH},
3124 [DRM_IOCTL_NR(DRM_RADEON_INDICES)] = {radeon_cp_indices, DRM_AUTH},
3125 [DRM_IOCTL_NR(DRM_RADEON_TEXTURE)] = {radeon_cp_texture, DRM_AUTH},
3126 [DRM_IOCTL_NR(DRM_RADEON_STIPPLE)] = {radeon_cp_stipple, DRM_AUTH},
3127 [DRM_IOCTL_NR(DRM_RADEON_INDIRECT)] = {radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3128 [DRM_IOCTL_NR(DRM_RADEON_VERTEX2)] = {radeon_cp_vertex2, DRM_AUTH},
3129 [DRM_IOCTL_NR(DRM_RADEON_CMDBUF)] = {radeon_cp_cmdbuf, DRM_AUTH},
3130 [DRM_IOCTL_NR(DRM_RADEON_GETPARAM)] = {radeon_cp_getparam, DRM_AUTH},
3131 [DRM_IOCTL_NR(DRM_RADEON_FLIP)] = {radeon_cp_flip, DRM_AUTH},
3132 [DRM_IOCTL_NR(DRM_RADEON_ALLOC)] = {radeon_mem_alloc, DRM_AUTH},
3133 [DRM_IOCTL_NR(DRM_RADEON_FREE)] = {radeon_mem_free, DRM_AUTH},
3134 [DRM_IOCTL_NR(DRM_RADEON_INIT_HEAP)] = {radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3135 [DRM_IOCTL_NR(DRM_RADEON_IRQ_EMIT)] = {radeon_irq_emit, DRM_AUTH},
3136 [DRM_IOCTL_NR(DRM_RADEON_IRQ_WAIT)] = {radeon_irq_wait, DRM_AUTH},
3137 [DRM_IOCTL_NR(DRM_RADEON_SETPARAM)] = {radeon_cp_setparam, DRM_AUTH},
3138 [DRM_IOCTL_NR(DRM_RADEON_SURF_ALLOC)] = {radeon_surface_alloc, DRM_AUTH},
3139 [DRM_IOCTL_NR(DRM_RADEON_SURF_FREE)] = {radeon_surface_free, DRM_AUTH}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140};
3141
3142int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls);