blob: 4ca6bd13d58996b9096a5a789321b24bb71d686b [file] [log] [blame]
Dave Airlied985c102006-01-02 21:32:48 +11001/* radeon_state.c -- State support for Radeon -*- linux-c -*- */
2/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * Copyright 2000 VA Linux Systems, Inc., Fremont, California.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 * Authors:
26 * Gareth Hughes <gareth@valinux.com>
27 * Kevin E. Martin <martin@valinux.com>
28 */
29
30#include "drmP.h"
31#include "drm.h"
32#include "drm_sarea.h"
33#include "radeon_drm.h"
34#include "radeon_drv.h"
35
36/* ================================================================
37 * Helper functions for client state checking and fixup
38 */
39
Dave Airlieb5e89ed2005-09-25 14:28:13 +100040static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
41 dev_priv,
42 drm_file_t * filp_priv,
Dave Airlieb3a83632005-09-30 18:37:36 +100043 u32 *offset)
Dave Airlieb5e89ed2005-09-25 14:28:13 +100044{
Linus Torvalds1da177e2005-04-16 15:20:36 -070045 u32 off = *offset;
46 struct drm_radeon_driver_file_fields *radeon_priv;
47
Dave Airlied5ea7022006-03-19 19:37:55 +110048 /* Hrm ... the story of the offset ... So this function converts
49 * the various ideas of what userland clients might have for an
50 * offset in the card address space into an offset into the card
51 * address space :) So with a sane client, it should just keep
52 * the value intact and just do some boundary checking. However,
53 * not all clients are sane. Some older clients pass us 0 based
54 * offsets relative to the start of the framebuffer and some may
55 * assume the AGP aperture it appended to the framebuffer, so we
56 * try to detect those cases and fix them up.
57 *
58 * Note: It might be a good idea here to make sure the offset lands
59 * in some "allowed" area to protect things like the PCIE GART...
60 */
61
62 /* First, the best case, the offset already lands in either the
63 * framebuffer or the GART mapped space
64 */
65 if ((off >= dev_priv->fb_location &&
66 off < (dev_priv->fb_location + dev_priv->fb_size)) ||
67 (off >= dev_priv->gart_vm_start &&
68 off < (dev_priv->gart_vm_start + dev_priv->gart_size)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 return 0;
70
Dave Airlied5ea7022006-03-19 19:37:55 +110071 /* Ok, that didn't happen... now check if we have a zero based
72 * offset that fits in the framebuffer + gart space, apply the
73 * magic offset we get from SETPARAM or calculated from fb_location
74 */
75 if (off < (dev_priv->fb_size + dev_priv->gart_size)) {
76 radeon_priv = filp_priv->driver_priv;
77 off += radeon_priv->radeon_fb_delta;
78 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Dave Airlied5ea7022006-03-19 19:37:55 +110080 /* Finally, assume we aimed at a GART offset if beyond the fb */
81 if (off > (dev_priv->fb_location + dev_priv->fb_size))
82 off = off - (dev_priv->fb_location + dev_priv->fb_size) +
83 dev_priv->gart_vm_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
Dave Airlied5ea7022006-03-19 19:37:55 +110085 /* Now recheck and fail if out of bounds */
86 if ((off >= dev_priv->fb_location &&
87 off < (dev_priv->fb_location + dev_priv->fb_size)) ||
88 (off >= dev_priv->gart_vm_start &&
89 off < (dev_priv->gart_vm_start + dev_priv->gart_size))) {
90 DRM_DEBUG("offset fixed up to 0x%x\n", off);
91 *offset = off;
92 return 0;
93 }
94 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095}
96
Dave Airlieb5e89ed2005-09-25 14:28:13 +100097static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
98 dev_priv,
99 drm_file_t * filp_priv,
Dave Airlieb3a83632005-09-30 18:37:36 +1000100 int id, u32 *data)
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000101{
102 switch (id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
104 case RADEON_EMIT_PP_MISC:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000105 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
Dave Airlied985c102006-01-02 21:32:48 +1100106 &data[(RADEON_RB3D_DEPTHOFFSET - RADEON_PP_MISC) / 4])) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000107 DRM_ERROR("Invalid depth buffer offset\n");
108 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 }
110 break;
111
112 case RADEON_EMIT_PP_CNTL:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000113 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
Dave Airlied985c102006-01-02 21:32:48 +1100114 &data[(RADEON_RB3D_COLOROFFSET - RADEON_PP_CNTL) / 4])) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000115 DRM_ERROR("Invalid colour buffer offset\n");
116 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 }
118 break;
119
120 case R200_EMIT_PP_TXOFFSET_0:
121 case R200_EMIT_PP_TXOFFSET_1:
122 case R200_EMIT_PP_TXOFFSET_2:
123 case R200_EMIT_PP_TXOFFSET_3:
124 case R200_EMIT_PP_TXOFFSET_4:
125 case R200_EMIT_PP_TXOFFSET_5:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000126 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
127 &data[0])) {
128 DRM_ERROR("Invalid R200 texture offset\n");
129 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 }
131 break;
132
133 case RADEON_EMIT_PP_TXFILTER_0:
134 case RADEON_EMIT_PP_TXFILTER_1:
135 case RADEON_EMIT_PP_TXFILTER_2:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000136 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
Dave Airlied985c102006-01-02 21:32:48 +1100137 &data[(RADEON_PP_TXOFFSET_0 - RADEON_PP_TXFILTER_0) / 4])) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000138 DRM_ERROR("Invalid R100 texture offset\n");
139 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 }
141 break;
142
143 case R200_EMIT_PP_CUBIC_OFFSETS_0:
144 case R200_EMIT_PP_CUBIC_OFFSETS_1:
145 case R200_EMIT_PP_CUBIC_OFFSETS_2:
146 case R200_EMIT_PP_CUBIC_OFFSETS_3:
147 case R200_EMIT_PP_CUBIC_OFFSETS_4:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000148 case R200_EMIT_PP_CUBIC_OFFSETS_5:{
149 int i;
150 for (i = 0; i < 5; i++) {
Dave Airlied985c102006-01-02 21:32:48 +1100151 if (radeon_check_and_fixup_offset(dev_priv,
152 filp_priv,
153 &data[i])) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000154 DRM_ERROR
155 ("Invalid R200 cubic texture offset\n");
156 return DRM_ERR(EINVAL);
157 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000159 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
162 case RADEON_EMIT_PP_CUBIC_OFFSETS_T0:
163 case RADEON_EMIT_PP_CUBIC_OFFSETS_T1:
164 case RADEON_EMIT_PP_CUBIC_OFFSETS_T2:{
165 int i;
166 for (i = 0; i < 5; i++) {
167 if (radeon_check_and_fixup_offset(dev_priv,
168 filp_priv,
169 &data[i])) {
170 DRM_ERROR
171 ("Invalid R100 cubic texture offset\n");
172 return DRM_ERR(EINVAL);
173 }
174 }
175 }
176 break;
177
178 case RADEON_EMIT_RB3D_COLORPITCH:
179 case RADEON_EMIT_RE_LINE_PATTERN:
180 case RADEON_EMIT_SE_LINE_WIDTH:
181 case RADEON_EMIT_PP_LUM_MATRIX:
182 case RADEON_EMIT_PP_ROT_MATRIX_0:
183 case RADEON_EMIT_RB3D_STENCILREFMASK:
184 case RADEON_EMIT_SE_VPORT_XSCALE:
185 case RADEON_EMIT_SE_CNTL:
186 case RADEON_EMIT_SE_CNTL_STATUS:
187 case RADEON_EMIT_RE_MISC:
188 case RADEON_EMIT_PP_BORDER_COLOR_0:
189 case RADEON_EMIT_PP_BORDER_COLOR_1:
190 case RADEON_EMIT_PP_BORDER_COLOR_2:
191 case RADEON_EMIT_SE_ZBIAS_FACTOR:
192 case RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT:
193 case RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED:
194 case R200_EMIT_PP_TXCBLEND_0:
195 case R200_EMIT_PP_TXCBLEND_1:
196 case R200_EMIT_PP_TXCBLEND_2:
197 case R200_EMIT_PP_TXCBLEND_3:
198 case R200_EMIT_PP_TXCBLEND_4:
199 case R200_EMIT_PP_TXCBLEND_5:
200 case R200_EMIT_PP_TXCBLEND_6:
201 case R200_EMIT_PP_TXCBLEND_7:
202 case R200_EMIT_TCL_LIGHT_MODEL_CTL_0:
203 case R200_EMIT_TFACTOR_0:
204 case R200_EMIT_VTX_FMT_0:
205 case R200_EMIT_VAP_CTL:
206 case R200_EMIT_MATRIX_SELECT_0:
207 case R200_EMIT_TEX_PROC_CTL_2:
208 case R200_EMIT_TCL_UCP_VERT_BLEND_CTL:
209 case R200_EMIT_PP_TXFILTER_0:
210 case R200_EMIT_PP_TXFILTER_1:
211 case R200_EMIT_PP_TXFILTER_2:
212 case R200_EMIT_PP_TXFILTER_3:
213 case R200_EMIT_PP_TXFILTER_4:
214 case R200_EMIT_PP_TXFILTER_5:
215 case R200_EMIT_VTE_CNTL:
216 case R200_EMIT_OUTPUT_VTX_COMP_SEL:
217 case R200_EMIT_PP_TAM_DEBUG3:
218 case R200_EMIT_PP_CNTL_X:
219 case R200_EMIT_RB3D_DEPTHXY_OFFSET:
220 case R200_EMIT_RE_AUX_SCISSOR_CNTL:
221 case R200_EMIT_RE_SCISSOR_TL_0:
222 case R200_EMIT_RE_SCISSOR_TL_1:
223 case R200_EMIT_RE_SCISSOR_TL_2:
224 case R200_EMIT_SE_VAP_CNTL_STATUS:
225 case R200_EMIT_SE_VTX_STATE_CNTL:
226 case R200_EMIT_RE_POINTSIZE:
227 case R200_EMIT_TCL_INPUT_VTX_VECTOR_ADDR_0:
228 case R200_EMIT_PP_CUBIC_FACES_0:
229 case R200_EMIT_PP_CUBIC_FACES_1:
230 case R200_EMIT_PP_CUBIC_FACES_2:
231 case R200_EMIT_PP_CUBIC_FACES_3:
232 case R200_EMIT_PP_CUBIC_FACES_4:
233 case R200_EMIT_PP_CUBIC_FACES_5:
234 case RADEON_EMIT_PP_TEX_SIZE_0:
235 case RADEON_EMIT_PP_TEX_SIZE_1:
236 case RADEON_EMIT_PP_TEX_SIZE_2:
237 case R200_EMIT_RB3D_BLENDCOLOR:
238 case R200_EMIT_TCL_POINT_SPRITE_CNTL:
239 case RADEON_EMIT_PP_CUBIC_FACES_0:
240 case RADEON_EMIT_PP_CUBIC_FACES_1:
241 case RADEON_EMIT_PP_CUBIC_FACES_2:
242 case R200_EMIT_PP_TRI_PERF_CNTL:
Dave Airlie9d176012005-09-11 19:55:53 +1000243 case R200_EMIT_PP_AFS_0:
244 case R200_EMIT_PP_AFS_1:
245 case R200_EMIT_ATF_TFACTOR:
246 case R200_EMIT_PP_TXCTLALL_0:
247 case R200_EMIT_PP_TXCTLALL_1:
248 case R200_EMIT_PP_TXCTLALL_2:
249 case R200_EMIT_PP_TXCTLALL_3:
250 case R200_EMIT_PP_TXCTLALL_4:
251 case R200_EMIT_PP_TXCTLALL_5:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 /* These packets don't contain memory offsets */
253 break;
254
255 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000256 DRM_ERROR("Unknown state packet ID %d\n", id);
257 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 }
259
260 return 0;
261}
262
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000263static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
264 dev_priv,
Dave Airlied985c102006-01-02 21:32:48 +1100265 drm_file_t *filp_priv,
266 drm_radeon_kcmd_buffer_t *
267 cmdbuf,
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000268 unsigned int *cmdsz)
269{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 u32 *cmd = (u32 *) cmdbuf->buf;
271
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000272 *cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000274 if ((cmd[0] & 0xc0000000) != RADEON_CP_PACKET3) {
275 DRM_ERROR("Not a type 3 packet\n");
276 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 }
278
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000279 if (4 * *cmdsz > cmdbuf->bufsz) {
280 DRM_ERROR("Packet size larger than size of data provided\n");
281 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 }
283
284 /* Check client state and fix it up if necessary */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000285 if (cmd[0] & 0x8000) { /* MSB of opcode: next DWORD GUI_CNTL */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 u32 offset;
287
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000288 if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
289 | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 offset = cmd[2] << 10;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000291 if (radeon_check_and_fixup_offset
292 (dev_priv, filp_priv, &offset)) {
293 DRM_ERROR("Invalid first packet offset\n");
294 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000296 cmd[2] = (cmd[2] & 0xffc00000) | offset >> 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 }
298
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000299 if ((cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&
300 (cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 offset = cmd[3] << 10;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000302 if (radeon_check_and_fixup_offset
303 (dev_priv, filp_priv, &offset)) {
304 DRM_ERROR("Invalid second packet offset\n");
305 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000307 cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 }
309 }
310
311 return 0;
312}
313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314/* ================================================================
315 * CP hardware state programming functions
316 */
317
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000318static __inline__ void radeon_emit_clip_rect(drm_radeon_private_t * dev_priv,
319 drm_clip_rect_t * box)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320{
321 RING_LOCALS;
322
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000323 DRM_DEBUG(" box: x1=%d y1=%d x2=%d y2=%d\n",
324 box->x1, box->y1, box->x2, box->y2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000326 BEGIN_RING(4);
327 OUT_RING(CP_PACKET0(RADEON_RE_TOP_LEFT, 0));
328 OUT_RING((box->y1 << 16) | box->x1);
329 OUT_RING(CP_PACKET0(RADEON_RE_WIDTH_HEIGHT, 0));
330 OUT_RING(((box->y2 - 1) << 16) | (box->x2 - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 ADVANCE_RING();
332}
333
334/* Emit 1.1 state
335 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000336static int radeon_emit_state(drm_radeon_private_t * dev_priv,
337 drm_file_t * filp_priv,
338 drm_radeon_context_regs_t * ctx,
339 drm_radeon_texture_regs_t * tex,
340 unsigned int dirty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341{
342 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000343 DRM_DEBUG("dirty=0x%08x\n", dirty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000345 if (dirty & RADEON_UPLOAD_CONTEXT) {
346 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
347 &ctx->rb3d_depthoffset)) {
348 DRM_ERROR("Invalid depth buffer offset\n");
349 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 }
351
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000352 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
353 &ctx->rb3d_coloroffset)) {
354 DRM_ERROR("Invalid depth buffer offset\n");
355 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 }
357
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000358 BEGIN_RING(14);
359 OUT_RING(CP_PACKET0(RADEON_PP_MISC, 6));
360 OUT_RING(ctx->pp_misc);
361 OUT_RING(ctx->pp_fog_color);
362 OUT_RING(ctx->re_solid_color);
363 OUT_RING(ctx->rb3d_blendcntl);
364 OUT_RING(ctx->rb3d_depthoffset);
365 OUT_RING(ctx->rb3d_depthpitch);
366 OUT_RING(ctx->rb3d_zstencilcntl);
367 OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 2));
368 OUT_RING(ctx->pp_cntl);
369 OUT_RING(ctx->rb3d_cntl);
370 OUT_RING(ctx->rb3d_coloroffset);
371 OUT_RING(CP_PACKET0(RADEON_RB3D_COLORPITCH, 0));
372 OUT_RING(ctx->rb3d_colorpitch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 ADVANCE_RING();
374 }
375
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000376 if (dirty & RADEON_UPLOAD_VERTFMT) {
377 BEGIN_RING(2);
378 OUT_RING(CP_PACKET0(RADEON_SE_COORD_FMT, 0));
379 OUT_RING(ctx->se_coord_fmt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 ADVANCE_RING();
381 }
382
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000383 if (dirty & RADEON_UPLOAD_LINE) {
384 BEGIN_RING(5);
385 OUT_RING(CP_PACKET0(RADEON_RE_LINE_PATTERN, 1));
386 OUT_RING(ctx->re_line_pattern);
387 OUT_RING(ctx->re_line_state);
388 OUT_RING(CP_PACKET0(RADEON_SE_LINE_WIDTH, 0));
389 OUT_RING(ctx->se_line_width);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 ADVANCE_RING();
391 }
392
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000393 if (dirty & RADEON_UPLOAD_BUMPMAP) {
394 BEGIN_RING(5);
395 OUT_RING(CP_PACKET0(RADEON_PP_LUM_MATRIX, 0));
396 OUT_RING(ctx->pp_lum_matrix);
397 OUT_RING(CP_PACKET0(RADEON_PP_ROT_MATRIX_0, 1));
398 OUT_RING(ctx->pp_rot_matrix_0);
399 OUT_RING(ctx->pp_rot_matrix_1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 ADVANCE_RING();
401 }
402
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000403 if (dirty & RADEON_UPLOAD_MASKS) {
404 BEGIN_RING(4);
405 OUT_RING(CP_PACKET0(RADEON_RB3D_STENCILREFMASK, 2));
406 OUT_RING(ctx->rb3d_stencilrefmask);
407 OUT_RING(ctx->rb3d_ropcntl);
408 OUT_RING(ctx->rb3d_planemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 ADVANCE_RING();
410 }
411
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000412 if (dirty & RADEON_UPLOAD_VIEWPORT) {
413 BEGIN_RING(7);
414 OUT_RING(CP_PACKET0(RADEON_SE_VPORT_XSCALE, 5));
415 OUT_RING(ctx->se_vport_xscale);
416 OUT_RING(ctx->se_vport_xoffset);
417 OUT_RING(ctx->se_vport_yscale);
418 OUT_RING(ctx->se_vport_yoffset);
419 OUT_RING(ctx->se_vport_zscale);
420 OUT_RING(ctx->se_vport_zoffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 ADVANCE_RING();
422 }
423
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000424 if (dirty & RADEON_UPLOAD_SETUP) {
425 BEGIN_RING(4);
426 OUT_RING(CP_PACKET0(RADEON_SE_CNTL, 0));
427 OUT_RING(ctx->se_cntl);
428 OUT_RING(CP_PACKET0(RADEON_SE_CNTL_STATUS, 0));
429 OUT_RING(ctx->se_cntl_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 ADVANCE_RING();
431 }
432
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000433 if (dirty & RADEON_UPLOAD_MISC) {
434 BEGIN_RING(2);
435 OUT_RING(CP_PACKET0(RADEON_RE_MISC, 0));
436 OUT_RING(ctx->re_misc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 ADVANCE_RING();
438 }
439
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000440 if (dirty & RADEON_UPLOAD_TEX0) {
441 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
442 &tex[0].pp_txoffset)) {
443 DRM_ERROR("Invalid texture offset for unit 0\n");
444 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 }
446
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000447 BEGIN_RING(9);
448 OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_0, 5));
449 OUT_RING(tex[0].pp_txfilter);
450 OUT_RING(tex[0].pp_txformat);
451 OUT_RING(tex[0].pp_txoffset);
452 OUT_RING(tex[0].pp_txcblend);
453 OUT_RING(tex[0].pp_txablend);
454 OUT_RING(tex[0].pp_tfactor);
455 OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_0, 0));
456 OUT_RING(tex[0].pp_border_color);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 ADVANCE_RING();
458 }
459
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000460 if (dirty & RADEON_UPLOAD_TEX1) {
461 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
462 &tex[1].pp_txoffset)) {
463 DRM_ERROR("Invalid texture offset for unit 1\n");
464 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 }
466
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000467 BEGIN_RING(9);
468 OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_1, 5));
469 OUT_RING(tex[1].pp_txfilter);
470 OUT_RING(tex[1].pp_txformat);
471 OUT_RING(tex[1].pp_txoffset);
472 OUT_RING(tex[1].pp_txcblend);
473 OUT_RING(tex[1].pp_txablend);
474 OUT_RING(tex[1].pp_tfactor);
475 OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_1, 0));
476 OUT_RING(tex[1].pp_border_color);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 ADVANCE_RING();
478 }
479
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000480 if (dirty & RADEON_UPLOAD_TEX2) {
481 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
482 &tex[2].pp_txoffset)) {
483 DRM_ERROR("Invalid texture offset for unit 2\n");
484 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 }
486
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000487 BEGIN_RING(9);
488 OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_2, 5));
489 OUT_RING(tex[2].pp_txfilter);
490 OUT_RING(tex[2].pp_txformat);
491 OUT_RING(tex[2].pp_txoffset);
492 OUT_RING(tex[2].pp_txcblend);
493 OUT_RING(tex[2].pp_txablend);
494 OUT_RING(tex[2].pp_tfactor);
495 OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_2, 0));
496 OUT_RING(tex[2].pp_border_color);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 ADVANCE_RING();
498 }
499
500 return 0;
501}
502
503/* Emit 1.2 state
504 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000505static int radeon_emit_state2(drm_radeon_private_t * dev_priv,
506 drm_file_t * filp_priv,
507 drm_radeon_state_t * state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508{
509 RING_LOCALS;
510
511 if (state->dirty & RADEON_UPLOAD_ZBIAS) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000512 BEGIN_RING(3);
513 OUT_RING(CP_PACKET0(RADEON_SE_ZBIAS_FACTOR, 1));
514 OUT_RING(state->context2.se_zbias_factor);
515 OUT_RING(state->context2.se_zbias_constant);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 ADVANCE_RING();
517 }
518
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000519 return radeon_emit_state(dev_priv, filp_priv, &state->context,
520 state->tex, state->dirty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521}
522
523/* New (1.3) state mechanism. 3 commands (packet, scalar, vector) in
524 * 1.3 cmdbuffers allow all previous state to be updated as well as
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000525 * the tcl scalar and vector areas.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000527static struct {
528 int start;
529 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 const char *name;
531} packet[RADEON_MAX_STATE_PACKETS] = {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000532 {RADEON_PP_MISC, 7, "RADEON_PP_MISC"},
533 {RADEON_PP_CNTL, 3, "RADEON_PP_CNTL"},
534 {RADEON_RB3D_COLORPITCH, 1, "RADEON_RB3D_COLORPITCH"},
535 {RADEON_RE_LINE_PATTERN, 2, "RADEON_RE_LINE_PATTERN"},
536 {RADEON_SE_LINE_WIDTH, 1, "RADEON_SE_LINE_WIDTH"},
537 {RADEON_PP_LUM_MATRIX, 1, "RADEON_PP_LUM_MATRIX"},
538 {RADEON_PP_ROT_MATRIX_0, 2, "RADEON_PP_ROT_MATRIX_0"},
539 {RADEON_RB3D_STENCILREFMASK, 3, "RADEON_RB3D_STENCILREFMASK"},
540 {RADEON_SE_VPORT_XSCALE, 6, "RADEON_SE_VPORT_XSCALE"},
541 {RADEON_SE_CNTL, 2, "RADEON_SE_CNTL"},
542 {RADEON_SE_CNTL_STATUS, 1, "RADEON_SE_CNTL_STATUS"},
543 {RADEON_RE_MISC, 1, "RADEON_RE_MISC"},
544 {RADEON_PP_TXFILTER_0, 6, "RADEON_PP_TXFILTER_0"},
545 {RADEON_PP_BORDER_COLOR_0, 1, "RADEON_PP_BORDER_COLOR_0"},
546 {RADEON_PP_TXFILTER_1, 6, "RADEON_PP_TXFILTER_1"},
547 {RADEON_PP_BORDER_COLOR_1, 1, "RADEON_PP_BORDER_COLOR_1"},
548 {RADEON_PP_TXFILTER_2, 6, "RADEON_PP_TXFILTER_2"},
549 {RADEON_PP_BORDER_COLOR_2, 1, "RADEON_PP_BORDER_COLOR_2"},
550 {RADEON_SE_ZBIAS_FACTOR, 2, "RADEON_SE_ZBIAS_FACTOR"},
551 {RADEON_SE_TCL_OUTPUT_VTX_FMT, 11, "RADEON_SE_TCL_OUTPUT_VTX_FMT"},
552 {RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED, 17,
553 "RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED"},
554 {R200_PP_TXCBLEND_0, 4, "R200_PP_TXCBLEND_0"},
555 {R200_PP_TXCBLEND_1, 4, "R200_PP_TXCBLEND_1"},
556 {R200_PP_TXCBLEND_2, 4, "R200_PP_TXCBLEND_2"},
557 {R200_PP_TXCBLEND_3, 4, "R200_PP_TXCBLEND_3"},
558 {R200_PP_TXCBLEND_4, 4, "R200_PP_TXCBLEND_4"},
559 {R200_PP_TXCBLEND_5, 4, "R200_PP_TXCBLEND_5"},
560 {R200_PP_TXCBLEND_6, 4, "R200_PP_TXCBLEND_6"},
561 {R200_PP_TXCBLEND_7, 4, "R200_PP_TXCBLEND_7"},
562 {R200_SE_TCL_LIGHT_MODEL_CTL_0, 6, "R200_SE_TCL_LIGHT_MODEL_CTL_0"},
563 {R200_PP_TFACTOR_0, 6, "R200_PP_TFACTOR_0"},
564 {R200_SE_VTX_FMT_0, 4, "R200_SE_VTX_FMT_0"},
565 {R200_SE_VAP_CNTL, 1, "R200_SE_VAP_CNTL"},
566 {R200_SE_TCL_MATRIX_SEL_0, 5, "R200_SE_TCL_MATRIX_SEL_0"},
567 {R200_SE_TCL_TEX_PROC_CTL_2, 5, "R200_SE_TCL_TEX_PROC_CTL_2"},
568 {R200_SE_TCL_UCP_VERT_BLEND_CTL, 1, "R200_SE_TCL_UCP_VERT_BLEND_CTL"},
569 {R200_PP_TXFILTER_0, 6, "R200_PP_TXFILTER_0"},
570 {R200_PP_TXFILTER_1, 6, "R200_PP_TXFILTER_1"},
571 {R200_PP_TXFILTER_2, 6, "R200_PP_TXFILTER_2"},
572 {R200_PP_TXFILTER_3, 6, "R200_PP_TXFILTER_3"},
573 {R200_PP_TXFILTER_4, 6, "R200_PP_TXFILTER_4"},
574 {R200_PP_TXFILTER_5, 6, "R200_PP_TXFILTER_5"},
575 {R200_PP_TXOFFSET_0, 1, "R200_PP_TXOFFSET_0"},
576 {R200_PP_TXOFFSET_1, 1, "R200_PP_TXOFFSET_1"},
577 {R200_PP_TXOFFSET_2, 1, "R200_PP_TXOFFSET_2"},
578 {R200_PP_TXOFFSET_3, 1, "R200_PP_TXOFFSET_3"},
579 {R200_PP_TXOFFSET_4, 1, "R200_PP_TXOFFSET_4"},
580 {R200_PP_TXOFFSET_5, 1, "R200_PP_TXOFFSET_5"},
581 {R200_SE_VTE_CNTL, 1, "R200_SE_VTE_CNTL"},
Dave Airlied985c102006-01-02 21:32:48 +1100582 {R200_SE_TCL_OUTPUT_VTX_COMP_SEL, 1,
583 "R200_SE_TCL_OUTPUT_VTX_COMP_SEL"},
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000584 {R200_PP_TAM_DEBUG3, 1, "R200_PP_TAM_DEBUG3"},
585 {R200_PP_CNTL_X, 1, "R200_PP_CNTL_X"},
586 {R200_RB3D_DEPTHXY_OFFSET, 1, "R200_RB3D_DEPTHXY_OFFSET"},
587 {R200_RE_AUX_SCISSOR_CNTL, 1, "R200_RE_AUX_SCISSOR_CNTL"},
588 {R200_RE_SCISSOR_TL_0, 2, "R200_RE_SCISSOR_TL_0"},
589 {R200_RE_SCISSOR_TL_1, 2, "R200_RE_SCISSOR_TL_1"},
590 {R200_RE_SCISSOR_TL_2, 2, "R200_RE_SCISSOR_TL_2"},
591 {R200_SE_VAP_CNTL_STATUS, 1, "R200_SE_VAP_CNTL_STATUS"},
592 {R200_SE_VTX_STATE_CNTL, 1, "R200_SE_VTX_STATE_CNTL"},
593 {R200_RE_POINTSIZE, 1, "R200_RE_POINTSIZE"},
594 {R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0, 4,
595 "R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0"},
596 {R200_PP_CUBIC_FACES_0, 1, "R200_PP_CUBIC_FACES_0"}, /* 61 */
Dave Airlied985c102006-01-02 21:32:48 +1100597 {R200_PP_CUBIC_OFFSET_F1_0, 5, "R200_PP_CUBIC_OFFSET_F1_0"}, /* 62 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000598 {R200_PP_CUBIC_FACES_1, 1, "R200_PP_CUBIC_FACES_1"},
599 {R200_PP_CUBIC_OFFSET_F1_1, 5, "R200_PP_CUBIC_OFFSET_F1_1"},
600 {R200_PP_CUBIC_FACES_2, 1, "R200_PP_CUBIC_FACES_2"},
601 {R200_PP_CUBIC_OFFSET_F1_2, 5, "R200_PP_CUBIC_OFFSET_F1_2"},
602 {R200_PP_CUBIC_FACES_3, 1, "R200_PP_CUBIC_FACES_3"},
603 {R200_PP_CUBIC_OFFSET_F1_3, 5, "R200_PP_CUBIC_OFFSET_F1_3"},
604 {R200_PP_CUBIC_FACES_4, 1, "R200_PP_CUBIC_FACES_4"},
605 {R200_PP_CUBIC_OFFSET_F1_4, 5, "R200_PP_CUBIC_OFFSET_F1_4"},
606 {R200_PP_CUBIC_FACES_5, 1, "R200_PP_CUBIC_FACES_5"},
607 {R200_PP_CUBIC_OFFSET_F1_5, 5, "R200_PP_CUBIC_OFFSET_F1_5"},
608 {RADEON_PP_TEX_SIZE_0, 2, "RADEON_PP_TEX_SIZE_0"},
609 {RADEON_PP_TEX_SIZE_1, 2, "RADEON_PP_TEX_SIZE_1"},
610 {RADEON_PP_TEX_SIZE_2, 2, "RADEON_PP_TEX_SIZE_2"},
611 {R200_RB3D_BLENDCOLOR, 3, "R200_RB3D_BLENDCOLOR"},
612 {R200_SE_TCL_POINT_SPRITE_CNTL, 1, "R200_SE_TCL_POINT_SPRITE_CNTL"},
613 {RADEON_PP_CUBIC_FACES_0, 1, "RADEON_PP_CUBIC_FACES_0"},
614 {RADEON_PP_CUBIC_OFFSET_T0_0, 5, "RADEON_PP_CUBIC_OFFSET_T0_0"},
615 {RADEON_PP_CUBIC_FACES_1, 1, "RADEON_PP_CUBIC_FACES_1"},
616 {RADEON_PP_CUBIC_OFFSET_T1_0, 5, "RADEON_PP_CUBIC_OFFSET_T1_0"},
617 {RADEON_PP_CUBIC_FACES_2, 1, "RADEON_PP_CUBIC_FACES_2"},
618 {RADEON_PP_CUBIC_OFFSET_T2_0, 5, "RADEON_PP_CUBIC_OFFSET_T2_0"},
619 {R200_PP_TRI_PERF, 2, "R200_PP_TRI_PERF"},
Dave Airlied985c102006-01-02 21:32:48 +1100620 {R200_PP_AFS_0, 32, "R200_PP_AFS_0"}, /* 85 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000621 {R200_PP_AFS_1, 32, "R200_PP_AFS_1"},
622 {R200_PP_TFACTOR_0, 8, "R200_ATF_TFACTOR"},
623 {R200_PP_TXFILTER_0, 8, "R200_PP_TXCTLALL_0"},
624 {R200_PP_TXFILTER_1, 8, "R200_PP_TXCTLALL_1"},
625 {R200_PP_TXFILTER_2, 8, "R200_PP_TXCTLALL_2"},
626 {R200_PP_TXFILTER_3, 8, "R200_PP_TXCTLALL_3"},
627 {R200_PP_TXFILTER_4, 8, "R200_PP_TXCTLALL_4"},
628 {R200_PP_TXFILTER_5, 8, "R200_PP_TXCTLALL_5"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629};
630
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631/* ================================================================
632 * Performance monitoring functions
633 */
634
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000635static void radeon_clear_box(drm_radeon_private_t * dev_priv,
636 int x, int y, int w, int h, int r, int g, int b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637{
638 u32 color;
639 RING_LOCALS;
640
641 x += dev_priv->sarea_priv->boxes[0].x1;
642 y += dev_priv->sarea_priv->boxes[0].y1;
643
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000644 switch (dev_priv->color_fmt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 case RADEON_COLOR_FORMAT_RGB565:
646 color = (((r & 0xf8) << 8) |
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000647 ((g & 0xfc) << 3) | ((b & 0xf8) >> 3));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 break;
649 case RADEON_COLOR_FORMAT_ARGB8888:
650 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000651 color = (((0xff) << 24) | (r << 16) | (g << 8) | b);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 break;
653 }
654
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000655 BEGIN_RING(4);
656 RADEON_WAIT_UNTIL_3D_IDLE();
657 OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0));
658 OUT_RING(0xffffffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 ADVANCE_RING();
660
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000661 BEGIN_RING(6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000663 OUT_RING(CP_PACKET3(RADEON_CNTL_PAINT_MULTI, 4));
664 OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
665 RADEON_GMC_BRUSH_SOLID_COLOR |
666 (dev_priv->color_fmt << 8) |
667 RADEON_GMC_SRC_DATATYPE_COLOR |
668 RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000670 if (dev_priv->page_flipping && dev_priv->current_page == 1) {
671 OUT_RING(dev_priv->front_pitch_offset);
672 } else {
673 OUT_RING(dev_priv->back_pitch_offset);
674 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000676 OUT_RING(color);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000678 OUT_RING((x << 16) | y);
679 OUT_RING((w << 16) | h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
681 ADVANCE_RING();
682}
683
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000684static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685{
686 /* Collapse various things into a wait flag -- trying to
687 * guess if userspase slept -- better just to have them tell us.
688 */
689 if (dev_priv->stats.last_frame_reads > 1 ||
690 dev_priv->stats.last_clear_reads > dev_priv->stats.clears) {
691 dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
692 }
693
694 if (dev_priv->stats.freelist_loops) {
695 dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
696 }
697
698 /* Purple box for page flipping
699 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000700 if (dev_priv->stats.boxes & RADEON_BOX_FLIP)
701 radeon_clear_box(dev_priv, 4, 4, 8, 8, 255, 0, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
703 /* Red box if we have to wait for idle at any point
704 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000705 if (dev_priv->stats.boxes & RADEON_BOX_WAIT_IDLE)
706 radeon_clear_box(dev_priv, 16, 4, 8, 8, 255, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
708 /* Blue box: lost context?
709 */
710
711 /* Yellow box for texture swaps
712 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000713 if (dev_priv->stats.boxes & RADEON_BOX_TEXTURE_LOAD)
714 radeon_clear_box(dev_priv, 40, 4, 8, 8, 255, 255, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
716 /* Green box if hardware never idles (as far as we can tell)
717 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000718 if (!(dev_priv->stats.boxes & RADEON_BOX_DMA_IDLE))
719 radeon_clear_box(dev_priv, 64, 4, 8, 8, 0, 255, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000721 /* Draw bars indicating number of buffers allocated
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 * (not a great measure, easily confused)
723 */
724 if (dev_priv->stats.requested_bufs) {
725 if (dev_priv->stats.requested_bufs > 100)
726 dev_priv->stats.requested_bufs = 100;
727
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000728 radeon_clear_box(dev_priv, 4, 16,
729 dev_priv->stats.requested_bufs, 4,
730 196, 128, 128);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 }
732
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000733 memset(&dev_priv->stats, 0, sizeof(dev_priv->stats));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
735}
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000736
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737/* ================================================================
738 * CP command dispatch functions
739 */
740
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000741static void radeon_cp_dispatch_clear(drm_device_t * dev,
742 drm_radeon_clear_t * clear,
743 drm_radeon_clear_rect_t * depth_boxes)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744{
745 drm_radeon_private_t *dev_priv = dev->dev_private;
746 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
747 drm_radeon_depth_clear_t *depth_clear = &dev_priv->depth_clear;
748 int nbox = sarea_priv->nbox;
749 drm_clip_rect_t *pbox = sarea_priv->boxes;
750 unsigned int flags = clear->flags;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000751 u32 rb3d_cntl = 0, rb3d_stencilrefmask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 int i;
753 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000754 DRM_DEBUG("flags = 0x%x\n", flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
756 dev_priv->stats.clears++;
757
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000758 if (dev_priv->page_flipping && dev_priv->current_page == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 unsigned int tmp = flags;
760
761 flags &= ~(RADEON_FRONT | RADEON_BACK);
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000762 if (tmp & RADEON_FRONT)
763 flags |= RADEON_BACK;
764 if (tmp & RADEON_BACK)
765 flags |= RADEON_FRONT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 }
767
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000768 if (flags & (RADEON_FRONT | RADEON_BACK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000770 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
772 /* Ensure the 3D stream is idle before doing a
773 * 2D fill to clear the front or back buffer.
774 */
775 RADEON_WAIT_UNTIL_3D_IDLE();
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000776
777 OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0));
778 OUT_RING(clear->color_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
780 ADVANCE_RING();
781
782 /* Make sure we restore the 3D state next time.
783 */
784 dev_priv->sarea_priv->ctx_owner = 0;
785
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000786 for (i = 0; i < nbox; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 int x = pbox[i].x1;
788 int y = pbox[i].y1;
789 int w = pbox[i].x2 - x;
790 int h = pbox[i].y2 - y;
791
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000792 DRM_DEBUG("dispatch clear %d,%d-%d,%d flags 0x%x\n",
793 x, y, w, h, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000795 if (flags & RADEON_FRONT) {
796 BEGIN_RING(6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000798 OUT_RING(CP_PACKET3
799 (RADEON_CNTL_PAINT_MULTI, 4));
800 OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
801 RADEON_GMC_BRUSH_SOLID_COLOR |
802 (dev_priv->
803 color_fmt << 8) |
804 RADEON_GMC_SRC_DATATYPE_COLOR |
805 RADEON_ROP3_P |
806 RADEON_GMC_CLR_CMP_CNTL_DIS);
807
808 OUT_RING(dev_priv->front_pitch_offset);
809 OUT_RING(clear->clear_color);
810
811 OUT_RING((x << 16) | y);
812 OUT_RING((w << 16) | h);
813
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 ADVANCE_RING();
815 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000817 if (flags & RADEON_BACK) {
818 BEGIN_RING(6);
819
820 OUT_RING(CP_PACKET3
821 (RADEON_CNTL_PAINT_MULTI, 4));
822 OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
823 RADEON_GMC_BRUSH_SOLID_COLOR |
824 (dev_priv->
825 color_fmt << 8) |
826 RADEON_GMC_SRC_DATATYPE_COLOR |
827 RADEON_ROP3_P |
828 RADEON_GMC_CLR_CMP_CNTL_DIS);
829
830 OUT_RING(dev_priv->back_pitch_offset);
831 OUT_RING(clear->clear_color);
832
833 OUT_RING((x << 16) | y);
834 OUT_RING((w << 16) | h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
836 ADVANCE_RING();
837 }
838 }
839 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000840
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 /* hyper z clear */
842 /* no docs available, based on reverse engeneering by Stephane Marchesin */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000843 if ((flags & (RADEON_DEPTH | RADEON_STENCIL))
844 && (flags & RADEON_CLEAR_FASTZ)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
846 int i;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000847 int depthpixperline =
848 dev_priv->depth_fmt ==
849 RADEON_DEPTH_FORMAT_16BIT_INT_Z ? (dev_priv->depth_pitch /
850 2) : (dev_priv->
851 depth_pitch / 4);
852
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 u32 clearmask;
854
855 u32 tempRB3D_DEPTHCLEARVALUE = clear->clear_depth |
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000856 ((clear->depth_mask & 0xff) << 24);
857
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 /* Make sure we restore the 3D state next time.
859 * we haven't touched any "normal" state - still need this?
860 */
861 dev_priv->sarea_priv->ctx_owner = 0;
862
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000863 if ((dev_priv->flags & CHIP_HAS_HIERZ)
864 && (flags & RADEON_USE_HIERZ)) {
865 /* FIXME : reverse engineer that for Rx00 cards */
866 /* FIXME : the mask supposedly contains low-res z values. So can't set
867 just to the max (0xff? or actually 0x3fff?), need to take z clear
868 value into account? */
869 /* pattern seems to work for r100, though get slight
870 rendering errors with glxgears. If hierz is not enabled for r100,
871 only 4 bits which indicate clear (15,16,31,32, all zero) matter, the
872 other ones are ignored, and the same clear mask can be used. That's
873 very different behaviour than R200 which needs different clear mask
874 and different number of tiles to clear if hierz is enabled or not !?!
875 */
876 clearmask = (0xff << 22) | (0xff << 6) | 0x003f003f;
877 } else {
878 /* clear mask : chooses the clearing pattern.
879 rv250: could be used to clear only parts of macrotiles
880 (but that would get really complicated...)?
881 bit 0 and 1 (either or both of them ?!?!) are used to
882 not clear tile (or maybe one of the bits indicates if the tile is
883 compressed or not), bit 2 and 3 to not clear tile 1,...,.
884 Pattern is as follows:
885 | 0,1 | 4,5 | 8,9 |12,13|16,17|20,21|24,25|28,29|
886 bits -------------------------------------------------
887 | 2,3 | 6,7 |10,11|14,15|18,19|22,23|26,27|30,31|
888 rv100: clearmask covers 2x8 4x1 tiles, but one clear still
889 covers 256 pixels ?!?
890 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 clearmask = 0x0;
892 }
893
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000894 BEGIN_RING(8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 RADEON_WAIT_UNTIL_2D_IDLE();
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000896 OUT_RING_REG(RADEON_RB3D_DEPTHCLEARVALUE,
897 tempRB3D_DEPTHCLEARVALUE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 /* what offset is this exactly ? */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000899 OUT_RING_REG(RADEON_RB3D_ZMASKOFFSET, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 /* need ctlstat, otherwise get some strange black flickering */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000901 OUT_RING_REG(RADEON_RB3D_ZCACHE_CTLSTAT,
902 RADEON_RB3D_ZC_FLUSH_ALL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 ADVANCE_RING();
904
905 for (i = 0; i < nbox; i++) {
906 int tileoffset, nrtilesx, nrtilesy, j;
907 /* it looks like r200 needs rv-style clears, at least if hierz is not enabled? */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000908 if ((dev_priv->flags & CHIP_HAS_HIERZ)
909 && !(dev_priv->microcode_version == UCODE_R200)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 /* FIXME : figure this out for r200 (when hierz is enabled). Or
911 maybe r200 actually doesn't need to put the low-res z value into
912 the tile cache like r100, but just needs to clear the hi-level z-buffer?
913 Works for R100, both with hierz and without.
914 R100 seems to operate on 2x1 8x8 tiles, but...
915 odd: offset/nrtiles need to be 64 pix (4 block) aligned? Potentially
916 problematic with resolutions which are not 64 pix aligned? */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000917 tileoffset =
918 ((pbox[i].y1 >> 3) * depthpixperline +
919 pbox[i].x1) >> 6;
920 nrtilesx =
921 ((pbox[i].x2 & ~63) -
922 (pbox[i].x1 & ~63)) >> 4;
923 nrtilesy =
924 (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 for (j = 0; j <= nrtilesy; j++) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000926 BEGIN_RING(4);
927 OUT_RING(CP_PACKET3
928 (RADEON_3D_CLEAR_ZMASK, 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 /* first tile */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000930 OUT_RING(tileoffset * 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 /* the number of tiles to clear */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000932 OUT_RING(nrtilesx + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 /* clear mask : chooses the clearing pattern. */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000934 OUT_RING(clearmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 ADVANCE_RING();
936 tileoffset += depthpixperline >> 6;
937 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000938 } else if (dev_priv->microcode_version == UCODE_R200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 /* works for rv250. */
940 /* find first macro tile (8x2 4x4 z-pixels on rv250) */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000941 tileoffset =
942 ((pbox[i].y1 >> 3) * depthpixperline +
943 pbox[i].x1) >> 5;
944 nrtilesx =
945 (pbox[i].x2 >> 5) - (pbox[i].x1 >> 5);
946 nrtilesy =
947 (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 for (j = 0; j <= nrtilesy; j++) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000949 BEGIN_RING(4);
950 OUT_RING(CP_PACKET3
951 (RADEON_3D_CLEAR_ZMASK, 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 /* first tile */
953 /* judging by the first tile offset needed, could possibly
954 directly address/clear 4x4 tiles instead of 8x2 * 4x4
955 macro tiles, though would still need clear mask for
956 right/bottom if truely 4x4 granularity is desired ? */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000957 OUT_RING(tileoffset * 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 /* the number of tiles to clear */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000959 OUT_RING(nrtilesx + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 /* clear mask : chooses the clearing pattern. */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000961 OUT_RING(clearmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 ADVANCE_RING();
963 tileoffset += depthpixperline >> 5;
964 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000965 } else { /* rv 100 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 /* rv100 might not need 64 pix alignment, who knows */
967 /* offsets are, hmm, weird */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000968 tileoffset =
969 ((pbox[i].y1 >> 4) * depthpixperline +
970 pbox[i].x1) >> 6;
971 nrtilesx =
972 ((pbox[i].x2 & ~63) -
973 (pbox[i].x1 & ~63)) >> 4;
974 nrtilesy =
975 (pbox[i].y2 >> 4) - (pbox[i].y1 >> 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 for (j = 0; j <= nrtilesy; j++) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000977 BEGIN_RING(4);
978 OUT_RING(CP_PACKET3
979 (RADEON_3D_CLEAR_ZMASK, 2));
980 OUT_RING(tileoffset * 128);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 /* the number of tiles to clear */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000982 OUT_RING(nrtilesx + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 /* clear mask : chooses the clearing pattern. */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000984 OUT_RING(clearmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 ADVANCE_RING();
986 tileoffset += depthpixperline >> 6;
987 }
988 }
989 }
990
991 /* TODO don't always clear all hi-level z tiles */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000992 if ((dev_priv->flags & CHIP_HAS_HIERZ)
993 && (dev_priv->microcode_version == UCODE_R200)
994 && (flags & RADEON_USE_HIERZ))
995 /* r100 and cards without hierarchical z-buffer have no high-level z-buffer */
996 /* FIXME : the mask supposedly contains low-res z values. So can't set
997 just to the max (0xff? or actually 0x3fff?), need to take z clear
998 value into account? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001000 BEGIN_RING(4);
1001 OUT_RING(CP_PACKET3(RADEON_3D_CLEAR_HIZ, 2));
1002 OUT_RING(0x0); /* First tile */
1003 OUT_RING(0x3cc0);
1004 OUT_RING((0xff << 22) | (0xff << 6) | 0x003f003f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 ADVANCE_RING();
1006 }
1007 }
1008
1009 /* We have to clear the depth and/or stencil buffers by
1010 * rendering a quad into just those buffers. Thus, we have to
1011 * make sure the 3D engine is configured correctly.
1012 */
Dave Airlied985c102006-01-02 21:32:48 +11001013 else if ((dev_priv->microcode_version == UCODE_R200) &&
1014 (flags & (RADEON_DEPTH | RADEON_STENCIL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
1016 int tempPP_CNTL;
1017 int tempRE_CNTL;
1018 int tempRB3D_CNTL;
1019 int tempRB3D_ZSTENCILCNTL;
1020 int tempRB3D_STENCILREFMASK;
1021 int tempRB3D_PLANEMASK;
1022 int tempSE_CNTL;
1023 int tempSE_VTE_CNTL;
1024 int tempSE_VTX_FMT_0;
1025 int tempSE_VTX_FMT_1;
1026 int tempSE_VAP_CNTL;
1027 int tempRE_AUX_SCISSOR_CNTL;
1028
1029 tempPP_CNTL = 0;
1030 tempRE_CNTL = 0;
1031
1032 tempRB3D_CNTL = depth_clear->rb3d_cntl;
1033
1034 tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl;
1035 tempRB3D_STENCILREFMASK = 0x0;
1036
1037 tempSE_CNTL = depth_clear->se_cntl;
1038
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 /* Disable TCL */
1040
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001041 tempSE_VAP_CNTL = ( /* SE_VAP_CNTL__FORCE_W_TO_ONE_MASK | */
1042 (0x9 <<
1043 SE_VAP_CNTL__VF_MAX_VTX_NUM__SHIFT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
1045 tempRB3D_PLANEMASK = 0x0;
1046
1047 tempRE_AUX_SCISSOR_CNTL = 0x0;
1048
1049 tempSE_VTE_CNTL =
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001050 SE_VTE_CNTL__VTX_XY_FMT_MASK | SE_VTE_CNTL__VTX_Z_FMT_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001052 /* Vertex format (X, Y, Z, W) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 tempSE_VTX_FMT_0 =
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001054 SE_VTX_FMT_0__VTX_Z0_PRESENT_MASK |
1055 SE_VTX_FMT_0__VTX_W0_PRESENT_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 tempSE_VTX_FMT_1 = 0x0;
1057
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001058 /*
1059 * Depth buffer specific enables
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 */
1061 if (flags & RADEON_DEPTH) {
1062 /* Enable depth buffer */
1063 tempRB3D_CNTL |= RADEON_Z_ENABLE;
1064 } else {
1065 /* Disable depth buffer */
1066 tempRB3D_CNTL &= ~RADEON_Z_ENABLE;
1067 }
1068
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001069 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 * Stencil buffer specific enables
1071 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001072 if (flags & RADEON_STENCIL) {
1073 tempRB3D_CNTL |= RADEON_STENCIL_ENABLE;
1074 tempRB3D_STENCILREFMASK = clear->depth_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 } else {
1076 tempRB3D_CNTL &= ~RADEON_STENCIL_ENABLE;
1077 tempRB3D_STENCILREFMASK = 0x00000000;
1078 }
1079
1080 if (flags & RADEON_USE_COMP_ZBUF) {
1081 tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE |
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001082 RADEON_Z_DECOMPRESSION_ENABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 }
1084 if (flags & RADEON_USE_HIERZ) {
1085 tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE;
1086 }
1087
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001088 BEGIN_RING(26);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 RADEON_WAIT_UNTIL_2D_IDLE();
1090
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001091 OUT_RING_REG(RADEON_PP_CNTL, tempPP_CNTL);
1092 OUT_RING_REG(R200_RE_CNTL, tempRE_CNTL);
1093 OUT_RING_REG(RADEON_RB3D_CNTL, tempRB3D_CNTL);
1094 OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL);
1095 OUT_RING_REG(RADEON_RB3D_STENCILREFMASK,
1096 tempRB3D_STENCILREFMASK);
1097 OUT_RING_REG(RADEON_RB3D_PLANEMASK, tempRB3D_PLANEMASK);
1098 OUT_RING_REG(RADEON_SE_CNTL, tempSE_CNTL);
1099 OUT_RING_REG(R200_SE_VTE_CNTL, tempSE_VTE_CNTL);
1100 OUT_RING_REG(R200_SE_VTX_FMT_0, tempSE_VTX_FMT_0);
1101 OUT_RING_REG(R200_SE_VTX_FMT_1, tempSE_VTX_FMT_1);
1102 OUT_RING_REG(R200_SE_VAP_CNTL, tempSE_VAP_CNTL);
1103 OUT_RING_REG(R200_RE_AUX_SCISSOR_CNTL, tempRE_AUX_SCISSOR_CNTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 ADVANCE_RING();
1105
1106 /* Make sure we restore the 3D state next time.
1107 */
1108 dev_priv->sarea_priv->ctx_owner = 0;
1109
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001110 for (i = 0; i < nbox; i++) {
1111
1112 /* Funny that this should be required --
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 * sets top-left?
1114 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001115 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001117 BEGIN_RING(14);
1118 OUT_RING(CP_PACKET3(R200_3D_DRAW_IMMD_2, 12));
1119 OUT_RING((RADEON_PRIM_TYPE_RECT_LIST |
1120 RADEON_PRIM_WALK_RING |
1121 (3 << RADEON_NUM_VERTICES_SHIFT)));
1122 OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1123 OUT_RING(depth_boxes[i].ui[CLEAR_Y1]);
1124 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1125 OUT_RING(0x3f800000);
1126 OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1127 OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1128 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1129 OUT_RING(0x3f800000);
1130 OUT_RING(depth_boxes[i].ui[CLEAR_X2]);
1131 OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1132 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1133 OUT_RING(0x3f800000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 ADVANCE_RING();
1135 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001136 } else if ((flags & (RADEON_DEPTH | RADEON_STENCIL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137
1138 int tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl;
1139
1140 rb3d_cntl = depth_clear->rb3d_cntl;
1141
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001142 if (flags & RADEON_DEPTH) {
1143 rb3d_cntl |= RADEON_Z_ENABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 } else {
1145 rb3d_cntl &= ~RADEON_Z_ENABLE;
1146 }
1147
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001148 if (flags & RADEON_STENCIL) {
1149 rb3d_cntl |= RADEON_STENCIL_ENABLE;
1150 rb3d_stencilrefmask = clear->depth_mask; /* misnamed field */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 } else {
1152 rb3d_cntl &= ~RADEON_STENCIL_ENABLE;
1153 rb3d_stencilrefmask = 0x00000000;
1154 }
1155
1156 if (flags & RADEON_USE_COMP_ZBUF) {
1157 tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE |
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001158 RADEON_Z_DECOMPRESSION_ENABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 }
1160 if (flags & RADEON_USE_HIERZ) {
1161 tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE;
1162 }
1163
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001164 BEGIN_RING(13);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 RADEON_WAIT_UNTIL_2D_IDLE();
1166
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001167 OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 1));
1168 OUT_RING(0x00000000);
1169 OUT_RING(rb3d_cntl);
1170
1171 OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL);
1172 OUT_RING_REG(RADEON_RB3D_STENCILREFMASK, rb3d_stencilrefmask);
1173 OUT_RING_REG(RADEON_RB3D_PLANEMASK, 0x00000000);
1174 OUT_RING_REG(RADEON_SE_CNTL, depth_clear->se_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 ADVANCE_RING();
1176
1177 /* Make sure we restore the 3D state next time.
1178 */
1179 dev_priv->sarea_priv->ctx_owner = 0;
1180
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001181 for (i = 0; i < nbox; i++) {
1182
1183 /* Funny that this should be required --
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 * sets top-left?
1185 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001186 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001188 BEGIN_RING(15);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001190 OUT_RING(CP_PACKET3(RADEON_3D_DRAW_IMMD, 13));
1191 OUT_RING(RADEON_VTX_Z_PRESENT |
1192 RADEON_VTX_PKCOLOR_PRESENT);
1193 OUT_RING((RADEON_PRIM_TYPE_RECT_LIST |
1194 RADEON_PRIM_WALK_RING |
1195 RADEON_MAOS_ENABLE |
1196 RADEON_VTX_FMT_RADEON_MODE |
1197 (3 << RADEON_NUM_VERTICES_SHIFT)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001199 OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1200 OUT_RING(depth_boxes[i].ui[CLEAR_Y1]);
1201 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1202 OUT_RING(0x0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001204 OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1205 OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1206 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1207 OUT_RING(0x0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001209 OUT_RING(depth_boxes[i].ui[CLEAR_X2]);
1210 OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1211 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1212 OUT_RING(0x0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213
1214 ADVANCE_RING();
1215 }
1216 }
1217
1218 /* Increment the clear counter. The client-side 3D driver must
1219 * wait on this value before performing the clear ioctl. We
1220 * need this because the card's so damned fast...
1221 */
1222 dev_priv->sarea_priv->last_clear++;
1223
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001224 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001226 RADEON_CLEAR_AGE(dev_priv->sarea_priv->last_clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 RADEON_WAIT_UNTIL_IDLE();
1228
1229 ADVANCE_RING();
1230}
1231
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001232static void radeon_cp_dispatch_swap(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233{
1234 drm_radeon_private_t *dev_priv = dev->dev_private;
1235 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
1236 int nbox = sarea_priv->nbox;
1237 drm_clip_rect_t *pbox = sarea_priv->boxes;
1238 int i;
1239 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001240 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241
1242 /* Do some trivial performance monitoring...
1243 */
1244 if (dev_priv->do_boxes)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001245 radeon_cp_performance_boxes(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
1247 /* Wait for the 3D stream to idle before dispatching the bitblt.
1248 * This will prevent data corruption between the two streams.
1249 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001250 BEGIN_RING(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
1252 RADEON_WAIT_UNTIL_3D_IDLE();
1253
1254 ADVANCE_RING();
1255
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001256 for (i = 0; i < nbox; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 int x = pbox[i].x1;
1258 int y = pbox[i].y1;
1259 int w = pbox[i].x2 - x;
1260 int h = pbox[i].y2 - y;
1261
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001262 DRM_DEBUG("dispatch swap %d,%d-%d,%d\n", x, y, w, h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001264 BEGIN_RING(7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001266 OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
1267 OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
1268 RADEON_GMC_DST_PITCH_OFFSET_CNTL |
1269 RADEON_GMC_BRUSH_NONE |
1270 (dev_priv->color_fmt << 8) |
1271 RADEON_GMC_SRC_DATATYPE_COLOR |
1272 RADEON_ROP3_S |
1273 RADEON_DP_SRC_SOURCE_MEMORY |
1274 RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
1275
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 /* Make this work even if front & back are flipped:
1277 */
1278 if (dev_priv->current_page == 0) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001279 OUT_RING(dev_priv->back_pitch_offset);
1280 OUT_RING(dev_priv->front_pitch_offset);
1281 } else {
1282 OUT_RING(dev_priv->front_pitch_offset);
1283 OUT_RING(dev_priv->back_pitch_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 }
1285
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001286 OUT_RING((x << 16) | y);
1287 OUT_RING((x << 16) | y);
1288 OUT_RING((w << 16) | h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
1290 ADVANCE_RING();
1291 }
1292
1293 /* Increment the frame counter. The client-side 3D driver must
1294 * throttle the framerate by waiting for this value before
1295 * performing the swapbuffer ioctl.
1296 */
1297 dev_priv->sarea_priv->last_frame++;
1298
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001299 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001301 RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 RADEON_WAIT_UNTIL_2D_IDLE();
1303
1304 ADVANCE_RING();
1305}
1306
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001307static void radeon_cp_dispatch_flip(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308{
1309 drm_radeon_private_t *dev_priv = dev->dev_private;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001310 drm_sarea_t *sarea = (drm_sarea_t *) dev_priv->sarea->handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 int offset = (dev_priv->current_page == 1)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001312 ? dev_priv->front_offset : dev_priv->back_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001314 DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
1315 __FUNCTION__,
1316 dev_priv->current_page, dev_priv->sarea_priv->pfCurrentPage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
1318 /* Do some trivial performance monitoring...
1319 */
1320 if (dev_priv->do_boxes) {
1321 dev_priv->stats.boxes |= RADEON_BOX_FLIP;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001322 radeon_cp_performance_boxes(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 }
1324
1325 /* Update the frame offsets for both CRTCs
1326 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001327 BEGIN_RING(6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
1329 RADEON_WAIT_UNTIL_3D_IDLE();
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001330 OUT_RING_REG(RADEON_CRTC_OFFSET,
1331 ((sarea->frame.y * dev_priv->front_pitch +
1332 sarea->frame.x * (dev_priv->color_fmt - 2)) & ~7)
1333 + offset);
1334 OUT_RING_REG(RADEON_CRTC2_OFFSET, dev_priv->sarea_priv->crtc2_base
1335 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336
1337 ADVANCE_RING();
1338
1339 /* Increment the frame counter. The client-side 3D driver must
1340 * throttle the framerate by waiting for this value before
1341 * performing the swapbuffer ioctl.
1342 */
1343 dev_priv->sarea_priv->last_frame++;
1344 dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page =
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001345 1 - dev_priv->current_page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001347 BEGIN_RING(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001349 RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350
1351 ADVANCE_RING();
1352}
1353
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001354static int bad_prim_vertex_nr(int primitive, int nr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355{
1356 switch (primitive & RADEON_PRIM_TYPE_MASK) {
1357 case RADEON_PRIM_TYPE_NONE:
1358 case RADEON_PRIM_TYPE_POINT:
1359 return nr < 1;
1360 case RADEON_PRIM_TYPE_LINE:
1361 return (nr & 1) || nr == 0;
1362 case RADEON_PRIM_TYPE_LINE_STRIP:
1363 return nr < 2;
1364 case RADEON_PRIM_TYPE_TRI_LIST:
1365 case RADEON_PRIM_TYPE_3VRT_POINT_LIST:
1366 case RADEON_PRIM_TYPE_3VRT_LINE_LIST:
1367 case RADEON_PRIM_TYPE_RECT_LIST:
1368 return nr % 3 || nr == 0;
1369 case RADEON_PRIM_TYPE_TRI_FAN:
1370 case RADEON_PRIM_TYPE_TRI_STRIP:
1371 return nr < 3;
1372 default:
1373 return 1;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001374 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375}
1376
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377typedef struct {
1378 unsigned int start;
1379 unsigned int finish;
1380 unsigned int prim;
1381 unsigned int numverts;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001382 unsigned int offset;
1383 unsigned int vc_format;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384} drm_radeon_tcl_prim_t;
1385
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001386static void radeon_cp_dispatch_vertex(drm_device_t * dev,
1387 drm_buf_t * buf,
1388 drm_radeon_tcl_prim_t * prim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389{
1390 drm_radeon_private_t *dev_priv = dev->dev_private;
1391 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
1392 int offset = dev_priv->gart_buffers_offset + buf->offset + prim->start;
1393 int numverts = (int)prim->numverts;
1394 int nbox = sarea_priv->nbox;
1395 int i = 0;
1396 RING_LOCALS;
1397
1398 DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d %d verts\n",
1399 prim->prim,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001400 prim->vc_format, prim->start, prim->finish, prim->numverts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001402 if (bad_prim_vertex_nr(prim->prim, prim->numverts)) {
1403 DRM_ERROR("bad prim %x numverts %d\n",
1404 prim->prim, prim->numverts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 return;
1406 }
1407
1408 do {
1409 /* Emit the next cliprect */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001410 if (i < nbox) {
1411 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 }
1413
1414 /* Emit the vertex buffer rendering commands */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001415 BEGIN_RING(5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001417 OUT_RING(CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, 3));
1418 OUT_RING(offset);
1419 OUT_RING(numverts);
1420 OUT_RING(prim->vc_format);
1421 OUT_RING(prim->prim | RADEON_PRIM_WALK_LIST |
1422 RADEON_COLOR_ORDER_RGBA |
1423 RADEON_VTX_FMT_RADEON_MODE |
1424 (numverts << RADEON_NUM_VERTICES_SHIFT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425
1426 ADVANCE_RING();
1427
1428 i++;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001429 } while (i < nbox);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430}
1431
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001432static void radeon_cp_discard_buffer(drm_device_t * dev, drm_buf_t * buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433{
1434 drm_radeon_private_t *dev_priv = dev->dev_private;
1435 drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
1436 RING_LOCALS;
1437
1438 buf_priv->age = ++dev_priv->sarea_priv->last_dispatch;
1439
1440 /* Emit the vertex buffer age */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001441 BEGIN_RING(2);
1442 RADEON_DISPATCH_AGE(buf_priv->age);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 ADVANCE_RING();
1444
1445 buf->pending = 1;
1446 buf->used = 0;
1447}
1448
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001449static void radeon_cp_dispatch_indirect(drm_device_t * dev,
1450 drm_buf_t * buf, int start, int end)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451{
1452 drm_radeon_private_t *dev_priv = dev->dev_private;
1453 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001454 DRM_DEBUG("indirect: buf=%d s=0x%x e=0x%x\n", buf->idx, start, end);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001456 if (start != end) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 int offset = (dev_priv->gart_buffers_offset
1458 + buf->offset + start);
1459 int dwords = (end - start + 3) / sizeof(u32);
1460
1461 /* Indirect buffer data must be an even number of
1462 * dwords, so if we've been given an odd number we must
1463 * pad the data with a Type-2 CP packet.
1464 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001465 if (dwords & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 u32 *data = (u32 *)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001467 ((char *)dev->agp_buffer_map->handle
1468 + buf->offset + start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 data[dwords++] = RADEON_CP_PACKET2;
1470 }
1471
1472 /* Fire off the indirect buffer */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001473 BEGIN_RING(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001475 OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1));
1476 OUT_RING(offset);
1477 OUT_RING(dwords);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478
1479 ADVANCE_RING();
1480 }
1481}
1482
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001483static void radeon_cp_dispatch_indices(drm_device_t * dev,
1484 drm_buf_t * elt_buf,
1485 drm_radeon_tcl_prim_t * prim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486{
1487 drm_radeon_private_t *dev_priv = dev->dev_private;
1488 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
1489 int offset = dev_priv->gart_buffers_offset + prim->offset;
1490 u32 *data;
1491 int dwords;
1492 int i = 0;
1493 int start = prim->start + RADEON_INDEX_PRIM_OFFSET;
1494 int count = (prim->finish - start) / sizeof(u16);
1495 int nbox = sarea_priv->nbox;
1496
1497 DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d offset: %x nr %d\n",
1498 prim->prim,
1499 prim->vc_format,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001500 prim->start, prim->finish, prim->offset, prim->numverts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001502 if (bad_prim_vertex_nr(prim->prim, count)) {
1503 DRM_ERROR("bad prim %x count %d\n", prim->prim, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 return;
1505 }
1506
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001507 if (start >= prim->finish || (prim->start & 0x7)) {
1508 DRM_ERROR("buffer prim %d\n", prim->prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 return;
1510 }
1511
1512 dwords = (prim->finish - prim->start + 3) / sizeof(u32);
1513
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001514 data = (u32 *) ((char *)dev->agp_buffer_map->handle +
1515 elt_buf->offset + prim->start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001517 data[0] = CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, dwords - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 data[1] = offset;
1519 data[2] = prim->numverts;
1520 data[3] = prim->vc_format;
1521 data[4] = (prim->prim |
1522 RADEON_PRIM_WALK_IND |
1523 RADEON_COLOR_ORDER_RGBA |
1524 RADEON_VTX_FMT_RADEON_MODE |
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001525 (count << RADEON_NUM_VERTICES_SHIFT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526
1527 do {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001528 if (i < nbox)
1529 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001531 radeon_cp_dispatch_indirect(dev, elt_buf,
1532 prim->start, prim->finish);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533
1534 i++;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001535 } while (i < nbox);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536
1537}
1538
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001539#define RADEON_MAX_TEXTURE_SIZE RADEON_BUFFER_SIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001541static int radeon_cp_dispatch_texture(DRMFILE filp,
1542 drm_device_t * dev,
1543 drm_radeon_texture_t * tex,
1544 drm_radeon_tex_image_t * image)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545{
1546 drm_radeon_private_t *dev_priv = dev->dev_private;
1547 drm_file_t *filp_priv;
1548 drm_buf_t *buf;
1549 u32 format;
1550 u32 *buffer;
1551 const u8 __user *data;
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001552 int size, dwords, tex_width, blit_width, spitch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 u32 height;
1554 int i;
1555 u32 texpitch, microtile;
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001556 u32 offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 RING_LOCALS;
1558
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001559 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001561 if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &tex->offset)) {
1562 DRM_ERROR("Invalid destination offset\n");
1563 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 }
1565
1566 dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD;
1567
1568 /* Flush the pixel cache. This ensures no pixel data gets mixed
1569 * up with the texture data from the host data blit, otherwise
1570 * part of the texture image may be corrupted.
1571 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001572 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 RADEON_FLUSH_CACHE();
1574 RADEON_WAIT_UNTIL_IDLE();
1575 ADVANCE_RING();
1576
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 /* The compiler won't optimize away a division by a variable,
1578 * even if the only legal values are powers of two. Thus, we'll
1579 * use a shift instead.
1580 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001581 switch (tex->format) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 case RADEON_TXFORMAT_ARGB8888:
1583 case RADEON_TXFORMAT_RGBA8888:
1584 format = RADEON_COLOR_FORMAT_ARGB8888;
1585 tex_width = tex->width * 4;
1586 blit_width = image->width * 4;
1587 break;
1588 case RADEON_TXFORMAT_AI88:
1589 case RADEON_TXFORMAT_ARGB1555:
1590 case RADEON_TXFORMAT_RGB565:
1591 case RADEON_TXFORMAT_ARGB4444:
1592 case RADEON_TXFORMAT_VYUY422:
1593 case RADEON_TXFORMAT_YVYU422:
1594 format = RADEON_COLOR_FORMAT_RGB565;
1595 tex_width = tex->width * 2;
1596 blit_width = image->width * 2;
1597 break;
1598 case RADEON_TXFORMAT_I8:
1599 case RADEON_TXFORMAT_RGB332:
1600 format = RADEON_COLOR_FORMAT_CI8;
1601 tex_width = tex->width * 1;
1602 blit_width = image->width * 1;
1603 break;
1604 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001605 DRM_ERROR("invalid texture format %d\n", tex->format);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 return DRM_ERR(EINVAL);
1607 }
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001608 spitch = blit_width >> 6;
1609 if (spitch == 0 && image->height > 1)
1610 return DRM_ERR(EINVAL);
1611
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 texpitch = tex->pitch;
1613 if ((texpitch << 22) & RADEON_DST_TILE_MICRO) {
1614 microtile = 1;
1615 if (tex_width < 64) {
1616 texpitch &= ~(RADEON_DST_TILE_MICRO >> 22);
1617 /* we got tiled coordinates, untile them */
1618 image->x *= 2;
1619 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001620 } else
1621 microtile = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001623 DRM_DEBUG("tex=%dx%d blit=%d\n", tex_width, tex->height, blit_width);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624
1625 do {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001626 DRM_DEBUG("tex: ofs=0x%x p=%d f=%d x=%hd y=%hd w=%hd h=%hd\n",
1627 tex->offset >> 10, tex->pitch, tex->format,
1628 image->x, image->y, image->width, image->height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629
1630 /* Make a copy of some parameters in case we have to
1631 * update them for a multi-pass texture blit.
1632 */
1633 height = image->height;
1634 data = (const u8 __user *)image->data;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001635
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 size = height * blit_width;
1637
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001638 if (size > RADEON_MAX_TEXTURE_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 height = RADEON_MAX_TEXTURE_SIZE / blit_width;
1640 size = height * blit_width;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001641 } else if (size < 4 && size > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 size = 4;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001643 } else if (size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 return 0;
1645 }
1646
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001647 buf = radeon_freelist_get(dev);
1648 if (0 && !buf) {
1649 radeon_do_cp_idle(dev_priv);
1650 buf = radeon_freelist_get(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001652 if (!buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 DRM_DEBUG("radeon_cp_dispatch_texture: EAGAIN\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001654 if (DRM_COPY_TO_USER(tex->image, image, sizeof(*image)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 return DRM_ERR(EFAULT);
1656 return DRM_ERR(EAGAIN);
1657 }
1658
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 /* Dispatch the indirect buffer.
1660 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001661 buffer =
1662 (u32 *) ((char *)dev->agp_buffer_map->handle + buf->offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 dwords = size / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664
Dave Airlied985c102006-01-02 21:32:48 +11001665#define RADEON_COPY_MT(_buf, _data, _width) \
1666 do { \
1667 if (DRM_COPY_FROM_USER(_buf, _data, (_width))) {\
1668 DRM_ERROR("EFAULT on pad, %d bytes\n", (_width)); \
1669 return DRM_ERR(EFAULT); \
1670 } \
1671 } while(0)
1672
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 if (microtile) {
1674 /* texture micro tiling in use, minimum texture width is thus 16 bytes.
1675 however, we cannot use blitter directly for texture width < 64 bytes,
1676 since minimum tex pitch is 64 bytes and we need this to match
1677 the texture width, otherwise the blitter will tile it wrong.
1678 Thus, tiling manually in this case. Additionally, need to special
1679 case tex height = 1, since our actual image will have height 2
1680 and we need to ensure we don't read beyond the texture size
1681 from user space. */
1682 if (tex->height == 1) {
1683 if (tex_width >= 64 || tex_width <= 16) {
Dave Airlied985c102006-01-02 21:32:48 +11001684 RADEON_COPY_MT(buffer, data,
Dave Airlief8e0f292006-01-10 19:56:17 +11001685 (int)(tex_width * sizeof(u32)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 } else if (tex_width == 32) {
Dave Airlied985c102006-01-02 21:32:48 +11001687 RADEON_COPY_MT(buffer, data, 16);
1688 RADEON_COPY_MT(buffer + 8,
1689 data + 16, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 }
1691 } else if (tex_width >= 64 || tex_width == 16) {
Dave Airlied985c102006-01-02 21:32:48 +11001692 RADEON_COPY_MT(buffer, data,
Dave Airlief8e0f292006-01-10 19:56:17 +11001693 (int)(dwords * sizeof(u32)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 } else if (tex_width < 16) {
1695 for (i = 0; i < tex->height; i++) {
Dave Airlied985c102006-01-02 21:32:48 +11001696 RADEON_COPY_MT(buffer, data, tex_width);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 buffer += 4;
1698 data += tex_width;
1699 }
1700 } else if (tex_width == 32) {
1701 /* TODO: make sure this works when not fitting in one buffer
1702 (i.e. 32bytes x 2048...) */
1703 for (i = 0; i < tex->height; i += 2) {
Dave Airlied985c102006-01-02 21:32:48 +11001704 RADEON_COPY_MT(buffer, data, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 data += 16;
Dave Airlied985c102006-01-02 21:32:48 +11001706 RADEON_COPY_MT(buffer + 8, data, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 data += 16;
Dave Airlied985c102006-01-02 21:32:48 +11001708 RADEON_COPY_MT(buffer + 4, data, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 data += 16;
Dave Airlied985c102006-01-02 21:32:48 +11001710 RADEON_COPY_MT(buffer + 12, data, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 data += 16;
1712 buffer += 16;
1713 }
1714 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001715 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 if (tex_width >= 32) {
1717 /* Texture image width is larger than the minimum, so we
1718 * can upload it directly.
1719 */
Dave Airlied985c102006-01-02 21:32:48 +11001720 RADEON_COPY_MT(buffer, data,
Dave Airlief8e0f292006-01-10 19:56:17 +11001721 (int)(dwords * sizeof(u32)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 } else {
1723 /* Texture image width is less than the minimum, so we
1724 * need to pad out each image scanline to the minimum
1725 * width.
1726 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001727 for (i = 0; i < tex->height; i++) {
Dave Airlied985c102006-01-02 21:32:48 +11001728 RADEON_COPY_MT(buffer, data, tex_width);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 buffer += 8;
1730 data += tex_width;
1731 }
1732 }
1733 }
1734
Dave Airlied985c102006-01-02 21:32:48 +11001735#undef RADEON_COPY_MT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 buf->filp = filp;
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001737 buf->used = size;
1738 offset = dev_priv->gart_buffers_offset + buf->offset;
1739 BEGIN_RING(9);
1740 OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
1741 OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
1742 RADEON_GMC_DST_PITCH_OFFSET_CNTL |
1743 RADEON_GMC_BRUSH_NONE |
1744 (format << 8) |
1745 RADEON_GMC_SRC_DATATYPE_COLOR |
1746 RADEON_ROP3_S |
1747 RADEON_DP_SRC_SOURCE_MEMORY |
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001748 RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001749 OUT_RING((spitch << 22) | (offset >> 10));
1750 OUT_RING((texpitch << 22) | (tex->offset >> 10));
1751 OUT_RING(0);
1752 OUT_RING((image->x << 16) | image->y);
1753 OUT_RING((image->width << 16) | height);
1754 RADEON_WAIT_UNTIL_2D_IDLE();
1755 ADVANCE_RING();
1756
1757 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758
1759 /* Update the input parameters for next time */
1760 image->y += height;
1761 image->height -= height;
1762 image->data = (const u8 __user *)image->data + size;
1763 } while (image->height > 0);
1764
1765 /* Flush the pixel cache after the blit completes. This ensures
1766 * the texture data is written out to memory before rendering
1767 * continues.
1768 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001769 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770 RADEON_FLUSH_CACHE();
1771 RADEON_WAIT_UNTIL_2D_IDLE();
1772 ADVANCE_RING();
1773 return 0;
1774}
1775
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001776static void radeon_cp_dispatch_stipple(drm_device_t * dev, u32 * stipple)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777{
1778 drm_radeon_private_t *dev_priv = dev->dev_private;
1779 int i;
1780 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001781 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001783 BEGIN_RING(35);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001785 OUT_RING(CP_PACKET0(RADEON_RE_STIPPLE_ADDR, 0));
1786 OUT_RING(0x00000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001788 OUT_RING(CP_PACKET0_TABLE(RADEON_RE_STIPPLE_DATA, 31));
1789 for (i = 0; i < 32; i++) {
1790 OUT_RING(stipple[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 }
1792
1793 ADVANCE_RING();
1794}
1795
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001796static void radeon_apply_surface_regs(int surf_index,
Dave Airlied985c102006-01-02 21:32:48 +11001797 drm_radeon_private_t *dev_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798{
1799 if (!dev_priv->mmio)
1800 return;
1801
1802 radeon_do_cp_idle(dev_priv);
1803
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001804 RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * surf_index,
1805 dev_priv->surfaces[surf_index].flags);
1806 RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND + 16 * surf_index,
1807 dev_priv->surfaces[surf_index].lower);
1808 RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND + 16 * surf_index,
1809 dev_priv->surfaces[surf_index].upper);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810}
1811
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812/* Allocates a virtual surface
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001813 * doesn't always allocate a real surface, will stretch an existing
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 * surface when possible.
1815 *
1816 * Note that refcount can be at most 2, since during a free refcount=3
1817 * might mean we have to allocate a new surface which might not always
1818 * be available.
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001819 * For example : we allocate three contigous surfaces ABC. If B is
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 * freed, we suddenly need two surfaces to store A and C, which might
1821 * not always be available.
1822 */
Dave Airlied985c102006-01-02 21:32:48 +11001823static int alloc_surface(drm_radeon_surface_alloc_t *new,
1824 drm_radeon_private_t *dev_priv, DRMFILE filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825{
1826 struct radeon_virt_surface *s;
1827 int i;
1828 int virt_surface_index;
1829 uint32_t new_upper, new_lower;
1830
1831 new_lower = new->address;
1832 new_upper = new_lower + new->size - 1;
1833
1834 /* sanity check */
1835 if ((new_lower >= new_upper) || (new->flags == 0) || (new->size == 0) ||
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001836 ((new_upper & RADEON_SURF_ADDRESS_FIXED_MASK) !=
1837 RADEON_SURF_ADDRESS_FIXED_MASK)
1838 || ((new_lower & RADEON_SURF_ADDRESS_FIXED_MASK) != 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 return -1;
1840
1841 /* make sure there is no overlap with existing surfaces */
1842 for (i = 0; i < RADEON_MAX_SURFACES; i++) {
1843 if ((dev_priv->surfaces[i].refcount != 0) &&
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001844 (((new_lower >= dev_priv->surfaces[i].lower) &&
1845 (new_lower < dev_priv->surfaces[i].upper)) ||
1846 ((new_lower < dev_priv->surfaces[i].lower) &&
1847 (new_upper > dev_priv->surfaces[i].lower)))) {
1848 return -1;
1849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 }
1851
1852 /* find a virtual surface */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001853 for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 if (dev_priv->virt_surfaces[i].filp == 0)
1855 break;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001856 if (i == 2 * RADEON_MAX_SURFACES) {
1857 return -1;
1858 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 virt_surface_index = i;
1860
1861 /* try to reuse an existing surface */
1862 for (i = 0; i < RADEON_MAX_SURFACES; i++) {
1863 /* extend before */
1864 if ((dev_priv->surfaces[i].refcount == 1) &&
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001865 (new->flags == dev_priv->surfaces[i].flags) &&
1866 (new_upper + 1 == dev_priv->surfaces[i].lower)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 s = &(dev_priv->virt_surfaces[virt_surface_index]);
1868 s->surface_index = i;
1869 s->lower = new_lower;
1870 s->upper = new_upper;
1871 s->flags = new->flags;
1872 s->filp = filp;
1873 dev_priv->surfaces[i].refcount++;
1874 dev_priv->surfaces[i].lower = s->lower;
1875 radeon_apply_surface_regs(s->surface_index, dev_priv);
1876 return virt_surface_index;
1877 }
1878
1879 /* extend after */
1880 if ((dev_priv->surfaces[i].refcount == 1) &&
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001881 (new->flags == dev_priv->surfaces[i].flags) &&
1882 (new_lower == dev_priv->surfaces[i].upper + 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 s = &(dev_priv->virt_surfaces[virt_surface_index]);
1884 s->surface_index = i;
1885 s->lower = new_lower;
1886 s->upper = new_upper;
1887 s->flags = new->flags;
1888 s->filp = filp;
1889 dev_priv->surfaces[i].refcount++;
1890 dev_priv->surfaces[i].upper = s->upper;
1891 radeon_apply_surface_regs(s->surface_index, dev_priv);
1892 return virt_surface_index;
1893 }
1894 }
1895
1896 /* okay, we need a new one */
1897 for (i = 0; i < RADEON_MAX_SURFACES; i++) {
1898 if (dev_priv->surfaces[i].refcount == 0) {
1899 s = &(dev_priv->virt_surfaces[virt_surface_index]);
1900 s->surface_index = i;
1901 s->lower = new_lower;
1902 s->upper = new_upper;
1903 s->flags = new->flags;
1904 s->filp = filp;
1905 dev_priv->surfaces[i].refcount = 1;
1906 dev_priv->surfaces[i].lower = s->lower;
1907 dev_priv->surfaces[i].upper = s->upper;
1908 dev_priv->surfaces[i].flags = s->flags;
1909 radeon_apply_surface_regs(s->surface_index, dev_priv);
1910 return virt_surface_index;
1911 }
1912 }
1913
1914 /* we didn't find anything */
1915 return -1;
1916}
1917
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001918static int free_surface(DRMFILE filp, drm_radeon_private_t * dev_priv,
1919 int lower)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920{
1921 struct radeon_virt_surface *s;
1922 int i;
1923 /* find the virtual surface */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001924 for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 s = &(dev_priv->virt_surfaces[i]);
1926 if (s->filp) {
1927 if ((lower == s->lower) && (filp == s->filp)) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001928 if (dev_priv->surfaces[s->surface_index].
1929 lower == s->lower)
1930 dev_priv->surfaces[s->surface_index].
1931 lower = s->upper;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001933 if (dev_priv->surfaces[s->surface_index].
1934 upper == s->upper)
1935 dev_priv->surfaces[s->surface_index].
1936 upper = s->lower;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937
1938 dev_priv->surfaces[s->surface_index].refcount--;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001939 if (dev_priv->surfaces[s->surface_index].
1940 refcount == 0)
1941 dev_priv->surfaces[s->surface_index].
1942 flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 s->filp = NULL;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001944 radeon_apply_surface_regs(s->surface_index,
1945 dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 return 0;
1947 }
1948 }
1949 }
1950 return 1;
1951}
1952
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001953static void radeon_surfaces_release(DRMFILE filp,
1954 drm_radeon_private_t * dev_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955{
1956 int i;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001957 for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 if (dev_priv->virt_surfaces[i].filp == filp)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001959 free_surface(filp, dev_priv,
1960 dev_priv->virt_surfaces[i].lower);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 }
1962}
1963
1964/* ================================================================
1965 * IOCTL functions
1966 */
1967static int radeon_surface_alloc(DRM_IOCTL_ARGS)
1968{
1969 DRM_DEVICE;
1970 drm_radeon_private_t *dev_priv = dev->dev_private;
1971 drm_radeon_surface_alloc_t alloc;
1972
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001973 DRM_COPY_FROM_USER_IOCTL(alloc,
1974 (drm_radeon_surface_alloc_t __user *) data,
1975 sizeof(alloc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976
1977 if (alloc_surface(&alloc, dev_priv, filp) == -1)
1978 return DRM_ERR(EINVAL);
1979 else
1980 return 0;
1981}
1982
1983static int radeon_surface_free(DRM_IOCTL_ARGS)
1984{
1985 DRM_DEVICE;
1986 drm_radeon_private_t *dev_priv = dev->dev_private;
1987 drm_radeon_surface_free_t memfree;
1988
Dave Airlief15e92d2006-03-19 20:12:23 +11001989 DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_surface_free_t __user *) data,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001990 sizeof(memfree));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991
1992 if (free_surface(filp, dev_priv, memfree.address))
1993 return DRM_ERR(EINVAL);
1994 else
1995 return 0;
1996}
1997
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001998static int radeon_cp_clear(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999{
2000 DRM_DEVICE;
2001 drm_radeon_private_t *dev_priv = dev->dev_private;
2002 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2003 drm_radeon_clear_t clear;
2004 drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002005 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002007 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002009 DRM_COPY_FROM_USER_IOCTL(clear, (drm_radeon_clear_t __user *) data,
2010 sizeof(clear));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002012 RING_SPACE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002014 if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
2016
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002017 if (DRM_COPY_FROM_USER(&depth_boxes, clear.depth_boxes,
2018 sarea_priv->nbox * sizeof(depth_boxes[0])))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019 return DRM_ERR(EFAULT);
2020
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002021 radeon_cp_dispatch_clear(dev, &clear, depth_boxes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022
2023 COMMIT_RING();
2024 return 0;
2025}
2026
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027/* Not sure why this isn't set all the time:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002028 */
2029static int radeon_do_init_pageflip(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030{
2031 drm_radeon_private_t *dev_priv = dev->dev_private;
2032 RING_LOCALS;
2033
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002034 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002036 BEGIN_RING(6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 RADEON_WAIT_UNTIL_3D_IDLE();
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002038 OUT_RING(CP_PACKET0(RADEON_CRTC_OFFSET_CNTL, 0));
2039 OUT_RING(RADEON_READ(RADEON_CRTC_OFFSET_CNTL) |
2040 RADEON_CRTC_OFFSET_FLIP_CNTL);
2041 OUT_RING(CP_PACKET0(RADEON_CRTC2_OFFSET_CNTL, 0));
2042 OUT_RING(RADEON_READ(RADEON_CRTC2_OFFSET_CNTL) |
2043 RADEON_CRTC_OFFSET_FLIP_CNTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 ADVANCE_RING();
2045
2046 dev_priv->page_flipping = 1;
2047 dev_priv->current_page = 0;
2048 dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page;
2049
2050 return 0;
2051}
2052
2053/* Called whenever a client dies, from drm_release.
2054 * NOTE: Lock isn't necessarily held when this is called!
2055 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002056static int radeon_do_cleanup_pageflip(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057{
2058 drm_radeon_private_t *dev_priv = dev->dev_private;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002059 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060
2061 if (dev_priv->current_page != 0)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002062 radeon_cp_dispatch_flip(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063
2064 dev_priv->page_flipping = 0;
2065 return 0;
2066}
2067
2068/* Swapping and flipping are different operations, need different ioctls.
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002069 * They can & should be intermixed to support multiple 3d windows.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002071static int radeon_cp_flip(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072{
2073 DRM_DEVICE;
2074 drm_radeon_private_t *dev_priv = dev->dev_private;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002075 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002077 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002079 RING_SPACE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002081 if (!dev_priv->page_flipping)
2082 radeon_do_init_pageflip(dev);
2083
2084 radeon_cp_dispatch_flip(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085
2086 COMMIT_RING();
2087 return 0;
2088}
2089
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002090static int radeon_cp_swap(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091{
2092 DRM_DEVICE;
2093 drm_radeon_private_t *dev_priv = dev->dev_private;
2094 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002095 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002097 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002099 RING_SPACE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002101 if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
2103
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002104 radeon_cp_dispatch_swap(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 dev_priv->sarea_priv->ctx_owner = 0;
2106
2107 COMMIT_RING();
2108 return 0;
2109}
2110
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002111static int radeon_cp_vertex(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112{
2113 DRM_DEVICE;
2114 drm_radeon_private_t *dev_priv = dev->dev_private;
2115 drm_file_t *filp_priv;
2116 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2117 drm_device_dma_t *dma = dev->dma;
2118 drm_buf_t *buf;
2119 drm_radeon_vertex_t vertex;
2120 drm_radeon_tcl_prim_t prim;
2121
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002122 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002124 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002126 DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex_t __user *) data,
2127 sizeof(vertex));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002129 DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n",
2130 DRM_CURRENTPID, vertex.idx, vertex.count, vertex.discard);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002132 if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
2133 DRM_ERROR("buffer index %d (of %d max)\n",
2134 vertex.idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 return DRM_ERR(EINVAL);
2136 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002137 if (vertex.prim < 0 || vertex.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
2138 DRM_ERROR("buffer prim %d\n", vertex.prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 return DRM_ERR(EINVAL);
2140 }
2141
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002142 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2143 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144
2145 buf = dma->buflist[vertex.idx];
2146
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002147 if (buf->filp != filp) {
2148 DRM_ERROR("process %d using buffer owned by %p\n",
2149 DRM_CURRENTPID, buf->filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 return DRM_ERR(EINVAL);
2151 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002152 if (buf->pending) {
2153 DRM_ERROR("sending pending buffer %d\n", vertex.idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 return DRM_ERR(EINVAL);
2155 }
2156
2157 /* Build up a prim_t record:
2158 */
2159 if (vertex.count) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002160 buf->used = vertex.count; /* not used? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002162 if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
2163 if (radeon_emit_state(dev_priv, filp_priv,
2164 &sarea_priv->context_state,
2165 sarea_priv->tex_state,
2166 sarea_priv->dirty)) {
2167 DRM_ERROR("radeon_emit_state failed\n");
2168 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 }
2170
2171 sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
2172 RADEON_UPLOAD_TEX1IMAGES |
2173 RADEON_UPLOAD_TEX2IMAGES |
2174 RADEON_REQUIRE_QUIESCENCE);
2175 }
2176
2177 prim.start = 0;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002178 prim.finish = vertex.count; /* unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 prim.prim = vertex.prim;
2180 prim.numverts = vertex.count;
2181 prim.vc_format = dev_priv->sarea_priv->vc_format;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002182
2183 radeon_cp_dispatch_vertex(dev, buf, &prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 }
2185
2186 if (vertex.discard) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002187 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 }
2189
2190 COMMIT_RING();
2191 return 0;
2192}
2193
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002194static int radeon_cp_indices(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195{
2196 DRM_DEVICE;
2197 drm_radeon_private_t *dev_priv = dev->dev_private;
2198 drm_file_t *filp_priv;
2199 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2200 drm_device_dma_t *dma = dev->dma;
2201 drm_buf_t *buf;
2202 drm_radeon_indices_t elts;
2203 drm_radeon_tcl_prim_t prim;
2204 int count;
2205
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002206 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002208 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002210 DRM_COPY_FROM_USER_IOCTL(elts, (drm_radeon_indices_t __user *) data,
2211 sizeof(elts));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002213 DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n",
2214 DRM_CURRENTPID, elts.idx, elts.start, elts.end, elts.discard);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002216 if (elts.idx < 0 || elts.idx >= dma->buf_count) {
2217 DRM_ERROR("buffer index %d (of %d max)\n",
2218 elts.idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 return DRM_ERR(EINVAL);
2220 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002221 if (elts.prim < 0 || elts.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
2222 DRM_ERROR("buffer prim %d\n", elts.prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 return DRM_ERR(EINVAL);
2224 }
2225
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002226 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2227 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228
2229 buf = dma->buflist[elts.idx];
2230
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002231 if (buf->filp != filp) {
2232 DRM_ERROR("process %d using buffer owned by %p\n",
2233 DRM_CURRENTPID, buf->filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 return DRM_ERR(EINVAL);
2235 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002236 if (buf->pending) {
2237 DRM_ERROR("sending pending buffer %d\n", elts.idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 return DRM_ERR(EINVAL);
2239 }
2240
2241 count = (elts.end - elts.start) / sizeof(u16);
2242 elts.start -= RADEON_INDEX_PRIM_OFFSET;
2243
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002244 if (elts.start & 0x7) {
2245 DRM_ERROR("misaligned buffer 0x%x\n", elts.start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 return DRM_ERR(EINVAL);
2247 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002248 if (elts.start < buf->used) {
2249 DRM_ERROR("no header 0x%x - 0x%x\n", elts.start, buf->used);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 return DRM_ERR(EINVAL);
2251 }
2252
2253 buf->used = elts.end;
2254
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002255 if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
2256 if (radeon_emit_state(dev_priv, filp_priv,
2257 &sarea_priv->context_state,
2258 sarea_priv->tex_state,
2259 sarea_priv->dirty)) {
2260 DRM_ERROR("radeon_emit_state failed\n");
2261 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 }
2263
2264 sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
2265 RADEON_UPLOAD_TEX1IMAGES |
2266 RADEON_UPLOAD_TEX2IMAGES |
2267 RADEON_REQUIRE_QUIESCENCE);
2268 }
2269
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 /* Build up a prim_t record:
2271 */
2272 prim.start = elts.start;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002273 prim.finish = elts.end;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 prim.prim = elts.prim;
2275 prim.offset = 0; /* offset from start of dma buffers */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002276 prim.numverts = RADEON_MAX_VB_VERTS; /* duh */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 prim.vc_format = dev_priv->sarea_priv->vc_format;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002278
2279 radeon_cp_dispatch_indices(dev, buf, &prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 if (elts.discard) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002281 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 }
2283
2284 COMMIT_RING();
2285 return 0;
2286}
2287
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002288static int radeon_cp_texture(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289{
2290 DRM_DEVICE;
2291 drm_radeon_private_t *dev_priv = dev->dev_private;
2292 drm_radeon_texture_t tex;
2293 drm_radeon_tex_image_t image;
2294 int ret;
2295
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002296 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002298 DRM_COPY_FROM_USER_IOCTL(tex, (drm_radeon_texture_t __user *) data,
2299 sizeof(tex));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002301 if (tex.image == NULL) {
2302 DRM_ERROR("null texture image!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 return DRM_ERR(EINVAL);
2304 }
2305
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002306 if (DRM_COPY_FROM_USER(&image,
2307 (drm_radeon_tex_image_t __user *) tex.image,
2308 sizeof(image)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 return DRM_ERR(EFAULT);
2310
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002311 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2312 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002314 ret = radeon_cp_dispatch_texture(filp, dev, &tex, &image);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315
2316 COMMIT_RING();
2317 return ret;
2318}
2319
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002320static int radeon_cp_stipple(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321{
2322 DRM_DEVICE;
2323 drm_radeon_private_t *dev_priv = dev->dev_private;
2324 drm_radeon_stipple_t stipple;
2325 u32 mask[32];
2326
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002327 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002329 DRM_COPY_FROM_USER_IOCTL(stipple, (drm_radeon_stipple_t __user *) data,
2330 sizeof(stipple));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002332 if (DRM_COPY_FROM_USER(&mask, stipple.mask, 32 * sizeof(u32)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 return DRM_ERR(EFAULT);
2334
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002335 RING_SPACE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002337 radeon_cp_dispatch_stipple(dev, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338
2339 COMMIT_RING();
2340 return 0;
2341}
2342
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002343static int radeon_cp_indirect(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344{
2345 DRM_DEVICE;
2346 drm_radeon_private_t *dev_priv = dev->dev_private;
2347 drm_device_dma_t *dma = dev->dma;
2348 drm_buf_t *buf;
2349 drm_radeon_indirect_t indirect;
2350 RING_LOCALS;
2351
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002352 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002354 DRM_COPY_FROM_USER_IOCTL(indirect,
2355 (drm_radeon_indirect_t __user *) data,
2356 sizeof(indirect));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002358 DRM_DEBUG("indirect: idx=%d s=%d e=%d d=%d\n",
2359 indirect.idx, indirect.start, indirect.end, indirect.discard);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002361 if (indirect.idx < 0 || indirect.idx >= dma->buf_count) {
2362 DRM_ERROR("buffer index %d (of %d max)\n",
2363 indirect.idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 return DRM_ERR(EINVAL);
2365 }
2366
2367 buf = dma->buflist[indirect.idx];
2368
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002369 if (buf->filp != filp) {
2370 DRM_ERROR("process %d using buffer owned by %p\n",
2371 DRM_CURRENTPID, buf->filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 return DRM_ERR(EINVAL);
2373 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002374 if (buf->pending) {
2375 DRM_ERROR("sending pending buffer %d\n", indirect.idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 return DRM_ERR(EINVAL);
2377 }
2378
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002379 if (indirect.start < buf->used) {
2380 DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n",
2381 indirect.start, buf->used);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 return DRM_ERR(EINVAL);
2383 }
2384
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002385 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2386 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387
2388 buf->used = indirect.end;
2389
2390 /* Wait for the 3D stream to idle before the indirect buffer
2391 * containing 2D acceleration commands is processed.
2392 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002393 BEGIN_RING(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394
2395 RADEON_WAIT_UNTIL_3D_IDLE();
2396
2397 ADVANCE_RING();
2398
2399 /* Dispatch the indirect buffer full of commands from the
2400 * X server. This is insecure and is thus only available to
2401 * privileged clients.
2402 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002403 radeon_cp_dispatch_indirect(dev, buf, indirect.start, indirect.end);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 if (indirect.discard) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002405 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 }
2407
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 COMMIT_RING();
2409 return 0;
2410}
2411
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002412static int radeon_cp_vertex2(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413{
2414 DRM_DEVICE;
2415 drm_radeon_private_t *dev_priv = dev->dev_private;
2416 drm_file_t *filp_priv;
2417 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2418 drm_device_dma_t *dma = dev->dma;
2419 drm_buf_t *buf;
2420 drm_radeon_vertex2_t vertex;
2421 int i;
2422 unsigned char laststate;
2423
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002424 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002426 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002428 DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex2_t __user *) data,
2429 sizeof(vertex));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002431 DRM_DEBUG("pid=%d index=%d discard=%d\n",
2432 DRM_CURRENTPID, vertex.idx, vertex.discard);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002434 if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
2435 DRM_ERROR("buffer index %d (of %d max)\n",
2436 vertex.idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 return DRM_ERR(EINVAL);
2438 }
2439
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002440 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2441 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442
2443 buf = dma->buflist[vertex.idx];
2444
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002445 if (buf->filp != filp) {
2446 DRM_ERROR("process %d using buffer owned by %p\n",
2447 DRM_CURRENTPID, buf->filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 return DRM_ERR(EINVAL);
2449 }
2450
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002451 if (buf->pending) {
2452 DRM_ERROR("sending pending buffer %d\n", vertex.idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 return DRM_ERR(EINVAL);
2454 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002455
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
2457 return DRM_ERR(EINVAL);
2458
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002459 for (laststate = 0xff, i = 0; i < vertex.nr_prims; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 drm_radeon_prim_t prim;
2461 drm_radeon_tcl_prim_t tclprim;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002462
2463 if (DRM_COPY_FROM_USER(&prim, &vertex.prim[i], sizeof(prim)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 return DRM_ERR(EFAULT);
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002465
2466 if (prim.stateidx != laststate) {
2467 drm_radeon_state_t state;
2468
2469 if (DRM_COPY_FROM_USER(&state,
2470 &vertex.state[prim.stateidx],
2471 sizeof(state)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 return DRM_ERR(EFAULT);
2473
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002474 if (radeon_emit_state2(dev_priv, filp_priv, &state)) {
2475 DRM_ERROR("radeon_emit_state2 failed\n");
2476 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 }
2478
2479 laststate = prim.stateidx;
2480 }
2481
2482 tclprim.start = prim.start;
2483 tclprim.finish = prim.finish;
2484 tclprim.prim = prim.prim;
2485 tclprim.vc_format = prim.vc_format;
2486
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002487 if (prim.prim & RADEON_PRIM_WALK_IND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 tclprim.offset = prim.numverts * 64;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002489 tclprim.numverts = RADEON_MAX_VB_VERTS; /* duh */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002491 radeon_cp_dispatch_indices(dev, buf, &tclprim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 } else {
2493 tclprim.numverts = prim.numverts;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002494 tclprim.offset = 0; /* not used */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002496 radeon_cp_dispatch_vertex(dev, buf, &tclprim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002498
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499 if (sarea_priv->nbox == 1)
2500 sarea_priv->nbox = 0;
2501 }
2502
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002503 if (vertex.discard) {
2504 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 }
2506
2507 COMMIT_RING();
2508 return 0;
2509}
2510
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002511static int radeon_emit_packets(drm_radeon_private_t * dev_priv,
2512 drm_file_t * filp_priv,
2513 drm_radeon_cmd_header_t header,
Dave Airlieb3a83632005-09-30 18:37:36 +10002514 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515{
2516 int id = (int)header.packet.packet_id;
2517 int sz, reg;
2518 int *data = (int *)cmdbuf->buf;
2519 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002520
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 if (id >= RADEON_MAX_STATE_PACKETS)
2522 return DRM_ERR(EINVAL);
2523
2524 sz = packet[id].len;
2525 reg = packet[id].start;
2526
2527 if (sz * sizeof(int) > cmdbuf->bufsz) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002528 DRM_ERROR("Packet size provided larger than data provided\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 return DRM_ERR(EINVAL);
2530 }
2531
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002532 if (radeon_check_and_fixup_packets(dev_priv, filp_priv, id, data)) {
2533 DRM_ERROR("Packet verification failed\n");
2534 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 }
2536
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002537 BEGIN_RING(sz + 1);
2538 OUT_RING(CP_PACKET0(reg, (sz - 1)));
2539 OUT_RING_TABLE(data, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 ADVANCE_RING();
2541
2542 cmdbuf->buf += sz * sizeof(int);
2543 cmdbuf->bufsz -= sz * sizeof(int);
2544 return 0;
2545}
2546
Dave Airlied985c102006-01-02 21:32:48 +11002547static __inline__ int radeon_emit_scalars(drm_radeon_private_t *dev_priv,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002548 drm_radeon_cmd_header_t header,
Dave Airlied985c102006-01-02 21:32:48 +11002549 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550{
2551 int sz = header.scalars.count;
2552 int start = header.scalars.offset;
2553 int stride = header.scalars.stride;
2554 RING_LOCALS;
2555
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002556 BEGIN_RING(3 + sz);
2557 OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
2558 OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
2559 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
2560 OUT_RING_TABLE(cmdbuf->buf, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 ADVANCE_RING();
2562 cmdbuf->buf += sz * sizeof(int);
2563 cmdbuf->bufsz -= sz * sizeof(int);
2564 return 0;
2565}
2566
2567/* God this is ugly
2568 */
Dave Airlied985c102006-01-02 21:32:48 +11002569static __inline__ int radeon_emit_scalars2(drm_radeon_private_t *dev_priv,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002570 drm_radeon_cmd_header_t header,
Dave Airlied985c102006-01-02 21:32:48 +11002571 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572{
2573 int sz = header.scalars.count;
2574 int start = ((unsigned int)header.scalars.offset) + 0x100;
2575 int stride = header.scalars.stride;
2576 RING_LOCALS;
2577
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002578 BEGIN_RING(3 + sz);
2579 OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
2580 OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
2581 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
2582 OUT_RING_TABLE(cmdbuf->buf, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 ADVANCE_RING();
2584 cmdbuf->buf += sz * sizeof(int);
2585 cmdbuf->bufsz -= sz * sizeof(int);
2586 return 0;
2587}
2588
Dave Airlied985c102006-01-02 21:32:48 +11002589static __inline__ int radeon_emit_vectors(drm_radeon_private_t *dev_priv,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002590 drm_radeon_cmd_header_t header,
Dave Airlied985c102006-01-02 21:32:48 +11002591 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592{
2593 int sz = header.vectors.count;
2594 int start = header.vectors.offset;
2595 int stride = header.vectors.stride;
2596 RING_LOCALS;
2597
Dave Airlief2a22792006-06-24 16:55:34 +10002598 BEGIN_RING(5 + sz);
2599 OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002600 OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
2601 OUT_RING(start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
2602 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
2603 OUT_RING_TABLE(cmdbuf->buf, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 ADVANCE_RING();
2605
2606 cmdbuf->buf += sz * sizeof(int);
2607 cmdbuf->bufsz -= sz * sizeof(int);
2608 return 0;
2609}
2610
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002611static int radeon_emit_packet3(drm_device_t * dev,
2612 drm_file_t * filp_priv,
Dave Airlieb3a83632005-09-30 18:37:36 +10002613 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614{
2615 drm_radeon_private_t *dev_priv = dev->dev_private;
2616 unsigned int cmdsz;
2617 int ret;
2618 RING_LOCALS;
2619
2620 DRM_DEBUG("\n");
2621
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002622 if ((ret = radeon_check_and_fixup_packet3(dev_priv, filp_priv,
2623 cmdbuf, &cmdsz))) {
2624 DRM_ERROR("Packet verification failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 return ret;
2626 }
2627
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002628 BEGIN_RING(cmdsz);
2629 OUT_RING_TABLE(cmdbuf->buf, cmdsz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 ADVANCE_RING();
2631
2632 cmdbuf->buf += cmdsz * 4;
2633 cmdbuf->bufsz -= cmdsz * 4;
2634 return 0;
2635}
2636
Dave Airlied985c102006-01-02 21:32:48 +11002637static int radeon_emit_packet3_cliprect(drm_device_t *dev,
2638 drm_file_t *filp_priv,
Dave Airlieb3a83632005-09-30 18:37:36 +10002639 drm_radeon_kcmd_buffer_t *cmdbuf,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002640 int orig_nbox)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641{
2642 drm_radeon_private_t *dev_priv = dev->dev_private;
2643 drm_clip_rect_t box;
2644 unsigned int cmdsz;
2645 int ret;
2646 drm_clip_rect_t __user *boxes = cmdbuf->boxes;
2647 int i = 0;
2648 RING_LOCALS;
2649
2650 DRM_DEBUG("\n");
2651
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002652 if ((ret = radeon_check_and_fixup_packet3(dev_priv, filp_priv,
2653 cmdbuf, &cmdsz))) {
2654 DRM_ERROR("Packet verification failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 return ret;
2656 }
2657
2658 if (!orig_nbox)
2659 goto out;
2660
2661 do {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002662 if (i < cmdbuf->nbox) {
2663 if (DRM_COPY_FROM_USER(&box, &boxes[i], sizeof(box)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 return DRM_ERR(EFAULT);
2665 /* FIXME The second and subsequent times round
2666 * this loop, send a WAIT_UNTIL_3D_IDLE before
2667 * calling emit_clip_rect(). This fixes a
2668 * lockup on fast machines when sending
2669 * several cliprects with a cmdbuf, as when
2670 * waving a 2D window over a 3D
2671 * window. Something in the commands from user
2672 * space seems to hang the card when they're
2673 * sent several times in a row. That would be
2674 * the correct place to fix it but this works
2675 * around it until I can figure that out - Tim
2676 * Smith */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002677 if (i) {
2678 BEGIN_RING(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 RADEON_WAIT_UNTIL_3D_IDLE();
2680 ADVANCE_RING();
2681 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002682 radeon_emit_clip_rect(dev_priv, &box);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002684
2685 BEGIN_RING(cmdsz);
2686 OUT_RING_TABLE(cmdbuf->buf, cmdsz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 ADVANCE_RING();
2688
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002689 } while (++i < cmdbuf->nbox);
2690 if (cmdbuf->nbox == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 cmdbuf->nbox = 0;
2692
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002693 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 cmdbuf->buf += cmdsz * 4;
2695 cmdbuf->bufsz -= cmdsz * 4;
2696 return 0;
2697}
2698
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002699static int radeon_emit_wait(drm_device_t * dev, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700{
2701 drm_radeon_private_t *dev_priv = dev->dev_private;
2702 RING_LOCALS;
2703
2704 DRM_DEBUG("%s: %x\n", __FUNCTION__, flags);
2705 switch (flags) {
2706 case RADEON_WAIT_2D:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002707 BEGIN_RING(2);
2708 RADEON_WAIT_UNTIL_2D_IDLE();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 ADVANCE_RING();
2710 break;
2711 case RADEON_WAIT_3D:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002712 BEGIN_RING(2);
2713 RADEON_WAIT_UNTIL_3D_IDLE();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 ADVANCE_RING();
2715 break;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002716 case RADEON_WAIT_2D | RADEON_WAIT_3D:
2717 BEGIN_RING(2);
2718 RADEON_WAIT_UNTIL_IDLE();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 ADVANCE_RING();
2720 break;
2721 default:
2722 return DRM_ERR(EINVAL);
2723 }
2724
2725 return 0;
2726}
2727
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002728static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729{
2730 DRM_DEVICE;
2731 drm_radeon_private_t *dev_priv = dev->dev_private;
2732 drm_file_t *filp_priv;
2733 drm_device_dma_t *dma = dev->dma;
2734 drm_buf_t *buf = NULL;
2735 int idx;
Dave Airlieb3a83632005-09-30 18:37:36 +10002736 drm_radeon_kcmd_buffer_t cmdbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 drm_radeon_cmd_header_t header;
2738 int orig_nbox, orig_bufsz;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002739 char *kbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002741 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002743 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002745 DRM_COPY_FROM_USER_IOCTL(cmdbuf,
2746 (drm_radeon_cmd_buffer_t __user *) data,
2747 sizeof(cmdbuf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002749 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2750 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002752 if (cmdbuf.bufsz > 64 * 1024 || cmdbuf.bufsz < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 return DRM_ERR(EINVAL);
2754 }
2755
2756 /* Allocate an in-kernel area and copy in the cmdbuf. Do this to avoid
2757 * races between checking values and using those values in other code,
2758 * and simply to avoid a lot of function calls to copy in data.
2759 */
2760 orig_bufsz = cmdbuf.bufsz;
2761 if (orig_bufsz != 0) {
2762 kbuf = drm_alloc(cmdbuf.bufsz, DRM_MEM_DRIVER);
2763 if (kbuf == NULL)
2764 return DRM_ERR(ENOMEM);
Dave Airlied985c102006-01-02 21:32:48 +11002765 if (DRM_COPY_FROM_USER(kbuf, (void __user *)cmdbuf.buf,
2766 cmdbuf.bufsz)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
2768 return DRM_ERR(EFAULT);
2769 }
2770 cmdbuf.buf = kbuf;
2771 }
2772
2773 orig_nbox = cmdbuf.nbox;
2774
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002775 if (dev_priv->microcode_version == UCODE_R300) {
Dave Airlie414ed532005-08-16 20:43:16 +10002776 int temp;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002777 temp = r300_do_cp_cmdbuf(dev, filp, filp_priv, &cmdbuf);
2778
Dave Airlie414ed532005-08-16 20:43:16 +10002779 if (orig_bufsz != 0)
2780 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002781
Dave Airlie414ed532005-08-16 20:43:16 +10002782 return temp;
2783 }
2784
2785 /* microcode_version != r300 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002786 while (cmdbuf.bufsz >= sizeof(header)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787
2788 header.i = *(int *)cmdbuf.buf;
2789 cmdbuf.buf += sizeof(header);
2790 cmdbuf.bufsz -= sizeof(header);
2791
2792 switch (header.header.cmd_type) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002793 case RADEON_CMD_PACKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 DRM_DEBUG("RADEON_CMD_PACKET\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002795 if (radeon_emit_packets
2796 (dev_priv, filp_priv, header, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 DRM_ERROR("radeon_emit_packets failed\n");
2798 goto err;
2799 }
2800 break;
2801
2802 case RADEON_CMD_SCALARS:
2803 DRM_DEBUG("RADEON_CMD_SCALARS\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002804 if (radeon_emit_scalars(dev_priv, header, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 DRM_ERROR("radeon_emit_scalars failed\n");
2806 goto err;
2807 }
2808 break;
2809
2810 case RADEON_CMD_VECTORS:
2811 DRM_DEBUG("RADEON_CMD_VECTORS\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002812 if (radeon_emit_vectors(dev_priv, header, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 DRM_ERROR("radeon_emit_vectors failed\n");
2814 goto err;
2815 }
2816 break;
2817
2818 case RADEON_CMD_DMA_DISCARD:
2819 DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n");
2820 idx = header.dma.buf_idx;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002821 if (idx < 0 || idx >= dma->buf_count) {
2822 DRM_ERROR("buffer index %d (of %d max)\n",
2823 idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 goto err;
2825 }
2826
2827 buf = dma->buflist[idx];
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002828 if (buf->filp != filp || buf->pending) {
2829 DRM_ERROR("bad buffer %p %p %d\n",
2830 buf->filp, filp, buf->pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 goto err;
2832 }
2833
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002834 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 break;
2836
2837 case RADEON_CMD_PACKET3:
2838 DRM_DEBUG("RADEON_CMD_PACKET3\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002839 if (radeon_emit_packet3(dev, filp_priv, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 DRM_ERROR("radeon_emit_packet3 failed\n");
2841 goto err;
2842 }
2843 break;
2844
2845 case RADEON_CMD_PACKET3_CLIP:
2846 DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002847 if (radeon_emit_packet3_cliprect
2848 (dev, filp_priv, &cmdbuf, orig_nbox)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 DRM_ERROR("radeon_emit_packet3_clip failed\n");
2850 goto err;
2851 }
2852 break;
2853
2854 case RADEON_CMD_SCALARS2:
2855 DRM_DEBUG("RADEON_CMD_SCALARS2\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002856 if (radeon_emit_scalars2(dev_priv, header, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 DRM_ERROR("radeon_emit_scalars2 failed\n");
2858 goto err;
2859 }
2860 break;
2861
2862 case RADEON_CMD_WAIT:
2863 DRM_DEBUG("RADEON_CMD_WAIT\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002864 if (radeon_emit_wait(dev, header.wait.flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 DRM_ERROR("radeon_emit_wait failed\n");
2866 goto err;
2867 }
2868 break;
2869 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002870 DRM_ERROR("bad cmd_type %d at %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 header.header.cmd_type,
2872 cmdbuf.buf - sizeof(header));
2873 goto err;
2874 }
2875 }
2876
2877 if (orig_bufsz != 0)
2878 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
2879
2880 DRM_DEBUG("DONE\n");
2881 COMMIT_RING();
2882 return 0;
2883
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002884 err:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 if (orig_bufsz != 0)
2886 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
2887 return DRM_ERR(EINVAL);
2888}
2889
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002890static int radeon_cp_getparam(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891{
2892 DRM_DEVICE;
2893 drm_radeon_private_t *dev_priv = dev->dev_private;
2894 drm_radeon_getparam_t param;
2895 int value;
2896
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002897 DRM_COPY_FROM_USER_IOCTL(param, (drm_radeon_getparam_t __user *) data,
2898 sizeof(param));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002900 DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002902 switch (param.param) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 case RADEON_PARAM_GART_BUFFER_OFFSET:
2904 value = dev_priv->gart_buffers_offset;
2905 break;
2906 case RADEON_PARAM_LAST_FRAME:
2907 dev_priv->stats.last_frame_reads++;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002908 value = GET_SCRATCH(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 break;
2910 case RADEON_PARAM_LAST_DISPATCH:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002911 value = GET_SCRATCH(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 break;
2913 case RADEON_PARAM_LAST_CLEAR:
2914 dev_priv->stats.last_clear_reads++;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002915 value = GET_SCRATCH(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 break;
2917 case RADEON_PARAM_IRQ_NR:
2918 value = dev->irq;
2919 break;
2920 case RADEON_PARAM_GART_BASE:
2921 value = dev_priv->gart_vm_start;
2922 break;
2923 case RADEON_PARAM_REGISTER_HANDLE:
Dave Airlied985c102006-01-02 21:32:48 +11002924 value = dev_priv->mmio->offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 break;
2926 case RADEON_PARAM_STATUS_HANDLE:
2927 value = dev_priv->ring_rptr_offset;
2928 break;
2929#if BITS_PER_LONG == 32
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002930 /*
2931 * This ioctl() doesn't work on 64-bit platforms because hw_lock is a
2932 * pointer which can't fit into an int-sized variable. According to
2933 * Michel Dänzer, the ioctl() is only used on embedded platforms, so
2934 * not supporting it shouldn't be a problem. If the same functionality
2935 * is needed on 64-bit platforms, a new ioctl() would have to be added,
2936 * so backwards-compatibility for the embedded platforms can be
2937 * maintained. --davidm 4-Feb-2004.
2938 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 case RADEON_PARAM_SAREA_HANDLE:
2940 /* The lock is the first dword in the sarea. */
2941 value = (long)dev->lock.hw_lock;
2942 break;
2943#endif
2944 case RADEON_PARAM_GART_TEX_HANDLE:
2945 value = dev_priv->gart_textures_offset;
2946 break;
Dave Airlied985c102006-01-02 21:32:48 +11002947
2948 case RADEON_PARAM_CARD_TYPE:
2949 if (dev_priv->flags & CHIP_IS_PCIE)
2950 value = RADEON_CARD_PCIE;
2951 else if (dev_priv->flags & CHIP_IS_AGP)
2952 value = RADEON_CARD_AGP;
2953 else
2954 value = RADEON_CARD_PCI;
2955 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 default:
2957 return DRM_ERR(EINVAL);
2958 }
2959
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002960 if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
2961 DRM_ERROR("copy_to_user\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 return DRM_ERR(EFAULT);
2963 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002964
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 return 0;
2966}
2967
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002968static int radeon_cp_setparam(DRM_IOCTL_ARGS)
2969{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 DRM_DEVICE;
2971 drm_radeon_private_t *dev_priv = dev->dev_private;
2972 drm_file_t *filp_priv;
2973 drm_radeon_setparam_t sp;
2974 struct drm_radeon_driver_file_fields *radeon_priv;
2975
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002976 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002978 DRM_COPY_FROM_USER_IOCTL(sp, (drm_radeon_setparam_t __user *) data,
2979 sizeof(sp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002981 switch (sp.param) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 case RADEON_SETPARAM_FB_LOCATION:
2983 radeon_priv = filp_priv->driver_priv;
2984 radeon_priv->radeon_fb_delta = dev_priv->fb_location - sp.value;
2985 break;
2986 case RADEON_SETPARAM_SWITCH_TILING:
2987 if (sp.value == 0) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002988 DRM_DEBUG("color tiling disabled\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO;
2990 dev_priv->back_pitch_offset &= ~RADEON_DST_TILE_MACRO;
2991 dev_priv->sarea_priv->tiling_enabled = 0;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002992 } else if (sp.value == 1) {
2993 DRM_DEBUG("color tiling enabled\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 dev_priv->front_pitch_offset |= RADEON_DST_TILE_MACRO;
2995 dev_priv->back_pitch_offset |= RADEON_DST_TILE_MACRO;
2996 dev_priv->sarea_priv->tiling_enabled = 1;
2997 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002998 break;
Dave Airlieea98a922005-09-11 20:28:11 +10002999 case RADEON_SETPARAM_PCIGART_LOCATION:
3000 dev_priv->pcigart_offset = sp.value;
3001 break;
Dave Airlied5ea7022006-03-19 19:37:55 +11003002 case RADEON_SETPARAM_NEW_MEMMAP:
3003 dev_priv->new_memmap = sp.value;
3004 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003006 DRM_DEBUG("Invalid parameter %d\n", sp.param);
3007 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 }
3009
3010 return 0;
3011}
3012
3013/* When a client dies:
3014 * - Check for and clean up flipped page state
3015 * - Free any alloced GART memory.
Dave Airlied985c102006-01-02 21:32:48 +11003016 * - Free any alloced radeon surfaces.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 *
3018 * DRM infrastructure takes care of reclaiming dma buffers.
3019 */
Dave Airlie22eae942005-11-10 22:16:34 +11003020void radeon_driver_preclose(drm_device_t * dev, DRMFILE filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021{
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003022 if (dev->dev_private) {
3023 drm_radeon_private_t *dev_priv = dev->dev_private;
3024 if (dev_priv->page_flipping) {
3025 radeon_do_cleanup_pageflip(dev);
3026 }
3027 radeon_mem_release(filp, dev_priv->gart_heap);
3028 radeon_mem_release(filp, dev_priv->fb_heap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 radeon_surfaces_release(filp, dev_priv);
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003030 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031}
3032
Dave Airlie22eae942005-11-10 22:16:34 +11003033void radeon_driver_lastclose(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034{
3035 radeon_do_release(dev);
3036}
3037
Dave Airlie22eae942005-11-10 22:16:34 +11003038int radeon_driver_open(drm_device_t * dev, drm_file_t * filp_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039{
3040 drm_radeon_private_t *dev_priv = dev->dev_private;
3041 struct drm_radeon_driver_file_fields *radeon_priv;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003042
Dave Airlied985c102006-01-02 21:32:48 +11003043 DRM_DEBUG("\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003044 radeon_priv =
3045 (struct drm_radeon_driver_file_fields *)
3046 drm_alloc(sizeof(*radeon_priv), DRM_MEM_FILES);
3047
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 if (!radeon_priv)
3049 return -ENOMEM;
3050
3051 filp_priv->driver_priv = radeon_priv;
Dave Airlied985c102006-01-02 21:32:48 +11003052
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003053 if (dev_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 radeon_priv->radeon_fb_delta = dev_priv->fb_location;
3055 else
3056 radeon_priv->radeon_fb_delta = 0;
3057 return 0;
3058}
3059
Dave Airlie22eae942005-11-10 22:16:34 +11003060void radeon_driver_postclose(drm_device_t * dev, drm_file_t * filp_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061{
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003062 struct drm_radeon_driver_file_fields *radeon_priv =
3063 filp_priv->driver_priv;
3064
3065 drm_free(radeon_priv, sizeof(*radeon_priv), DRM_MEM_FILES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066}
3067
3068drm_ioctl_desc_t radeon_ioctls[] = {
Dave Airliea7a2cc32006-01-02 13:54:04 +11003069 [DRM_IOCTL_NR(DRM_RADEON_CP_INIT)] = {radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3070 [DRM_IOCTL_NR(DRM_RADEON_CP_START)] = {radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3071 [DRM_IOCTL_NR(DRM_RADEON_CP_STOP)] = {radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3072 [DRM_IOCTL_NR(DRM_RADEON_CP_RESET)] = {radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3073 [DRM_IOCTL_NR(DRM_RADEON_CP_IDLE)] = {radeon_cp_idle, DRM_AUTH},
3074 [DRM_IOCTL_NR(DRM_RADEON_CP_RESUME)] = {radeon_cp_resume, DRM_AUTH},
3075 [DRM_IOCTL_NR(DRM_RADEON_RESET)] = {radeon_engine_reset, DRM_AUTH},
3076 [DRM_IOCTL_NR(DRM_RADEON_FULLSCREEN)] = {radeon_fullscreen, DRM_AUTH},
3077 [DRM_IOCTL_NR(DRM_RADEON_SWAP)] = {radeon_cp_swap, DRM_AUTH},
3078 [DRM_IOCTL_NR(DRM_RADEON_CLEAR)] = {radeon_cp_clear, DRM_AUTH},
3079 [DRM_IOCTL_NR(DRM_RADEON_VERTEX)] = {radeon_cp_vertex, DRM_AUTH},
3080 [DRM_IOCTL_NR(DRM_RADEON_INDICES)] = {radeon_cp_indices, DRM_AUTH},
3081 [DRM_IOCTL_NR(DRM_RADEON_TEXTURE)] = {radeon_cp_texture, DRM_AUTH},
3082 [DRM_IOCTL_NR(DRM_RADEON_STIPPLE)] = {radeon_cp_stipple, DRM_AUTH},
3083 [DRM_IOCTL_NR(DRM_RADEON_INDIRECT)] = {radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3084 [DRM_IOCTL_NR(DRM_RADEON_VERTEX2)] = {radeon_cp_vertex2, DRM_AUTH},
3085 [DRM_IOCTL_NR(DRM_RADEON_CMDBUF)] = {radeon_cp_cmdbuf, DRM_AUTH},
3086 [DRM_IOCTL_NR(DRM_RADEON_GETPARAM)] = {radeon_cp_getparam, DRM_AUTH},
3087 [DRM_IOCTL_NR(DRM_RADEON_FLIP)] = {radeon_cp_flip, DRM_AUTH},
3088 [DRM_IOCTL_NR(DRM_RADEON_ALLOC)] = {radeon_mem_alloc, DRM_AUTH},
3089 [DRM_IOCTL_NR(DRM_RADEON_FREE)] = {radeon_mem_free, DRM_AUTH},
3090 [DRM_IOCTL_NR(DRM_RADEON_INIT_HEAP)] = {radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3091 [DRM_IOCTL_NR(DRM_RADEON_IRQ_EMIT)] = {radeon_irq_emit, DRM_AUTH},
3092 [DRM_IOCTL_NR(DRM_RADEON_IRQ_WAIT)] = {radeon_irq_wait, DRM_AUTH},
3093 [DRM_IOCTL_NR(DRM_RADEON_SETPARAM)] = {radeon_cp_setparam, DRM_AUTH},
3094 [DRM_IOCTL_NR(DRM_RADEON_SURF_ALLOC)] = {radeon_surface_alloc, DRM_AUTH},
3095 [DRM_IOCTL_NR(DRM_RADEON_SURF_FREE)] = {radeon_surface_free, DRM_AUTH}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096};
3097
3098int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls);