This patch adds three new ioctl's to the VIA Unichrome/Pro DRM driver:

DRM_IOCTL_VIA_DMA_INIT DRM_IOCTL_VIA_CMDBUFFER DRM_IOCTL_VIA_FLUSH
The first ioctl sets up an area in AGP memory that will be used as the ring
    buffer. The second ioctl copies a command buffer from user space memory
    to the ring buffer. The third ioctl waits for engine idle until it
    returns.
The motivation for this patch is to avoid the wait for engine idle call
    before each buffer flush in the current DRI driver. With this patch,
    the DRI driver can continue to flush its buffer as long as there is
    free space in the ring buffer.
This patch adds an additional copy operation on the command buffer. This
    buffer copying is necessary to support multiple DRI clients rendering
    simultaneously. Otherwise, more CPU time will be spent in the busy loop
    waiting for engine idle between DRI context switch. Even in the single
    client case, the tradeoff is reasonable in comparision to the kernel
    call to check for free buffer space for the client to render directly
    to the ring buffer.
This commit is contained in:
Erdi Chen 2004-08-24 01:44:37 +00:00
parent 7fe4f60768
commit 25e319c1ef
22 changed files with 4448 additions and 16 deletions

View file

@ -50,7 +50,9 @@ SHAREDFILES= drm.h \
via_irq.c \
via_map.c \
via_mm.c \
via_mm.h
via_mm.h \
via_3d_reg.h \
via_dma.c
SUBDIR = i915 mach64 mga r128 radeon sis tdfx

View file

@ -50,7 +50,9 @@ SHAREDFILES= drm.h \
via_irq.c \
via_map.c \
via_mm.c \
via_mm.h
via_mm.h \
via_3d_reg.h \
via_dma.c
SUBDIR = i915 mach64 mga r128 radeon sis tdfx

View file

@ -97,9 +97,10 @@ SISSHARED= sis.h sis_drv.h sis_drm.h sis_ds.c sis_ds.h sis_mm.c
SAVAGEHEADERS= savage.h savage_drv.h savage_drm.h $(DRMHEADERS) \
$(DRMTEMPLATES)
VIAHEADERS = via_drm.h via_drv.h via.h via_mm.h via_ds.h \
$(DRMHEADERS) $(DRMTEMPLATES)
VIASHARED = via_drm.h via_drv.h via.h via_mm.h via_ds.h via_drv.c \
via_ds.c via_irq.c via_map.c via_mm.c
via_3d_reg.h $(DRMHEADERS) $(DRMTEMPLATES)
VIASHARED = via_drm.h via_drv.h via.h via_mm.h via_ds.h \
via_3d_reg.h via_drv.c via_ds.c via_irq.c via_map.c \
via_mm.c via_dma.c
MACH64HEADERS = mach64.h mach64_drv.h mach64_drm.h $(DRMHEADERS) \
$(DRMTEMPLATES)
MACH64SHARED = mach64.h mach64_drv.h mach64_drm.h mach64_dma.c \

View file

@ -18,7 +18,7 @@ radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o
sis-objs := sis_drv.o sis_ds.o sis_mm.o
ffb-objs := ffb_drv.o ffb_context.o
savage-objs := savage_drv.o savage_dma.o
via-objs := via_irq.o via_drv.o via_ds.o via_map.o via_mm.o
via-objs := via_irq.o via_drv.o via_ds.o via_map.o via_mm.o via_dma.o
mach64-objs := mach64_drv.o mach64_dma.o mach64_irq.o mach64_state.o
# Kernel version checks

View file

@ -934,6 +934,7 @@ int DRM(release)( struct inode *inode, struct file *filp )
#endif
list_del( &pos->head );
DRM(free)( pos, sizeof(*pos), DRM_MEM_CTXLIST );
--dev->ctx_count;
}
}
}

View file

@ -97,9 +97,10 @@ SISSHARED= sis.h sis_drv.h sis_drm.h sis_ds.c sis_ds.h sis_mm.c
SAVAGEHEADERS= savage.h savage_drv.h savage_drm.h $(DRMHEADERS) \
$(DRMTEMPLATES)
VIAHEADERS = via_drm.h via_drv.h via.h via_mm.h via_ds.h \
$(DRMHEADERS) $(DRMTEMPLATES)
VIASHARED = via_drm.h via_drv.h via.h via_mm.h via_ds.h via_drv.c \
via_ds.c via_irq.c via_map.c via_mm.c
via_3d_reg.h $(DRMHEADERS) $(DRMTEMPLATES)
VIASHARED = via_drm.h via_drv.h via.h via_mm.h via_ds.h \
via_3d_reg.h via_drv.c via_ds.c via_irq.c via_map.c \
via_mm.c via_dma.c
MACH64HEADERS = mach64.h mach64_drv.h mach64_drm.h $(DRMHEADERS) \
$(DRMTEMPLATES)
MACH64SHARED = mach64.h mach64_drv.h mach64_drm.h mach64_dma.c \

View file

@ -18,7 +18,7 @@ radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o
sis-objs := sis_drv.o sis_ds.o sis_mm.o
ffb-objs := ffb_drv.o ffb_context.o
savage-objs := savage_drv.o savage_dma.o
via-objs := via_irq.o via_drv.o via_ds.o via_map.o via_mm.o
via-objs := via_irq.o via_drv.o via_ds.o via_map.o via_mm.o via_dma.o
mach64-objs := mach64_drv.o mach64_dma.o mach64_irq.o mach64_state.o
# Kernel version checks

View file

@ -934,6 +934,7 @@ int DRM(release)( struct inode *inode, struct file *filp )
#endif
list_del( &pos->head );
DRM(free)( pos, sizeof(*pos), DRM_MEM_CTXLIST );
--dev->ctx_count;
}
}
}

1644
shared-core/via_3d_reg.h Normal file

File diff suppressed because it is too large Load diff

517
shared-core/via_dma.c Normal file
View file

@ -0,0 +1,517 @@
/* via_dma.c -- DMA support for the VIA Unichrome/Pro
*/
/**************************************************************************
*
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* Copyright 2004 Digeo, Inc., Palo Alto, CA, U.S.A.
* All Rights Reserved.
*
**************************************************************************/
#define __NO_VERSION__
#include "via.h"
#include "drmP.h"
#include "drm.h"
#include "via_drm.h"
#include "via_drv.h"
static inline uint32_t * via_check_dma(drm_via_private_t * dev_priv,
unsigned int size);
static void via_cmdbuf_start(drm_via_private_t * dev_priv);
static void via_cmdbuf_pause(drm_via_private_t * dev_priv);
static void via_cmdbuf_reset(drm_via_private_t * dev_priv);
static void via_cmdbuf_rewind(drm_via_private_t * dev_priv);
static int via_wait_idle(drm_via_private_t * dev_priv);
int via_dma_cleanup(drm_device_t *dev)
{
if (dev->dev_private) {
drm_via_private_t *dev_priv =
(drm_via_private_t *) dev->dev_private;
if (dev_priv->ring.virtual_start) {
via_cmdbuf_reset(dev_priv);
drm_core_ioremapfree( &dev_priv->ring.map, dev);
dev_priv->ring.virtual_start = NULL;
}
}
return 0;
}
static int via_initialize(drm_device_t *dev,
drm_via_private_t *dev_priv,
drm_via_dma_init_t *init)
{
if (!dev_priv || !dev_priv->mmio) {
DRM_ERROR("via_dma_init called before via_map_init\n");
return DRM_ERR(EFAULT);
}
if (dev_priv->ring.virtual_start != NULL) {
DRM_ERROR("%s called again without calling cleanup\n",
__FUNCTION__);
return DRM_ERR(EFAULT);
}
dev_priv->ring.map.offset = dev->agp->base + init->offset;
dev_priv->ring.map.size = init->size;
dev_priv->ring.map.type = 0;
dev_priv->ring.map.flags = 0;
dev_priv->ring.map.mtrr = 0;
drm_core_ioremap( &dev_priv->ring.map, dev );
if (dev_priv->ring.map.handle == NULL) {
via_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
return DRM_ERR(ENOMEM);
}
dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
dev_priv->dma_ptr = dev_priv->ring.virtual_start;
dev_priv->dma_low = 0;
dev_priv->dma_high = init->size;
dev_priv->dma_offset = init->offset;
dev_priv->last_pause_ptr = NULL;
dev_priv->hw_addr_ptr = dev_priv->mmio->handle + init->reg_pause_addr;
via_cmdbuf_start(dev_priv);
return 0;
}
int via_dma_init( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
drm_via_dma_init_t init;
int retcode = 0;
DRM_COPY_FROM_USER_IOCTL(init, (drm_via_dma_init_t *)data, sizeof(init));
switch(init.func) {
case VIA_INIT_DMA:
retcode = via_initialize(dev, dev_priv, &init);
break;
case VIA_CLEANUP_DMA:
retcode = via_dma_cleanup(dev);
break;
default:
retcode = DRM_ERR(EINVAL);
break;
}
return retcode;
}
static int via_dispatch_cmdbuffer(drm_device_t *dev,
drm_via_cmdbuffer_t *cmd )
{
drm_via_private_t *dev_priv = dev->dev_private;
uint32_t * vb;
vb = via_check_dma(dev_priv, cmd->size);
if (vb == NULL) {
return DRM_ERR(EAGAIN);
}
DRM_COPY_FROM_USER(vb, cmd->buf, cmd->size);
dev_priv->dma_low += cmd->size;
via_cmdbuf_pause(dev_priv);
return 0;
}
static int via_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 0;
}
int via_flush_ioctl( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
DRM_ERROR("via_flush_ioctl called without lock held\n");
return DRM_ERR(EINVAL);
}
return via_quiescent(dev);
}
int via_cmdbuffer( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_via_cmdbuffer_t cmdbuf;
int ret;
DRM_COPY_FROM_USER_IOCTL( cmdbuf, (drm_via_cmdbuffer_t *)data,
sizeof(cmdbuf) );
DRM_DEBUG("via cmdbuffer, buf %p size %lu\n", cmdbuf.buf, cmdbuf.size);
if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
DRM_ERROR("via_cmdbuffer called without lock held\n");
return DRM_ERR(EINVAL);
}
ret = via_dispatch_cmdbuffer( dev, &cmdbuf );
if (ret) {
return ret;
}
return 0;
}
/************************************************************************/
#include "via_3d_reg.h"
#define CMDBUF_ALIGNMENT_SIZE (0x100)
#define CMDBUF_ALIGNMENT_MASK (0xff)
/* defines for VIA 3D registers */
#define VIA_REG_STATUS 0x400
#define VIA_REG_TRANSET 0x43C
#define VIA_REG_TRANSPACE 0x440
/* VIA_REG_STATUS(0x400): Engine Status */
#define VIA_CMD_RGTR_BUSY 0x00000080 /* Command Regulator is busy */
#define VIA_2D_ENG_BUSY 0x00000001 /* 2D Engine is busy */
#define VIA_3D_ENG_BUSY 0x00000002 /* 3D Engine is busy */
#define VIA_VR_QUEUE_BUSY 0x00020000 /* Virtual Queue is busy */
#define SetReg2DAGP(nReg, nData) { \
*((uint32_t *)(vb)) = ((nReg) >> 2) | 0xF0000000; \
*((uint32_t *)(vb) + 1) = (nData); \
vb = ((uint32_t *)vb) + 2; \
dev_priv->dma_low +=8; \
}
static uint32_t via_swap_count = 0;
static inline uint32_t *
via_align_buffer(drm_via_private_t * dev_priv, uint32_t * vb, int qw_count)
{
for ( ; qw_count > 0; --qw_count) {
*vb++ = (0xcc000000 | (dev_priv->dma_low & 0xffffff));
*vb++ = (0xdd400000 | via_swap_count);
dev_priv->dma_low += 8;
}
via_swap_count = (via_swap_count + 1) & 0xffff;
return vb;
}
static inline int
via_cmdbuf_wait(drm_via_private_t * dev_priv, unsigned int size)
{
uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
uint32_t cur_addr, hw_addr, next_addr;
volatile uint32_t * hw_addr_ptr;
uint32_t count;
hw_addr_ptr = dev_priv->hw_addr_ptr;
cur_addr = agp_base + dev_priv->dma_low;
/* At high resolution (i.e. 1280x1024) and with high workload within
* a short commmand stream, the following test will fail. It may be
* that the engine is too busy to update hw_addr. Therefore, add
* a large 64KB window between buffer head and tail.
*/
next_addr = cur_addr + size + 64 * 1024;
count = 1000000; /* How long is this? */
do {
hw_addr = *hw_addr_ptr;
if (count-- == 0) {
DRM_ERROR("via_cmdbuf_wait timed out hw %x dma_low %x\n",
hw_addr, dev_priv->dma_low);
return -1;
}
} while ((cur_addr < hw_addr) && (next_addr >= hw_addr));
return 0;
}
/*
* Checks whether buffer head has reach the end. Rewind the ring buffer
* when necessary.
*
* Returns virtual pointer to ring buffer.
*/
static inline uint32_t *
via_check_dma(drm_via_private_t * dev_priv, unsigned int size)
{
if ((dev_priv->dma_low + size + 0x400) > dev_priv->dma_high) {
via_cmdbuf_rewind(dev_priv);
}
if (via_cmdbuf_wait(dev_priv, size) != 0) {
return NULL;
}
return (uint32_t*)(dev_priv->dma_ptr + dev_priv->dma_low);
}
/*
* This function is used internally by ring buffer mangement code.
*
* Returns virtual pointer to ring buffer.
*/
static inline uint32_t * via_get_dma(drm_via_private_t * dev_priv)
{
return (uint32_t*)(dev_priv->dma_ptr + dev_priv->dma_low);
}
static int via_wait_idle(drm_via_private_t * dev_priv)
{
int count = 10000000;
while (count-- && (VIA_READ(VIA_REG_STATUS) &
(VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY)));
return count;
}
static inline void
via_dummy_bitblt(drm_via_private_t * dev_priv)
{
uint32_t * vb = via_get_dma(dev_priv);
/* GEDST*/
SetReg2DAGP(0x0C, (0 | (0 << 16)));
/* GEWD*/
SetReg2DAGP(0x10, 0 | (0 << 16));
/* BITBLT*/
SetReg2DAGP(0x0, 0x1 | 0x2000 | 0xAA000000);
}
static void via_cmdbuf_start(drm_via_private_t * dev_priv)
{
uint32_t agp_base;
uint32_t pause_addr, pause_addr_lo, pause_addr_hi;
uint32_t start_addr, start_addr_lo;
uint32_t end_addr, end_addr_lo;
uint32_t qw_pad_count;
uint32_t command;
uint32_t * vb;
dev_priv->dma_low = 0;
vb = via_get_dma(dev_priv);
agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
start_addr = agp_base;
end_addr = agp_base + dev_priv->dma_high;
start_addr_lo = ((HC_SubA_HAGPBstL << 24) | (start_addr & 0xFFFFFF));
end_addr_lo = ((HC_SubA_HAGPBendL << 24) | (end_addr & 0xFFFFFF));
command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) |
((end_addr & 0xff000000) >> 16));
*vb++ = HC_HEADER2 | ((VIA_REG_TRANSET>>2)<<12) |
(VIA_REG_TRANSPACE>>2);
*vb++ = (HC_ParaType_PreCR<<16);
dev_priv->dma_low += 8;
qw_pad_count = (CMDBUF_ALIGNMENT_SIZE>>3) -
((dev_priv->dma_low & CMDBUF_ALIGNMENT_MASK) >> 3);
pause_addr = agp_base + dev_priv->dma_low - 8 + (qw_pad_count<<3);
pause_addr_lo = ((HC_SubA_HAGPBpL<<24) |
HC_HAGPBpID_PAUSE |
(pause_addr & 0xffffff));
pause_addr_hi = ((HC_SubA_HAGPBpH<<24) | (pause_addr >> 24));
vb = via_align_buffer(dev_priv, vb, qw_pad_count-1);
*vb++ = pause_addr_hi;
*vb++ = pause_addr_lo;
dev_priv->dma_low += 8;
dev_priv->last_pause_ptr = vb-1;
VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
VIA_WRITE(VIA_REG_TRANSPACE, command);
VIA_WRITE(VIA_REG_TRANSPACE, start_addr_lo);
VIA_WRITE(VIA_REG_TRANSPACE, end_addr_lo);
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
}
static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
{
uint32_t agp_base;
uint32_t pause_addr, pause_addr_lo, pause_addr_hi;
uint32_t start_addr;
uint32_t end_addr, end_addr_lo;
uint32_t * vb;
uint32_t qw_pad_count;
uint32_t command;
uint32_t jump_addr, jump_addr_lo, jump_addr_hi;
/* Seems like Unichrome has bug that when the PAUSE register is
* set in the AGP command stream immediately after a PCI write to
* the same register, the command regulator goes into a looping
* state. Prepending a BitBLT command to stall the command
* regulator for a moment seems to solve the problem.
*/
via_cmdbuf_wait(dev_priv, 48);
via_dummy_bitblt(dev_priv);
via_cmdbuf_wait(dev_priv, 2*CMDBUF_ALIGNMENT_SIZE);
/* At end of buffer, rewind with a JUMP command. */
vb = via_get_dma(dev_priv);
*vb++ = HC_HEADER2 | ((VIA_REG_TRANSET>>2)<<12) |
(VIA_REG_TRANSPACE>>2);
*vb++ = (HC_ParaType_PreCR<<16);
dev_priv->dma_low += 8;
qw_pad_count = (CMDBUF_ALIGNMENT_SIZE>>3) -
((dev_priv->dma_low & CMDBUF_ALIGNMENT_MASK) >> 3);
agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
start_addr = agp_base;
end_addr = agp_base + dev_priv->dma_low - 8 + (qw_pad_count<<3);
jump_addr = end_addr;
jump_addr_lo = ((HC_SubA_HAGPBpL<<24) | HC_HAGPBpID_JUMP |
(jump_addr & 0xffffff));
jump_addr_hi = ((HC_SubA_HAGPBpH<<24) | (jump_addr >> 24));
end_addr_lo = ((HC_SubA_HAGPBendL << 24) | (end_addr & 0xFFFFFF));
command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) |
((end_addr & 0xff000000) >> 16));
*vb++ = command;
*vb++ = end_addr_lo;
dev_priv->dma_low += 8;
vb = via_align_buffer(dev_priv, vb, qw_pad_count-1);
/* Now at beginning of buffer, make sure engine will pause here. */
dev_priv->dma_low = 0;
if (via_cmdbuf_wait(dev_priv, CMDBUF_ALIGNMENT_SIZE) != 0) {
DRM_ERROR("via_cmdbuf_jump failed\n");
}
vb = via_get_dma(dev_priv);
end_addr = agp_base + dev_priv->dma_high;
end_addr_lo = ((HC_SubA_HAGPBendL << 24) | (end_addr & 0xFFFFFF));
command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) |
((end_addr & 0xff000000) >> 16));
qw_pad_count = (CMDBUF_ALIGNMENT_SIZE>>3) -
((dev_priv->dma_low & CMDBUF_ALIGNMENT_MASK) >> 3);
pause_addr = agp_base + dev_priv->dma_low - 8 + (qw_pad_count<<3);
pause_addr_lo = ((HC_SubA_HAGPBpL<<24) | HC_HAGPBpID_PAUSE |
(pause_addr & 0xffffff));
pause_addr_hi = ((HC_SubA_HAGPBpH<<24) | (pause_addr >> 24));
*vb++ = HC_HEADER2 | ((VIA_REG_TRANSET>>2)<<12) |
(VIA_REG_TRANSPACE>>2);
*vb++ = (HC_ParaType_PreCR<<16);
dev_priv->dma_low += 8;
*vb++ = pause_addr_hi;
*vb++ = pause_addr_lo;
dev_priv->dma_low += 8;
*vb++ = command;
*vb++ = end_addr_lo;
dev_priv->dma_low += 8;
vb = via_align_buffer(dev_priv, vb, qw_pad_count - 4);
*vb++ = pause_addr_hi;
*vb++ = pause_addr_lo;
dev_priv->dma_low += 8;
*dev_priv->last_pause_ptr = jump_addr_lo;
dev_priv->last_pause_ptr = vb-1;
if (VIA_READ(0x41c) & 0x80000000) {
VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
VIA_WRITE(VIA_REG_TRANSPACE, jump_addr_hi);
VIA_WRITE(VIA_REG_TRANSPACE, jump_addr_lo);
}
}
static void via_cmdbuf_rewind(drm_via_private_t * dev_priv)
{
via_cmdbuf_pause(dev_priv);
via_cmdbuf_jump(dev_priv);
}
static void via_cmdbuf_flush(drm_via_private_t * dev_priv, uint32_t cmd_type)
{
uint32_t agp_base;
uint32_t pause_addr, pause_addr_lo, pause_addr_hi;
uint32_t * vb;
uint32_t qw_pad_count;
via_cmdbuf_wait(dev_priv, 0x200);
vb = via_get_dma(dev_priv);
*vb++ = HC_HEADER2 | ((VIA_REG_TRANSET>>2)<<12) |
(VIA_REG_TRANSPACE>>2);
*vb++ = (HC_ParaType_PreCR<<16);
dev_priv->dma_low += 8;
agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
qw_pad_count = (CMDBUF_ALIGNMENT_SIZE>>3) -
((dev_priv->dma_low & CMDBUF_ALIGNMENT_MASK) >> 3);
pause_addr = agp_base + dev_priv->dma_low - 8 + (qw_pad_count<<3);
pause_addr_lo = ((HC_SubA_HAGPBpL<<24) | cmd_type |
(pause_addr & 0xffffff));
pause_addr_hi = ((HC_SubA_HAGPBpH<<24) | (pause_addr >> 24));
vb = via_align_buffer(dev_priv, vb, qw_pad_count-1);
*vb++ = pause_addr_hi;
*vb++ = pause_addr_lo;
dev_priv->dma_low += 8;
*dev_priv->last_pause_ptr = pause_addr_lo;
dev_priv->last_pause_ptr = vb-1;
if (VIA_READ(0x41c) & 0x80000000) {
VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
}
}
static void via_cmdbuf_pause(drm_via_private_t * dev_priv)
{
via_cmdbuf_flush(dev_priv, HC_HAGPBpID_PAUSE);
}
static void via_cmdbuf_reset(drm_via_private_t * dev_priv)
{
via_cmdbuf_flush(dev_priv, HC_HAGPBpID_STOP);
via_wait_idle(dev_priv);
}
/************************************************************************/

View file

@ -66,6 +66,9 @@
#define DRM_IOCTL_VIA_FB_INIT DRM_IOWR(0x43, drm_via_fb_t)
#define DRM_IOCTL_VIA_MAP_INIT DRM_IOWR(0x44, drm_via_init_t)
#define DRM_IOCTL_VIA_DEC_FUTEX DRM_IOW(0x45, drm_via_futex_t)
#define DRM_IOCTL_VIA_DMA_INIT DRM_IOWR(0x47, drm_via_dma_init_t)
#define DRM_IOCTL_VIA_CMDBUFFER DRM_IOWR(0x48, drm_via_dma_init_t)
#define DRM_IOCTL_VIA_FLUSH DRM_IO(0x49)
/* Indices into buf.Setup where various bits of state are mirrored per
* context and per buffer. These can be fired at the card as a unit,
@ -123,6 +126,22 @@ typedef struct _drm_via_futex {
unsigned int val;
} drm_via_futex_t;
typedef struct _drm_via_dma_init {
enum {
VIA_INIT_DMA = 0x01,
VIA_CLEANUP_DMA = 0x02
} func;
unsigned long offset;
unsigned long size;
unsigned long reg_pause_addr;
} drm_via_dma_init_t;
typedef struct _drm_via_cmdbuffer {
char *buf;
unsigned long size;
} drm_via_cmdbuffer_t;
/* Warning: If you change the SAREA structure you must change the Xserver
* structure as well */
@ -178,6 +197,9 @@ int via_mem_free( DRM_IOCTL_ARGS );
int via_agp_init( DRM_IOCTL_ARGS );
int via_map_init( DRM_IOCTL_ARGS );
int via_decoder_futex( DRM_IOCTL_ARGS );
int via_dma_init( DRM_IOCTL_ARGS );
int via_cmdbuffer( DRM_IOCTL_ARGS );
int via_flush_ioctl( DRM_IOCTL_ARGS );
#endif
#endif /* _VIA_DRM_H_ */

View file

@ -31,10 +31,10 @@
#define DRIVER_NAME "via"
#define DRIVER_DESC "VIA Unichrome"
#define DRIVER_DATE "20040411"
#define DRIVER_DATE "20040819"
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 3
#define DRIVER_MINOR 4
#define DRIVER_PATCHLEVEL 0
@ -44,7 +44,10 @@
[DRM_IOCTL_NR(DRM_IOCTL_VIA_AGP_INIT)] = { via_agp_init, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_VIA_FB_INIT)] = { via_fb_init, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_VIA_MAP_INIT)] = { via_map_init, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_VIA_DEC_FUTEX)] = { via_decoder_futex, 1, 0}
[DRM_IOCTL_NR(DRM_IOCTL_VIA_DEC_FUTEX)] = { via_decoder_futex, 1, 0}, \
[DRM_IOCTL_NR(DRM_IOCTL_VIA_DMA_INIT)] = { via_dma_init, 1, 0}, \
[DRM_IOCTL_NR(DRM_IOCTL_VIA_CMDBUFFER)] = { via_cmdbuffer, 1, 0}, \
[DRM_IOCTL_NR(DRM_IOCTL_VIA_FLUSH)] = { via_flush_ioctl, 1, 0}
#define __HAVE_COUNTERS 0

