import Thomas' shared-core via changes up to 2.4.1
parent
17d893f567
commit
9904319b95
|
@ -30,11 +30,11 @@
|
|||
|
||||
#define DRIVER_NAME "via"
|
||||
#define DRIVER_DESC "VIA Unichrome"
|
||||
#define DRIVER_DATE "20041231"
|
||||
#define DRIVER_DATE "20050106"
|
||||
|
||||
#define DRIVER_MAJOR 2
|
||||
#define DRIVER_MINOR 3
|
||||
#define DRIVER_PATCHLEVEL 4
|
||||
#define DRIVER_MINOR 4
|
||||
#define DRIVER_PATCHLEVEL 1
|
||||
|
||||
#define DRIVER_IOCTLS \
|
||||
[DRM_IOCTL_NR(DRM_IOCTL_VIA_ALLOCMEM)] = { via_mem_alloc, 1, 0 }, \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -299,12 +299,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;
|
||||
}
|
||||
|
@ -315,7 +315,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)
|
||||
|
|
|
@ -75,6 +75,7 @@ extern void via_driver_irq_uninstall(drm_device_t * dev);
|
|||
|
||||
extern int via_dma_cleanup(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);
|
||||
extern void via_init_command_verifier( void );
|
||||
extern int via_verify_command_stream(const uint32_t * buf, unsigned int size,
|
||||
drm_device_t *dev);
|
||||
|
|
|
@ -44,53 +44,37 @@
|
|||
/* VIA_REG_INTERRUPT */
|
||||
#define VIA_IRQ_GLOBAL (1 << 31)
|
||||
#define VIA_IRQ_VBI_ENABLE (1 << 19)
|
||||
#define VIA_IRQ_SEC_VBI_ENABLE (1 << 17)
|
||||
#define VIA_IRQ_SEC_VBI_PENDING (1 << 15)
|
||||
#define VIA_IRQ_VBI_PENDING (1 << 3)
|
||||
|
||||
|
||||
|
||||
static unsigned time_diff(struct timeval *now,struct timeval *then)
|
||||
{
|
||||
return (now->tv_usec >= then->tv_usec) ?
|
||||
now->tv_usec - then->tv_usec :
|
||||
1000000 - (then->tv_usec - now->tv_usec);
|
||||
}
|
||||
|
||||
irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
|
||||
{
|
||||
drm_device_t *dev = (drm_device_t *) arg;
|
||||
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
|
||||
u32 status;
|
||||
int handled = 0;
|
||||
struct timeval cur_vblank;
|
||||
int handled = IRQ_NONE;
|
||||
u32 status = VIA_READ(VIA_REG_INTERRUPT);
|
||||
|
||||
status = VIA_READ(VIA_REG_INTERRUPT);
|
||||
if (status & VIA_IRQ_VBI_PENDING) {
|
||||
atomic_inc(&dev->vbl_received);
|
||||
if (!(atomic_read(&dev->vbl_received) & 0x0F)) {
|
||||
do_gettimeofday(&cur_vblank);
|
||||
if (dev_priv->last_vblank_valid) {
|
||||
dev_priv->usec_per_vblank =
|
||||
time_diff( &cur_vblank,&dev_priv->last_vblank) >> 4;
|
||||
}
|
||||
dev_priv->last_vblank = cur_vblank;
|
||||
dev_priv->last_vblank_valid = 1;
|
||||
}
|
||||
if (!(atomic_read(&dev->vbl_received) & 0xFF)) {
|
||||
DRM_DEBUG("US per vblank is: %u\n",
|
||||
dev_priv->usec_per_vblank);
|
||||
}
|
||||
DRM_WAKEUP(&dev->vbl_queue);
|
||||
DRM(vbl_send_signals) (dev);
|
||||
handled = 1;
|
||||
handled = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* Acknowlege interrupts ?? */
|
||||
VIA_WRITE(VIA_REG_INTERRUPT, status);
|
||||
#if 0
|
||||
if (status & VIA_IRQ_SEC_VBI_PENDING) {
|
||||
atomic_inc(&dev->sec_vbl_received);
|
||||
DRM_WAKEUP(&dev->sec_vbl_queue);
|
||||
DRM(vbl_send_signals)(dev); /* KW: Need a parameter here? */
|
||||
handled = IRQ_HANDLED;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (handled)
|
||||
return IRQ_HANDLED;
|
||||
else
|
||||
return IRQ_NONE;
|
||||
VIA_WRITE(VIA_REG_INTERRUPT, status);
|
||||
return handled;
|
||||
}
|
||||
|
||||
static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv)
|
||||
|
|
|
@ -131,8 +131,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))
|
||||
|
@ -167,6 +171,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 */
|
||||
|
@ -362,4 +382,5 @@ void DRM(driver_register_fns) (drm_device_t * dev) {
|
|||
dev->fn_tbl.irq_postinstall = via_driver_irq_postinstall;
|
||||
dev->fn_tbl.irq_uninstall = via_driver_irq_uninstall;
|
||||
dev->fn_tbl.irq_handler = via_driver_irq_handler;
|
||||
dev->fn_tbl.dma_quiescent = via_driver_dma_quiescent;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@ typedef enum{
|
|||
state_command,
|
||||
state_header2,
|
||||
state_header1,
|
||||
state_vheader5,
|
||||
state_vheader6,
|
||||
state_error
|
||||
} verifier_state_t;
|
||||
|
||||
|
@ -72,6 +74,8 @@ typedef enum{
|
|||
check_texture_addr7,
|
||||
check_texture_addr8,
|
||||
check_texture_addr_mode,
|
||||
check_for_vertex_count,
|
||||
check_number_texunits,
|
||||
forbidden_command
|
||||
}hazard_t;
|
||||
|
||||
|
@ -165,7 +169,7 @@ static hz_init_t init_table1[] = {
|
|||
{0x7A, no_check},
|
||||
{0x7B, no_check},
|
||||
{0x7C, no_check},
|
||||
{0x7D, no_check}
|
||||
{0x7D, check_for_vertex_count}
|
||||
};
|
||||
|
||||
|
||||
|
@ -232,7 +236,7 @@ static hz_init_t init_table3[] = {
|
|||
{0xf2, check_for_header2_err},
|
||||
{0xf0, check_for_header1_err},
|
||||
{0xcc, check_for_dummy},
|
||||
{0x00, no_check}
|
||||
{0x00, check_number_texunits}
|
||||
};
|
||||
|
||||
|
||||
|
@ -254,8 +258,10 @@ typedef struct{
|
|||
uint32_t tex_palette_size[2];
|
||||
sequence_t unfinished;
|
||||
int agp_texture;
|
||||
int multitex;
|
||||
drm_device_t *dev;
|
||||
drm_map_t *map_cache;
|
||||
uint32_t vertex_count;
|
||||
} sequence_context_t;
|
||||
|
||||
static sequence_context_t hc_sequence;
|
||||
|
@ -497,6 +503,12 @@ investigate_hazard( uint32_t cmd, hazard_t hz, sequence_context_t *cur_seq)
|
|||
cur_seq->tex_palette_size[cur_seq->texture] =
|
||||
(cmd >> 16) & 0x000000007;
|
||||
return 0;
|
||||
case check_for_vertex_count:
|
||||
cur_seq->vertex_count = cmd & 0x0000FFFF;
|
||||
return 0;
|
||||
case check_number_texunits:
|
||||
cur_seq->multitex = (cmd >> 3) & 1;
|
||||
return 0;
|
||||
default:
|
||||
DRM_ERROR("Illegal DMA data: 0x%x\n", cmd);
|
||||
return 2;
|
||||
|
@ -505,6 +517,84 @@ investigate_hazard( uint32_t cmd, hazard_t hz, sequence_context_t *cur_seq)
|
|||
}
|
||||
|
||||
|
||||
static __inline__ int
|
||||
via_check_prim_list(uint32_t const **buffer, const uint32_t *buf_end,
|
||||
sequence_context_t *cur_seq)
|
||||
{
|
||||
uint32_t a_fire, bcmd , dw_count;
|
||||
int ret = 0;
|
||||
int have_fire;
|
||||
const uint32_t *buf = *buffer;
|
||||
|
||||
while(buf < buf_end) {
|
||||
have_fire = 0;
|
||||
if ((buf_end - buf) < 2) {
|
||||
DRM_ERROR("Unexpected termination of primitive list.\n");
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdB) break;
|
||||
bcmd = *buf++;
|
||||
if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdA) {
|
||||
DRM_ERROR("Expected Vertex List A command, got 0x%x\n",
|
||||
*buf);
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
a_fire = *buf++ | HC_HPLEND_MASK | HC_HPMValidN_MASK | HC_HE3Fire_MASK;
|
||||
|
||||
/*
|
||||
* How many dwords per vertex ?
|
||||
*/
|
||||
|
||||
if ((bcmd & (0xF << 11)) == 0) {
|
||||
DRM_ERROR("Illegal B command vertex data for AGP.\n");
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
dw_count = 0;
|
||||
if (bcmd & (1 << 7)) dw_count += (cur_seq->multitex) ? 2:1;
|
||||
if (bcmd & (1 << 8)) dw_count += (cur_seq->multitex) ? 2:1;
|
||||
if (bcmd & (1 << 9)) dw_count++;
|
||||
if (bcmd & (1 << 10)) dw_count++;
|
||||
if (bcmd & (1 << 11)) dw_count++;
|
||||
if (bcmd & (1 << 12)) dw_count++;
|
||||
if (bcmd & (1 << 13)) dw_count++;
|
||||
if (bcmd & (1 << 14)) dw_count++;
|
||||
|
||||
while(buf < buf_end) {
|
||||
if (*buf == HALCYON_HEADER2) {
|
||||
DRM_ERROR("Missing Vertex Fire command or verifier "
|
||||
"lost sync.\n");
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
if (*buf == a_fire) {
|
||||
have_fire = 1;
|
||||
buf++;
|
||||
if (buf < buf_end && *buf == a_fire)
|
||||
buf++;
|
||||
break;
|
||||
}
|
||||
if ((ret = eat_words(&buf, buf_end, dw_count)))
|
||||
break;
|
||||
}
|
||||
if (buf >= buf_end && !have_fire) {
|
||||
DRM_ERROR("Missing Vertex Fire command or verifier "
|
||||
"lost sync.\n");
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*buffer = buf;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static __inline__ verifier_state_t
|
||||
via_check_header2( uint32_t const **buffer, const uint32_t *buf_end )
|
||||
{
|
||||
|
@ -514,6 +604,7 @@ via_check_header2( uint32_t const **buffer, const uint32_t *buf_end )
|
|||
const uint32_t *buf = *buffer;
|
||||
const hazard_t *hz_table;
|
||||
|
||||
|
||||
if ((buf_end - buf) < 2) {
|
||||
DRM_ERROR("Illegal termination of DMA HALCYON_HEADER2 sequence.\n");
|
||||
return state_error;
|
||||
|
@ -523,32 +614,10 @@ via_check_header2( uint32_t const **buffer, const uint32_t *buf_end )
|
|||
|
||||
switch(cmd) {
|
||||
case HC_ParaType_CmdVdata:
|
||||
|
||||
/*
|
||||
* Command vertex data.
|
||||
* It is assumed that the command regulator remains in this state
|
||||
* until it encounters a possibly double fire command or a header2 data.
|
||||
* FIXME: Vertex data can accidently be header2 or fire.
|
||||
* CHECK: What does the regulator do if it encounters a header1
|
||||
* cmd?
|
||||
*/
|
||||
|
||||
while (buf < buf_end) {
|
||||
if (*buf == HALCYON_HEADER2) break;
|
||||
if ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD) {
|
||||
buf++;
|
||||
if ((buf < buf_end) &&
|
||||
((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD))
|
||||
buf++;
|
||||
if ((buf < buf_end) &&
|
||||
((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD))
|
||||
break;
|
||||
}
|
||||
buf++;
|
||||
}
|
||||
if (via_check_prim_list(&buf, buf_end, &hc_sequence ))
|
||||
return state_error;
|
||||
*buffer = buf;
|
||||
return state_command;
|
||||
|
||||
case HC_ParaType_NotTex:
|
||||
hz_table = table1;
|
||||
break;
|
||||
|
@ -590,7 +659,8 @@ via_check_header2( uint32_t const **buffer, const uint32_t *buf_end )
|
|||
*/
|
||||
|
||||
DRM_ERROR("Invalid or unimplemented HALCYON_HEADER2 "
|
||||
"DMA subcommand: 0x%x\n", cmd);
|
||||
"DMA subcommand: 0x%x. Previous dword: 0x%x\n",
|
||||
cmd, *(buf -2));
|
||||
*buffer = buf;
|
||||
return state_error;
|
||||
}
|
||||
|
@ -618,6 +688,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 )
|
||||
{
|
||||
|
@ -650,6 +755,75 @@ 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;
|
||||
|
||||
DRM_ERROR("H6\n");
|
||||
|
||||
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
|
||||
|
@ -665,6 +839,7 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t
|
|||
hc_sequence.map_cache = NULL;
|
||||
|
||||
while (buf < buf_end) {
|
||||
|
||||
switch (state) {
|
||||
case state_header2:
|
||||
state = via_check_header2( &buf, buf_end );
|
||||
|
@ -672,11 +847,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);
|
||||
|
|
Loading…
Reference in New Issue