patch-2.4.23 linux-2.4.23/drivers/char/drm/radeon_state.c

Next file: linux-2.4.23/drivers/char/drm/savage.h
Previous file: linux-2.4.23/drivers/char/drm/radeon_mem.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.22/drivers/char/drm/radeon_state.c linux-2.4.23/drivers/char/drm/radeon_state.c
@@ -29,10 +29,11 @@
 
 #include "radeon.h"
 #include "drmP.h"
-#include "radeon_drv.h"
 #include "drm.h"
-#include <linux/delay.h>
-
+#include "drm_sarea.h"
+#include "radeon_drm.h"
+#include "radeon_drv.h"
+#include "drm_os_linux.h"
 
 /* ================================================================
  * CP hardware state programming functions
@@ -47,360 +48,254 @@
 		   box->x1, box->y1, box->x2, box->y2 );
 
 	BEGIN_RING( 4 );
-
 	OUT_RING( CP_PACKET0( RADEON_RE_TOP_LEFT, 0 ) );
 	OUT_RING( (box->y1 << 16) | box->x1 );
-
 	OUT_RING( CP_PACKET0( RADEON_RE_WIDTH_HEIGHT, 0 ) );
 	OUT_RING( ((box->y2 - 1) << 16) | (box->x2 - 1) );
-
-	ADVANCE_RING();
-}
-
-static inline void radeon_emit_context( drm_radeon_private_t *dev_priv )
-{
-	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
-	drm_radeon_context_regs_t *ctx = &sarea_priv->context_state;
-	RING_LOCALS;
-	DRM_DEBUG( "    %s\n", __FUNCTION__ );
-
-	BEGIN_RING( 14 );
-
-	OUT_RING( CP_PACKET0( RADEON_PP_MISC, 6 ) );
-	OUT_RING( ctx->pp_misc );
-	OUT_RING( ctx->pp_fog_color );
-	OUT_RING( ctx->re_solid_color );
-	OUT_RING( ctx->rb3d_blendcntl );
-	OUT_RING( ctx->rb3d_depthoffset );
-	OUT_RING( ctx->rb3d_depthpitch );
-	OUT_RING( ctx->rb3d_zstencilcntl );
-
-	OUT_RING( CP_PACKET0( RADEON_PP_CNTL, 2 ) );
-	OUT_RING( ctx->pp_cntl );
-	OUT_RING( ctx->rb3d_cntl );
-	OUT_RING( ctx->rb3d_coloroffset );
-
-	OUT_RING( CP_PACKET0( RADEON_RB3D_COLORPITCH, 0 ) );
-	OUT_RING( ctx->rb3d_colorpitch );
-
-	ADVANCE_RING();
-}
-
-static inline void radeon_emit_vertfmt( drm_radeon_private_t *dev_priv )
-{
-	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
-	drm_radeon_context_regs_t *ctx = &sarea_priv->context_state;
-	RING_LOCALS;
-	DRM_DEBUG( "    %s\n", __FUNCTION__ );
-
-	BEGIN_RING( 2 );
-
-	OUT_RING( CP_PACKET0( RADEON_SE_COORD_FMT, 0 ) );
-	OUT_RING( ctx->se_coord_fmt );
-
-	ADVANCE_RING();
-}
-
-static inline void radeon_emit_line( drm_radeon_private_t *dev_priv )
-{
-	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
-	drm_radeon_context_regs_t *ctx = &sarea_priv->context_state;
-	RING_LOCALS;
-	DRM_DEBUG( "    %s\n", __FUNCTION__ );
-
-	BEGIN_RING( 5 );
-
-	OUT_RING( CP_PACKET0( RADEON_RE_LINE_PATTERN, 1 ) );
-	OUT_RING( ctx->re_line_pattern );
-	OUT_RING( ctx->re_line_state );
-
-	OUT_RING( CP_PACKET0( RADEON_SE_LINE_WIDTH, 0 ) );
-	OUT_RING( ctx->se_line_width );
-
-	ADVANCE_RING();
-}
-
-static inline void radeon_emit_bumpmap( drm_radeon_private_t *dev_priv )
-{
-	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
-	drm_radeon_context_regs_t *ctx = &sarea_priv->context_state;
-	RING_LOCALS;
-	DRM_DEBUG( "    %s\n", __FUNCTION__ );
-
-	BEGIN_RING( 5 );
-
-	OUT_RING( CP_PACKET0( RADEON_PP_LUM_MATRIX, 0 ) );
-	OUT_RING( ctx->pp_lum_matrix );
-
-	OUT_RING( CP_PACKET0( RADEON_PP_ROT_MATRIX_0, 1 ) );
-	OUT_RING( ctx->pp_rot_matrix_0 );
-	OUT_RING( ctx->pp_rot_matrix_1 );
-
-	ADVANCE_RING();
-}
-
-static inline void radeon_emit_masks( drm_radeon_private_t *dev_priv )
-{
-	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
-	drm_radeon_context_regs_t *ctx = &sarea_priv->context_state;
-	RING_LOCALS;
-	DRM_DEBUG( "    %s\n", __FUNCTION__ );
-
-	BEGIN_RING( 4 );
-
-	OUT_RING( CP_PACKET0( RADEON_RB3D_STENCILREFMASK, 2 ) );
-	OUT_RING( ctx->rb3d_stencilrefmask );
-	OUT_RING( ctx->rb3d_ropcntl );
-	OUT_RING( ctx->rb3d_planemask );
-
-	ADVANCE_RING();
-}
-
-static inline void radeon_emit_viewport( drm_radeon_private_t *dev_priv )
-{
-	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
-	drm_radeon_context_regs_t *ctx = &sarea_priv->context_state;
-	RING_LOCALS;
-	DRM_DEBUG( "    %s\n", __FUNCTION__ );
-
-	BEGIN_RING( 7 );
-
-	OUT_RING( CP_PACKET0( RADEON_SE_VPORT_XSCALE, 5 ) );
-	OUT_RING( ctx->se_vport_xscale );
-	OUT_RING( ctx->se_vport_xoffset );
-	OUT_RING( ctx->se_vport_yscale );
-	OUT_RING( ctx->se_vport_yoffset );
-	OUT_RING( ctx->se_vport_zscale );
-	OUT_RING( ctx->se_vport_zoffset );
-
-	ADVANCE_RING();
-}
-
-static inline void radeon_emit_setup( drm_radeon_private_t *dev_priv )
-{
-	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
-	drm_radeon_context_regs_t *ctx = &sarea_priv->context_state;
-	RING_LOCALS;
-	DRM_DEBUG( "    %s\n", __FUNCTION__ );
-
-	BEGIN_RING( 4 );
-
-	OUT_RING( CP_PACKET0( RADEON_SE_CNTL, 0 ) );
-	OUT_RING( ctx->se_cntl );
-	OUT_RING( CP_PACKET0( RADEON_SE_CNTL_STATUS, 0 ) );
-	OUT_RING( ctx->se_cntl_status );
-
-	ADVANCE_RING();
-}
-
-static inline void radeon_emit_tcl( drm_radeon_private_t *dev_priv )
-{
-#ifdef TCL_ENABLE
-	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
-	drm_radeon_context_regs_t *ctx = &sarea_priv->context_state;
-	RING_LOCALS;
-	DRM_DEBUG( "    %s\n", __FUNCTION__ );
-
-	BEGIN_RING( 29 );
-
-	OUT_RING( CP_PACKET0( RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED, 27 ) );
-	OUT_RING( ctx->se_tcl_material_emmissive.red );
-	OUT_RING( ctx->se_tcl_material_emmissive.green );
-	OUT_RING( ctx->se_tcl_material_emmissive.blue );
-	OUT_RING( ctx->se_tcl_material_emmissive.alpha );
-	OUT_RING( ctx->se_tcl_material_ambient.red );
-	OUT_RING( ctx->se_tcl_material_ambient.green );
-	OUT_RING( ctx->se_tcl_material_ambient.blue );
-	OUT_RING( ctx->se_tcl_material_ambient.alpha );
-	OUT_RING( ctx->se_tcl_material_diffuse.red );
-	OUT_RING( ctx->se_tcl_material_diffuse.green );
-	OUT_RING( ctx->se_tcl_material_diffuse.blue );
-	OUT_RING( ctx->se_tcl_material_diffuse.alpha );
-	OUT_RING( ctx->se_tcl_material_specular.red );
-	OUT_RING( ctx->se_tcl_material_specular.green );
-	OUT_RING( ctx->se_tcl_material_specular.blue );
-	OUT_RING( ctx->se_tcl_material_specular.alpha );
-	OUT_RING( ctx->se_tcl_shininess );
-	OUT_RING( ctx->se_tcl_output_vtx_fmt );
-	OUT_RING( ctx->se_tcl_output_vtx_sel );
-	OUT_RING( ctx->se_tcl_matrix_select_0 );
-	OUT_RING( ctx->se_tcl_matrix_select_1 );
-	OUT_RING( ctx->se_tcl_ucp_vert_blend_ctl );
-	OUT_RING( ctx->se_tcl_texture_proc_ctl );
-	OUT_RING( ctx->se_tcl_light_model_ctl );
-	for ( i = 0 ; i < 4 ; i++ ) {
-		OUT_RING( ctx->se_tcl_per_light_ctl[i] );
-	}
-
 	ADVANCE_RING();
-#else
-	DRM_ERROR( "TCL not enabled!\n" );
-#endif
 }
 
-static inline void radeon_emit_misc( drm_radeon_private_t *dev_priv )
-{
-	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
-	drm_radeon_context_regs_t *ctx = &sarea_priv->context_state;
-	RING_LOCALS;
-	DRM_DEBUG( "    %s\n", __FUNCTION__ );
-
-	BEGIN_RING( 2 );
-
-	OUT_RING( CP_PACKET0( RADEON_RE_MISC, 0 ) );
-	OUT_RING( ctx->re_misc );
-
-	ADVANCE_RING();
-}
-
-static inline void radeon_emit_tex0( drm_radeon_private_t *dev_priv )
-{
-	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
-	drm_radeon_texture_regs_t *tex = &sarea_priv->tex_state[0];
-	RING_LOCALS;
-	DRM_DEBUG( "    %s: offset=0x%x\n", __FUNCTION__, tex->pp_txoffset );
-
-	BEGIN_RING( 9 );
-
-	OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_0, 5 ) );
-	OUT_RING( tex->pp_txfilter );
-	OUT_RING( tex->pp_txformat );
-	OUT_RING( tex->pp_txoffset );
-	OUT_RING( tex->pp_txcblend );
-	OUT_RING( tex->pp_txablend );
-	OUT_RING( tex->pp_tfactor );
-
-	OUT_RING( CP_PACKET0( RADEON_PP_BORDER_COLOR_0, 0 ) );
-	OUT_RING( tex->pp_border_color );
-
-	ADVANCE_RING();
-}
-
-static inline void radeon_emit_tex1( drm_radeon_private_t *dev_priv )
-{
-	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
-	drm_radeon_texture_regs_t *tex = &sarea_priv->tex_state[1];
-	RING_LOCALS;
-	DRM_DEBUG( "    %s: offset=0x%x\n", __FUNCTION__, tex->pp_txoffset );
-
-	BEGIN_RING( 9 );
-
-	OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_1, 5 ) );
-	OUT_RING( tex->pp_txfilter );
-	OUT_RING( tex->pp_txformat );
-	OUT_RING( tex->pp_txoffset );
-	OUT_RING( tex->pp_txcblend );
-	OUT_RING( tex->pp_txablend );
-	OUT_RING( tex->pp_tfactor );
-
-	OUT_RING( CP_PACKET0( RADEON_PP_BORDER_COLOR_1, 0 ) );
-	OUT_RING( tex->pp_border_color );
-
-	ADVANCE_RING();
-}
-
-static inline void radeon_emit_tex2( drm_radeon_private_t *dev_priv )
+/* Emit 1.1 state
+ */
+static void radeon_emit_state( drm_radeon_private_t *dev_priv,
+			       drm_radeon_context_regs_t *ctx,
+			       drm_radeon_texture_regs_t *tex,
+			       unsigned int dirty )
 {
-	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
-	drm_radeon_texture_regs_t *tex = &sarea_priv->tex_state[2];
 	RING_LOCALS;
-	DRM_DEBUG( "    %s\n", __FUNCTION__ );
-
-	BEGIN_RING( 9 );
-
-	OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_2, 5 ) );
-	OUT_RING( tex->pp_txfilter );
-	OUT_RING( tex->pp_txformat );
-	OUT_RING( tex->pp_txoffset );
-	OUT_RING( tex->pp_txcblend );
-	OUT_RING( tex->pp_txablend );
-	OUT_RING( tex->pp_tfactor );
-
-	OUT_RING( CP_PACKET0( RADEON_PP_BORDER_COLOR_2, 0 ) );
-	OUT_RING( tex->pp_border_color );
-
-	ADVANCE_RING();
-}
-
-static inline void radeon_emit_state( drm_radeon_private_t *dev_priv )
-{
-	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
-	unsigned int dirty = sarea_priv->dirty;
-
-	DRM_DEBUG( "%s: dirty=0x%08x\n", __FUNCTION__, dirty );
+	DRM_DEBUG( "dirty=0x%08x\n", dirty );
 
 	if ( dirty & RADEON_UPLOAD_CONTEXT ) {
-		radeon_emit_context( dev_priv );
-		sarea_priv->dirty &= ~RADEON_UPLOAD_CONTEXT;
+		BEGIN_RING( 14 );
+		OUT_RING( CP_PACKET0( RADEON_PP_MISC, 6 ) );
+		OUT_RING( ctx->pp_misc );
+		OUT_RING( ctx->pp_fog_color );
+		OUT_RING( ctx->re_solid_color );
+		OUT_RING( ctx->rb3d_blendcntl );
+		OUT_RING( ctx->rb3d_depthoffset );
+		OUT_RING( ctx->rb3d_depthpitch );
+		OUT_RING( ctx->rb3d_zstencilcntl );
+		OUT_RING( CP_PACKET0( RADEON_PP_CNTL, 2 ) );
+		OUT_RING( ctx->pp_cntl );
+		OUT_RING( ctx->rb3d_cntl );
+		OUT_RING( ctx->rb3d_coloroffset );
+		OUT_RING( CP_PACKET0( RADEON_RB3D_COLORPITCH, 0 ) );
+		OUT_RING( ctx->rb3d_colorpitch );
+		ADVANCE_RING();
 	}
 
 	if ( dirty & RADEON_UPLOAD_VERTFMT ) {
-		radeon_emit_vertfmt( dev_priv );
-		sarea_priv->dirty &= ~RADEON_UPLOAD_VERTFMT;
+		BEGIN_RING( 2 );
+		OUT_RING( CP_PACKET0( RADEON_SE_COORD_FMT, 0 ) );
+		OUT_RING( ctx->se_coord_fmt );
+		ADVANCE_RING();
 	}
 
 	if ( dirty & RADEON_UPLOAD_LINE ) {
-		radeon_emit_line( dev_priv );
-		sarea_priv->dirty &= ~RADEON_UPLOAD_LINE;
+		BEGIN_RING( 5 );
+		OUT_RING( CP_PACKET0( RADEON_RE_LINE_PATTERN, 1 ) );
+		OUT_RING( ctx->re_line_pattern );
+		OUT_RING( ctx->re_line_state );
+		OUT_RING( CP_PACKET0( RADEON_SE_LINE_WIDTH, 0 ) );
+		OUT_RING( ctx->se_line_width );
+		ADVANCE_RING();
 	}
 
 	if ( dirty & RADEON_UPLOAD_BUMPMAP ) {
-		radeon_emit_bumpmap( dev_priv );
-		sarea_priv->dirty &= ~RADEON_UPLOAD_BUMPMAP;
+		BEGIN_RING( 5 );
+		OUT_RING( CP_PACKET0( RADEON_PP_LUM_MATRIX, 0 ) );
+		OUT_RING( ctx->pp_lum_matrix );
+		OUT_RING( CP_PACKET0( RADEON_PP_ROT_MATRIX_0, 1 ) );
+		OUT_RING( ctx->pp_rot_matrix_0 );
+		OUT_RING( ctx->pp_rot_matrix_1 );
+		ADVANCE_RING();
 	}
 
 	if ( dirty & RADEON_UPLOAD_MASKS ) {
-		radeon_emit_masks( dev_priv );
-		sarea_priv->dirty &= ~RADEON_UPLOAD_MASKS;
+		BEGIN_RING( 4 );
+		OUT_RING( CP_PACKET0( RADEON_RB3D_STENCILREFMASK, 2 ) );
+		OUT_RING( ctx->rb3d_stencilrefmask );
+		OUT_RING( ctx->rb3d_ropcntl );
+		OUT_RING( ctx->rb3d_planemask );
+		ADVANCE_RING();
 	}
 
 	if ( dirty & RADEON_UPLOAD_VIEWPORT ) {
-		radeon_emit_viewport( dev_priv );
-		sarea_priv->dirty &= ~RADEON_UPLOAD_VIEWPORT;
+		BEGIN_RING( 7 );
+		OUT_RING( CP_PACKET0( RADEON_SE_VPORT_XSCALE, 5 ) );
+		OUT_RING( ctx->se_vport_xscale );
+		OUT_RING( ctx->se_vport_xoffset );
+		OUT_RING( ctx->se_vport_yscale );
+		OUT_RING( ctx->se_vport_yoffset );
+		OUT_RING( ctx->se_vport_zscale );
+		OUT_RING( ctx->se_vport_zoffset );
+		ADVANCE_RING();
 	}
 
 	if ( dirty & RADEON_UPLOAD_SETUP ) {
-		radeon_emit_setup( dev_priv );
-		sarea_priv->dirty &= ~RADEON_UPLOAD_SETUP;
-	}
-
-	if ( dirty & RADEON_UPLOAD_TCL ) {
-#ifdef TCL_ENABLE
-		radeon_emit_tcl( dev_priv );
-#endif
-		sarea_priv->dirty &= ~RADEON_UPLOAD_TCL;
+		BEGIN_RING( 4 );
+		OUT_RING( CP_PACKET0( RADEON_SE_CNTL, 0 ) );
+		OUT_RING( ctx->se_cntl );
+		OUT_RING( CP_PACKET0( RADEON_SE_CNTL_STATUS, 0 ) );
+		OUT_RING( ctx->se_cntl_status );
+		ADVANCE_RING();
 	}
 
 	if ( dirty & RADEON_UPLOAD_MISC ) {
-		radeon_emit_misc( dev_priv );
-		sarea_priv->dirty &= ~RADEON_UPLOAD_MISC;
+		BEGIN_RING( 2 );
+		OUT_RING( CP_PACKET0( RADEON_RE_MISC, 0 ) );
+		OUT_RING( ctx->re_misc );
+		ADVANCE_RING();
 	}
 
 	if ( dirty & RADEON_UPLOAD_TEX0 ) {
-		radeon_emit_tex0( dev_priv );
-		sarea_priv->dirty &= ~RADEON_UPLOAD_TEX0;
+		BEGIN_RING( 9 );
+		OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_0, 5 ) );
+		OUT_RING( tex[0].pp_txfilter );
+		OUT_RING( tex[0].pp_txformat );
+		OUT_RING( tex[0].pp_txoffset );
+		OUT_RING( tex[0].pp_txcblend );
+		OUT_RING( tex[0].pp_txablend );
+		OUT_RING( tex[0].pp_tfactor );
+		OUT_RING( CP_PACKET0( RADEON_PP_BORDER_COLOR_0, 0 ) );
+		OUT_RING( tex[0].pp_border_color );
+		ADVANCE_RING();
 	}
 
 	if ( dirty & RADEON_UPLOAD_TEX1 ) {
-		radeon_emit_tex1( dev_priv );
-		sarea_priv->dirty &= ~RADEON_UPLOAD_TEX1;
+		BEGIN_RING( 9 );
+		OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_1, 5 ) );
+		OUT_RING( tex[1].pp_txfilter );
+		OUT_RING( tex[1].pp_txformat );
+		OUT_RING( tex[1].pp_txoffset );
+		OUT_RING( tex[1].pp_txcblend );
+		OUT_RING( tex[1].pp_txablend );
+		OUT_RING( tex[1].pp_tfactor );
+		OUT_RING( CP_PACKET0( RADEON_PP_BORDER_COLOR_1, 0 ) );
+		OUT_RING( tex[1].pp_border_color );
+		ADVANCE_RING();
 	}
 
 	if ( dirty & RADEON_UPLOAD_TEX2 ) {
-#if 0
-		radeon_emit_tex2( dev_priv );
-#endif
-		sarea_priv->dirty &= ~RADEON_UPLOAD_TEX2;
+		BEGIN_RING( 9 );
+		OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_2, 5 ) );
+		OUT_RING( tex[2].pp_txfilter );
+		OUT_RING( tex[2].pp_txformat );
+		OUT_RING( tex[2].pp_txoffset );
+		OUT_RING( tex[2].pp_txcblend );
+		OUT_RING( tex[2].pp_txablend );
+		OUT_RING( tex[2].pp_tfactor );
+		OUT_RING( CP_PACKET0( RADEON_PP_BORDER_COLOR_2, 0 ) );
+		OUT_RING( tex[2].pp_border_color );
+		ADVANCE_RING();
 	}