View file

@ -27,6 +27,11 @@
#include "via_drm.h"
typedef struct drm_via_ring_buffer {
drm_map_t map;
char * virtual_start;
} drm_via_ring_buffer_t;
typedef struct drm_via_private {
drm_via_sarea_t *sarea_priv;
drm_map_t *sarea;
@ -34,6 +39,13 @@ typedef struct drm_via_private {
drm_map_t *mmio;
unsigned long agpAddr;
wait_queue_head_t decoder_queue[VIA_NR_XVMC_LOCKS];
char * dma_ptr;
unsigned int dma_low;
unsigned int dma_high;
unsigned int dma_offset;
uint32_t * last_pause_ptr;
volatile uint32_t * hw_addr_ptr;
drm_via_ring_buffer_t ring;
} drm_via_private_t;
@ -53,4 +65,6 @@ extern int via_do_cleanup_map(drm_device_t *dev);
extern int via_map_init(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int via_dma_cleanup(drm_device_t *dev);
#endif

View file

@ -83,6 +83,8 @@ int via_do_cleanup_map(drm_device_t *dev)
drm_via_private_t *dev_priv = dev->dev_private;
via_dma_cleanup(dev);
DRM(free)(dev_priv, sizeof(drm_via_private_t),
DRM_MEM_DRIVER);
dev->dev_private = NULL;

View file

@ -171,6 +171,16 @@ int via_final_context(struct drm_device *dev, int context)
global_ppriv[i].used = 0;
}
#if defined(__linux__)
/* Linux specific until context tracking code gets ported to BSD */
/* Last context, perform cleanup */
if (dev->ctx_count == 1 && dev->dev_private) {
if (dev->irq) DRM(irq_uninstall)(dev);
via_do_cleanup_map(dev);
}
#endif
return 1;
}

1644
shared/via_3d_reg.h Normal file

File diff suppressed because it is too large Load diff

517
shared/via_dma.c Normal file
View file

