summaryrefslogtreecommitdiff
path: root/shared-core/radeon_state.c
diff options
context:
space:
mode:
authorMichel Daenzer <michel@daenzer.net>2003-11-04 00:46:05 +0000
committerMichel Daenzer <michel@daenzer.net>2003-11-04 00:46:05 +0000
commit2655ccddf4c026f37dcc76754cdfde6f0a4a4c86 (patch)
tree98ae7d93c77d64e24863fb27d5ce8342fd2fe2fa /shared-core/radeon_state.c
parent84dfe702e27e0ef22801f8fe366120bea90adf4f (diff)
Memory layout transition:
the 2D driver initializes MC_FB_LOCATION and related registers sanely the DRM deduces the layout from these registers clients use the new SETPARAM ioctl to tell the DRM where they think the framebuffer is located in the card's address space the DRM uses all this information to check client state and fix it up if necessary This is a prerequisite for things like direct rendering with IGP chips and video capturing.
Diffstat (limited to 'shared-core/radeon_state.c')
-rw-r--r--shared-core/radeon_state.c323
1 files changed, 281 insertions, 42 deletions
diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c
index 833f9698..e24bee8a 100644
--- a/shared-core/radeon_state.c
+++ b/shared-core/radeon_state.c
@@ -36,6 +36,151 @@
/* ================================================================
+ * Helper functions for client state checking and fixup
+ */
+
+static __inline__ int radeon_check_and_fixup_offset( drm_radeon_private_t *dev_priv,
+ drm_file_t *filp_priv,
+ u32 *offset ) {
+ u32 off = *offset;
+
+ if ( off >= dev_priv->fb_location &&
+ off < ( dev_priv->gart_vm_start + dev_priv->gart_size ) )
+ return 0;
+
+ off += filp_priv->radeon_fb_delta;
+
+ DRM_DEBUG( "offset fixed up to 0x%x\n", off );
+
+ if ( off < dev_priv->fb_location ||
+ off >= ( dev_priv->gart_vm_start + dev_priv->gart_size ) )
+ return DRM_ERR( EINVAL );
+
+ *offset = off;
+
+ return 0;
+}
+
+static __inline__ int radeon_check_and_fixup_offset_user( drm_radeon_private_t *dev_priv,
+ drm_file_t *filp_priv,
+ u32 *offset ) {
+ u32 off;
+
+ DRM_GET_USER_UNCHECKED( off, offset );
+
+ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &off ) )
+ return DRM_ERR( EINVAL );
+
+ DRM_PUT_USER_UNCHECKED( offset, off );
+
+ return 0;
+}
+
+static __inline__ int radeon_check_and_fixup_packets( drm_radeon_private_t *dev_priv,
+ drm_file_t *filp_priv,
+ int id,
+ u32 *data ) {
+ if ( id == RADEON_EMIT_PP_MISC &&
+ radeon_check_and_fixup_offset_user( dev_priv, filp_priv,
+ &data[( RADEON_RB3D_DEPTHOFFSET
+ - RADEON_PP_MISC ) / 4] ) ) {
+ DRM_ERROR( "Invalid depth buffer offset\n" );
+ return DRM_ERR( EINVAL );
+ } else if ( id == RADEON_EMIT_PP_CNTL &&
+ radeon_check_and_fixup_offset_user( dev_priv, filp_priv,
+ &data[( RADEON_RB3D_COLOROFFSET
+ - RADEON_PP_CNTL ) / 4] ) ) {
+ DRM_ERROR( "Invalid colour buffer offset\n" );
+ return DRM_ERR( EINVAL );
+ } else if ( id >= R200_EMIT_PP_TXOFFSET_0 &&
+ id <= R200_EMIT_PP_TXOFFSET_5 &&
+ radeon_check_and_fixup_offset_user( dev_priv, filp_priv,
+ &data[0] ) ) {
+ DRM_ERROR( "Invalid R200 texture offset\n" );
+ return DRM_ERR( EINVAL );
+ } else if ( ( id == RADEON_EMIT_PP_TXFILTER_0 || id == RADEON_EMIT_PP_TXFILTER_1 ||
+ id == RADEON_EMIT_PP_TXFILTER_2 /*|| id == RADEON_EMIT_PP_TXFILTER_3 ||
+ id == RADEON_EMIT_PP_TXFILTER_4 || id == RADEON_EMIT_PP_TXFILTER_5*/ ) &&
+ radeon_check_and_fixup_offset_user( dev_priv, filp_priv,
+ &data[( RADEON_PP_TXOFFSET_0
+ - RADEON_PP_TXFILTER_0 ) / 4] ) ) {
+ DRM_ERROR( "Invalid R100 texture offset\n" );
+ return DRM_ERR( EINVAL );
+ } else if ( id == R200_PP_CUBIC_OFFSET_F1_0 || id == R200_PP_CUBIC_OFFSET_F1_1 ||
+ id == R200_PP_CUBIC_OFFSET_F1_2 || id == R200_PP_CUBIC_OFFSET_F1_3 ||
+ id == R200_PP_CUBIC_OFFSET_F1_4 || id == R200_PP_CUBIC_OFFSET_F1_5 ) {
+ int i;
+ for ( i = 0; i < 6; i++ ) {
+ if ( radeon_check_and_fixup_offset_user( dev_priv,
+ filp_priv,
+ &data[i] ) ) {
+ DRM_ERROR( "Invalid R200 cubic texture offset\n" );
+ return DRM_ERR( EINVAL );
+ }
+ }
+ }
+
+ return 0;
+}
+
+static __inline__ int radeon_check_and_fixup_packet3( drm_radeon_private_t *dev_priv,
+ drm_file_t *filp_priv,
+ drm_radeon_cmd_buffer_t *cmdbuf,
+ unsigned int *cmdsz ) {
+ u32 tmp[4], *cmd = ( u32* )cmdbuf->buf;
+
+ if ( DRM_COPY_FROM_USER_UNCHECKED( tmp, cmd, sizeof( tmp ) ) ) {
+ DRM_ERROR( "Failed to copy data from user space\n" );
+ return DRM_ERR( EFAULT );
+ }
+
+ *cmdsz = 2 + ( ( tmp[0] & RADEON_CP_PACKET_COUNT_MASK ) >> 16 );
+
+ if ( ( tmp[0] & 0xc0000000 ) != RADEON_CP_PACKET3 ) {
+ DRM_ERROR( "Not a type 3 packet\n" );
+ return DRM_ERR( EINVAL );
+ }
+
+ if ( 4 * *cmdsz > cmdbuf->bufsz ) {
+ DRM_ERROR( "Packet size larger than size of data provided\n" );
+ return DRM_ERR( EINVAL );
+ }
+
+ /* Check client state and fix it up if necessary */
+ if ( tmp[0] & 0x8000 ) { /* MSB of opcode: next DWORD GUI_CNTL */
+ u32 offset;
+
+ if ( tmp[1] & ( RADEON_GMC_SRC_PITCH_OFFSET_CNTL
+ | RADEON_GMC_DST_PITCH_OFFSET_CNTL ) ) {
+ offset = tmp[2] << 10;
+ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &offset ) ) {
+ DRM_ERROR( "Invalid first packet offset\n" );
+ return DRM_ERR( EINVAL );
+ }
+ tmp[2] = ( tmp[2] & 0xffc00000 ) | offset >> 10;
+ }
+
+ if ( ( tmp[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL ) &&
+ ( tmp[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL ) ) {
+ offset = tmp[3] << 10;
+ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &offset ) ) {
+ DRM_ERROR( "Invalid second packet offset\n" );
+ return DRM_ERR( EINVAL );
+ }
+ tmp[3] = ( tmp[3] & 0xffc00000 ) | offset >> 10;
+ }
+
+ if ( DRM_COPY_TO_USER_UNCHECKED( cmd, tmp, sizeof( tmp ) ) ) {
+ DRM_ERROR( "Failed to copy data to user space\n" );
+ return DRM_ERR( EFAULT );
+ }
+ }
+
+ return 0;
+}
+
+
+/* ================================================================
* CP hardware state programming functions
*/
@@ -57,15 +202,28 @@ static __inline__ void radeon_emit_clip_rect( 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 )
+static int radeon_emit_state( drm_radeon_private_t *dev_priv,
+ drm_file_t *filp_priv,
+ drm_radeon_context_regs_t *ctx,
+ drm_radeon_texture_regs_t *tex,
+ unsigned int dirty )
{
RING_LOCALS;
DRM_DEBUG( "dirty=0x%08x\n", dirty );
if ( dirty & RADEON_UPLOAD_CONTEXT ) {
+ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
+ &ctx->rb3d_depthoffset ) ) {
+ DRM_ERROR( "Invalid depth buffer offset\n" );
+ return DRM_ERR( EINVAL );
+ }
+
+ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
+ &ctx->rb3d_coloroffset ) ) {
+ DRM_ERROR( "Invalid depth buffer offset\n" );
+ return DRM_ERR( EINVAL );
+ }
+
BEGIN_RING( 14 );
OUT_RING( CP_PACKET0( RADEON_PP_MISC, 6 ) );
OUT_RING( ctx->pp_misc );
@@ -149,6 +307,12 @@ static void radeon_emit_state( drm_radeon_private_t *dev_priv,
}
if ( dirty & RADEON_UPLOAD_TEX0 ) {
+ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
+ &tex[0].pp_txoffset ) ) {
+ DRM_ERROR( "Invalid texture offset for unit 0\n" );
+ return DRM_ERR( EINVAL );
+ }
+
BEGIN_RING( 9 );
OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_0, 5 ) );
OUT_RING( tex[0].pp_txfilter );
@@ -163,6 +327,12 @@ static void radeon_emit_state( drm_radeon_private_t *dev_priv,
}
if ( dirty & RADEON_UPLOAD_TEX1 ) {
+ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
+ &tex[1].pp_txoffset ) ) {
+ DRM_ERROR( "Invalid texture offset for unit 1\n" );
+ return DRM_ERR( EINVAL );
+ }
+
BEGIN_RING( 9 );
OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_1, 5 ) );
OUT_RING( tex[1].pp_txfilter );
@@ -177,6 +347,12 @@ static void radeon_emit_state( drm_radeon_private_t *dev_priv,
}
if ( dirty & RADEON_UPLOAD_TEX2 ) {
+ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
+ &tex[2].pp_txoffset ) ) {
+ DRM_ERROR( "Invalid texture offset for unit 2\n" );
+ return DRM_ERR( EINVAL );
+ }
+
BEGIN_RING( 9 );
OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_2, 5 ) );
OUT_RING( tex[2].pp_txfilter );
@@ -189,12 +365,15 @@ static void radeon_emit_state( drm_radeon_private_t *dev_priv,
OUT_RING( tex[2].pp_border_color );
ADVANCE_RING();
}
+
+ return 0;
}
/* Emit 1.2 state
*/
-static void radeon_emit_state2( drm_radeon_private_t *dev_priv,
- drm_radeon_state_t *state )
+static int radeon_emit_state2( drm_radeon_private_t *dev_priv,
+ drm_file_t *filp_priv,
+ drm_radeon_state_t *state )
{
RING_LOCALS;
@@ -206,7 +385,7 @@ static void radeon_emit_state2( drm_radeon_private_t *dev_priv,
ADVANCE_RING();
}
- radeon_emit_state( dev_priv, &state->context,
+ return radeon_emit_state( dev_priv, filp_priv, &state->context,
state->tex, state->dirty );
}
@@ -1065,6 +1244,7 @@ static int radeon_cp_dispatch_texture( DRMFILE filp,
drm_radeon_tex_image_t *image )
{
drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_file_t *filp_priv;
drm_buf_t *buf;
u32 format;
u32 *buffer;
@@ -1074,6 +1254,13 @@ static int radeon_cp_dispatch_texture( DRMFILE filp,
int i;
RING_LOCALS;
+ DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
+ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &tex->offset ) ) {
+ DRM_ERROR( "Invalid destination offset\n" );
+ return DRM_ERR( EINVAL );
+ }
+
dev_priv->stats.boxes |= RADEON_BOX_TEXTURE_LOAD;
/* Flush the pixel cache. This ensures no pixel data gets mixed
@@ -1377,6 +1564,7 @@ int radeon_cp_vertex( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_file_t *filp_priv;
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_device_dma_t *dma = dev->dma;
drm_buf_t *buf;
@@ -1390,6 +1578,8 @@ int radeon_cp_vertex( DRM_IOCTL_ARGS )
return DRM_ERR(EINVAL);
}
+ DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
DRM_COPY_FROM_USER_IOCTL( vertex, (drm_radeon_vertex_t *)data,
sizeof(vertex) );
@@ -1429,11 +1619,14 @@ int radeon_cp_vertex( DRM_IOCTL_ARGS )
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 );
-
+ if ( radeon_emit_state( dev_priv, filp_priv,
+ &sarea_priv->context_state,
+ sarea_priv->tex_state,
+ sarea_priv->dirty ) ) {
+ DRM_ERROR( "radeon_emit_state failed\n" );
+ return DRM_ERR( EINVAL );
+ }
+
sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
RADEON_UPLOAD_TEX1IMAGES |
RADEON_UPLOAD_TEX2IMAGES |
@@ -1461,6 +1654,7 @@ int radeon_cp_indices( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_file_t *filp_priv;
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_device_dma_t *dma = dev->dma;
drm_buf_t *buf;
@@ -1475,6 +1669,8 @@ int radeon_cp_indices( DRM_IOCTL_ARGS )
return DRM_ERR(EINVAL);
}
+ DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
DRM_COPY_FROM_USER_IOCTL( elts, (drm_radeon_indices_t *)data,
sizeof(elts) );
@@ -1523,10 +1719,13 @@ int radeon_cp_indices( DRM_IOCTL_ARGS )
buf->used = elts.end;
if ( sarea_priv->dirty & ~RADEON_UPLOAD_CLIPRECTS ) {
- radeon_emit_state( dev_priv,
- &sarea_priv->context_state,
- sarea_priv->tex_state,
- sarea_priv->dirty );
+ if ( radeon_emit_state( dev_priv, filp_priv,
+ &sarea_priv->context_state,
+ sarea_priv->tex_state,
+ sarea_priv->dirty ) ) {
+ DRM_ERROR( "radeon_emit_state failed\n" );
+ return DRM_ERR( EINVAL );
+ }
sarea_priv->dirty &= ~(RADEON_UPLOAD_TEX0IMAGES |
RADEON_UPLOAD_TEX1IMAGES |
@@ -1686,6 +1885,7 @@ int radeon_cp_vertex2( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_file_t *filp_priv;
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_device_dma_t *dma = dev->dma;
drm_buf_t *buf;
@@ -1700,6 +1900,8 @@ int radeon_cp_vertex2( DRM_IOCTL_ARGS )
return DRM_ERR(EINVAL);
}
+ DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
DRM_COPY_FROM_USER_IOCTL( vertex, (drm_radeon_vertex2_t *)data,
sizeof(vertex) );
@@ -1747,7 +1949,10 @@ int radeon_cp_vertex2( DRM_IOCTL_ARGS )
sizeof(state) ) )
return DRM_ERR(EFAULT);
- radeon_emit_state2( dev_priv, &state );
+ if ( radeon_emit_state2( dev_priv, filp_priv, &state ) ) {
+ DRM_ERROR( "radeon_emit_state2 failed\n" );
+ return DRM_ERR( EINVAL );
+ }
laststate = prim.stateidx;
}
@@ -1784,6 +1989,7 @@ int radeon_cp_vertex2( DRM_IOCTL_ARGS )
static int radeon_emit_packets(
drm_radeon_private_t *dev_priv,
+ drm_file_t *filp_priv,
drm_radeon_cmd_header_t header,
drm_radeon_cmd_buffer_t *cmdbuf )
{
@@ -1798,8 +2004,15 @@ static int radeon_emit_packets(
sz = packet[id].len;
reg = packet[id].start;
- if (sz * sizeof(int) > cmdbuf->bufsz)
+ if (sz * sizeof(int) > cmdbuf->bufsz) {
+ DRM_ERROR( "Packet size provided larger than data provided\n" );
return DRM_ERR(EINVAL);
+ }
+
+ if ( radeon_check_and_fixup_packets( dev_priv, filp_priv, id, data ) ) {
+ DRM_ERROR( "Packet verification failed\n" );
+ return DRM_ERR( EINVAL );
+ }
BEGIN_RING(sz+1);
OUT_RING( CP_PACKET0( reg, (sz-1) ) );
@@ -1882,24 +2095,21 @@ static __inline__ int radeon_emit_vectors(
static int radeon_emit_packet3( drm_device_t *dev,
+ drm_file_t *filp_priv,
drm_radeon_cmd_buffer_t *cmdbuf )
{
drm_radeon_private_t *dev_priv = dev->dev_private;
- int cmdsz, tmp;
- int *cmd = (int *)cmdbuf->buf;
+ unsigned int cmdsz;
+ int *cmd = (int *)cmdbuf->buf, ret;
RING_LOCALS;
-
DRM_DEBUG("\n");
- if (DRM_GET_USER_UNCHECKED( tmp, &cmd[0]))
- return DRM_ERR(EFAULT);
-
- cmdsz = 2 + ((tmp & RADEON_CP_PACKET_COUNT_MASK) >> 16);
-
- if ((tmp & 0xc0000000) != RADEON_CP_PACKET3 ||
- cmdsz * 4 > cmdbuf->bufsz)
- return DRM_ERR(EINVAL);
+ if ( ( ret = radeon_check_and_fixup_packet3( dev_priv, filp_priv,
+ cmdbuf, &cmdsz ) ) ) {
+ DRM_ERROR( "Packet verification failed\n" );
+ return ret;
+ }
BEGIN_RING( cmdsz );
OUT_RING_USER_TABLE( cmd, cmdsz );
@@ -1912,27 +2122,25 @@ static int radeon_emit_packet3( drm_device_t *dev,
static int radeon_emit_packet3_cliprect( drm_device_t *dev,
+ drm_file_t *filp_priv,
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;
+ unsigned int cmdsz;
+ int *cmd = (int *)cmdbuf->buf, ret;
drm_clip_rect_t *boxes = cmdbuf->boxes;
int i = 0;
RING_LOCALS;
DRM_DEBUG("\n");
- if (DRM_GET_USER_UNCHECKED( tmp, &cmd[0]))
- return DRM_ERR(EFAULT);
-
- cmdsz = 2 + ((tmp & RADEON_CP_PACKET_COUNT_MASK) >> 16);
-
- if ((tmp & 0xc0000000) != RADEON_CP_PACKET3 ||
- cmdsz * 4 > cmdbuf->bufsz)
- return DRM_ERR(EINVAL);
+ if ( ( ret = radeon_check_and_fixup_packet3( dev_priv, filp_priv,
+ cmdbuf, &cmdsz ) ) ) {
+ DRM_ERROR( "Packet verification failed\n" );
+ return ret;
+ }
if (!orig_nbox)
goto out;
@@ -2009,6 +2217,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_file_t *filp_priv;
drm_device_dma_t *dma = dev->dma;
drm_buf_t *buf = 0;
int idx;
@@ -2023,6 +2232,8 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
return DRM_ERR(EINVAL);
}
+ DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
DRM_COPY_FROM_USER_IOCTL( cmdbuf, (drm_radeon_cmd_buffer_t *)data,
sizeof(cmdbuf) );
@@ -2053,7 +2264,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
switch (header.header.cmd_type) {
case RADEON_CMD_PACKET:
DRM_DEBUG("RADEON_CMD_PACKET\n");
- if (radeon_emit_packets( dev_priv, header, &cmdbuf )) {
+ if (radeon_emit_packets( dev_priv, filp_priv, header, &cmdbuf )) {
DRM_ERROR("radeon_emit_packets failed\n");
return DRM_ERR(EINVAL);
}
@@ -2096,7 +2307,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
case RADEON_CMD_PACKET3:
DRM_DEBUG("RADEON_CMD_PACKET3\n");
- if (radeon_emit_packet3( dev, &cmdbuf )) {
+ if (radeon_emit_packet3( dev, filp_priv, &cmdbuf )) {
DRM_ERROR("radeon_emit_packet3 failed\n");
return DRM_ERR(EINVAL);
}
@@ -2104,7 +2315,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
case RADEON_CMD_PACKET3_CLIP:
DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n");
- if (radeon_emit_packet3_cliprect( dev, &cmdbuf, orig_nbox )) {
+ if (radeon_emit_packet3_cliprect( dev, filp_priv, &cmdbuf, orig_nbox )) {
DRM_ERROR("radeon_emit_packet3_clip failed\n");
return DRM_ERR(EINVAL);
}
@@ -2203,3 +2414,31 @@ int radeon_cp_getparam( DRM_IOCTL_ARGS )
return 0;
}
+
+int radeon_cp_setparam( DRM_IOCTL_ARGS ) {
+ DRM_DEVICE;
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_file_t *filp_priv;
+ drm_radeon_setparam_t sp;
+
+ if ( !dev_priv ) {
+ DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+ return DRM_ERR( EINVAL );
+ }
+
+ DRM_GET_PRIV_WITH_RETURN( filp_priv, filp );
+
+ DRM_COPY_FROM_USER_IOCTL( sp, ( drm_radeon_setparam_t* )data,
+ sizeof( sp ) );
+
+ switch( sp.param ) {
+ case RADEON_SETPARAM_FB_LOCATION:
+ filp_priv->radeon_fb_delta = dev_priv->fb_location - sp.value;
+ break;
+ default:
+ DRM_DEBUG( "Invalid parameter %d\n", sp.param );
+ return DRM_ERR( EINVAL );
+ }
+
+ return 0;
+}