diff options
author | daenzer <daenzer> | 2003-11-04 00:46:04 +0000 |
---|---|---|
committer | daenzer <daenzer> | 2003-11-04 00:46:04 +0000 |
commit | f16ad3b582846cbdbffda8fb35fb15c6c659a6f2 (patch) | |
tree | eca840e56ab0e00e3c8c0da969af0c9746eefddc | |
parent | 59a31925ce7320a09c0f71e5919c0d81ccb07f68 (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.
32 files changed, 510 insertions, 120 deletions
diff --git a/xc/lib/GL/mesa/src/drv/r200/r200_ioctl.c b/xc/lib/GL/mesa/src/drv/r200/r200_ioctl.c index 458b51913..284cd47b9 100644 --- a/xc/lib/GL/mesa/src/drv/r200/r200_ioctl.c +++ b/xc/lib/GL/mesa/src/drv/r200/r200_ioctl.c @@ -531,7 +531,8 @@ void r200PageFlip( const __DRIdrawablePrivate *dPriv ) } R200_STATECHANGE( rmesa, ctx ); - rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = rmesa->state.color.drawOffset; + rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = rmesa->state.color.drawOffset + + rmesa->r200Screen->fbLocation; rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] = rmesa->state.color.drawPitch; } diff --git a/xc/lib/GL/mesa/src/drv/r200/r200_lock.c b/xc/lib/GL/mesa/src/drv/r200/r200_lock.c index 9d6cff50a..3c3356eec 100644 --- a/xc/lib/GL/mesa/src/drv/r200/r200_lock.c +++ b/xc/lib/GL/mesa/src/drv/r200/r200_lock.c @@ -64,7 +64,8 @@ r200UpdatePageFlipping( r200ContextPtr rmesa ) } R200_STATECHANGE( rmesa, ctx ); - rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = rmesa->state.color.drawOffset; + rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = rmesa->state.color.drawOffset + + rmesa->r200Screen->fbLocation; rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] = rmesa->state.color.drawPitch; } diff --git a/xc/lib/GL/mesa/src/drv/r200/r200_pixel.c b/xc/lib/GL/mesa/src/drv/r200/r200_pixel.c index 29eab6cd2..806484404 100644 --- a/xc/lib/GL/mesa/src/drv/r200/r200_pixel.c +++ b/xc/lib/GL/mesa/src/drv/r200/r200_pixel.c @@ -215,7 +215,8 @@ r200TryReadPixels( GLcontext *ctx, { __DRIdrawablePrivate *dPriv = rmesa->dri.drawable; int nbox = dPriv->numClipRects; - int src_offset = rmesa->state.color.drawOffset; + int src_offset = rmesa->state.color.drawOffset + + rmesa->r200Screen->fbLocation; int src_pitch = rmesa->state.color.drawPitch * rmesa->r200Screen->cpp; int dst_offset = r200GartOffsetFromVirtual( rmesa, pixels ); int dst_pitch = pitch * rmesa->r200Screen->cpp; @@ -288,7 +289,7 @@ static void do_draw_pix( GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLint pitch, const void *pixels, - GLuint dest, GLuint planemask) + GLuint planemask) { r200ContextPtr rmesa = R200_CONTEXT(ctx); __DRIdrawablePrivate *dPriv = rmesa->dri.drawable; @@ -354,7 +355,7 @@ static void do_draw_pix( GLcontext *ctx, blit_format, src_pitch, src_offset, rmesa->state.color.drawPitch * rmesa->r200Screen->cpp, - rmesa->state.color.drawOffset, + rmesa->state.color.drawOffset + rmesa->r200Screen->fbLocation, bx - x, by - y, bx, by, bw, bh ); @@ -377,7 +378,7 @@ r200TryDrawPixels( GLcontext *ctx, { r200ContextPtr rmesa = R200_CONTEXT(ctx); GLint pitch = unpack->RowLength ? unpack->RowLength : width; - GLuint dest, planemask; + GLuint planemask; GLuint cpp = rmesa->r200Screen->cpp; GLint size = width * pitch * cpp; @@ -388,8 +389,6 @@ r200TryDrawPixels( GLcontext *ctx, case GL_RGB: case GL_RGBA: case GL_BGRA: - dest = rmesa->state.color.drawOffset; - planemask = r200PackColor(cpp, ctx->Color.ColorMask[RCOMP], ctx->Color.ColorMask[GCOMP], @@ -428,8 +427,7 @@ r200TryDrawPixels( GLcontext *ctx, if ( r200IsGartMemory(rmesa, pixels, size) ) { - do_draw_pix( ctx, x, y, width, height, pitch, pixels, - dest, planemask ); + do_draw_pix( ctx, x, y, width, height, pitch, pixels, planemask ); return GL_TRUE; } else if (0) diff --git a/xc/lib/GL/mesa/src/drv/r200/r200_screen.c b/xc/lib/GL/mesa/src/drv/r200/r200_screen.c index 268d38ffb..332c89d55 100644 --- a/xc/lib/GL/mesa/src/drv/r200/r200_screen.c +++ b/xc/lib/GL/mesa/src/drv/r200/r200_screen.c @@ -76,6 +76,7 @@ r200CreateScreen( __DRIscreenPrivate *sPriv ) { r200ScreenPtr screen; RADEONDRIPtr dri_priv = (RADEONDRIPtr)sPriv->pDevPriv; + unsigned char *RADEONMMIO; if ( ! driCheckDriDdxDrmVersions( sPriv, "R200", 4, 0, 4, 0, 1, 5 ) ) return NULL; @@ -170,6 +171,8 @@ r200CreateScreen( __DRIscreenPrivate *sPriv ) return NULL; } + RADEONMMIO = screen->mmio.map; + screen->status.handle = dri_priv->statusHandle; screen->status.size = dri_priv->statusSize; if ( drmMap( sPriv->fd, @@ -194,8 +197,6 @@ r200CreateScreen( __DRIscreenPrivate *sPriv ) } if ( dri_priv->gartTexHandle && dri_priv->gartTexMapSize ) { - unsigned char *RADEONMMIO = screen->mmio.map; - screen->gartTextures.handle = dri_priv->gartTexHandle; screen->gartTextures.size = dri_priv->gartTexMapSize; if ( drmMap( sPriv->fd, @@ -218,6 +219,18 @@ r200CreateScreen( __DRIscreenPrivate *sPriv ) screen->cpp = dri_priv->bpp / 8; screen->AGPMode = dri_priv->AGPMode; + screen->fbLocation = ( INREG( RADEON_MC_FB_LOCATION ) & 0xffff ) << 16; + + if ( sPriv->drmMinor >= 10 ) { + drmRadeonSetParam sp; + + sp.param = RADEON_SETPARAM_FB_LOCATION; + sp.value = screen->fbLocation; + + drmCommandWrite( sPriv->fd, DRM_RADEON_SETPARAM, + &sp, sizeof( sp ) ); + } + screen->frontOffset = dri_priv->frontOffset; screen->frontPitch = dri_priv->frontPitch; screen->backOffset = dri_priv->backOffset; diff --git a/xc/lib/GL/mesa/src/drv/r200/r200_screen.h b/xc/lib/GL/mesa/src/drv/r200/r200_screen.h index 3ed4f5502..6b12227ec 100644 --- a/xc/lib/GL/mesa/src/drv/r200/r200_screen.h +++ b/xc/lib/GL/mesa/src/drv/r200/r200_screen.h @@ -64,6 +64,7 @@ typedef struct { int AGPMode; unsigned int irq; /* IRQ number (0 means none) */ + unsigned int fbLocation; unsigned int frontOffset; unsigned int frontPitch; unsigned int backOffset; diff --git a/xc/lib/GL/mesa/src/drv/r200/r200_state.c b/xc/lib/GL/mesa/src/drv/r200/r200_state.c index b501f9111..5e10b52c0 100644 --- a/xc/lib/GL/mesa/src/drv/r200/r200_state.c +++ b/xc/lib/GL/mesa/src/drv/r200/r200_state.c @@ -1646,8 +1646,9 @@ static void r200DrawBuffer( GLcontext *ctx, GLenum mode ) _swrast_DrawBuffer(ctx, mode); R200_STATECHANGE( rmesa, ctx ); - rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = (rmesa->state.color.drawOffset & - R200_COLOROFFSET_MASK); + rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = ((rmesa->state.color.drawOffset + + rmesa->r200Screen->fbLocation) + & R200_COLOROFFSET_MASK); rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] = rmesa->state.color.drawPitch; } diff --git a/xc/lib/GL/mesa/src/drv/r200/r200_state_init.c b/xc/lib/GL/mesa/src/drv/r200/r200_state_init.c index 006e8d82a..1afd59c27 100644 --- a/xc/lib/GL/mesa/src/drv/r200/r200_state_init.c +++ b/xc/lib/GL/mesa/src/drv/r200/r200_state_init.c @@ -365,7 +365,7 @@ void r200InitState( r200ContextPtr rmesa ) R200_DST_BLEND_GL_ZERO ); rmesa->hw.ctx.cmd[CTX_RB3D_DEPTHOFFSET] = - rmesa->r200Screen->depthOffset; + rmesa->r200Screen->depthOffset + rmesa->r200Screen->fbLocation; rmesa->hw.ctx.cmd[CTX_RB3D_DEPTHPITCH] = ((rmesa->r200Screen->depthPitch & @@ -403,8 +403,9 @@ void r200InitState( r200ContextPtr rmesa ) else rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= rmesa->state.color.roundEnable; - rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = (rmesa->state.color.drawOffset & - R200_COLOROFFSET_MASK); + rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = ((rmesa->state.color.drawOffset + + rmesa->r200Screen->fbLocation) + & R200_COLOROFFSET_MASK); rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] = ((rmesa->state.color.drawPitch & R200_COLORPITCH_MASK) | diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_ioctl.c b/xc/lib/GL/mesa/src/drv/radeon/radeon_ioctl.c index 93bfa3bc1..483733305 100644 --- a/xc/lib/GL/mesa/src/drv/radeon/radeon_ioctl.c +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_ioctl.c @@ -920,7 +920,8 @@ void radeonPageFlip( const __DRIdrawablePrivate *dPriv ) } RADEON_STATECHANGE( rmesa, ctx ); - rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = rmesa->state.color.drawOffset; + rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = rmesa->state.color.drawOffset + + rmesa->radeonScreen->fbLocation; rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] = rmesa->state.color.drawPitch; } diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_lock.c b/xc/lib/GL/mesa/src/drv/radeon/radeon_lock.c index daf001e04..fb285157a 100644 --- a/xc/lib/GL/mesa/src/drv/radeon/radeon_lock.c +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_lock.c @@ -73,7 +73,8 @@ radeonUpdatePageFlipping( radeonContextPtr rmesa ) } RADEON_STATECHANGE( rmesa, ctx ); - rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = rmesa->state.color.drawOffset; + rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = rmesa->state.color.drawOffset + + rmesa->radeonScreen->fbLocation; rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] = rmesa->state.color.drawPitch; } diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_screen.c b/xc/lib/GL/mesa/src/drv/radeon/radeon_screen.c index 75221c61d..c861fe590 100644 --- a/xc/lib/GL/mesa/src/drv/radeon/radeon_screen.c +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_screen.c @@ -75,6 +75,7 @@ radeonScreenPtr radeonCreateScreen( __DRIscreenPrivate *sPriv ) { radeonScreenPtr screen; RADEONDRIPtr dri_priv = (RADEONDRIPtr)sPriv->pDevPriv; + unsigned char *RADEONMMIO; if ( ! driCheckDriDdxDrmVersions( sPriv, "Radeon", 4, 0, 4, 0, 1, 3 ) ) return NULL; @@ -135,6 +136,8 @@ radeonScreenPtr radeonCreateScreen( __DRIscreenPrivate *sPriv ) return NULL; } + RADEONMMIO = screen->mmio.map; + screen->status.handle = dri_priv->statusHandle; screen->status.size = dri_priv->statusSize; if ( drmMap( sPriv->fd, @@ -159,8 +162,6 @@ radeonScreenPtr radeonCreateScreen( __DRIscreenPrivate *sPriv ) } if ( dri_priv->gartTexHandle && dri_priv->gartTexMapSize ) { - unsigned char *RADEONMMIO = screen->mmio.map; - screen->gartTextures.handle = dri_priv->gartTexHandle; screen->gartTextures.size = dri_priv->gartTexMapSize; if ( drmMap( sPriv->fd, @@ -201,6 +202,18 @@ radeonScreenPtr radeonCreateScreen( __DRIscreenPrivate *sPriv ) screen->cpp = dri_priv->bpp / 8; screen->AGPMode = dri_priv->AGPMode; + screen->fbLocation = ( INREG( RADEON_MC_FB_LOCATION ) & 0xffff ) << 16; + + if ( sPriv->drmMinor >= 10 ) { + drmRadeonSetParam sp; + + sp.param = RADEON_SETPARAM_FB_LOCATION; + sp.value = screen->fbLocation; + + drmCommandWrite( sPriv->fd, DRM_RADEON_SETPARAM, + &sp, sizeof( sp ) ); + } + screen->frontOffset = dri_priv->frontOffset; screen->frontPitch = dri_priv->frontPitch; screen->backOffset = dri_priv->backOffset; diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_screen.h b/xc/lib/GL/mesa/src/drv/radeon/radeon_screen.h index 133c3633c..4a0f6d47f 100644 --- a/xc/lib/GL/mesa/src/drv/radeon/radeon_screen.h +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_screen.h @@ -68,6 +68,7 @@ typedef struct { int AGPMode; unsigned int irq; /* IRQ number (0 means none) */ + unsigned int fbLocation; unsigned int frontOffset; unsigned int frontPitch; unsigned int backOffset; diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_state.c b/xc/lib/GL/mesa/src/drv/radeon/radeon_state.c index f33183b29..c291701d3 100644 --- a/xc/lib/GL/mesa/src/drv/radeon/radeon_state.c +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_state.c @@ -1617,8 +1617,9 @@ static void radeonDrawBuffer( GLcontext *ctx, GLenum mode ) _swrast_DrawBuffer(ctx, mode); RADEON_STATECHANGE( rmesa, ctx ); - rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = (rmesa->state.color.drawOffset & - RADEON_COLOROFFSET_MASK); + rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = ((rmesa->state.color.drawOffset + + rmesa->radeonScreen->fbLocation) + & RADEON_COLOROFFSET_MASK); rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] = rmesa->state.color.drawPitch; } diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_state_init.c b/xc/lib/GL/mesa/src/drv/radeon/radeon_state_init.c index a43084ead..09ec4417b 100644 --- a/xc/lib/GL/mesa/src/drv/radeon/radeon_state_init.c +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_state_init.c @@ -324,7 +324,7 @@ void radeonInitState( radeonContextPtr rmesa ) RADEON_DST_BLEND_GL_ZERO ); rmesa->hw.ctx.cmd[CTX_RB3D_DEPTHOFFSET] = - rmesa->radeonScreen->depthOffset; + rmesa->radeonScreen->depthOffset + rmesa->radeonScreen->fbLocation; rmesa->hw.ctx.cmd[CTX_RB3D_DEPTHPITCH] = ((rmesa->radeonScreen->depthPitch & @@ -365,8 +365,9 @@ void radeonInitState( radeonContextPtr rmesa ) else rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= rmesa->state.color.roundEnable; - rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = (rmesa->state.color.drawOffset & - RADEON_COLOROFFSET_MASK); + rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = ((rmesa->state.color.drawOffset + + rmesa->radeonScreen->fbLocation) + & RADEON_COLOROFFSET_MASK); rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] = ((rmesa->state.color.drawPitch & RADEON_COLORPITCH_MASK) | diff --git a/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon.h b/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon.h index 7121c9305..625dd0c65 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon.h +++ b/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon.h @@ -499,6 +499,7 @@ typedef struct { int depthX; int depthY; + unsigned int fbLocation; int frontOffset; int frontPitch; int backOffset; diff --git a/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_accel.c b/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_accel.c index 8556cc25f..58d883614 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_accel.c +++ b/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_accel.c @@ -283,8 +283,8 @@ void RADEONEngineRestore(ScrnInfoPtr pScrn) pitch64 = ((pScrn->displayWidth * (pScrn->bitsPerPixel / 8) + 0x3f)) >> 6; RADEONWaitForFifo(pScrn, 1); - OUTREG(RADEON_DEFAULT_OFFSET, ((INREG(RADEON_DISPLAY_BASE_ADDR) >> 10) - | (pitch64 << 22))); + OUTREG(RADEON_DEFAULT_OFFSET, ((info->fbLocation >> 10) + | (pitch64 << 22))); RADEONWaitForFifo(pScrn, 1); #if X_BYTE_ORDER == X_BIG_ENDIAN @@ -329,15 +329,6 @@ void RADEONEngineInit(ScrnInfoPtr pScrn) info->CurrentLayout.bitsPerPixel)); OUTREG(RADEON_RB3D_CNTL, 0); -#if defined(__powerpc__) -#if defined(XF86_DRI) - if(!info->directRenderingEnabled) -#endif - { - OUTREG(RADEON_MC_FB_LOCATION, 0xffff0000); - OUTREG(RADEON_MC_AGP_LOCATION, 0xfffff000); - } -#endif RADEONEngineReset(pScrn); diff --git a/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_accelfuncs.c b/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_accelfuncs.c index 843fd6bb7..c1eb29ec8 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_accelfuncs.c +++ b/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_accelfuncs.c @@ -181,8 +181,8 @@ FUNC_NAME(RADEONRestoreAccelState)(ScrnInfoPtr pScrn) pitch64 = ((pScrn->displayWidth * (pScrn->bitsPerPixel / 8) + 0x3f)) >> 6; - OUTREG(RADEON_DEFAULT_OFFSET, (((INREG(RADEON_DISPLAY_BASE_ADDR) + pScrn->fbOffset) >> 10) | - (pitch64 << 22))); + OUTREG(RADEON_DEFAULT_OFFSET, ((info->fbLocation + pScrn->fbOffset) >> 10) + | (pitch64 << 22)); /* FIXME: May need to restore other things, like BKGD_CLK FG_CLK... */ diff --git a/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_common.h b/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_common.h index 31e2a0b77..2193e7698 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_common.h +++ b/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_common.h @@ -38,6 +38,7 @@ #ifndef _RADEON_COMMON_H_ #define _RADEON_COMMON_H_ +#include <inttypes.h> #include "xf86drm.h" /* WARNING: If you change any of these defines, make sure to change @@ -71,6 +72,7 @@ #define DRM_RADEON_IRQ_EMIT 0x16 #define DRM_RADEON_IRQ_WAIT 0x17 #define DRM_RADEON_CP_RESUME 0x18 +#define DRM_RADEON_SETPARAM 0x19 #define DRM_RADEON_MAX_DRM_COMMAND_INDEX 0x39 @@ -159,7 +161,7 @@ typedef struct { } drmRadeonTexImage; typedef struct { - int offset; + unsigned int offset; int pitch; int format; int width; /* Texture image coordinates */ @@ -445,4 +447,16 @@ typedef struct drm_radeon_irq_wait { } drmRadeonIrqWait; +/* 1.10: Clients tell the DRM where they think the framebuffer is located in + * the card's address space, via a new generic ioctl to set parameters + */ + +typedef struct drm_radeon_set_param { + unsigned int param; + int64_t value; +} drmRadeonSetParam; + +#define RADEON_SETPARAM_FB_LOCATION 1 + + #endif diff --git a/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c b/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c index 3a9d9f943..33220dac3 100644 --- a/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c +++ b/xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c @@ -1982,6 +1982,61 @@ static Bool RADEONPreInitWeight(ScrnInfoPtr pScrn) return TRUE; } +/* Set up MC_FB_LOCATION and related registers */ +static void +RADEONSetFBLocation(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + CARD32 mc_fb_location; + CARD32 mc_agp_location = INREG(RADEON_MC_AGP_LOCATION); + + if (info->IsIGP) { + mc_fb_location = INREG(RADEON_NB_TOM); + + OUTREG(RADEON_GRPH2_BUFFER_CNTL, + INREG(RADEON_GRPH2_BUFFER_CNTL) & ~0x7f0000); + + if ((info->ChipFamily == CHIP_FAMILY_RS100) || + (info->ChipFamily == CHIP_FAMILY_RS200)) { + /* This is to workaround the asic bug for RMX, some versions + of BIOS don't have this register initialized correctly. + */ + OUTREGP(RADEON_CRTC_MORE_CNTL, RADEON_CRTC_H_CUTOFF_ACTIVE_EN, + ~RADEON_CRTC_H_CUTOFF_ACTIVE_EN); + } + } else +#ifdef XF86DRI + if ( info->directRenderingEnabled && info->drmMinor < 10 ) { + mc_fb_location = (INREG(RADEON_CONFIG_APER_SIZE) - 1) & 0xffff0000U; + } else +#endif + { + CARD32 aper0_base = INREG(RADEON_CONFIG_APER_0_BASE); + + mc_fb_location = (aper0_base >> 16) + | ((aper0_base + (INREG(RADEON_CONFIG_APER_SIZE) - 1) + ) & 0xffff0000U); + } + + info->fbLocation = (mc_fb_location & 0xffff) << 16; + + if (((mc_agp_location & 0xffff) << 16) != + ((mc_fb_location & 0xffff0000U) + 0x10000)) { + mc_agp_location = mc_fb_location & 0xffff0000U; + mc_agp_location |= (mc_agp_location + 0x10000) >> 16; + } + + RADEONWaitForIdleMMIO(pScrn); + + OUTREG(RADEON_MC_FB_LOCATION, mc_fb_location); + OUTREG(RADEON_MC_AGP_LOCATION, mc_agp_location); + OUTREG(RADEON_DISPLAY_BASE_ADDR, info->fbLocation); + if (info->HasCRTC2) + OUTREG(RADEON_DISPLAY2_BASE_ADDR, info->fbLocation); + OUTREG(RADEON_OV0_BASE_ADDR, info->fbLocation); +} + static void RADEONGetVRamType(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); @@ -2226,34 +2281,18 @@ static Bool RADEONPreInitConfig(ScrnInfoPtr pScrn) from = X_PROBED; if (info->FBDev) pScrn->videoRam = fbdevHWGetVidmem(pScrn) / 1024; - else if ((info->ChipFamily == CHIP_FAMILY_RS100) || + else if ((info->ChipFamily == CHIP_FAMILY_RS100) || (info->ChipFamily == CHIP_FAMILY_RS200) || (info->ChipFamily == CHIP_FAMILY_RS300)) { CARD32 tom = INREG(RADEON_NB_TOM); - pScrn->videoRam = (((tom >> 16) - - (tom & 0xffff) + 1) << 6); - OUTREG(RADEON_MC_FB_LOCATION, tom); - OUTREG(RADEON_DISPLAY_BASE_ADDR, (tom & 0xffff) << 16); - OUTREG(RADEON_DISPLAY2_BASE_ADDR, (tom & 0xffff) << 16); - OUTREG(RADEON_OV0_BASE_ADDR, (tom & 0xffff) << 16); - /* This is supposed to fix the crtc2 noise problem. - */ - OUTREG(RADEON_GRPH2_BUFFER_CNTL, - INREG(RADEON_GRPH2_BUFFER_CNTL) & ~0x7f0000); - - if ((info->ChipFamily == CHIP_FAMILY_RS100) || - (info->ChipFamily == CHIP_FAMILY_RS200)) { - /* This is to workaround the asic bug for RMX, some versions - of BIOS dosen't have this register initialized correctly. - */ - OUTREGP(RADEON_CRTC_MORE_CNTL, RADEON_CRTC_H_CUTOFF_ACTIVE_EN, - ~RADEON_CRTC_H_CUTOFF_ACTIVE_EN); - } + pScrn->videoRam = (((tom >> 16) - + (tom & 0xffff) + 1) << 6); - } - else + OUTREG(RADEON_CONFIG_MEMSIZE, pScrn->videoRam * 1024); + } else { pScrn->videoRam = INREG(RADEON_CONFIG_MEMSIZE) / 1024; + } /* Some production boards of m6 will return 0 if it's 8 MB */ if (pScrn->videoRam == 0) pScrn->videoRam = 8192; @@ -4397,6 +4436,8 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) } #endif + RADEONSetFBLocation(pScrn); + if (!fbScreenInit(pScreen, info->FB, pScrn->virtualX, pScrn->virtualY, pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth, @@ -4628,13 +4669,13 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) info->textureSize/1024, info->textureOffset); info->frontPitchOffset = (((info->frontPitch * cpp / 64) << 22) | - (info->frontOffset >> 10)); + ((info->frontOffset + info->fbLocation) >> 10)); info->backPitchOffset = (((info->backPitch * cpp / 64) << 22) | - (info->backOffset >> 10)); + ((info->backOffset + info->fbLocation) >> 10)); info->depthPitchOffset = (((info->depthPitch * cpp / 64) << 22) | - (info->depthOffset >> 10)); + ((info->depthOffset + info->fbLocation) >> 10)); } else #endif { diff --git a/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drmP.h b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drmP.h index eec3faed4..2bbe2733d 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drmP.h +++ b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drmP.h @@ -210,6 +210,9 @@ struct drm_file { drm_magic_t magic; unsigned long ioctl_count; struct drm_device *devXX; +#ifdef DRIVER_FILE_FIELDS + DRIVER_FILE_FIELDS; +#endif }; typedef struct drm_lock_data { diff --git a/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_drv.h b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_drv.h index 3f4946949..911e7f705 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_drv.h +++ b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_drv.h @@ -101,6 +101,9 @@ #ifndef DRIVER_IOCTLS #define DRIVER_IOCTLS #endif +#ifndef DRIVER_OPEN_HELPER +#define DRIVER_OPEN_HELPER( priv, dev ) +#endif #ifndef DRIVER_FOPS #endif diff --git a/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_fops.h b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_fops.h index 3c4553dec..55ef8ce0c 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_fops.h +++ b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_fops.h @@ -88,6 +88,9 @@ int DRM(open_helper)(dev_t kdev, int flags, int fmt, DRM_STRUCTPROC *p, priv->devXX = dev; priv->ioctl_count = 0; priv->authenticated = !DRM_SUSER(p); + + DRIVER_OPEN_HELPER( priv, dev ); + TAILQ_INSERT_TAIL(&dev->files, priv, link); } DRM_UNLOCK(); diff --git a/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_os_freebsd.h b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_os_freebsd.h index 4822b0569..480a53f59 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_os_freebsd.h +++ b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_os_freebsd.h @@ -267,6 +267,8 @@ for ( ret = 0 ; !ret && !(condition) ; ) { \ (!useracc((caddr_t)uaddr, size, VM_PROT_READ)) #define DRM_COPY_FROM_USER_UNCHECKED(arg1, arg2, arg3) \ copyin(arg2, arg1, arg3) +#define DRM_COPY_TO_USER_UNCHECKED(arg1, arg2, arg3) \ + copyout(arg2, arg1, arg3) #define DRM_GET_USER_UNCHECKED(val, uaddr) \ ((val) = fuword(uaddr), 0) #define DRM_PUT_USER_UNCHECKED(val, uaddr) \ diff --git a/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_os_netbsd.h b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_os_netbsd.h index 4c95c50f6..47b8f5017 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_os_netbsd.h +++ b/xc/programs/Xserver/hw/xfree86/os-support/bsd/drm/kernel/drm_os_netbsd.h @@ -215,6 +215,8 @@ while (!condition) { \ (!uvm_useracc((caddr_t)uaddr, size, VM_PROT_READ)) #define DRM_COPY_FROM_USER_UNCHECKED(arg1, arg2, arg3) \ copyin(arg2, arg1, arg3) +#define DRM_COPY_TO_USER_UNCHECKED(arg1, arg2, arg3) \ + copyout(arg2, arg1, arg3) #define DRM_GET_USER_UNCHECKED(val, uaddr) \ ((val) = fuword(uaddr), 0) diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drmP.h b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drmP.h index 3d3796645..f0fc64d4c 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drmP.h +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drmP.h @@ -520,6 +520,9 @@ typedef struct drm_file { struct drm_device *dev; int remove_auth_on_close; unsigned long lock_count; +#ifdef DRIVER_FILE_FIELDS + DRIVER_FILE_FIELDS; +#endif } drm_file_t; /** Wait queue */ diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drm_drv.h b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drm_drv.h index e0c00f02f..e472dc332 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drm_drv.h +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drm_drv.h @@ -126,6 +126,9 @@ #ifndef DRIVER_IOCTLS #define DRIVER_IOCTLS #endif +#ifndef DRIVER_OPEN_HELPER +#define DRIVER_OPEN_HELPER( priv, dev ) +#endif #ifndef DRIVER_FOPS #define DRIVER_FOPS \ static struct file_operations DRM(fops) = { \ diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drm_fops.h b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drm_fops.h index f4841ae8b..771a2fa28 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drm_fops.h +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drm_fops.h @@ -73,6 +73,8 @@ int DRM(open_helper)(struct inode *inode, struct file *filp, drm_device_t *dev) priv->authenticated = capable(CAP_SYS_ADMIN); priv->lock_count = 0; + DRIVER_OPEN_HELPER( priv, dev ); + down(&dev->struct_sem); if (!dev->file_last) { priv->next = NULL; diff --git a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drm_os_linux.h b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drm_os_linux.h index cf7d7c2d4..c26a41086 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drm_os_linux.h +++ b/xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/drm_os_linux.h @@ -74,8 +74,12 @@ typedef void irqreturn_t; verify_area( VERIFY_READ, uaddr, size ) #define DRM_COPY_FROM_USER_UNCHECKED(arg1, arg2, arg3) \ __copy_from_user(arg1, arg2, arg3) +#define DRM_COPY_TO_USER_UNCHECKED(arg1, arg2, arg3) \ + __copy_to_user(arg1, arg2, arg3) #define DRM_GET_USER_UNCHECKED(val, uaddr) \ __get_user(val, uaddr) +#define DRM_PUT_USER_UNCHECKED(uaddr, val) \ + __put_user(val, uaddr) /** 'malloc' without the overhead of DRM(alloc)() */ diff --git a/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon.h b/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon.h index fadb248b7..af1f6ca4b 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon.h +++ b/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon.h @@ -51,7 +51,7 @@ #define DRIVER_DATE "20020828" #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 9 +#define DRIVER_MINOR 10 #define DRIVER_PATCHLEVEL 0 /* Interface history: @@ -81,6 +81,9 @@ * Add 'GET' queries for starting additional clients on different VT's. * 1.9 - Add DRM_IOCTL_RADEON_CP_RESUME ioctl. * Add texture rectangle support for r100. + * 1.10- Add SETPARAM ioctl; first parameter to set is FB_LOCATION, which + * clients use to tell the DRM where they think the framebuffer is + * located in the card's address space */ #define DRIVER_IOCTLS \ [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { radeon_cp_buffers, 1, 0 }, \ @@ -106,8 +109,9 @@ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_ALLOC)] = { radeon_mem_alloc, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_FREE)] = { radeon_mem_free, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_INIT_HEAP)] = { radeon_mem_init_heap, 1, 1 }, \ - [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_EMIT)] = { radeon_irq_emit, 1, 0 }, \ - [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_WAIT)] = { radeon_irq_wait, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_EMIT)] = { radeon_irq_emit, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_WAIT)] = { radeon_irq_wait, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_SETPARAM)] = { radeon_cp_setparam, 1, 0 }, \ #define DRIVER_PCI_IDS \ {0x1002, 0x4242, 0, "ATI Radeon BB R200 AIW 8500DV"}, \ @@ -147,6 +151,17 @@ {0x1002, 0x5961, 0, "ATI Radeon RV280 9200"}, \ {0, 0, 0, NULL} +#define DRIVER_FILE_FIELDS \ + s64 radeon_fb_delta; \ + +#define DRIVER_OPEN_HELPER( filp_priv, dev ) \ +do { \ + drm_radeon_private_t *dev_priv = dev->dev_private; \ + if ( dev_priv ) \ + filp_priv->radeon_fb_delta = dev_priv->fb_location; \ + else \ + filp_priv->radeon_fb_delta = 0; \ +} while( 0 ) /* When a client dies: * - Check for and clean up flipped page state diff --git a/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_cp.c b/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_cp.c index b24880a8b..87aef0105 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_cp.c +++ b/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_cp.c @@ -855,7 +855,8 @@ static void radeon_cp_init_ring_buffer( drm_device_t *dev, /* Initialize the memory controller */ RADEON_WRITE( RADEON_MC_FB_LOCATION, - (dev_priv->gart_vm_start - 1) & 0xffff0000 ); + ( ( dev_priv->gart_vm_start - 1 ) & 0xffff0000 ) + | ( dev_priv->fb_location >> 16 ) ); #if __REALLY_HAVE_AGP if ( !dev_priv->is_pci ) { @@ -1071,13 +1072,6 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) dev_priv->depth_offset = init->depth_offset; dev_priv->depth_pitch = init->depth_pitch; - dev_priv->front_pitch_offset = (((dev_priv->front_pitch/64) << 22) | - (dev_priv->front_offset >> 10)); - dev_priv->back_pitch_offset = (((dev_priv->back_pitch/64) << 22) | - (dev_priv->back_offset >> 10)); - dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch/64) << 22) | - (dev_priv->depth_offset >> 10)); - /* Hardware state for depth clears. Remove this if/when we no * longer clear the depth buffer with a 3D rectangle. Hard-code * all values to prevent unwanted 3D state from slipping through @@ -1204,9 +1198,26 @@ static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) dev_priv->buffers->handle ); } + dev_priv->fb_location = ( RADEON_READ( RADEON_MC_FB_LOCATION ) + & 0xffff ) << 16; + + dev_priv->front_pitch_offset = (((dev_priv->front_pitch/64) << 22) | + ( ( dev_priv->front_offset + + dev_priv->fb_location ) >> 10 ) ); + + dev_priv->back_pitch_offset = (((dev_priv->back_pitch/64) << 22) | + ( ( dev_priv->back_offset + + dev_priv->fb_location ) >> 10 ) ); + + dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch/64) << 22) | + ( ( dev_priv->depth_offset + + dev_priv->fb_location ) >> 10 ) ); + dev_priv->gart_size = init->gart_size; - dev_priv->gart_vm_start = RADEON_READ( RADEON_CONFIG_APER_SIZE ); + dev_priv->gart_vm_start = dev_priv->fb_location + + RADEON_READ( RADEON_CONFIG_APER_SIZE ); + #if __REALLY_HAVE_AGP if ( !dev_priv->is_pci ) dev_priv->gart_buffers_offset = (dev_priv->buffers->offset diff --git a/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_drm.h b/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_drm.h index c4a746490..f56b188dd 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_drm.h +++ b/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_drm.h @@ -390,6 +390,7 @@ typedef struct { #define DRM_IOCTL_RADEON_IRQ_WAIT DRM_IOW( 0x57, drm_radeon_irq_wait_t) /* added by Charl P. Botha - see radeon_cp.c for details */ #define DRM_IOCTL_RADEON_CP_RESUME DRM_IO(0x58) +#define DRM_IOCTL_RADEON_SETPARAM DRM_IOW(0x59, drm_radeon_setparam_t) typedef struct drm_radeon_init { enum { @@ -502,7 +503,7 @@ typedef struct drm_radeon_tex_image { } drm_radeon_tex_image_t; typedef struct drm_radeon_texture { - int offset; + unsigned int offset; int pitch; int format; int width; /* Texture image coordinates */ @@ -537,6 +538,7 @@ typedef struct drm_radeon_indirect { #define RADEON_PARAM_STATUS_HANDLE 8 #define RADEON_PARAM_SAREA_HANDLE 9 #define RADEON_PARAM_GART_TEX_HANDLE 10 +#define RADEON_PARAM_SCRATCH_OFFSET 11 typedef struct drm_radeon_getparam { int param; @@ -578,4 +580,16 @@ typedef struct drm_radeon_irq_wait { } drm_radeon_irq_wait_t; +/* 1.10: Clients tell the DRM where they think the framebuffer is located in + * the card's address space, via a new generic ioctl to set parameters + */ + +typedef struct drm_radeon_setparam { + unsigned int param; + int64_t value; +} drm_radeon_setparam_t; + +#define RADEON_SETPARAM_FB_LOCATION 1 /* determined framebuffer location */ + + #endif diff --git a/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_drv.h b/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_drv.h index fd23aa28e..1569caa70 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_drv.h +++ b/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_drv.h @@ -73,6 +73,8 @@ typedef struct drm_radeon_private { drm_radeon_ring_buffer_t ring; drm_radeon_sarea_t *sarea_priv; + u32 fb_location; + int gart_size; u32 gart_vm_start; unsigned long gart_buffers_offset; @@ -184,6 +186,7 @@ extern int radeon_cp_indirect( DRM_IOCTL_ARGS ); extern int radeon_cp_vertex2( DRM_IOCTL_ARGS ); extern int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ); extern int radeon_cp_getparam( DRM_IOCTL_ARGS ); +extern int radeon_cp_setparam( DRM_IOCTL_ARGS ); extern int radeon_cp_flip( DRM_IOCTL_ARGS ); extern int radeon_mem_alloc( DRM_IOCTL_ARGS ); @@ -239,6 +242,7 @@ extern void radeon_do_release(drm_device_t *dev); #define RADEON_CRTC2_OFFSET 0x0324 #define RADEON_CRTC2_OFFSET_CNTL 0x0328 +#define RADEON_RB3D_COLOROFFSET 0x1c40 #define RADEON_RB3D_COLORPITCH 0x1c48 #define RADEON_DP_GUI_MASTER_CNTL 0x146c @@ -332,6 +336,7 @@ extern void radeon_do_release(drm_device_t *dev); #define RADEON_PP_MISC 0x1c14 #define RADEON_PP_ROT_MATRIX_0 0x1d58 #define RADEON_PP_TXFILTER_0 0x1c54 +#define RADEON_PP_TXOFFSET_0 0x1c5c #define RADEON_PP_TXFILTER_1 0x1c6c #define RADEON_PP_TXFILTER_2 0x1c84 diff --git a/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_state.c b/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_state.c index 833f96981..e24bee8aa 100644 --- a/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/radeon_state.c +++ b/xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/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; +} |