@ -0,0 +1,517 @@
/* via_dma.c -- DMA support for the VIA Unichrome/Pro
*/
/**************************************************************************
*
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* Copyright 2004 Digeo, Inc., Palo Alto, CA, U.S.A.
* All Rights Reserved.
*
**************************************************************************/
#define __NO_VERSION__
#include "via.h"
#include "drmP.h"
#include "drm.h"
#include "via_drm.h"
#include "via_drv.h"
static inline uint32_t * via_check_dma(drm_via_private_t * dev_priv,
unsigned int size);
static void via_cmdbuf_start(drm_via_private_t * dev_priv);
static void via_cmdbuf_pause(drm_via_private_t * dev_priv);
static void via_cmdbuf_reset(drm_via_private_t * dev_priv);
static void via_cmdbuf_rewind(drm_via_private_t * dev_priv);
static int via_wait_idle(drm_via_private_t * dev_priv);
int via_dma_cleanup(drm_device_t *dev)
{
if (dev->dev_private) {
drm_via_private_t *dev_priv =
(drm_via_private_t *) dev->dev_private;
if (dev_priv->ring.virtual_start) {
via_cmdbuf_reset(dev_priv);
drm_core_ioremapfree( &dev_priv->ring.map, dev);
dev_priv->ring.virtual_start = NULL;
}
}
return 0;
}
static int via_initialize(drm_device_t *dev,
drm_via_private_t *dev_priv,
drm_via_dma_init_t *init)
{
if (!dev_priv || !dev_priv->mmio) {
DRM_ERROR("via_dma_init called before via_map_init\n");
return DRM_ERR(EFAULT);
}
if (dev_priv->ring.virtual_start != NULL) {
DRM_ERROR("%s called again without calling cleanup\n",
__FUNCTION__);
return DRM_ERR(EFAULT);
}
dev_priv->ring.map.offset = dev->agp->base + init->offset;
dev_priv->ring.map.size = init->size;
dev_priv->ring.map.type = 0;
dev_priv->ring.map.flags = 0;
dev_priv->ring.map.mtrr = 0;
drm_core_ioremap( &dev_priv->ring.map, dev );
if (dev_priv->ring.map.handle == NULL) {
via_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
return DRM_ERR(ENOMEM);
}
dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
dev_priv->dma_ptr = dev_priv->ring.virtual_start;
dev_priv->dma_low = 0;
dev_priv->dma_high = init->size;
dev_priv->dma_offset = init->offset;
dev_priv->last_pause_ptr = NULL;
dev_priv->hw_addr_ptr = dev_priv->mmio->handle + init->reg_pause_addr;
via_cmdbuf_start(dev_priv);
return 0;
}
int via_dma_init( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
drm_via_dma_init_t init;
int retcode = 0;
DRM_COPY_FROM_USER_IOCTL(init, (drm_via_dma_init_t *)data, sizeof(init));
switch(init.func) {
case VIA_INIT_DMA:
retcode = via_initialize(dev, dev_priv, &init);
break;
case VIA_CLEANUP_DMA:
retcode = via_dma_cleanup(dev);
break;
default:
retcode = DRM_ERR(EINVAL);
break;
}
return retcode;
}
static int via_dispatch_cmdbuffer(drm_device_t *dev,
drm_via_cmdbuffer_t *cmd )
{
drm_via_private_t *dev_priv = dev->dev_private;
uint32_t * vb;
vb = via_check_dma(dev_priv, cmd->size);
if (vb == NULL) {
return DRM_ERR(EAGAIN);
}
DRM_COPY_FROM_USER(vb, cmd->buf, cmd->size);
dev_priv->dma_low += cmd->size;
via_cmdbuf_pause(dev_priv);
return 0;
}
static int via_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 0;
}
int via_flush_ioctl( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
DRM_ERROR("via_flush_ioctl called without lock held\n");
return DRM_ERR(EINVAL);
}
return via_quiescent(dev);
}
int via_cmdbuffer( DRM_IOCTL_ARGS )
{
DRM_DEVICE;
drm_via_cmdbuffer_t cmdbuf;
int ret;
DRM_COPY_FROM_USER_IOCTL( cmdbuf, (drm_via_cmdbuffer_t *)data,
sizeof(cmdbuf) );
DRM_DEBUG("via cmdbuffer, buf %p size %lu\n", cmdbuf.buf, cmdbuf.size);
if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
DRM_ERROR("via_cmdbuffer called without lock held\n");
return DRM_ERR(EINVAL);
}
ret = via_dispatch_cmdbuffer( dev, &cmdbuf );
if (ret) {
return ret;
}
return 0;
}
/************************************************************************/
#include "via_3d_reg.h"
#define CMDBUF_ALIGNMENT_SIZE (0x100)
#define CMDBUF_ALIGNMENT_MASK (0xff)
/* defines for VIA 3D registers */
#define VIA_REG_STATUS 0x400
#define VIA_REG_TRANSET 0x43C
#define VIA_REG_TRANSPACE 0x440
/* VIA_REG_STATUS(0x400): Engine Status */
#define VIA_CMD_RGTR_BUSY 0x00000080 /* Command Regulator is busy */
#define VIA_2D_ENG_BUSY 0x00000001 /* 2D Engine is busy */
#define VIA_3D_ENG_BUSY 0x00000002 /* 3D Engine is busy */
#define VIA_VR_QUEUE_BUSY 0x00020000 /* Virtual Queue is busy */
#define SetReg2DAGP(nReg, nData) { \
*((uint32_t *)(vb)) = ((nReg) >> 2) | 0xF0000000; \
*((uint32_t *)(vb) + 1) = (nData); \
vb = ((uint32_t *)vb) + 2; \
dev_priv->dma_low +=8; \
}
static uint32_t via_swap_count = 0;
static inline uint32_t *
via_align_buffer(drm_via_private_t * dev_priv, uint32_t * vb, int qw_count)
{
for ( ; qw_count > 0; --qw_count) {
*vb++ = (0xcc000000 | (dev_priv->dma_low & 0xffffff));
*vb++ = (0xdd400000 | via_swap_count);
dev_priv->dma_low += 8;
}
via_swap_count = (via_swap_count + 1) & 0xffff;
return vb;
}
static inline int
via_cmdbuf_wait(drm_via_private_t * dev_priv, unsigned int size)
{
uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
uint32_t cur_addr, hw_addr, next_addr;
volatile uint32_t * hw_addr_ptr;
uint32_t count;
hw_addr_ptr = dev_priv->hw_addr_ptr;
cur_addr = agp_base + dev_priv->dma_low;
/* At high resolution (i.e. 1280x1024) and with high workload within
* a short commmand stream, the following test will fail. It may be
* that the engine is too busy to update hw_addr. Therefore, add
* a large 64KB window between buffer head and tail.
*/
next_addr = cur_addr + size + 64 * 1024;
count = 1000000; /* How long is this? */
do {
hw_addr = *hw_addr_ptr;
if (count-- == 0) {
DRM_ERROR("via_cmdbuf_wait timed out hw %x dma_low %x\n",
hw_addr, dev_priv->dma_low);
return -1;
}
} while ((cur_addr < hw_addr) && (next_addr >= hw_addr));
return 0;
}
/*
* Checks whether buffer head has reach the end. Rewind the ring buffer
* when necessary.
*
* Returns virtual pointer to ring buffer.
*/
static inline uint32_t *
via_check_dma(drm_via_private_t * dev_priv, unsigned int size)
{
if ((dev_priv->dma_low + size + 0x400) > dev_priv->dma_high) {
via_cmdbuf_rewind(dev_priv);
}
if (via_cmdbuf_wait(dev_priv, size) != 0) {
return NULL;
}
return (uint32_t*)(dev_priv->dma_ptr + dev_priv->dma_low);
}
/*
* This function is used internally by ring buffer mangement code.
*
* Returns virtual pointer to ring buffer.
*/
static inline uint32_t * via_get_dma(drm_via_private_t * dev_priv)
{
return (uint32_t*)(dev_priv->dma_ptr + dev_priv->dma_low);
}
static int via_wait_idle(drm_via_private_t * dev_priv)
{
int count = 10000000;
while (count-- && (VIA_READ(VIA_REG_STATUS) &
(VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY)));
return count;
}
static inline void
via_dummy_bitblt(drm_via_private_t * dev_priv)
{
uint32_t * vb = via_get_dma(dev_priv);
/* GEDST*/
SetReg2DAGP(0x0C, (0 | (0 << 16)));
/* GEWD*/
SetReg2DAGP(0x10, 0 | (0 << 16));
/* BITBLT*/
SetReg2DAGP(0x0, 0x1 | 0x2000 | 0xAA000000);
}
static void via_cmdbuf_start(drm_via_private_t * dev_priv)
{
uint32_t agp_base;
uint32_t pause_addr, pause_addr_lo, pause_addr_hi;
uint32_t start_addr, start_addr_lo;
uint32_t end_addr, end_addr_lo;
uint32_t qw_pad_count;
uint32_t command;
uint32_t * vb;
dev_priv->dma_low = 0;
vb = via_get_dma(dev_priv);
agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
start_addr = agp_base;
end_addr = agp_base + dev_priv->dma_high;
start_addr_lo = ((HC_SubA_HAGPBstL << 24) | (start_addr & 0xFFFFFF));
end_addr_lo = ((HC_SubA_HAGPBendL << 24) | (end_addr & 0xFFFFFF));
command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) |
((end_addr & 0xff000000) >> 16));
*vb++ = HC_HEADER2 | ((VIA_REG_TRANSET>>2)<<12) |
(VIA_REG_TRANSPACE>>2);
*vb++ = (HC_ParaType_PreCR<<16);
dev_priv->dma_low += 8;
qw_pad_count = (CMDBUF_ALIGNMENT_SIZE>>3) -
((dev_priv->dma_low & CMDBUF_ALIGNMENT_MASK) >> 3);
pause_addr = agp_base + dev_priv->dma_low - 8 + (qw_pad_count<<3);
pause_addr_lo = ((HC_SubA_HAGPBpL<<24) |
HC_HAGPBpID_PAUSE |
(pause_addr & 0xffffff));
pause_addr_hi = ((HC_SubA_HAGPBpH<<24) | (pause_addr >> 24));
vb = via_align_buffer(dev_priv, vb, qw_pad_count-1);
*vb++ = pause_addr_hi;
*vb++ = pause_addr_lo;
dev_priv->dma_low += 8;
dev_priv->last_pause_ptr = vb-1;
VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
VIA_WRITE(VIA_REG_TRANSPACE, command);
VIA_WRITE(VIA_REG_TRANSPACE, start_addr_lo);
VIA_WRITE(VIA_REG_TRANSPACE, end_addr_lo);
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
}
static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
{
uint32_t agp_base;
uint32_t pause_addr, pause_addr_lo, pause_addr_hi;
uint32_t start_addr;
uint32_t end_addr, end_addr_lo;
uint32_t * vb;
uint32_t qw_pad_count;
uint32_t command;
uint32_t jump_addr, jump_addr_lo, jump_addr_hi;
/* Seems like Unichrome has bug that when the PAUSE register is
* set in the AGP command stream immediately after a PCI write to
* the same register, the command regulator goes into a looping
* state. Prepending a BitBLT command to stall the command
* regulator for a moment seems to solve the problem.
*/
via_cmdbuf_wait(dev_priv, 48);
via_dummy_bitblt(dev_priv);
via_cmdbuf_wait(dev_priv, 2*CMDBUF_ALIGNMENT_SIZE);
/* At end of buffer, rewind with a JUMP command. */
vb = via_get_dma(dev_priv);
*vb++ = HC_HEADER2 | ((VIA_REG_TRANSET>>2)<<12) |
(VIA_REG_TRANSPACE>>2);
*vb++ = (HC_ParaType_PreCR<<16);
dev_priv->dma_low += 8;
qw_pad_count = (CMDBUF_ALIGNMENT_SIZE>>3) -
((dev_priv->dma_low & CMDBUF_ALIGNMENT_MASK) >> 3);
agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
start_addr = agp_base;
end_addr = agp_base + dev_priv->dma_low - 8 + (qw_pad_count<<3);
jump_addr = end_addr;
jump_addr_lo = ((HC_SubA_HAGPBpL<<24) | HC_HAGPBpID_JUMP |
(jump_addr & 0xffffff));
jump_addr_hi = ((HC_SubA_HAGPBpH<<24) | (jump_addr >> 24));
end_addr_lo = ((HC_SubA_HAGPBendL << 24) | (end_addr & 0xFFFFFF));
command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) |
((end_addr & 0xff000000) >> 16));
*vb++ = command;
*vb++ = end_addr_lo;
dev_priv->dma_low += 8;
vb = via_align_buffer(dev_priv, vb, qw_pad_count-1);
/* Now at beginning of buffer, make sure engine will pause here. */
dev_priv->dma_low = 0;
if (via_cmdbuf_wait(dev_priv, CMDBUF_ALIGNMENT_SIZE) != 0) {
DRM_ERROR("via_cmdbuf_jump failed\n");
}
vb = via_get_dma(dev_priv);
end_addr = agp_base + dev_priv->dma_high;
end_addr_lo = ((HC_SubA_HAGPBendL << 24) | (end_addr & 0xFFFFFF));
command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) |
((end_addr & 0xff000000) >> 16));
qw_pad_count = (CMDBUF_ALIGNMENT_SIZE>>3) -
((dev_priv->dma_low & CMDBUF_ALIGNMENT_MASK) >> 3);
pause_addr = agp_base + dev_priv->dma_low - 8 + (qw_pad_count<<3);
pause_addr_lo = ((HC_SubA_HAGPBpL<<24) | HC_HAGPBpID_PAUSE |
(pause_addr & 0xffffff));
pause_addr_hi = ((HC_SubA_HAGPBpH<<24) | (pause_addr >> 24));
*vb++ = HC_HEADER2 | ((VIA_REG_TRANSET>>2)<<12) |
(VIA_REG_TRANSPACE>>2);
*vb++ = (HC_ParaType_PreCR<<16);
dev_priv->dma_low += 8;
*vb++ = pause_addr_hi;
*vb++ = pause_addr_lo;
dev_priv->dma_low += 8;
*vb++ = command;
*vb++ = end_addr_lo;
dev_priv->dma_low += 8;
vb = via_align_buffer(dev_priv, vb, qw_pad_count - 4);
*vb++ = pause_addr_hi;
*vb++ = pause_addr_lo;
dev_priv->dma_low += 8;
*dev_priv->last_pause_ptr = jump_addr_lo;
dev_priv->last_pause_ptr = vb-1;
if (VIA_READ(0x41c) & 0x80000000) {
VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
VIA_WRITE(VIA_REG_TRANSPACE, jump_addr_hi);
VIA_WRITE(VIA_REG_TRANSPACE, jump_addr_lo);
}
}
static void via_cmdbuf_rewind(drm_via_private_t * dev_priv)
{
via_cmdbuf_pause(dev_priv);
via_cmdbuf_jump(dev_priv);
}
static void via_cmdbuf_flush(drm_via_private_t * dev_priv, uint32_t cmd_type)
{
uint32_t agp_base;
uint32_t pause_addr, pause_addr_lo, pause_addr_hi;
uint32_t * vb;
uint32_t qw_pad_count;
via_cmdbuf_wait(dev_priv, 0x200);
vb = via_get_dma(dev_priv);
*vb++ = HC_HEADER2 | ((VIA_REG_TRANSET>>2)<<12) |
(VIA_REG_TRANSPACE>>2);
*vb++ = (HC_ParaType_PreCR<<16);
dev_priv->dma_low += 8;
agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
qw_pad_count = (CMDBUF_ALIGNMENT_SIZE>>3) -
((dev_priv->dma_low & CMDBUF_ALIGNMENT_MASK) >> 3);
pause_addr = agp_base + dev_priv->dma_low - 8 + (qw_pad_count<<3);
pause_addr_lo = ((HC_SubA_HAGPBpL<<24) | cmd_type |
(pause_addr & 0xffffff));
pause_addr_hi = ((HC_SubA_HAGPBpH<<24) | (pause_addr >> 24));
vb = via_align_buffer(dev_priv, vb, qw_pad_count-1);
*vb++ = pause_addr_hi;
*vb++ = pause_addr_lo;
dev_priv->dma_low += 8;
*dev_priv->last_pause_ptr = pause_addr_lo;
dev_priv->last_pause_ptr = vb-1;
if (VIA_READ(0x41c) & 0x80000000) {
VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
}
}
static void via_cmdbuf_pause(drm_via_private_t * dev_priv)
{
via_cmdbuf_flush(dev_priv, HC_HAGPBpID_PAUSE);
}
static void via_cmdbuf_reset(drm_via_private_t * dev_priv)
{
via_cmdbuf_flush(dev_priv, HC_HAGPBpID_STOP);
via_wait_idle(dev_priv);
}
/************************************************************************/

