blob: 99589fe0032f4d7c5d4d7724f71601fe1edf4455 [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
Roland Scheidegger18f29052006-08-30 23:17:55 +0100178 case R200_EMIT_VAP_CTL:{
179 RING_LOCALS;
180 BEGIN_RING(2);
181 OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
182 ADVANCE_RING();
183 }
184 break;
185
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 case RADEON_EMIT_RB3D_COLORPITCH:
187 case RADEON_EMIT_RE_LINE_PATTERN:
188 case RADEON_EMIT_SE_LINE_WIDTH:
189 case RADEON_EMIT_PP_LUM_MATRIX:
190 case RADEON_EMIT_PP_ROT_MATRIX_0:
191 case RADEON_EMIT_RB3D_STENCILREFMASK:
192 case RADEON_EMIT_SE_VPORT_XSCALE:
193 case RADEON_EMIT_SE_CNTL:
194 case RADEON_EMIT_SE_CNTL_STATUS:
195 case RADEON_EMIT_RE_MISC:
196 case RADEON_EMIT_PP_BORDER_COLOR_0:
197 case RADEON_EMIT_PP_BORDER_COLOR_1:
198 case RADEON_EMIT_PP_BORDER_COLOR_2:
199 case RADEON_EMIT_SE_ZBIAS_FACTOR:
200 case RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT:
201 case RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED:
202 case R200_EMIT_PP_TXCBLEND_0:
203 case R200_EMIT_PP_TXCBLEND_1:
204 case R200_EMIT_PP_TXCBLEND_2:
205 case R200_EMIT_PP_TXCBLEND_3:
206 case R200_EMIT_PP_TXCBLEND_4:
207 case R200_EMIT_PP_TXCBLEND_5:
208 case R200_EMIT_PP_TXCBLEND_6:
209 case R200_EMIT_PP_TXCBLEND_7:
210 case R200_EMIT_TCL_LIGHT_MODEL_CTL_0:
211 case R200_EMIT_TFACTOR_0:
212 case R200_EMIT_VTX_FMT_0:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 case R200_EMIT_MATRIX_SELECT_0:
214 case R200_EMIT_TEX_PROC_CTL_2:
215 case R200_EMIT_TCL_UCP_VERT_BLEND_CTL:
216 case R200_EMIT_PP_TXFILTER_0:
217 case R200_EMIT_PP_TXFILTER_1:
218 case R200_EMIT_PP_TXFILTER_2:
219 case R200_EMIT_PP_TXFILTER_3:
220 case R200_EMIT_PP_TXFILTER_4:
221 case R200_EMIT_PP_TXFILTER_5:
222 case R200_EMIT_VTE_CNTL:
223 case R200_EMIT_OUTPUT_VTX_COMP_SEL:
224 case R200_EMIT_PP_TAM_DEBUG3:
225 case R200_EMIT_PP_CNTL_X:
226 case R200_EMIT_RB3D_DEPTHXY_OFFSET:
227 case R200_EMIT_RE_AUX_SCISSOR_CNTL:
228 case R200_EMIT_RE_SCISSOR_TL_0:
229 case R200_EMIT_RE_SCISSOR_TL_1:
230 case R200_EMIT_RE_SCISSOR_TL_2:
231 case R200_EMIT_SE_VAP_CNTL_STATUS:
232 case R200_EMIT_SE_VTX_STATE_CNTL:
233 case R200_EMIT_RE_POINTSIZE:
234 case R200_EMIT_TCL_INPUT_VTX_VECTOR_ADDR_0:
235 case R200_EMIT_PP_CUBIC_FACES_0:
236 case R200_EMIT_PP_CUBIC_FACES_1:
237 case R200_EMIT_PP_CUBIC_FACES_2:
238 case R200_EMIT_PP_CUBIC_FACES_3:
239 case R200_EMIT_PP_CUBIC_FACES_4:
240 case R200_EMIT_PP_CUBIC_FACES_5:
241 case RADEON_EMIT_PP_TEX_SIZE_0:
242 case RADEON_EMIT_PP_TEX_SIZE_1:
243 case RADEON_EMIT_PP_TEX_SIZE_2:
244 case R200_EMIT_RB3D_BLENDCOLOR:
245 case R200_EMIT_TCL_POINT_SPRITE_CNTL:
246 case RADEON_EMIT_PP_CUBIC_FACES_0:
247 case RADEON_EMIT_PP_CUBIC_FACES_1:
248 case RADEON_EMIT_PP_CUBIC_FACES_2:
249 case R200_EMIT_PP_TRI_PERF_CNTL:
Dave Airlie9d176012005-09-11 19:55:53 +1000250 case R200_EMIT_PP_AFS_0:
251 case R200_EMIT_PP_AFS_1:
252 case R200_EMIT_ATF_TFACTOR:
253 case R200_EMIT_PP_TXCTLALL_0:
254 case R200_EMIT_PP_TXCTLALL_1:
255 case R200_EMIT_PP_TXCTLALL_2:
256 case R200_EMIT_PP_TXCTLALL_3:
257 case R200_EMIT_PP_TXCTLALL_4:
258 case R200_EMIT_PP_TXCTLALL_5:
Dave Airlied6fece02006-06-24 17:04:07 +1000259 case R200_EMIT_VAP_PVS_CNTL:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 /* These packets don't contain memory offsets */
261 break;
262
263 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000264 DRM_ERROR("Unknown state packet ID %d\n", id);
265 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 }
267
268 return 0;
269}
270
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000271static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
272 dev_priv,
Dave Airlied985c102006-01-02 21:32:48 +1100273 drm_file_t *filp_priv,
274 drm_radeon_kcmd_buffer_t *
275 cmdbuf,
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000276 unsigned int *cmdsz)
277{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 u32 *cmd = (u32 *) cmdbuf->buf;
279
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000280 *cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000282 if ((cmd[0] & 0xc0000000) != RADEON_CP_PACKET3) {
283 DRM_ERROR("Not a type 3 packet\n");
284 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 }
286
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000287 if (4 * *cmdsz > cmdbuf->bufsz) {
288 DRM_ERROR("Packet size larger than size of data provided\n");
289 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 }
291
292 /* Check client state and fix it up if necessary */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000293 if (cmd[0] & 0x8000) { /* MSB of opcode: next DWORD GUI_CNTL */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 u32 offset;
295
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000296 if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
297 | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 offset = cmd[2] << 10;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000299 if (radeon_check_and_fixup_offset
300 (dev_priv, filp_priv, &offset)) {
301 DRM_ERROR("Invalid first packet offset\n");
302 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000304 cmd[2] = (cmd[2] & 0xffc00000) | offset >> 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 }
306
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000307 if ((cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&
308 (cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 offset = cmd[3] << 10;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000310 if (radeon_check_and_fixup_offset
311 (dev_priv, filp_priv, &offset)) {
312 DRM_ERROR("Invalid second packet offset\n");
313 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000315 cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 }
317 }
318
319 return 0;
320}
321
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322/* ================================================================
323 * CP hardware state programming functions
324 */
325
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000326static __inline__ void radeon_emit_clip_rect(drm_radeon_private_t * dev_priv,
327 drm_clip_rect_t * box)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328{
329 RING_LOCALS;
330
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000331 DRM_DEBUG(" box: x1=%d y1=%d x2=%d y2=%d\n",
332 box->x1, box->y1, box->x2, box->y2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000334 BEGIN_RING(4);
335 OUT_RING(CP_PACKET0(RADEON_RE_TOP_LEFT, 0));
336 OUT_RING((box->y1 << 16) | box->x1);
337 OUT_RING(CP_PACKET0(RADEON_RE_WIDTH_HEIGHT, 0));
338 OUT_RING(((box->y2 - 1) << 16) | (box->x2 - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 ADVANCE_RING();
340}
341
342/* Emit 1.1 state
343 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000344static int radeon_emit_state(drm_radeon_private_t * dev_priv,
345 drm_file_t * filp_priv,
346 drm_radeon_context_regs_t * ctx,
347 drm_radeon_texture_regs_t * tex,
348 unsigned int dirty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349{
350 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000351 DRM_DEBUG("dirty=0x%08x\n", dirty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000353 if (dirty & RADEON_UPLOAD_CONTEXT) {
354 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
355 &ctx->rb3d_depthoffset)) {
356 DRM_ERROR("Invalid depth buffer offset\n");
357 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 }
359
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000360 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
361 &ctx->rb3d_coloroffset)) {
362 DRM_ERROR("Invalid depth buffer offset\n");
363 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 }
365
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000366 BEGIN_RING(14);
367 OUT_RING(CP_PACKET0(RADEON_PP_MISC, 6));
368 OUT_RING(ctx->pp_misc);
369 OUT_RING(ctx->pp_fog_color);
370 OUT_RING(ctx->re_solid_color);
371 OUT_RING(ctx->rb3d_blendcntl);
372 OUT_RING(ctx->rb3d_depthoffset);
373 OUT_RING(ctx->rb3d_depthpitch);
374 OUT_RING(ctx->rb3d_zstencilcntl);
375 OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 2));
376 OUT_RING(ctx->pp_cntl);
377 OUT_RING(ctx->rb3d_cntl);
378 OUT_RING(ctx->rb3d_coloroffset);
379 OUT_RING(CP_PACKET0(RADEON_RB3D_COLORPITCH, 0));
380 OUT_RING(ctx->rb3d_colorpitch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 ADVANCE_RING();
382 }
383
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000384 if (dirty & RADEON_UPLOAD_VERTFMT) {
385 BEGIN_RING(2);
386 OUT_RING(CP_PACKET0(RADEON_SE_COORD_FMT, 0));
387 OUT_RING(ctx->se_coord_fmt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 ADVANCE_RING();
389 }
390
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000391 if (dirty & RADEON_UPLOAD_LINE) {
392 BEGIN_RING(5);
393 OUT_RING(CP_PACKET0(RADEON_RE_LINE_PATTERN, 1));
394 OUT_RING(ctx->re_line_pattern);
395 OUT_RING(ctx->re_line_state);
396 OUT_RING(CP_PACKET0(RADEON_SE_LINE_WIDTH, 0));
397 OUT_RING(ctx->se_line_width);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 ADVANCE_RING();
399 }
400
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000401 if (dirty & RADEON_UPLOAD_BUMPMAP) {
402 BEGIN_RING(5);
403 OUT_RING(CP_PACKET0(RADEON_PP_LUM_MATRIX, 0));
404 OUT_RING(ctx->pp_lum_matrix);
405 OUT_RING(CP_PACKET0(RADEON_PP_ROT_MATRIX_0, 1));
406 OUT_RING(ctx->pp_rot_matrix_0);
407 OUT_RING(ctx->pp_rot_matrix_1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 ADVANCE_RING();
409 }
410
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000411 if (dirty & RADEON_UPLOAD_MASKS) {
412 BEGIN_RING(4);
413 OUT_RING(CP_PACKET0(RADEON_RB3D_STENCILREFMASK, 2));
414 OUT_RING(ctx->rb3d_stencilrefmask);
415 OUT_RING(ctx->rb3d_ropcntl);
416 OUT_RING(ctx->rb3d_planemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 ADVANCE_RING();
418 }
419
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000420 if (dirty & RADEON_UPLOAD_VIEWPORT) {
421 BEGIN_RING(7);
422 OUT_RING(CP_PACKET0(RADEON_SE_VPORT_XSCALE, 5));
423 OUT_RING(ctx->se_vport_xscale);
424 OUT_RING(ctx->se_vport_xoffset);
425 OUT_RING(ctx->se_vport_yscale);
426 OUT_RING(ctx->se_vport_yoffset);
427 OUT_RING(ctx->se_vport_zscale);
428 OUT_RING(ctx->se_vport_zoffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 ADVANCE_RING();
430 }
431
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000432 if (dirty & RADEON_UPLOAD_SETUP) {
433 BEGIN_RING(4);
434 OUT_RING(CP_PACKET0(RADEON_SE_CNTL, 0));
435 OUT_RING(ctx->se_cntl);
436 OUT_RING(CP_PACKET0(RADEON_SE_CNTL_STATUS, 0));
437 OUT_RING(ctx->se_cntl_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 ADVANCE_RING();
439 }
440
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000441 if (dirty & RADEON_UPLOAD_MISC) {
442 BEGIN_RING(2);
443 OUT_RING(CP_PACKET0(RADEON_RE_MISC, 0));
444 OUT_RING(ctx->re_misc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 ADVANCE_RING();
446 }
447
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000448 if (dirty & RADEON_UPLOAD_TEX0) {
449 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
450 &tex[0].pp_txoffset)) {
451 DRM_ERROR("Invalid texture offset for unit 0\n");
452 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 }
454
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000455 BEGIN_RING(9);
456 OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_0, 5));
457 OUT_RING(tex[0].pp_txfilter);
458 OUT_RING(tex[0].pp_txformat);
459 OUT_RING(tex[0].pp_txoffset);
460 OUT_RING(tex[0].pp_txcblend);
461 OUT_RING(tex[0].pp_txablend);
462 OUT_RING(tex[0].pp_tfactor);
463 OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_0, 0));
464 OUT_RING(tex[0].pp_border_color);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 ADVANCE_RING();
466 }
467
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000468 if (dirty & RADEON_UPLOAD_TEX1) {
469 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
470 &tex[1].pp_txoffset)) {
471 DRM_ERROR("Invalid texture offset for unit 1\n");
472 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 }
474
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000475 BEGIN_RING(9);
476 OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_1, 5));
477 OUT_RING(tex[1].pp_txfilter);
478 OUT_RING(tex[1].pp_txformat);
479 OUT_RING(tex[1].pp_txoffset);
480 OUT_RING(tex[1].pp_txcblend);
481 OUT_RING(tex[1].pp_txablend);
482 OUT_RING(tex[1].pp_tfactor);
483 OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_1, 0));
484 OUT_RING(tex[1].pp_border_color);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 ADVANCE_RING();
486 }
487
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000488 if (dirty & RADEON_UPLOAD_TEX2) {
489 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
490 &tex[2].pp_txoffset)) {
491 DRM_ERROR("Invalid texture offset for unit 2\n");
492 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 }
494
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000495 BEGIN_RING(9);
496 OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_2, 5));
497 OUT_RING(tex[2].pp_txfilter);
498 OUT_RING(tex[2].pp_txformat);
499 OUT_RING(tex[2].pp_txoffset);
500 OUT_RING(tex[2].pp_txcblend);
501 OUT_RING(tex[2].pp_txablend);
502 OUT_RING(tex[2].pp_tfactor);
503 OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_2, 0));
504 OUT_RING(tex[2].pp_border_color);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 ADVANCE_RING();
506 }
507
508 return 0;
509}
510
511/* Emit 1.2 state
512 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000513static int radeon_emit_state2(drm_radeon_private_t * dev_priv,
514 drm_file_t * filp_priv,
515 drm_radeon_state_t * state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516{
517 RING_LOCALS;
518
519 if (state->dirty & RADEON_UPLOAD_ZBIAS) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000520 BEGIN_RING(3);
521 OUT_RING(CP_PACKET0(RADEON_SE_ZBIAS_FACTOR, 1));
522 OUT_RING(state->context2.se_zbias_factor);
523 OUT_RING(state->context2.se_zbias_constant);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 ADVANCE_RING();
525 }
526
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000527 return radeon_emit_state(dev_priv, filp_priv, &state->context,
528 state->tex, state->dirty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529}
530
531/* New (1.3) state mechanism. 3 commands (packet, scalar, vector) in
532 * 1.3 cmdbuffers allow all previous state to be updated as well as
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000533 * the tcl scalar and vector areas.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000535static struct {
536 int start;
537 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 const char *name;
539} packet[RADEON_MAX_STATE_PACKETS] = {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000540 {RADEON_PP_MISC, 7, "RADEON_PP_MISC"},
541 {RADEON_PP_CNTL, 3, "RADEON_PP_CNTL"},
542 {RADEON_RB3D_COLORPITCH, 1, "RADEON_RB3D_COLORPITCH"},
543 {RADEON_RE_LINE_PATTERN, 2, "RADEON_RE_LINE_PATTERN"},
544 {RADEON_SE_LINE_WIDTH, 1, "RADEON_SE_LINE_WIDTH"},
545 {RADEON_PP_LUM_MATRIX, 1, "RADEON_PP_LUM_MATRIX"},
546 {RADEON_PP_ROT_MATRIX_0, 2, "RADEON_PP_ROT_MATRIX_0"},
547 {RADEON_RB3D_STENCILREFMASK, 3, "RADEON_RB3D_STENCILREFMASK"},
548 {RADEON_SE_VPORT_XSCALE, 6, "RADEON_SE_VPORT_XSCALE"},
549 {RADEON_SE_CNTL, 2, "RADEON_SE_CNTL"},
550 {RADEON_SE_CNTL_STATUS, 1, "RADEON_SE_CNTL_STATUS"},
551 {RADEON_RE_MISC, 1, "RADEON_RE_MISC"},
552 {RADEON_PP_TXFILTER_0, 6, "RADEON_PP_TXFILTER_0"},
553 {RADEON_PP_BORDER_COLOR_0, 1, "RADEON_PP_BORDER_COLOR_0"},
554 {RADEON_PP_TXFILTER_1, 6, "RADEON_PP_TXFILTER_1"},
555 {RADEON_PP_BORDER_COLOR_1, 1, "RADEON_PP_BORDER_COLOR_1"},
556 {RADEON_PP_TXFILTER_2, 6, "RADEON_PP_TXFILTER_2"},
557 {RADEON_PP_BORDER_COLOR_2, 1, "RADEON_PP_BORDER_COLOR_2"},
558 {RADEON_SE_ZBIAS_FACTOR, 2, "RADEON_SE_ZBIAS_FACTOR"},
559 {RADEON_SE_TCL_OUTPUT_VTX_FMT, 11, "RADEON_SE_TCL_OUTPUT_VTX_FMT"},
560 {RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED, 17,
561 "RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED"},
562 {R200_PP_TXCBLEND_0, 4, "R200_PP_TXCBLEND_0"},
563 {R200_PP_TXCBLEND_1, 4, "R200_PP_TXCBLEND_1"},
564 {R200_PP_TXCBLEND_2, 4, "R200_PP_TXCBLEND_2"},
565 {R200_PP_TXCBLEND_3, 4, "R200_PP_TXCBLEND_3"},
566 {R200_PP_TXCBLEND_4, 4, "R200_PP_TXCBLEND_4"},
567 {R200_PP_TXCBLEND_5, 4, "R200_PP_TXCBLEND_5"},
568 {R200_PP_TXCBLEND_6, 4, "R200_PP_TXCBLEND_6"},
569 {R200_PP_TXCBLEND_7, 4, "R200_PP_TXCBLEND_7"},
570 {R200_SE_TCL_LIGHT_MODEL_CTL_0, 6, "R200_SE_TCL_LIGHT_MODEL_CTL_0"},
571 {R200_PP_TFACTOR_0, 6, "R200_PP_TFACTOR_0"},
572 {R200_SE_VTX_FMT_0, 4, "R200_SE_VTX_FMT_0"},
573 {R200_SE_VAP_CNTL, 1, "R200_SE_VAP_CNTL"},
574 {R200_SE_TCL_MATRIX_SEL_0, 5, "R200_SE_TCL_MATRIX_SEL_0"},
575 {R200_SE_TCL_TEX_PROC_CTL_2, 5, "R200_SE_TCL_TEX_PROC_CTL_2"},
576 {R200_SE_TCL_UCP_VERT_BLEND_CTL, 1, "R200_SE_TCL_UCP_VERT_BLEND_CTL"},
577 {R200_PP_TXFILTER_0, 6, "R200_PP_TXFILTER_0"},
578 {R200_PP_TXFILTER_1, 6, "R200_PP_TXFILTER_1"},
579 {R200_PP_TXFILTER_2, 6, "R200_PP_TXFILTER_2"},
580 {R200_PP_TXFILTER_3, 6, "R200_PP_TXFILTER_3"},
581 {R200_PP_TXFILTER_4, 6, "R200_PP_TXFILTER_4"},
582 {R200_PP_TXFILTER_5, 6, "R200_PP_TXFILTER_5"},
583 {R200_PP_TXOFFSET_0, 1, "R200_PP_TXOFFSET_0"},
584 {R200_PP_TXOFFSET_1, 1, "R200_PP_TXOFFSET_1"},
585 {R200_PP_TXOFFSET_2, 1, "R200_PP_TXOFFSET_2"},
586 {R200_PP_TXOFFSET_3, 1, "R200_PP_TXOFFSET_3"},
587 {R200_PP_TXOFFSET_4, 1, "R200_PP_TXOFFSET_4"},
588 {R200_PP_TXOFFSET_5, 1, "R200_PP_TXOFFSET_5"},
589 {R200_SE_VTE_CNTL, 1, "R200_SE_VTE_CNTL"},
Dave Airlied985c102006-01-02 21:32:48 +1100590 {R200_SE_TCL_OUTPUT_VTX_COMP_SEL, 1,
591 "R200_SE_TCL_OUTPUT_VTX_COMP_SEL"},
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000592 {R200_PP_TAM_DEBUG3, 1, "R200_PP_TAM_DEBUG3"},
593 {R200_PP_CNTL_X, 1, "R200_PP_CNTL_X"},
594 {R200_RB3D_DEPTHXY_OFFSET, 1, "R200_RB3D_DEPTHXY_OFFSET"},
595 {R200_RE_AUX_SCISSOR_CNTL, 1, "R200_RE_AUX_SCISSOR_CNTL"},
596 {R200_RE_SCISSOR_TL_0, 2, "R200_RE_SCISSOR_TL_0"},
597 {R200_RE_SCISSOR_TL_1, 2, "R200_RE_SCISSOR_TL_1"},
598 {R200_RE_SCISSOR_TL_2, 2, "R200_RE_SCISSOR_TL_2"},
599 {R200_SE_VAP_CNTL_STATUS, 1, "R200_SE_VAP_CNTL_STATUS"},
600 {R200_SE_VTX_STATE_CNTL, 1, "R200_SE_VTX_STATE_CNTL"},
601 {R200_RE_POINTSIZE, 1, "R200_RE_POINTSIZE"},
602 {R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0, 4,
603 "R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0"},
604 {R200_PP_CUBIC_FACES_0, 1, "R200_PP_CUBIC_FACES_0"}, /* 61 */
Dave Airlied985c102006-01-02 21:32:48 +1100605 {R200_PP_CUBIC_OFFSET_F1_0, 5, "R200_PP_CUBIC_OFFSET_F1_0"}, /* 62 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000606 {R200_PP_CUBIC_FACES_1, 1, "R200_PP_CUBIC_FACES_1"},
607 {R200_PP_CUBIC_OFFSET_F1_1, 5, "R200_PP_CUBIC_OFFSET_F1_1"},
608 {R200_PP_CUBIC_FACES_2, 1, "R200_PP_CUBIC_FACES_2"},
609 {R200_PP_CUBIC_OFFSET_F1_2, 5, "R200_PP_CUBIC_OFFSET_F1_2"},
610 {R200_PP_CUBIC_FACES_3, 1, "R200_PP_CUBIC_FACES_3"},
611 {R200_PP_CUBIC_OFFSET_F1_3, 5, "R200_PP_CUBIC_OFFSET_F1_3"},
612 {R200_PP_CUBIC_FACES_4, 1, "R200_PP_CUBIC_FACES_4"},
613 {R200_PP_CUBIC_OFFSET_F1_4, 5, "R200_PP_CUBIC_OFFSET_F1_4"},
614 {R200_PP_CUBIC_FACES_5, 1, "R200_PP_CUBIC_FACES_5"},
615 {R200_PP_CUBIC_OFFSET_F1_5, 5, "R200_PP_CUBIC_OFFSET_F1_5"},
616 {RADEON_PP_TEX_SIZE_0, 2, "RADEON_PP_TEX_SIZE_0"},
617 {RADEON_PP_TEX_SIZE_1, 2, "RADEON_PP_TEX_SIZE_1"},
618 {RADEON_PP_TEX_SIZE_2, 2, "RADEON_PP_TEX_SIZE_2"},
619 {R200_RB3D_BLENDCOLOR, 3, "R200_RB3D_BLENDCOLOR"},
620 {R200_SE_TCL_POINT_SPRITE_CNTL, 1, "R200_SE_TCL_POINT_SPRITE_CNTL"},
621 {RADEON_PP_CUBIC_FACES_0, 1, "RADEON_PP_CUBIC_FACES_0"},
622 {RADEON_PP_CUBIC_OFFSET_T0_0, 5, "RADEON_PP_CUBIC_OFFSET_T0_0"},
623 {RADEON_PP_CUBIC_FACES_1, 1, "RADEON_PP_CUBIC_FACES_1"},
624 {RADEON_PP_CUBIC_OFFSET_T1_0, 5, "RADEON_PP_CUBIC_OFFSET_T1_0"},
625 {RADEON_PP_CUBIC_FACES_2, 1, "RADEON_PP_CUBIC_FACES_2"},
626 {RADEON_PP_CUBIC_OFFSET_T2_0, 5, "RADEON_PP_CUBIC_OFFSET_T2_0"},
627 {R200_PP_TRI_PERF, 2, "R200_PP_TRI_PERF"},
Dave Airlied985c102006-01-02 21:32:48 +1100628 {R200_PP_AFS_0, 32, "R200_PP_AFS_0"}, /* 85 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000629 {R200_PP_AFS_1, 32, "R200_PP_AFS_1"},
630 {R200_PP_TFACTOR_0, 8, "R200_ATF_TFACTOR"},
631 {R200_PP_TXFILTER_0, 8, "R200_PP_TXCTLALL_0"},
632 {R200_PP_TXFILTER_1, 8, "R200_PP_TXCTLALL_1"},
633 {R200_PP_TXFILTER_2, 8, "R200_PP_TXCTLALL_2"},
634 {R200_PP_TXFILTER_3, 8, "R200_PP_TXCTLALL_3"},
635 {R200_PP_TXFILTER_4, 8, "R200_PP_TXCTLALL_4"},
636 {R200_PP_TXFILTER_5, 8, "R200_PP_TXCTLALL_5"},
Dave Airlied6fece02006-06-24 17:04:07 +1000637 {R200_VAP_PVS_CNTL_1, 2, "R200_VAP_PVS_CNTL"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638};
639
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640/* ================================================================
641 * Performance monitoring functions
642 */
643
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000644static void radeon_clear_box(drm_radeon_private_t * dev_priv,
645 int x, int y, int w, int h, int r, int g, int b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646{
647 u32 color;
648 RING_LOCALS;
649
650 x += dev_priv->sarea_priv->boxes[0].x1;
651 y += dev_priv->sarea_priv->boxes[0].y1;
652
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000653 switch (dev_priv->color_fmt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 case RADEON_COLOR_FORMAT_RGB565:
655 color = (((r & 0xf8) << 8) |
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000656 ((g & 0xfc) << 3) | ((b & 0xf8) >> 3));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 break;
658 case RADEON_COLOR_FORMAT_ARGB8888:
659 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000660 color = (((0xff) << 24) | (r << 16) | (g << 8) | b);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 break;
662 }
663
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000664 BEGIN_RING(4);
665 RADEON_WAIT_UNTIL_3D_IDLE();
666 OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0));
667 OUT_RING(0xffffffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 ADVANCE_RING();
669
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000670 BEGIN_RING(6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000672 OUT_RING(CP_PACKET3(RADEON_CNTL_PAINT_MULTI, 4));
673 OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
674 RADEON_GMC_BRUSH_SOLID_COLOR |
675 (dev_priv->color_fmt << 8) |
676 RADEON_GMC_SRC_DATATYPE_COLOR |
677 RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000679 if (dev_priv->page_flipping && dev_priv->current_page == 1) {
680 OUT_RING(dev_priv->front_pitch_offset);
681 } else {
682 OUT_RING(dev_priv->back_pitch_offset);
683 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000685 OUT_RING(color);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000687 OUT_RING((x << 16) | y);
688 OUT_RING((w << 16) | h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
690 ADVANCE_RING();
691}
692
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000693static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694{
695 /* Collapse various things into a wait flag -- trying to
696 * guess if userspase slept -- better just to have them tell us.
697 */
698 if (dev_priv->stats.last_frame_reads > 1 ||
699 dev_priv->stats.last_clear_reads > dev_priv->stats.clears) {
700 dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
701 }
702
703 if (dev_priv->stats.freelist_loops) {
704 dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
705 }
706
707 /* Purple box for page flipping
708 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000709 if (dev_priv->stats.boxes & RADEON_BOX_FLIP)
710 radeon_clear_box(dev_priv, 4, 4, 8, 8, 255, 0, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
712 /* Red box if we have to wait for idle at any point
713 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000714 if (dev_priv->stats.boxes & RADEON_BOX_WAIT_IDLE)
715 radeon_clear_box(dev_priv, 16, 4, 8, 8, 255, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716
717 /* Blue box: lost context?
718 */
719
720 /* Yellow box for texture swaps
721 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000722 if (dev_priv->stats.boxes & RADEON_BOX_TEXTURE_LOAD)
723 radeon_clear_box(dev_priv, 40, 4, 8, 8, 255, 255, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
725 /* Green box if hardware never idles (as far as we can tell)
726 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000727 if (!(dev_priv->stats.boxes & RADEON_BOX_DMA_IDLE))
728 radeon_clear_box(dev_priv, 64, 4, 8, 8, 0, 255, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000730 /* Draw bars indicating number of buffers allocated
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 * (not a great measure, easily confused)
732 */
733 if (dev_priv->stats.requested_bufs) {
734 if (dev_priv->stats.requested_bufs > 100)
735 dev_priv->stats.requested_bufs = 100;
736
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000737 radeon_clear_box(dev_priv, 4, 16,
738 dev_priv->stats.requested_bufs, 4,
739 196, 128, 128);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 }
741
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000742 memset(&dev_priv->stats, 0, sizeof(dev_priv->stats));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
744}
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000745
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746/* ================================================================
747 * CP command dispatch functions
748 */
749
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000750static void radeon_cp_dispatch_clear(drm_device_t * dev,
751 drm_radeon_clear_t * clear,
752 drm_radeon_clear_rect_t * depth_boxes)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753{
754 drm_radeon_private_t *dev_priv = dev->dev_private;
755 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
756 drm_radeon_depth_clear_t *depth_clear = &dev_priv->depth_clear;
757 int nbox = sarea_priv->nbox;
758 drm_clip_rect_t *pbox = sarea_priv->boxes;
759 unsigned int flags = clear->flags;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000760 u32 rb3d_cntl = 0, rb3d_stencilrefmask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 int i;
762 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000763 DRM_DEBUG("flags = 0x%x\n", flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764
765 dev_priv->stats.clears++;
766
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000767 if (dev_priv->page_flipping && dev_priv->current_page == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 unsigned int tmp = flags;
769
770 flags &= ~(RADEON_FRONT | RADEON_BACK);
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000771 if (tmp & RADEON_FRONT)
772 flags |= RADEON_BACK;
773 if (tmp & RADEON_BACK)
774 flags |= RADEON_FRONT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 }
776
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000777 if (flags & (RADEON_FRONT | RADEON_BACK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000779 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
781 /* Ensure the 3D stream is idle before doing a
782 * 2D fill to clear the front or back buffer.
783 */
784 RADEON_WAIT_UNTIL_3D_IDLE();
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000785
786 OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0));
787 OUT_RING(clear->color_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
789 ADVANCE_RING();
790
791 /* Make sure we restore the 3D state next time.
792 */
793 dev_priv->sarea_priv->ctx_owner = 0;
794
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000795 for (i = 0; i < nbox; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 int x = pbox[i].x1;
797 int y = pbox[i].y1;
798 int w = pbox[i].x2 - x;
799 int h = pbox[i].y2 - y;
800
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000801 DRM_DEBUG("dispatch clear %d,%d-%d,%d flags 0x%x\n",
802 x, y, w, h, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000804 if (flags & RADEON_FRONT) {
805 BEGIN_RING(6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000807 OUT_RING(CP_PACKET3
808 (RADEON_CNTL_PAINT_MULTI, 4));
809 OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
810 RADEON_GMC_BRUSH_SOLID_COLOR |
811 (dev_priv->
812 color_fmt << 8) |
813 RADEON_GMC_SRC_DATATYPE_COLOR |
814 RADEON_ROP3_P |
815 RADEON_GMC_CLR_CMP_CNTL_DIS);
816
817 OUT_RING(dev_priv->front_pitch_offset);
818 OUT_RING(clear->clear_color);
819
820 OUT_RING((x << 16) | y);
821 OUT_RING((w << 16) | h);
822
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 ADVANCE_RING();
824 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000826 if (flags & RADEON_BACK) {
827 BEGIN_RING(6);
828
829 OUT_RING(CP_PACKET3
830 (RADEON_CNTL_PAINT_MULTI, 4));
831 OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
832 RADEON_GMC_BRUSH_SOLID_COLOR |
833 (dev_priv->
834 color_fmt << 8) |
835 RADEON_GMC_SRC_DATATYPE_COLOR |
836 RADEON_ROP3_P |
837 RADEON_GMC_CLR_CMP_CNTL_DIS);
838
839 OUT_RING(dev_priv->back_pitch_offset);
840 OUT_RING(clear->clear_color);
841
842 OUT_RING((x << 16) | y);
843 OUT_RING((w << 16) | h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
845 ADVANCE_RING();
846 }
847 }
848 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000849
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 /* hyper z clear */
851 /* no docs available, based on reverse engeneering by Stephane Marchesin */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000852 if ((flags & (RADEON_DEPTH | RADEON_STENCIL))
853 && (flags & RADEON_CLEAR_FASTZ)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854
855 int i;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000856 int depthpixperline =
857 dev_priv->depth_fmt ==
858 RADEON_DEPTH_FORMAT_16BIT_INT_Z ? (dev_priv->depth_pitch /
859 2) : (dev_priv->
860 depth_pitch / 4);
861
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 u32 clearmask;
863
864 u32 tempRB3D_DEPTHCLEARVALUE = clear->clear_depth |
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000865 ((clear->depth_mask & 0xff) << 24);
866
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 /* Make sure we restore the 3D state next time.
868 * we haven't touched any "normal" state - still need this?
869 */
870 dev_priv->sarea_priv->ctx_owner = 0;
871
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000872 if ((dev_priv->flags & CHIP_HAS_HIERZ)
873 && (flags & RADEON_USE_HIERZ)) {
874 /* FIXME : reverse engineer that for Rx00 cards */
875 /* FIXME : the mask supposedly contains low-res z values. So can't set
876 just to the max (0xff? or actually 0x3fff?), need to take z clear
877 value into account? */
878 /* pattern seems to work for r100, though get slight
879 rendering errors with glxgears. If hierz is not enabled for r100,
880 only 4 bits which indicate clear (15,16,31,32, all zero) matter, the
881 other ones are ignored, and the same clear mask can be used. That's
882 very different behaviour than R200 which needs different clear mask
883 and different number of tiles to clear if hierz is enabled or not !?!
884 */
885 clearmask = (0xff << 22) | (0xff << 6) | 0x003f003f;
886 } else {
887 /* clear mask : chooses the clearing pattern.
888 rv250: could be used to clear only parts of macrotiles
889 (but that would get really complicated...)?
890 bit 0 and 1 (either or both of them ?!?!) are used to
891 not clear tile (or maybe one of the bits indicates if the tile is
892 compressed or not), bit 2 and 3 to not clear tile 1,...,.
893 Pattern is as follows:
894 | 0,1 | 4,5 | 8,9 |12,13|16,17|20,21|24,25|28,29|
895 bits -------------------------------------------------
896 | 2,3 | 6,7 |10,11|14,15|18,19|22,23|26,27|30,31|
897 rv100: clearmask covers 2x8 4x1 tiles, but one clear still
898 covers 256 pixels ?!?
899 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 clearmask = 0x0;
901 }
902
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000903 BEGIN_RING(8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 RADEON_WAIT_UNTIL_2D_IDLE();
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000905 OUT_RING_REG(RADEON_RB3D_DEPTHCLEARVALUE,
906 tempRB3D_DEPTHCLEARVALUE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 /* what offset is this exactly ? */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000908 OUT_RING_REG(RADEON_RB3D_ZMASKOFFSET, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 /* need ctlstat, otherwise get some strange black flickering */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000910 OUT_RING_REG(RADEON_RB3D_ZCACHE_CTLSTAT,
911 RADEON_RB3D_ZC_FLUSH_ALL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 ADVANCE_RING();
913
914 for (i = 0; i < nbox; i++) {
915 int tileoffset, nrtilesx, nrtilesy, j;
916 /* it looks like r200 needs rv-style clears, at least if hierz is not enabled? */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000917 if ((dev_priv->flags & CHIP_HAS_HIERZ)
918 && !(dev_priv->microcode_version == UCODE_R200)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 /* FIXME : figure this out for r200 (when hierz is enabled). Or
920 maybe r200 actually doesn't need to put the low-res z value into
921 the tile cache like r100, but just needs to clear the hi-level z-buffer?
922 Works for R100, both with hierz and without.
923 R100 seems to operate on 2x1 8x8 tiles, but...
924 odd: offset/nrtiles need to be 64 pix (4 block) aligned? Potentially
925 problematic with resolutions which are not 64 pix aligned? */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000926 tileoffset =
927 ((pbox[i].y1 >> 3) * depthpixperline +
928 pbox[i].x1) >> 6;
929 nrtilesx =
930 ((pbox[i].x2 & ~63) -
931 (pbox[i].x1 & ~63)) >> 4;
932 nrtilesy =
933 (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 for (j = 0; j <= nrtilesy; j++) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000935 BEGIN_RING(4);
936 OUT_RING(CP_PACKET3
937 (RADEON_3D_CLEAR_ZMASK, 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 /* first tile */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000939 OUT_RING(tileoffset * 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 /* the number of tiles to clear */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000941 OUT_RING(nrtilesx + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 /* clear mask : chooses the clearing pattern. */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000943 OUT_RING(clearmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 ADVANCE_RING();
945 tileoffset += depthpixperline >> 6;
946 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000947 } else if (dev_priv->microcode_version == UCODE_R200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 /* works for rv250. */
949 /* find first macro tile (8x2 4x4 z-pixels on rv250) */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000950 tileoffset =
951 ((pbox[i].y1 >> 3) * depthpixperline +
952 pbox[i].x1) >> 5;
953 nrtilesx =
954 (pbox[i].x2 >> 5) - (pbox[i].x1 >> 5);
955 nrtilesy =
956 (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 for (j = 0; j <= nrtilesy; j++) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000958 BEGIN_RING(4);
959 OUT_RING(CP_PACKET3
960 (RADEON_3D_CLEAR_ZMASK, 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 /* first tile */
962 /* judging by the first tile offset needed, could possibly
963 directly address/clear 4x4 tiles instead of 8x2 * 4x4
964 macro tiles, though would still need clear mask for
965 right/bottom if truely 4x4 granularity is desired ? */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000966 OUT_RING(tileoffset * 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 /* the number of tiles to clear */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000968 OUT_RING(nrtilesx + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 /* clear mask : chooses the clearing pattern. */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000970 OUT_RING(clearmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 ADVANCE_RING();
972 tileoffset += depthpixperline >> 5;
973 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000974 } else { /* rv 100 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 /* rv100 might not need 64 pix alignment, who knows */
976 /* offsets are, hmm, weird */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000977 tileoffset =
978 ((pbox[i].y1 >> 4) * depthpixperline +
979 pbox[i].x1) >> 6;
980 nrtilesx =
981 ((pbox[i].x2 & ~63) -
982 (pbox[i].x1 & ~63)) >> 4;
983 nrtilesy =
984 (pbox[i].y2 >> 4) - (pbox[i].y1 >> 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 for (j = 0; j <= nrtilesy; j++) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000986 BEGIN_RING(4);
987 OUT_RING(CP_PACKET3
988 (RADEON_3D_CLEAR_ZMASK, 2));
989 OUT_RING(tileoffset * 128);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 /* the number of tiles to clear */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000991 OUT_RING(nrtilesx + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 /* clear mask : chooses the clearing pattern. */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000993 OUT_RING(clearmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 ADVANCE_RING();
995 tileoffset += depthpixperline >> 6;
996 }
997 }
998 }
999
1000 /* TODO don't always clear all hi-level z tiles */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001001 if ((dev_priv->flags & CHIP_HAS_HIERZ)
1002 && (dev_priv->microcode_version == UCODE_R200)
1003 && (flags & RADEON_USE_HIERZ))
1004 /* r100 and cards without hierarchical z-buffer have no high-level z-buffer */
1005 /* FIXME : the mask supposedly contains low-res z values. So can't set
1006 just to the max (0xff? or actually 0x3fff?), need to take z clear
1007 value into account? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001009 BEGIN_RING(4);
1010 OUT_RING(CP_PACKET3(RADEON_3D_CLEAR_HIZ, 2));
1011 OUT_RING(0x0); /* First tile */
1012 OUT_RING(0x3cc0);
1013 OUT_RING((0xff << 22) | (0xff << 6) | 0x003f003f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 ADVANCE_RING();
1015 }
1016 }
1017
1018 /* We have to clear the depth and/or stencil buffers by
1019 * rendering a quad into just those buffers. Thus, we have to
1020 * make sure the 3D engine is configured correctly.
1021 */
Dave Airlied985c102006-01-02 21:32:48 +11001022 else if ((dev_priv->microcode_version == UCODE_R200) &&
1023 (flags & (RADEON_DEPTH | RADEON_STENCIL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024
1025 int tempPP_CNTL;
1026 int tempRE_CNTL;
1027 int tempRB3D_CNTL;
1028 int tempRB3D_ZSTENCILCNTL;
1029 int tempRB3D_STENCILREFMASK;
1030 int tempRB3D_PLANEMASK;
1031 int tempSE_CNTL;
1032 int tempSE_VTE_CNTL;
1033 int tempSE_VTX_FMT_0;
1034 int tempSE_VTX_FMT_1;
1035 int tempSE_VAP_CNTL;
1036 int tempRE_AUX_SCISSOR_CNTL;
1037
1038 tempPP_CNTL = 0;
1039 tempRE_CNTL = 0;
1040
1041 tempRB3D_CNTL = depth_clear->rb3d_cntl;
1042
1043 tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl;
1044 tempRB3D_STENCILREFMASK = 0x0;
1045
1046 tempSE_CNTL = depth_clear->se_cntl;
1047
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 /* Disable TCL */
1049
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001050 tempSE_VAP_CNTL = ( /* SE_VAP_CNTL__FORCE_W_TO_ONE_MASK | */
1051 (0x9 <<
1052 SE_VAP_CNTL__VF_MAX_VTX_NUM__SHIFT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053
1054 tempRB3D_PLANEMASK = 0x0;
1055
1056 tempRE_AUX_SCISSOR_CNTL = 0x0;
1057
1058 tempSE_VTE_CNTL =
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001059 SE_VTE_CNTL__VTX_XY_FMT_MASK | SE_VTE_CNTL__VTX_Z_FMT_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001061 /* Vertex format (X, Y, Z, W) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 tempSE_VTX_FMT_0 =
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001063 SE_VTX_FMT_0__VTX_Z0_PRESENT_MASK |
1064 SE_VTX_FMT_0__VTX_W0_PRESENT_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 tempSE_VTX_FMT_1 = 0x0;
1066
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001067 /*
1068 * Depth buffer specific enables
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 */
1070 if (flags & RADEON_DEPTH) {
1071 /* Enable depth buffer */
1072 tempRB3D_CNTL |= RADEON_Z_ENABLE;
1073 } else {
1074 /* Disable depth buffer */
1075 tempRB3D_CNTL &= ~RADEON_Z_ENABLE;
1076 }
1077
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001078 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 * Stencil buffer specific enables
1080 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001081 if (flags & RADEON_STENCIL) {
1082 tempRB3D_CNTL |= RADEON_STENCIL_ENABLE;
1083 tempRB3D_STENCILREFMASK = clear->depth_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 } else {
1085 tempRB3D_CNTL &= ~RADEON_STENCIL_ENABLE;
1086 tempRB3D_STENCILREFMASK = 0x00000000;
1087 }
1088
1089 if (flags & RADEON_USE_COMP_ZBUF) {
1090 tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE |
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001091 RADEON_Z_DECOMPRESSION_ENABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 }
1093 if (flags & RADEON_USE_HIERZ) {
1094 tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE;
1095 }
1096
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001097 BEGIN_RING(26);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 RADEON_WAIT_UNTIL_2D_IDLE();
1099
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001100 OUT_RING_REG(RADEON_PP_CNTL, tempPP_CNTL);
1101 OUT_RING_REG(R200_RE_CNTL, tempRE_CNTL);
1102 OUT_RING_REG(RADEON_RB3D_CNTL, tempRB3D_CNTL);
1103 OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL);
1104 OUT_RING_REG(RADEON_RB3D_STENCILREFMASK,
1105 tempRB3D_STENCILREFMASK);
1106 OUT_RING_REG(RADEON_RB3D_PLANEMASK, tempRB3D_PLANEMASK);
1107 OUT_RING_REG(RADEON_SE_CNTL, tempSE_CNTL);
1108 OUT_RING_REG(R200_SE_VTE_CNTL, tempSE_VTE_CNTL);
1109 OUT_RING_REG(R200_SE_VTX_FMT_0, tempSE_VTX_FMT_0);
1110 OUT_RING_REG(R200_SE_VTX_FMT_1, tempSE_VTX_FMT_1);
1111 OUT_RING_REG(R200_SE_VAP_CNTL, tempSE_VAP_CNTL);
1112 OUT_RING_REG(R200_RE_AUX_SCISSOR_CNTL, tempRE_AUX_SCISSOR_CNTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 ADVANCE_RING();
1114
1115 /* Make sure we restore the 3D state next time.
1116 */
1117 dev_priv->sarea_priv->ctx_owner = 0;
1118
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001119 for (i = 0; i < nbox; i++) {
1120
1121 /* Funny that this should be required --
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 * sets top-left?
1123 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001124 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001126 BEGIN_RING(14);
1127 OUT_RING(CP_PACKET3(R200_3D_DRAW_IMMD_2, 12));
1128 OUT_RING((RADEON_PRIM_TYPE_RECT_LIST |
1129 RADEON_PRIM_WALK_RING |
1130 (3 << RADEON_NUM_VERTICES_SHIFT)));
1131 OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1132 OUT_RING(depth_boxes[i].ui[CLEAR_Y1]);
1133 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1134 OUT_RING(0x3f800000);
1135 OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1136 OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1137 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1138 OUT_RING(0x3f800000);
1139 OUT_RING(depth_boxes[i].ui[CLEAR_X2]);
1140 OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1141 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1142 OUT_RING(0x3f800000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 ADVANCE_RING();
1144 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001145 } else if ((flags & (RADEON_DEPTH | RADEON_STENCIL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
1147 int tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl;
1148
1149 rb3d_cntl = depth_clear->rb3d_cntl;
1150
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001151 if (flags & RADEON_DEPTH) {
1152 rb3d_cntl |= RADEON_Z_ENABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 } else {
1154 rb3d_cntl &= ~RADEON_Z_ENABLE;
1155 }
1156
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001157 if (flags & RADEON_STENCIL) {
1158 rb3d_cntl |= RADEON_STENCIL_ENABLE;
1159 rb3d_stencilrefmask = clear->depth_mask; /* misnamed field */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 } else {
1161 rb3d_cntl &= ~RADEON_STENCIL_ENABLE;
1162 rb3d_stencilrefmask = 0x00000000;
1163 }
1164
1165 if (flags & RADEON_USE_COMP_ZBUF) {
1166 tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE |
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001167 RADEON_Z_DECOMPRESSION_ENABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 }
1169 if (flags & RADEON_USE_HIERZ) {
1170 tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE;
1171 }
1172
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001173 BEGIN_RING(13);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 RADEON_WAIT_UNTIL_2D_IDLE();
1175
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001176 OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 1));
1177 OUT_RING(0x00000000);
1178 OUT_RING(rb3d_cntl);
1179
1180 OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL);
1181 OUT_RING_REG(RADEON_RB3D_STENCILREFMASK, rb3d_stencilrefmask);
1182 OUT_RING_REG(RADEON_RB3D_PLANEMASK, 0x00000000);
1183 OUT_RING_REG(RADEON_SE_CNTL, depth_clear->se_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 ADVANCE_RING();
1185
1186 /* Make sure we restore the 3D state next time.
1187 */
1188 dev_priv->sarea_priv->ctx_owner = 0;
1189
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001190 for (i = 0; i < nbox; i++) {
1191
1192 /* Funny that this should be required --
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 * sets top-left?
1194 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001195 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001197 BEGIN_RING(15);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001199 OUT_RING(CP_PACKET3(RADEON_3D_DRAW_IMMD, 13));
1200 OUT_RING(RADEON_VTX_Z_PRESENT |
1201 RADEON_VTX_PKCOLOR_PRESENT);
1202 OUT_RING((RADEON_PRIM_TYPE_RECT_LIST |
1203 RADEON_PRIM_WALK_RING |
1204 RADEON_MAOS_ENABLE |
1205 RADEON_VTX_FMT_RADEON_MODE |
1206 (3 << RADEON_NUM_VERTICES_SHIFT)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001208 OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1209 OUT_RING(depth_boxes[i].ui[CLEAR_Y1]);
1210 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1211 OUT_RING(0x0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001213 OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1214 OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1215 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1216 OUT_RING(0x0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001218 OUT_RING(depth_boxes[i].ui[CLEAR_X2]);
1219 OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1220 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1221 OUT_RING(0x0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222
1223 ADVANCE_RING();
1224 }
1225 }
1226
1227 /* Increment the clear counter. The client-side 3D driver must
1228 * wait on this value before performing the clear ioctl. We
1229 * need this because the card's so damned fast...
1230 */
1231 dev_priv->sarea_priv->last_clear++;
1232
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001233 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001235 RADEON_CLEAR_AGE(dev_priv->sarea_priv->last_clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 RADEON_WAIT_UNTIL_IDLE();
1237
1238 ADVANCE_RING();
1239}
1240
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001241static void radeon_cp_dispatch_swap(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242{
1243 drm_radeon_private_t *dev_priv = dev->dev_private;
1244 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
1245 int nbox = sarea_priv->nbox;
1246 drm_clip_rect_t *pbox = sarea_priv->boxes;
1247 int i;
1248 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001249 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250
1251 /* Do some trivial performance monitoring...
1252 */
1253 if (dev_priv->do_boxes)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001254 radeon_cp_performance_boxes(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255
1256 /* Wait for the 3D stream to idle before dispatching the bitblt.
1257 * This will prevent data corruption between the two streams.
1258 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001259 BEGIN_RING(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260
1261 RADEON_WAIT_UNTIL_3D_IDLE();
1262
1263 ADVANCE_RING();
1264
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001265 for (i = 0; i < nbox; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 int x = pbox[i].x1;
1267 int y = pbox[i].y1;
1268 int w = pbox[i].x2 - x;
1269 int h = pbox[i].y2 - y;
1270
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001271 DRM_DEBUG("dispatch swap %d,%d-%d,%d\n", x, y, w, h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001273 BEGIN_RING(7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001275 OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
1276 OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
1277 RADEON_GMC_DST_PITCH_OFFSET_CNTL |
1278 RADEON_GMC_BRUSH_NONE |
1279 (dev_priv->color_fmt << 8) |
1280 RADEON_GMC_SRC_DATATYPE_COLOR |
1281 RADEON_ROP3_S |
1282 RADEON_DP_SRC_SOURCE_MEMORY |
1283 RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
1284
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 /* Make this work even if front & back are flipped:
1286 */
1287 if (dev_priv->current_page == 0) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001288 OUT_RING(dev_priv->back_pitch_offset);
1289 OUT_RING(dev_priv->front_pitch_offset);
1290 } else {
1291 OUT_RING(dev_priv->front_pitch_offset);
1292 OUT_RING(dev_priv->back_pitch_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 }
1294
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001295 OUT_RING((x << 16) | y);
1296 OUT_RING((x << 16) | y);
1297 OUT_RING((w << 16) | h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
1299 ADVANCE_RING();
1300 }
1301
1302 /* Increment the frame counter. The client-side 3D driver must
1303 * throttle the framerate by waiting for this value before
1304 * performing the swapbuffer ioctl.
1305 */
1306 dev_priv->sarea_priv->last_frame++;
1307
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001308 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001310 RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 RADEON_WAIT_UNTIL_2D_IDLE();
1312
1313 ADVANCE_RING();
1314}
1315
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001316static void radeon_cp_dispatch_flip(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317{
1318 drm_radeon_private_t *dev_priv = dev->dev_private;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001319 drm_sarea_t *sarea = (drm_sarea_t *) dev_priv->sarea->handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 int offset = (dev_priv->current_page == 1)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001321 ? dev_priv->front_offset : dev_priv->back_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001323 DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
1324 __FUNCTION__,
1325 dev_priv->current_page, dev_priv->sarea_priv->pfCurrentPage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326
1327 /* Do some trivial performance monitoring...
1328 */
1329 if (dev_priv->do_boxes) {
1330 dev_priv->stats.boxes |= RADEON_BOX_FLIP;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001331 radeon_cp_performance_boxes(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 }
1333
1334 /* Update the frame offsets for both CRTCs
1335 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001336 BEGIN_RING(6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337
1338 RADEON_WAIT_UNTIL_3D_IDLE();
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001339 OUT_RING_REG(RADEON_CRTC_OFFSET,
1340 ((sarea->frame.y * dev_priv->front_pitch +
1341 sarea->frame.x * (dev_priv->color_fmt - 2)) & ~7)
1342 + offset);
1343 OUT_RING_REG(RADEON_CRTC2_OFFSET, dev_priv->sarea_priv->crtc2_base
1344 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
1346 ADVANCE_RING();
1347
1348 /* Increment the frame counter. The client-side 3D driver must
1349 * throttle the framerate by waiting for this value before
1350 * performing the swapbuffer ioctl.
1351 */
1352 dev_priv->sarea_priv->last_frame++;
1353 dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page =
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001354 1 - dev_priv->current_page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001356 BEGIN_RING(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001358 RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359
1360 ADVANCE_RING();
1361}
1362
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001363static int bad_prim_vertex_nr(int primitive, int nr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364{
1365 switch (primitive & RADEON_PRIM_TYPE_MASK) {
1366 case RADEON_PRIM_TYPE_NONE:
1367 case RADEON_PRIM_TYPE_POINT:
1368 return nr < 1;
1369 case RADEON_PRIM_TYPE_LINE:
1370 return (nr & 1) || nr == 0;
1371 case RADEON_PRIM_TYPE_LINE_STRIP:
1372 return nr < 2;
1373 case RADEON_PRIM_TYPE_TRI_LIST:
1374 case RADEON_PRIM_TYPE_3VRT_POINT_LIST:
1375 case RADEON_PRIM_TYPE_3VRT_LINE_LIST:
1376 case RADEON_PRIM_TYPE_RECT_LIST:
1377 return nr % 3 || nr == 0;
1378 case RADEON_PRIM_TYPE_TRI_FAN:
1379 case RADEON_PRIM_TYPE_TRI_STRIP:
1380 return nr < 3;
1381 default:
1382 return 1;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001383 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384}
1385
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386typedef struct {
1387 unsigned int start;
1388 unsigned int finish;
1389 unsigned int prim;
1390 unsigned int numverts;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001391 unsigned int offset;
1392 unsigned int vc_format;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393} drm_radeon_tcl_prim_t;
1394
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001395static void radeon_cp_dispatch_vertex(drm_device_t * dev,
1396 drm_buf_t * buf,
1397 drm_radeon_tcl_prim_t * prim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398{
1399 drm_radeon_private_t *dev_priv = dev->dev_private;
1400 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
1401 int offset = dev_priv->gart_buffers_offset + buf->offset + prim->start;
1402 int numverts = (int)prim->numverts;
1403 int nbox = sarea_priv->nbox;
1404 int i = 0;
1405 RING_LOCALS;
1406
1407 DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d %d verts\n",
1408 prim->prim,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001409 prim->vc_format, prim->start, prim->finish, prim->numverts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001411 if (bad_prim_vertex_nr(prim->prim, prim->numverts)) {
1412 DRM_ERROR("bad prim %x numverts %d\n",
1413 prim->prim, prim->numverts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 return;
1415 }
1416
1417 do {
1418 /* Emit the next cliprect */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001419 if (i < nbox) {
1420 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 }
1422
1423 /* Emit the vertex buffer rendering commands */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001424 BEGIN_RING(5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001426 OUT_RING(CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, 3));
1427 OUT_RING(offset);
1428 OUT_RING(numverts);
1429 OUT_RING(prim->vc_format);
1430 OUT_RING(prim->prim | RADEON_PRIM_WALK_LIST |
1431 RADEON_COLOR_ORDER_RGBA |
1432 RADEON_VTX_FMT_RADEON_MODE |
1433 (numverts << RADEON_NUM_VERTICES_SHIFT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434
1435 ADVANCE_RING();
1436
1437 i++;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001438 } while (i < nbox);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439}
1440
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001441static void radeon_cp_discard_buffer(drm_device_t * dev, drm_buf_t * buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442{
1443 drm_radeon_private_t *dev_priv = dev->dev_private;
1444 drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
1445 RING_LOCALS;
1446
1447 buf_priv->age = ++dev_priv->sarea_priv->last_dispatch;
1448
1449 /* Emit the vertex buffer age */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001450 BEGIN_RING(2);
1451 RADEON_DISPATCH_AGE(buf_priv->age);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 ADVANCE_RING();
1453
1454 buf->pending = 1;
1455 buf->used = 0;
1456}
1457
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001458static void radeon_cp_dispatch_indirect(drm_device_t * dev,
1459 drm_buf_t * buf, int start, int end)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460{
1461 drm_radeon_private_t *dev_priv = dev->dev_private;
1462 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001463 DRM_DEBUG("indirect: buf=%d s=0x%x e=0x%x\n", buf->idx, start, end);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001465 if (start != end) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 int offset = (dev_priv->gart_buffers_offset
1467 + buf->offset + start);
1468 int dwords = (end - start + 3) / sizeof(u32);
1469
1470 /* Indirect buffer data must be an even number of
1471 * dwords, so if we've been given an odd number we must
1472 * pad the data with a Type-2 CP packet.
1473 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001474 if (dwords & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 u32 *data = (u32 *)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001476 ((char *)dev->agp_buffer_map->handle
1477 + buf->offset + start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 data[dwords++] = RADEON_CP_PACKET2;
1479 }
1480
1481 /* Fire off the indirect buffer */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001482 BEGIN_RING(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001484 OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1));
1485 OUT_RING(offset);
1486 OUT_RING(dwords);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487
1488 ADVANCE_RING();
1489 }
1490}
1491
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001492static void radeon_cp_dispatch_indices(drm_device_t * dev,
1493 drm_buf_t * elt_buf,
1494 drm_radeon_tcl_prim_t * prim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495{
1496 drm_radeon_private_t *dev_priv = dev->dev_private;
1497 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
1498 int offset = dev_priv->gart_buffers_offset + prim->offset;
1499 u32 *data;
1500 int dwords;
1501 int i = 0;
1502 int start = prim->start + RADEON_INDEX_PRIM_OFFSET;
1503 int count = (prim->finish - start) / sizeof(u16);
1504 int nbox = sarea_priv->nbox;
1505
1506 DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d offset: %x nr %d\n",
1507 prim->prim,
1508 prim->vc_format,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001509 prim->start, prim->finish, prim->offset, prim->numverts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001511 if (bad_prim_vertex_nr(prim->prim, count)) {
1512 DRM_ERROR("bad prim %x count %d\n", prim->prim, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 return;
1514 }
1515
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001516 if (start >= prim->finish || (prim->start & 0x7)) {
1517 DRM_ERROR("buffer prim %d\n", prim->prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 return;
1519 }
1520
1521 dwords = (prim->finish - prim->start + 3) / sizeof(u32);
1522
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001523 data = (u32 *) ((char *)dev->agp_buffer_map->handle +
1524 elt_buf->offset + prim->start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001526 data[0] = CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, dwords - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 data[1] = offset;
1528 data[2] = prim->numverts;
1529 data[3] = prim->vc_format;
1530 data[4] = (prim->prim |
1531 RADEON_PRIM_WALK_IND |
1532 RADEON_COLOR_ORDER_RGBA |
1533 RADEON_VTX_FMT_RADEON_MODE |
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001534 (count << RADEON_NUM_VERTICES_SHIFT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535
1536 do {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001537 if (i < nbox)
1538 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001540 radeon_cp_dispatch_indirect(dev, elt_buf,
1541 prim->start, prim->finish);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542
1543 i++;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001544 } while (i < nbox);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545
1546}
1547
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001548#define RADEON_MAX_TEXTURE_SIZE RADEON_BUFFER_SIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001550static int radeon_cp_dispatch_texture(DRMFILE filp,
1551 drm_device_t * dev,
1552 drm_radeon_texture_t * tex,
1553 drm_radeon_tex_image_t * image)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554{
1555 drm_radeon_private_t *dev_priv = dev->dev_private;
1556 drm_file_t *filp_priv;
1557 drm_buf_t *buf;
1558 u32 format;
1559 u32 *buffer;
1560 const u8 __user *data;
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001561 int size, dwords, tex_width, blit_width, spitch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 u32 height;
1563 int i;
1564 u32 texpitch, microtile;
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001565 u32 offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 RING_LOCALS;
1567
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001568 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001570 if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &tex->offset)) {
1571 DRM_ERROR("Invalid destination offset\n");
1572 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 }
1574
1575 dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD;
1576
1577 /* Flush the pixel cache. This ensures no pixel data gets mixed
1578 * up with the texture data from the host data blit, otherwise
1579 * part of the texture image may be corrupted.
1580 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001581 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 RADEON_FLUSH_CACHE();
1583 RADEON_WAIT_UNTIL_IDLE();
1584 ADVANCE_RING();
1585
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 /* The compiler won't optimize away a division by a variable,
1587 * even if the only legal values are powers of two. Thus, we'll
1588 * use a shift instead.
1589 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001590 switch (tex->format) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 case RADEON_TXFORMAT_ARGB8888:
1592 case RADEON_TXFORMAT_RGBA8888:
1593 format = RADEON_COLOR_FORMAT_ARGB8888;
1594 tex_width = tex->width * 4;
1595 blit_width = image->width * 4;
1596 break;
1597 case RADEON_TXFORMAT_AI88:
1598 case RADEON_TXFORMAT_ARGB1555:
1599 case RADEON_TXFORMAT_RGB565:
1600 case RADEON_TXFORMAT_ARGB4444:
1601 case RADEON_TXFORMAT_VYUY422:
1602 case RADEON_TXFORMAT_YVYU422:
1603 format = RADEON_COLOR_FORMAT_RGB565;
1604 tex_width = tex->width * 2;
1605 blit_width = image->width * 2;
1606 break;
1607 case RADEON_TXFORMAT_I8:
1608 case RADEON_TXFORMAT_RGB332:
1609 format = RADEON_COLOR_FORMAT_CI8;
1610 tex_width = tex->width * 1;
1611 blit_width = image->width * 1;
1612 break;
1613 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001614 DRM_ERROR("invalid texture format %d\n", tex->format);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 return DRM_ERR(EINVAL);
1616 }
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001617 spitch = blit_width >> 6;
1618 if (spitch == 0 && image->height > 1)
1619 return DRM_ERR(EINVAL);
1620
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 texpitch = tex->pitch;
1622 if ((texpitch << 22) & RADEON_DST_TILE_MICRO) {
1623 microtile = 1;
1624 if (tex_width < 64) {
1625 texpitch &= ~(RADEON_DST_TILE_MICRO >> 22);
1626 /* we got tiled coordinates, untile them */
1627 image->x *= 2;
1628 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001629 } else
1630 microtile = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001632 DRM_DEBUG("tex=%dx%d blit=%d\n", tex_width, tex->height, blit_width);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633
1634 do {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001635 DRM_DEBUG("tex: ofs=0x%x p=%d f=%d x=%hd y=%hd w=%hd h=%hd\n",
1636 tex->offset >> 10, tex->pitch, tex->format,
1637 image->x, image->y, image->width, image->height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638
1639 /* Make a copy of some parameters in case we have to
1640 * update them for a multi-pass texture blit.
1641 */
1642 height = image->height;
1643 data = (const u8 __user *)image->data;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001644
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 size = height * blit_width;
1646
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001647 if (size > RADEON_MAX_TEXTURE_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 height = RADEON_MAX_TEXTURE_SIZE / blit_width;
1649 size = height * blit_width;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001650 } else if (size < 4 && size > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 size = 4;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001652 } else if (size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 return 0;
1654 }
1655
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001656 buf = radeon_freelist_get(dev);
1657 if (0 && !buf) {
1658 radeon_do_cp_idle(dev_priv);
1659 buf = radeon_freelist_get(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001661 if (!buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 DRM_DEBUG("radeon_cp_dispatch_texture: EAGAIN\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001663 if (DRM_COPY_TO_USER(tex->image, image, sizeof(*image)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 return DRM_ERR(EFAULT);
1665 return DRM_ERR(EAGAIN);
1666 }
1667
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 /* Dispatch the indirect buffer.
1669 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001670 buffer =
1671 (u32 *) ((char *)dev->agp_buffer_map->handle + buf->offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 dwords = size / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673
Dave Airlied985c102006-01-02 21:32:48 +11001674#define RADEON_COPY_MT(_buf, _data, _width) \
1675 do { \
1676 if (DRM_COPY_FROM_USER(_buf, _data, (_width))) {\
1677 DRM_ERROR("EFAULT on pad, %d bytes\n", (_width)); \
1678 return DRM_ERR(EFAULT); \
1679 } \
1680 } while(0)
1681
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 if (microtile) {
1683 /* texture micro tiling in use, minimum texture width is thus 16 bytes.
1684 however, we cannot use blitter directly for texture width < 64 bytes,
1685 since minimum tex pitch is 64 bytes and we need this to match
1686 the texture width, otherwise the blitter will tile it wrong.
1687 Thus, tiling manually in this case. Additionally, need to special
1688 case tex height = 1, since our actual image will have height 2
1689 and we need to ensure we don't read beyond the texture size
1690 from user space. */
1691 if (tex->height == 1) {
1692 if (tex_width >= 64 || tex_width <= 16) {
Dave Airlied985c102006-01-02 21:32:48 +11001693 RADEON_COPY_MT(buffer, data,
Dave Airlief8e0f292006-01-10 19:56:17 +11001694 (int)(tex_width * sizeof(u32)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 } else if (tex_width == 32) {
Dave Airlied985c102006-01-02 21:32:48 +11001696 RADEON_COPY_MT(buffer, data, 16);
1697 RADEON_COPY_MT(buffer + 8,
1698 data + 16, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 }
1700 } else if (tex_width >= 64 || tex_width == 16) {
Dave Airlied985c102006-01-02 21:32:48 +11001701 RADEON_COPY_MT(buffer, data,
Dave Airlief8e0f292006-01-10 19:56:17 +11001702 (int)(dwords * sizeof(u32)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 } else if (tex_width < 16) {
1704 for (i = 0; i < tex->height; i++) {
Dave Airlied985c102006-01-02 21:32:48 +11001705 RADEON_COPY_MT(buffer, data, tex_width);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 buffer += 4;
1707 data += tex_width;
1708 }
1709 } else if (tex_width == 32) {
1710 /* TODO: make sure this works when not fitting in one buffer
1711 (i.e. 32bytes x 2048...) */
1712 for (i = 0; i < tex->height; i += 2) {
Dave Airlied985c102006-01-02 21:32:48 +11001713 RADEON_COPY_MT(buffer, data, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 data += 16;
Dave Airlied985c102006-01-02 21:32:48 +11001715 RADEON_COPY_MT(buffer + 8, data, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 data += 16;
Dave Airlied985c102006-01-02 21:32:48 +11001717 RADEON_COPY_MT(buffer + 4, data, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 data += 16;
Dave Airlied985c102006-01-02 21:32:48 +11001719 RADEON_COPY_MT(buffer + 12, data, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 data += 16;
1721 buffer += 16;
1722 }
1723 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001724 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 if (tex_width >= 32) {
1726 /* Texture image width is larger than the minimum, so we
1727 * can upload it directly.
1728 */
Dave Airlied985c102006-01-02 21:32:48 +11001729 RADEON_COPY_MT(buffer, data,
Dave Airlief8e0f292006-01-10 19:56:17 +11001730 (int)(dwords * sizeof(u32)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 } else {
1732 /* Texture image width is less than the minimum, so we
1733 * need to pad out each image scanline to the minimum
1734 * width.
1735 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001736 for (i = 0; i < tex->height; i++) {
Dave Airlied985c102006-01-02 21:32:48 +11001737 RADEON_COPY_MT(buffer, data, tex_width);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 buffer += 8;
1739 data += tex_width;
1740 }
1741 }
1742 }
1743
Dave Airlied985c102006-01-02 21:32:48 +11001744#undef RADEON_COPY_MT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 buf->filp = filp;
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001746 buf->used = size;
1747 offset = dev_priv->gart_buffers_offset + buf->offset;
1748 BEGIN_RING(9);
1749 OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
1750 OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
1751 RADEON_GMC_DST_PITCH_OFFSET_CNTL |
1752 RADEON_GMC_BRUSH_NONE |
1753 (format << 8) |
1754 RADEON_GMC_SRC_DATATYPE_COLOR |
1755 RADEON_ROP3_S |
1756 RADEON_DP_SRC_SOURCE_MEMORY |
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001757 RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001758 OUT_RING((spitch << 22) | (offset >> 10));
1759 OUT_RING((texpitch << 22) | (tex->offset >> 10));
1760 OUT_RING(0);
1761 OUT_RING((image->x << 16) | image->y);
1762 OUT_RING((image->width << 16) | height);
1763 RADEON_WAIT_UNTIL_2D_IDLE();
1764 ADVANCE_RING();
1765
1766 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767
1768 /* Update the input parameters for next time */
1769 image->y += height;
1770 image->height -= height;
1771 image->data = (const u8 __user *)image->data + size;
1772 } while (image->height > 0);
1773
1774 /* Flush the pixel cache after the blit completes. This ensures
1775 * the texture data is written out to memory before rendering
1776 * continues.
1777 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001778 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779 RADEON_FLUSH_CACHE();
1780 RADEON_WAIT_UNTIL_2D_IDLE();
1781 ADVANCE_RING();
1782 return 0;
1783}
1784
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001785static void radeon_cp_dispatch_stipple(drm_device_t * dev, u32 * stipple)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786{
1787 drm_radeon_private_t *dev_priv = dev->dev_private;
1788 int i;
1789 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001790 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001792 BEGIN_RING(35);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001794 OUT_RING(CP_PACKET0(RADEON_RE_STIPPLE_ADDR, 0));
1795 OUT_RING(0x00000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001797 OUT_RING(CP_PACKET0_TABLE(RADEON_RE_STIPPLE_DATA, 31));
1798 for (i = 0; i < 32; i++) {
1799 OUT_RING(stipple[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 }
1801
1802 ADVANCE_RING();
1803}
1804
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001805static void radeon_apply_surface_regs(int surf_index,
Dave Airlied985c102006-01-02 21:32:48 +11001806 drm_radeon_private_t *dev_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807{
1808 if (!dev_priv->mmio)
1809 return;
1810
1811 radeon_do_cp_idle(dev_priv);
1812
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001813 RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * surf_index,
1814 dev_priv->surfaces[surf_index].flags);
1815 RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND + 16 * surf_index,
1816 dev_priv->surfaces[surf_index].lower);
1817 RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND + 16 * surf_index,
1818 dev_priv->surfaces[surf_index].upper);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819}
1820
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821/* Allocates a virtual surface
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001822 * doesn't always allocate a real surface, will stretch an existing
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 * surface when possible.
1824 *
1825 * Note that refcount can be at most 2, since during a free refcount=3
1826 * might mean we have to allocate a new surface which might not always
1827 * be available.
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001828 * For example : we allocate three contigous surfaces ABC. If B is
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 * freed, we suddenly need two surfaces to store A and C, which might
1830 * not always be available.
1831 */
Dave Airlied985c102006-01-02 21:32:48 +11001832static int alloc_surface(drm_radeon_surface_alloc_t *new,
1833 drm_radeon_private_t *dev_priv, DRMFILE filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834{
1835 struct radeon_virt_surface *s;
1836 int i;
1837 int virt_surface_index;
1838 uint32_t new_upper, new_lower;
1839
1840 new_lower = new->address;
1841 new_upper = new_lower + new->size - 1;
1842
1843 /* sanity check */
1844 if ((new_lower >= new_upper) || (new->flags == 0) || (new->size == 0) ||
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001845 ((new_upper & RADEON_SURF_ADDRESS_FIXED_MASK) !=
1846 RADEON_SURF_ADDRESS_FIXED_MASK)
1847 || ((new_lower & RADEON_SURF_ADDRESS_FIXED_MASK) != 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 return -1;
1849
1850 /* make sure there is no overlap with existing surfaces */
1851 for (i = 0; i < RADEON_MAX_SURFACES; i++) {
1852 if ((dev_priv->surfaces[i].refcount != 0) &&
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001853 (((new_lower >= dev_priv->surfaces[i].lower) &&
1854 (new_lower < dev_priv->surfaces[i].upper)) ||
1855 ((new_lower < dev_priv->surfaces[i].lower) &&
1856 (new_upper > dev_priv->surfaces[i].lower)))) {
1857 return -1;
1858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 }
1860
1861 /* find a virtual surface */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001862 for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 if (dev_priv->virt_surfaces[i].filp == 0)
1864 break;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001865 if (i == 2 * RADEON_MAX_SURFACES) {
1866 return -1;
1867 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 virt_surface_index = i;
1869
1870 /* try to reuse an existing surface */
1871 for (i = 0; i < RADEON_MAX_SURFACES; i++) {
1872 /* extend before */
1873 if ((dev_priv->surfaces[i].refcount == 1) &&
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001874 (new->flags == dev_priv->surfaces[i].flags) &&
1875 (new_upper + 1 == dev_priv->surfaces[i].lower)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 s = &(dev_priv->virt_surfaces[virt_surface_index]);
1877 s->surface_index = i;
1878 s->lower = new_lower;
1879 s->upper = new_upper;
1880 s->flags = new->flags;
1881 s->filp = filp;
1882 dev_priv->surfaces[i].refcount++;
1883 dev_priv->surfaces[i].lower = s->lower;
1884 radeon_apply_surface_regs(s->surface_index, dev_priv);
1885 return virt_surface_index;
1886 }
1887
1888 /* extend after */
1889 if ((dev_priv->surfaces[i].refcount == 1) &&
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001890 (new->flags == dev_priv->surfaces[i].flags) &&
1891 (new_lower == dev_priv->surfaces[i].upper + 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 s = &(dev_priv->virt_surfaces[virt_surface_index]);
1893 s->surface_index = i;
1894 s->lower = new_lower;
1895 s->upper = new_upper;
1896 s->flags = new->flags;
1897 s->filp = filp;
1898 dev_priv->surfaces[i].refcount++;
1899 dev_priv->surfaces[i].upper = s->upper;
1900 radeon_apply_surface_regs(s->surface_index, dev_priv);
1901 return virt_surface_index;
1902 }
1903 }
1904
1905 /* okay, we need a new one */
1906 for (i = 0; i < RADEON_MAX_SURFACES; i++) {
1907 if (dev_priv->surfaces[i].refcount == 0) {
1908 s = &(dev_priv->virt_surfaces[virt_surface_index]);
1909 s->surface_index = i;
1910 s->lower = new_lower;
1911 s->upper = new_upper;
1912 s->flags = new->flags;
1913 s->filp = filp;
1914 dev_priv->surfaces[i].refcount = 1;
1915 dev_priv->surfaces[i].lower = s->lower;
1916 dev_priv->surfaces[i].upper = s->upper;
1917 dev_priv->surfaces[i].flags = s->flags;
1918 radeon_apply_surface_regs(s->surface_index, dev_priv);
1919 return virt_surface_index;
1920 }
1921 }
1922
1923 /* we didn't find anything */
1924 return -1;
1925}
1926
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001927static int free_surface(DRMFILE filp, drm_radeon_private_t * dev_priv,
1928 int lower)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929{
1930 struct radeon_virt_surface *s;
1931 int i;
1932 /* find the virtual surface */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001933 for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934 s = &(dev_priv->virt_surfaces[i]);
1935 if (s->filp) {
1936 if ((lower == s->lower) && (filp == s->filp)) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001937 if (dev_priv->surfaces[s->surface_index].
1938 lower == s->lower)
1939 dev_priv->surfaces[s->surface_index].
1940 lower = s->upper;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001942 if (dev_priv->surfaces[s->surface_index].
1943 upper == s->upper)
1944 dev_priv->surfaces[s->surface_index].
1945 upper = s->lower;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946
1947 dev_priv->surfaces[s->surface_index].refcount--;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001948 if (dev_priv->surfaces[s->surface_index].
1949 refcount == 0)
1950 dev_priv->surfaces[s->surface_index].
1951 flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 s->filp = NULL;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001953 radeon_apply_surface_regs(s->surface_index,
1954 dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 return 0;
1956 }
1957 }
1958 }
1959 return 1;
1960}
1961
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001962static void radeon_surfaces_release(DRMFILE filp,
1963 drm_radeon_private_t * dev_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964{
1965 int i;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001966 for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 if (dev_priv->virt_surfaces[i].filp == filp)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001968 free_surface(filp, dev_priv,
1969 dev_priv->virt_surfaces[i].lower);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 }
1971}
1972
1973/* ================================================================
1974 * IOCTL functions
1975 */
1976static int radeon_surface_alloc(DRM_IOCTL_ARGS)
1977{
1978 DRM_DEVICE;
1979 drm_radeon_private_t *dev_priv = dev->dev_private;
1980 drm_radeon_surface_alloc_t alloc;
1981
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001982 DRM_COPY_FROM_USER_IOCTL(alloc,
1983 (drm_radeon_surface_alloc_t __user *) data,
1984 sizeof(alloc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985
1986 if (alloc_surface(&alloc, dev_priv, filp) == -1)
1987 return DRM_ERR(EINVAL);
1988 else
1989 return 0;
1990}
1991
1992static int radeon_surface_free(DRM_IOCTL_ARGS)
1993{
1994 DRM_DEVICE;
1995 drm_radeon_private_t *dev_priv = dev->dev_private;
1996 drm_radeon_surface_free_t memfree;
1997
Dave Airlief15e92d2006-03-19 20:12:23 +11001998 DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_surface_free_t __user *) data,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001999 sizeof(memfree));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000
2001 if (free_surface(filp, dev_priv, memfree.address))
2002 return DRM_ERR(EINVAL);
2003 else
2004 return 0;
2005}
2006
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002007static int radeon_cp_clear(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008{
2009 DRM_DEVICE;
2010 drm_radeon_private_t *dev_priv = dev->dev_private;
2011 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2012 drm_radeon_clear_t clear;
2013 drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002014 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002016 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002018 DRM_COPY_FROM_USER_IOCTL(clear, (drm_radeon_clear_t __user *) data,
2019 sizeof(clear));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002021 RING_SPACE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002023 if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
2025
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002026 if (DRM_COPY_FROM_USER(&depth_boxes, clear.depth_boxes,
2027 sarea_priv->nbox * sizeof(depth_boxes[0])))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 return DRM_ERR(EFAULT);
2029
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002030 radeon_cp_dispatch_clear(dev, &clear, depth_boxes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031
2032 COMMIT_RING();
2033 return 0;
2034}
2035
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036/* Not sure why this isn't set all the time:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002037 */
2038static int radeon_do_init_pageflip(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039{
2040 drm_radeon_private_t *dev_priv = dev->dev_private;
2041 RING_LOCALS;
2042
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002043 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002045 BEGIN_RING(6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 RADEON_WAIT_UNTIL_3D_IDLE();
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002047 OUT_RING(CP_PACKET0(RADEON_CRTC_OFFSET_CNTL, 0));
2048 OUT_RING(RADEON_READ(RADEON_CRTC_OFFSET_CNTL) |
2049 RADEON_CRTC_OFFSET_FLIP_CNTL);
2050 OUT_RING(CP_PACKET0(RADEON_CRTC2_OFFSET_CNTL, 0));
2051 OUT_RING(RADEON_READ(RADEON_CRTC2_OFFSET_CNTL) |
2052 RADEON_CRTC_OFFSET_FLIP_CNTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 ADVANCE_RING();
2054
2055 dev_priv->page_flipping = 1;
2056 dev_priv->current_page = 0;
2057 dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page;
2058
2059 return 0;
2060}
2061
2062/* Called whenever a client dies, from drm_release.
2063 * NOTE: Lock isn't necessarily held when this is called!
2064 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002065static int radeon_do_cleanup_pageflip(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066{
2067 drm_radeon_private_t *dev_priv = dev->dev_private;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002068 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069
2070 if (dev_priv->current_page != 0)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002071 radeon_cp_dispatch_flip(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072
2073 dev_priv->page_flipping = 0;
2074 return 0;
2075}
2076
2077/* Swapping and flipping are different operations, need different ioctls.
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002078 * They can & should be intermixed to support multiple 3d windows.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002080static int radeon_cp_flip(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081{
2082 DRM_DEVICE;
2083 drm_radeon_private_t *dev_priv = dev->dev_private;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002084 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002086 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002088 RING_SPACE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002090 if (!dev_priv->page_flipping)
2091 radeon_do_init_pageflip(dev);
2092
2093 radeon_cp_dispatch_flip(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094
2095 COMMIT_RING();
2096 return 0;
2097}
2098
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002099static int radeon_cp_swap(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100{
2101 DRM_DEVICE;
2102 drm_radeon_private_t *dev_priv = dev->dev_private;
2103 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002104 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002106 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002108 RING_SPACE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002110 if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
2112
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002113 radeon_cp_dispatch_swap(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 dev_priv->sarea_priv->ctx_owner = 0;
2115
2116 COMMIT_RING();
2117 return 0;
2118}
2119
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002120static int radeon_cp_vertex(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121{
2122 DRM_DEVICE;
2123 drm_radeon_private_t *dev_priv = dev->dev_private;
2124 drm_file_t *filp_priv;
2125 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2126 drm_device_dma_t *dma = dev->dma;
2127 drm_buf_t *buf;
2128 drm_radeon_vertex_t vertex;
2129 drm_radeon_tcl_prim_t prim;
2130
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002131 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002133 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002135 DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex_t __user *) data,
2136 sizeof(vertex));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002138 DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n",
2139 DRM_CURRENTPID, vertex.idx, vertex.count, vertex.discard);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002141 if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
2142 DRM_ERROR("buffer index %d (of %d max)\n",
2143 vertex.idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 return DRM_ERR(EINVAL);
2145 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002146 if (vertex.prim < 0 || vertex.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
2147 DRM_ERROR("buffer prim %d\n", vertex.prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 return DRM_ERR(EINVAL);
2149 }
2150
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002151 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2152 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153
2154 buf = dma->buflist[vertex.idx];
2155
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002156 if (buf->filp != filp) {
2157 DRM_ERROR("process %d using buffer owned by %p\n",
2158 DRM_CURRENTPID, buf->filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 return DRM_ERR(EINVAL);
2160 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002161 if (buf->pending) {
2162 DRM_ERROR("sending pending buffer %d\n", vertex.idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 return DRM_ERR(EINVAL);
2164 }
2165
2166 /* Build up a prim_t record:
2167 */
2168 if (vertex.count) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002169 buf->used = vertex.count; /* not used? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002171 if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
2172 if (radeon_emit_state(dev_priv, filp_priv,
2173 &sarea_priv->context_state,
2174 sarea_priv->tex_state,
2175 sarea_priv->dirty)) {
2176 DRM_ERROR("radeon_emit_state failed\n");
2177 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 }
2179
2180 sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
2181 RADEON_UPLOAD_TEX1IMAGES |
2182 RADEON_UPLOAD_TEX2IMAGES |
2183 RADEON_REQUIRE_QUIESCENCE);
2184 }
2185
2186 prim.start = 0;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002187 prim.finish = vertex.count; /* unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 prim.prim = vertex.prim;
2189 prim.numverts = vertex.count;
2190 prim.vc_format = dev_priv->sarea_priv->vc_format;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002191
2192 radeon_cp_dispatch_vertex(dev, buf, &prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 }
2194
2195 if (vertex.discard) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002196 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 }
2198
2199 COMMIT_RING();
2200 return 0;
2201}
2202
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002203static int radeon_cp_indices(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204{
2205 DRM_DEVICE;
2206 drm_radeon_private_t *dev_priv = dev->dev_private;
2207 drm_file_t *filp_priv;
2208 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2209 drm_device_dma_t *dma = dev->dma;
2210 drm_buf_t *buf;
2211 drm_radeon_indices_t elts;
2212 drm_radeon_tcl_prim_t prim;
2213 int count;
2214
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002215 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002217 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002219 DRM_COPY_FROM_USER_IOCTL(elts, (drm_radeon_indices_t __user *) data,
2220 sizeof(elts));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002222 DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n",
2223 DRM_CURRENTPID, elts.idx, elts.start, elts.end, elts.discard);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002225 if (elts.idx < 0 || elts.idx >= dma->buf_count) {
2226 DRM_ERROR("buffer index %d (of %d max)\n",
2227 elts.idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 return DRM_ERR(EINVAL);
2229 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002230 if (elts.prim < 0 || elts.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
2231 DRM_ERROR("buffer prim %d\n", elts.prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 return DRM_ERR(EINVAL);
2233 }
2234
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002235 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2236 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237
2238 buf = dma->buflist[elts.idx];
2239
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002240 if (buf->filp != filp) {
2241 DRM_ERROR("process %d using buffer owned by %p\n",
2242 DRM_CURRENTPID, buf->filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 return DRM_ERR(EINVAL);
2244 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002245 if (buf->pending) {
2246 DRM_ERROR("sending pending buffer %d\n", elts.idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 return DRM_ERR(EINVAL);
2248 }
2249
2250 count = (elts.end - elts.start) / sizeof(u16);
2251 elts.start -= RADEON_INDEX_PRIM_OFFSET;
2252
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002253 if (elts.start & 0x7) {
2254 DRM_ERROR("misaligned buffer 0x%x\n", elts.start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 return DRM_ERR(EINVAL);
2256 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002257 if (elts.start < buf->used) {
2258 DRM_ERROR("no header 0x%x - 0x%x\n", elts.start, buf->used);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 return DRM_ERR(EINVAL);
2260 }
2261
2262 buf->used = elts.end;
2263
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002264 if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
2265 if (radeon_emit_state(dev_priv, filp_priv,
2266 &sarea_priv->context_state,
2267 sarea_priv->tex_state,
2268 sarea_priv->dirty)) {
2269 DRM_ERROR("radeon_emit_state failed\n");
2270 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 }
2272
2273 sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
2274 RADEON_UPLOAD_TEX1IMAGES |
2275 RADEON_UPLOAD_TEX2IMAGES |
2276 RADEON_REQUIRE_QUIESCENCE);
2277 }
2278
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 /* Build up a prim_t record:
2280 */
2281 prim.start = elts.start;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002282 prim.finish = elts.end;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 prim.prim = elts.prim;
2284 prim.offset = 0; /* offset from start of dma buffers */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002285 prim.numverts = RADEON_MAX_VB_VERTS; /* duh */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 prim.vc_format = dev_priv->sarea_priv->vc_format;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002287
2288 radeon_cp_dispatch_indices(dev, buf, &prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 if (elts.discard) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002290 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 }
2292
2293 COMMIT_RING();
2294 return 0;
2295}
2296
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002297static int radeon_cp_texture(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298{
2299 DRM_DEVICE;
2300 drm_radeon_private_t *dev_priv = dev->dev_private;
2301 drm_radeon_texture_t tex;
2302 drm_radeon_tex_image_t image;
2303 int ret;
2304
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002305 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002307 DRM_COPY_FROM_USER_IOCTL(tex, (drm_radeon_texture_t __user *) data,
2308 sizeof(tex));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002310 if (tex.image == NULL) {
2311 DRM_ERROR("null texture image!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 return DRM_ERR(EINVAL);
2313 }
2314
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002315 if (DRM_COPY_FROM_USER(&image,
2316 (drm_radeon_tex_image_t __user *) tex.image,
2317 sizeof(image)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 return DRM_ERR(EFAULT);
2319
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002320 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2321 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002323 ret = radeon_cp_dispatch_texture(filp, dev, &tex, &image);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324
2325 COMMIT_RING();
2326 return ret;
2327}
2328
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002329static int radeon_cp_stipple(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330{
2331 DRM_DEVICE;
2332 drm_radeon_private_t *dev_priv = dev->dev_private;
2333 drm_radeon_stipple_t stipple;
2334 u32 mask[32];
2335
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002336 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002338 DRM_COPY_FROM_USER_IOCTL(stipple, (drm_radeon_stipple_t __user *) data,
2339 sizeof(stipple));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002341 if (DRM_COPY_FROM_USER(&mask, stipple.mask, 32 * sizeof(u32)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 return DRM_ERR(EFAULT);
2343
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002344 RING_SPACE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002346 radeon_cp_dispatch_stipple(dev, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347
2348 COMMIT_RING();
2349 return 0;
2350}
2351
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002352static int radeon_cp_indirect(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353{
2354 DRM_DEVICE;
2355 drm_radeon_private_t *dev_priv = dev->dev_private;
2356 drm_device_dma_t *dma = dev->dma;
2357 drm_buf_t *buf;
2358 drm_radeon_indirect_t indirect;
2359 RING_LOCALS;
2360
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002361 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002363 DRM_COPY_FROM_USER_IOCTL(indirect,
2364 (drm_radeon_indirect_t __user *) data,
2365 sizeof(indirect));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002367 DRM_DEBUG("indirect: idx=%d s=%d e=%d d=%d\n",
2368 indirect.idx, indirect.start, indirect.end, indirect.discard);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002370 if (indirect.idx < 0 || indirect.idx >= dma->buf_count) {
2371 DRM_ERROR("buffer index %d (of %d max)\n",
2372 indirect.idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 return DRM_ERR(EINVAL);
2374 }
2375
2376 buf = dma->buflist[indirect.idx];
2377
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002378 if (buf->filp != filp) {
2379 DRM_ERROR("process %d using buffer owned by %p\n",
2380 DRM_CURRENTPID, buf->filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002381 return DRM_ERR(EINVAL);
2382 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002383 if (buf->pending) {
2384 DRM_ERROR("sending pending buffer %d\n", indirect.idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 return DRM_ERR(EINVAL);
2386 }
2387
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002388 if (indirect.start < buf->used) {
2389 DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n",
2390 indirect.start, buf->used);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 return DRM_ERR(EINVAL);
2392 }
2393
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002394 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2395 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396
2397 buf->used = indirect.end;
2398
2399 /* Wait for the 3D stream to idle before the indirect buffer
2400 * containing 2D acceleration commands is processed.
2401 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002402 BEGIN_RING(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403
2404 RADEON_WAIT_UNTIL_3D_IDLE();
2405
2406 ADVANCE_RING();
2407
2408 /* Dispatch the indirect buffer full of commands from the
2409 * X server. This is insecure and is thus only available to
2410 * privileged clients.
2411 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002412 radeon_cp_dispatch_indirect(dev, buf, indirect.start, indirect.end);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 if (indirect.discard) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002414 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 }
2416
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 COMMIT_RING();
2418 return 0;
2419}
2420
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002421static int radeon_cp_vertex2(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422{
2423 DRM_DEVICE;
2424 drm_radeon_private_t *dev_priv = dev->dev_private;
2425 drm_file_t *filp_priv;
2426 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2427 drm_device_dma_t *dma = dev->dma;
2428 drm_buf_t *buf;
2429 drm_radeon_vertex2_t vertex;
2430 int i;
2431 unsigned char laststate;
2432
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002433 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002435 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002437 DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex2_t __user *) data,
2438 sizeof(vertex));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002440 DRM_DEBUG("pid=%d index=%d discard=%d\n",
2441 DRM_CURRENTPID, vertex.idx, vertex.discard);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002443 if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
2444 DRM_ERROR("buffer index %d (of %d max)\n",
2445 vertex.idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 return DRM_ERR(EINVAL);
2447 }
2448
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002449 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2450 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451
2452 buf = dma->buflist[vertex.idx];
2453
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002454 if (buf->filp != filp) {
2455 DRM_ERROR("process %d using buffer owned by %p\n",
2456 DRM_CURRENTPID, buf->filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 return DRM_ERR(EINVAL);
2458 }
2459
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002460 if (buf->pending) {
2461 DRM_ERROR("sending pending buffer %d\n", vertex.idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 return DRM_ERR(EINVAL);
2463 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002464
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
2466 return DRM_ERR(EINVAL);
2467
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002468 for (laststate = 0xff, i = 0; i < vertex.nr_prims; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 drm_radeon_prim_t prim;
2470 drm_radeon_tcl_prim_t tclprim;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002471
2472 if (DRM_COPY_FROM_USER(&prim, &vertex.prim[i], sizeof(prim)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 return DRM_ERR(EFAULT);
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002474
2475 if (prim.stateidx != laststate) {
2476 drm_radeon_state_t state;
2477
2478 if (DRM_COPY_FROM_USER(&state,
2479 &vertex.state[prim.stateidx],
2480 sizeof(state)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 return DRM_ERR(EFAULT);
2482
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002483 if (radeon_emit_state2(dev_priv, filp_priv, &state)) {
2484 DRM_ERROR("radeon_emit_state2 failed\n");
2485 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 }
2487
2488 laststate = prim.stateidx;
2489 }
2490
2491 tclprim.start = prim.start;
2492 tclprim.finish = prim.finish;
2493 tclprim.prim = prim.prim;
2494 tclprim.vc_format = prim.vc_format;
2495
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002496 if (prim.prim & RADEON_PRIM_WALK_IND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 tclprim.offset = prim.numverts * 64;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002498 tclprim.numverts = RADEON_MAX_VB_VERTS; /* duh */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002500 radeon_cp_dispatch_indices(dev, buf, &tclprim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 } else {
2502 tclprim.numverts = prim.numverts;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002503 tclprim.offset = 0; /* not used */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002505 radeon_cp_dispatch_vertex(dev, buf, &tclprim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002507
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 if (sarea_priv->nbox == 1)
2509 sarea_priv->nbox = 0;
2510 }
2511
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002512 if (vertex.discard) {
2513 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 }
2515
2516 COMMIT_RING();
2517 return 0;
2518}
2519
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002520static int radeon_emit_packets(drm_radeon_private_t * dev_priv,
2521 drm_file_t * filp_priv,
2522 drm_radeon_cmd_header_t header,
Dave Airlieb3a83632005-09-30 18:37:36 +10002523 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524{
2525 int id = (int)header.packet.packet_id;
2526 int sz, reg;
2527 int *data = (int *)cmdbuf->buf;
2528 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002529
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 if (id >= RADEON_MAX_STATE_PACKETS)
2531 return DRM_ERR(EINVAL);
2532
2533 sz = packet[id].len;
2534 reg = packet[id].start;
2535
2536 if (sz * sizeof(int) > cmdbuf->bufsz) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002537 DRM_ERROR("Packet size provided larger than data provided\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 return DRM_ERR(EINVAL);
2539 }
2540
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002541 if (radeon_check_and_fixup_packets(dev_priv, filp_priv, id, data)) {
2542 DRM_ERROR("Packet verification failed\n");
2543 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 }
2545
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002546 BEGIN_RING(sz + 1);
2547 OUT_RING(CP_PACKET0(reg, (sz - 1)));
2548 OUT_RING_TABLE(data, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 ADVANCE_RING();
2550
2551 cmdbuf->buf += sz * sizeof(int);
2552 cmdbuf->bufsz -= sz * sizeof(int);
2553 return 0;
2554}
2555
Dave Airlied985c102006-01-02 21:32:48 +11002556static __inline__ int radeon_emit_scalars(drm_radeon_private_t *dev_priv,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002557 drm_radeon_cmd_header_t header,
Dave Airlied985c102006-01-02 21:32:48 +11002558 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559{
2560 int sz = header.scalars.count;
2561 int start = header.scalars.offset;
2562 int stride = header.scalars.stride;
2563 RING_LOCALS;
2564
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002565 BEGIN_RING(3 + sz);
2566 OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
2567 OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
2568 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
2569 OUT_RING_TABLE(cmdbuf->buf, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 ADVANCE_RING();
2571 cmdbuf->buf += sz * sizeof(int);
2572 cmdbuf->bufsz -= sz * sizeof(int);
2573 return 0;
2574}
2575
2576/* God this is ugly
2577 */
Dave Airlied985c102006-01-02 21:32:48 +11002578static __inline__ int radeon_emit_scalars2(drm_radeon_private_t *dev_priv,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002579 drm_radeon_cmd_header_t header,
Dave Airlied985c102006-01-02 21:32:48 +11002580 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581{
2582 int sz = header.scalars.count;
2583 int start = ((unsigned int)header.scalars.offset) + 0x100;
2584 int stride = header.scalars.stride;
2585 RING_LOCALS;
2586
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002587 BEGIN_RING(3 + sz);
2588 OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
2589 OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
2590 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
2591 OUT_RING_TABLE(cmdbuf->buf, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 ADVANCE_RING();
2593 cmdbuf->buf += sz * sizeof(int);
2594 cmdbuf->bufsz -= sz * sizeof(int);
2595 return 0;
2596}
2597
Dave Airlied985c102006-01-02 21:32:48 +11002598static __inline__ int radeon_emit_vectors(drm_radeon_private_t *dev_priv,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002599 drm_radeon_cmd_header_t header,
Dave Airlied985c102006-01-02 21:32:48 +11002600 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601{
2602 int sz = header.vectors.count;
2603 int start = header.vectors.offset;
2604 int stride = header.vectors.stride;
2605 RING_LOCALS;
2606
Dave Airlief2a22792006-06-24 16:55:34 +10002607 BEGIN_RING(5 + sz);
2608 OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002609 OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
2610 OUT_RING(start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
2611 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
2612 OUT_RING_TABLE(cmdbuf->buf, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 ADVANCE_RING();
2614
2615 cmdbuf->buf += sz * sizeof(int);
2616 cmdbuf->bufsz -= sz * sizeof(int);
2617 return 0;
2618}
2619
Dave Airlied6fece02006-06-24 17:04:07 +10002620static __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv,
2621 drm_radeon_cmd_header_t header,
2622 drm_radeon_kcmd_buffer_t *cmdbuf)
2623{
2624 int sz = header.veclinear.count * 4;
2625 int start = header.veclinear.addr_lo | (header.veclinear.addr_hi << 8);
2626 RING_LOCALS;
2627
2628 if (!sz)
2629 return 0;
2630 if (sz * 4 > cmdbuf->bufsz)
2631 return DRM_ERR(EINVAL);
2632
2633 BEGIN_RING(5 + sz);
2634 OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
2635 OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
2636 OUT_RING(start | (1 << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
2637 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
2638 OUT_RING_TABLE(cmdbuf->buf, sz);
2639 ADVANCE_RING();
2640
2641 cmdbuf->buf += sz * sizeof(int);
2642 cmdbuf->bufsz -= sz * sizeof(int);
2643 return 0;
2644}
2645
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002646static int radeon_emit_packet3(drm_device_t * dev,
2647 drm_file_t * filp_priv,
Dave Airlieb3a83632005-09-30 18:37:36 +10002648 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649{
2650 drm_radeon_private_t *dev_priv = dev->dev_private;
2651 unsigned int cmdsz;
2652 int ret;
2653 RING_LOCALS;
2654
2655 DRM_DEBUG("\n");
2656
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002657 if ((ret = radeon_check_and_fixup_packet3(dev_priv, filp_priv,
2658 cmdbuf, &cmdsz))) {
2659 DRM_ERROR("Packet verification failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 return ret;
2661 }
2662
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002663 BEGIN_RING(cmdsz);
2664 OUT_RING_TABLE(cmdbuf->buf, cmdsz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 ADVANCE_RING();
2666
2667 cmdbuf->buf += cmdsz * 4;
2668 cmdbuf->bufsz -= cmdsz * 4;
2669 return 0;
2670}
2671
Dave Airlied985c102006-01-02 21:32:48 +11002672static int radeon_emit_packet3_cliprect(drm_device_t *dev,
2673 drm_file_t *filp_priv,
Dave Airlieb3a83632005-09-30 18:37:36 +10002674 drm_radeon_kcmd_buffer_t *cmdbuf,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002675 int orig_nbox)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676{
2677 drm_radeon_private_t *dev_priv = dev->dev_private;
2678 drm_clip_rect_t box;
2679 unsigned int cmdsz;
2680 int ret;
2681 drm_clip_rect_t __user *boxes = cmdbuf->boxes;
2682 int i = 0;
2683 RING_LOCALS;
2684
2685 DRM_DEBUG("\n");
2686
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002687 if ((ret = radeon_check_and_fixup_packet3(dev_priv, filp_priv,
2688 cmdbuf, &cmdsz))) {
2689 DRM_ERROR("Packet verification failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 return ret;
2691 }
2692
2693 if (!orig_nbox)
2694 goto out;
2695
2696 do {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002697 if (i < cmdbuf->nbox) {
2698 if (DRM_COPY_FROM_USER(&box, &boxes[i], sizeof(box)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 return DRM_ERR(EFAULT);
2700 /* FIXME The second and subsequent times round
2701 * this loop, send a WAIT_UNTIL_3D_IDLE before
2702 * calling emit_clip_rect(). This fixes a
2703 * lockup on fast machines when sending
2704 * several cliprects with a cmdbuf, as when
2705 * waving a 2D window over a 3D
2706 * window. Something in the commands from user
2707 * space seems to hang the card when they're
2708 * sent several times in a row. That would be
2709 * the correct place to fix it but this works
2710 * around it until I can figure that out - Tim
2711 * Smith */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002712 if (i) {
2713 BEGIN_RING(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 RADEON_WAIT_UNTIL_3D_IDLE();
2715 ADVANCE_RING();
2716 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002717 radeon_emit_clip_rect(dev_priv, &box);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002719
2720 BEGIN_RING(cmdsz);
2721 OUT_RING_TABLE(cmdbuf->buf, cmdsz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 ADVANCE_RING();
2723
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002724 } while (++i < cmdbuf->nbox);
2725 if (cmdbuf->nbox == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 cmdbuf->nbox = 0;
2727
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002728 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 cmdbuf->buf += cmdsz * 4;
2730 cmdbuf->bufsz -= cmdsz * 4;
2731 return 0;
2732}
2733
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002734static int radeon_emit_wait(drm_device_t * dev, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735{
2736 drm_radeon_private_t *dev_priv = dev->dev_private;
2737 RING_LOCALS;
2738
2739 DRM_DEBUG("%s: %x\n", __FUNCTION__, flags);
2740 switch (flags) {
2741 case RADEON_WAIT_2D:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002742 BEGIN_RING(2);
2743 RADEON_WAIT_UNTIL_2D_IDLE();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 ADVANCE_RING();
2745 break;
2746 case RADEON_WAIT_3D:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002747 BEGIN_RING(2);
2748 RADEON_WAIT_UNTIL_3D_IDLE();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 ADVANCE_RING();
2750 break;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002751 case RADEON_WAIT_2D | RADEON_WAIT_3D:
2752 BEGIN_RING(2);
2753 RADEON_WAIT_UNTIL_IDLE();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 ADVANCE_RING();
2755 break;
2756 default:
2757 return DRM_ERR(EINVAL);
2758 }
2759
2760 return 0;
2761}
2762
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002763static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764{
2765 DRM_DEVICE;
2766 drm_radeon_private_t *dev_priv = dev->dev_private;
2767 drm_file_t *filp_priv;
2768 drm_device_dma_t *dma = dev->dma;
2769 drm_buf_t *buf = NULL;
2770 int idx;
Dave Airlieb3a83632005-09-30 18:37:36 +10002771 drm_radeon_kcmd_buffer_t cmdbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 drm_radeon_cmd_header_t header;
2773 int orig_nbox, orig_bufsz;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002774 char *kbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002776 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002778 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002780 DRM_COPY_FROM_USER_IOCTL(cmdbuf,
2781 (drm_radeon_cmd_buffer_t __user *) data,
2782 sizeof(cmdbuf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002784 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2785 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002787 if (cmdbuf.bufsz > 64 * 1024 || cmdbuf.bufsz < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 return DRM_ERR(EINVAL);
2789 }
2790
2791 /* Allocate an in-kernel area and copy in the cmdbuf. Do this to avoid
2792 * races between checking values and using those values in other code,
2793 * and simply to avoid a lot of function calls to copy in data.
2794 */
2795 orig_bufsz = cmdbuf.bufsz;
2796 if (orig_bufsz != 0) {
2797 kbuf = drm_alloc(cmdbuf.bufsz, DRM_MEM_DRIVER);
2798 if (kbuf == NULL)
2799 return DRM_ERR(ENOMEM);
Dave Airlied985c102006-01-02 21:32:48 +11002800 if (DRM_COPY_FROM_USER(kbuf, (void __user *)cmdbuf.buf,
2801 cmdbuf.bufsz)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
2803 return DRM_ERR(EFAULT);
2804 }
2805 cmdbuf.buf = kbuf;
2806 }
2807
2808 orig_nbox = cmdbuf.nbox;
2809
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002810 if (dev_priv->microcode_version == UCODE_R300) {
Dave Airlie414ed532005-08-16 20:43:16 +10002811 int temp;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002812 temp = r300_do_cp_cmdbuf(dev, filp, filp_priv, &cmdbuf);
2813
Dave Airlie414ed532005-08-16 20:43:16 +10002814 if (orig_bufsz != 0)
2815 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002816
Dave Airlie414ed532005-08-16 20:43:16 +10002817 return temp;
2818 }
2819
2820 /* microcode_version != r300 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002821 while (cmdbuf.bufsz >= sizeof(header)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822
2823 header.i = *(int *)cmdbuf.buf;
2824 cmdbuf.buf += sizeof(header);
2825 cmdbuf.bufsz -= sizeof(header);
2826
2827 switch (header.header.cmd_type) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002828 case RADEON_CMD_PACKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 DRM_DEBUG("RADEON_CMD_PACKET\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002830 if (radeon_emit_packets
2831 (dev_priv, filp_priv, header, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 DRM_ERROR("radeon_emit_packets failed\n");
2833 goto err;
2834 }
2835 break;
2836
2837 case RADEON_CMD_SCALARS:
2838 DRM_DEBUG("RADEON_CMD_SCALARS\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002839 if (radeon_emit_scalars(dev_priv, header, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 DRM_ERROR("radeon_emit_scalars failed\n");
2841 goto err;
2842 }
2843 break;
2844
2845 case RADEON_CMD_VECTORS:
2846 DRM_DEBUG("RADEON_CMD_VECTORS\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002847 if (radeon_emit_vectors(dev_priv, header, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 DRM_ERROR("radeon_emit_vectors failed\n");
2849 goto err;
2850 }
2851 break;
2852
2853 case RADEON_CMD_DMA_DISCARD:
2854 DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n");
2855 idx = header.dma.buf_idx;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002856 if (idx < 0 || idx >= dma->buf_count) {
2857 DRM_ERROR("buffer index %d (of %d max)\n",
2858 idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 goto err;
2860 }
2861
2862 buf = dma->buflist[idx];
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002863 if (buf->filp != filp || buf->pending) {
2864 DRM_ERROR("bad buffer %p %p %d\n",
2865 buf->filp, filp, buf->pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 goto err;
2867 }
2868
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002869 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 break;
2871
2872 case RADEON_CMD_PACKET3:
2873 DRM_DEBUG("RADEON_CMD_PACKET3\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002874 if (radeon_emit_packet3(dev, filp_priv, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 DRM_ERROR("radeon_emit_packet3 failed\n");
2876 goto err;
2877 }
2878 break;
2879
2880 case RADEON_CMD_PACKET3_CLIP:
2881 DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002882 if (radeon_emit_packet3_cliprect
2883 (dev, filp_priv, &cmdbuf, orig_nbox)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 DRM_ERROR("radeon_emit_packet3_clip failed\n");
2885 goto err;
2886 }
2887 break;
2888
2889 case RADEON_CMD_SCALARS2:
2890 DRM_DEBUG("RADEON_CMD_SCALARS2\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002891 if (radeon_emit_scalars2(dev_priv, header, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 DRM_ERROR("radeon_emit_scalars2 failed\n");
2893 goto err;
2894 }
2895 break;
2896
2897 case RADEON_CMD_WAIT:
2898 DRM_DEBUG("RADEON_CMD_WAIT\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002899 if (radeon_emit_wait(dev, header.wait.flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900 DRM_ERROR("radeon_emit_wait failed\n");
2901 goto err;
2902 }
2903 break;
Dave Airlied6fece02006-06-24 17:04:07 +10002904 case RADEON_CMD_VECLINEAR:
2905 DRM_DEBUG("RADEON_CMD_VECLINEAR\n");
2906 if (radeon_emit_veclinear(dev_priv, header, &cmdbuf)) {
2907 DRM_ERROR("radeon_emit_veclinear failed\n");
2908 goto err;
2909 }
2910 break;
2911
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002913 DRM_ERROR("bad cmd_type %d at %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 header.header.cmd_type,
2915 cmdbuf.buf - sizeof(header));
2916 goto err;
2917 }
2918 }
2919
2920 if (orig_bufsz != 0)
2921 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
2922
2923 DRM_DEBUG("DONE\n");
2924 COMMIT_RING();
2925 return 0;
2926
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002927 err:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 if (orig_bufsz != 0)
2929 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
2930 return DRM_ERR(EINVAL);
2931}
2932
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002933static int radeon_cp_getparam(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934{
2935 DRM_DEVICE;
2936 drm_radeon_private_t *dev_priv = dev->dev_private;
2937 drm_radeon_getparam_t param;
2938 int value;
2939
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002940 DRM_COPY_FROM_USER_IOCTL(param, (drm_radeon_getparam_t __user *) data,
2941 sizeof(param));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002943 DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002945 switch (param.param) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 case RADEON_PARAM_GART_BUFFER_OFFSET:
2947 value = dev_priv->gart_buffers_offset;
2948 break;
2949 case RADEON_PARAM_LAST_FRAME:
2950 dev_priv->stats.last_frame_reads++;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002951 value = GET_SCRATCH(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 break;
2953 case RADEON_PARAM_LAST_DISPATCH:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002954 value = GET_SCRATCH(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 break;
2956 case RADEON_PARAM_LAST_CLEAR:
2957 dev_priv->stats.last_clear_reads++;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002958 value = GET_SCRATCH(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 break;
2960 case RADEON_PARAM_IRQ_NR:
2961 value = dev->irq;
2962 break;
2963 case RADEON_PARAM_GART_BASE:
2964 value = dev_priv->gart_vm_start;
2965 break;
2966 case RADEON_PARAM_REGISTER_HANDLE:
Dave Airlied985c102006-01-02 21:32:48 +11002967 value = dev_priv->mmio->offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 break;
2969 case RADEON_PARAM_STATUS_HANDLE:
2970 value = dev_priv->ring_rptr_offset;
2971 break;
2972#if BITS_PER_LONG == 32
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002973 /*
2974 * This ioctl() doesn't work on 64-bit platforms because hw_lock is a
2975 * pointer which can't fit into an int-sized variable. According to
2976 * Michel Dänzer, the ioctl() is only used on embedded platforms, so
2977 * not supporting it shouldn't be a problem. If the same functionality
2978 * is needed on 64-bit platforms, a new ioctl() would have to be added,
2979 * so backwards-compatibility for the embedded platforms can be
2980 * maintained. --davidm 4-Feb-2004.
2981 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 case RADEON_PARAM_SAREA_HANDLE:
2983 /* The lock is the first dword in the sarea. */
2984 value = (long)dev->lock.hw_lock;
2985 break;
2986#endif
2987 case RADEON_PARAM_GART_TEX_HANDLE:
2988 value = dev_priv->gart_textures_offset;
2989 break;
Dave Airlied985c102006-01-02 21:32:48 +11002990
2991 case RADEON_PARAM_CARD_TYPE:
2992 if (dev_priv->flags & CHIP_IS_PCIE)
2993 value = RADEON_CARD_PCIE;
2994 else if (dev_priv->flags & CHIP_IS_AGP)
2995 value = RADEON_CARD_AGP;
2996 else
2997 value = RADEON_CARD_PCI;
2998 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 default:
Michel Dänzer9ca94162006-08-07 20:31:30 +10003000 DRM_DEBUG("Invalid parameter %d\n", param.param);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 return DRM_ERR(EINVAL);
3002 }
3003
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003004 if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
3005 DRM_ERROR("copy_to_user\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 return DRM_ERR(EFAULT);
3007 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003008
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 return 0;
3010}
3011
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003012static int radeon_cp_setparam(DRM_IOCTL_ARGS)
3013{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 DRM_DEVICE;
3015 drm_radeon_private_t *dev_priv = dev->dev_private;
3016 drm_file_t *filp_priv;
3017 drm_radeon_setparam_t sp;
3018 struct drm_radeon_driver_file_fields *radeon_priv;
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);