+}
 
-	sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
-			       RADEON_UPLOAD_TEX1IMAGES |
-			       RADEON_UPLOAD_TEX2IMAGES |
-			       RADEON_REQUIRE_QUIESCENCE);
+/* Emit 1.2 state
+ */
+static void radeon_emit_state2( drm_radeon_private_t *dev_priv,
+				drm_radeon_state_t *state )
+{
+	RING_LOCALS;
+
+	if (state->dirty & RADEON_UPLOAD_ZBIAS) {
+		BEGIN_RING( 3 );
+		OUT_RING( CP_PACKET0( RADEON_SE_ZBIAS_FACTOR, 1 ) );
+		OUT_RING( state->context2.se_zbias_factor ); 
+		OUT_RING( state->context2.se_zbias_constant ); 
+		ADVANCE_RING();
+	}
+
+	radeon_emit_state( dev_priv, &state->context, 
+			   state->tex, state->dirty );
 }
 
+/* New (1.3) state mechanism.  3 commands (packet, scalar, vector) in
+ * 1.3 cmdbuffers allow all previous state to be updated as well as
+ * the tcl scalar and vector areas.  
+ */
+static struct { 
+	int start; 
+	int len; 
+	const char *name;
+} packet[RADEON_MAX_STATE_PACKETS] = {
+	{ RADEON_PP_MISC,7,"RADEON_PP_MISC" },
+	{ RADEON_PP_CNTL,3,"RADEON_PP_CNTL" },
+	{ RADEON_RB3D_COLORPITCH,1,"RADEON_RB3D_COLORPITCH" },
+	{ RADEON_RE_LINE_PATTERN,2,"RADEON_RE_LINE_PATTERN" },
+	{ RADEON_SE_LINE_WIDTH,1,"RADEON_SE_LINE_WIDTH" },
+	{ RADEON_PP_LUM_MATRIX,1,"RADEON_PP_LUM_MATRIX" },
+	{ RADEON_PP_ROT_MATRIX_0,2,"RADEON_PP_ROT_MATRIX_0" },
+	{ RADEON_RB3D_STENCILREFMASK,3,"RADEON_RB3D_STENCILREFMASK" },
+	{ RADEON_SE_VPORT_XSCALE,6,"RADEON_SE_VPORT_XSCALE" },
+	{ RADEON_SE_CNTL,2,"RADEON_SE_CNTL" },
+	{ RADEON_SE_CNTL_STATUS,1,"RADEON_SE_CNTL_STATUS" },
+	{ RADEON_RE_MISC,1,"RADEON_RE_MISC" },
+	{ RADEON_PP_TXFILTER_0,6,"RADEON_PP_TXFILTER_0" },
+	{ RADEON_PP_BORDER_COLOR_0,1,"RADEON_PP_BORDER_COLOR_0" },
+	{ RADEON_PP_TXFILTER_1,6,"RADEON_PP_TXFILTER_1" },
+	{ RADEON_PP_BORDER_COLOR_1,1,"RADEON_PP_BORDER_COLOR_1" },
+	{ RADEON_PP_TXFILTER_2,6,"RADEON_PP_TXFILTER_2" },
+	{ RADEON_PP_BORDER_COLOR_2,1,"RADEON_PP_BORDER_COLOR_2" },
+	{ RADEON_SE_ZBIAS_FACTOR,2,"RADEON_SE_ZBIAS_FACTOR" },
+	{ RADEON_SE_TCL_OUTPUT_VTX_FMT,11,"RADEON_SE_TCL_OUTPUT_VTX_FMT" },
+	{ RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED,17,"RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED" },
+	{ R200_PP_TXCBLEND_0, 4, "R200_PP_TXCBLEND_0" },
+	{ R200_PP_TXCBLEND_1, 4, "R200_PP_TXCBLEND_1" },
+	{ R200_PP_TXCBLEND_2, 4, "R200_PP_TXCBLEND_2" },
+	{ R200_PP_TXCBLEND_3, 4, "R200_PP_TXCBLEND_3" },
+	{ R200_PP_TXCBLEND_4, 4, "R200_PP_TXCBLEND_4" },
+	{ R200_PP_TXCBLEND_5, 4, "R200_PP_TXCBLEND_5" },
+	{ R200_PP_TXCBLEND_6, 4, "R200_PP_TXCBLEND_6" },
+	{ R200_PP_TXCBLEND_7, 4, "R200_PP_TXCBLEND_7" },
+	{ R200_SE_TCL_LIGHT_MODEL_CTL_0, 6, "R200_SE_TCL_LIGHT_MODEL_CTL_0" },
+	{ R200_PP_TFACTOR_0, 6, "R200_PP_TFACTOR_0" },
+	{ R200_SE_VTX_FMT_0, 4, "R200_SE_VTX_FMT_0" },
+	{ R200_SE_VAP_CNTL, 1, "R200_SE_VAP_CNTL" },
+	{ R200_SE_TCL_MATRIX_SEL_0, 5, "R200_SE_TCL_MATRIX_SEL_0" },
+	{ R200_SE_TCL_TEX_PROC_CTL_2, 5, "R200_SE_TCL_TEX_PROC_CTL_2" },
+	{ R200_SE_TCL_UCP_VERT_BLEND_CTL, 1, "R200_SE_TCL_UCP_VERT_BLEND_CTL" },
+	{ R200_PP_TXFILTER_0, 6, "R200_PP_TXFILTER_0" },
+	{ R200_PP_TXFILTER_1, 6, "R200_PP_TXFILTER_1" },
+	{ R200_PP_TXFILTER_2, 6, "R200_PP_TXFILTER_2" },
+	{ R200_PP_TXFILTER_3, 6, "R200_PP_TXFILTER_3" },
+	{ R200_PP_TXFILTER_4, 6, "R200_PP_TXFILTER_4" },
+	{ R200_PP_TXFILTER_5, 6, "R200_PP_TXFILTER_5" },
+	{ R200_PP_TXOFFSET_0, 1, "R200_PP_TXOFFSET_0" },
+	{ R200_PP_TXOFFSET_1, 1, "R200_PP_TXOFFSET_1" },
+	{ R200_PP_TXOFFSET_2, 1, "R200_PP_TXOFFSET_2" },
+	{ R200_PP_TXOFFSET_3, 1, "R200_PP_TXOFFSET_3" },
+	{ R200_PP_TXOFFSET_4, 1, "R200_PP_TXOFFSET_4" },
+	{ R200_PP_TXOFFSET_5, 1, "R200_PP_TXOFFSET_5" },
+	{ R200_SE_VTE_CNTL, 1, "R200_SE_VTE_CNTL" },
+	{ R200_SE_TCL_OUTPUT_VTX_COMP_SEL, 1, "R200_SE_TCL_OUTPUT_VTX_COMP_SEL" },
+	{ R200_PP_TAM_DEBUG3, 1, "R200_PP_TAM_DEBUG3" },
+	{ R200_PP_CNTL_X, 1, "R200_PP_CNTL_X" }, 
+	{ R200_RB3D_DEPTHXY_OFFSET, 1, "R200_RB3D_DEPTHXY_OFFSET" }, 
+	{ R200_RE_AUX_SCISSOR_CNTL, 1, "R200_RE_AUX_SCISSOR_CNTL" }, 
+	{ R200_RE_SCISSOR_TL_0, 2, "R200_RE_SCISSOR_TL_0" }, 
+	{ R200_RE_SCISSOR_TL_1, 2, "R200_RE_SCISSOR_TL_1" }, 
+	{ R200_RE_SCISSOR_TL_2, 2, "R200_RE_SCISSOR_TL_2" }, 
+	{ R200_SE_VAP_CNTL_STATUS, 1, "R200_SE_VAP_CNTL_STATUS" }, 
+	{ R200_SE_VTX_STATE_CNTL, 1, "R200_SE_VTX_STATE_CNTL" }, 
+	{ R200_RE_POINTSIZE, 1, "R200_RE_POINTSIZE" }, 
+	{ R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0, 4, "R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0" },
+	{ R200_PP_CUBIC_FACES_0, 1, "R200_PP_CUBIC_FACES_0" }, /* 61 */
+	{ R200_PP_CUBIC_OFFSET_F1_0, 5, "R200_PP_CUBIC_OFFSET_F1_0" }, /* 62 */
+	{ R200_PP_CUBIC_FACES_1, 1, "R200_PP_CUBIC_FACES_1" },
+	{ R200_PP_CUBIC_OFFSET_F1_1, 5, "R200_PP_CUBIC_OFFSET_F1_1" },
+	{ R200_PP_CUBIC_FACES_2, 1, "R200_PP_CUBIC_FACES_2" },
+	{ R200_PP_CUBIC_OFFSET_F1_2, 5, "R200_PP_CUBIC_OFFSET_F1_2" },
+	{ R200_PP_CUBIC_FACES_3, 1, "R200_PP_CUBIC_FACES_3" },
+	{ R200_PP_CUBIC_OFFSET_F1_3, 5, "R200_PP_CUBIC_OFFSET_F1_3" },
+	{ R200_PP_CUBIC_FACES_4, 1, "R200_PP_CUBIC_FACES_4" },
+	{ R200_PP_CUBIC_OFFSET_F1_4, 5, "R200_PP_CUBIC_OFFSET_F1_4" },
+	{ R200_PP_CUBIC_FACES_5, 1, "R200_PP_CUBIC_FACES_5" },
+	{ R200_PP_CUBIC_OFFSET_F1_5, 5, "R200_PP_CUBIC_OFFSET_F1_5" },
+};
+
+
 
