diff options
Diffstat (limited to 'shared-core')
-rw-r--r-- | shared-core/via_3d_reg.h | 5 | ||||
-rw-r--r-- | shared-core/via_dma.c | 6 | ||||
-rw-r--r-- | shared-core/via_drv.c | 1 | ||||
-rw-r--r-- | shared-core/via_drv.h | 1 | ||||
-rw-r--r-- | shared-core/via_mm.c | 24 | ||||
-rw-r--r-- | shared-core/via_verifier.c | 114 |
6 files changed, 146 insertions, 5 deletions
diff --git a/shared-core/via_3d_reg.h b/shared-core/via_3d_reg.h index 43c01836..cf61bb51 100644 --- a/shared-core/via_3d_reg.h +++ b/shared-core/via_3d_reg.h @@ -1643,4 +1643,9 @@ #define HC_HAGPBpID_STOP 0x00000002 #define HC_HAGPBpH_MASK 0x00ffffff + +#define VIA_VIDEO_HEADER5 0xFE040000 +#define VIA_VIDEO_HEADER6 0xFE050000 +#define VIA_VIDEO_HEADER7 0xFE060000 +#define VIA_VIDEOMASK 0xFFFF0000 #endif diff --git a/shared-core/via_dma.c b/shared-core/via_dma.c index b8c916d9..d514e4d7 100644 --- a/shared-core/via_dma.c +++ b/shared-core/via_dma.c @@ -298,12 +298,12 @@ static int via_dispatch_cmdbuffer(drm_device_t * dev, drm_via_cmdbuffer_t * cmd) return 0; } -static int via_quiescent(drm_device_t * dev) +int via_driver_dma_quiescent(drm_device_t * dev) { drm_via_private_t *dev_priv = dev->dev_private; if (!via_wait_idle(dev_priv)) { - return DRM_ERR(EAGAIN); + return DRM_ERR(EBUSY); } return 0; } @@ -314,7 +314,7 @@ int via_flush_ioctl(DRM_IOCTL_ARGS) LOCK_TEST_WITH_RETURN( dev, filp ); - return via_quiescent(dev); + return via_driver_dma_quiescent(dev); } int via_cmdbuffer(DRM_IOCTL_ARGS) diff --git a/shared-core/via_drv.c b/shared-core/via_drv.c index 16233380..d3d843da 100644 --- a/shared-core/via_drv.c +++ b/shared-core/via_drv.c @@ -84,6 +84,7 @@ static struct drm_driver driver = { .irq_postinstall = via_driver_irq_postinstall, .irq_uninstall = via_driver_irq_uninstall, .irq_handler = via_driver_irq_handler, + .dma_quiescent = via_driver_dma_quiescent, .reclaim_buffers = drm_core_reclaim_buffers, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, diff --git a/shared-core/via_drv.h b/shared-core/via_drv.h index 48a93f78..c07747b2 100644 --- a/shared-core/via_drv.h +++ b/shared-core/via_drv.h @@ -85,6 +85,7 @@ extern int via_dma_cleanup(drm_device_t * dev); extern void via_init_command_verifier(void); extern int via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t *dev); extern int via_wait_idle(drm_via_private_t * dev_priv); +extern int via_driver_dma_quiescent(drm_device_t * dev); #endif diff --git a/shared-core/via_mm.c b/shared-core/via_mm.c index 5199f6c9..5940de70 100644 --- a/shared-core/via_mm.c +++ b/shared-core/via_mm.c @@ -130,8 +130,12 @@ int via_init_context(struct drm_device *dev, int context) } int via_final_context(struct drm_device *dev, int context) -{ - int i; +{ + int i; + volatile int *lock; + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + drm_via_sarea_t *sAPriv = dev_priv->sarea_priv; + for (i = 0; i < MAX_CONTEXT; i++) if (global_ppriv[i].used && (global_ppriv[i].context == context)) @@ -166,6 +170,22 @@ int via_final_context(struct drm_device *dev, int context) global_ppriv[i].used = 0; } + + /* + * Release futex locks. + */ + + for (i=0; i < VIA_NR_XVMC_LOCKS; ++i) { + lock = XVMCLOCKPTR(sAPriv, i); + if ( (_DRM_LOCKING_CONTEXT( *lock ) == i) && + (_DRM_LOCK_IS_HELD( *lock ))) { + if ( *lock & _DRM_LOCK_CONT) { + DRM_WAKEUP( &(dev_priv->decoder_queue[i])); + } + *lock &= ~( _DRM_LOCK_HELD | _DRM_LOCK_CONT ); + } + } + #if defined(__linux__) /* Linux specific until context tracking code gets ported to BSD */ /* Last context, perform cleanup */ diff --git a/shared-core/via_verifier.c b/shared-core/via_verifier.c index c60c911f..7a772588 100644 --- a/shared-core/via_verifier.c +++ b/shared-core/via_verifier.c @@ -35,6 +35,8 @@ typedef enum{ state_command, state_header2, state_header1, + state_vheader5, + state_vheader6, state_error } verifier_state_t; @@ -617,6 +619,41 @@ via_check_header2( uint32_t const **buffer, const uint32_t *buf_end ) } +static __inline__ int +verify_mmio_address( uint32_t address) +{ + if ((address > 0x3FF) && (address < 0xC00 )) { + DRM_ERROR("Invalid HALCYON_HEADER1 command. " + "Attempt to access 3D- or command burst area.\n"); + return 1; + } else if (address > 0xCFF ) { + DRM_ERROR("Invalid HALCYON_HEADER1 command. " + "Attempt to access VGA registers.\n"); + return 1; + } + return 0; +} + +static __inline__ int +verify_video_tail( uint32_t const **buffer, const uint32_t *buf_end, uint32_t dwords) +{ + const uint32_t *buf = *buffer; + + if (buf_end - buf < dwords) { + DRM_ERROR("Illegal termination of video command.\n"); + return 1; + } + while (dwords--) { + if (*buf++) { + DRM_ERROR("Illegal video command tail.\n"); + return 1; + } + } + *buffer = buf; + return 0; +} + + static __inline__ verifier_state_t via_check_header1( uint32_t const **buffer, const uint32_t *buf_end ) { @@ -649,6 +686,73 @@ via_check_header1( uint32_t const **buffer, const uint32_t *buf_end ) return ret; } +static __inline__ verifier_state_t +via_check_vheader5( uint32_t const **buffer, const uint32_t *buf_end ) +{ + uint32_t data; + const uint32_t *buf = *buffer; + + if (buf_end - buf < 4) { + DRM_ERROR("Illegal termination of video header5 command\n"); + return state_error; + } + + data = *buf++ & ~VIA_VIDEOMASK; + if (verify_mmio_address(data)) + return state_error; + + data = *buf++; + if (*buf++ != 0x00F50000) { + DRM_ERROR("Illegal header5 header data\n"); + return state_error; + } + if (*buf++ != 0x00000000) { + DRM_ERROR("Illegal header5 header data\n"); + return state_error; + } + if (eat_words(&buf, buf_end, data)) + return state_error; + if (verify_video_tail(&buf, buf_end, 4 - (data & 3))) + return state_error; + *buffer = buf; + return state_command; + +} + +static __inline__ verifier_state_t +via_check_vheader6( uint32_t const **buffer, const uint32_t *buf_end ) +{ + uint32_t data; + const uint32_t *buf = *buffer; + uint32_t i; + + if (buf_end - buf < 4) { + DRM_ERROR("Illegal termination of video header6 command\n"); + return state_error; + } + + data = *buf++; + if (*buf++ != 0x00F60000) { + DRM_ERROR("Illegal header6 header data\n"); + return state_error; + } + if (*buf++ != 0x00000000) { + DRM_ERROR("Illegal header6 header data\n"); + return state_error; + } + if ((buf_end - buf) < (data << 1)) { + DRM_ERROR("Illegal termination of video header6 command\n"); + } + for (i=0; i<data; ++i) { + if (verify_mmio_address(*buf++)) + return state_error; + buf++; + } + if (verify_video_tail(&buf, buf_end, 4 - ((data << 1) & 3))) + return state_error; + *buffer = buf; + return state_command; +} int @@ -671,11 +775,21 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t case state_header1: state = via_check_header1( &buf, buf_end ); break; + case state_vheader5: + state = via_check_vheader5( &buf, buf_end ); + break; + case state_vheader6: + state = via_check_vheader6( &buf, buf_end ); + break; case state_command: if (HALCYON_HEADER2 == (cmd = *buf)) state = state_header2; else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) state = state_header1; + else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5) + state = state_vheader5; + else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6) + state = state_vheader6; else { DRM_ERROR("Invalid / Unimplemented DMA HEADER command. 0x%x\n", cmd); |