View file

@ -66,6 +66,9 @@
#define DRM_IOCTL_VIA_FB_INIT DRM_IOWR(0x43, drm_via_fb_t)
#define DRM_IOCTL_VIA_MAP_INIT DRM_IOWR(0x44, drm_via_init_t)
#define DRM_IOCTL_VIA_DEC_FUTEX DRM_IOW(0x45, drm_via_futex_t)
#define DRM_IOCTL_VIA_DMA_INIT DRM_IOWR(0x47, drm_via_dma_init_t)
#define DRM_IOCTL_VIA_CMDBUFFER DRM_IOWR(0x48, drm_via_dma_init_t)
#define DRM_IOCTL_VIA_FLUSH DRM_IO(0x49)
/* Indices into buf.Setup where various bits of state are mirrored per
* context and per buffer. These can be fired at the card as a unit,
@ -123,6 +126,22 @@ typedef struct _drm_via_futex {
unsigned int val;
} drm_via_futex_t;
typedef struct _drm_via_dma_init {
enum {
VIA_INIT_DMA = 0x01,
VIA_CLEANUP_DMA = 0x02
} func;
unsigned long offset;
unsigned long size;
unsigned long reg_pause_addr;
} drm_via_dma_init_t;
typedef struct _drm_via_cmdbuffer {
char *buf;
unsigned long size;
} drm_via_cmdbuffer_t;
/* Warning: If you change the SAREA structure you must change the Xserver
* structure as well */
@ -178,6 +197,9 @@ int via_mem_free( DRM_IOCTL_ARGS );
int via_agp_init( DRM_IOCTL_ARGS );
int via_map_init( DRM_IOCTL_ARGS );
int via_decoder_futex( DRM_IOCTL_ARGS );
int via_dma_init( DRM_IOCTL_ARGS );
int via_cmdbuffer( DRM_IOCTL_ARGS );
int via_flush_ioctl( DRM_IOCTL_ARGS );
#endif
#endif /* _VIA_DRM_H_ */

View file

@ -31,10 +31,10 @@
#define DRIVER_NAME "via"
#define DRIVER_DESC "VIA Unichrome"
#define DRIVER_DATE "20040411"
#define DRIVER_DATE "20040819"
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 3
#define DRIVER_MINOR 4
#define DRIVER_PATCHLEVEL 0
@ -44,7 +44,10 @@
[DRM_IOCTL_NR(DRM_IOCTL_VIA_AGP_INIT)] = { via_agp_init, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_VIA_FB_INIT)] = { via_fb_init, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_VIA_MAP_INIT)] = { via_map_init, 1, 0 }, \
[DRM_IOCTL_NR(DRM_IOCTL_VIA_DEC_FUTEX)] = { via_decoder_futex, 1, 0}
[DRM_IOCTL_NR(DRM_IOCTL_VIA_DEC_FUTEX)] = { via_decoder_futex, 1, 0}, \
[DRM_IOCTL_NR(DRM_IOCTL_VIA_DMA_INIT)] = { via_dma_init, 1, 0}, \
[DRM_IOCTL_NR(DRM_IOCTL_VIA_CMDBUFFER)] = { via_cmdbuffer, 1, 0}, \
[DRM_IOCTL_NR(DRM_IOCTL_VIA_FLUSH)] = { via_flush_ioctl, 1, 0}
#define __HAVE_COUNTERS 0

View file

@ -27,6 +27,11 @@
#include "via_drm.h"
typedef struct drm_via_ring_buffer {
drm_map_t map;
char * virtual_start;
} drm_via_ring_buffer_t;
typedef struct drm_via_private {
drm_via_sarea_t *sarea_priv;
drm_map_t *sarea;
@ -34,6 +39,13 @@ typedef struct drm_via_private {
drm_map_t *mmio;
unsigned long agpAddr;
wait_queue_head_t decoder_queue[VIA_NR_XVMC_LOCKS];
char * dma_ptr;
unsigned int dma_low;
unsigned int dma_high;
unsigned int dma_offset;
uint32_t * last_pause_ptr;
volatile uint32_t * hw_addr_ptr;
drm_via_ring_buffer_t ring;
} drm_via_private_t;
@ -53,4 +65,6 @@ extern int via_do_cleanup_map(drm_device_t *dev);
extern int via_map_init(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int via_dma_cleanup(drm_device_t *dev);
#endif

View file

@ -83,6 +83,8 @@ int via_do_cleanup_map(drm_device_t *dev)
drm_via_private_t *dev_priv = dev->dev_private;
via_dma_cleanup(dev);
DRM(free)(dev_priv, sizeof(drm_via_private_t),
DRM_MEM_DRIVER);
dev->dev_private = NULL;

View file

@ -171,6 +171,16 @@ int via_final_context(struct drm_device *dev, int context)
global_ppriv[i].used = 0;
}
#if defined(__linux__)
/* Linux specific until context tracking code gets ported to BSD */
/* Last context, perform cleanup */
if (dev->ctx_count == 1 && dev->dev_private) {
if (dev->irq) DRM(irq_uninstall)(dev);
via_do_cleanup_map(dev);
}
#endif
return 1;
}