-#if RADEON_PERFORMANCE_BOXES
 /* ================================================================
  * Performance monitoring functions
  */
@@ -409,10 +304,12 @@
 			      int x, int y, int w, int h,
 			      int r, int g, int b )
 {
-	u32 pitch, offset;
 	u32 color;
 	RING_LOCALS;
 
+	x += dev_priv->sarea_priv->boxes[0].x1;
+	y += dev_priv->sarea_priv->boxes[0].y1;
+
 	switch ( dev_priv->color_fmt ) {
 	case RADEON_COLOR_FORMAT_RGB565:
 		color = (((r & 0xf8) << 8) |
@@ -425,8 +322,11 @@
 		break;
 	}
 
-	offset = dev_priv->back_offset;
-	pitch = dev_priv->back_pitch >> 3;
+	BEGIN_RING( 4 );
+	RADEON_WAIT_UNTIL_3D_IDLE();		
+	OUT_RING( CP_PACKET0( RADEON_DP_WRITE_MASK, 0 ) );
+	OUT_RING( 0xffffffff );
+	ADVANCE_RING();
 
 	BEGIN_RING( 6 );
 
@@ -438,7 +338,12 @@
 		  RADEON_ROP3_P |
 		  RADEON_GMC_CLR_CMP_CNTL_DIS );
 
-	OUT_RING( (pitch << 22) | (offset >> 5) );
+ 	if ( dev_priv->page_flipping && dev_priv->current_page == 1 ) { 
+		OUT_RING( dev_priv->front_pitch_offset );
+ 	} else {	 
+		OUT_RING( dev_priv->back_pitch_offset );
+ 	} 
+
 	OUT_RING( color );
 
 	OUT_RING( (x << 16) | y );
@@ -449,53 +354,77 @@
 
 static void radeon_cp_performance_boxes( drm_radeon_private_t *dev_priv )
 {
-	if ( atomic_read( &dev_priv->idle_count ) == 0 ) {
-		radeon_clear_box( dev_priv, 64, 4, 8, 8, 0, 255, 0 );
-	} else {
-		atomic_set( &dev_priv->idle_count, 0 );
+	/* Collapse various things into a wait flag -- trying to
+	 * guess if userspase slept -- better just to have them tell us.
+	 */
+	if (dev_priv->stats.last_frame_reads > 1 ||
+	    dev_priv->stats.last_clear_reads > dev_priv->stats.clears) {
+		dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
 	}
-}
 
-#endif
+	if (dev_priv->stats.freelist_loops) {
+		dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
+	}
+
+	/* Purple box for page flipping
+	 */
+	if ( dev_priv->stats.boxes & RADEON_BOX_FLIP ) 
+		radeon_clear_box( dev_priv, 4, 4, 8, 8, 255, 0, 255 );
 
+	/* Red box if we have to wait for idle at any point
+	 */
+	if ( dev_priv->stats.boxes & RADEON_BOX_WAIT_IDLE ) 
+		radeon_clear_box( dev_priv, 16, 4, 8, 8, 255, 0, 0 );
 
+	/* Blue box: lost context?
+	 */
+
+	/* Yellow box for texture swaps
+	 */
+	if ( dev_priv->stats.boxes & RADEON_BOX_TEXTURE_LOAD ) 
+		radeon_clear_box( dev_priv, 40, 4, 8, 8, 255, 255, 0 );
+
+	/* Green box if hardware never idles (as far as we can tell)
+	 */
+	if ( !(dev_priv->stats.boxes & RADEON_BOX_DMA_IDLE) ) 
+		radeon_clear_box( dev_priv, 64, 4, 8, 8, 0, 255, 0 );
+
+
+	/* Draw bars indicating number of buffers allocated 
+	 * (not a great measure, easily confused)
+	 */
+	if (dev_priv->stats.requested_bufs) {
+		if (dev_priv->stats.requested_bufs > 100)
+			dev_priv->stats.requested_bufs = 100;
+
+		radeon_clear_box( dev_priv, 4, 16,  
+				  dev_priv->stats.requested_bufs, 4,
+				  196, 128, 128 );
+	}
+
+	memset( &dev_priv->stats, 0, sizeof(dev_priv->stats) );
+
+}
 /* ================================================================
  * CP command dispatch functions
  */
 
-static void radeon_print_dirty( const char *msg, unsigned int flags )
-{
-	DRM_DEBUG( "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
-		   msg,
-		   flags,
-		   (flags & RADEON_UPLOAD_CONTEXT)     ? "context, " : "",
-		   (flags & RADEON_UPLOAD_VERTFMT)     ? "vertfmt, " : "",
-		   (flags & RADEON_UPLOAD_LINE)        ? "line, " : "",
-		   (flags & RADEON_UPLOAD_BUMPMAP)     ? "bumpmap, " : "",
-		   (flags & RADEON_UPLOAD_MASKS)       ? "masks, " : "",
-		   (flags & RADEON_UPLOAD_VIEWPORT)    ? "viewport, " : "",
-		   (flags & RADEON_UPLOAD_SETUP)       ? "setup, " : "",
-		   (flags & RADEON_UPLOAD_TCL)         ? "tcl, " : "",
-		   (flags & RADEON_UPLOAD_MISC)        ? "misc, " : "",
-		   (flags & RADEON_UPLOAD_TEX0)        ? "tex0, " : "",
-		   (flags & RADEON_UPLOAD_TEX1)        ? "tex1, " : "",
-		   (flags & RADEON_UPLOAD_TEX2)        ? "tex2, " : "",
-		   (flags & RADEON_UPLOAD_CLIPRECTS)   ? "cliprects, " : "",
-		   (flags & RADEON_REQUIRE_QUIESCENCE) ? "quiescence, " : "" );
-}
-
 static void radeon_cp_dispatch_clear( drm_device_t *dev,
 				      drm_radeon_clear_t *clear,
 				      drm_radeon_clear_rect_t *depth_boxes )
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	drm_radeon_depth_clear_t *depth_clear = &dev_priv->depth_clear;
 	int nbox = sarea_priv->nbox;
 	drm_clip_rect_t *pbox = sarea_priv->boxes;
 	unsigned int flags = clear->flags;
+	u32 rb3d_cntl = 0, rb3d_stencilrefmask= 0;
 	int i;
 	RING_LOCALS;
-	DRM_DEBUG( "%s\n", __FUNCTION__ );
+	DRM_DEBUG( "flags = 0x%x\n", flags );
+
+	dev_priv->stats.clears++;
 
 	if ( dev_priv->page_flipping && dev_priv->current_page == 1 ) {
 		unsigned int tmp = flags;
@@ -505,127 +434,277 @@
 		if ( tmp & RADEON_BACK )  flags |= RADEON_FRONT;
 	}
 
-	for ( i = 0 ; i < nbox ; i++ ) {
-		int x = pbox[i].x1;
-		int y = pbox[i].y1;
-		int w = pbox[i].x2 - x;
-		int h = pbox[i].y2 - y;
+	if ( flags & (RADEON_FRONT | RADEON_BACK) ) {
 
-		DRM_DEBUG( "dispatch clear %d,%d-%d,%d flags 0x%x\n",
-			   x, y, w, h, flags );
+		BEGIN_RING( 4 );
 
-		if ( flags & (RADEON_FRONT | RADEON_BACK) ) {
-			BEGIN_RING( 4 );
+		/* Ensure the 3D stream is idle before doing a
+		 * 2D fill to clear the front or back buffer.
+		 */
+		RADEON_WAIT_UNTIL_3D_IDLE();
+		
+		OUT_RING( CP_PACKET0( RADEON_DP_WRITE_MASK, 0 ) );
+		OUT_RING( clear->color_mask );
 
-			/* Ensure the 3D stream is idle before doing a
-			 * 2D fill to clear the front or back buffer.
-			 */
-			RADEON_WAIT_UNTIL_3D_IDLE();
+		ADVANCE_RING();
 
-			OUT_RING( CP_PACKET0( RADEON_DP_WRITE_MASK, 0 ) );
-			OUT_RING( clear->color_mask );
+		/* Make sure we restore the 3D state next time.
+		 */
+		dev_priv->sarea_priv->ctx_owner = 0;
 
-			ADVANCE_RING();
+		for ( i = 0 ; i < nbox ; i++ ) {
+			int x = pbox[i].x1;
+			int y = pbox[i].y1;
+			int w = pbox[i].x2 - x;
+			int h = pbox[i].y2 - y;
+
+			DRM_DEBUG( "dispatch clear %d,%d-%d,%d flags 0x%x\n",
+				   x, y, w, h, flags );
+
+			if ( flags & RADEON_FRONT ) {
+				BEGIN_RING( 6 );
+				
+				OUT_RING( CP_PACKET3( RADEON_CNTL_PAINT_MULTI, 4 ) );
+				OUT_RING( RADEON_GMC_DST_PITCH_OFFSET_CNTL |
+					  RADEON_GMC_BRUSH_SOLID_COLOR |
+					  (dev_priv->color_fmt << 8) |
+					  RADEON_GMC_SRC_DATATYPE_COLOR |
+					  RADEON_ROP3_P |
+					  RADEON_GMC_CLR_CMP_CNTL_DIS );
+
+				OUT_RING( dev_priv->front_pitch_offset );
+				OUT_RING( clear->clear_color );
+				
+				OUT_RING( (x << 16) | y );
+				OUT_RING( (w << 16) | h );
+				
+				ADVANCE_RING();
+			}
+			
+			if ( flags & RADEON_BACK ) {
+				BEGIN_RING( 6 );
+				
+				OUT_RING( CP_PACKET3( RADEON_CNTL_PAINT_MULTI, 4 ) );
+				OUT_RING( RADEON_GMC_DST_PITCH_OFFSET_CNTL |
+					  RADEON_GMC_BRUSH_SOLID_COLOR |
+					  (dev_priv->color_fmt << 8) |
+					  RADEON_GMC_SRC_DATATYPE_COLOR |
+					  RADEON_ROP3_P |
+					  RADEON_GMC_CLR_CMP_CNTL_DIS );
+				
+				OUT_RING( dev_priv->back_pitch_offset );
+				OUT_RING( clear->clear_color );
 
-			/* Make sure we restore the 3D state next time.
-			 */
-			dev_priv->sarea_priv->dirty |= (RADEON_UPLOAD_CONTEXT |
-							RADEON_UPLOAD_MASKS);
+				OUT_RING( (x << 16) | y );
+				OUT_RING( (w << 16) | h );
+
+				ADVANCE_RING();
+			}
 		}
+	}
 
-		if ( flags & RADEON_FRONT ) {
-			BEGIN_RING( 6 );
+	/* We have to clear the depth and/or stencil buffers by
+	 * rendering a quad into just those buffers.  Thus, we have to
+	 * make sure the 3D engine is configured correctly.
+	 */
+	if ( dev_priv->is_r200 &&
+	     (flags & (RADEON_DEPTH | RADEON_STENCIL)) ) {
 
-			OUT_RING( CP_PACKET3( RADEON_CNTL_PAINT_MULTI, 4 ) );
-			OUT_RING( RADEON_GMC_DST_PITCH_OFFSET_CNTL |
-				  RADEON_GMC_BRUSH_SOLID_COLOR |
-				  (dev_priv->color_fmt << 8) |
-				  RADEON_GMC_SRC_DATATYPE_COLOR |
-				  RADEON_ROP3_P |
-				  RADEON_GMC_CLR_CMP_CNTL_DIS );
+		int tempPP_CNTL;
+		int tempRE_CNTL;
+		int tempRB3D_CNTL;
+		int tempRB3D_ZSTENCILCNTL;
+		int tempRB3D_STENCILREFMASK;
+		int tempRB3D_PLANEMASK;
+		int tempSE_CNTL;
+		int tempSE_VTE_CNTL;
+		int tempSE_VTX_FMT_0;
+		int tempSE_VTX_FMT_1;
+		int tempSE_VAP_CNTL;
+		int tempRE_AUX_SCISSOR_CNTL;
 
-			OUT_RING( dev_priv->front_pitch_offset );
-			OUT_RING( clear->clear_color );
+		tempPP_CNTL = 0;
+		tempRE_CNTL = 0;
 
-			OUT_RING( (x << 16) | y );
-			OUT_RING( (w << 16) | h );
+		tempRB3D_CNTL = depth_clear->rb3d_cntl;
+		tempRB3D_CNTL &= ~(1<<15); /* unset radeon magic flag */
 
-			ADVANCE_RING();
+		tempRB3D_ZSTENCILCNTL = depth_clear->rb3d_zstencilcntl;
+		tempRB3D_STENCILREFMASK = 0x0;
+
+		tempSE_CNTL = depth_clear->se_cntl;
+
+
+
+		/* Disable TCL */
+
+		tempSE_VAP_CNTL = (/* SE_VAP_CNTL__FORCE_W_TO_ONE_MASK |  */
+				   (0x9 << SE_VAP_CNTL__VF_MAX_VTX_NUM__SHIFT));
+
+		tempRB3D_PLANEMASK = 0x0;
+
+		tempRE_AUX_SCISSOR_CNTL = 0x0;
+
+		tempSE_VTE_CNTL =
+			SE_VTE_CNTL__VTX_XY_FMT_MASK |
+			SE_VTE_CNTL__VTX_Z_FMT_MASK;
+
+		/* Vertex format (X, Y, Z, W)*/
+		tempSE_VTX_FMT_0 =
+			SE_VTX_FMT_0__VTX_Z0_PRESENT_MASK |
+			SE_VTX_FMT_0__VTX_W0_PRESENT_MASK;
+		tempSE_VTX_FMT_1 = 0x0;
+
+
+		/* 
+		 * Depth buffer specific enables 
+		 */
+		if (flags & RADEON_DEPTH) {
+			/* Enable depth buffer */
+			tempRB3D_CNTL |= RADEON_Z_ENABLE;
+		} else {
+			/* Disable depth buffer */
+			tempRB3D_CNTL &= ~RADEON_Z_ENABLE;
 		}
 
-		if ( flags & RADEON_BACK ) {
-			BEGIN_RING( 6 );
+		/* 
+		 * Stencil buffer specific enables
+		 */
+		if ( flags & RADEON_STENCIL ) {
+			tempRB3D_CNTL |=  RADEON_STENCIL_ENABLE;
+			tempRB3D_STENCILREFMASK = clear->depth_mask; 
+		} else {
+			tempRB3D_CNTL &= ~RADEON_STENCIL_ENABLE;
+			tempRB3D_STENCILREFMASK = 0x00000000;
+		}
 
-			OUT_RING( CP_PACKET3( RADEON_CNTL_PAINT_MULTI, 4 ) );
-			OUT_RING( RADEON_GMC_DST_PITCH_OFFSET_CNTL |
-				  RADEON_GMC_BRUSH_SOLID_COLOR |
-				  (dev_priv->color_fmt << 8) |
-				  RADEON_GMC_SRC_DATATYPE_COLOR |
-				  RADEON_ROP3_P |
-				  RADEON_GMC_CLR_CMP_CNTL_DIS );
+		BEGIN_RING( 26 );
+		RADEON_WAIT_UNTIL_2D_IDLE();
 
-			OUT_RING( dev_priv->back_pitch_offset );
-			OUT_RING( clear->clear_color );
+		OUT_RING_REG( RADEON_PP_CNTL, tempPP_CNTL );
+		OUT_RING_REG( R200_RE_CNTL, tempRE_CNTL );
+		OUT_RING_REG( RADEON_RB3D_CNTL, tempRB3D_CNTL );
+		OUT_RING_REG( RADEON_RB3D_ZSTENCILCNTL,
+			      tempRB3D_ZSTENCILCNTL );
+		OUT_RING_REG( RADEON_RB3D_STENCILREFMASK, 
+			      tempRB3D_STENCILREFMASK );
+		OUT_RING_REG( RADEON_RB3D_PLANEMASK, tempRB3D_PLANEMASK );
+		OUT_RING_REG( RADEON_SE_CNTL, tempSE_CNTL );
+		OUT_RING_REG( R200_SE_VTE_CNTL, tempSE_VTE_CNTL );
+		OUT_RING_REG( R200_SE_VTX_FMT_0, tempSE_VTX_FMT_0 );
+		OUT_RING_REG( R200_SE_VTX_FMT_1, tempSE_VTX_FMT_1 );
+		OUT_RING_REG( R200_SE_VAP_CNTL, tempSE_VAP_CNTL );
+		OUT_RING_REG( R200_RE_AUX_SCISSOR_CNTL, 
+			      tempRE_AUX_SCISSOR_CNTL );
+		ADVANCE_RING();
 
-			OUT_RING( (x << 16) | y );
-			OUT_RING( (w << 16) | h );
+		/* Make sure we restore the 3D state next time.
+		 */
+		dev_priv->sarea_priv->ctx_owner = 0;
 
-			ADVANCE_RING();
+		for ( i = 0 ; i < nbox ; i++ ) {
+			
+			/* Funny that this should be required -- 
+			 *  sets top-left?
+			 */
+			radeon_emit_clip_rect( dev_priv,
+					       &sarea_priv->boxes[i] );
 
+			BEGIN_RING( 14 );
+			OUT_RING( CP_PACKET3( R200_3D_DRAW_IMMD_2, 12 ) );
+			OUT_RING( (RADEON_PRIM_TYPE_RECT_LIST |
+				   RADEON_PRIM_WALK_RING |
+				   (3 << RADEON_NUM_VERTICES_SHIFT)) );
+			OUT_RING( depth_boxes[i].ui[CLEAR_X1] );
+			OUT_RING( depth_boxes[i].ui[CLEAR_Y1] );
+			OUT_RING( depth_boxes[i].ui[CLEAR_DEPTH] );
+			OUT_RING( 0x3f800000 );
+			OUT_RING( depth_boxes[i].ui[CLEAR_X1] );
+			OUT_RING( depth_boxes[i].ui[CLEAR_Y2] );
+			OUT_RING( depth_boxes[i].ui[CLEAR_DEPTH] );
+			OUT_RING( 0x3f800000 );
+			OUT_RING( depth_boxes[i].ui[CLEAR_X2] );
+			OUT_RING( depth_boxes[i].ui[CLEAR_Y2] );
+			OUT_RING( depth_boxes[i].ui[CLEAR_DEPTH] );
+			OUT_RING( 0x3f800000 );
+			ADVANCE_RING();
 		}
+	} 
+	else if ( (flags & (RADEON_DEPTH | RADEON_STENCIL)) ) {
+
+		rb3d_cntl = depth_clear->rb3d_cntl;
 
 		if ( flags & RADEON_DEPTH ) {
-			drm_radeon_depth_clear_t *depth_clear =
-			   &dev_priv->depth_clear;
+			rb3d_cntl |=  RADEON_Z_ENABLE;
+		} else {
+			rb3d_cntl &= ~RADEON_Z_ENABLE;
+		}
 
-			if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) {
-				radeon_emit_state( dev_priv );
-			}
+		if ( flags & RADEON_STENCIL ) {
+			rb3d_cntl |=  RADEON_STENCIL_ENABLE;
+			rb3d_stencilrefmask = clear->depth_mask; /* misnamed field */
+		} else {
+			rb3d_cntl &= ~RADEON_STENCIL_ENABLE;
+			rb3d_stencilrefmask = 0x00000000;
+		}
 
-			/* FIXME: Render a rectangle to clear the depth
-			 * buffer.  So much for those "fast Z clears"...
-			 */
-			BEGIN_RING( 23 );
+		BEGIN_RING( 13 );
+		RADEON_WAIT_UNTIL_2D_IDLE();
+
+		OUT_RING( CP_PACKET0( RADEON_PP_CNTL, 1 ) );
+		OUT_RING( 0x00000000 );
+		OUT_RING( rb3d_cntl );
+		
+		OUT_RING_REG( RADEON_RB3D_ZSTENCILCNTL,
+			      depth_clear->rb3d_zstencilcntl );
+		OUT_RING_REG( RADEON_RB3D_STENCILREFMASK,
+			      rb3d_stencilrefmask );
+		OUT_RING_REG( RADEON_RB3D_PLANEMASK,
+			      0x00000000 );
+		OUT_RING_REG( RADEON_SE_CNTL,
+			      depth_clear->se_cntl );
+		ADVANCE_RING();
+
+		/* Make sure we restore the 3D state next time.
+		 */
+		dev_priv->sarea_priv->ctx_owner = 0;
 
-			RADEON_WAIT_UNTIL_2D_IDLE();
+		for ( i = 0 ; i < nbox ; i++ ) {
+			
+			/* Funny that this should be required -- 
+			 *  sets top-left?
+			 */
+			radeon_emit_clip_rect( dev_priv,
+					       &sarea_priv->boxes[i] );
 
-			OUT_RING( CP_PACKET0( RADEON_PP_CNTL, 1 ) );
-			OUT_RING( 0x00000000 );
-			OUT_RING( depth_clear->rb3d_cntl );
-			OUT_RING( CP_PACKET0( RADEON_RB3D_ZSTENCILCNTL, 0 ) );
-			OUT_RING( depth_clear->rb3d_zstencilcntl );
-			OUT_RING( CP_PACKET0( RADEON_RB3D_PLANEMASK, 0 ) );
-			OUT_RING( 0x00000000 );
-			OUT_RING( CP_PACKET0( RADEON_SE_CNTL, 0 ) );
-			OUT_RING( depth_clear->se_cntl );
+			BEGIN_RING( 15 );
 
-			OUT_RING( CP_PACKET3( RADEON_3D_DRAW_IMMD, 10 ) );
-			OUT_RING( RADEON_VTX_Z_PRESENT );
+			OUT_RING( CP_PACKET3( RADEON_3D_DRAW_IMMD, 13 ) );
+			OUT_RING( RADEON_VTX_Z_PRESENT |
+				  RADEON_VTX_PKCOLOR_PRESENT);
 			OUT_RING( (RADEON_PRIM_TYPE_RECT_LIST |
 				   RADEON_PRIM_WALK_RING |
 				   RADEON_MAOS_ENABLE |
 				   RADEON_VTX_FMT_RADEON_MODE |
 				   (3 << RADEON_NUM_VERTICES_SHIFT)) );
 
+
 			OUT_RING( depth_boxes[i].ui[CLEAR_X1] );
 			OUT_RING( depth_boxes[i].ui[CLEAR_Y1] );
 			OUT_RING( depth_boxes[i].ui[CLEAR_DEPTH] );
+			OUT_RING( 0x0 );
 
 			OUT_RING( depth_boxes[i].ui[CLEAR_X1] );
 			OUT_RING( depth_boxes[i].ui[CLEAR_Y2] );
 			OUT_RING( depth_boxes[i].ui[CLEAR_DEPTH] );
+			OUT_RING( 0x0 );
 
 			OUT_RING( depth_boxes[i].ui[CLEAR_X2] );
 			OUT_RING( depth_boxes[i].ui[CLEAR_Y2] );
 			OUT_RING( depth_boxes[i].ui[CLEAR_DEPTH] );
+			OUT_RING( 0x0 );
 
 			ADVANCE_RING();
-
-			/* Make sure we restore the 3D state next time.
-			 */
-			dev_priv->sarea_priv->dirty |= (RADEON_UPLOAD_CONTEXT |
-							RADEON_UPLOAD_SETUP |
-							RADEON_UPLOAD_MASKS);
 		}
 	}
 
@@ -651,13 +730,13 @@
 	drm_clip_rect_t *pbox = sarea_priv->boxes;
 	int i;
 	RING_LOCALS;
-	DRM_DEBUG( "%s\n", __FUNCTION__ );
+	DRM_DEBUG( "\n" );
 
-#if RADEON_PERFORMANCE_BOXES
 	/* Do some trivial performance monitoring...
 	 */
-	radeon_cp_performance_boxes( dev_priv );
-#endif
+	if (dev_priv->do_boxes)
+		radeon_cp_performance_boxes( dev_priv );
+
 
 	/* Wait for the 3D stream to idle before dispatching the bitblt.
 	 * This will prevent data corruption between the two streams.
@@ -689,9 +768,17 @@
 			  RADEON_DP_SRC_SOURCE_MEMORY |
 			  RADEON_GMC_CLR_CMP_CNTL_DIS |
 			  RADEON_GMC_WR_MSK_DIS );
-
-		OUT_RING( dev_priv->back_pitch_offset );
-		OUT_RING( dev_priv->front_pitch_offset );
+		
+		/* Make this work even if front & back are flipped:
+		 */
+		if (dev_priv->current_page == 0) {
+			OUT_RING( dev_priv->back_pitch_offset );
+			OUT_RING( dev_priv->front_pitch_offset );
+		} 
+		else {
+			OUT_RING( dev_priv->front_pitch_offset );
+			OUT_RING( dev_priv->back_pitch_offset );
+		}
 
 		OUT_RING( (x << 16) | y );
 		OUT_RING( (x << 16) | y );
@@ -717,29 +804,33 @@
 static void radeon_cp_dispatch_flip( drm_device_t *dev )
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
-	RING_LOCALS;
-	DRM_DEBUG( "%s: page=%d\n", __FUNCTION__, dev_priv->current_page );
+	drm_sarea_t *sarea = (drm_sarea_t *)dev_priv->sarea->handle;
+	int offset = (dev_priv->current_page == 1)
+		   ? dev_priv->front_offset : dev_priv->back_offset;
+	RING_LOCALS;
+	DRM_DEBUG( "%s: page=%d pfCurrentPage=%d\n", 
+		__FUNCTION__, 
+		dev_priv->current_page,
+		dev_priv->sarea_priv->pfCurrentPage);
 
-#if RADEON_PERFORMANCE_BOXES
 	/* Do some trivial performance monitoring...
 	 */
-	radeon_cp_performance_boxes( dev_priv );
-#endif
+	if (dev_priv->do_boxes) {
+		dev_priv->stats.boxes |= RADEON_BOX_FLIP;
+		radeon_cp_performance_boxes( dev_priv );
+	}
 
+	/* Update the frame offsets for both CRTCs
+	 */
 	BEGIN_RING( 6 );
 
 	RADEON_WAIT_UNTIL_3D_IDLE();
-	RADEON_WAIT_UNTIL_PAGE_FLIPPED();
-
-	OUT_RING( CP_PACKET0( RADEON_CRTC_OFFSET, 0 ) );
-
-	if ( dev_priv->current_page == 0 ) {
-		OUT_RING( dev_priv->back_offset );
-		dev_priv->current_page = 1;
-	} else {
-		OUT_RING( dev_priv->front_offset );
-		dev_priv->current_page = 0;
-	}
+	OUT_RING_REG( RADEON_CRTC_OFFSET, ( ( sarea->frame.y * dev_priv->front_pitch
+					      + sarea->frame.x 
+					      * ( dev_priv->color_fmt - 2 ) ) & ~7 )
+					  + offset );
+	OUT_RING_REG( RADEON_CRTC2_OFFSET, dev_priv->sarea_priv->crtc2_base
+					   + offset );
 
 	ADVANCE_RING();
 
@@ -748,6 +839,8 @@
 	 * performing the swapbuffer ioctl.
 	 */
 	dev_priv->sarea_priv->last_frame++;
+	dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page =
+					      1 - dev_priv->current_page;
 
 	BEGIN_RING( 2 );
 
@@ -756,82 +849,118 @@
 	ADVANCE_RING();
 }
 
+static int bad_prim_vertex_nr( int primitive, int nr )
+{
+	switch (primitive & RADEON_PRIM_TYPE_MASK) {
+	case RADEON_PRIM_TYPE_NONE:
+	case RADEON_PRIM_TYPE_POINT:
+		return nr < 1;
+	case RADEON_PRIM_TYPE_LINE:
+		return (nr & 1) || nr == 0;
+	case RADEON_PRIM_TYPE_LINE_STRIP:
+		return nr < 2;
+	case RADEON_PRIM_TYPE_TRI_LIST:
+	case RADEON_PRIM_TYPE_3VRT_POINT_LIST:
+	case RADEON_PRIM_TYPE_3VRT_LINE_LIST:
+	case RADEON_PRIM_TYPE_RECT_LIST:
+		return nr % 3 || nr == 0;
+	case RADEON_PRIM_TYPE_TRI_FAN:
+	case RADEON_PRIM_TYPE_TRI_STRIP:
+		return nr < 3;
+	default:
+		return 1;
+	}	
+}
+
+
+
+typedef struct {
+	unsigned int start;
+	unsigned int finish;
+	unsigned int prim;
+	unsigned int numverts;
+	unsigned int offset;   
+        unsigned int vc_format;
+} drm_radeon_tcl_prim_t;
+
 static void radeon_cp_dispatch_vertex( drm_device_t *dev,
-				       drm_buf_t *buf )
+				       drm_buf_t *buf,
+				       drm_radeon_tcl_prim_t *prim,
+				       drm_clip_rect_t *boxes,
+				       int nbox )
+
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
-	drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
-	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
-	int format = sarea_priv->vc_format;
-	int offset = dev_priv->agp_buffers_offset + buf->offset;
-	int size = buf->used;
-	int prim = buf_priv->prim;
+	drm_clip_rect_t box;
+	int offset = dev_priv->agp_buffers_offset + buf->offset + prim->start;
+	int numverts = (int)prim->numverts;
 	int i = 0;
 	RING_LOCALS;
-	DRM_DEBUG( "%s: nbox=%d\n", __FUNCTION__, sarea_priv->nbox );
 
-	if ( 0 )
-		radeon_print_dirty( "dispatch_vertex", sarea_priv->dirty );
+	DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d %d verts\n",
+		  prim->prim,
+		  prim->vc_format,
+		  prim->start,
+		  prim->finish,
+		  prim->numverts);
+
+	if (bad_prim_vertex_nr( prim->prim, prim->numverts )) {
+		DRM_ERROR( "bad prim %x numverts %d\n", 
+			   prim->prim, prim->numverts );
+		return;
+	}
+
+	do {
+		/* Emit the next cliprect */
+		if ( i < nbox ) {
+			if (__copy_from_user( &box, &boxes[i], sizeof(box) ))
+				return;
 
-	if ( buf->used ) {
-		buf_priv->dispatched = 1;
-
-		if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) {
-			radeon_emit_state( dev_priv );
+			radeon_emit_clip_rect( dev_priv, &box );
 		}
 
-		do {
-			/* Emit the next set of up to three cliprects */
-			if ( i < sarea_priv->nbox ) {
-				radeon_emit_clip_rect( dev_priv,
-						       &sarea_priv->boxes[i] );
-			}
+		/* Emit the vertex buffer rendering commands */
+		BEGIN_RING( 5 );
 
-			/* Emit the vertex buffer rendering commands */
-			BEGIN_RING( 5 );
+		OUT_RING( CP_PACKET3( RADEON_3D_RNDR_GEN_INDX_PRIM, 3 ) );
+		OUT_RING( offset );
+		OUT_RING( numverts );
+		OUT_RING( prim->vc_format );
+		OUT_RING( prim->prim | RADEON_PRIM_WALK_LIST |
+			  RADEON_COLOR_ORDER_RGBA |
+			  RADEON_VTX_FMT_RADEON_MODE |
+			  (numverts << RADEON_NUM_VERTICES_SHIFT) );
 
-			OUT_RING( CP_PACKET3( RADEON_3D_RNDR_GEN_INDX_PRIM, 3 ) );
-			OUT_RING( offset );
-			OUT_RING( size );
-			OUT_RING( format );
-			OUT_RING( prim | RADEON_PRIM_WALK_LIST |
-				  RADEON_COLOR_ORDER_RGBA |
-				  RADEON_VTX_FMT_RADEON_MODE |
-				  (size << RADEON_NUM_VERTICES_SHIFT) );
+		ADVANCE_RING();
 
-			ADVANCE_RING();
+		i++;
+	} while ( i < nbox );
+}
 
-			i++;
-		} while ( i < sarea_priv->nbox );
-	}
 
