blob: bb4b2e1a78c1a079b3c7f96c63b7a1ff50388464 [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{
Michel Daenzer214ff132006-09-22 04:12:11 +100045 u64 off = *offset;
46 u32 fb_start = dev_priv->fb_location;
47 u32 fb_end = fb_start + dev_priv->fb_size - 1;
48 u32 gart_start = dev_priv->gart_vm_start;
49 u32 gart_end = gart_start + dev_priv->gart_size - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 struct drm_radeon_driver_file_fields *radeon_priv;
51
Dave Airlied5ea7022006-03-19 19:37:55 +110052 /* Hrm ... the story of the offset ... So this function converts
53 * the various ideas of what userland clients might have for an
54 * offset in the card address space into an offset into the card
55 * address space :) So with a sane client, it should just keep
56 * the value intact and just do some boundary checking. However,
57 * not all clients are sane. Some older clients pass us 0 based
58 * offsets relative to the start of the framebuffer and some may
59 * assume the AGP aperture it appended to the framebuffer, so we
60 * try to detect those cases and fix them up.
61 *
62 * Note: It might be a good idea here to make sure the offset lands
63 * in some "allowed" area to protect things like the PCIE GART...
64 */
65
66 /* First, the best case, the offset already lands in either the
67 * framebuffer or the GART mapped space
68 */
Michel Daenzer214ff132006-09-22 04:12:11 +100069 if ((off >= fb_start && off <= fb_end) ||
70 (off >= gart_start && off <= gart_end))
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 return 0;
72
Dave Airlied5ea7022006-03-19 19:37:55 +110073 /* Ok, that didn't happen... now check if we have a zero based
74 * offset that fits in the framebuffer + gart space, apply the
75 * magic offset we get from SETPARAM or calculated from fb_location
76 */
77 if (off < (dev_priv->fb_size + dev_priv->gart_size)) {
78 radeon_priv = filp_priv->driver_priv;
79 off += radeon_priv->radeon_fb_delta;
80 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
Dave Airlied5ea7022006-03-19 19:37:55 +110082 /* Finally, assume we aimed at a GART offset if beyond the fb */
Michel Daenzer214ff132006-09-22 04:12:11 +100083 if (off > fb_end)
84 off = off - fb_end - 1 + gart_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
Dave Airlied5ea7022006-03-19 19:37:55 +110086 /* Now recheck and fail if out of bounds */
Michel Daenzer214ff132006-09-22 04:12:11 +100087 if ((off >= fb_start && off <= fb_end) ||
88 (off >= gart_start && off <= gart_end)) {
89 DRM_DEBUG("offset fixed up to 0x%x\n", (unsigned int)off);
Dave Airlied5ea7022006-03-19 19:37:55 +110090 *offset = off;
91 return 0;
92 }
93 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070094}
95
Dave Airlieb5e89ed2005-09-25 14:28:13 +100096static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
97 dev_priv,
98 drm_file_t * filp_priv,
Dave Airlieb3a83632005-09-30 18:37:36 +100099 int id, u32 *data)
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000100{
101 switch (id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
103 case RADEON_EMIT_PP_MISC:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000104 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
Dave Airlied985c102006-01-02 21:32:48 +1100105 &data[(RADEON_RB3D_DEPTHOFFSET - RADEON_PP_MISC) / 4])) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000106 DRM_ERROR("Invalid depth buffer offset\n");
107 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 }
109 break;
110
111 case RADEON_EMIT_PP_CNTL:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000112 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
Dave Airlied985c102006-01-02 21:32:48 +1100113 &data[(RADEON_RB3D_COLOROFFSET - RADEON_PP_CNTL) / 4])) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000114 DRM_ERROR("Invalid colour buffer offset\n");
115 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 }
117 break;
118
119 case R200_EMIT_PP_TXOFFSET_0:
120 case R200_EMIT_PP_TXOFFSET_1:
121 case R200_EMIT_PP_TXOFFSET_2:
122 case R200_EMIT_PP_TXOFFSET_3:
123 case R200_EMIT_PP_TXOFFSET_4:
124 case R200_EMIT_PP_TXOFFSET_5:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000125 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
126 &data[0])) {
127 DRM_ERROR("Invalid R200 texture offset\n");
128 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 }
130 break;
131
132 case RADEON_EMIT_PP_TXFILTER_0:
133 case RADEON_EMIT_PP_TXFILTER_1:
134 case RADEON_EMIT_PP_TXFILTER_2:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000135 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
Dave Airlied985c102006-01-02 21:32:48 +1100136 &data[(RADEON_PP_TXOFFSET_0 - RADEON_PP_TXFILTER_0) / 4])) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000137 DRM_ERROR("Invalid R100 texture offset\n");
138 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 }
140 break;
141
142 case R200_EMIT_PP_CUBIC_OFFSETS_0:
143 case R200_EMIT_PP_CUBIC_OFFSETS_1:
144 case R200_EMIT_PP_CUBIC_OFFSETS_2:
145 case R200_EMIT_PP_CUBIC_OFFSETS_3:
146 case R200_EMIT_PP_CUBIC_OFFSETS_4:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000147 case R200_EMIT_PP_CUBIC_OFFSETS_5:{
148 int i;
149 for (i = 0; i < 5; i++) {
Dave Airlied985c102006-01-02 21:32:48 +1100150 if (radeon_check_and_fixup_offset(dev_priv,
151 filp_priv,
152 &data[i])) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000153 DRM_ERROR
154 ("Invalid R200 cubic texture offset\n");
155 return DRM_ERR(EINVAL);
156 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000158 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
161 case RADEON_EMIT_PP_CUBIC_OFFSETS_T0:
162 case RADEON_EMIT_PP_CUBIC_OFFSETS_T1:
163 case RADEON_EMIT_PP_CUBIC_OFFSETS_T2:{
164 int i;
165 for (i = 0; i < 5; i++) {
166 if (radeon_check_and_fixup_offset(dev_priv,
167 filp_priv,
168 &data[i])) {
169 DRM_ERROR
170 ("Invalid R100 cubic texture offset\n");
171 return DRM_ERR(EINVAL);
172 }
173 }
174 }
175 break;
176
Roland Scheidegger18f29052006-08-30 23:17:55 +0100177 case R200_EMIT_VAP_CTL:{
178 RING_LOCALS;
179 BEGIN_RING(2);
180 OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
181 ADVANCE_RING();
182 }
183 break;
184
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 case RADEON_EMIT_RB3D_COLORPITCH:
186 case RADEON_EMIT_RE_LINE_PATTERN:
187 case RADEON_EMIT_SE_LINE_WIDTH:
188 case RADEON_EMIT_PP_LUM_MATRIX:
189 case RADEON_EMIT_PP_ROT_MATRIX_0:
190 case RADEON_EMIT_RB3D_STENCILREFMASK:
191 case RADEON_EMIT_SE_VPORT_XSCALE:
192 case RADEON_EMIT_SE_CNTL:
193 case RADEON_EMIT_SE_CNTL_STATUS:
194 case RADEON_EMIT_RE_MISC:
195 case RADEON_EMIT_PP_BORDER_COLOR_0:
196 case RADEON_EMIT_PP_BORDER_COLOR_1:
197 case RADEON_EMIT_PP_BORDER_COLOR_2:
198 case RADEON_EMIT_SE_ZBIAS_FACTOR:
199 case RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT:
200 case RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED:
201 case R200_EMIT_PP_TXCBLEND_0:
202 case R200_EMIT_PP_TXCBLEND_1:
203 case R200_EMIT_PP_TXCBLEND_2:
204 case R200_EMIT_PP_TXCBLEND_3:
205 case R200_EMIT_PP_TXCBLEND_4:
206 case R200_EMIT_PP_TXCBLEND_5:
207 case R200_EMIT_PP_TXCBLEND_6:
208 case R200_EMIT_PP_TXCBLEND_7:
209 case R200_EMIT_TCL_LIGHT_MODEL_CTL_0:
210 case R200_EMIT_TFACTOR_0:
211 case R200_EMIT_VTX_FMT_0:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 case R200_EMIT_MATRIX_SELECT_0:
213 case R200_EMIT_TEX_PROC_CTL_2:
214 case R200_EMIT_TCL_UCP_VERT_BLEND_CTL:
215 case R200_EMIT_PP_TXFILTER_0:
216 case R200_EMIT_PP_TXFILTER_1:
217 case R200_EMIT_PP_TXFILTER_2:
218 case R200_EMIT_PP_TXFILTER_3:
219 case R200_EMIT_PP_TXFILTER_4:
220 case R200_EMIT_PP_TXFILTER_5:
221 case R200_EMIT_VTE_CNTL:
222 case R200_EMIT_OUTPUT_VTX_COMP_SEL:
223 case R200_EMIT_PP_TAM_DEBUG3:
224 case R200_EMIT_PP_CNTL_X:
225 case R200_EMIT_RB3D_DEPTHXY_OFFSET:
226 case R200_EMIT_RE_AUX_SCISSOR_CNTL:
227 case R200_EMIT_RE_SCISSOR_TL_0:
228 case R200_EMIT_RE_SCISSOR_TL_1:
229 case R200_EMIT_RE_SCISSOR_TL_2:
230 case R200_EMIT_SE_VAP_CNTL_STATUS:
231 case R200_EMIT_SE_VTX_STATE_CNTL:
232 case R200_EMIT_RE_POINTSIZE:
233 case R200_EMIT_TCL_INPUT_VTX_VECTOR_ADDR_0:
234 case R200_EMIT_PP_CUBIC_FACES_0:
235 case R200_EMIT_PP_CUBIC_FACES_1:
236 case R200_EMIT_PP_CUBIC_FACES_2:
237 case R200_EMIT_PP_CUBIC_FACES_3:
238 case R200_EMIT_PP_CUBIC_FACES_4:
239 case R200_EMIT_PP_CUBIC_FACES_5:
240 case RADEON_EMIT_PP_TEX_SIZE_0:
241 case RADEON_EMIT_PP_TEX_SIZE_1:
242 case RADEON_EMIT_PP_TEX_SIZE_2:
243 case R200_EMIT_RB3D_BLENDCOLOR:
244 case R200_EMIT_TCL_POINT_SPRITE_CNTL:
245 case RADEON_EMIT_PP_CUBIC_FACES_0:
246 case RADEON_EMIT_PP_CUBIC_FACES_1:
247 case RADEON_EMIT_PP_CUBIC_FACES_2:
248 case R200_EMIT_PP_TRI_PERF_CNTL:
Dave Airlie9d176012005-09-11 19:55:53 +1000249 case R200_EMIT_PP_AFS_0:
250 case R200_EMIT_PP_AFS_1:
251 case R200_EMIT_ATF_TFACTOR:
252 case R200_EMIT_PP_TXCTLALL_0:
253 case R200_EMIT_PP_TXCTLALL_1:
254 case R200_EMIT_PP_TXCTLALL_2:
255 case R200_EMIT_PP_TXCTLALL_3:
256 case R200_EMIT_PP_TXCTLALL_4:
257 case R200_EMIT_PP_TXCTLALL_5:
Dave Airlied6fece02006-06-24 17:04:07 +1000258 case R200_EMIT_VAP_PVS_CNTL:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 /* These packets don't contain memory offsets */
260 break;
261
262 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000263 DRM_ERROR("Unknown state packet ID %d\n", id);
264 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 }
266
267 return 0;
268}
269
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000270static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
271 dev_priv,
Dave Airlied985c102006-01-02 21:32:48 +1100272 drm_file_t *filp_priv,
273 drm_radeon_kcmd_buffer_t *
274 cmdbuf,
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000275 unsigned int *cmdsz)
276{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 u32 *cmd = (u32 *) cmdbuf->buf;
278
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000279 *cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000281 if ((cmd[0] & 0xc0000000) != RADEON_CP_PACKET3) {
282 DRM_ERROR("Not a type 3 packet\n");
283 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 }
285
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000286 if (4 * *cmdsz > cmdbuf->bufsz) {
287 DRM_ERROR("Packet size larger than size of data provided\n");
288 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 }
290
291 /* Check client state and fix it up if necessary */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000292 if (cmd[0] & 0x8000) { /* MSB of opcode: next DWORD GUI_CNTL */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 u32 offset;
294
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000295 if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
296 | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 offset = cmd[2] << 10;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000298 if (radeon_check_and_fixup_offset
299 (dev_priv, filp_priv, &offset)) {
300 DRM_ERROR("Invalid first packet offset\n");
301 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000303 cmd[2] = (cmd[2] & 0xffc00000) | offset >> 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 }
305
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000306 if ((cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL) &&
307 (cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 offset = cmd[3] << 10;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000309 if (radeon_check_and_fixup_offset
310 (dev_priv, filp_priv, &offset)) {
311 DRM_ERROR("Invalid second packet offset\n");
312 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000314 cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 }
316 }
317
318 return 0;
319}
320
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321/* ================================================================
322 * CP hardware state programming functions
323 */
324
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000325static __inline__ void radeon_emit_clip_rect(drm_radeon_private_t * dev_priv,
326 drm_clip_rect_t * box)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327{
328 RING_LOCALS;
329
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000330 DRM_DEBUG(" box: x1=%d y1=%d x2=%d y2=%d\n",
331 box->x1, box->y1, box->x2, box->y2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000333 BEGIN_RING(4);
334 OUT_RING(CP_PACKET0(RADEON_RE_TOP_LEFT, 0));
335 OUT_RING((box->y1 << 16) | box->x1);
336 OUT_RING(CP_PACKET0(RADEON_RE_WIDTH_HEIGHT, 0));
337 OUT_RING(((box->y2 - 1) << 16) | (box->x2 - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 ADVANCE_RING();
339}
340
341/* Emit 1.1 state
342 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000343static int radeon_emit_state(drm_radeon_private_t * dev_priv,
344 drm_file_t * filp_priv,
345 drm_radeon_context_regs_t * ctx,
346 drm_radeon_texture_regs_t * tex,
347 unsigned int dirty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348{
349 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000350 DRM_DEBUG("dirty=0x%08x\n", dirty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000352 if (dirty & RADEON_UPLOAD_CONTEXT) {
353 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
354 &ctx->rb3d_depthoffset)) {
355 DRM_ERROR("Invalid depth buffer offset\n");
356 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 }
358
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000359 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
360 &ctx->rb3d_coloroffset)) {
361 DRM_ERROR("Invalid depth buffer offset\n");
362 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 }
364
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000365 BEGIN_RING(14);
366 OUT_RING(CP_PACKET0(RADEON_PP_MISC, 6));
367 OUT_RING(ctx->pp_misc);
368 OUT_RING(ctx->pp_fog_color);
369 OUT_RING(ctx->re_solid_color);
370 OUT_RING(ctx->rb3d_blendcntl);
371 OUT_RING(ctx->rb3d_depthoffset);
372 OUT_RING(ctx->rb3d_depthpitch);
373 OUT_RING(ctx->rb3d_zstencilcntl);
374 OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 2));
375 OUT_RING(ctx->pp_cntl);
376 OUT_RING(ctx->rb3d_cntl);
377 OUT_RING(ctx->rb3d_coloroffset);
378 OUT_RING(CP_PACKET0(RADEON_RB3D_COLORPITCH, 0));
379 OUT_RING(ctx->rb3d_colorpitch);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 ADVANCE_RING();
381 }
382
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000383 if (dirty & RADEON_UPLOAD_VERTFMT) {
384 BEGIN_RING(2);
385 OUT_RING(CP_PACKET0(RADEON_SE_COORD_FMT, 0));
386 OUT_RING(ctx->se_coord_fmt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 ADVANCE_RING();
388 }
389
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000390 if (dirty & RADEON_UPLOAD_LINE) {
391 BEGIN_RING(5);
392 OUT_RING(CP_PACKET0(RADEON_RE_LINE_PATTERN, 1));
393 OUT_RING(ctx->re_line_pattern);
394 OUT_RING(ctx->re_line_state);
395 OUT_RING(CP_PACKET0(RADEON_SE_LINE_WIDTH, 0));
396 OUT_RING(ctx->se_line_width);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 ADVANCE_RING();
398 }
399
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000400 if (dirty & RADEON_UPLOAD_BUMPMAP) {
401 BEGIN_RING(5);
402 OUT_RING(CP_PACKET0(RADEON_PP_LUM_MATRIX, 0));
403 OUT_RING(ctx->pp_lum_matrix);
404 OUT_RING(CP_PACKET0(RADEON_PP_ROT_MATRIX_0, 1));
405 OUT_RING(ctx->pp_rot_matrix_0);
406 OUT_RING(ctx->pp_rot_matrix_1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 ADVANCE_RING();
408 }
409
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000410 if (dirty & RADEON_UPLOAD_MASKS) {
411 BEGIN_RING(4);
412 OUT_RING(CP_PACKET0(RADEON_RB3D_STENCILREFMASK, 2));
413 OUT_RING(ctx->rb3d_stencilrefmask);
414 OUT_RING(ctx->rb3d_ropcntl);
415 OUT_RING(ctx->rb3d_planemask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 ADVANCE_RING();
417 }
418
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000419 if (dirty & RADEON_UPLOAD_VIEWPORT) {
420 BEGIN_RING(7);
421 OUT_RING(CP_PACKET0(RADEON_SE_VPORT_XSCALE, 5));
422 OUT_RING(ctx->se_vport_xscale);
423 OUT_RING(ctx->se_vport_xoffset);
424 OUT_RING(ctx->se_vport_yscale);
425 OUT_RING(ctx->se_vport_yoffset);
426 OUT_RING(ctx->se_vport_zscale);
427 OUT_RING(ctx->se_vport_zoffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 ADVANCE_RING();
429 }
430
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000431 if (dirty & RADEON_UPLOAD_SETUP) {
432 BEGIN_RING(4);
433 OUT_RING(CP_PACKET0(RADEON_SE_CNTL, 0));
434 OUT_RING(ctx->se_cntl);
435 OUT_RING(CP_PACKET0(RADEON_SE_CNTL_STATUS, 0));
436 OUT_RING(ctx->se_cntl_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 ADVANCE_RING();
438 }
439
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000440 if (dirty & RADEON_UPLOAD_MISC) {
441 BEGIN_RING(2);
442 OUT_RING(CP_PACKET0(RADEON_RE_MISC, 0));
443 OUT_RING(ctx->re_misc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 ADVANCE_RING();
445 }
446
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000447 if (dirty & RADEON_UPLOAD_TEX0) {
448 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
449 &tex[0].pp_txoffset)) {
450 DRM_ERROR("Invalid texture offset for unit 0\n");
451 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 }
453
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000454 BEGIN_RING(9);
455 OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_0, 5));
456 OUT_RING(tex[0].pp_txfilter);
457 OUT_RING(tex[0].pp_txformat);
458 OUT_RING(tex[0].pp_txoffset);
459 OUT_RING(tex[0].pp_txcblend);
460 OUT_RING(tex[0].pp_txablend);
461 OUT_RING(tex[0].pp_tfactor);
462 OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_0, 0));
463 OUT_RING(tex[0].pp_border_color);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 ADVANCE_RING();
465 }
466
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000467 if (dirty & RADEON_UPLOAD_TEX1) {
468 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
469 &tex[1].pp_txoffset)) {
470 DRM_ERROR("Invalid texture offset for unit 1\n");
471 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 }
473
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000474 BEGIN_RING(9);
475 OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_1, 5));
476 OUT_RING(tex[1].pp_txfilter);
477 OUT_RING(tex[1].pp_txformat);
478 OUT_RING(tex[1].pp_txoffset);
479 OUT_RING(tex[1].pp_txcblend);
480 OUT_RING(tex[1].pp_txablend);
481 OUT_RING(tex[1].pp_tfactor);
482 OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_1, 0));
483 OUT_RING(tex[1].pp_border_color);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 ADVANCE_RING();
485 }
486
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000487 if (dirty & RADEON_UPLOAD_TEX2) {
488 if (radeon_check_and_fixup_offset(dev_priv, filp_priv,
489 &tex[2].pp_txoffset)) {
490 DRM_ERROR("Invalid texture offset for unit 2\n");
491 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 }
493
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000494 BEGIN_RING(9);
495 OUT_RING(CP_PACKET0(RADEON_PP_TXFILTER_2, 5));
496 OUT_RING(tex[2].pp_txfilter);
497 OUT_RING(tex[2].pp_txformat);
498 OUT_RING(tex[2].pp_txoffset);
499 OUT_RING(tex[2].pp_txcblend);
500 OUT_RING(tex[2].pp_txablend);
501 OUT_RING(tex[2].pp_tfactor);
502 OUT_RING(CP_PACKET0(RADEON_PP_BORDER_COLOR_2, 0));
503 OUT_RING(tex[2].pp_border_color);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 ADVANCE_RING();
505 }
506
507 return 0;
508}
509
510/* Emit 1.2 state
511 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000512static int radeon_emit_state2(drm_radeon_private_t * dev_priv,
513 drm_file_t * filp_priv,
514 drm_radeon_state_t * state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515{
516 RING_LOCALS;
517
518 if (state->dirty & RADEON_UPLOAD_ZBIAS) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000519 BEGIN_RING(3);
520 OUT_RING(CP_PACKET0(RADEON_SE_ZBIAS_FACTOR, 1));
521 OUT_RING(state->context2.se_zbias_factor);
522 OUT_RING(state->context2.se_zbias_constant);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 ADVANCE_RING();
524 }
525
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000526 return radeon_emit_state(dev_priv, filp_priv, &state->context,
527 state->tex, state->dirty);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528}
529
530/* New (1.3) state mechanism. 3 commands (packet, scalar, vector) in
531 * 1.3 cmdbuffers allow all previous state to be updated as well as
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000532 * the tcl scalar and vector areas.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000534static struct {
535 int start;
536 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 const char *name;
538} packet[RADEON_MAX_STATE_PACKETS] = {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000539 {RADEON_PP_MISC, 7, "RADEON_PP_MISC"},
540 {RADEON_PP_CNTL, 3, "RADEON_PP_CNTL"},
541 {RADEON_RB3D_COLORPITCH, 1, "RADEON_RB3D_COLORPITCH"},
542 {RADEON_RE_LINE_PATTERN, 2, "RADEON_RE_LINE_PATTERN"},
543 {RADEON_SE_LINE_WIDTH, 1, "RADEON_SE_LINE_WIDTH"},
544 {RADEON_PP_LUM_MATRIX, 1, "RADEON_PP_LUM_MATRIX"},
545 {RADEON_PP_ROT_MATRIX_0, 2, "RADEON_PP_ROT_MATRIX_0"},
546 {RADEON_RB3D_STENCILREFMASK, 3, "RADEON_RB3D_STENCILREFMASK"},
547 {RADEON_SE_VPORT_XSCALE, 6, "RADEON_SE_VPORT_XSCALE"},
548 {RADEON_SE_CNTL, 2, "RADEON_SE_CNTL"},
549 {RADEON_SE_CNTL_STATUS, 1, "RADEON_SE_CNTL_STATUS"},
550 {RADEON_RE_MISC, 1, "RADEON_RE_MISC"},
551 {RADEON_PP_TXFILTER_0, 6, "RADEON_PP_TXFILTER_0"},
552 {RADEON_PP_BORDER_COLOR_0, 1, "RADEON_PP_BORDER_COLOR_0"},
553 {RADEON_PP_TXFILTER_1, 6, "RADEON_PP_TXFILTER_1"},
554 {RADEON_PP_BORDER_COLOR_1, 1, "RADEON_PP_BORDER_COLOR_1"},
555 {RADEON_PP_TXFILTER_2, 6, "RADEON_PP_TXFILTER_2"},
556 {RADEON_PP_BORDER_COLOR_2, 1, "RADEON_PP_BORDER_COLOR_2"},
557 {RADEON_SE_ZBIAS_FACTOR, 2, "RADEON_SE_ZBIAS_FACTOR"},
558 {RADEON_SE_TCL_OUTPUT_VTX_FMT, 11, "RADEON_SE_TCL_OUTPUT_VTX_FMT"},
559 {RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED, 17,
560 "RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED"},
561 {R200_PP_TXCBLEND_0, 4, "R200_PP_TXCBLEND_0"},
562 {R200_PP_TXCBLEND_1, 4, "R200_PP_TXCBLEND_1"},
563 {R200_PP_TXCBLEND_2, 4, "R200_PP_TXCBLEND_2"},
564 {R200_PP_TXCBLEND_3, 4, "R200_PP_TXCBLEND_3"},
565 {R200_PP_TXCBLEND_4, 4, "R200_PP_TXCBLEND_4"},
566 {R200_PP_TXCBLEND_5, 4, "R200_PP_TXCBLEND_5"},
567 {R200_PP_TXCBLEND_6, 4, "R200_PP_TXCBLEND_6"},
568 {R200_PP_TXCBLEND_7, 4, "R200_PP_TXCBLEND_7"},
569 {R200_SE_TCL_LIGHT_MODEL_CTL_0, 6, "R200_SE_TCL_LIGHT_MODEL_CTL_0"},
570 {R200_PP_TFACTOR_0, 6, "R200_PP_TFACTOR_0"},
571 {R200_SE_VTX_FMT_0, 4, "R200_SE_VTX_FMT_0"},
572 {R200_SE_VAP_CNTL, 1, "R200_SE_VAP_CNTL"},
573 {R200_SE_TCL_MATRIX_SEL_0, 5, "R200_SE_TCL_MATRIX_SEL_0"},
574 {R200_SE_TCL_TEX_PROC_CTL_2, 5, "R200_SE_TCL_TEX_PROC_CTL_2"},
575 {R200_SE_TCL_UCP_VERT_BLEND_CTL, 1, "R200_SE_TCL_UCP_VERT_BLEND_CTL"},
576 {R200_PP_TXFILTER_0, 6, "R200_PP_TXFILTER_0"},
577 {R200_PP_TXFILTER_1, 6, "R200_PP_TXFILTER_1"},
578 {R200_PP_TXFILTER_2, 6, "R200_PP_TXFILTER_2"},
579 {R200_PP_TXFILTER_3, 6, "R200_PP_TXFILTER_3"},
580 {R200_PP_TXFILTER_4, 6, "R200_PP_TXFILTER_4"},
581 {R200_PP_TXFILTER_5, 6, "R200_PP_TXFILTER_5"},
582 {R200_PP_TXOFFSET_0, 1, "R200_PP_TXOFFSET_0"},
583 {R200_PP_TXOFFSET_1, 1, "R200_PP_TXOFFSET_1"},
584 {R200_PP_TXOFFSET_2, 1, "R200_PP_TXOFFSET_2"},
585 {R200_PP_TXOFFSET_3, 1, "R200_PP_TXOFFSET_3"},
586 {R200_PP_TXOFFSET_4, 1, "R200_PP_TXOFFSET_4"},
587 {R200_PP_TXOFFSET_5, 1, "R200_PP_TXOFFSET_5"},
588 {R200_SE_VTE_CNTL, 1, "R200_SE_VTE_CNTL"},
Dave Airlied985c102006-01-02 21:32:48 +1100589 {R200_SE_TCL_OUTPUT_VTX_COMP_SEL, 1,
590 "R200_SE_TCL_OUTPUT_VTX_COMP_SEL"},
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000591 {R200_PP_TAM_DEBUG3, 1, "R200_PP_TAM_DEBUG3"},
592 {R200_PP_CNTL_X, 1, "R200_PP_CNTL_X"},
593 {R200_RB3D_DEPTHXY_OFFSET, 1, "R200_RB3D_DEPTHXY_OFFSET"},
594 {R200_RE_AUX_SCISSOR_CNTL, 1, "R200_RE_AUX_SCISSOR_CNTL"},
595 {R200_RE_SCISSOR_TL_0, 2, "R200_RE_SCISSOR_TL_0"},
596 {R200_RE_SCISSOR_TL_1, 2, "R200_RE_SCISSOR_TL_1"},
597 {R200_RE_SCISSOR_TL_2, 2, "R200_RE_SCISSOR_TL_2"},
598 {R200_SE_VAP_CNTL_STATUS, 1, "R200_SE_VAP_CNTL_STATUS"},
599 {R200_SE_VTX_STATE_CNTL, 1, "R200_SE_VTX_STATE_CNTL"},
600 {R200_RE_POINTSIZE, 1, "R200_RE_POINTSIZE"},
601 {R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0, 4,
602 "R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0"},
603 {R200_PP_CUBIC_FACES_0, 1, "R200_PP_CUBIC_FACES_0"}, /* 61 */
Dave Airlied985c102006-01-02 21:32:48 +1100604 {R200_PP_CUBIC_OFFSET_F1_0, 5, "R200_PP_CUBIC_OFFSET_F1_0"}, /* 62 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000605 {R200_PP_CUBIC_FACES_1, 1, "R200_PP_CUBIC_FACES_1"},
606 {R200_PP_CUBIC_OFFSET_F1_1, 5, "R200_PP_CUBIC_OFFSET_F1_1"},
607 {R200_PP_CUBIC_FACES_2, 1, "R200_PP_CUBIC_FACES_2"},
608 {R200_PP_CUBIC_OFFSET_F1_2, 5, "R200_PP_CUBIC_OFFSET_F1_2"},
609 {R200_PP_CUBIC_FACES_3, 1, "R200_PP_CUBIC_FACES_3"},
610 {R200_PP_CUBIC_OFFSET_F1_3, 5, "R200_PP_CUBIC_OFFSET_F1_3"},
611 {R200_PP_CUBIC_FACES_4, 1, "R200_PP_CUBIC_FACES_4"},
612 {R200_PP_CUBIC_OFFSET_F1_4, 5, "R200_PP_CUBIC_OFFSET_F1_4"},
613 {R200_PP_CUBIC_FACES_5, 1, "R200_PP_CUBIC_FACES_5"},
614 {R200_PP_CUBIC_OFFSET_F1_5, 5, "R200_PP_CUBIC_OFFSET_F1_5"},
615 {RADEON_PP_TEX_SIZE_0, 2, "RADEON_PP_TEX_SIZE_0"},
616 {RADEON_PP_TEX_SIZE_1, 2, "RADEON_PP_TEX_SIZE_1"},
617 {RADEON_PP_TEX_SIZE_2, 2, "RADEON_PP_TEX_SIZE_2"},
618 {R200_RB3D_BLENDCOLOR, 3, "R200_RB3D_BLENDCOLOR"},
619 {R200_SE_TCL_POINT_SPRITE_CNTL, 1, "R200_SE_TCL_POINT_SPRITE_CNTL"},
620 {RADEON_PP_CUBIC_FACES_0, 1, "RADEON_PP_CUBIC_FACES_0"},
621 {RADEON_PP_CUBIC_OFFSET_T0_0, 5, "RADEON_PP_CUBIC_OFFSET_T0_0"},
622 {RADEON_PP_CUBIC_FACES_1, 1, "RADEON_PP_CUBIC_FACES_1"},
623 {RADEON_PP_CUBIC_OFFSET_T1_0, 5, "RADEON_PP_CUBIC_OFFSET_T1_0"},
624 {RADEON_PP_CUBIC_FACES_2, 1, "RADEON_PP_CUBIC_FACES_2"},
625 {RADEON_PP_CUBIC_OFFSET_T2_0, 5, "RADEON_PP_CUBIC_OFFSET_T2_0"},
626 {R200_PP_TRI_PERF, 2, "R200_PP_TRI_PERF"},
Dave Airlied985c102006-01-02 21:32:48 +1100627 {R200_PP_AFS_0, 32, "R200_PP_AFS_0"}, /* 85 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000628 {R200_PP_AFS_1, 32, "R200_PP_AFS_1"},
629 {R200_PP_TFACTOR_0, 8, "R200_ATF_TFACTOR"},
630 {R200_PP_TXFILTER_0, 8, "R200_PP_TXCTLALL_0"},
631 {R200_PP_TXFILTER_1, 8, "R200_PP_TXCTLALL_1"},
632 {R200_PP_TXFILTER_2, 8, "R200_PP_TXCTLALL_2"},
633 {R200_PP_TXFILTER_3, 8, "R200_PP_TXCTLALL_3"},
634 {R200_PP_TXFILTER_4, 8, "R200_PP_TXCTLALL_4"},
635 {R200_PP_TXFILTER_5, 8, "R200_PP_TXCTLALL_5"},
Dave Airlied6fece02006-06-24 17:04:07 +1000636 {R200_VAP_PVS_CNTL_1, 2, "R200_VAP_PVS_CNTL"},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637};
638
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639/* ================================================================
640 * Performance monitoring functions
641 */
642
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000643static void radeon_clear_box(drm_radeon_private_t * dev_priv,
644 int x, int y, int w, int h, int r, int g, int b)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645{
646 u32 color;
647 RING_LOCALS;
648
649 x += dev_priv->sarea_priv->boxes[0].x1;
650 y += dev_priv->sarea_priv->boxes[0].y1;
651
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000652 switch (dev_priv->color_fmt) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 case RADEON_COLOR_FORMAT_RGB565:
654 color = (((r & 0xf8) << 8) |
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000655 ((g & 0xfc) << 3) | ((b & 0xf8) >> 3));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 break;
657 case RADEON_COLOR_FORMAT_ARGB8888:
658 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000659 color = (((0xff) << 24) | (r << 16) | (g << 8) | b);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 break;
661 }
662
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000663 BEGIN_RING(4);
664 RADEON_WAIT_UNTIL_3D_IDLE();
665 OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0));
666 OUT_RING(0xffffffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 ADVANCE_RING();
668
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000669 BEGIN_RING(6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000671 OUT_RING(CP_PACKET3(RADEON_CNTL_PAINT_MULTI, 4));
672 OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
673 RADEON_GMC_BRUSH_SOLID_COLOR |
674 (dev_priv->color_fmt << 8) |
675 RADEON_GMC_SRC_DATATYPE_COLOR |
676 RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000678 if (dev_priv->page_flipping && dev_priv->current_page == 1) {
679 OUT_RING(dev_priv->front_pitch_offset);
680 } else {
681 OUT_RING(dev_priv->back_pitch_offset);
682 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000684 OUT_RING(color);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000686 OUT_RING((x << 16) | y);
687 OUT_RING((w << 16) | h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688
689 ADVANCE_RING();
690}
691
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000692static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693{
694 /* Collapse various things into a wait flag -- trying to
695 * guess if userspase slept -- better just to have them tell us.
696 */
697 if (dev_priv->stats.last_frame_reads > 1 ||
698 dev_priv->stats.last_clear_reads > dev_priv->stats.clears) {
699 dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
700 }
701
702 if (dev_priv->stats.freelist_loops) {
703 dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
704 }
705
706 /* Purple box for page flipping
707 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000708 if (dev_priv->stats.boxes & RADEON_BOX_FLIP)
709 radeon_clear_box(dev_priv, 4, 4, 8, 8, 255, 0, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
711 /* Red box if we have to wait for idle at any point
712 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000713 if (dev_priv->stats.boxes & RADEON_BOX_WAIT_IDLE)
714 radeon_clear_box(dev_priv, 16, 4, 8, 8, 255, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
716 /* Blue box: lost context?
717 */
718
719 /* Yellow box for texture swaps
720 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000721 if (dev_priv->stats.boxes & RADEON_BOX_TEXTURE_LOAD)
722 radeon_clear_box(dev_priv, 40, 4, 8, 8, 255, 255, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
724 /* Green box if hardware never idles (as far as we can tell)
725 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000726 if (!(dev_priv->stats.boxes & RADEON_BOX_DMA_IDLE))
727 radeon_clear_box(dev_priv, 64, 4, 8, 8, 0, 255, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000729 /* Draw bars indicating number of buffers allocated
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 * (not a great measure, easily confused)
731 */
732 if (dev_priv->stats.requested_bufs) {
733 if (dev_priv->stats.requested_bufs > 100)
734 dev_priv->stats.requested_bufs = 100;
735
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000736 radeon_clear_box(dev_priv, 4, 16,
737 dev_priv->stats.requested_bufs, 4,
738 196, 128, 128);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 }
740
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000741 memset(&dev_priv->stats, 0, sizeof(dev_priv->stats));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
743}
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000744
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745/* ================================================================
746 * CP command dispatch functions
747 */
748
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000749static void radeon_cp_dispatch_clear(drm_device_t * dev,
750 drm_radeon_clear_t * clear,
751 drm_radeon_clear_rect_t * depth_boxes)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752{
753 drm_radeon_private_t *dev_priv = dev->dev_private;
754 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
755 drm_radeon_depth_clear_t *depth_clear = &dev_priv->depth_clear;
756 int nbox = sarea_priv->nbox;
757 drm_clip_rect_t *pbox = sarea_priv->boxes;
758 unsigned int flags = clear->flags;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000759 u32 rb3d_cntl = 0, rb3d_stencilrefmask = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 int i;
761 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000762 DRM_DEBUG("flags = 0x%x\n", flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
764 dev_priv->stats.clears++;
765
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000766 if (dev_priv->page_flipping && dev_priv->current_page == 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 unsigned int tmp = flags;
768
769 flags &= ~(RADEON_FRONT | RADEON_BACK);
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000770 if (tmp & RADEON_FRONT)
771 flags |= RADEON_BACK;
772 if (tmp & RADEON_BACK)
773 flags |= RADEON_FRONT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 }
775
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000776 if (flags & (RADEON_FRONT | RADEON_BACK)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000778 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
780 /* Ensure the 3D stream is idle before doing a
781 * 2D fill to clear the front or back buffer.
782 */
783 RADEON_WAIT_UNTIL_3D_IDLE();
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000784
785 OUT_RING(CP_PACKET0(RADEON_DP_WRITE_MASK, 0));
786 OUT_RING(clear->color_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
788 ADVANCE_RING();
789
790 /* Make sure we restore the 3D state next time.
791 */
792 dev_priv->sarea_priv->ctx_owner = 0;
793
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000794 for (i = 0; i < nbox; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 int x = pbox[i].x1;
796 int y = pbox[i].y1;
797 int w = pbox[i].x2 - x;
798 int h = pbox[i].y2 - y;
799
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000800 DRM_DEBUG("dispatch clear %d,%d-%d,%d flags 0x%x\n",
801 x, y, w, h, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000803 if (flags & RADEON_FRONT) {
804 BEGIN_RING(6);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000806 OUT_RING(CP_PACKET3
807 (RADEON_CNTL_PAINT_MULTI, 4));
808 OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
809 RADEON_GMC_BRUSH_SOLID_COLOR |
810 (dev_priv->
811 color_fmt << 8) |
812 RADEON_GMC_SRC_DATATYPE_COLOR |
813 RADEON_ROP3_P |
814 RADEON_GMC_CLR_CMP_CNTL_DIS);
815
816 OUT_RING(dev_priv->front_pitch_offset);
817 OUT_RING(clear->clear_color);
818
819 OUT_RING((x << 16) | y);
820 OUT_RING((w << 16) | h);
821
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 ADVANCE_RING();
823 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000825 if (flags & RADEON_BACK) {
826 BEGIN_RING(6);
827
828 OUT_RING(CP_PACKET3
829 (RADEON_CNTL_PAINT_MULTI, 4));
830 OUT_RING(RADEON_GMC_DST_PITCH_OFFSET_CNTL |
831 RADEON_GMC_BRUSH_SOLID_COLOR |
832 (dev_priv->
833 color_fmt << 8) |
834 RADEON_GMC_SRC_DATATYPE_COLOR |
835 RADEON_ROP3_P |
836 RADEON_GMC_CLR_CMP_CNTL_DIS);
837
838 OUT_RING(dev_priv->back_pitch_offset);
839 OUT_RING(clear->clear_color);
840
841 OUT_RING((x << 16) | y);
842 OUT_RING((w << 16) | h);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843
844 ADVANCE_RING();
845 }
846 }
847 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000848
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 /* hyper z clear */
850 /* no docs available, based on reverse engeneering by Stephane Marchesin */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000851 if ((flags & (RADEON_DEPTH | RADEON_STENCIL))
852 && (flags & RADEON_CLEAR_FASTZ)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853
854 int i;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000855 int depthpixperline =
856 dev_priv->depth_fmt ==
857 RADEON_DEPTH_FORMAT_16BIT_INT_Z ? (dev_priv->depth_pitch /
858 2) : (dev_priv->
859 depth_pitch / 4);
860
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 u32 clearmask;
862
863 u32 tempRB3D_DEPTHCLEARVALUE = clear->clear_depth |
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000864 ((clear->depth_mask & 0xff) << 24);
865
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 /* Make sure we restore the 3D state next time.
867 * we haven't touched any "normal" state - still need this?
868 */
869 dev_priv->sarea_priv->ctx_owner = 0;
870
Dave Airlie54a56ac2006-09-22 04:25:09 +1000871 if ((dev_priv->flags & RADEON_HAS_HIERZ)
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000872 && (flags & RADEON_USE_HIERZ)) {
873 /* FIXME : reverse engineer that for Rx00 cards */
874 /* FIXME : the mask supposedly contains low-res z values. So can't set
875 just to the max (0xff? or actually 0x3fff?), need to take z clear
876 value into account? */
877 /* pattern seems to work for r100, though get slight
878 rendering errors with glxgears. If hierz is not enabled for r100,
879 only 4 bits which indicate clear (15,16,31,32, all zero) matter, the
880 other ones are ignored, and the same clear mask can be used. That's
881 very different behaviour than R200 which needs different clear mask
882 and different number of tiles to clear if hierz is enabled or not !?!
883 */
884 clearmask = (0xff << 22) | (0xff << 6) | 0x003f003f;
885 } else {
886 /* clear mask : chooses the clearing pattern.
887 rv250: could be used to clear only parts of macrotiles
888 (but that would get really complicated...)?
889 bit 0 and 1 (either or both of them ?!?!) are used to
890 not clear tile (or maybe one of the bits indicates if the tile is
891 compressed or not), bit 2 and 3 to not clear tile 1,...,.
892 Pattern is as follows:
893 | 0,1 | 4,5 | 8,9 |12,13|16,17|20,21|24,25|28,29|
894 bits -------------------------------------------------
895 | 2,3 | 6,7 |10,11|14,15|18,19|22,23|26,27|30,31|
896 rv100: clearmask covers 2x8 4x1 tiles, but one clear still
897 covers 256 pixels ?!?
898 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 clearmask = 0x0;
900 }
901
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000902 BEGIN_RING(8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 RADEON_WAIT_UNTIL_2D_IDLE();
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000904 OUT_RING_REG(RADEON_RB3D_DEPTHCLEARVALUE,
905 tempRB3D_DEPTHCLEARVALUE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 /* what offset is this exactly ? */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000907 OUT_RING_REG(RADEON_RB3D_ZMASKOFFSET, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 /* need ctlstat, otherwise get some strange black flickering */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000909 OUT_RING_REG(RADEON_RB3D_ZCACHE_CTLSTAT,
910 RADEON_RB3D_ZC_FLUSH_ALL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 ADVANCE_RING();
912
913 for (i = 0; i < nbox; i++) {
914 int tileoffset, nrtilesx, nrtilesy, j;
915 /* it looks like r200 needs rv-style clears, at least if hierz is not enabled? */
Dave Airlie54a56ac2006-09-22 04:25:09 +1000916 if ((dev_priv->flags & RADEON_HAS_HIERZ)
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000917 && !(dev_priv->microcode_version == UCODE_R200)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 /* FIXME : figure this out for r200 (when hierz is enabled). Or
919 maybe r200 actually doesn't need to put the low-res z value into
920 the tile cache like r100, but just needs to clear the hi-level z-buffer?
921 Works for R100, both with hierz and without.
922 R100 seems to operate on 2x1 8x8 tiles, but...
923 odd: offset/nrtiles need to be 64 pix (4 block) aligned? Potentially
924 problematic with resolutions which are not 64 pix aligned? */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000925 tileoffset =
926 ((pbox[i].y1 >> 3) * depthpixperline +
927 pbox[i].x1) >> 6;
928 nrtilesx =
929 ((pbox[i].x2 & ~63) -
930 (pbox[i].x1 & ~63)) >> 4;
931 nrtilesy =
932 (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 for (j = 0; j <= nrtilesy; j++) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000934 BEGIN_RING(4);
935 OUT_RING(CP_PACKET3
936 (RADEON_3D_CLEAR_ZMASK, 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 /* first tile */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000938 OUT_RING(tileoffset * 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 /* the number of tiles to clear */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000940 OUT_RING(nrtilesx + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 /* clear mask : chooses the clearing pattern. */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000942 OUT_RING(clearmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 ADVANCE_RING();
944 tileoffset += depthpixperline >> 6;
945 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000946 } else if (dev_priv->microcode_version == UCODE_R200) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 /* works for rv250. */
948 /* find first macro tile (8x2 4x4 z-pixels on rv250) */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000949 tileoffset =
950 ((pbox[i].y1 >> 3) * depthpixperline +
951 pbox[i].x1) >> 5;
952 nrtilesx =
953 (pbox[i].x2 >> 5) - (pbox[i].x1 >> 5);
954 nrtilesy =
955 (pbox[i].y2 >> 3) - (pbox[i].y1 >> 3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 for (j = 0; j <= nrtilesy; j++) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000957 BEGIN_RING(4);
958 OUT_RING(CP_PACKET3
959 (RADEON_3D_CLEAR_ZMASK, 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 /* first tile */
961 /* judging by the first tile offset needed, could possibly
962 directly address/clear 4x4 tiles instead of 8x2 * 4x4
963 macro tiles, though would still need clear mask for
964 right/bottom if truely 4x4 granularity is desired ? */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000965 OUT_RING(tileoffset * 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 /* the number of tiles to clear */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000967 OUT_RING(nrtilesx + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 /* clear mask : chooses the clearing pattern. */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000969 OUT_RING(clearmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 ADVANCE_RING();
971 tileoffset += depthpixperline >> 5;
972 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000973 } else { /* rv 100 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 /* rv100 might not need 64 pix alignment, who knows */
975 /* offsets are, hmm, weird */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000976 tileoffset =
977 ((pbox[i].y1 >> 4) * depthpixperline +
978 pbox[i].x1) >> 6;
979 nrtilesx =
980 ((pbox[i].x2 & ~63) -
981 (pbox[i].x1 & ~63)) >> 4;
982 nrtilesy =
983 (pbox[i].y2 >> 4) - (pbox[i].y1 >> 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 for (j = 0; j <= nrtilesy; j++) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000985 BEGIN_RING(4);
986 OUT_RING(CP_PACKET3
987 (RADEON_3D_CLEAR_ZMASK, 2));
988 OUT_RING(tileoffset * 128);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 /* the number of tiles to clear */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000990 OUT_RING(nrtilesx + 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 /* clear mask : chooses the clearing pattern. */
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000992 OUT_RING(clearmask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 ADVANCE_RING();
994 tileoffset += depthpixperline >> 6;
995 }
996 }
997 }
998
999 /* TODO don't always clear all hi-level z tiles */
Dave Airlie54a56ac2006-09-22 04:25:09 +10001000 if ((dev_priv->flags & RADEON_HAS_HIERZ)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001001 && (dev_priv->microcode_version == UCODE_R200)
1002 && (flags & RADEON_USE_HIERZ))
1003 /* r100 and cards without hierarchical z-buffer have no high-level z-buffer */
1004 /* FIXME : the mask supposedly contains low-res z values. So can't set
1005 just to the max (0xff? or actually 0x3fff?), need to take z clear
1006 value into account? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001008 BEGIN_RING(4);
1009 OUT_RING(CP_PACKET3(RADEON_3D_CLEAR_HIZ, 2));
1010 OUT_RING(0x0); /* First tile */
1011 OUT_RING(0x3cc0);
1012 OUT_RING((0xff << 22) | (0xff << 6) | 0x003f003f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 ADVANCE_RING();
1014 }
1015 }
1016
1017 /* We have to clear the depth and/or stencil buffers by
1018 * rendering a quad into just those buffers. Thus, we have to
1019 * make sure the 3D engine is configured correctly.
1020 */
Dave Airlied985c102006-01-02 21:32:48 +11001021 else if ((dev_priv->microcode_version == UCODE_R200) &&
1022 (flags & (RADEON_DEPTH | RADEON_STENCIL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023
1024 int tempPP_CNTL;
1025 int tempRE_CNTL;
1026 int tempRB3D_CNTL;
1027 int tempRB3D_ZSTENCILCNTL;
1028 int tempRB3D_STENCILREFMASK;
1029 int tempRB3D_PLANEMASK;
1030 int tempSE_CNTL;
1031 int tempSE_VTE_CNTL;
1032 int tempSE_VTX_FMT_0;
1033 int tempSE_VTX_FMT_1;
1034 int tempSE_VAP_CNTL;
1035 int tempRE_AUX_SCISSOR_CNTL;
1036
1037 tempPP_CNTL = 0;
1038 tempRE_CNTL = 0;
1039
1040 tempRB3D_CNTL = depth_clear->rb3d_cntl;
1041
1042 tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl;
1043 tempRB3D_STENCILREFMASK = 0x0;
1044
1045 tempSE_CNTL = depth_clear->se_cntl;
1046
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 /* Disable TCL */
1048
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001049 tempSE_VAP_CNTL = ( /* SE_VAP_CNTL__FORCE_W_TO_ONE_MASK | */
1050 (0x9 <<
1051 SE_VAP_CNTL__VF_MAX_VTX_NUM__SHIFT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052
1053 tempRB3D_PLANEMASK = 0x0;
1054
1055 tempRE_AUX_SCISSOR_CNTL = 0x0;
1056
1057 tempSE_VTE_CNTL =
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001058 SE_VTE_CNTL__VTX_XY_FMT_MASK | SE_VTE_CNTL__VTX_Z_FMT_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001060 /* Vertex format (X, Y, Z, W) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 tempSE_VTX_FMT_0 =
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001062 SE_VTX_FMT_0__VTX_Z0_PRESENT_MASK |
1063 SE_VTX_FMT_0__VTX_W0_PRESENT_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 tempSE_VTX_FMT_1 = 0x0;
1065
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001066 /*
1067 * Depth buffer specific enables
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 */
1069 if (flags & RADEON_DEPTH) {
1070 /* Enable depth buffer */
1071 tempRB3D_CNTL |= RADEON_Z_ENABLE;
1072 } else {
1073 /* Disable depth buffer */
1074 tempRB3D_CNTL &= ~RADEON_Z_ENABLE;
1075 }
1076
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001077 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 * Stencil buffer specific enables
1079 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001080 if (flags & RADEON_STENCIL) {
1081 tempRB3D_CNTL |= RADEON_STENCIL_ENABLE;
1082 tempRB3D_STENCILREFMASK = clear->depth_mask;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 } else {
1084 tempRB3D_CNTL &= ~RADEON_STENCIL_ENABLE;
1085 tempRB3D_STENCILREFMASK = 0x00000000;
1086 }
1087
1088 if (flags & RADEON_USE_COMP_ZBUF) {
1089 tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE |
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001090 RADEON_Z_DECOMPRESSION_ENABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 }
1092 if (flags & RADEON_USE_HIERZ) {
1093 tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE;
1094 }
1095
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001096 BEGIN_RING(26);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 RADEON_WAIT_UNTIL_2D_IDLE();
1098
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001099 OUT_RING_REG(RADEON_PP_CNTL, tempPP_CNTL);
1100 OUT_RING_REG(R200_RE_CNTL, tempRE_CNTL);
1101 OUT_RING_REG(RADEON_RB3D_CNTL, tempRB3D_CNTL);
1102 OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL);
1103 OUT_RING_REG(RADEON_RB3D_STENCILREFMASK,
1104 tempRB3D_STENCILREFMASK);
1105 OUT_RING_REG(RADEON_RB3D_PLANEMASK, tempRB3D_PLANEMASK);
1106 OUT_RING_REG(RADEON_SE_CNTL, tempSE_CNTL);
1107 OUT_RING_REG(R200_SE_VTE_CNTL, tempSE_VTE_CNTL);
1108 OUT_RING_REG(R200_SE_VTX_FMT_0, tempSE_VTX_FMT_0);
1109 OUT_RING_REG(R200_SE_VTX_FMT_1, tempSE_VTX_FMT_1);
1110 OUT_RING_REG(R200_SE_VAP_CNTL, tempSE_VAP_CNTL);
1111 OUT_RING_REG(R200_RE_AUX_SCISSOR_CNTL, tempRE_AUX_SCISSOR_CNTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 ADVANCE_RING();
1113
1114 /* Make sure we restore the 3D state next time.
1115 */
1116 dev_priv->sarea_priv->ctx_owner = 0;
1117
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001118 for (i = 0; i < nbox; i++) {
1119
1120 /* Funny that this should be required --
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 * sets top-left?
1122 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001123 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001125 BEGIN_RING(14);
1126 OUT_RING(CP_PACKET3(R200_3D_DRAW_IMMD_2, 12));
1127 OUT_RING((RADEON_PRIM_TYPE_RECT_LIST |
1128 RADEON_PRIM_WALK_RING |
1129 (3 << RADEON_NUM_VERTICES_SHIFT)));
1130 OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1131 OUT_RING(depth_boxes[i].ui[CLEAR_Y1]);
1132 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1133 OUT_RING(0x3f800000);
1134 OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1135 OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1136 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1137 OUT_RING(0x3f800000);
1138 OUT_RING(depth_boxes[i].ui[CLEAR_X2]);
1139 OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1140 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1141 OUT_RING(0x3f800000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 ADVANCE_RING();
1143 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001144 } else if ((flags & (RADEON_DEPTH | RADEON_STENCIL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
1146 int tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl;
1147
1148 rb3d_cntl = depth_clear->rb3d_cntl;
1149
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001150 if (flags & RADEON_DEPTH) {
1151 rb3d_cntl |= RADEON_Z_ENABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 } else {
1153 rb3d_cntl &= ~RADEON_Z_ENABLE;
1154 }
1155
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001156 if (flags & RADEON_STENCIL) {
1157 rb3d_cntl |= RADEON_STENCIL_ENABLE;
1158 rb3d_stencilrefmask = clear->depth_mask; /* misnamed field */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 } else {
1160 rb3d_cntl &= ~RADEON_STENCIL_ENABLE;
1161 rb3d_stencilrefmask = 0x00000000;
1162 }
1163
1164 if (flags & RADEON_USE_COMP_ZBUF) {
1165 tempRB3D_ZSTENCILCNTL |= RADEON_Z_COMPRESSION_ENABLE |
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001166 RADEON_Z_DECOMPRESSION_ENABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 }
1168 if (flags & RADEON_USE_HIERZ) {
1169 tempRB3D_ZSTENCILCNTL |= RADEON_Z_HIERARCHY_ENABLE;
1170 }
1171
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001172 BEGIN_RING(13);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 RADEON_WAIT_UNTIL_2D_IDLE();
1174
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001175 OUT_RING(CP_PACKET0(RADEON_PP_CNTL, 1));
1176 OUT_RING(0x00000000);
1177 OUT_RING(rb3d_cntl);
1178
1179 OUT_RING_REG(RADEON_RB3D_ZSTENCILCNTL, tempRB3D_ZSTENCILCNTL);
1180 OUT_RING_REG(RADEON_RB3D_STENCILREFMASK, rb3d_stencilrefmask);
1181 OUT_RING_REG(RADEON_RB3D_PLANEMASK, 0x00000000);
1182 OUT_RING_REG(RADEON_SE_CNTL, depth_clear->se_cntl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 ADVANCE_RING();
1184
1185 /* Make sure we restore the 3D state next time.
1186 */
1187 dev_priv->sarea_priv->ctx_owner = 0;
1188
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001189 for (i = 0; i < nbox; i++) {
1190
1191 /* Funny that this should be required --
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 * sets top-left?
1193 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001194 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001196 BEGIN_RING(15);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001198 OUT_RING(CP_PACKET3(RADEON_3D_DRAW_IMMD, 13));
1199 OUT_RING(RADEON_VTX_Z_PRESENT |
1200 RADEON_VTX_PKCOLOR_PRESENT);
1201 OUT_RING((RADEON_PRIM_TYPE_RECT_LIST |
1202 RADEON_PRIM_WALK_RING |
1203 RADEON_MAOS_ENABLE |
1204 RADEON_VTX_FMT_RADEON_MODE |
1205 (3 << RADEON_NUM_VERTICES_SHIFT)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001207 OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1208 OUT_RING(depth_boxes[i].ui[CLEAR_Y1]);
1209 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1210 OUT_RING(0x0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001212 OUT_RING(depth_boxes[i].ui[CLEAR_X1]);
1213 OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1214 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1215 OUT_RING(0x0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001217 OUT_RING(depth_boxes[i].ui[CLEAR_X2]);
1218 OUT_RING(depth_boxes[i].ui[CLEAR_Y2]);
1219 OUT_RING(depth_boxes[i].ui[CLEAR_DEPTH]);
1220 OUT_RING(0x0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221
1222 ADVANCE_RING();
1223 }
1224 }
1225
1226 /* Increment the clear counter. The client-side 3D driver must
1227 * wait on this value before performing the clear ioctl. We
1228 * need this because the card's so damned fast...
1229 */
1230 dev_priv->sarea_priv->last_clear++;
1231
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001232 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001234 RADEON_CLEAR_AGE(dev_priv->sarea_priv->last_clear);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 RADEON_WAIT_UNTIL_IDLE();
1236
1237 ADVANCE_RING();
1238}
1239
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001240static void radeon_cp_dispatch_swap(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241{
1242 drm_radeon_private_t *dev_priv = dev->dev_private;
1243 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
1244 int nbox = sarea_priv->nbox;
1245 drm_clip_rect_t *pbox = sarea_priv->boxes;
1246 int i;
1247 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001248 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249
1250 /* Do some trivial performance monitoring...
1251 */
1252 if (dev_priv->do_boxes)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001253 radeon_cp_performance_boxes(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254
1255 /* Wait for the 3D stream to idle before dispatching the bitblt.
1256 * This will prevent data corruption between the two streams.
1257 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001258 BEGIN_RING(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259
1260 RADEON_WAIT_UNTIL_3D_IDLE();
1261
1262 ADVANCE_RING();
1263
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001264 for (i = 0; i < nbox; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 int x = pbox[i].x1;
1266 int y = pbox[i].y1;
1267 int w = pbox[i].x2 - x;
1268 int h = pbox[i].y2 - y;
1269
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001270 DRM_DEBUG("dispatch swap %d,%d-%d,%d\n", x, y, w, h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001272 BEGIN_RING(7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001274 OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
1275 OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
1276 RADEON_GMC_DST_PITCH_OFFSET_CNTL |
1277 RADEON_GMC_BRUSH_NONE |
1278 (dev_priv->color_fmt << 8) |
1279 RADEON_GMC_SRC_DATATYPE_COLOR |
1280 RADEON_ROP3_S |
1281 RADEON_DP_SRC_SOURCE_MEMORY |
1282 RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
1283
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 /* Make this work even if front & back are flipped:
1285 */
1286 if (dev_priv->current_page == 0) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001287 OUT_RING(dev_priv->back_pitch_offset);
1288 OUT_RING(dev_priv->front_pitch_offset);
1289 } else {
1290 OUT_RING(dev_priv->front_pitch_offset);
1291 OUT_RING(dev_priv->back_pitch_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 }
1293
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001294 OUT_RING((x << 16) | y);
1295 OUT_RING((x << 16) | y);
1296 OUT_RING((w << 16) | h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297
1298 ADVANCE_RING();
1299 }
1300
1301 /* Increment the frame counter. The client-side 3D driver must
1302 * throttle the framerate by waiting for this value before
1303 * performing the swapbuffer ioctl.
1304 */
1305 dev_priv->sarea_priv->last_frame++;
1306
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001307 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001309 RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 RADEON_WAIT_UNTIL_2D_IDLE();
1311
1312 ADVANCE_RING();
1313}
1314
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001315static void radeon_cp_dispatch_flip(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316{
1317 drm_radeon_private_t *dev_priv = dev->dev_private;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001318 drm_sarea_t *sarea = (drm_sarea_t *) dev_priv->sarea->handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 int offset = (dev_priv->current_page == 1)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001320 ? dev_priv->front_offset : dev_priv->back_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001322 DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
1323 __FUNCTION__,
1324 dev_priv->current_page, dev_priv->sarea_priv->pfCurrentPage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325
1326 /* Do some trivial performance monitoring...
1327 */
1328 if (dev_priv->do_boxes) {
1329 dev_priv->stats.boxes |= RADEON_BOX_FLIP;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001330 radeon_cp_performance_boxes(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 }
1332
1333 /* Update the frame offsets for both CRTCs
1334 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001335 BEGIN_RING(6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336
1337 RADEON_WAIT_UNTIL_3D_IDLE();
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001338 OUT_RING_REG(RADEON_CRTC_OFFSET,
1339 ((sarea->frame.y * dev_priv->front_pitch +
1340 sarea->frame.x * (dev_priv->color_fmt - 2)) & ~7)
1341 + offset);
1342 OUT_RING_REG(RADEON_CRTC2_OFFSET, dev_priv->sarea_priv->crtc2_base
1343 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344
1345 ADVANCE_RING();
1346
1347 /* Increment the frame counter. The client-side 3D driver must
1348 * throttle the framerate by waiting for this value before
1349 * performing the swapbuffer ioctl.
1350 */
1351 dev_priv->sarea_priv->last_frame++;
1352 dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page =
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001353 1 - dev_priv->current_page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001355 BEGIN_RING(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001357 RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358
1359 ADVANCE_RING();
1360}
1361
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001362static int bad_prim_vertex_nr(int primitive, int nr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363{
1364 switch (primitive & RADEON_PRIM_TYPE_MASK) {
1365 case RADEON_PRIM_TYPE_NONE:
1366 case RADEON_PRIM_TYPE_POINT:
1367 return nr < 1;
1368 case RADEON_PRIM_TYPE_LINE:
1369 return (nr & 1) || nr == 0;
1370 case RADEON_PRIM_TYPE_LINE_STRIP:
1371 return nr < 2;
1372 case RADEON_PRIM_TYPE_TRI_LIST:
1373 case RADEON_PRIM_TYPE_3VRT_POINT_LIST:
1374 case RADEON_PRIM_TYPE_3VRT_LINE_LIST:
1375 case RADEON_PRIM_TYPE_RECT_LIST:
1376 return nr % 3 || nr == 0;
1377 case RADEON_PRIM_TYPE_TRI_FAN:
1378 case RADEON_PRIM_TYPE_TRI_STRIP:
1379 return nr < 3;
1380 default:
1381 return 1;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001382 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383}
1384
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385typedef struct {
1386 unsigned int start;
1387 unsigned int finish;
1388 unsigned int prim;
1389 unsigned int numverts;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001390 unsigned int offset;
1391 unsigned int vc_format;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392} drm_radeon_tcl_prim_t;
1393
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001394static void radeon_cp_dispatch_vertex(drm_device_t * dev,
1395 drm_buf_t * buf,
1396 drm_radeon_tcl_prim_t * prim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397{
1398 drm_radeon_private_t *dev_priv = dev->dev_private;
1399 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
1400 int offset = dev_priv->gart_buffers_offset + buf->offset + prim->start;
1401 int numverts = (int)prim->numverts;
1402 int nbox = sarea_priv->nbox;
1403 int i = 0;
1404 RING_LOCALS;
1405
1406 DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d %d verts\n",
1407 prim->prim,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001408 prim->vc_format, prim->start, prim->finish, prim->numverts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001410 if (bad_prim_vertex_nr(prim->prim, prim->numverts)) {
1411 DRM_ERROR("bad prim %x numverts %d\n",
1412 prim->prim, prim->numverts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 return;
1414 }
1415
1416 do {
1417 /* Emit the next cliprect */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001418 if (i < nbox) {
1419 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 }
1421
1422 /* Emit the vertex buffer rendering commands */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001423 BEGIN_RING(5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001425 OUT_RING(CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, 3));
1426 OUT_RING(offset);
1427 OUT_RING(numverts);
1428 OUT_RING(prim->vc_format);
1429 OUT_RING(prim->prim | RADEON_PRIM_WALK_LIST |
1430 RADEON_COLOR_ORDER_RGBA |
1431 RADEON_VTX_FMT_RADEON_MODE |
1432 (numverts << RADEON_NUM_VERTICES_SHIFT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433
1434 ADVANCE_RING();
1435
1436 i++;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001437 } while (i < nbox);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438}
1439
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001440static void radeon_cp_discard_buffer(drm_device_t * dev, drm_buf_t * buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441{
1442 drm_radeon_private_t *dev_priv = dev->dev_private;
1443 drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
1444 RING_LOCALS;
1445
1446 buf_priv->age = ++dev_priv->sarea_priv->last_dispatch;
1447
1448 /* Emit the vertex buffer age */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001449 BEGIN_RING(2);
1450 RADEON_DISPATCH_AGE(buf_priv->age);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 ADVANCE_RING();
1452
1453 buf->pending = 1;
1454 buf->used = 0;
1455}
1456
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001457static void radeon_cp_dispatch_indirect(drm_device_t * dev,
1458 drm_buf_t * buf, int start, int end)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459{
1460 drm_radeon_private_t *dev_priv = dev->dev_private;
1461 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001462 DRM_DEBUG("indirect: buf=%d s=0x%x e=0x%x\n", buf->idx, start, end);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001464 if (start != end) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 int offset = (dev_priv->gart_buffers_offset
1466 + buf->offset + start);
1467 int dwords = (end - start + 3) / sizeof(u32);
1468
1469 /* Indirect buffer data must be an even number of
1470 * dwords, so if we've been given an odd number we must
1471 * pad the data with a Type-2 CP packet.
1472 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001473 if (dwords & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 u32 *data = (u32 *)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001475 ((char *)dev->agp_buffer_map->handle
1476 + buf->offset + start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 data[dwords++] = RADEON_CP_PACKET2;
1478 }
1479
1480 /* Fire off the indirect buffer */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001481 BEGIN_RING(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001483 OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1));
1484 OUT_RING(offset);
1485 OUT_RING(dwords);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486
1487 ADVANCE_RING();
1488 }
1489}
1490
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001491static void radeon_cp_dispatch_indices(drm_device_t * dev,
1492 drm_buf_t * elt_buf,
1493 drm_radeon_tcl_prim_t * prim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494{
1495 drm_radeon_private_t *dev_priv = dev->dev_private;
1496 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
1497 int offset = dev_priv->gart_buffers_offset + prim->offset;
1498 u32 *data;
1499 int dwords;
1500 int i = 0;
1501 int start = prim->start + RADEON_INDEX_PRIM_OFFSET;
1502 int count = (prim->finish - start) / sizeof(u16);
1503 int nbox = sarea_priv->nbox;
1504
1505 DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d offset: %x nr %d\n",
1506 prim->prim,
1507 prim->vc_format,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001508 prim->start, prim->finish, prim->offset, prim->numverts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001510 if (bad_prim_vertex_nr(prim->prim, count)) {
1511 DRM_ERROR("bad prim %x count %d\n", prim->prim, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 return;
1513 }
1514
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001515 if (start >= prim->finish || (prim->start & 0x7)) {
1516 DRM_ERROR("buffer prim %d\n", prim->prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 return;
1518 }
1519
1520 dwords = (prim->finish - prim->start + 3) / sizeof(u32);
1521
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001522 data = (u32 *) ((char *)dev->agp_buffer_map->handle +
1523 elt_buf->offset + prim->start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001525 data[0] = CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, dwords - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 data[1] = offset;
1527 data[2] = prim->numverts;
1528 data[3] = prim->vc_format;
1529 data[4] = (prim->prim |
1530 RADEON_PRIM_WALK_IND |
1531 RADEON_COLOR_ORDER_RGBA |
1532 RADEON_VTX_FMT_RADEON_MODE |
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001533 (count << RADEON_NUM_VERTICES_SHIFT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534
1535 do {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001536 if (i < nbox)
1537 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001539 radeon_cp_dispatch_indirect(dev, elt_buf,
1540 prim->start, prim->finish);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541
1542 i++;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001543 } while (i < nbox);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544
1545}
1546
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001547#define RADEON_MAX_TEXTURE_SIZE RADEON_BUFFER_SIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001549static int radeon_cp_dispatch_texture(DRMFILE filp,
1550 drm_device_t * dev,
1551 drm_radeon_texture_t * tex,
1552 drm_radeon_tex_image_t * image)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553{
1554 drm_radeon_private_t *dev_priv = dev->dev_private;
1555 drm_file_t *filp_priv;
1556 drm_buf_t *buf;
1557 u32 format;
1558 u32 *buffer;
1559 const u8 __user *data;
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001560 int size, dwords, tex_width, blit_width, spitch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 u32 height;
1562 int i;
1563 u32 texpitch, microtile;
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001564 u32 offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 RING_LOCALS;
1566
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001567 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001569 if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &tex->offset)) {
1570 DRM_ERROR("Invalid destination offset\n");
1571 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 }
1573
1574 dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD;
1575
1576 /* Flush the pixel cache. This ensures no pixel data gets mixed
1577 * up with the texture data from the host data blit, otherwise
1578 * part of the texture image may be corrupted.
1579 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001580 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 RADEON_FLUSH_CACHE();
1582 RADEON_WAIT_UNTIL_IDLE();
1583 ADVANCE_RING();
1584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 /* The compiler won't optimize away a division by a variable,
1586 * even if the only legal values are powers of two. Thus, we'll
1587 * use a shift instead.
1588 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001589 switch (tex->format) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 case RADEON_TXFORMAT_ARGB8888:
1591 case RADEON_TXFORMAT_RGBA8888:
1592 format = RADEON_COLOR_FORMAT_ARGB8888;
1593 tex_width = tex->width * 4;
1594 blit_width = image->width * 4;
1595 break;
1596 case RADEON_TXFORMAT_AI88:
1597 case RADEON_TXFORMAT_ARGB1555:
1598 case RADEON_TXFORMAT_RGB565:
1599 case RADEON_TXFORMAT_ARGB4444:
1600 case RADEON_TXFORMAT_VYUY422:
1601 case RADEON_TXFORMAT_YVYU422:
1602 format = RADEON_COLOR_FORMAT_RGB565;
1603 tex_width = tex->width * 2;
1604 blit_width = image->width * 2;
1605 break;
1606 case RADEON_TXFORMAT_I8:
1607 case RADEON_TXFORMAT_RGB332:
1608 format = RADEON_COLOR_FORMAT_CI8;
1609 tex_width = tex->width * 1;
1610 blit_width = image->width * 1;
1611 break;
1612 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001613 DRM_ERROR("invalid texture format %d\n", tex->format);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 return DRM_ERR(EINVAL);
1615 }
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001616 spitch = blit_width >> 6;
1617 if (spitch == 0 && image->height > 1)
1618 return DRM_ERR(EINVAL);
1619
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 texpitch = tex->pitch;
1621 if ((texpitch << 22) & RADEON_DST_TILE_MICRO) {
1622 microtile = 1;
1623 if (tex_width < 64) {
1624 texpitch &= ~(RADEON_DST_TILE_MICRO >> 22);
1625 /* we got tiled coordinates, untile them */
1626 image->x *= 2;
1627 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001628 } else
1629 microtile = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001631 DRM_DEBUG("tex=%dx%d blit=%d\n", tex_width, tex->height, blit_width);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632
1633 do {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001634 DRM_DEBUG("tex: ofs=0x%x p=%d f=%d x=%hd y=%hd w=%hd h=%hd\n",
1635 tex->offset >> 10, tex->pitch, tex->format,
1636 image->x, image->y, image->width, image->height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637
1638 /* Make a copy of some parameters in case we have to
1639 * update them for a multi-pass texture blit.
1640 */
1641 height = image->height;
1642 data = (const u8 __user *)image->data;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001643
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 size = height * blit_width;
1645
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001646 if (size > RADEON_MAX_TEXTURE_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 height = RADEON_MAX_TEXTURE_SIZE / blit_width;
1648 size = height * blit_width;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001649 } else if (size < 4 && size > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 size = 4;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001651 } else if (size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 return 0;
1653 }
1654
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001655 buf = radeon_freelist_get(dev);
1656 if (0 && !buf) {
1657 radeon_do_cp_idle(dev_priv);
1658 buf = radeon_freelist_get(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001660 if (!buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 DRM_DEBUG("radeon_cp_dispatch_texture: EAGAIN\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001662 if (DRM_COPY_TO_USER(tex->image, image, sizeof(*image)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 return DRM_ERR(EFAULT);
1664 return DRM_ERR(EAGAIN);
1665 }
1666
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 /* Dispatch the indirect buffer.
1668 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001669 buffer =
1670 (u32 *) ((char *)dev->agp_buffer_map->handle + buf->offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 dwords = size / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672
Dave Airlied985c102006-01-02 21:32:48 +11001673#define RADEON_COPY_MT(_buf, _data, _width) \
1674 do { \
1675 if (DRM_COPY_FROM_USER(_buf, _data, (_width))) {\
1676 DRM_ERROR("EFAULT on pad, %d bytes\n", (_width)); \
1677 return DRM_ERR(EFAULT); \
1678 } \
1679 } while(0)
1680
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681 if (microtile) {
1682 /* texture micro tiling in use, minimum texture width is thus 16 bytes.
1683 however, we cannot use blitter directly for texture width < 64 bytes,
1684 since minimum tex pitch is 64 bytes and we need this to match
1685 the texture width, otherwise the blitter will tile it wrong.
1686 Thus, tiling manually in this case. Additionally, need to special
1687 case tex height = 1, since our actual image will have height 2
1688 and we need to ensure we don't read beyond the texture size
1689 from user space. */
1690 if (tex->height == 1) {
1691 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)(tex_width * sizeof(u32)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 } else if (tex_width == 32) {
Dave Airlied985c102006-01-02 21:32:48 +11001695 RADEON_COPY_MT(buffer, data, 16);
1696 RADEON_COPY_MT(buffer + 8,
1697 data + 16, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 }
1699 } else if (tex_width >= 64 || tex_width == 16) {
Dave Airlied985c102006-01-02 21:32:48 +11001700 RADEON_COPY_MT(buffer, data,
Dave Airlief8e0f292006-01-10 19:56:17 +11001701 (int)(dwords * sizeof(u32)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 } else if (tex_width < 16) {
1703 for (i = 0; i < tex->height; i++) {
Dave Airlied985c102006-01-02 21:32:48 +11001704 RADEON_COPY_MT(buffer, data, tex_width);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 buffer += 4;
1706 data += tex_width;
1707 }
1708 } else if (tex_width == 32) {
1709 /* TODO: make sure this works when not fitting in one buffer
1710 (i.e. 32bytes x 2048...) */
1711 for (i = 0; i < tex->height; i += 2) {
Dave Airlied985c102006-01-02 21:32:48 +11001712 RADEON_COPY_MT(buffer, data, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 data += 16;
Dave Airlied985c102006-01-02 21:32:48 +11001714 RADEON_COPY_MT(buffer + 8, data, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 data += 16;
Dave Airlied985c102006-01-02 21:32:48 +11001716 RADEON_COPY_MT(buffer + 4, data, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 data += 16;
Dave Airlied985c102006-01-02 21:32:48 +11001718 RADEON_COPY_MT(buffer + 12, data, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 data += 16;
1720 buffer += 16;
1721 }
1722 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001723 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 if (tex_width >= 32) {
1725 /* Texture image width is larger than the minimum, so we
1726 * can upload it directly.
1727 */
Dave Airlied985c102006-01-02 21:32:48 +11001728 RADEON_COPY_MT(buffer, data,
Dave Airlief8e0f292006-01-10 19:56:17 +11001729 (int)(dwords * sizeof(u32)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 } else {
1731 /* Texture image width is less than the minimum, so we
1732 * need to pad out each image scanline to the minimum
1733 * width.
1734 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001735 for (i = 0; i < tex->height; i++) {
Dave Airlied985c102006-01-02 21:32:48 +11001736 RADEON_COPY_MT(buffer, data, tex_width);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 buffer += 8;
1738 data += tex_width;
1739 }
1740 }
1741 }
1742
Dave Airlied985c102006-01-02 21:32:48 +11001743#undef RADEON_COPY_MT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 buf->filp = filp;
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001745 buf->used = size;
1746 offset = dev_priv->gart_buffers_offset + buf->offset;
1747 BEGIN_RING(9);
1748 OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
1749 OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
1750 RADEON_GMC_DST_PITCH_OFFSET_CNTL |
1751 RADEON_GMC_BRUSH_NONE |
1752 (format << 8) |
1753 RADEON_GMC_SRC_DATATYPE_COLOR |
1754 RADEON_ROP3_S |
1755 RADEON_DP_SRC_SOURCE_MEMORY |
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001756 RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001757 OUT_RING((spitch << 22) | (offset >> 10));
1758 OUT_RING((texpitch << 22) | (tex->offset >> 10));
1759 OUT_RING(0);
1760 OUT_RING((image->x << 16) | image->y);
1761 OUT_RING((image->width << 16) | height);
1762 RADEON_WAIT_UNTIL_2D_IDLE();
1763 ADVANCE_RING();
1764
1765 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766
1767 /* Update the input parameters for next time */
1768 image->y += height;
1769 image->height -= height;
1770 image->data = (const u8 __user *)image->data + size;
1771 } while (image->height > 0);
1772
1773 /* Flush the pixel cache after the blit completes. This ensures
1774 * the texture data is written out to memory before rendering
1775 * continues.
1776 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001777 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 RADEON_FLUSH_CACHE();
1779 RADEON_WAIT_UNTIL_2D_IDLE();
1780 ADVANCE_RING();
1781 return 0;
1782}
1783
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001784static void radeon_cp_dispatch_stipple(drm_device_t * dev, u32 * stipple)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785{
1786 drm_radeon_private_t *dev_priv = dev->dev_private;
1787 int i;
1788 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001789 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001791 BEGIN_RING(35);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001793 OUT_RING(CP_PACKET0(RADEON_RE_STIPPLE_ADDR, 0));
1794 OUT_RING(0x00000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001796 OUT_RING(CP_PACKET0_TABLE(RADEON_RE_STIPPLE_DATA, 31));
1797 for (i = 0; i < 32; i++) {
1798 OUT_RING(stipple[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 }
1800
1801 ADVANCE_RING();
1802}
1803
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001804static void radeon_apply_surface_regs(int surf_index,
Dave Airlied985c102006-01-02 21:32:48 +11001805 drm_radeon_private_t *dev_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806{
1807 if (!dev_priv->mmio)
1808 return;
1809
1810 radeon_do_cp_idle(dev_priv);
1811
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001812 RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * surf_index,
1813 dev_priv->surfaces[surf_index].flags);
1814 RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND + 16 * surf_index,
1815 dev_priv->surfaces[surf_index].lower);
1816 RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND + 16 * surf_index,
1817 dev_priv->surfaces[surf_index].upper);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818}
1819
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820/* Allocates a virtual surface
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001821 * doesn't always allocate a real surface, will stretch an existing
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 * surface when possible.
1823 *
1824 * Note that refcount can be at most 2, since during a free refcount=3
1825 * might mean we have to allocate a new surface which might not always
1826 * be available.
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001827 * For example : we allocate three contigous surfaces ABC. If B is
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 * freed, we suddenly need two surfaces to store A and C, which might
1829 * not always be available.
1830 */
Dave Airlied985c102006-01-02 21:32:48 +11001831static int alloc_surface(drm_radeon_surface_alloc_t *new,
1832 drm_radeon_private_t *dev_priv, DRMFILE filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833{
1834 struct radeon_virt_surface *s;
1835 int i;
1836 int virt_surface_index;
1837 uint32_t new_upper, new_lower;
1838
1839 new_lower = new->address;
1840 new_upper = new_lower + new->size - 1;
1841
1842 /* sanity check */
1843 if ((new_lower >= new_upper) || (new->flags == 0) || (new->size == 0) ||
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001844 ((new_upper & RADEON_SURF_ADDRESS_FIXED_MASK) !=
1845 RADEON_SURF_ADDRESS_FIXED_MASK)
1846 || ((new_lower & RADEON_SURF_ADDRESS_FIXED_MASK) != 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 return -1;
1848
1849 /* make sure there is no overlap with existing surfaces */
1850 for (i = 0; i < RADEON_MAX_SURFACES; i++) {
1851 if ((dev_priv->surfaces[i].refcount != 0) &&
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001852 (((new_lower >= dev_priv->surfaces[i].lower) &&
1853 (new_lower < dev_priv->surfaces[i].upper)) ||
1854 ((new_lower < dev_priv->surfaces[i].lower) &&
1855 (new_upper > dev_priv->surfaces[i].lower)))) {
1856 return -1;
1857 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 }
1859
1860 /* find a virtual surface */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001861 for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 if (dev_priv->virt_surfaces[i].filp == 0)
1863 break;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001864 if (i == 2 * RADEON_MAX_SURFACES) {
1865 return -1;
1866 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 virt_surface_index = i;
1868
1869 /* try to reuse an existing surface */
1870 for (i = 0; i < RADEON_MAX_SURFACES; i++) {
1871 /* extend before */
1872 if ((dev_priv->surfaces[i].refcount == 1) &&
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001873 (new->flags == dev_priv->surfaces[i].flags) &&
1874 (new_upper + 1 == dev_priv->surfaces[i].lower)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 s = &(dev_priv->virt_surfaces[virt_surface_index]);
1876 s->surface_index = i;
1877 s->lower = new_lower;
1878 s->upper = new_upper;
1879 s->flags = new->flags;
1880 s->filp = filp;
1881 dev_priv->surfaces[i].refcount++;
1882 dev_priv->surfaces[i].lower = s->lower;
1883 radeon_apply_surface_regs(s->surface_index, dev_priv);
1884 return virt_surface_index;
1885 }
1886
1887 /* extend after */
1888 if ((dev_priv->surfaces[i].refcount == 1) &&
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001889 (new->flags == dev_priv->surfaces[i].flags) &&
1890 (new_lower == dev_priv->surfaces[i].upper + 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 s = &(dev_priv->virt_surfaces[virt_surface_index]);
1892 s->surface_index = i;
1893 s->lower = new_lower;
1894 s->upper = new_upper;
1895 s->flags = new->flags;
1896 s->filp = filp;
1897 dev_priv->surfaces[i].refcount++;
1898 dev_priv->surfaces[i].upper = s->upper;
1899 radeon_apply_surface_regs(s->surface_index, dev_priv);
1900 return virt_surface_index;
1901 }
1902 }
1903
1904 /* okay, we need a new one */
1905 for (i = 0; i < RADEON_MAX_SURFACES; i++) {
1906 if (dev_priv->surfaces[i].refcount == 0) {
1907 s = &(dev_priv->virt_surfaces[virt_surface_index]);
1908 s->surface_index = i;
1909 s->lower = new_lower;
1910 s->upper = new_upper;
1911 s->flags = new->flags;
1912 s->filp = filp;
1913 dev_priv->surfaces[i].refcount = 1;
1914 dev_priv->surfaces[i].lower = s->lower;
1915 dev_priv->surfaces[i].upper = s->upper;
1916 dev_priv->surfaces[i].flags = s->flags;
1917 radeon_apply_surface_regs(s->surface_index, dev_priv);
1918 return virt_surface_index;
1919 }
1920 }
1921
1922 /* we didn't find anything */
1923 return -1;
1924}
1925
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001926static int free_surface(DRMFILE filp, drm_radeon_private_t * dev_priv,
1927 int lower)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928{
1929 struct radeon_virt_surface *s;
1930 int i;
1931 /* find the virtual surface */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001932 for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 s = &(dev_priv->virt_surfaces[i]);
1934 if (s->filp) {
1935 if ((lower == s->lower) && (filp == s->filp)) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001936 if (dev_priv->surfaces[s->surface_index].
1937 lower == s->lower)
1938 dev_priv->surfaces[s->surface_index].
1939 lower = s->upper;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001941 if (dev_priv->surfaces[s->surface_index].
1942 upper == s->upper)
1943 dev_priv->surfaces[s->surface_index].
1944 upper = s->lower;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945
1946 dev_priv->surfaces[s->surface_index].refcount--;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001947 if (dev_priv->surfaces[s->surface_index].
1948 refcount == 0)
1949 dev_priv->surfaces[s->surface_index].
1950 flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 s->filp = NULL;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001952 radeon_apply_surface_regs(s->surface_index,
1953 dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 return 0;
1955 }
1956 }
1957 }
1958 return 1;
1959}
1960
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001961static void radeon_surfaces_release(DRMFILE filp,
1962 drm_radeon_private_t * dev_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963{
1964 int i;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001965 for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 if (dev_priv->virt_surfaces[i].filp == filp)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001967 free_surface(filp, dev_priv,
1968 dev_priv->virt_surfaces[i].lower);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 }
1970}
1971
1972/* ================================================================
1973 * IOCTL functions
1974 */
1975static int radeon_surface_alloc(DRM_IOCTL_ARGS)
1976{
1977 DRM_DEVICE;
1978 drm_radeon_private_t *dev_priv = dev->dev_private;
1979 drm_radeon_surface_alloc_t alloc;
1980
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001981 DRM_COPY_FROM_USER_IOCTL(alloc,
1982 (drm_radeon_surface_alloc_t __user *) data,
1983 sizeof(alloc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984
1985 if (alloc_surface(&alloc, dev_priv, filp) == -1)
1986 return DRM_ERR(EINVAL);
1987 else
1988 return 0;
1989}
1990
1991static int radeon_surface_free(DRM_IOCTL_ARGS)
1992{
1993 DRM_DEVICE;
1994 drm_radeon_private_t *dev_priv = dev->dev_private;
1995 drm_radeon_surface_free_t memfree;
1996
Dave Airlief15e92d2006-03-19 20:12:23 +11001997 DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_surface_free_t __user *) data,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001998 sizeof(memfree));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999
2000 if (free_surface(filp, dev_priv, memfree.address))
2001 return DRM_ERR(EINVAL);
2002 else
2003 return 0;
2004}
2005
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002006static int radeon_cp_clear(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007{
2008 DRM_DEVICE;
2009 drm_radeon_private_t *dev_priv = dev->dev_private;
2010 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2011 drm_radeon_clear_t clear;
2012 drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002013 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002015 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002017 DRM_COPY_FROM_USER_IOCTL(clear, (drm_radeon_clear_t __user *) data,
2018 sizeof(clear));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002020 RING_SPACE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002022 if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
2024
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002025 if (DRM_COPY_FROM_USER(&depth_boxes, clear.depth_boxes,
2026 sarea_priv->nbox * sizeof(depth_boxes[0])))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 return DRM_ERR(EFAULT);
2028
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002029 radeon_cp_dispatch_clear(dev, &clear, depth_boxes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030
2031 COMMIT_RING();
2032 return 0;
2033}
2034
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035/* Not sure why this isn't set all the time:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002036 */
2037static int radeon_do_init_pageflip(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038{
2039 drm_radeon_private_t *dev_priv = dev->dev_private;
2040 RING_LOCALS;
2041
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002042 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002044 BEGIN_RING(6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 RADEON_WAIT_UNTIL_3D_IDLE();
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002046 OUT_RING(CP_PACKET0(RADEON_CRTC_OFFSET_CNTL, 0));
2047 OUT_RING(RADEON_READ(RADEON_CRTC_OFFSET_CNTL) |
2048 RADEON_CRTC_OFFSET_FLIP_CNTL);
2049 OUT_RING(CP_PACKET0(RADEON_CRTC2_OFFSET_CNTL, 0));
2050 OUT_RING(RADEON_READ(RADEON_CRTC2_OFFSET_CNTL) |
2051 RADEON_CRTC_OFFSET_FLIP_CNTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 ADVANCE_RING();
2053
2054 dev_priv->page_flipping = 1;
2055 dev_priv->current_page = 0;
2056 dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page;
2057
2058 return 0;
2059}
2060
2061/* Called whenever a client dies, from drm_release.
2062 * NOTE: Lock isn't necessarily held when this is called!
2063 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002064static int radeon_do_cleanup_pageflip(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065{
2066 drm_radeon_private_t *dev_priv = dev->dev_private;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002067 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068
2069 if (dev_priv->current_page != 0)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002070 radeon_cp_dispatch_flip(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071
2072 dev_priv->page_flipping = 0;
2073 return 0;
2074}
2075
2076/* Swapping and flipping are different operations, need different ioctls.
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002077 * They can & should be intermixed to support multiple 3d windows.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002079static int radeon_cp_flip(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080{
2081 DRM_DEVICE;
2082 drm_radeon_private_t *dev_priv = dev->dev_private;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002083 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002085 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002087 RING_SPACE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002089 if (!dev_priv->page_flipping)
2090 radeon_do_init_pageflip(dev);
2091
2092 radeon_cp_dispatch_flip(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093
2094 COMMIT_RING();
2095 return 0;
2096}
2097
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002098static int radeon_cp_swap(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099{
2100 DRM_DEVICE;
2101 drm_radeon_private_t *dev_priv = dev->dev_private;
2102 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002103 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002105 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002107 RING_SPACE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002109 if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
2111
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002112 radeon_cp_dispatch_swap(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 dev_priv->sarea_priv->ctx_owner = 0;
2114
2115 COMMIT_RING();
2116 return 0;
2117}
2118
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002119static int radeon_cp_vertex(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120{
2121 DRM_DEVICE;
2122 drm_radeon_private_t *dev_priv = dev->dev_private;
2123 drm_file_t *filp_priv;
2124 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2125 drm_device_dma_t *dma = dev->dma;
2126 drm_buf_t *buf;
2127 drm_radeon_vertex_t vertex;
2128 drm_radeon_tcl_prim_t prim;
2129
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002130 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002132 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002134 DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex_t __user *) data,
2135 sizeof(vertex));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002137 DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n",
2138 DRM_CURRENTPID, vertex.idx, vertex.count, vertex.discard);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002140 if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
2141 DRM_ERROR("buffer index %d (of %d max)\n",
2142 vertex.idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 return DRM_ERR(EINVAL);
2144 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002145 if (vertex.prim < 0 || vertex.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
2146 DRM_ERROR("buffer prim %d\n", vertex.prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 return DRM_ERR(EINVAL);
2148 }
2149
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002150 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2151 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152
2153 buf = dma->buflist[vertex.idx];
2154
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002155 if (buf->filp != filp) {
2156 DRM_ERROR("process %d using buffer owned by %p\n",
2157 DRM_CURRENTPID, buf->filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 return DRM_ERR(EINVAL);
2159 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002160 if (buf->pending) {
2161 DRM_ERROR("sending pending buffer %d\n", vertex.idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 return DRM_ERR(EINVAL);
2163 }
2164
2165 /* Build up a prim_t record:
2166 */
2167 if (vertex.count) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002168 buf->used = vertex.count; /* not used? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002170 if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
2171 if (radeon_emit_state(dev_priv, filp_priv,
2172 &sarea_priv->context_state,
2173 sarea_priv->tex_state,
2174 sarea_priv->dirty)) {
2175 DRM_ERROR("radeon_emit_state failed\n");
2176 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 }
2178
2179 sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
2180 RADEON_UPLOAD_TEX1IMAGES |
2181 RADEON_UPLOAD_TEX2IMAGES |
2182 RADEON_REQUIRE_QUIESCENCE);
2183 }
2184
2185 prim.start = 0;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002186 prim.finish = vertex.count; /* unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 prim.prim = vertex.prim;
2188 prim.numverts = vertex.count;
2189 prim.vc_format = dev_priv->sarea_priv->vc_format;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002190
2191 radeon_cp_dispatch_vertex(dev, buf, &prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 }
2193
2194 if (vertex.discard) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002195 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 }
2197
2198 COMMIT_RING();
2199 return 0;
2200}
2201
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002202static int radeon_cp_indices(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203{
2204 DRM_DEVICE;
2205 drm_radeon_private_t *dev_priv = dev->dev_private;
2206 drm_file_t *filp_priv;
2207 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2208 drm_device_dma_t *dma = dev->dma;
2209 drm_buf_t *buf;
2210 drm_radeon_indices_t elts;
2211 drm_radeon_tcl_prim_t prim;
2212 int count;
2213
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002214 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002216 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002218 DRM_COPY_FROM_USER_IOCTL(elts, (drm_radeon_indices_t __user *) data,
2219 sizeof(elts));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002221 DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n",
2222 DRM_CURRENTPID, elts.idx, elts.start, elts.end, elts.discard);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002224 if (elts.idx < 0 || elts.idx >= dma->buf_count) {
2225 DRM_ERROR("buffer index %d (of %d max)\n",
2226 elts.idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 return DRM_ERR(EINVAL);
2228 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002229 if (elts.prim < 0 || elts.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
2230 DRM_ERROR("buffer prim %d\n", elts.prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 return DRM_ERR(EINVAL);
2232 }
2233
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002234 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2235 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236
2237 buf = dma->buflist[elts.idx];
2238
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002239 if (buf->filp != filp) {
2240 DRM_ERROR("process %d using buffer owned by %p\n",
2241 DRM_CURRENTPID, buf->filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 return DRM_ERR(EINVAL);
2243 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002244 if (buf->pending) {
2245 DRM_ERROR("sending pending buffer %d\n", elts.idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 return DRM_ERR(EINVAL);
2247 }
2248
2249 count = (elts.end - elts.start) / sizeof(u16);
2250 elts.start -= RADEON_INDEX_PRIM_OFFSET;
2251
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002252 if (elts.start & 0x7) {
2253 DRM_ERROR("misaligned buffer 0x%x\n", elts.start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 return DRM_ERR(EINVAL);
2255 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002256 if (elts.start < buf->used) {
2257 DRM_ERROR("no header 0x%x - 0x%x\n", elts.start, buf->used);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 return DRM_ERR(EINVAL);
2259 }
2260
2261 buf->used = elts.end;
2262
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002263 if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
2264 if (radeon_emit_state(dev_priv, filp_priv,
2265 &sarea_priv->context_state,
2266 sarea_priv->tex_state,
2267 sarea_priv->dirty)) {
2268 DRM_ERROR("radeon_emit_state failed\n");
2269 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 }
2271
2272 sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
2273 RADEON_UPLOAD_TEX1IMAGES |
2274 RADEON_UPLOAD_TEX2IMAGES |
2275 RADEON_REQUIRE_QUIESCENCE);
2276 }
2277
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 /* Build up a prim_t record:
2279 */
2280 prim.start = elts.start;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002281 prim.finish = elts.end;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 prim.prim = elts.prim;
2283 prim.offset = 0; /* offset from start of dma buffers */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002284 prim.numverts = RADEON_MAX_VB_VERTS; /* duh */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 prim.vc_format = dev_priv->sarea_priv->vc_format;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002286
2287 radeon_cp_dispatch_indices(dev, buf, &prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 if (elts.discard) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002289 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 }
2291
2292 COMMIT_RING();
2293 return 0;
2294}
2295
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002296static int radeon_cp_texture(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297{
2298 DRM_DEVICE;
2299 drm_radeon_private_t *dev_priv = dev->dev_private;
2300 drm_radeon_texture_t tex;
2301 drm_radeon_tex_image_t image;
2302 int ret;
2303
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002304 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002306 DRM_COPY_FROM_USER_IOCTL(tex, (drm_radeon_texture_t __user *) data,
2307 sizeof(tex));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002309 if (tex.image == NULL) {
2310 DRM_ERROR("null texture image!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 return DRM_ERR(EINVAL);
2312 }
2313
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002314 if (DRM_COPY_FROM_USER(&image,
2315 (drm_radeon_tex_image_t __user *) tex.image,
2316 sizeof(image)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 return DRM_ERR(EFAULT);
2318
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002319 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2320 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002322 ret = radeon_cp_dispatch_texture(filp, dev, &tex, &image);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323
2324 COMMIT_RING();
2325 return ret;
2326}
2327
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002328static int radeon_cp_stipple(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329{
2330 DRM_DEVICE;
2331 drm_radeon_private_t *dev_priv = dev->dev_private;
2332 drm_radeon_stipple_t stipple;
2333 u32 mask[32];
2334
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002335 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002337 DRM_COPY_FROM_USER_IOCTL(stipple, (drm_radeon_stipple_t __user *) data,
2338 sizeof(stipple));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002340 if (DRM_COPY_FROM_USER(&mask, stipple.mask, 32 * sizeof(u32)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 return DRM_ERR(EFAULT);
2342
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002343 RING_SPACE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002345 radeon_cp_dispatch_stipple(dev, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346
2347 COMMIT_RING();
2348 return 0;
2349}
2350
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002351static int radeon_cp_indirect(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352{
2353 DRM_DEVICE;
2354 drm_radeon_private_t *dev_priv = dev->dev_private;
2355 drm_device_dma_t *dma = dev->dma;
2356 drm_buf_t *buf;
2357 drm_radeon_indirect_t indirect;
2358 RING_LOCALS;
2359
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002360 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002362 DRM_COPY_FROM_USER_IOCTL(indirect,
2363 (drm_radeon_indirect_t __user *) data,
2364 sizeof(indirect));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002366 DRM_DEBUG("indirect: idx=%d s=%d e=%d d=%d\n",
2367 indirect.idx, indirect.start, indirect.end, indirect.discard);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002369 if (indirect.idx < 0 || indirect.idx >= dma->buf_count) {
2370 DRM_ERROR("buffer index %d (of %d max)\n",
2371 indirect.idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 return DRM_ERR(EINVAL);
2373 }
2374
2375 buf = dma->buflist[indirect.idx];
2376
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002377 if (buf->filp != filp) {
2378 DRM_ERROR("process %d using buffer owned by %p\n",
2379 DRM_CURRENTPID, buf->filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 return DRM_ERR(EINVAL);
2381 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002382 if (buf->pending) {
2383 DRM_ERROR("sending pending buffer %d\n", indirect.idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 return DRM_ERR(EINVAL);
2385 }
2386
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002387 if (indirect.start < buf->used) {
2388 DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n",
2389 indirect.start, buf->used);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 return DRM_ERR(EINVAL);
2391 }
2392
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002393 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2394 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395
2396 buf->used = indirect.end;
2397
2398 /* Wait for the 3D stream to idle before the indirect buffer
2399 * containing 2D acceleration commands is processed.
2400 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002401 BEGIN_RING(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402
2403 RADEON_WAIT_UNTIL_3D_IDLE();
2404
2405 ADVANCE_RING();
2406
2407 /* Dispatch the indirect buffer full of commands from the
2408 * X server. This is insecure and is thus only available to
2409 * privileged clients.
2410 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002411 radeon_cp_dispatch_indirect(dev, buf, indirect.start, indirect.end);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 if (indirect.discard) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002413 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 }
2415
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 COMMIT_RING();
2417 return 0;
2418}
2419
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002420static int radeon_cp_vertex2(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421{
2422 DRM_DEVICE;
2423 drm_radeon_private_t *dev_priv = dev->dev_private;
2424 drm_file_t *filp_priv;
2425 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2426 drm_device_dma_t *dma = dev->dma;
2427 drm_buf_t *buf;
2428 drm_radeon_vertex2_t vertex;
2429 int i;
2430 unsigned char laststate;
2431
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002432 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002434 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002436 DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex2_t __user *) data,
2437 sizeof(vertex));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002439 DRM_DEBUG("pid=%d index=%d discard=%d\n",
2440 DRM_CURRENTPID, vertex.idx, vertex.discard);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002442 if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
2443 DRM_ERROR("buffer index %d (of %d max)\n",
2444 vertex.idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 return DRM_ERR(EINVAL);
2446 }
2447
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002448 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2449 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450
2451 buf = dma->buflist[vertex.idx];
2452
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002453 if (buf->filp != filp) {
2454 DRM_ERROR("process %d using buffer owned by %p\n",
2455 DRM_CURRENTPID, buf->filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 return DRM_ERR(EINVAL);
2457 }
2458
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002459 if (buf->pending) {
2460 DRM_ERROR("sending pending buffer %d\n", vertex.idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 return DRM_ERR(EINVAL);
2462 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002463
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
2465 return DRM_ERR(EINVAL);
2466
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002467 for (laststate = 0xff, i = 0; i < vertex.nr_prims; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 drm_radeon_prim_t prim;
2469 drm_radeon_tcl_prim_t tclprim;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002470
2471 if (DRM_COPY_FROM_USER(&prim, &vertex.prim[i], sizeof(prim)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 return DRM_ERR(EFAULT);
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002473
2474 if (prim.stateidx != laststate) {
2475 drm_radeon_state_t state;
2476
2477 if (DRM_COPY_FROM_USER(&state,
2478 &vertex.state[prim.stateidx],
2479 sizeof(state)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 return DRM_ERR(EFAULT);
2481
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002482 if (radeon_emit_state2(dev_priv, filp_priv, &state)) {
2483 DRM_ERROR("radeon_emit_state2 failed\n");
2484 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 }
2486
2487 laststate = prim.stateidx;
2488 }
2489
2490 tclprim.start = prim.start;
2491 tclprim.finish = prim.finish;
2492 tclprim.prim = prim.prim;
2493 tclprim.vc_format = prim.vc_format;
2494
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002495 if (prim.prim & RADEON_PRIM_WALK_IND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 tclprim.offset = prim.numverts * 64;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002497 tclprim.numverts = RADEON_MAX_VB_VERTS; /* duh */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002499 radeon_cp_dispatch_indices(dev, buf, &tclprim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 } else {
2501 tclprim.numverts = prim.numverts;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002502 tclprim.offset = 0; /* not used */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002504 radeon_cp_dispatch_vertex(dev, buf, &tclprim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002506
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 if (sarea_priv->nbox == 1)
2508 sarea_priv->nbox = 0;
2509 }
2510
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002511 if (vertex.discard) {
2512 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 }
2514
2515 COMMIT_RING();
2516 return 0;
2517}
2518
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002519static int radeon_emit_packets(drm_radeon_private_t * dev_priv,
2520 drm_file_t * filp_priv,
2521 drm_radeon_cmd_header_t header,
Dave Airlieb3a83632005-09-30 18:37:36 +10002522 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523{
2524 int id = (int)header.packet.packet_id;
2525 int sz, reg;
2526 int *data = (int *)cmdbuf->buf;
2527 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002528
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 if (id >= RADEON_MAX_STATE_PACKETS)
2530 return DRM_ERR(EINVAL);
2531
2532 sz = packet[id].len;
2533 reg = packet[id].start;
2534
2535 if (sz * sizeof(int) > cmdbuf->bufsz) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002536 DRM_ERROR("Packet size provided larger than data provided\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 return DRM_ERR(EINVAL);
2538 }
2539
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002540 if (radeon_check_and_fixup_packets(dev_priv, filp_priv, id, data)) {
2541 DRM_ERROR("Packet verification failed\n");
2542 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543 }
2544
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002545 BEGIN_RING(sz + 1);
2546 OUT_RING(CP_PACKET0(reg, (sz - 1)));
2547 OUT_RING_TABLE(data, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 ADVANCE_RING();
2549
2550 cmdbuf->buf += sz * sizeof(int);
2551 cmdbuf->bufsz -= sz * sizeof(int);
2552 return 0;
2553}
2554
Dave Airlied985c102006-01-02 21:32:48 +11002555static __inline__ int radeon_emit_scalars(drm_radeon_private_t *dev_priv,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002556 drm_radeon_cmd_header_t header,
Dave Airlied985c102006-01-02 21:32:48 +11002557 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558{
2559 int sz = header.scalars.count;
2560 int start = header.scalars.offset;
2561 int stride = header.scalars.stride;
2562 RING_LOCALS;
2563
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002564 BEGIN_RING(3 + sz);
2565 OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
2566 OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
2567 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
2568 OUT_RING_TABLE(cmdbuf->buf, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 ADVANCE_RING();
2570 cmdbuf->buf += sz * sizeof(int);
2571 cmdbuf->bufsz -= sz * sizeof(int);
2572 return 0;
2573}
2574
2575/* God this is ugly
2576 */
Dave Airlied985c102006-01-02 21:32:48 +11002577static __inline__ int radeon_emit_scalars2(drm_radeon_private_t *dev_priv,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002578 drm_radeon_cmd_header_t header,
Dave Airlied985c102006-01-02 21:32:48 +11002579 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580{
2581 int sz = header.scalars.count;
2582 int start = ((unsigned int)header.scalars.offset) + 0x100;
2583 int stride = header.scalars.stride;
2584 RING_LOCALS;
2585
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002586 BEGIN_RING(3 + sz);
2587 OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
2588 OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
2589 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
2590 OUT_RING_TABLE(cmdbuf->buf, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 ADVANCE_RING();
2592 cmdbuf->buf += sz * sizeof(int);
2593 cmdbuf->bufsz -= sz * sizeof(int);
2594 return 0;
2595}
2596
Dave Airlied985c102006-01-02 21:32:48 +11002597static __inline__ int radeon_emit_vectors(drm_radeon_private_t *dev_priv,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002598 drm_radeon_cmd_header_t header,
Dave Airlied985c102006-01-02 21:32:48 +11002599 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600{
2601 int sz = header.vectors.count;
2602 int start = header.vectors.offset;
2603 int stride = header.vectors.stride;
2604 RING_LOCALS;
2605
Dave Airlief2a22792006-06-24 16:55:34 +10002606 BEGIN_RING(5 + sz);
2607 OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002608 OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
2609 OUT_RING(start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
2610 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
2611 OUT_RING_TABLE(cmdbuf->buf, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 ADVANCE_RING();
2613
2614 cmdbuf->buf += sz * sizeof(int);
2615 cmdbuf->bufsz -= sz * sizeof(int);
2616 return 0;
2617}
2618
Dave Airlied6fece02006-06-24 17:04:07 +10002619static __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv,
2620 drm_radeon_cmd_header_t header,
2621 drm_radeon_kcmd_buffer_t *cmdbuf)
2622{
2623 int sz = header.veclinear.count * 4;
2624 int start = header.veclinear.addr_lo | (header.veclinear.addr_hi << 8);
2625 RING_LOCALS;
2626
2627 if (!sz)
2628 return 0;
2629 if (sz * 4 > cmdbuf->bufsz)
2630 return DRM_ERR(EINVAL);
2631
2632 BEGIN_RING(5 + sz);
2633 OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
2634 OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
2635 OUT_RING(start | (1 << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
2636 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
2637 OUT_RING_TABLE(cmdbuf->buf, sz);
2638 ADVANCE_RING();
2639
2640 cmdbuf->buf += sz * sizeof(int);
2641 cmdbuf->bufsz -= sz * sizeof(int);
2642 return 0;
2643}
2644
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002645static int radeon_emit_packet3(drm_device_t * dev,
2646 drm_file_t * filp_priv,
Dave Airlieb3a83632005-09-30 18:37:36 +10002647 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648{
2649 drm_radeon_private_t *dev_priv = dev->dev_private;
2650 unsigned int cmdsz;
2651 int ret;
2652 RING_LOCALS;
2653
2654 DRM_DEBUG("\n");
2655
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002656 if ((ret = radeon_check_and_fixup_packet3(dev_priv, filp_priv,
2657 cmdbuf, &cmdsz))) {
2658 DRM_ERROR("Packet verification failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 return ret;
2660 }
2661
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002662 BEGIN_RING(cmdsz);
2663 OUT_RING_TABLE(cmdbuf->buf, cmdsz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 ADVANCE_RING();
2665
2666 cmdbuf->buf += cmdsz * 4;
2667 cmdbuf->bufsz -= cmdsz * 4;
2668 return 0;
2669}
2670
Dave Airlied985c102006-01-02 21:32:48 +11002671static int radeon_emit_packet3_cliprect(drm_device_t *dev,
2672 drm_file_t *filp_priv,
Dave Airlieb3a83632005-09-30 18:37:36 +10002673 drm_radeon_kcmd_buffer_t *cmdbuf,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002674 int orig_nbox)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675{
2676 drm_radeon_private_t *dev_priv = dev->dev_private;
2677 drm_clip_rect_t box;
2678 unsigned int cmdsz;
2679 int ret;
2680 drm_clip_rect_t __user *boxes = cmdbuf->boxes;
2681 int i = 0;
2682 RING_LOCALS;
2683
2684 DRM_DEBUG("\n");
2685
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002686 if ((ret = radeon_check_and_fixup_packet3(dev_priv, filp_priv,
2687 cmdbuf, &cmdsz))) {
2688 DRM_ERROR("Packet verification failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 return ret;
2690 }
2691
2692 if (!orig_nbox)
2693 goto out;
2694
2695 do {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002696 if (i < cmdbuf->nbox) {
2697 if (DRM_COPY_FROM_USER(&box, &boxes[i], sizeof(box)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 return DRM_ERR(EFAULT);
2699 /* FIXME The second and subsequent times round
2700 * this loop, send a WAIT_UNTIL_3D_IDLE before
2701 * calling emit_clip_rect(). This fixes a
2702 * lockup on fast machines when sending
2703 * several cliprects with a cmdbuf, as when
2704 * waving a 2D window over a 3D
2705 * window. Something in the commands from user
2706 * space seems to hang the card when they're
2707 * sent several times in a row. That would be
2708 * the correct place to fix it but this works
2709 * around it until I can figure that out - Tim
2710 * Smith */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002711 if (i) {
2712 BEGIN_RING(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 RADEON_WAIT_UNTIL_3D_IDLE();
2714 ADVANCE_RING();
2715 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002716 radeon_emit_clip_rect(dev_priv, &box);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002718
2719 BEGIN_RING(cmdsz);
2720 OUT_RING_TABLE(cmdbuf->buf, cmdsz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 ADVANCE_RING();
2722
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002723 } while (++i < cmdbuf->nbox);
2724 if (cmdbuf->nbox == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 cmdbuf->nbox = 0;
2726
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002727 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 cmdbuf->buf += cmdsz * 4;
2729 cmdbuf->bufsz -= cmdsz * 4;
2730 return 0;
2731}
2732
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002733static int radeon_emit_wait(drm_device_t * dev, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734{
2735 drm_radeon_private_t *dev_priv = dev->dev_private;
2736 RING_LOCALS;
2737
2738 DRM_DEBUG("%s: %x\n", __FUNCTION__, flags);
2739 switch (flags) {
2740 case RADEON_WAIT_2D:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002741 BEGIN_RING(2);
2742 RADEON_WAIT_UNTIL_2D_IDLE();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 ADVANCE_RING();
2744 break;
2745 case RADEON_WAIT_3D:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002746 BEGIN_RING(2);
2747 RADEON_WAIT_UNTIL_3D_IDLE();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 ADVANCE_RING();
2749 break;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002750 case RADEON_WAIT_2D | RADEON_WAIT_3D:
2751 BEGIN_RING(2);
2752 RADEON_WAIT_UNTIL_IDLE();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 ADVANCE_RING();
2754 break;
2755 default:
2756 return DRM_ERR(EINVAL);
2757 }
2758
2759 return 0;
2760}
2761
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002762static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763{
2764 DRM_DEVICE;
2765 drm_radeon_private_t *dev_priv = dev->dev_private;
2766 drm_file_t *filp_priv;
2767 drm_device_dma_t *dma = dev->dma;
2768 drm_buf_t *buf = NULL;
2769 int idx;
Dave Airlieb3a83632005-09-30 18:37:36 +10002770 drm_radeon_kcmd_buffer_t cmdbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 drm_radeon_cmd_header_t header;
2772 int orig_nbox, orig_bufsz;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002773 char *kbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002775 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002777 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002779 DRM_COPY_FROM_USER_IOCTL(cmdbuf,
2780 (drm_radeon_cmd_buffer_t __user *) data,
2781 sizeof(cmdbuf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002783 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2784 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002786 if (cmdbuf.bufsz > 64 * 1024 || cmdbuf.bufsz < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 return DRM_ERR(EINVAL);
2788 }
2789
2790 /* Allocate an in-kernel area and copy in the cmdbuf. Do this to avoid
2791 * races between checking values and using those values in other code,
2792 * and simply to avoid a lot of function calls to copy in data.
2793 */
2794 orig_bufsz = cmdbuf.bufsz;
2795 if (orig_bufsz != 0) {
2796 kbuf = drm_alloc(cmdbuf.bufsz, DRM_MEM_DRIVER);
2797 if (kbuf == NULL)
2798 return DRM_ERR(ENOMEM);
Dave Airlied985c102006-01-02 21:32:48 +11002799 if (DRM_COPY_FROM_USER(kbuf, (void __user *)cmdbuf.buf,
2800 cmdbuf.bufsz)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
2802 return DRM_ERR(EFAULT);
2803 }
2804 cmdbuf.buf = kbuf;
2805 }
2806
2807 orig_nbox = cmdbuf.nbox;
2808
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002809 if (dev_priv->microcode_version == UCODE_R300) {
Dave Airlie414ed532005-08-16 20:43:16 +10002810 int temp;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002811 temp = r300_do_cp_cmdbuf(dev, filp, filp_priv, &cmdbuf);
2812
Dave Airlie414ed532005-08-16 20:43:16 +10002813 if (orig_bufsz != 0)
2814 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002815
Dave Airlie414ed532005-08-16 20:43:16 +10002816 return temp;
2817 }
2818
2819 /* microcode_version != r300 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002820 while (cmdbuf.bufsz >= sizeof(header)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821
2822 header.i = *(int *)cmdbuf.buf;
2823 cmdbuf.buf += sizeof(header);
2824 cmdbuf.bufsz -= sizeof(header);
2825
2826 switch (header.header.cmd_type) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002827 case RADEON_CMD_PACKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 DRM_DEBUG("RADEON_CMD_PACKET\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002829 if (radeon_emit_packets
2830 (dev_priv, filp_priv, header, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 DRM_ERROR("radeon_emit_packets failed\n");
2832 goto err;
2833 }
2834 break;
2835
2836 case RADEON_CMD_SCALARS:
2837 DRM_DEBUG("RADEON_CMD_SCALARS\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002838 if (radeon_emit_scalars(dev_priv, header, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 DRM_ERROR("radeon_emit_scalars failed\n");
2840 goto err;
2841 }
2842 break;
2843
2844 case RADEON_CMD_VECTORS:
2845 DRM_DEBUG("RADEON_CMD_VECTORS\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002846 if (radeon_emit_vectors(dev_priv, header, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 DRM_ERROR("radeon_emit_vectors failed\n");
2848 goto err;
2849 }
2850 break;
2851
2852 case RADEON_CMD_DMA_DISCARD:
2853 DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n");
2854 idx = header.dma.buf_idx;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002855 if (idx < 0 || idx >= dma->buf_count) {
2856 DRM_ERROR("buffer index %d (of %d max)\n",
2857 idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 goto err;
2859 }
2860
2861 buf = dma->buflist[idx];
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002862 if (buf->filp != filp || buf->pending) {
2863 DRM_ERROR("bad buffer %p %p %d\n",
2864 buf->filp, filp, buf->pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 goto err;
2866 }
2867
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002868 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 break;
2870
2871 case RADEON_CMD_PACKET3:
2872 DRM_DEBUG("RADEON_CMD_PACKET3\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002873 if (radeon_emit_packet3(dev, filp_priv, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 DRM_ERROR("radeon_emit_packet3 failed\n");
2875 goto err;
2876 }
2877 break;
2878
2879 case RADEON_CMD_PACKET3_CLIP:
2880 DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002881 if (radeon_emit_packet3_cliprect
2882 (dev, filp_priv, &cmdbuf, orig_nbox)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 DRM_ERROR("radeon_emit_packet3_clip failed\n");
2884 goto err;
2885 }
2886 break;
2887
2888 case RADEON_CMD_SCALARS2:
2889 DRM_DEBUG("RADEON_CMD_SCALARS2\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002890 if (radeon_emit_scalars2(dev_priv, header, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 DRM_ERROR("radeon_emit_scalars2 failed\n");
2892 goto err;
2893 }
2894 break;
2895
2896 case RADEON_CMD_WAIT:
2897 DRM_DEBUG("RADEON_CMD_WAIT\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002898 if (radeon_emit_wait(dev, header.wait.flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 DRM_ERROR("radeon_emit_wait failed\n");
2900 goto err;
2901 }
2902 break;
Dave Airlied6fece02006-06-24 17:04:07 +10002903 case RADEON_CMD_VECLINEAR:
2904 DRM_DEBUG("RADEON_CMD_VECLINEAR\n");
2905 if (radeon_emit_veclinear(dev_priv, header, &cmdbuf)) {
2906 DRM_ERROR("radeon_emit_veclinear failed\n");
2907 goto err;
2908 }
2909 break;
2910
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002912 DRM_ERROR("bad cmd_type %d at %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 header.header.cmd_type,
2914 cmdbuf.buf - sizeof(header));
2915 goto err;
2916 }
2917 }
2918
2919 if (orig_bufsz != 0)
2920 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
2921
2922 DRM_DEBUG("DONE\n");
2923 COMMIT_RING();
2924 return 0;
2925
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002926 err:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 if (orig_bufsz != 0)
2928 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
2929 return DRM_ERR(EINVAL);
2930}
2931
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002932static int radeon_cp_getparam(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933{
2934 DRM_DEVICE;
2935 drm_radeon_private_t *dev_priv = dev->dev_private;
2936 drm_radeon_getparam_t param;
2937 int value;
2938
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002939 DRM_COPY_FROM_USER_IOCTL(param, (drm_radeon_getparam_t __user *) data,
2940 sizeof(param));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002942 DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002944 switch (param.param) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 case RADEON_PARAM_GART_BUFFER_OFFSET:
2946 value = dev_priv->gart_buffers_offset;
2947 break;
2948 case RADEON_PARAM_LAST_FRAME:
2949 dev_priv->stats.last_frame_reads++;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002950 value = GET_SCRATCH(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 break;
2952 case RADEON_PARAM_LAST_DISPATCH:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002953 value = GET_SCRATCH(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 break;
2955 case RADEON_PARAM_LAST_CLEAR:
2956 dev_priv->stats.last_clear_reads++;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002957 value = GET_SCRATCH(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 break;
2959 case RADEON_PARAM_IRQ_NR:
2960 value = dev->irq;
2961 break;
2962 case RADEON_PARAM_GART_BASE:
2963 value = dev_priv->gart_vm_start;
2964 break;
2965 case RADEON_PARAM_REGISTER_HANDLE:
Dave Airlied985c102006-01-02 21:32:48 +11002966 value = dev_priv->mmio->offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 break;
2968 case RADEON_PARAM_STATUS_HANDLE:
2969 value = dev_priv->ring_rptr_offset;
2970 break;
2971#if BITS_PER_LONG == 32
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002972 /*
2973 * This ioctl() doesn't work on 64-bit platforms because hw_lock is a
2974 * pointer which can't fit into an int-sized variable. According to
2975 * Michel Dänzer, the ioctl() is only used on embedded platforms, so
2976 * not supporting it shouldn't be a problem. If the same functionality
2977 * is needed on 64-bit platforms, a new ioctl() would have to be added,
2978 * so backwards-compatibility for the embedded platforms can be
2979 * maintained. --davidm 4-Feb-2004.
2980 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 case RADEON_PARAM_SAREA_HANDLE:
2982 /* The lock is the first dword in the sarea. */
2983 value = (long)dev->lock.hw_lock;
2984 break;
2985#endif
2986 case RADEON_PARAM_GART_TEX_HANDLE:
2987 value = dev_priv->gart_textures_offset;
2988 break;
Michel Dänzer8624ecb2006-08-07 20:33:57 +10002989 case RADEON_PARAM_SCRATCH_OFFSET:
2990 if (!dev_priv->writeback_works)
2991 return DRM_ERR(EINVAL);
2992 value = RADEON_SCRATCH_REG_OFFSET;
2993 break;
Dave Airlied985c102006-01-02 21:32:48 +11002994 case RADEON_PARAM_CARD_TYPE:
Dave Airlie54a56ac2006-09-22 04:25:09 +10002995 if (dev_priv->flags & RADEON_IS_PCIE)
Dave Airlied985c102006-01-02 21:32:48 +11002996 value = RADEON_CARD_PCIE;
Dave Airlie54a56ac2006-09-22 04:25:09 +10002997 else if (dev_priv->flags & RADEON_IS_AGP)
Dave Airlied985c102006-01-02 21:32:48 +11002998 value = RADEON_CARD_AGP;
2999 else
3000 value = RADEON_CARD_PCI;
3001 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 default:
Michel Dänzer9ca94162006-08-07 20:31:30 +10003003 DRM_DEBUG("Invalid parameter %d\n", param.param);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 return DRM_ERR(EINVAL);
3005 }
3006
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003007 if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
3008 DRM_ERROR("copy_to_user\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 return DRM_ERR(EFAULT);
3010 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003011
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 return 0;
3013}
3014
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003015static int radeon_cp_setparam(DRM_IOCTL_ARGS)
3016{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 DRM_DEVICE;
3018 drm_radeon_private_t *dev_priv = dev->dev_private;
3019 drm_file_t *filp_priv;
3020 drm_radeon_setparam_t sp;
3021 struct drm_radeon_driver_file_fields *radeon_priv;
3022
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003023 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003025 DRM_COPY_FROM_USER_IOCTL(sp, (drm_radeon_setparam_t __user *) data,
3026 sizeof(sp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003028 switch (sp.param) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 case RADEON_SETPARAM_FB_LOCATION:
3030 radeon_priv = filp_priv->driver_priv;
3031 radeon_priv->radeon_fb_delta = dev_priv->fb_location - sp.value;
3032 break;
3033 case RADEON_SETPARAM_SWITCH_TILING:
3034 if (sp.value == 0) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003035 DRM_DEBUG("color tiling disabled\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036 dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO;
3037 dev_priv->back_pitch_offset &= ~RADEON_DST_TILE_MACRO;
3038 dev_priv->sarea_priv->tiling_enabled = 0;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003039 } else if (sp.value == 1) {
3040 DRM_DEBUG("color tiling enabled\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 dev_priv->front_pitch_offset |= RADEON_DST_TILE_MACRO;
3042 dev_priv->back_pitch_offset |= RADEON_DST_TILE_MACRO;
3043 dev_priv->sarea_priv->tiling_enabled = 1;
3044 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003045 break;
Dave Airlieea98a922005-09-11 20:28:11 +10003046 case RADEON_SETPARAM_PCIGART_LOCATION:
3047 dev_priv->pcigart_offset = sp.value;
3048 break;
Dave Airlied5ea7022006-03-19 19:37:55 +11003049 case RADEON_SETPARAM_NEW_MEMMAP:
3050 dev_priv->new_memmap = sp.value;
3051 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003053 DRM_DEBUG("Invalid parameter %d\n", sp.param);
3054 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 }
3056
3057 return 0;
3058}
3059
3060/* When a client dies:
3061 * - Check for and clean up flipped page state
3062 * - Free any alloced GART memory.
Dave Airlied985c102006-01-02 21:32:48 +11003063 * - Free any alloced radeon surfaces.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 *
3065 * DRM infrastructure takes care of reclaiming dma buffers.
3066 */
Dave Airlie22eae942005-11-10 22:16:34 +11003067void radeon_driver_preclose(drm_device_t * dev, DRMFILE filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068{
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003069 if (dev->dev_private) {
3070 drm_radeon_private_t *dev_priv = dev->dev_private;
3071 if (dev_priv->page_flipping) {
3072 radeon_do_cleanup_pageflip(dev);
3073 }
3074 radeon_mem_release(filp, dev_priv->gart_heap);
3075 radeon_mem_release(filp, dev_priv->fb_heap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 radeon_surfaces_release(filp, dev_priv);
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003077 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078}
3079
Dave Airlie22eae942005-11-10 22:16:34 +11003080void radeon_driver_lastclose(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081{
3082 radeon_do_release(dev);
3083}
3084
Dave Airlie22eae942005-11-10 22:16:34 +11003085int radeon_driver_open(drm_device_t * dev, drm_file_t * filp_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086{
3087 drm_radeon_private_t *dev_priv = dev->dev_private;
3088 struct drm_radeon_driver_file_fields *radeon_priv;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003089
Dave Airlied985c102006-01-02 21:32:48 +11003090 DRM_DEBUG("\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003091 radeon_priv =
3092 (struct drm_radeon_driver_file_fields *)
3093 drm_alloc(sizeof(*radeon_priv), DRM_MEM_FILES);
3094
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 if (!radeon_priv)
3096 return -ENOMEM;
3097
3098 filp_priv->driver_priv = radeon_priv;
Dave Airlied985c102006-01-02 21:32:48 +11003099
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003100 if (dev_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 radeon_priv->radeon_fb_delta = dev_priv->fb_location;
3102 else
3103 radeon_priv->radeon_fb_delta = 0;
3104 return 0;
3105}
3106
Dave Airlie22eae942005-11-10 22:16:34 +11003107void radeon_driver_postclose(drm_device_t * dev, drm_file_t * filp_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108{
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003109 struct drm_radeon_driver_file_fields *radeon_priv =
3110 filp_priv->driver_priv;
3111
3112 drm_free(radeon_priv, sizeof(*radeon_priv), DRM_MEM_FILES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113}
3114
3115drm_ioctl_desc_t radeon_ioctls[] = {
Dave Airliea7a2cc32006-01-02 13:54:04 +11003116 [DRM_IOCTL_NR(DRM_RADEON_CP_INIT)] = {radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3117 [DRM_IOCTL_NR(DRM_RADEON_CP_START)] = {radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3118 [DRM_IOCTL_NR(DRM_RADEON_CP_STOP)] = {radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3119 [DRM_IOCTL_NR(DRM_RADEON_CP_RESET)] = {radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3120 [DRM_IOCTL_NR(DRM_RADEON_CP_IDLE)] = {radeon_cp_idle, DRM_AUTH},
3121 [DRM_IOCTL_NR(DRM_RADEON_CP_RESUME)] = {radeon_cp_resume, DRM_AUTH},
3122 [DRM_IOCTL_NR(DRM_RADEON_RESET)] = {radeon_engine_reset, DRM_AUTH},
3123 [DRM_IOCTL_NR(DRM_RADEON_FULLSCREEN)] = {radeon_fullscreen, DRM_AUTH},
3124 [DRM_IOCTL_NR(DRM_RADEON_SWAP)] = {radeon_cp_swap, DRM_AUTH},
3125 [DRM_IOCTL_NR(DRM_RADEON_CLEAR)] = {radeon_cp_clear, DRM_AUTH},
3126 [DRM_IOCTL_NR(DRM_RADEON_VERTEX)] = {radeon_cp_vertex, DRM_AUTH},
3127 [DRM_IOCTL_NR(DRM_RADEON_INDICES)] = {radeon_cp_indices, DRM_AUTH},
3128 [DRM_IOCTL_NR(DRM_RADEON_TEXTURE)] = {radeon_cp_texture, DRM_AUTH},
3129 [DRM_IOCTL_NR(DRM_RADEON_STIPPLE)] = {radeon_cp_stipple, DRM_AUTH},
3130 [DRM_IOCTL_NR(DRM_RADEON_INDIRECT)] = {radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3131 [DRM_IOCTL_NR(DRM_RADEON_VERTEX2)] = {radeon_cp_vertex2, DRM_AUTH},
3132 [DRM_IOCTL_NR(DRM_RADEON_CMDBUF)] = {radeon_cp_cmdbuf, DRM_AUTH},
3133 [DRM_IOCTL_NR(DRM_RADEON_GETPARAM)] = {radeon_cp_getparam, DRM_AUTH},
3134 [DRM_IOCTL_NR(DRM_RADEON_FLIP)] = {radeon_cp_flip, DRM_AUTH},
3135 [DRM_IOCTL_NR(DRM_RADEON_ALLOC)] = {radeon_mem_alloc, DRM_AUTH},
3136 [DRM_IOCTL_NR(DRM_RADEON_FREE)] = {radeon_mem_free, DRM_AUTH},
3137 [DRM_IOCTL_NR(DRM_RADEON_INIT_HEAP)] = {radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3138 [DRM_IOCTL_NR(DRM_RADEON_IRQ_EMIT)] = {radeon_irq_emit, DRM_AUTH},
3139 [DRM_IOCTL_NR(DRM_RADEON_IRQ_WAIT)] = {radeon_irq_wait, DRM_AUTH},
3140 [DRM_IOCTL_NR(DRM_RADEON_SETPARAM)] = {radeon_cp_setparam, DRM_AUTH},
3141 [DRM_IOCTL_NR(DRM_RADEON_SURF_ALLOC)] = {radeon_surface_alloc, DRM_AUTH},
3142 [DRM_IOCTL_NR(DRM_RADEON_SURF_FREE)] = {radeon_surface_free, DRM_AUTH}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143};
3144
3145int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls);