diff options
author | Thomas Hellstrom <unichrome@shipmail.org> | 2005-03-28 21:21:42 +0000 |
---|---|---|
committer | Thomas Hellstrom <unichrome@shipmail.org> | 2005-03-28 21:21:42 +0000 |
commit | 532ccb98b5f2946f574a747b90c39edbe783f888 (patch) | |
tree | cfbdf4e8e2b8e0827b35b92a7e57e7f6104e18f1 /shared-core/via_verifier.c | |
parent | c6161eff86b250f3113791edcc162dc97322c401 (diff) |
Via updates:
New PCI command parser. Moved from via_dma.c to via_verifier.c so functions
with similar functionality are close to eachother.
Moved video related functions to via_video.c, which might be extended in
the future, as new video functionality is added.
New device-specific generic IRQ IOCTL, similar to the general VBLANK IOCTL,
but with support for multiple device IRQ sources and functionality.
Support for Unichrome Pro PM800/CN400 video DMA commands in verifier and
PCI parser.
Support for Unichrome Pro PM800/CN400 HQV IRQs in the new generic IRQ
IOCTL.
Bumped minor. New version 2.6.0.
Diffstat (limited to 'shared-core/via_verifier.c')
-rw-r--r-- | shared-core/via_verifier.c | 181 |
1 files changed, 168 insertions, 13 deletions
diff --git a/shared-core/via_verifier.c b/shared-core/via_verifier.c index 6b08f5d8..5b1f30a7 100644 --- a/shared-core/via_verifier.c +++ b/shared-core/via_verifier.c @@ -1,5 +1,6 @@ /* * Copyright 2004 The Unichrome Project. All Rights Reserved. + * Copyright 2005 Thomas Hellstrom. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -15,12 +16,12 @@ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE UNICHROME PROJECT, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * THE AUTHOR(S), AND/OR THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * Author: Thomas Hellström 2004. + * Author: Thomas Hellstrom 2004, 2005. * This code was written using docs obtained under NDA from VIA Inc. * * Don't run this code directly on an AGP buffer. Due to cache problems it will @@ -677,16 +678,62 @@ via_check_header2( uint32_t const **buffer, const uint32_t *buf_end, return state_command; } +static __inline__ verifier_state_t +via_parse_header2( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end, + int *fire_count) +{ + uint32_t cmd; + const uint32_t *buf = *buffer; + const uint32_t *next_fire; + int burst = 0; + + next_fire = dev_priv->fire_offsets[*fire_count]; + buf++; + cmd = (*buf & 0xFFFF0000) >> 16; + VIA_WRITE(HC_REG_TRANS_SET + HC_REG_BASE, *buf++); + switch(cmd) { + case HC_ParaType_CmdVdata: + while ((buf < buf_end) && + (*fire_count < dev_priv->num_fire_offsets) && + (*buf & HC_ACMD_MASK) == HC_ACMD_HCmdB ) { + while(buf <= next_fire) { + VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE + (burst & 63), *buf++); + burst += 4; + } + if ( ( buf < buf_end ) && ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD)) + buf++; + + if (++(*fire_count) < dev_priv->num_fire_offsets) + next_fire = dev_priv->fire_offsets[*fire_count]; + } + break; + default: + while(buf < buf_end) { + + if ( *buf == HC_HEADER2 || + (*buf & HALCYON_HEADER1MASK) == HALCYON_HEADER1 || + (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5 || + (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6 ) break; + + VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE + (burst & 63), *buf++); + burst +=4; + } + } + *buffer = buf; + return state_command; +} + + static __inline__ int verify_mmio_address( uint32_t address) { if ((address > 0x3FF) && (address < 0xC00 )) { - DRM_ERROR("Invalid HALCYON_HEADER1 command. " + DRM_ERROR("Invalid VIDEO DMA command. " "Attempt to access 3D- or command burst area.\n"); return 1; - } else if (address > 0xCFF ) { - DRM_ERROR("Invalid HALCYON_HEADER1 command. " + } else if (address > 0x13FF ) { + DRM_ERROR("Invalid VIDEO DMA command. " "Attempt to access VGA registers.\n"); return 1; } @@ -746,6 +793,22 @@ via_check_header1( uint32_t const **buffer, const uint32_t *buf_end ) } static __inline__ verifier_state_t +via_parse_header1( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end ) +{ + register uint32_t cmd; + const uint32_t *buf = *buffer; + + while (buf < buf_end) { + cmd = *buf; + if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) break; + VIA_WRITE( (cmd & ~HALCYON_HEADER1MASK) << 2, *++buf); + buf++; + } + *buffer = buf; + return state_command; +} + +static __inline__ verifier_state_t via_check_vheader5( uint32_t const **buffer, const uint32_t *buf_end ) { uint32_t data; @@ -771,7 +834,7 @@ via_check_vheader5( uint32_t const **buffer, const uint32_t *buf_end ) } if (eat_words(&buf, buf_end, data)) return state_error; - if (verify_video_tail(&buf, buf_end, 4 - (data & 3))) + if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3))) return state_error; *buffer = buf; return state_command; @@ -779,19 +842,36 @@ via_check_vheader5( uint32_t const **buffer, const uint32_t *buf_end ) } static __inline__ verifier_state_t +via_parse_vheader5( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end ) +{ + uint32_t addr, count, i; + const uint32_t *buf = *buffer; + + addr = *buf++ & ~VIA_VIDEOMASK; + i = count = *buf; + buf += 3; + while(i--) { + VIA_WRITE(addr, *buf++); + } + if (count & 3) buf += 4 - (count & 3); + *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; - DRM_ERROR("H6\n"); if (buf_end - buf < 4) { DRM_ERROR("Illegal termination of video header6 command\n"); return state_error; } - + buf++; data = *buf++; if (*buf++ != 0x00F60000) { DRM_ERROR("Illegal header6 header data\n"); @@ -803,18 +883,40 @@ via_check_vheader6( uint32_t const **buffer, const uint32_t *buf_end ) } if ((buf_end - buf) < (data << 1)) { DRM_ERROR("Illegal termination of video header6 command\n"); + return state_error; } 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))) + data <<= 1; + if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3))) return state_error; *buffer = buf; return state_command; } +static __inline__ verifier_state_t +via_parse_vheader6( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end ) +{ + + uint32_t addr, count, i; + const uint32_t *buf = *buffer; + + i = count = *++buf; + buf += 3; + while(i--) { + addr = *buf++; + VIA_WRITE(addr, *buf++); + } + count <<= 1; + if (count & 3) buf += 4 - (count & 3); + *buffer = buf; + return state_command; +} + + int via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t *dev, @@ -827,7 +929,7 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t uint32_t cmd; const uint32_t *buf_end = buf + ( size >> 2 ); verifier_state_t state = state_command; - + int pro_group_a = dev_priv->pro_group_a; hc_state->dev = dev; hc_state->unfinished = no_sequence; @@ -840,7 +942,7 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t switch (state) { case state_header2: - state = via_check_header2( &buf, buf_end, hc_state ); + state = via_check_header2( &buf, buf_end, hc_state ); break; case state_header1: state = via_check_header1( &buf, buf_end ); @@ -856,9 +958,9 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t state = state_header2; else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) state = state_header1; - else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5) + else if (pro_group_a && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5) state = state_vheader5; - else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6) + else if (pro_group_a && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6) state = state_vheader6; else { DRM_ERROR("Invalid / Unimplemented DMA HEADER command. 0x%x\n", @@ -879,6 +981,59 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t return 0; } +int +via_parse_command_stream(drm_device_t *dev, const uint32_t * buf, unsigned int size) +{ + + drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; + uint32_t cmd; + const uint32_t *buf_end = buf + ( size >> 2 ); + verifier_state_t state = state_command; + int fire_count = 0; + + while (buf < buf_end) { + + switch (state) { + case state_header2: + state = via_parse_header2( dev_priv, &buf, buf_end, &fire_count ); + break; + case state_header1: + state = via_parse_header1( dev_priv, &buf, buf_end ); + break; + case state_vheader5: + state = via_parse_vheader5( dev_priv, &buf, buf_end ); + break; + case state_vheader6: + state = via_parse_vheader6( dev_priv, &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); + state = state_error; + } + break; + case state_error: + default: + return DRM_ERR(EINVAL); + } + } + if (state == state_error) { + return DRM_ERR(EINVAL); + } + return 0; +} + + + static void setup_hazard_table(hz_init_t init_table[], hazard_t table[], int size) { |