-	if ( buf_priv->discard ) {
-		buf_priv->age = dev_priv->sarea_priv->last_dispatch;
 
-		/* Emit the vertex buffer age */
-		BEGIN_RING( 2 );
-		RADEON_DISPATCH_AGE( buf_priv->age );
-		ADVANCE_RING();
+static void radeon_cp_discard_buffer( drm_device_t *dev, drm_buf_t *buf )
+{
+	drm_radeon_private_t *dev_priv = dev->dev_private;
+	drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
+	RING_LOCALS;
 
-		buf->pending = 1;
-		buf->used = 0;
-		/* FIXME: Check dispatched field */
-		buf_priv->dispatched = 0;
-	}
+	buf_priv->age = ++dev_priv->sarea_priv->last_dispatch;
 
-	dev_priv->sarea_priv->last_dispatch++;
+	/* Emit the vertex buffer age */
+	BEGIN_RING( 2 );
+	RADEON_DISPATCH_AGE( buf_priv->age );
+	ADVANCE_RING();
 
-	sarea_priv->dirty &= ~RADEON_UPLOAD_CLIPRECTS;
-	sarea_priv->nbox = 0;
+	buf->pending = 1;
+	buf->used = 0;
 }
 
-
 static void radeon_cp_dispatch_indirect( drm_device_t *dev,
 					 drm_buf_t *buf,
 					 int start, int end )
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
-	drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
 	RING_LOCALS;
 	DRM_DEBUG( "indirect: buf=%d s=0x%x e=0x%x\n",
 		   buf->idx, start, end );
