blob: feac5f005d47be1d56d52819ff8074651ec87e7a [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
Michel Daenzer3e14a282006-09-22 04:26:35 +10001272 BEGIN_RING(9);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273
Michel Daenzer3e14a282006-09-22 04:26:35 +10001274 OUT_RING(CP_PACKET0(RADEON_DP_GUI_MASTER_CNTL, 0));
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001275 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 */
Michel Daenzer3e14a282006-09-22 04:26:35 +10001286 OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 if (dev_priv->current_page == 0) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001288 OUT_RING(dev_priv->back_pitch_offset);
1289 OUT_RING(dev_priv->front_pitch_offset);
1290 } else {
1291 OUT_RING(dev_priv->front_pitch_offset);
1292 OUT_RING(dev_priv->back_pitch_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 }
1294
Michel Daenzer3e14a282006-09-22 04:26:35 +10001295 OUT_RING(CP_PACKET0(RADEON_SRC_X_Y, 2));
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001296 OUT_RING((x << 16) | y);
1297 OUT_RING((x << 16) | y);
1298 OUT_RING((w << 16) | h);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
1300 ADVANCE_RING();
1301 }
1302
1303 /* Increment the frame counter. The client-side 3D driver must
1304 * throttle the framerate by waiting for this value before
1305 * performing the swapbuffer ioctl.
1306 */
1307 dev_priv->sarea_priv->last_frame++;
1308
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001309 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001311 RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 RADEON_WAIT_UNTIL_2D_IDLE();
1313
1314 ADVANCE_RING();
1315}
1316
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001317static void radeon_cp_dispatch_flip(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318{
1319 drm_radeon_private_t *dev_priv = dev->dev_private;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001320 drm_sarea_t *sarea = (drm_sarea_t *) dev_priv->sarea->handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 int offset = (dev_priv->current_page == 1)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001322 ? dev_priv->front_offset : dev_priv->back_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001324 DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
1325 __FUNCTION__,
1326 dev_priv->current_page, dev_priv->sarea_priv->pfCurrentPage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327
1328 /* Do some trivial performance monitoring...
1329 */
1330 if (dev_priv->do_boxes) {
1331 dev_priv->stats.boxes |= RADEON_BOX_FLIP;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001332 radeon_cp_performance_boxes(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 }
1334
1335 /* Update the frame offsets for both CRTCs
1336 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001337 BEGIN_RING(6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338
1339 RADEON_WAIT_UNTIL_3D_IDLE();
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001340 OUT_RING_REG(RADEON_CRTC_OFFSET,
1341 ((sarea->frame.y * dev_priv->front_pitch +
1342 sarea->frame.x * (dev_priv->color_fmt - 2)) & ~7)
1343 + offset);
1344 OUT_RING_REG(RADEON_CRTC2_OFFSET, dev_priv->sarea_priv->crtc2_base
1345 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
1347 ADVANCE_RING();
1348
1349 /* Increment the frame counter. The client-side 3D driver must
1350 * throttle the framerate by waiting for this value before
1351 * performing the swapbuffer ioctl.
1352 */
1353 dev_priv->sarea_priv->last_frame++;
1354 dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page =
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001355 1 - dev_priv->current_page;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001357 BEGIN_RING(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001359 RADEON_FRAME_AGE(dev_priv->sarea_priv->last_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360
1361 ADVANCE_RING();
1362}
1363
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001364static int bad_prim_vertex_nr(int primitive, int nr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365{
1366 switch (primitive & RADEON_PRIM_TYPE_MASK) {
1367 case RADEON_PRIM_TYPE_NONE:
1368 case RADEON_PRIM_TYPE_POINT:
1369 return nr < 1;
1370 case RADEON_PRIM_TYPE_LINE:
1371 return (nr & 1) || nr == 0;
1372 case RADEON_PRIM_TYPE_LINE_STRIP:
1373 return nr < 2;
1374 case RADEON_PRIM_TYPE_TRI_LIST:
1375 case RADEON_PRIM_TYPE_3VRT_POINT_LIST:
1376 case RADEON_PRIM_TYPE_3VRT_LINE_LIST:
1377 case RADEON_PRIM_TYPE_RECT_LIST:
1378 return nr % 3 || nr == 0;
1379 case RADEON_PRIM_TYPE_TRI_FAN:
1380 case RADEON_PRIM_TYPE_TRI_STRIP:
1381 return nr < 3;
1382 default:
1383 return 1;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001384 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385}
1386
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387typedef struct {
1388 unsigned int start;
1389 unsigned int finish;
1390 unsigned int prim;
1391 unsigned int numverts;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001392 unsigned int offset;
1393 unsigned int vc_format;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394} drm_radeon_tcl_prim_t;
1395
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001396static void radeon_cp_dispatch_vertex(drm_device_t * dev,
1397 drm_buf_t * buf,
1398 drm_radeon_tcl_prim_t * prim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399{
1400 drm_radeon_private_t *dev_priv = dev->dev_private;
1401 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
1402 int offset = dev_priv->gart_buffers_offset + buf->offset + prim->start;
1403 int numverts = (int)prim->numverts;
1404 int nbox = sarea_priv->nbox;
1405 int i = 0;
1406 RING_LOCALS;
1407
1408 DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d %d verts\n",
1409 prim->prim,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001410 prim->vc_format, prim->start, prim->finish, prim->numverts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001412 if (bad_prim_vertex_nr(prim->prim, prim->numverts)) {
1413 DRM_ERROR("bad prim %x numverts %d\n",
1414 prim->prim, prim->numverts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 return;
1416 }
1417
1418 do {
1419 /* Emit the next cliprect */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001420 if (i < nbox) {
1421 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 }
1423
1424 /* Emit the vertex buffer rendering commands */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001425 BEGIN_RING(5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001427 OUT_RING(CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, 3));
1428 OUT_RING(offset);
1429 OUT_RING(numverts);
1430 OUT_RING(prim->vc_format);
1431 OUT_RING(prim->prim | RADEON_PRIM_WALK_LIST |
1432 RADEON_COLOR_ORDER_RGBA |
1433 RADEON_VTX_FMT_RADEON_MODE |
1434 (numverts << RADEON_NUM_VERTICES_SHIFT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435
1436 ADVANCE_RING();
1437
1438 i++;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001439 } while (i < nbox);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440}
1441
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001442static void radeon_cp_discard_buffer(drm_device_t * dev, drm_buf_t * buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443{
1444 drm_radeon_private_t *dev_priv = dev->dev_private;
1445 drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
1446 RING_LOCALS;
1447
1448 buf_priv->age = ++dev_priv->sarea_priv->last_dispatch;
1449
1450 /* Emit the vertex buffer age */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001451 BEGIN_RING(2);
1452 RADEON_DISPATCH_AGE(buf_priv->age);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 ADVANCE_RING();
1454
1455 buf->pending = 1;
1456 buf->used = 0;
1457}
1458
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001459static void radeon_cp_dispatch_indirect(drm_device_t * dev,
1460 drm_buf_t * buf, int start, int end)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461{
1462 drm_radeon_private_t *dev_priv = dev->dev_private;
1463 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001464 DRM_DEBUG("indirect: buf=%d s=0x%x e=0x%x\n", buf->idx, start, end);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001466 if (start != end) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 int offset = (dev_priv->gart_buffers_offset
1468 + buf->offset + start);
1469 int dwords = (end - start + 3) / sizeof(u32);
1470
1471 /* Indirect buffer data must be an even number of
1472 * dwords, so if we've been given an odd number we must
1473 * pad the data with a Type-2 CP packet.
1474 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001475 if (dwords & 1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 u32 *data = (u32 *)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001477 ((char *)dev->agp_buffer_map->handle
1478 + buf->offset + start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 data[dwords++] = RADEON_CP_PACKET2;
1480 }
1481
1482 /* Fire off the indirect buffer */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001483 BEGIN_RING(3);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001485 OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1));
1486 OUT_RING(offset);
1487 OUT_RING(dwords);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488
1489 ADVANCE_RING();
1490 }
1491}
1492
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001493static void radeon_cp_dispatch_indices(drm_device_t * dev,
1494 drm_buf_t * elt_buf,
1495 drm_radeon_tcl_prim_t * prim)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496{
1497 drm_radeon_private_t *dev_priv = dev->dev_private;
1498 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
1499 int offset = dev_priv->gart_buffers_offset + prim->offset;
1500 u32 *data;
1501 int dwords;
1502 int i = 0;
1503 int start = prim->start + RADEON_INDEX_PRIM_OFFSET;
1504 int count = (prim->finish - start) / sizeof(u16);
1505 int nbox = sarea_priv->nbox;
1506
1507 DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d offset: %x nr %d\n",
1508 prim->prim,
1509 prim->vc_format,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001510 prim->start, prim->finish, prim->offset, prim->numverts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001512 if (bad_prim_vertex_nr(prim->prim, count)) {
1513 DRM_ERROR("bad prim %x count %d\n", prim->prim, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 return;
1515 }
1516
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001517 if (start >= prim->finish || (prim->start & 0x7)) {
1518 DRM_ERROR("buffer prim %d\n", prim->prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 return;
1520 }
1521
1522 dwords = (prim->finish - prim->start + 3) / sizeof(u32);
1523
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001524 data = (u32 *) ((char *)dev->agp_buffer_map->handle +
1525 elt_buf->offset + prim->start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001527 data[0] = CP_PACKET3(RADEON_3D_RNDR_GEN_INDX_PRIM, dwords - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 data[1] = offset;
1529 data[2] = prim->numverts;
1530 data[3] = prim->vc_format;
1531 data[4] = (prim->prim |
1532 RADEON_PRIM_WALK_IND |
1533 RADEON_COLOR_ORDER_RGBA |
1534 RADEON_VTX_FMT_RADEON_MODE |
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001535 (count << RADEON_NUM_VERTICES_SHIFT));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536
1537 do {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001538 if (i < nbox)
1539 radeon_emit_clip_rect(dev_priv, &sarea_priv->boxes[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001541 radeon_cp_dispatch_indirect(dev, elt_buf,
1542 prim->start, prim->finish);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543
1544 i++;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001545 } while (i < nbox);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546
1547}
1548
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001549#define RADEON_MAX_TEXTURE_SIZE RADEON_BUFFER_SIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001551static int radeon_cp_dispatch_texture(DRMFILE filp,
1552 drm_device_t * dev,
1553 drm_radeon_texture_t * tex,
1554 drm_radeon_tex_image_t * image)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555{
1556 drm_radeon_private_t *dev_priv = dev->dev_private;
1557 drm_file_t *filp_priv;
1558 drm_buf_t *buf;
1559 u32 format;
1560 u32 *buffer;
1561 const u8 __user *data;
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001562 int size, dwords, tex_width, blit_width, spitch;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 u32 height;
1564 int i;
1565 u32 texpitch, microtile;
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001566 u32 offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 RING_LOCALS;
1568
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001569 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001571 if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &tex->offset)) {
1572 DRM_ERROR("Invalid destination offset\n");
1573 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 }
1575
1576 dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD;
1577
1578 /* Flush the pixel cache. This ensures no pixel data gets mixed
1579 * up with the texture data from the host data blit, otherwise
1580 * part of the texture image may be corrupted.
1581 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001582 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 RADEON_FLUSH_CACHE();
1584 RADEON_WAIT_UNTIL_IDLE();
1585 ADVANCE_RING();
1586
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 /* The compiler won't optimize away a division by a variable,
1588 * even if the only legal values are powers of two. Thus, we'll
1589 * use a shift instead.
1590 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001591 switch (tex->format) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 case RADEON_TXFORMAT_ARGB8888:
1593 case RADEON_TXFORMAT_RGBA8888:
1594 format = RADEON_COLOR_FORMAT_ARGB8888;
1595 tex_width = tex->width * 4;
1596 blit_width = image->width * 4;
1597 break;
1598 case RADEON_TXFORMAT_AI88:
1599 case RADEON_TXFORMAT_ARGB1555:
1600 case RADEON_TXFORMAT_RGB565:
1601 case RADEON_TXFORMAT_ARGB4444:
1602 case RADEON_TXFORMAT_VYUY422:
1603 case RADEON_TXFORMAT_YVYU422:
1604 format = RADEON_COLOR_FORMAT_RGB565;
1605 tex_width = tex->width * 2;
1606 blit_width = image->width * 2;
1607 break;
1608 case RADEON_TXFORMAT_I8:
1609 case RADEON_TXFORMAT_RGB332:
1610 format = RADEON_COLOR_FORMAT_CI8;
1611 tex_width = tex->width * 1;
1612 blit_width = image->width * 1;
1613 break;
1614 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001615 DRM_ERROR("invalid texture format %d\n", tex->format);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 return DRM_ERR(EINVAL);
1617 }
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001618 spitch = blit_width >> 6;
1619 if (spitch == 0 && image->height > 1)
1620 return DRM_ERR(EINVAL);
1621
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 texpitch = tex->pitch;
1623 if ((texpitch << 22) & RADEON_DST_TILE_MICRO) {
1624 microtile = 1;
1625 if (tex_width < 64) {
1626 texpitch &= ~(RADEON_DST_TILE_MICRO >> 22);
1627 /* we got tiled coordinates, untile them */
1628 image->x *= 2;
1629 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001630 } else
1631 microtile = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001633 DRM_DEBUG("tex=%dx%d blit=%d\n", tex_width, tex->height, blit_width);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634
1635 do {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001636 DRM_DEBUG("tex: ofs=0x%x p=%d f=%d x=%hd y=%hd w=%hd h=%hd\n",
1637 tex->offset >> 10, tex->pitch, tex->format,
1638 image->x, image->y, image->width, image->height);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639
1640 /* Make a copy of some parameters in case we have to
1641 * update them for a multi-pass texture blit.
1642 */
1643 height = image->height;
1644 data = (const u8 __user *)image->data;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001645
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 size = height * blit_width;
1647
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001648 if (size > RADEON_MAX_TEXTURE_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 height = RADEON_MAX_TEXTURE_SIZE / blit_width;
1650 size = height * blit_width;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001651 } else if (size < 4 && size > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 size = 4;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001653 } else if (size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 return 0;
1655 }
1656
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001657 buf = radeon_freelist_get(dev);
1658 if (0 && !buf) {
1659 radeon_do_cp_idle(dev_priv);
1660 buf = radeon_freelist_get(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001662 if (!buf) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 DRM_DEBUG("radeon_cp_dispatch_texture: EAGAIN\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001664 if (DRM_COPY_TO_USER(tex->image, image, sizeof(*image)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 return DRM_ERR(EFAULT);
1666 return DRM_ERR(EAGAIN);
1667 }
1668
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 /* Dispatch the indirect buffer.
1670 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001671 buffer =
1672 (u32 *) ((char *)dev->agp_buffer_map->handle + buf->offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 dwords = size / 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674
Dave Airlied985c102006-01-02 21:32:48 +11001675#define RADEON_COPY_MT(_buf, _data, _width) \
1676 do { \
1677 if (DRM_COPY_FROM_USER(_buf, _data, (_width))) {\
1678 DRM_ERROR("EFAULT on pad, %d bytes\n", (_width)); \
1679 return DRM_ERR(EFAULT); \
1680 } \
1681 } while(0)
1682
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 if (microtile) {
1684 /* texture micro tiling in use, minimum texture width is thus 16 bytes.
1685 however, we cannot use blitter directly for texture width < 64 bytes,
1686 since minimum tex pitch is 64 bytes and we need this to match
1687 the texture width, otherwise the blitter will tile it wrong.
1688 Thus, tiling manually in this case. Additionally, need to special
1689 case tex height = 1, since our actual image will have height 2
1690 and we need to ensure we don't read beyond the texture size
1691 from user space. */
1692 if (tex->height == 1) {
1693 if (tex_width >= 64 || tex_width <= 16) {
Dave Airlied985c102006-01-02 21:32:48 +11001694 RADEON_COPY_MT(buffer, data,
Dave Airlief8e0f292006-01-10 19:56:17 +11001695 (int)(tex_width * sizeof(u32)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 } else if (tex_width == 32) {
Dave Airlied985c102006-01-02 21:32:48 +11001697 RADEON_COPY_MT(buffer, data, 16);
1698 RADEON_COPY_MT(buffer + 8,
1699 data + 16, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 }
1701 } else if (tex_width >= 64 || tex_width == 16) {
Dave Airlied985c102006-01-02 21:32:48 +11001702 RADEON_COPY_MT(buffer, data,
Dave Airlief8e0f292006-01-10 19:56:17 +11001703 (int)(dwords * sizeof(u32)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 } else if (tex_width < 16) {
1705 for (i = 0; i < tex->height; i++) {
Dave Airlied985c102006-01-02 21:32:48 +11001706 RADEON_COPY_MT(buffer, data, tex_width);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 buffer += 4;
1708 data += tex_width;
1709 }
1710 } else if (tex_width == 32) {
1711 /* TODO: make sure this works when not fitting in one buffer
1712 (i.e. 32bytes x 2048...) */
1713 for (i = 0; i < tex->height; i += 2) {
Dave Airlied985c102006-01-02 21:32:48 +11001714 RADEON_COPY_MT(buffer, data, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 data += 16;
Dave Airlied985c102006-01-02 21:32:48 +11001716 RADEON_COPY_MT(buffer + 8, data, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 data += 16;
Dave Airlied985c102006-01-02 21:32:48 +11001718 RADEON_COPY_MT(buffer + 4, data, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 data += 16;
Dave Airlied985c102006-01-02 21:32:48 +11001720 RADEON_COPY_MT(buffer + 12, data, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 data += 16;
1722 buffer += 16;
1723 }
1724 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001725 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 if (tex_width >= 32) {
1727 /* Texture image width is larger than the minimum, so we
1728 * can upload it directly.
1729 */
Dave Airlied985c102006-01-02 21:32:48 +11001730 RADEON_COPY_MT(buffer, data,
Dave Airlief8e0f292006-01-10 19:56:17 +11001731 (int)(dwords * sizeof(u32)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 } else {
1733 /* Texture image width is less than the minimum, so we
1734 * need to pad out each image scanline to the minimum
1735 * width.
1736 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001737 for (i = 0; i < tex->height; i++) {
Dave Airlied985c102006-01-02 21:32:48 +11001738 RADEON_COPY_MT(buffer, data, tex_width);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 buffer += 8;
1740 data += tex_width;
1741 }
1742 }
1743 }
1744
Dave Airlied985c102006-01-02 21:32:48 +11001745#undef RADEON_COPY_MT
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 buf->filp = filp;
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001747 buf->used = size;
1748 offset = dev_priv->gart_buffers_offset + buf->offset;
1749 BEGIN_RING(9);
1750 OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
1751 OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
1752 RADEON_GMC_DST_PITCH_OFFSET_CNTL |
1753 RADEON_GMC_BRUSH_NONE |
1754 (format << 8) |
1755 RADEON_GMC_SRC_DATATYPE_COLOR |
1756 RADEON_ROP3_S |
1757 RADEON_DP_SRC_SOURCE_MEMORY |
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001758 RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
Dave Airlieffbbf7a2005-08-20 17:40:04 +10001759 OUT_RING((spitch << 22) | (offset >> 10));
1760 OUT_RING((texpitch << 22) | (tex->offset >> 10));
1761 OUT_RING(0);
1762 OUT_RING((image->x << 16) | image->y);
1763 OUT_RING((image->width << 16) | height);
1764 RADEON_WAIT_UNTIL_2D_IDLE();
1765 ADVANCE_RING();
1766
1767 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768
1769 /* Update the input parameters for next time */
1770 image->y += height;
1771 image->height -= height;
1772 image->data = (const u8 __user *)image->data + size;
1773 } while (image->height > 0);
1774
1775 /* Flush the pixel cache after the blit completes. This ensures
1776 * the texture data is written out to memory before rendering
1777 * continues.
1778 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001779 BEGIN_RING(4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 RADEON_FLUSH_CACHE();
1781 RADEON_WAIT_UNTIL_2D_IDLE();
1782 ADVANCE_RING();
1783 return 0;
1784}
1785
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001786static void radeon_cp_dispatch_stipple(drm_device_t * dev, u32 * stipple)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787{
1788 drm_radeon_private_t *dev_priv = dev->dev_private;
1789 int i;
1790 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001791 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001793 BEGIN_RING(35);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001795 OUT_RING(CP_PACKET0(RADEON_RE_STIPPLE_ADDR, 0));
1796 OUT_RING(0x00000000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001798 OUT_RING(CP_PACKET0_TABLE(RADEON_RE_STIPPLE_DATA, 31));
1799 for (i = 0; i < 32; i++) {
1800 OUT_RING(stipple[i]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 }
1802
1803 ADVANCE_RING();
1804}
1805
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001806static void radeon_apply_surface_regs(int surf_index,
Dave Airlied985c102006-01-02 21:32:48 +11001807 drm_radeon_private_t *dev_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808{
1809 if (!dev_priv->mmio)
1810 return;
1811
1812 radeon_do_cp_idle(dev_priv);
1813
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001814 RADEON_WRITE(RADEON_SURFACE0_INFO + 16 * surf_index,
1815 dev_priv->surfaces[surf_index].flags);
1816 RADEON_WRITE(RADEON_SURFACE0_LOWER_BOUND + 16 * surf_index,
1817 dev_priv->surfaces[surf_index].lower);
1818 RADEON_WRITE(RADEON_SURFACE0_UPPER_BOUND + 16 * surf_index,
1819 dev_priv->surfaces[surf_index].upper);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820}
1821
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822/* Allocates a virtual surface
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001823 * doesn't always allocate a real surface, will stretch an existing
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 * surface when possible.
1825 *
1826 * Note that refcount can be at most 2, since during a free refcount=3
1827 * might mean we have to allocate a new surface which might not always
1828 * be available.
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001829 * For example : we allocate three contigous surfaces ABC. If B is
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 * freed, we suddenly need two surfaces to store A and C, which might
1831 * not always be available.
1832 */
Dave Airlied985c102006-01-02 21:32:48 +11001833static int alloc_surface(drm_radeon_surface_alloc_t *new,
1834 drm_radeon_private_t *dev_priv, DRMFILE filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835{
1836 struct radeon_virt_surface *s;
1837 int i;
1838 int virt_surface_index;
1839 uint32_t new_upper, new_lower;
1840
1841 new_lower = new->address;
1842 new_upper = new_lower + new->size - 1;
1843
1844 /* sanity check */
1845 if ((new_lower >= new_upper) || (new->flags == 0) || (new->size == 0) ||
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001846 ((new_upper & RADEON_SURF_ADDRESS_FIXED_MASK) !=
1847 RADEON_SURF_ADDRESS_FIXED_MASK)
1848 || ((new_lower & RADEON_SURF_ADDRESS_FIXED_MASK) != 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 return -1;
1850
1851 /* make sure there is no overlap with existing surfaces */
1852 for (i = 0; i < RADEON_MAX_SURFACES; i++) {
1853 if ((dev_priv->surfaces[i].refcount != 0) &&
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001854 (((new_lower >= dev_priv->surfaces[i].lower) &&
1855 (new_lower < dev_priv->surfaces[i].upper)) ||
1856 ((new_lower < dev_priv->surfaces[i].lower) &&
1857 (new_upper > dev_priv->surfaces[i].lower)))) {
1858 return -1;
1859 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 }
1861
1862 /* find a virtual surface */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001863 for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 if (dev_priv->virt_surfaces[i].filp == 0)
1865 break;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001866 if (i == 2 * RADEON_MAX_SURFACES) {
1867 return -1;
1868 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 virt_surface_index = i;
1870
1871 /* try to reuse an existing surface */
1872 for (i = 0; i < RADEON_MAX_SURFACES; i++) {
1873 /* extend before */
1874 if ((dev_priv->surfaces[i].refcount == 1) &&
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001875 (new->flags == dev_priv->surfaces[i].flags) &&
1876 (new_upper + 1 == dev_priv->surfaces[i].lower)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 s = &(dev_priv->virt_surfaces[virt_surface_index]);
1878 s->surface_index = i;
1879 s->lower = new_lower;
1880 s->upper = new_upper;
1881 s->flags = new->flags;
1882 s->filp = filp;
1883 dev_priv->surfaces[i].refcount++;
1884 dev_priv->surfaces[i].lower = s->lower;
1885 radeon_apply_surface_regs(s->surface_index, dev_priv);
1886 return virt_surface_index;
1887 }
1888
1889 /* extend after */
1890 if ((dev_priv->surfaces[i].refcount == 1) &&
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001891 (new->flags == dev_priv->surfaces[i].flags) &&
1892 (new_lower == dev_priv->surfaces[i].upper + 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 s = &(dev_priv->virt_surfaces[virt_surface_index]);
1894 s->surface_index = i;
1895 s->lower = new_lower;
1896 s->upper = new_upper;
1897 s->flags = new->flags;
1898 s->filp = filp;
1899 dev_priv->surfaces[i].refcount++;
1900 dev_priv->surfaces[i].upper = s->upper;
1901 radeon_apply_surface_regs(s->surface_index, dev_priv);
1902 return virt_surface_index;
1903 }
1904 }
1905
1906 /* okay, we need a new one */
1907 for (i = 0; i < RADEON_MAX_SURFACES; i++) {
1908 if (dev_priv->surfaces[i].refcount == 0) {
1909 s = &(dev_priv->virt_surfaces[virt_surface_index]);
1910 s->surface_index = i;
1911 s->lower = new_lower;
1912 s->upper = new_upper;
1913 s->flags = new->flags;
1914 s->filp = filp;
1915 dev_priv->surfaces[i].refcount = 1;
1916 dev_priv->surfaces[i].lower = s->lower;
1917 dev_priv->surfaces[i].upper = s->upper;
1918 dev_priv->surfaces[i].flags = s->flags;
1919 radeon_apply_surface_regs(s->surface_index, dev_priv);
1920 return virt_surface_index;
1921 }
1922 }
1923
1924 /* we didn't find anything */
1925 return -1;
1926}
1927
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001928static int free_surface(DRMFILE filp, drm_radeon_private_t * dev_priv,
1929 int lower)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930{
1931 struct radeon_virt_surface *s;
1932 int i;
1933 /* find the virtual surface */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001934 for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 s = &(dev_priv->virt_surfaces[i]);
1936 if (s->filp) {
1937 if ((lower == s->lower) && (filp == s->filp)) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001938 if (dev_priv->surfaces[s->surface_index].
1939 lower == s->lower)
1940 dev_priv->surfaces[s->surface_index].
1941 lower = s->upper;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001943 if (dev_priv->surfaces[s->surface_index].
1944 upper == s->upper)
1945 dev_priv->surfaces[s->surface_index].
1946 upper = s->lower;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947
1948 dev_priv->surfaces[s->surface_index].refcount--;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001949 if (dev_priv->surfaces[s->surface_index].
1950 refcount == 0)
1951 dev_priv->surfaces[s->surface_index].
1952 flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 s->filp = NULL;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001954 radeon_apply_surface_regs(s->surface_index,
1955 dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 return 0;
1957 }
1958 }
1959 }
1960 return 1;
1961}
1962
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001963static void radeon_surfaces_release(DRMFILE filp,
1964 drm_radeon_private_t * dev_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965{
1966 int i;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001967 for (i = 0; i < 2 * RADEON_MAX_SURFACES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 if (dev_priv->virt_surfaces[i].filp == filp)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001969 free_surface(filp, dev_priv,
1970 dev_priv->virt_surfaces[i].lower);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 }
1972}
1973
1974/* ================================================================
1975 * IOCTL functions
1976 */
1977static int radeon_surface_alloc(DRM_IOCTL_ARGS)
1978{
1979 DRM_DEVICE;
1980 drm_radeon_private_t *dev_priv = dev->dev_private;
1981 drm_radeon_surface_alloc_t alloc;
1982
Dave Airlieb5e89ed2005-09-25 14:28:13 +10001983 DRM_COPY_FROM_USER_IOCTL(alloc,
1984 (drm_radeon_surface_alloc_t __user *) data,
1985 sizeof(alloc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986
1987 if (alloc_surface(&alloc, dev_priv, filp) == -1)
1988 return DRM_ERR(EINVAL);
1989 else
1990 return 0;
1991}
1992
1993static int radeon_surface_free(DRM_IOCTL_ARGS)
1994{
1995 DRM_DEVICE;
1996 drm_radeon_private_t *dev_priv = dev->dev_private;
1997 drm_radeon_surface_free_t memfree;
1998
Dave Airlief15e92d2006-03-19 20:12:23 +11001999 DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_surface_free_t __user *) data,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002000 sizeof(memfree));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001
2002 if (free_surface(filp, dev_priv, memfree.address))
2003 return DRM_ERR(EINVAL);
2004 else
2005 return 0;
2006}
2007
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002008static int radeon_cp_clear(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009{
2010 DRM_DEVICE;
2011 drm_radeon_private_t *dev_priv = dev->dev_private;
2012 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2013 drm_radeon_clear_t clear;
2014 drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002015 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002017 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002019 DRM_COPY_FROM_USER_IOCTL(clear, (drm_radeon_clear_t __user *) data,
2020 sizeof(clear));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002022 RING_SPACE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002024 if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
2026
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002027 if (DRM_COPY_FROM_USER(&depth_boxes, clear.depth_boxes,
2028 sarea_priv->nbox * sizeof(depth_boxes[0])))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 return DRM_ERR(EFAULT);
2030
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002031 radeon_cp_dispatch_clear(dev, &clear, depth_boxes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032
2033 COMMIT_RING();
2034 return 0;
2035}
2036
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037/* Not sure why this isn't set all the time:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002038 */
2039static int radeon_do_init_pageflip(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040{
2041 drm_radeon_private_t *dev_priv = dev->dev_private;
2042 RING_LOCALS;
2043
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002044 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002046 BEGIN_RING(6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 RADEON_WAIT_UNTIL_3D_IDLE();
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002048 OUT_RING(CP_PACKET0(RADEON_CRTC_OFFSET_CNTL, 0));
2049 OUT_RING(RADEON_READ(RADEON_CRTC_OFFSET_CNTL) |
2050 RADEON_CRTC_OFFSET_FLIP_CNTL);
2051 OUT_RING(CP_PACKET0(RADEON_CRTC2_OFFSET_CNTL, 0));
2052 OUT_RING(RADEON_READ(RADEON_CRTC2_OFFSET_CNTL) |
2053 RADEON_CRTC_OFFSET_FLIP_CNTL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 ADVANCE_RING();
2055
2056 dev_priv->page_flipping = 1;
2057 dev_priv->current_page = 0;
2058 dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page;
2059
2060 return 0;
2061}
2062
2063/* Called whenever a client dies, from drm_release.
2064 * NOTE: Lock isn't necessarily held when this is called!
2065 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002066static int radeon_do_cleanup_pageflip(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067{
2068 drm_radeon_private_t *dev_priv = dev->dev_private;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002069 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070
2071 if (dev_priv->current_page != 0)
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002072 radeon_cp_dispatch_flip(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073
2074 dev_priv->page_flipping = 0;
2075 return 0;
2076}
2077
2078/* Swapping and flipping are different operations, need different ioctls.
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002079 * They can & should be intermixed to support multiple 3d windows.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002081static int radeon_cp_flip(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082{
2083 DRM_DEVICE;
2084 drm_radeon_private_t *dev_priv = dev->dev_private;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002085 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002087 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002089 RING_SPACE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002091 if (!dev_priv->page_flipping)
2092 radeon_do_init_pageflip(dev);
2093
2094 radeon_cp_dispatch_flip(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095
2096 COMMIT_RING();
2097 return 0;
2098}
2099
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002100static int radeon_cp_swap(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101{
2102 DRM_DEVICE;
2103 drm_radeon_private_t *dev_priv = dev->dev_private;
2104 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002105 DRM_DEBUG("\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002107 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002109 RING_SPACE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002111 if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
2113
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002114 radeon_cp_dispatch_swap(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 dev_priv->sarea_priv->ctx_owner = 0;
2116
2117 COMMIT_RING();
2118 return 0;
2119}
2120
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002121static int radeon_cp_vertex(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122{
2123 DRM_DEVICE;
2124 drm_radeon_private_t *dev_priv = dev->dev_private;
2125 drm_file_t *filp_priv;
2126 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2127 drm_device_dma_t *dma = dev->dma;
2128 drm_buf_t *buf;
2129 drm_radeon_vertex_t vertex;
2130 drm_radeon_tcl_prim_t prim;
2131
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002132 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002134 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002136 DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex_t __user *) data,
2137 sizeof(vertex));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002139 DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n",
2140 DRM_CURRENTPID, vertex.idx, vertex.count, vertex.discard);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002142 if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
2143 DRM_ERROR("buffer index %d (of %d max)\n",
2144 vertex.idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 return DRM_ERR(EINVAL);
2146 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002147 if (vertex.prim < 0 || vertex.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
2148 DRM_ERROR("buffer prim %d\n", vertex.prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 return DRM_ERR(EINVAL);
2150 }
2151
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002152 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2153 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154
2155 buf = dma->buflist[vertex.idx];
2156
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002157 if (buf->filp != filp) {
2158 DRM_ERROR("process %d using buffer owned by %p\n",
2159 DRM_CURRENTPID, buf->filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 return DRM_ERR(EINVAL);
2161 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002162 if (buf->pending) {
2163 DRM_ERROR("sending pending buffer %d\n", vertex.idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 return DRM_ERR(EINVAL);
2165 }
2166
2167 /* Build up a prim_t record:
2168 */
2169 if (vertex.count) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002170 buf->used = vertex.count; /* not used? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002172 if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
2173 if (radeon_emit_state(dev_priv, filp_priv,
2174 &sarea_priv->context_state,
2175 sarea_priv->tex_state,
2176 sarea_priv->dirty)) {
2177 DRM_ERROR("radeon_emit_state failed\n");
2178 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 }
2180
2181 sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
2182 RADEON_UPLOAD_TEX1IMAGES |
2183 RADEON_UPLOAD_TEX2IMAGES |
2184 RADEON_REQUIRE_QUIESCENCE);
2185 }
2186
2187 prim.start = 0;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002188 prim.finish = vertex.count; /* unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 prim.prim = vertex.prim;
2190 prim.numverts = vertex.count;
2191 prim.vc_format = dev_priv->sarea_priv->vc_format;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002192
2193 radeon_cp_dispatch_vertex(dev, buf, &prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 }
2195
2196 if (vertex.discard) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002197 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 }
2199
2200 COMMIT_RING();
2201 return 0;
2202}
2203
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002204static int radeon_cp_indices(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205{
2206 DRM_DEVICE;
2207 drm_radeon_private_t *dev_priv = dev->dev_private;
2208 drm_file_t *filp_priv;
2209 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2210 drm_device_dma_t *dma = dev->dma;
2211 drm_buf_t *buf;
2212 drm_radeon_indices_t elts;
2213 drm_radeon_tcl_prim_t prim;
2214 int count;
2215
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002216 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002218 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002220 DRM_COPY_FROM_USER_IOCTL(elts, (drm_radeon_indices_t __user *) data,
2221 sizeof(elts));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002223 DRM_DEBUG("pid=%d index=%d start=%d end=%d discard=%d\n",
2224 DRM_CURRENTPID, elts.idx, elts.start, elts.end, elts.discard);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002226 if (elts.idx < 0 || elts.idx >= dma->buf_count) {
2227 DRM_ERROR("buffer index %d (of %d max)\n",
2228 elts.idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 return DRM_ERR(EINVAL);
2230 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002231 if (elts.prim < 0 || elts.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST) {
2232 DRM_ERROR("buffer prim %d\n", elts.prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 return DRM_ERR(EINVAL);
2234 }
2235
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002236 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2237 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238
2239 buf = dma->buflist[elts.idx];
2240
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002241 if (buf->filp != filp) {
2242 DRM_ERROR("process %d using buffer owned by %p\n",
2243 DRM_CURRENTPID, buf->filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244 return DRM_ERR(EINVAL);
2245 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002246 if (buf->pending) {
2247 DRM_ERROR("sending pending buffer %d\n", elts.idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 return DRM_ERR(EINVAL);
2249 }
2250
2251 count = (elts.end - elts.start) / sizeof(u16);
2252 elts.start -= RADEON_INDEX_PRIM_OFFSET;
2253
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002254 if (elts.start & 0x7) {
2255 DRM_ERROR("misaligned buffer 0x%x\n", elts.start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 return DRM_ERR(EINVAL);
2257 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002258 if (elts.start < buf->used) {
2259 DRM_ERROR("no header 0x%x - 0x%x\n", elts.start, buf->used);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 return DRM_ERR(EINVAL);
2261 }
2262
2263 buf->used = elts.end;
2264
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002265 if (sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS) {
2266 if (radeon_emit_state(dev_priv, filp_priv,
2267 &sarea_priv->context_state,
2268 sarea_priv->tex_state,
2269 sarea_priv->dirty)) {
2270 DRM_ERROR("radeon_emit_state failed\n");
2271 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 }
2273
2274 sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
2275 RADEON_UPLOAD_TEX1IMAGES |
2276 RADEON_UPLOAD_TEX2IMAGES |
2277 RADEON_REQUIRE_QUIESCENCE);
2278 }
2279
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 /* Build up a prim_t record:
2281 */
2282 prim.start = elts.start;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002283 prim.finish = elts.end;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 prim.prim = elts.prim;
2285 prim.offset = 0; /* offset from start of dma buffers */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002286 prim.numverts = RADEON_MAX_VB_VERTS; /* duh */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 prim.vc_format = dev_priv->sarea_priv->vc_format;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002288
2289 radeon_cp_dispatch_indices(dev, buf, &prim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 if (elts.discard) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002291 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 }
2293
2294 COMMIT_RING();
2295 return 0;
2296}
2297
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002298static int radeon_cp_texture(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299{
2300 DRM_DEVICE;
2301 drm_radeon_private_t *dev_priv = dev->dev_private;
2302 drm_radeon_texture_t tex;
2303 drm_radeon_tex_image_t image;
2304 int ret;
2305
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002306 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002308 DRM_COPY_FROM_USER_IOCTL(tex, (drm_radeon_texture_t __user *) data,
2309 sizeof(tex));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002311 if (tex.image == NULL) {
2312 DRM_ERROR("null texture image!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 return DRM_ERR(EINVAL);
2314 }
2315
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002316 if (DRM_COPY_FROM_USER(&image,
2317 (drm_radeon_tex_image_t __user *) tex.image,
2318 sizeof(image)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319 return DRM_ERR(EFAULT);
2320
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002321 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2322 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002324 ret = radeon_cp_dispatch_texture(filp, dev, &tex, &image);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325
2326 COMMIT_RING();
2327 return ret;
2328}
2329
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002330static int radeon_cp_stipple(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331{
2332 DRM_DEVICE;
2333 drm_radeon_private_t *dev_priv = dev->dev_private;
2334 drm_radeon_stipple_t stipple;
2335 u32 mask[32];
2336
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002337 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002339 DRM_COPY_FROM_USER_IOCTL(stipple, (drm_radeon_stipple_t __user *) data,
2340 sizeof(stipple));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002342 if (DRM_COPY_FROM_USER(&mask, stipple.mask, 32 * sizeof(u32)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 return DRM_ERR(EFAULT);
2344
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002345 RING_SPACE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002347 radeon_cp_dispatch_stipple(dev, mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348
2349 COMMIT_RING();
2350 return 0;
2351}
2352
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002353static int radeon_cp_indirect(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354{
2355 DRM_DEVICE;
2356 drm_radeon_private_t *dev_priv = dev->dev_private;
2357 drm_device_dma_t *dma = dev->dma;
2358 drm_buf_t *buf;
2359 drm_radeon_indirect_t indirect;
2360 RING_LOCALS;
2361
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002362 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002364 DRM_COPY_FROM_USER_IOCTL(indirect,
2365 (drm_radeon_indirect_t __user *) data,
2366 sizeof(indirect));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002368 DRM_DEBUG("indirect: idx=%d s=%d e=%d d=%d\n",
2369 indirect.idx, indirect.start, indirect.end, indirect.discard);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002371 if (indirect.idx < 0 || indirect.idx >= dma->buf_count) {
2372 DRM_ERROR("buffer index %d (of %d max)\n",
2373 indirect.idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 return DRM_ERR(EINVAL);
2375 }
2376
2377 buf = dma->buflist[indirect.idx];
2378
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002379 if (buf->filp != filp) {
2380 DRM_ERROR("process %d using buffer owned by %p\n",
2381 DRM_CURRENTPID, buf->filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 return DRM_ERR(EINVAL);
2383 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002384 if (buf->pending) {
2385 DRM_ERROR("sending pending buffer %d\n", indirect.idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 return DRM_ERR(EINVAL);
2387 }
2388
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002389 if (indirect.start < buf->used) {
2390 DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n",
2391 indirect.start, buf->used);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392 return DRM_ERR(EINVAL);
2393 }
2394
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002395 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2396 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397
2398 buf->used = indirect.end;
2399
2400 /* Wait for the 3D stream to idle before the indirect buffer
2401 * containing 2D acceleration commands is processed.
2402 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002403 BEGIN_RING(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404
2405 RADEON_WAIT_UNTIL_3D_IDLE();
2406
2407 ADVANCE_RING();
2408
2409 /* Dispatch the indirect buffer full of commands from the
2410 * X server. This is insecure and is thus only available to
2411 * privileged clients.
2412 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002413 radeon_cp_dispatch_indirect(dev, buf, indirect.start, indirect.end);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 if (indirect.discard) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002415 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 }
2417
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 COMMIT_RING();
2419 return 0;
2420}
2421
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002422static int radeon_cp_vertex2(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423{
2424 DRM_DEVICE;
2425 drm_radeon_private_t *dev_priv = dev->dev_private;
2426 drm_file_t *filp_priv;
2427 drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
2428 drm_device_dma_t *dma = dev->dma;
2429 drm_buf_t *buf;
2430 drm_radeon_vertex2_t vertex;
2431 int i;
2432 unsigned char laststate;
2433
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002434 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002436 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002438 DRM_COPY_FROM_USER_IOCTL(vertex, (drm_radeon_vertex2_t __user *) data,
2439 sizeof(vertex));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002441 DRM_DEBUG("pid=%d index=%d discard=%d\n",
2442 DRM_CURRENTPID, vertex.idx, vertex.discard);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002444 if (vertex.idx < 0 || vertex.idx >= dma->buf_count) {
2445 DRM_ERROR("buffer index %d (of %d max)\n",
2446 vertex.idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 return DRM_ERR(EINVAL);
2448 }
2449
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002450 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2451 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452
2453 buf = dma->buflist[vertex.idx];
2454
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002455 if (buf->filp != filp) {
2456 DRM_ERROR("process %d using buffer owned by %p\n",
2457 DRM_CURRENTPID, buf->filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 return DRM_ERR(EINVAL);
2459 }
2460
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002461 if (buf->pending) {
2462 DRM_ERROR("sending pending buffer %d\n", vertex.idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 return DRM_ERR(EINVAL);
2464 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002465
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
2467 return DRM_ERR(EINVAL);
2468
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002469 for (laststate = 0xff, i = 0; i < vertex.nr_prims; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 drm_radeon_prim_t prim;
2471 drm_radeon_tcl_prim_t tclprim;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002472
2473 if (DRM_COPY_FROM_USER(&prim, &vertex.prim[i], sizeof(prim)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 return DRM_ERR(EFAULT);
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002475
2476 if (prim.stateidx != laststate) {
2477 drm_radeon_state_t state;
2478
2479 if (DRM_COPY_FROM_USER(&state,
2480 &vertex.state[prim.stateidx],
2481 sizeof(state)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 return DRM_ERR(EFAULT);
2483
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002484 if (radeon_emit_state2(dev_priv, filp_priv, &state)) {
2485 DRM_ERROR("radeon_emit_state2 failed\n");
2486 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 }
2488
2489 laststate = prim.stateidx;
2490 }
2491
2492 tclprim.start = prim.start;
2493 tclprim.finish = prim.finish;
2494 tclprim.prim = prim.prim;
2495 tclprim.vc_format = prim.vc_format;
2496
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002497 if (prim.prim & RADEON_PRIM_WALK_IND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498 tclprim.offset = prim.numverts * 64;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002499 tclprim.numverts = RADEON_MAX_VB_VERTS; /* duh */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002501 radeon_cp_dispatch_indices(dev, buf, &tclprim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502 } else {
2503 tclprim.numverts = prim.numverts;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002504 tclprim.offset = 0; /* not used */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002506 radeon_cp_dispatch_vertex(dev, buf, &tclprim);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002508
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 if (sarea_priv->nbox == 1)
2510 sarea_priv->nbox = 0;
2511 }
2512
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002513 if (vertex.discard) {
2514 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 }
2516
2517 COMMIT_RING();
2518 return 0;
2519}
2520
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002521static int radeon_emit_packets(drm_radeon_private_t * dev_priv,
2522 drm_file_t * filp_priv,
2523 drm_radeon_cmd_header_t header,
Dave Airlieb3a83632005-09-30 18:37:36 +10002524 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525{
2526 int id = (int)header.packet.packet_id;
2527 int sz, reg;
2528 int *data = (int *)cmdbuf->buf;
2529 RING_LOCALS;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002530
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 if (id >= RADEON_MAX_STATE_PACKETS)
2532 return DRM_ERR(EINVAL);
2533
2534 sz = packet[id].len;
2535 reg = packet[id].start;
2536
2537 if (sz * sizeof(int) > cmdbuf->bufsz) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002538 DRM_ERROR("Packet size provided larger than data provided\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 return DRM_ERR(EINVAL);
2540 }
2541
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002542 if (radeon_check_and_fixup_packets(dev_priv, filp_priv, id, data)) {
2543 DRM_ERROR("Packet verification failed\n");
2544 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 }
2546
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002547 BEGIN_RING(sz + 1);
2548 OUT_RING(CP_PACKET0(reg, (sz - 1)));
2549 OUT_RING_TABLE(data, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 ADVANCE_RING();
2551
2552 cmdbuf->buf += sz * sizeof(int);
2553 cmdbuf->bufsz -= sz * sizeof(int);
2554 return 0;
2555}
2556
Dave Airlied985c102006-01-02 21:32:48 +11002557static __inline__ int radeon_emit_scalars(drm_radeon_private_t *dev_priv,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002558 drm_radeon_cmd_header_t header,
Dave Airlied985c102006-01-02 21:32:48 +11002559 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560{
2561 int sz = header.scalars.count;
2562 int start = header.scalars.offset;
2563 int stride = header.scalars.stride;
2564 RING_LOCALS;
2565
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002566 BEGIN_RING(3 + sz);
2567 OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
2568 OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
2569 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
2570 OUT_RING_TABLE(cmdbuf->buf, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 ADVANCE_RING();
2572 cmdbuf->buf += sz * sizeof(int);
2573 cmdbuf->bufsz -= sz * sizeof(int);
2574 return 0;
2575}
2576
2577/* God this is ugly
2578 */
Dave Airlied985c102006-01-02 21:32:48 +11002579static __inline__ int radeon_emit_scalars2(drm_radeon_private_t *dev_priv,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002580 drm_radeon_cmd_header_t header,
Dave Airlied985c102006-01-02 21:32:48 +11002581 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582{
2583 int sz = header.scalars.count;
2584 int start = ((unsigned int)header.scalars.offset) + 0x100;
2585 int stride = header.scalars.stride;
2586 RING_LOCALS;
2587
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002588 BEGIN_RING(3 + sz);
2589 OUT_RING(CP_PACKET0(RADEON_SE_TCL_SCALAR_INDX_REG, 0));
2590 OUT_RING(start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
2591 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_SCALAR_DATA_REG, sz - 1));
2592 OUT_RING_TABLE(cmdbuf->buf, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 ADVANCE_RING();
2594 cmdbuf->buf += sz * sizeof(int);
2595 cmdbuf->bufsz -= sz * sizeof(int);
2596 return 0;
2597}
2598
Dave Airlied985c102006-01-02 21:32:48 +11002599static __inline__ int radeon_emit_vectors(drm_radeon_private_t *dev_priv,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002600 drm_radeon_cmd_header_t header,
Dave Airlied985c102006-01-02 21:32:48 +11002601 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602{
2603 int sz = header.vectors.count;
2604 int start = header.vectors.offset;
2605 int stride = header.vectors.stride;
2606 RING_LOCALS;
2607
Dave Airlief2a22792006-06-24 16:55:34 +10002608 BEGIN_RING(5 + sz);
2609 OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002610 OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
2611 OUT_RING(start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
2612 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
2613 OUT_RING_TABLE(cmdbuf->buf, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 ADVANCE_RING();
2615
2616 cmdbuf->buf += sz * sizeof(int);
2617 cmdbuf->bufsz -= sz * sizeof(int);
2618 return 0;
2619}
2620
Dave Airlied6fece02006-06-24 17:04:07 +10002621static __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv,
2622 drm_radeon_cmd_header_t header,
2623 drm_radeon_kcmd_buffer_t *cmdbuf)
2624{
2625 int sz = header.veclinear.count * 4;
2626 int start = header.veclinear.addr_lo | (header.veclinear.addr_hi << 8);
2627 RING_LOCALS;
2628
2629 if (!sz)
2630 return 0;
2631 if (sz * 4 > cmdbuf->bufsz)
2632 return DRM_ERR(EINVAL);
2633
2634 BEGIN_RING(5 + sz);
2635 OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
2636 OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
2637 OUT_RING(start | (1 << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
2638 OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
2639 OUT_RING_TABLE(cmdbuf->buf, sz);
2640 ADVANCE_RING();
2641
2642 cmdbuf->buf += sz * sizeof(int);
2643 cmdbuf->bufsz -= sz * sizeof(int);
2644 return 0;
2645}
2646
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002647static int radeon_emit_packet3(drm_device_t * dev,
2648 drm_file_t * filp_priv,
Dave Airlieb3a83632005-09-30 18:37:36 +10002649 drm_radeon_kcmd_buffer_t *cmdbuf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650{
2651 drm_radeon_private_t *dev_priv = dev->dev_private;
2652 unsigned int cmdsz;
2653 int ret;
2654 RING_LOCALS;
2655
2656 DRM_DEBUG("\n");
2657
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002658 if ((ret = radeon_check_and_fixup_packet3(dev_priv, filp_priv,
2659 cmdbuf, &cmdsz))) {
2660 DRM_ERROR("Packet verification failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 return ret;
2662 }
2663
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002664 BEGIN_RING(cmdsz);
2665 OUT_RING_TABLE(cmdbuf->buf, cmdsz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 ADVANCE_RING();
2667
2668 cmdbuf->buf += cmdsz * 4;
2669 cmdbuf->bufsz -= cmdsz * 4;
2670 return 0;
2671}
2672
Dave Airlied985c102006-01-02 21:32:48 +11002673static int radeon_emit_packet3_cliprect(drm_device_t *dev,
2674 drm_file_t *filp_priv,
Dave Airlieb3a83632005-09-30 18:37:36 +10002675 drm_radeon_kcmd_buffer_t *cmdbuf,
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002676 int orig_nbox)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677{
2678 drm_radeon_private_t *dev_priv = dev->dev_private;
2679 drm_clip_rect_t box;
2680 unsigned int cmdsz;
2681 int ret;
2682 drm_clip_rect_t __user *boxes = cmdbuf->boxes;
2683 int i = 0;
2684 RING_LOCALS;
2685
2686 DRM_DEBUG("\n");
2687
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002688 if ((ret = radeon_check_and_fixup_packet3(dev_priv, filp_priv,
2689 cmdbuf, &cmdsz))) {
2690 DRM_ERROR("Packet verification failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 return ret;
2692 }
2693
2694 if (!orig_nbox)
2695 goto out;
2696
2697 do {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002698 if (i < cmdbuf->nbox) {
2699 if (DRM_COPY_FROM_USER(&box, &boxes[i], sizeof(box)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 return DRM_ERR(EFAULT);
2701 /* FIXME The second and subsequent times round
2702 * this loop, send a WAIT_UNTIL_3D_IDLE before
2703 * calling emit_clip_rect(). This fixes a
2704 * lockup on fast machines when sending
2705 * several cliprects with a cmdbuf, as when
2706 * waving a 2D window over a 3D
2707 * window. Something in the commands from user
2708 * space seems to hang the card when they're
2709 * sent several times in a row. That would be
2710 * the correct place to fix it but this works
2711 * around it until I can figure that out - Tim
2712 * Smith */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002713 if (i) {
2714 BEGIN_RING(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 RADEON_WAIT_UNTIL_3D_IDLE();
2716 ADVANCE_RING();
2717 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002718 radeon_emit_clip_rect(dev_priv, &box);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002720
2721 BEGIN_RING(cmdsz);
2722 OUT_RING_TABLE(cmdbuf->buf, cmdsz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 ADVANCE_RING();
2724
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002725 } while (++i < cmdbuf->nbox);
2726 if (cmdbuf->nbox == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 cmdbuf->nbox = 0;
2728
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002729 out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 cmdbuf->buf += cmdsz * 4;
2731 cmdbuf->bufsz -= cmdsz * 4;
2732 return 0;
2733}
2734
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002735static int radeon_emit_wait(drm_device_t * dev, int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736{
2737 drm_radeon_private_t *dev_priv = dev->dev_private;
2738 RING_LOCALS;
2739
2740 DRM_DEBUG("%s: %x\n", __FUNCTION__, flags);
2741 switch (flags) {
2742 case RADEON_WAIT_2D:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002743 BEGIN_RING(2);
2744 RADEON_WAIT_UNTIL_2D_IDLE();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 ADVANCE_RING();
2746 break;
2747 case RADEON_WAIT_3D:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002748 BEGIN_RING(2);
2749 RADEON_WAIT_UNTIL_3D_IDLE();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 ADVANCE_RING();
2751 break;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002752 case RADEON_WAIT_2D | RADEON_WAIT_3D:
2753 BEGIN_RING(2);
2754 RADEON_WAIT_UNTIL_IDLE();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 ADVANCE_RING();
2756 break;
2757 default:
2758 return DRM_ERR(EINVAL);
2759 }
2760
2761 return 0;
2762}
2763
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002764static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765{
2766 DRM_DEVICE;
2767 drm_radeon_private_t *dev_priv = dev->dev_private;
2768 drm_file_t *filp_priv;
2769 drm_device_dma_t *dma = dev->dma;
2770 drm_buf_t *buf = NULL;
2771 int idx;
Dave Airlieb3a83632005-09-30 18:37:36 +10002772 drm_radeon_kcmd_buffer_t cmdbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 drm_radeon_cmd_header_t header;
2774 int orig_nbox, orig_bufsz;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002775 char *kbuf = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002777 LOCK_TEST_WITH_RETURN(dev, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002779 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002781 DRM_COPY_FROM_USER_IOCTL(cmdbuf,
2782 (drm_radeon_cmd_buffer_t __user *) data,
2783 sizeof(cmdbuf));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002785 RING_SPACE_TEST_WITH_RETURN(dev_priv);
2786 VB_AGE_TEST_WITH_RETURN(dev_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002788 if (cmdbuf.bufsz > 64 * 1024 || cmdbuf.bufsz < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 return DRM_ERR(EINVAL);
2790 }
2791
2792 /* Allocate an in-kernel area and copy in the cmdbuf. Do this to avoid
2793 * races between checking values and using those values in other code,
2794 * and simply to avoid a lot of function calls to copy in data.
2795 */
2796 orig_bufsz = cmdbuf.bufsz;
2797 if (orig_bufsz != 0) {
2798 kbuf = drm_alloc(cmdbuf.bufsz, DRM_MEM_DRIVER);
2799 if (kbuf == NULL)
2800 return DRM_ERR(ENOMEM);
Dave Airlied985c102006-01-02 21:32:48 +11002801 if (DRM_COPY_FROM_USER(kbuf, (void __user *)cmdbuf.buf,
2802 cmdbuf.bufsz)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
2804 return DRM_ERR(EFAULT);
2805 }
2806 cmdbuf.buf = kbuf;
2807 }
2808
2809 orig_nbox = cmdbuf.nbox;
2810
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002811 if (dev_priv->microcode_version == UCODE_R300) {
Dave Airlie414ed532005-08-16 20:43:16 +10002812 int temp;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002813 temp = r300_do_cp_cmdbuf(dev, filp, filp_priv, &cmdbuf);
2814
Dave Airlie414ed532005-08-16 20:43:16 +10002815 if (orig_bufsz != 0)
2816 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002817
Dave Airlie414ed532005-08-16 20:43:16 +10002818 return temp;
2819 }
2820
2821 /* microcode_version != r300 */
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002822 while (cmdbuf.bufsz >= sizeof(header)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823
2824 header.i = *(int *)cmdbuf.buf;
2825 cmdbuf.buf += sizeof(header);
2826 cmdbuf.bufsz -= sizeof(header);
2827
2828 switch (header.header.cmd_type) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002829 case RADEON_CMD_PACKET:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 DRM_DEBUG("RADEON_CMD_PACKET\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002831 if (radeon_emit_packets
2832 (dev_priv, filp_priv, header, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 DRM_ERROR("radeon_emit_packets failed\n");
2834 goto err;
2835 }
2836 break;
2837
2838 case RADEON_CMD_SCALARS:
2839 DRM_DEBUG("RADEON_CMD_SCALARS\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002840 if (radeon_emit_scalars(dev_priv, header, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 DRM_ERROR("radeon_emit_scalars failed\n");
2842 goto err;
2843 }
2844 break;
2845
2846 case RADEON_CMD_VECTORS:
2847 DRM_DEBUG("RADEON_CMD_VECTORS\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002848 if (radeon_emit_vectors(dev_priv, header, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 DRM_ERROR("radeon_emit_vectors failed\n");
2850 goto err;
2851 }
2852 break;
2853
2854 case RADEON_CMD_DMA_DISCARD:
2855 DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n");
2856 idx = header.dma.buf_idx;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002857 if (idx < 0 || idx >= dma->buf_count) {
2858 DRM_ERROR("buffer index %d (of %d max)\n",
2859 idx, dma->buf_count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 goto err;
2861 }
2862
2863 buf = dma->buflist[idx];
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002864 if (buf->filp != filp || buf->pending) {
2865 DRM_ERROR("bad buffer %p %p %d\n",
2866 buf->filp, filp, buf->pending);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 goto err;
2868 }
2869
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002870 radeon_cp_discard_buffer(dev, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 break;
2872
2873 case RADEON_CMD_PACKET3:
2874 DRM_DEBUG("RADEON_CMD_PACKET3\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002875 if (radeon_emit_packet3(dev, filp_priv, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 DRM_ERROR("radeon_emit_packet3 failed\n");
2877 goto err;
2878 }
2879 break;
2880
2881 case RADEON_CMD_PACKET3_CLIP:
2882 DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002883 if (radeon_emit_packet3_cliprect
2884 (dev, filp_priv, &cmdbuf, orig_nbox)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 DRM_ERROR("radeon_emit_packet3_clip failed\n");
2886 goto err;
2887 }
2888 break;
2889
2890 case RADEON_CMD_SCALARS2:
2891 DRM_DEBUG("RADEON_CMD_SCALARS2\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002892 if (radeon_emit_scalars2(dev_priv, header, &cmdbuf)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 DRM_ERROR("radeon_emit_scalars2 failed\n");
2894 goto err;
2895 }
2896 break;
2897
2898 case RADEON_CMD_WAIT:
2899 DRM_DEBUG("RADEON_CMD_WAIT\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002900 if (radeon_emit_wait(dev, header.wait.flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 DRM_ERROR("radeon_emit_wait failed\n");
2902 goto err;
2903 }
2904 break;
Dave Airlied6fece02006-06-24 17:04:07 +10002905 case RADEON_CMD_VECLINEAR:
2906 DRM_DEBUG("RADEON_CMD_VECLINEAR\n");
2907 if (radeon_emit_veclinear(dev_priv, header, &cmdbuf)) {
2908 DRM_ERROR("radeon_emit_veclinear failed\n");
2909 goto err;
2910 }
2911 break;
2912
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002914 DRM_ERROR("bad cmd_type %d at %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 header.header.cmd_type,
2916 cmdbuf.buf - sizeof(header));
2917 goto err;
2918 }
2919 }
2920
2921 if (orig_bufsz != 0)
2922 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
2923
2924 DRM_DEBUG("DONE\n");
2925 COMMIT_RING();
2926 return 0;
2927
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002928 err:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 if (orig_bufsz != 0)
2930 drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
2931 return DRM_ERR(EINVAL);
2932}
2933
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002934static int radeon_cp_getparam(DRM_IOCTL_ARGS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935{
2936 DRM_DEVICE;
2937 drm_radeon_private_t *dev_priv = dev->dev_private;
2938 drm_radeon_getparam_t param;
2939 int value;
2940
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002941 DRM_COPY_FROM_USER_IOCTL(param, (drm_radeon_getparam_t __user *) data,
2942 sizeof(param));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002944 DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002946 switch (param.param) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 case RADEON_PARAM_GART_BUFFER_OFFSET:
2948 value = dev_priv->gart_buffers_offset;
2949 break;
2950 case RADEON_PARAM_LAST_FRAME:
2951 dev_priv->stats.last_frame_reads++;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002952 value = GET_SCRATCH(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 break;
2954 case RADEON_PARAM_LAST_DISPATCH:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002955 value = GET_SCRATCH(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 break;
2957 case RADEON_PARAM_LAST_CLEAR:
2958 dev_priv->stats.last_clear_reads++;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002959 value = GET_SCRATCH(2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 break;
2961 case RADEON_PARAM_IRQ_NR:
2962 value = dev->irq;
2963 break;
2964 case RADEON_PARAM_GART_BASE:
2965 value = dev_priv->gart_vm_start;
2966 break;
2967 case RADEON_PARAM_REGISTER_HANDLE:
Dave Airlied985c102006-01-02 21:32:48 +11002968 value = dev_priv->mmio->offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 break;
2970 case RADEON_PARAM_STATUS_HANDLE:
2971 value = dev_priv->ring_rptr_offset;
2972 break;
2973#if BITS_PER_LONG == 32
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002974 /*
2975 * This ioctl() doesn't work on 64-bit platforms because hw_lock is a
2976 * pointer which can't fit into an int-sized variable. According to
2977 * Michel Dänzer, the ioctl() is only used on embedded platforms, so
2978 * not supporting it shouldn't be a problem. If the same functionality
2979 * is needed on 64-bit platforms, a new ioctl() would have to be added,
2980 * so backwards-compatibility for the embedded platforms can be
2981 * maintained. --davidm 4-Feb-2004.
2982 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 case RADEON_PARAM_SAREA_HANDLE:
2984 /* The lock is the first dword in the sarea. */
2985 value = (long)dev->lock.hw_lock;
2986 break;
2987#endif
2988 case RADEON_PARAM_GART_TEX_HANDLE:
2989 value = dev_priv->gart_textures_offset;
2990 break;
Michel Dänzer8624ecb2006-08-07 20:33:57 +10002991 case RADEON_PARAM_SCRATCH_OFFSET:
2992 if (!dev_priv->writeback_works)
2993 return DRM_ERR(EINVAL);
2994 value = RADEON_SCRATCH_REG_OFFSET;
2995 break;
Dave Airlied985c102006-01-02 21:32:48 +11002996 case RADEON_PARAM_CARD_TYPE:
Dave Airlie54a56ac2006-09-22 04:25:09 +10002997 if (dev_priv->flags & RADEON_IS_PCIE)
Dave Airlied985c102006-01-02 21:32:48 +11002998 value = RADEON_CARD_PCIE;
Dave Airlie54a56ac2006-09-22 04:25:09 +10002999 else if (dev_priv->flags & RADEON_IS_AGP)
Dave Airlied985c102006-01-02 21:32:48 +11003000 value = RADEON_CARD_AGP;
3001 else
3002 value = RADEON_CARD_PCI;
3003 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 default:
Michel Dänzer9ca94162006-08-07 20:31:30 +10003005 DRM_DEBUG("Invalid parameter %d\n", param.param);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 return DRM_ERR(EINVAL);
3007 }
3008
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003009 if (DRM_COPY_TO_USER(param.value, &value, sizeof(int))) {
3010 DRM_ERROR("copy_to_user\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 return DRM_ERR(EFAULT);
3012 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003013
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 return 0;
3015}
3016
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003017static int radeon_cp_setparam(DRM_IOCTL_ARGS)
3018{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019 DRM_DEVICE;
3020 drm_radeon_private_t *dev_priv = dev->dev_private;
3021 drm_file_t *filp_priv;
3022 drm_radeon_setparam_t sp;
3023 struct drm_radeon_driver_file_fields *radeon_priv;
3024
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003025 DRM_GET_PRIV_WITH_RETURN(filp_priv, filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003027 DRM_COPY_FROM_USER_IOCTL(sp, (drm_radeon_setparam_t __user *) data,
3028 sizeof(sp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003030 switch (sp.param) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 case RADEON_SETPARAM_FB_LOCATION:
3032 radeon_priv = filp_priv->driver_priv;
3033 radeon_priv->radeon_fb_delta = dev_priv->fb_location - sp.value;
3034 break;
3035 case RADEON_SETPARAM_SWITCH_TILING:
3036 if (sp.value == 0) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003037 DRM_DEBUG("color tiling disabled\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 dev_priv->front_pitch_offset &= ~RADEON_DST_TILE_MACRO;
3039 dev_priv->back_pitch_offset &= ~RADEON_DST_TILE_MACRO;
3040 dev_priv->sarea_priv->tiling_enabled = 0;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003041 } else if (sp.value == 1) {
3042 DRM_DEBUG("color tiling enabled\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043 dev_priv->front_pitch_offset |= RADEON_DST_TILE_MACRO;
3044 dev_priv->back_pitch_offset |= RADEON_DST_TILE_MACRO;
3045 dev_priv->sarea_priv->tiling_enabled = 1;
3046 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003047 break;
Dave Airlieea98a922005-09-11 20:28:11 +10003048 case RADEON_SETPARAM_PCIGART_LOCATION:
3049 dev_priv->pcigart_offset = sp.value;
3050 break;
Dave Airlied5ea7022006-03-19 19:37:55 +11003051 case RADEON_SETPARAM_NEW_MEMMAP:
3052 dev_priv->new_memmap = sp.value;
3053 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 default:
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003055 DRM_DEBUG("Invalid parameter %d\n", sp.param);
3056 return DRM_ERR(EINVAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 }
3058
3059 return 0;
3060}
3061
3062/* When a client dies:
3063 * - Check for and clean up flipped page state
3064 * - Free any alloced GART memory.
Dave Airlied985c102006-01-02 21:32:48 +11003065 * - Free any alloced radeon surfaces.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 *
3067 * DRM infrastructure takes care of reclaiming dma buffers.
3068 */
Dave Airlie22eae942005-11-10 22:16:34 +11003069void radeon_driver_preclose(drm_device_t * dev, DRMFILE filp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070{
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003071 if (dev->dev_private) {
3072 drm_radeon_private_t *dev_priv = dev->dev_private;
3073 if (dev_priv->page_flipping) {
3074 radeon_do_cleanup_pageflip(dev);
3075 }
3076 radeon_mem_release(filp, dev_priv->gart_heap);
3077 radeon_mem_release(filp, dev_priv->fb_heap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 radeon_surfaces_release(filp, dev_priv);
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003079 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080}
3081
Dave Airlie22eae942005-11-10 22:16:34 +11003082void radeon_driver_lastclose(drm_device_t * dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083{
3084 radeon_do_release(dev);
3085}
3086
Dave Airlie22eae942005-11-10 22:16:34 +11003087int radeon_driver_open(drm_device_t * dev, drm_file_t * filp_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088{
3089 drm_radeon_private_t *dev_priv = dev->dev_private;
3090 struct drm_radeon_driver_file_fields *radeon_priv;
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003091
Dave Airlied985c102006-01-02 21:32:48 +11003092 DRM_DEBUG("\n");
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003093 radeon_priv =
3094 (struct drm_radeon_driver_file_fields *)
3095 drm_alloc(sizeof(*radeon_priv), DRM_MEM_FILES);
3096
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 if (!radeon_priv)
3098 return -ENOMEM;
3099
3100 filp_priv->driver_priv = radeon_priv;
Dave Airlied985c102006-01-02 21:32:48 +11003101
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003102 if (dev_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 radeon_priv->radeon_fb_delta = dev_priv->fb_location;
3104 else
3105 radeon_priv->radeon_fb_delta = 0;
3106 return 0;
3107}
3108
Dave Airlie22eae942005-11-10 22:16:34 +11003109void radeon_driver_postclose(drm_device_t * dev, drm_file_t * filp_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110{
Dave Airlieb5e89ed2005-09-25 14:28:13 +10003111 struct drm_radeon_driver_file_fields *radeon_priv =
3112 filp_priv->driver_priv;
3113
3114 drm_free(radeon_priv, sizeof(*radeon_priv), DRM_MEM_FILES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115}
3116
3117drm_ioctl_desc_t radeon_ioctls[] = {
Dave Airliea7a2cc32006-01-02 13:54:04 +11003118 [DRM_IOCTL_NR(DRM_RADEON_CP_INIT)] = {radeon_cp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3119 [DRM_IOCTL_NR(DRM_RADEON_CP_START)] = {radeon_cp_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3120 [DRM_IOCTL_NR(DRM_RADEON_CP_STOP)] = {radeon_cp_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3121 [DRM_IOCTL_NR(DRM_RADEON_CP_RESET)] = {radeon_cp_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3122 [DRM_IOCTL_NR(DRM_RADEON_CP_IDLE)] = {radeon_cp_idle, DRM_AUTH},
3123 [DRM_IOCTL_NR(DRM_RADEON_CP_RESUME)] = {radeon_cp_resume, DRM_AUTH},
3124 [DRM_IOCTL_NR(DRM_RADEON_RESET)] = {radeon_engine_reset, DRM_AUTH},
3125 [DRM_IOCTL_NR(DRM_RADEON_FULLSCREEN)] = {radeon_fullscreen, DRM_AUTH},
3126 [DRM_IOCTL_NR(DRM_RADEON_SWAP)] = {radeon_cp_swap, DRM_AUTH},
3127 [DRM_IOCTL_NR(DRM_RADEON_CLEAR)] = {radeon_cp_clear, DRM_AUTH},
3128 [DRM_IOCTL_NR(DRM_RADEON_VERTEX)] = {radeon_cp_vertex, DRM_AUTH},
3129 [DRM_IOCTL_NR(DRM_RADEON_INDICES)] = {radeon_cp_indices, DRM_AUTH},
3130 [DRM_IOCTL_NR(DRM_RADEON_TEXTURE)] = {radeon_cp_texture, DRM_AUTH},
3131 [DRM_IOCTL_NR(DRM_RADEON_STIPPLE)] = {radeon_cp_stipple, DRM_AUTH},
3132 [DRM_IOCTL_NR(DRM_RADEON_INDIRECT)] = {radeon_cp_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3133 [DRM_IOCTL_NR(DRM_RADEON_VERTEX2)] = {radeon_cp_vertex2, DRM_AUTH},
3134 [DRM_IOCTL_NR(DRM_RADEON_CMDBUF)] = {radeon_cp_cmdbuf, DRM_AUTH},
3135 [DRM_IOCTL_NR(DRM_RADEON_GETPARAM)] = {radeon_cp_getparam, DRM_AUTH},
3136 [DRM_IOCTL_NR(DRM_RADEON_FLIP)] = {radeon_cp_flip, DRM_AUTH},
3137 [DRM_IOCTL_NR(DRM_RADEON_ALLOC)] = {radeon_mem_alloc, DRM_AUTH},
3138 [DRM_IOCTL_NR(DRM_RADEON_FREE)] = {radeon_mem_free, DRM_AUTH},
3139 [DRM_IOCTL_NR(DRM_RADEON_INIT_HEAP)] = {radeon_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
3140 [DRM_IOCTL_NR(DRM_RADEON_IRQ_EMIT)] = {radeon_irq_emit, DRM_AUTH},
3141 [DRM_IOCTL_NR(DRM_RADEON_IRQ_WAIT)] = {radeon_irq_wait, DRM_AUTH},
3142 [DRM_IOCTL_NR(DRM_RADEON_SETPARAM)] = {radeon_cp_setparam, DRM_AUTH},
3143 [DRM_IOCTL_NR(DRM_RADEON_SURF_ALLOC)] = {radeon_surface_alloc, DRM_AUTH},
3144 [DRM_IOCTL_NR(DRM_RADEON_SURF_FREE)] = {radeon_surface_free, DRM_AUTH}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145};
3146
3147int radeon_max_ioctl = DRM_ARRAY_SIZE(radeon_ioctls);