@@ -852,8 +981,6 @@
 			data[dwords++] = RADEON_CP_PACKET2;
 		}
 
-		buf_priv->dispatched = 1;
-
 		/* Fire off the indirect buffer */
 		BEGIN_RING( 3 );
 
@@ -863,100 +990,75 @@
 
 		ADVANCE_RING();
 	}
-
-	if ( buf_priv->discard ) {
-		buf_priv->age = dev_priv->sarea_priv->last_dispatch;
-
-		/* Emit the indirect buffer age */
-		BEGIN_RING( 2 );
-		RADEON_DISPATCH_AGE( buf_priv->age );
-		ADVANCE_RING();
-
-		buf->pending = 1;
-		buf->used = 0;
-		/* FIXME: Check dispatched field */
-		buf_priv->dispatched = 0;
-	}
-
-	dev_priv->sarea_priv->last_dispatch++;
 }
 
+
 static void radeon_cp_dispatch_indices( drm_device_t *dev,
-					drm_buf_t *buf,
-					int start, int end,
-					int count )
+					drm_buf_t *elt_buf,
+					drm_radeon_tcl_prim_t *prim, 
+					drm_clip_rect_t *boxes,
+					int nbox )
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
-	drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
-	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
-	int format = sarea_priv->vc_format;
-	int offset = dev_priv->agp_buffers_offset;
-	int prim = buf_priv->prim;
+	drm_clip_rect_t box;
+	int offset = dev_priv->agp_buffers_offset + prim->offset;
 	u32 *data;
 	int dwords;
 	int i = 0;
-	RING_LOCALS;
-	DRM_DEBUG( "indices: s=%d e=%d c=%d\n", start, end, count );
-
-	if ( 0 )
-		radeon_print_dirty( "dispatch_indices", sarea_priv->dirty );
-
-	if ( start != end ) {
-		buf_priv->dispatched = 1;
-
-		if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) {
-			radeon_emit_state( dev_priv );
-		}
-
-		dwords = (end - start + 3) / sizeof(u32);
-
-		data = (u32 *)((char *)dev_priv->buffers->handle
-			       + buf->offset + start);
+	int start = prim->start + RADEON_INDEX_PRIM_OFFSET;
+	int count = (prim->finish - start) / sizeof(u16);
 
-		data[0] = CP_PACKET3( RADEON_3D_RNDR_GEN_INDX_PRIM, dwords-2 );
-
-		data[1] = offset;
-		data[2] = RADEON_MAX_VB_VERTS;
-		data[3] = format;
-		data[4] = (prim | RADEON_PRIM_WALK_IND |
-			   RADEON_COLOR_ORDER_RGBA |
-			   RADEON_VTX_FMT_RADEON_MODE |
-			   (count << RADEON_NUM_VERTICES_SHIFT) );
-
-		if ( count & 0x1 ) {
-			data[dwords-1] &= 0x0000ffff;
-		}
-
-		do {
-			/* Emit the next set of up to three cliprects */
-			if ( i < sarea_priv->nbox ) {
-				radeon_emit_clip_rect( dev_priv,
-						       &sarea_priv->boxes[i] );
-			}
-
-			radeon_cp_dispatch_indirect( dev, buf, start, end );
-
-			i++;
-		} while ( i < sarea_priv->nbox );
+	DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d offset: %x nr %d\n",
+		  prim->prim,
+		  prim->vc_format,
+		  prim->start,
+		  prim->finish,
+		  prim->offset,
+		  prim->numverts);
+
+	if (bad_prim_vertex_nr( prim->prim, count )) {
+		DRM_ERROR( "bad prim %x count %d\n", 
+			   prim->prim, count );
+		return;
 	}
 
-	if ( buf_priv->discard ) {
-		buf_priv->age = dev_priv->sarea_priv->last_dispatch;
 
-		/* Emit the vertex buffer age */
-		BEGIN_RING( 2 );
-		RADEON_DISPATCH_AGE( buf_priv->age );
-		ADVANCE_RING();
+	if ( start >= prim->finish ||
+	     (prim->start & 0x7) ) {
+		DRM_ERROR( "buffer prim %d\n", prim->prim );
+		return;
+	}
+
+	dwords = (prim->finish - prim->start + 3) / sizeof(u32);
+
+	data = (u32 *)((char *)dev_priv->buffers->handle +
+		       elt_buf->offset + prim->start);
+
+	data[0] = CP_PACKET3( RADEON_3D_RNDR_GEN_INDX_PRIM, dwords-2 );
+	data[1] = offset;
+	data[2] = prim->numverts;
+	data[3] = prim->vc_format;
+	data[4] = (prim->prim |
+		   RADEON_PRIM_WALK_IND |
+		   RADEON_COLOR_ORDER_RGBA |
+		   RADEON_VTX_FMT_RADEON_MODE |
+		   (count << RADEON_NUM_VERTICES_SHIFT) );
+
+	do {
+		if ( i < nbox ) {
+			if (__copy_from_user( &box, &boxes[i], sizeof(box) ))
+				return;
+			
+			radeon_emit_clip_rect( dev_priv, &box );
+		}
 
-		buf->pending = 1;
-		/* FIXME: Check dispatched field */
-		buf_priv->dispatched = 0;
-	}
+		radeon_cp_dispatch_indirect( dev, elt_buf,
+					     prim->start,
+					     prim->finish );
 
-	dev_priv->sarea_priv->last_dispatch++;
+		i++;
+	} while ( i < nbox );
 
-	sarea_priv->dirty &= ~RADEON_UPLOAD_CLIPRECTS;
-	sarea_priv->nbox = 0;
 }
 
 #define RADEON_MAX_TEXTURE_SIZE (RADEON_BUFFER_SIZE - 8 * sizeof(u32))
@@ -967,25 +1069,35 @@
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	drm_buf_t *buf;
-	drm_radeon_buf_priv_t *buf_priv;
 	u32 format;
 	u32 *buffer;
-	u8 *data;
+	const u8 *data;
 	int size, dwords, tex_width, blit_width;
-	u32 y, height;
-	int ret = 0, i;
+	u32 height;
+	int i;
 	RING_LOCALS;
 
-	/* FIXME: Be smarter about this...
+	dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD;
+
+	/* Flush the pixel cache.  This ensures no pixel data gets mixed
+	 * up with the texture data from the host data blit, otherwise
+	 * part of the texture image may be corrupted.
 	 */
-	buf = radeon_freelist_get( dev );
-	if ( !buf ) return -EAGAIN;
+	BEGIN_RING( 4 );
+	RADEON_FLUSH_CACHE();
+	RADEON_WAIT_UNTIL_IDLE();
+	ADVANCE_RING();
 
-	DRM_DEBUG( "tex: ofs=0x%x p=%d f=%d x=%hd y=%hd w=%hd h=%hd\n",
-		   tex->offset >> 10, tex->pitch, tex->format,
-		   image->x, image->y, image->width, image->height );
+#ifdef __BIG_ENDIAN
+	/* The Mesa texture functions provide the data in little endian as the
+	 * chip wants it, but we need to compensate for the fact that the CP
+	 * ring gets byte-swapped
+	 */
+	BEGIN_RING( 2 );
+	OUT_RING_REG( RADEON_RBBM_GUICNTL, RADEON_HOST_DATA_SWAP_32BIT );
+	ADVANCE_RING();
+#endif
 
-	buf_priv = buf->dev_private;
 
 	/* The compiler won't optimize away a division by a variable,
 	 * even if the only legal values are powers of two.  Thus, we'll
@@ -1002,6 +1114,8 @@
 	case RADEON_TXFORMAT_ARGB1555:
 	case RADEON_TXFORMAT_RGB565:
 	case RADEON_TXFORMAT_ARGB4444:
+	case RADEON_TXFORMAT_VYUY422:
+	case RADEON_TXFORMAT_YVYU422:
 		format = RADEON_COLOR_FORMAT_RGB565;
 		tex_width = tex->width * 2;
 		blit_width = image->width * 2;
@@ -1017,56 +1131,46 @@
 		return -EINVAL;
 	}
 
-	DRM_DEBUG( "   tex=%dx%d  blit=%d\n",
-		   tex_width, tex->height, blit_width );
-
-	/* Flush the pixel cache.  This ensures no pixel data gets mixed
-	 * up with the texture data from the host data blit, otherwise
-	 * part of the texture image may be corrupted.
-	 */
-	BEGIN_RING( 4 );
-
-	RADEON_FLUSH_CACHE();
-	RADEON_WAIT_UNTIL_IDLE();
+	DRM_DEBUG("tex=%dx%d blit=%d\n", tex_width, tex->height, blit_width );
 
-	ADVANCE_RING();
+	do {
+		DRM_DEBUG( "tex: ofs=0x%x p=%d f=%d x=%hd y=%hd w=%hd h=%hd\n",
+			   tex->offset >> 10, tex->pitch, tex->format,
+			   image->x, image->y, image->width, image->height );
 
-	/* Make a copy of the parameters in case we have to update them
-	 * for a multi-pass texture blit.
+		/* Make a copy of some parameters in case we have to
+		 * update them for a multi-pass texture blit.
 	 */
-	y = image->y;
 	height = image->height;
-	data = (u8 *)image->data;
+	data = (const u8 *)image->data;
 
 	size = height * blit_width;
 
 	if ( size > RADEON_MAX_TEXTURE_SIZE ) {
-		/* Texture image is too large, do a multipass upload */
-		ret = -EAGAIN;
-
-		/* Adjust the blit size to fit the indirect buffer */
 		height = RADEON_MAX_TEXTURE_SIZE / blit_width;
 		size = height * blit_width;
-
-		/* Update the input parameters for next time */
-		image->y += height;
-		image->height -= height;
-		image->data = (char *)image->data + size;
-
-		if ( copy_to_user( tex->image, image, sizeof(*image) ) ) {
-			DRM_ERROR( "EFAULT on tex->image\n" );
-			return -EFAULT;
-		}
 	} else if ( size < 4 && size > 0 ) {
 		size = 4;
+		} else if ( size == 0 ) {
+			return 0;
+		}
+
+		buf = radeon_freelist_get( dev );
+		if ( 0 && !buf ) {
+			radeon_do_cp_idle( dev_priv );
+			buf = radeon_freelist_get( dev );
+		}
+		if ( !buf ) {
+			DRM_DEBUG("radeon_cp_dispatch_texture: EAGAIN\n");
+			copy_to_user( tex->image, image, sizeof(*image) );
+			return -EAGAIN;
 	}
 
-	dwords = size / 4;
 
 	/* Dispatch the indirect buffer.
 	 */
-	buffer = (u32 *)((char *)dev_priv->buffers->handle + buf->offset);
-
+		buffer = (u32*)((char*)dev_priv->buffers->handle + buf->offset);
+		dwords = size / 4;
 	buffer[0] = CP_PACKET3( RADEON_CNTL_HOSTDATA_BLT, dwords + 6 );
 	buffer[1] = (RADEON_GMC_DST_PITCH_OFFSET_CNTL |
 		     RADEON_GMC_BRUSH_NONE |
@@ -1080,7 +1184,7 @@
 	buffer[2] = (tex->pitch << 22) | (tex->offset >> 10);
 	buffer[3] = 0xffffffff;
 	buffer[4] = 0xffffffff;
-	buffer[5] = (y << 16) | image->x;
+	buffer[5] = (image->y << 16) | image->x;
 	buffer[6] = (height << 16) | image->width;
 	buffer[7] = dwords;
 
@@ -1112,30 +1216,34 @@
 
 	buf->pid = current->pid;
 	buf->used = (dwords + 8) * sizeof(u32);
-	buf_priv->discard = 1;
 
 	radeon_cp_dispatch_indirect( dev, buf, 0, buf->used );
+	radeon_cp_discard_buffer( dev, buf );
+
+		/* Update the input parameters for next time */
+		image->y += height;
+		image->height -= height;
+		(const u8 *)image->data += size;
+	} while (image->height > 0);
 
 	/* Flush the pixel cache after the blit completes.  This ensures
 	 * the texture data is written out to memory before rendering
 	 * continues.
 	 */
 	BEGIN_RING( 4 );
-
 	RADEON_FLUSH_CACHE();
 	RADEON_WAIT_UNTIL_2D_IDLE();
-
 	ADVANCE_RING();
-
-	return ret;
+	return 0;
 }
 
+
 static void radeon_cp_dispatch_stipple( drm_device_t *dev, u32 *stipple )
 {
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	int i;
 	RING_LOCALS;
-	DRM_DEBUG( "%s\n", __FUNCTION__ );
+	DRM_DEBUG( "\n" );
 
 	BEGIN_RING( 35 );
 
@@ -1158,31 +1266,95 @@
 int radeon_cp_clear( struct inode *inode, struct file *filp,
 		     unsigned int cmd, unsigned long arg )
 {
-	drm_file_t *priv = filp->private_data;
-	drm_device_t *dev = priv->dev;
+	drm_file_t *priv = filp->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_radeon_private_t *dev_priv = dev->dev_private;
+	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	drm_radeon_clear_t clear;
+	drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
+	DRM_DEBUG( "\n" );
+
+	LOCK_TEST_WITH_RETURN( dev );
+
+	if ( copy_from_user( &clear, (drm_radeon_clear_t *)arg,
+			     sizeof(clear) ) )
+		return -EFAULT;
+
+	RING_SPACE_TEST_WITH_RETURN( dev_priv );
+
+	if ( sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS )
+		sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
+
+	if ( copy_from_user( &depth_boxes, clear.depth_boxes,
+			     sarea_priv->nbox * sizeof(depth_boxes[0]) ) )
+		return -EFAULT;
+
+	radeon_cp_dispatch_clear( dev, &clear, depth_boxes );
+
+	COMMIT_RING();
+	return 0;
+}
+
+
+/* Not sure why this isn't set all the time:
+ */ 
+static int radeon_do_init_pageflip( drm_device_t *dev )
+{
+	drm_radeon_private_t *dev_priv = dev->dev_private;
+	RING_LOCALS;
+
+	DRM_DEBUG( "\n" );
+
+	BEGIN_RING( 6 );
+	RADEON_WAIT_UNTIL_3D_IDLE();
+	OUT_RING( CP_PACKET0( RADEON_CRTC_OFFSET_CNTL, 0 ) );
+	OUT_RING( RADEON_READ( RADEON_CRTC_OFFSET_CNTL ) | RADEON_CRTC_OFFSET_FLIP_CNTL );
+	OUT_RING( CP_PACKET0( RADEON_CRTC2_OFFSET_CNTL, 0 ) );
+	OUT_RING( RADEON_READ( RADEON_CRTC2_OFFSET_CNTL ) | RADEON_CRTC_OFFSET_FLIP_CNTL );
+	ADVANCE_RING();
+
+	dev_priv->page_flipping = 1;
+	dev_priv->current_page = 0;
+	dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page;
+
+	return 0;
+}
+
+/* Called whenever a client dies, from DRM(release).
+ * NOTE:  Lock isn't necessarily held when this is called!
+ */
+int radeon_do_cleanup_pageflip( drm_device_t *dev )
+{
+	drm_radeon_private_t *dev_priv = dev->dev_private;
+	DRM_DEBUG( "\n" );
+
+	if (dev_priv->current_page != 0)
+		radeon_cp_dispatch_flip( dev );
+
+	dev_priv->page_flipping = 0;
+	return 0;
+}
+
+/* Swapping and flipping are different operations, need different ioctls.
+ * They can & should be intermixed to support multiple 3d windows.  
+ */
+int radeon_cp_flip(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data )
+{
+        drm_file_t      *priv   = filp->private_data;
+        drm_device_t    *dev    = priv->dev;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
-	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
-	drm_radeon_clear_t clear;
-	drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS];
-	DRM_DEBUG( "%s\n", __FUNCTION__ );
+	DRM_DEBUG( "\n" );
 
 	LOCK_TEST_WITH_RETURN( dev );
 
-	if ( copy_from_user( &clear, (drm_radeon_clear_t *)arg,
-			     sizeof(clear) ) )
-		return -EFAULT;
-
 	RING_SPACE_TEST_WITH_RETURN( dev_priv );
 
-	if ( sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS )
-		sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
-
-	if ( copy_from_user( &depth_boxes, clear.depth_boxes,
-			     sarea_priv->nbox * sizeof(depth_boxes[0]) ) )
-		return -EFAULT;
-
-	radeon_cp_dispatch_clear( dev, &clear, depth_boxes );
+	if (!dev_priv->page_flipping) 
+		radeon_do_init_pageflip( dev );
+		
+	radeon_cp_dispatch_flip( dev );
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1193,7 +1365,7 @@
 	drm_device_t *dev = priv->dev;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
-	DRM_DEBUG( "%s\n", __FUNCTION__ );
+	DRM_DEBUG( "\n" );
 
 	LOCK_TEST_WITH_RETURN( dev );
 
@@ -1202,14 +1374,10 @@
 	if ( sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS )
 		sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
 
-	if ( !dev_priv->page_flipping ) {
-		radeon_cp_dispatch_swap( dev );
-		dev_priv->sarea_priv->dirty |= (RADEON_UPLOAD_CONTEXT |
-						RADEON_UPLOAD_MASKS);
-	} else {
-		radeon_cp_dispatch_flip( dev );
-	}
+	radeon_cp_dispatch_swap( dev );
+	dev_priv->sarea_priv->ctx_owner = 0;
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1219,10 +1387,11 @@
 	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->dev;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
+	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	drm_device_dma_t *dma = dev->dma;
 	drm_buf_t *buf;
-	drm_radeon_buf_priv_t *buf_priv;
 	drm_radeon_vertex_t vertex;
+	drm_radeon_tcl_prim_t prim;
 
 	LOCK_TEST_WITH_RETURN( dev );
 
@@ -1235,8 +1404,8 @@
 			     sizeof(vertex) ) )
 		return -EFAULT;
 
-	DRM_DEBUG( "%s: pid=%d index=%d count=%d discard=%d\n",
-		   __FUNCTION__, current->pid,
+	DRM_DEBUG( "pid=%d index=%d count=%d discard=%d\n",
+		   current->pid,
 		   vertex.idx, vertex.count, vertex.discard );
 
 	if ( vertex.idx < 0 || vertex.idx >= dma->buf_count ) {
@@ -1254,7 +1423,6 @@
 	VB_AGE_TEST_WITH_RETURN( dev_priv );
 
 	buf = dma->buflist[vertex.idx];
-	buf_priv = buf->dev_private;
 
 	if ( buf->pid != current->pid ) {
 		DRM_ERROR( "process %d using buffer owned by %d\n",
@@ -1266,12 +1434,39 @@
 		return -EINVAL;
 	}
 
-	buf->used = vertex.count;
-	buf_priv->prim = vertex.prim;
-	buf_priv->discard = vertex.discard;
+	/* Build up a prim_t record:
+	 */
+	if (vertex.count) {
+		buf->used = vertex.count; /* not used? */
+
+		if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) {
+			radeon_emit_state( dev_priv,
+					   &sarea_priv->context_state,
+					   sarea_priv->tex_state,
+					   sarea_priv->dirty );
+			
+			sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
+					       RADEON_UPLOAD_TEX1IMAGES |
+					       RADEON_UPLOAD_TEX2IMAGES |
+					       RADEON_REQUIRE_QUIESCENCE);
+		}
+
+		prim.start = 0;
+		prim.finish = vertex.count; /* unused */
+		prim.prim = vertex.prim;
+		prim.numverts = vertex.count;
+		prim.vc_format = dev_priv->sarea_priv->vc_format;
+		
+		radeon_cp_dispatch_vertex( dev, buf, &prim,
+					   dev_priv->sarea_priv->boxes,
+					   dev_priv->sarea_priv->nbox );
+	}
 
-	radeon_cp_dispatch_vertex( dev, buf );
+	if (vertex.discard) {
+		radeon_cp_discard_buffer( dev, buf );
+	}
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1281,10 +1476,11 @@
 	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->dev;
 	drm_radeon_private_t *dev_priv = dev->dev_private;
+	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
 	drm_device_dma_t *dma = dev->dma;
 	drm_buf_t *buf;
-	drm_radeon_buf_priv_t *buf_priv;
 	drm_radeon_indices_t elts;
+	drm_radeon_tcl_prim_t prim;
 	int count;
 
 	LOCK_TEST_WITH_RETURN( dev );
@@ -1317,7 +1513,6 @@
 	VB_AGE_TEST_WITH_RETURN( dev_priv );
 
 	buf = dma->buflist[elts.idx];
-	buf_priv = buf->dev_private;
 
 	if ( buf->pid != current->pid ) {
 		DRM_ERROR( "process %d using buffer owned by %d\n",
@@ -1342,11 +1537,37 @@
 	}
 
 	buf->used = elts.end;
-	buf_priv->prim = elts.prim;
-	buf_priv->discard = elts.discard;
 
-	radeon_cp_dispatch_indices( dev, buf, elts.start, elts.end, count );
+	if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) {
+		radeon_emit_state( dev_priv,
+				   &sarea_priv->context_state,
+				   sarea_priv->tex_state,
+				   sarea_priv->dirty );
+
+		sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
+				       RADEON_UPLOAD_TEX1IMAGES |
+				       RADEON_UPLOAD_TEX2IMAGES |
+				       RADEON_REQUIRE_QUIESCENCE);
+	}
+
+
+	/* Build up a prim_t record:
+	 */
+	prim.start = elts.start;
+	prim.finish = elts.end; 
+	prim.prim = elts.prim;
+	prim.offset = 0;	/* offset from start of dma buffers */
+	prim.numverts = RADEON_MAX_VB_VERTS; /* duh */
+	prim.vc_format = dev_priv->sarea_priv->vc_format;
+	
+	radeon_cp_dispatch_indices( dev, buf, &prim,
+				   dev_priv->sarea_priv->boxes,
+				   dev_priv->sarea_priv->nbox );
+	if (elts.discard) {
+		radeon_cp_discard_buffer( dev, buf );
+	}
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1358,6 +1579,7 @@
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	drm_radeon_texture_t tex;
 	drm_radeon_tex_image_t image;
+	int ret;
 
 	LOCK_TEST_WITH_RETURN( dev );
 
@@ -1377,7 +1599,10 @@
 	RING_SPACE_TEST_WITH_RETURN( dev_priv );
 	VB_AGE_TEST_WITH_RETURN( dev_priv );
 
-	return radeon_cp_dispatch_texture( dev, &tex, &image );
+	ret = radeon_cp_dispatch_texture( dev, &tex, &image );
+
+	COMMIT_RING();
+	return ret;
 }
 
 int radeon_cp_stipple( struct inode *inode, struct file *filp,
@@ -1402,6 +1627,7 @@
 
 	radeon_cp_dispatch_stipple( dev, mask );
 
+	COMMIT_RING();
 	return 0;
 }
 
@@ -1413,7 +1639,6 @@
 	drm_radeon_private_t *dev_priv = dev->dev_private;
 	drm_device_dma_t *dma = dev->dma;
 	drm_buf_t *buf;
-	drm_radeon_buf_priv_t *buf_priv;
 	drm_radeon_indirect_t indirect;
 	RING_LOCALS;
 
@@ -1439,7 +1664,6 @@
 	}
 
 	buf = dma->buflist[indirect.idx];
-	buf_priv = buf->dev_private;
 
 	if ( buf->pid != current->pid ) {
 		DRM_ERROR( "process %d using buffer owned by %d\n",
@@ -1461,7 +1685,6 @@
 	VB_AGE_TEST_WITH_RETURN( dev_priv );
 
 	buf->used = indirect.end;
-	buf_priv->discard = indirect.discard;
 
 	/* Wait for the 3D stream to idle before the indirect buffer
 	 * containing 2D acceleration commands is processed.
@@ -1477,6 +1700,526 @@
 	 * privileged clients.
 	 */
 	radeon_cp_dispatch_indirect( dev, buf, indirect.start, indirect.end );
+	if (indirect.discard) {
+		radeon_cp_discard_buffer( dev, buf );
+	}
+
+
+	COMMIT_RING();
+	return 0;
+}
+
+int radeon_cp_vertex2(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data )
+{
+        drm_file_t      *priv   = filp->private_data;
+        drm_device_t    *dev    = priv->dev;
+	drm_radeon_private_t *dev_priv = dev->dev_private;
+	drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	drm_device_dma_t *dma = dev->dma;
+	drm_buf_t *buf;
+	drm_radeon_vertex2_t vertex;
+	int i;
+	unsigned char laststate;
+
+	LOCK_TEST_WITH_RETURN( dev );
+
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+		return -EINVAL;
+	}
+
+	DRM_COPY_FROM_USER_IOCTL( vertex, (drm_radeon_vertex2_t *)data,
+			     sizeof(vertex) );
+
+	DRM_DEBUG( "pid=%d index=%d discard=%d\n",
+		   current->pid,
+		   vertex.idx, vertex.discard );
+
+	if ( vertex.idx < 0 || vertex.idx >= dma->buf_count ) {
+		DRM_ERROR( "buffer index %d (of %d max)\n",
+			   vertex.idx, dma->buf_count - 1 );
+		return -EINVAL;
+	}
+
+	RING_SPACE_TEST_WITH_RETURN( dev_priv );
+	VB_AGE_TEST_WITH_RETURN( dev_priv );
+
+	buf = dma->buflist[vertex.idx];
+
+	if ( buf->pid != current->pid ) {
+		DRM_ERROR( "process %d using buffer owned by %d\n",
+			   current->pid, buf->pid );
+		return -EINVAL;
+	}
+
+	if ( buf->pending ) {
+		DRM_ERROR( "sending pending buffer %d\n", vertex.idx );
+		return -EINVAL;
+	}
+	
+	if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
+		return -EINVAL;
+
+	for (laststate = 0xff, i = 0 ; i < vertex.nr_prims ; i++) {
+		drm_radeon_prim_t prim;
+		drm_radeon_tcl_prim_t tclprim;
+		
+		if ( copy_from_user( &prim, &vertex.prim[i], sizeof(prim) ) )
+			return -EFAULT;
+		
+		if ( prim.stateidx != laststate ) {
+			drm_radeon_state_t state;			       
+				
+			if ( copy_from_user( &state, 
+					     &vertex.state[prim.stateidx], 
+					     sizeof(state) ) )
+				return -EFAULT;
+
+			radeon_emit_state2( dev_priv, &state );
+
+			laststate = prim.stateidx;
+		}
+
+		tclprim.start = prim.start;
+		tclprim.finish = prim.finish;
+		tclprim.prim = prim.prim;
+		tclprim.vc_format = prim.vc_format;
+
+		if ( prim.prim & RADEON_PRIM_WALK_IND ) {
+			tclprim.offset = prim.numverts * 64;
+			tclprim.numverts = RADEON_MAX_VB_VERTS; /* duh */
+
+			radeon_cp_dispatch_indices( dev, buf, &tclprim,
+						    sarea_priv->boxes,
+						    sarea_priv->nbox);
+		} else {
+			tclprim.numverts = prim.numverts;
+			tclprim.offset = 0; /* not used */
+
+			radeon_cp_dispatch_vertex( dev, buf, &tclprim,
+						   sarea_priv->boxes,
+						   sarea_priv->nbox);
+		}
+		
+		if (sarea_priv->nbox == 1)
+			sarea_priv->nbox = 0;
+	}
+
+	if ( vertex.discard ) {
+		radeon_cp_discard_buffer( dev, buf );
+	}
+
+	COMMIT_RING();
+	return 0;
+}
+
+
+static int radeon_emit_packets( 
+	drm_radeon_private_t *dev_priv,
+	drm_radeon_cmd_header_t header,
+	drm_radeon_cmd_buffer_t *cmdbuf )
+{
+	int id = (int)header.packet.packet_id;
+	int sz, reg;
+	int *data = (int *)cmdbuf->buf;
+	RING_LOCALS;
+   
+	if (id >= RADEON_MAX_STATE_PACKETS)
+		return -EINVAL;
+
+	sz = packet[id].len;
+	reg = packet[id].start;
+
+	if (sz * sizeof(int) > cmdbuf->bufsz) 
+		return -EINVAL;
+
+	BEGIN_RING(sz+1);
+	OUT_RING( CP_PACKET0( reg, (sz-1) ) );
+	OUT_RING_USER_TABLE( data, sz );
+	ADVANCE_RING();
+
+	cmdbuf->buf += sz * sizeof(int);
+	cmdbuf->bufsz -= sz * sizeof(int);
+	return 0;
+}
+
+static __inline__ int radeon_emit_scalars( 
+	drm_radeon_private_t *dev_priv,
+	drm_radeon_cmd_header_t header,
+	drm_radeon_cmd_buffer_t *cmdbuf )
+{
+	int sz = header.scalars.count;
+	int *data = (int *)cmdbuf->buf;
+	int start = header.scalars.offset;
+	int stride = header.scalars.stride;
+	RING_LOCALS;
+
+	BEGIN_RING( 3+sz );
+	OUT_RING( CP_PACKET0( RADEON_SE_TCL_SCALAR_INDX_REG, 0 ) );
+	OUT_RING( start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
+	OUT_RING( CP_PACKET0_TABLE( RADEON_SE_TCL_SCALAR_DATA_REG, sz-1 ) );
+	OUT_RING_USER_TABLE( data, sz );
+	ADVANCE_RING();
+	cmdbuf->buf += sz * sizeof(int);
+	cmdbuf->bufsz -= sz * sizeof(int);
+	return 0;
+}
+
+/* God this is ugly
+ */
+static __inline__ int radeon_emit_scalars2( 
+	drm_radeon_private_t *dev_priv,
+	drm_radeon_cmd_header_t header,
+	drm_radeon_cmd_buffer_t *cmdbuf )
+{
+	int sz = header.scalars.count;
+	int *data = (int *)cmdbuf->buf;
+	int start = ((unsigned int)header.scalars.offset) + 0x100;
+	int stride = header.scalars.stride;
+	RING_LOCALS;
+
+	BEGIN_RING( 3+sz );
+	OUT_RING( CP_PACKET0( RADEON_SE_TCL_SCALAR_INDX_REG, 0 ) );
+	OUT_RING( start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
+	OUT_RING( CP_PACKET0_TABLE( RADEON_SE_TCL_SCALAR_DATA_REG, sz-1 ) );
+	OUT_RING_USER_TABLE( data, sz );
+	ADVANCE_RING();
+	cmdbuf->buf += sz * sizeof(int);
+	cmdbuf->bufsz -= sz * sizeof(int);
+	return 0;
+}
+
+static __inline__ int radeon_emit_vectors( 
+	drm_radeon_private_t *dev_priv,
+	drm_radeon_cmd_header_t header,
+	drm_radeon_cmd_buffer_t *cmdbuf )
+{
+	int sz = header.vectors.count;
+	int *data = (int *)cmdbuf->buf;
+	int start = header.vectors.offset;
+	int stride = header.vectors.stride;
+	RING_LOCALS;
+
+	BEGIN_RING( 3+sz );
+	OUT_RING( CP_PACKET0( RADEON_SE_TCL_VECTOR_INDX_REG, 0 ) );
+	OUT_RING( start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
+	OUT_RING( CP_PACKET0_TABLE( RADEON_SE_TCL_VECTOR_DATA_REG, (sz-1) ) );
+	OUT_RING_USER_TABLE( data, sz );
+	ADVANCE_RING();
+
+	cmdbuf->buf += sz * sizeof(int);
+	cmdbuf->bufsz -= sz * sizeof(int);
+	return 0;
+}
+
+
+static int radeon_emit_packet3( drm_device_t *dev,
+				drm_radeon_cmd_buffer_t *cmdbuf )
+{
+	drm_radeon_private_t *dev_priv = dev->dev_private;
+	int cmdsz, tmp;
+	int *cmd = (int *)cmdbuf->buf;
+	RING_LOCALS;
 
+
+	DRM_DEBUG("\n");
+
+	if (__get_user( tmp, &cmd[0]))
+		return -EFAULT;
+
+	cmdsz = 2 + ((tmp & RADEON_CP_PACKET_COUNT_MASK) >> 16);
+
+	if ((tmp & 0xc0000000) != RADEON_CP_PACKET3 ||
+	    cmdsz * 4 > cmdbuf->bufsz)
+		return -EINVAL;
+
+	BEGIN_RING( cmdsz );
+	OUT_RING_USER_TABLE( cmd, cmdsz );
+	ADVANCE_RING();
+
+	cmdbuf->buf += cmdsz * 4;
+	cmdbuf->bufsz -= cmdsz * 4;
+	return 0;
+}
+
+
+static int radeon_emit_packet3_cliprect( drm_device_t *dev,
+					 drm_radeon_cmd_buffer_t *cmdbuf,
+					 int orig_nbox )
+{
+	drm_radeon_private_t *dev_priv = dev->dev_private;
+	drm_clip_rect_t box;
+	int cmdsz, tmp;
+	int *cmd = (int *)cmdbuf->buf;
+	drm_clip_rect_t *boxes = cmdbuf->boxes;
+	int i = 0;
+	RING_LOCALS;
+
+	DRM_DEBUG("\n");
+
+	if (__get_user( tmp, &cmd[0]))
+		return -EFAULT;
+
+	cmdsz = 2 + ((tmp & RADEON_CP_PACKET_COUNT_MASK) >> 16);
+
+	if ((tmp & 0xc0000000) != RADEON_CP_PACKET3 ||
+	    cmdsz * 4 > cmdbuf->bufsz)
+		return -EINVAL;
+
+	if (!orig_nbox)
+		goto out;
+
+	do {
+		if ( i < cmdbuf->nbox ) {
+			if (__copy_from_user( &box, &boxes[i], sizeof(box) ))
+				return -EFAULT;
+			/* FIXME The second and subsequent times round
+			 * this loop, send a WAIT_UNTIL_3D_IDLE before
+			 * calling emit_clip_rect(). This fixes a
+			 * lockup on fast machines when sending
+			 * several cliprects with a cmdbuf, as when
+			 * waving a 2D window over a 3D
+			 * window. Something in the commands from user
+			 * space seems to hang the card when they're
+			 * sent several times in a row. That would be
+			 * the correct place to fix it but this works
+			 * around it until I can figure that out - Tim
+			 * Smith */
+			if ( i ) {
+				BEGIN_RING( 2 );
+				RADEON_WAIT_UNTIL_3D_IDLE();
+				ADVANCE_RING();
+			}
+			radeon_emit_clip_rect( dev_priv, &box );
+		}
+		
+		BEGIN_RING( cmdsz );
+		OUT_RING_USER_TABLE( cmd, cmdsz );
+		ADVANCE_RING();
+
+	} while ( ++i < cmdbuf->nbox );
+ 	if (cmdbuf->nbox == 1)
+		cmdbuf->nbox = 0;
+
+ out:
+	cmdbuf->buf += cmdsz * 4;
+	cmdbuf->bufsz -= cmdsz * 4;
+	return 0;
+}
+
+
+static int radeon_emit_wait( drm_device_t *dev, int flags )
+{
+	drm_radeon_private_t *dev_priv = dev->dev_private;
+	RING_LOCALS;
+
+	DRM_DEBUG("%s: %x\n", __FUNCTION__, flags);
+	switch (flags) {
+	case RADEON_WAIT_2D:
+		BEGIN_RING( 2 );
+		RADEON_WAIT_UNTIL_2D_IDLE(); 
+		ADVANCE_RING();
+		break;
+	case RADEON_WAIT_3D:
+		BEGIN_RING( 2 );
+		RADEON_WAIT_UNTIL_3D_IDLE(); 
+		ADVANCE_RING();
+		break;
+	case RADEON_WAIT_2D|RADEON_WAIT_3D:
+		BEGIN_RING( 2 );
+		RADEON_WAIT_UNTIL_IDLE(); 
+		ADVANCE_RING();
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int radeon_cp_cmdbuf(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data )
+{
+        drm_file_t      *priv   = filp->private_data;
+        drm_device_t    *dev    = priv->dev;
+	drm_radeon_private_t *dev_priv = dev->dev_private;
+	drm_device_dma_t *dma = dev->dma;
+	drm_buf_t *buf = 0;
+	int idx;
+	drm_radeon_cmd_buffer_t cmdbuf;
+	drm_radeon_cmd_header_t header;
+	int orig_nbox;
+
+	LOCK_TEST_WITH_RETURN( dev );
+
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+		return -EINVAL;
+	}
+
+	DRM_COPY_FROM_USER_IOCTL( cmdbuf, (drm_radeon_cmd_buffer_t *)data,
+			     sizeof(cmdbuf) );
+
+	RING_SPACE_TEST_WITH_RETURN( dev_priv );
+	VB_AGE_TEST_WITH_RETURN( dev_priv );
+
+
+	if (verify_area( VERIFY_READ, cmdbuf.buf, cmdbuf.bufsz ))
+		return -EFAULT;
+
+	if (cmdbuf.nbox &&
+	    verify_area( VERIFY_READ, cmdbuf.boxes, 
+			 cmdbuf.nbox * sizeof(drm_clip_rect_t)))
+		return -EFAULT;
+
+	orig_nbox = cmdbuf.nbox;
+
+	while ( cmdbuf.bufsz >= sizeof(header) ) {
+		
+		if (__get_user( header.i, (int *)cmdbuf.buf )) {
+			DRM_ERROR("__get_user %p\n", cmdbuf.buf);
+			return -EFAULT;
+		}
+
+		cmdbuf.buf += sizeof(header);
+		cmdbuf.bufsz -= sizeof(header);
+
+		switch (header.header.cmd_type) {
+		case RADEON_CMD_PACKET: 
+			DRM_DEBUG("RADEON_CMD_PACKET\n");
+			if (radeon_emit_packets( dev_priv, header, &cmdbuf )) {
+				DRM_ERROR("radeon_emit_packets failed\n");
+				return -EINVAL;
+			}
+			break;
+
+		case RADEON_CMD_SCALARS:
+			DRM_DEBUG("RADEON_CMD_SCALARS\n");
+			if (radeon_emit_scalars( dev_priv, header, &cmdbuf )) {
+				DRM_ERROR("radeon_emit_scalars failed\n");
+				return -EINVAL;
+			}
+			break;
+
+		case RADEON_CMD_VECTORS:
+			DRM_DEBUG("RADEON_CMD_VECTORS\n");
+			if (radeon_emit_vectors( dev_priv, header, &cmdbuf )) {
+				DRM_ERROR("radeon_emit_vectors failed\n");
+				return -EINVAL;
+			}
+			break;
+
+		case RADEON_CMD_DMA_DISCARD:
+			DRM_DEBUG("RADEON_CMD_DMA_DISCARD\n");
+			idx = header.dma.buf_idx;
+			if ( idx < 0 || idx >= dma->buf_count ) {
+				DRM_ERROR( "buffer index %d (of %d max)\n",
+					   idx, dma->buf_count - 1 );
+				return -EINVAL;
+			}
+
+			buf = dma->buflist[idx];
+			if ( buf->pid != current->pid || buf->pending ) {
+				DRM_ERROR( "bad buffer\n" );
+				return -EINVAL;
+			}
+
+			radeon_cp_discard_buffer( dev, buf );
+			break;
+
+		case RADEON_CMD_PACKET3:
+			DRM_DEBUG("RADEON_CMD_PACKET3\n");
+			if (radeon_emit_packet3( dev, &cmdbuf )) {
+				DRM_ERROR("radeon_emit_packet3 failed\n");
+				return -EINVAL;
+			}
+			break;
+
+		case RADEON_CMD_PACKET3_CLIP:
+			DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n");
+			if (radeon_emit_packet3_cliprect( dev, &cmdbuf, orig_nbox )) {
+				DRM_ERROR("radeon_emit_packet3_clip failed\n");
+				return -EINVAL;
+			}
+			break;
+
+		case RADEON_CMD_SCALARS2:
+			DRM_DEBUG("RADEON_CMD_SCALARS2\n");
+			if (radeon_emit_scalars2( dev_priv, header, &cmdbuf )) {
+				DRM_ERROR("radeon_emit_scalars2 failed\n");
+				return -EINVAL;
+			}
+			break;
+
+		case RADEON_CMD_WAIT:
+			DRM_DEBUG("RADEON_CMD_WAIT\n");
+			if (radeon_emit_wait( dev, header.wait.flags )) {
+				DRM_ERROR("radeon_emit_wait failed\n");
+				return -EINVAL;
+			}
+			break;
+		default:
+			DRM_ERROR("bad cmd_type %d at %p\n", 
+				  header.header.cmd_type,
+				  cmdbuf.buf - sizeof(header));
+			return -EINVAL;
+		}
+	}
+
+
+	DRM_DEBUG("DONE\n");
+	COMMIT_RING();
+	return 0;
+}
+
+
+
+int radeon_cp_getparam(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data)
+{
+        drm_file_t      *priv   = filp->private_data;
+        drm_device_t    *dev    = priv->dev;
+	drm_radeon_private_t *dev_priv = dev->dev_private;
+	drm_radeon_getparam_t param;
+	int value;
+
+	if ( !dev_priv ) {
+		DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+		return -EINVAL;
+	}
+
+	DRM_COPY_FROM_USER_IOCTL( param, (drm_radeon_getparam_t *)data,
+			     sizeof(param) );
+
+	DRM_DEBUG( "pid=%d\n", current->pid );
+
+	switch( param.param ) {
+	case RADEON_PARAM_AGP_BUFFER_OFFSET:
+		value = dev_priv->agp_buffers_offset;
+		break;
+	case RADEON_PARAM_LAST_FRAME:
+		dev_priv->stats.last_frame_reads++;
+		value = GET_SCRATCH( 0 );
+		break;
+	case RADEON_PARAM_LAST_DISPATCH:
+		value = GET_SCRATCH( 1 );
+		break;
+	case RADEON_PARAM_LAST_CLEAR:
+		dev_priv->stats.last_clear_reads++;
+		value = GET_SCRATCH( 2 );
+		break;
+	case RADEON_PARAM_IRQ_NR:
+		value = dev->irq;
+		break;
+	case RADEON_PARAM_AGP_BASE:
+		value = dev_priv->agp_vm_start;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if ( copy_to_user( param.value, &value, sizeof(int) ) ) {
+		DRM_ERROR( "copy_to_user\n" );
+		return -EFAULT;
+	}
+	
 	return 0;
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)