Some stabilizing work to the DMA ring-buffer code. Temporarily replaced the
rewind jump with a reinitialization. This makes the code stable on CLE266 and KM400.main
parent
816a291709
commit
8264e2c8aa
|
@ -16,6 +16,14 @@
|
||||||
#include "via_drv.h"
|
#include "via_drv.h"
|
||||||
|
|
||||||
#define VIA_2D_CMD 0xF0000000
|
#define VIA_2D_CMD 0xF0000000
|
||||||
|
#define via_flush_write_combine() DRM_MEMORYBARRIER()
|
||||||
|
|
||||||
|
#define VIA_OUT_RING_QW(w1,w2) \
|
||||||
|
*vb++ = (w1); \
|
||||||
|
*vb++ = (w2); \
|
||||||
|
dev_priv->dma_low += 8;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void via_cmdbuf_start(drm_via_private_t * dev_priv);
|
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_pause(drm_via_private_t * dev_priv);
|
||||||
|
@ -23,6 +31,7 @@ static void via_cmdbuf_reset(drm_via_private_t * dev_priv);
|
||||||
static void via_cmdbuf_rewind(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);
|
static int via_wait_idle(drm_via_private_t * dev_priv);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function needs to be extended whenever a new command set
|
* This function needs to be extended whenever a new command set
|
||||||
* is implemented. Currently it works only for the 2D engine
|
* is implemented. Currently it works only for the 2D engine
|
||||||
|
@ -81,12 +90,7 @@ via_cmdbuf_wait(drm_via_private_t * dev_priv, unsigned int size)
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
hw_addr_ptr = dev_priv->hw_addr_ptr;
|
hw_addr_ptr = dev_priv->hw_addr_ptr;
|
||||||
cur_addr = dev_priv->dma_low;
|
cur_addr = dev_priv->dma_low;
|
||||||
/* At high resolution (i.e. 1280x1024) and with high workload within
|
next_addr = cur_addr + size;
|
||||||
* 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? */
|
count = 1000000; /* How long is this? */
|
||||||
do {
|
do {
|
||||||
hw_addr = *hw_addr_ptr - agp_base;
|
hw_addr = *hw_addr_ptr - agp_base;
|
||||||
|
@ -375,20 +379,16 @@ int via_pci_cmdbuffer(DRM_IOCTL_ARGS)
|
||||||
dev_priv->dma_low +=8; \
|
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,
|
static inline uint32_t *via_align_buffer(drm_via_private_t * dev_priv,
|
||||||
uint32_t * vb, int qw_count)
|
uint32_t * vb, int qw_count)
|
||||||
{
|
{
|
||||||
for (; qw_count > 0; --qw_count) {
|
for (; qw_count > 0; --qw_count) {
|
||||||
*vb++ = (0xcc000000 | (dev_priv->dma_low & 0xffffff));
|
VIA_OUT_RING_QW(HC_DUMMY, HC_DUMMY);
|
||||||
*vb++ = (0xdd400000 | via_swap_count);
|
|
||||||
dev_priv->dma_low += 8;
|
|
||||||
}
|
}
|
||||||
via_swap_count = (via_swap_count + 1) & 0xffff;
|
|
||||||
return vb;
|
return vb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function is used internally by ring buffer mangement code.
|
* This function is used internally by ring buffer mangement code.
|
||||||
*
|
*
|
||||||
|
@ -399,6 +399,58 @@ static inline uint32_t *via_get_dma(drm_via_private_t * dev_priv)
|
||||||
return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low);
|
return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hooks a segment of data into the tail of the ring-buffer by
|
||||||
|
* modifying the pause address stored in the buffer itself. If
|
||||||
|
* the regulator has already paused, restart it.
|
||||||
|
*/
|
||||||
|
static int via_hook_segment(drm_via_private_t *dev_priv,
|
||||||
|
uint32_t pause_addr_hi, uint32_t pause_addr_lo,
|
||||||
|
int no_pci_fire)
|
||||||
|
{
|
||||||
|
int paused, count;
|
||||||
|
|
||||||
|
via_flush_write_combine();
|
||||||
|
while(! *(via_get_dma(dev_priv)-1));
|
||||||
|
*dev_priv->last_pause_ptr = pause_addr_lo;
|
||||||
|
via_flush_write_combine();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The below statement is inserted to really force the flush.
|
||||||
|
* Not sure it is needed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
while(! *dev_priv->last_pause_ptr);
|
||||||
|
dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1;
|
||||||
|
|
||||||
|
paused = 0;
|
||||||
|
count = 3;
|
||||||
|
|
||||||
|
while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--);
|
||||||
|
if ((count < 1) && (count >= 0)) {
|
||||||
|
uint32_t rgtr, ptr;
|
||||||
|
rgtr = *(dev_priv->hw_addr_ptr);
|
||||||
|
ptr = ((char *)dev_priv->last_pause_ptr - dev_priv->dma_ptr) +
|
||||||
|
dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4 - 0x100;
|
||||||
|
if (rgtr <= ptr) {
|
||||||
|
DRM_ERROR("Command regulator\npaused at count %d, address %x, "
|
||||||
|
"while current pause address is %x.\n"
|
||||||
|
"Please mail this message to "
|
||||||
|
"<unichrome-devel@lists.sourceforge.net>\n",
|
||||||
|
count, rgtr, ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (paused && !no_pci_fire) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
return paused;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int via_wait_idle(drm_via_private_t * dev_priv)
|
static int via_wait_idle(drm_via_private_t * dev_priv)
|
||||||
{
|
{
|
||||||
int count = 10000000;
|
int count = 10000000;
|
||||||
|
@ -408,29 +460,50 @@ static int via_wait_idle(drm_via_private_t * dev_priv)
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void via_dummy_bitblt(drm_via_private_t * dev_priv)
|
static uint32_t *via_align_cmd(drm_via_private_t * dev_priv, uint32_t cmd_type,
|
||||||
|
uint32_t addr, uint32_t *cmd_addr_hi,
|
||||||
|
uint32_t *cmd_addr_lo)
|
||||||
{
|
{
|
||||||
uint32_t *vb = via_get_dma(dev_priv);
|
uint32_t agp_base;
|
||||||
/* GEDST */
|
uint32_t cmd_addr, addr_lo, addr_hi;
|
||||||
SetReg2DAGP(0x0C, (0 | (0 << 16)));
|
uint32_t *vb;
|
||||||
/* GEWD */
|
uint32_t qw_pad_count;
|
||||||
SetReg2DAGP(0x10, 0 | (0 << 16));
|
|
||||||
/* BITBLT */
|
via_cmdbuf_wait(dev_priv, 2*CMDBUF_ALIGNMENT_SIZE);
|
||||||
SetReg2DAGP(0x0, 0x1 | 0x2000 | 0xAA000000);
|
|
||||||
|
vb = via_get_dma(dev_priv);
|
||||||
|
VIA_OUT_RING_QW( HC_HEADER2 | ((VIA_REG_TRANSET >> 2) << 12) |
|
||||||
|
(VIA_REG_TRANSPACE >> 2), HC_ParaType_PreCR << 16);
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
cmd_addr = (addr) ? addr :
|
||||||
|
agp_base + dev_priv->dma_low - 8 + (qw_pad_count << 3);
|
||||||
|
addr_lo = ((HC_SubA_HAGPBpL << 24) | cmd_type |
|
||||||
|
(cmd_addr & 0xffffff));
|
||||||
|
addr_hi = ((HC_SubA_HAGPBpH << 24) | (cmd_addr >> 24));
|
||||||
|
|
||||||
|
vb = via_align_buffer(dev_priv, vb, qw_pad_count - 1);
|
||||||
|
VIA_OUT_RING_QW(*cmd_addr_hi = addr_hi,
|
||||||
|
*cmd_addr_lo = addr_lo);
|
||||||
|
return vb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void via_cmdbuf_start(drm_via_private_t * dev_priv)
|
static void via_cmdbuf_start(drm_via_private_t * dev_priv)
|
||||||
{
|
{
|
||||||
uint32_t agp_base;
|
uint32_t pause_addr_lo, pause_addr_hi;
|
||||||
uint32_t pause_addr, pause_addr_lo, pause_addr_hi;
|
|
||||||
uint32_t start_addr, start_addr_lo;
|
uint32_t start_addr, start_addr_lo;
|
||||||
uint32_t end_addr, end_addr_lo;
|
uint32_t end_addr, end_addr_lo;
|
||||||
uint32_t qw_pad_count;
|
|
||||||
uint32_t command;
|
uint32_t command;
|
||||||
uint32_t *vb;
|
uint32_t agp_base;
|
||||||
|
|
||||||
|
|
||||||
dev_priv->dma_low = 0;
|
dev_priv->dma_low = 0;
|
||||||
vb = via_get_dma(dev_priv);
|
|
||||||
|
|
||||||
agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
|
agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
|
||||||
start_addr = agp_base;
|
start_addr = agp_base;
|
||||||
|
@ -441,25 +514,12 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
|
||||||
command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) |
|
command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) |
|
||||||
((end_addr & 0xff000000) >> 16));
|
((end_addr & 0xff000000) >> 16));
|
||||||
|
|
||||||
*vb++ = HC_HEADER2 | ((VIA_REG_TRANSET >> 2) << 12) |
|
dev_priv->last_pause_ptr =
|
||||||
(VIA_REG_TRANSPACE >> 2);
|
via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0,
|
||||||
*vb++ = (HC_ParaType_PreCR << 16);
|
&pause_addr_hi, & pause_addr_lo) - 1;
|
||||||
dev_priv->dma_low += 8;
|
|
||||||
|
|
||||||
qw_pad_count = (CMDBUF_ALIGNMENT_SIZE >> 3) -
|
via_flush_write_combine();
|
||||||
((dev_priv->dma_low & CMDBUF_ALIGNMENT_MASK) >> 3);
|
while(! *dev_priv->last_pause_ptr);
|
||||||
|
|
||||||
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_TRANSET, (HC_ParaType_PreCR << 16));
|
||||||
VIA_WRITE(VIA_REG_TRANSPACE, command);
|
VIA_WRITE(VIA_REG_TRANSPACE, command);
|
||||||
|
@ -471,6 +531,17 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
|
||||||
|
|
||||||
VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
|
VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
|
||||||
}
|
}
|
||||||
|
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_jump(drm_via_private_t * dev_priv)
|
static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
|
||||||
{
|
{
|
||||||
|
@ -563,62 +634,27 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
|
||||||
*vb++ = pause_addr_hi;
|
*vb++ = pause_addr_hi;
|
||||||
*vb++ = pause_addr_lo;
|
*vb++ = pause_addr_lo;
|
||||||
dev_priv->dma_low += 8;
|
dev_priv->dma_low += 8;
|
||||||
|
via_hook_segment( dev_priv, jump_addr_hi, jump_addr_lo, 0);
|
||||||
*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)
|
static void via_cmdbuf_rewind(drm_via_private_t * dev_priv)
|
||||||
{
|
{
|
||||||
via_cmdbuf_pause(dev_priv);
|
/* via_cmdbuf_jump(dev_priv); */
|
||||||
via_cmdbuf_jump(dev_priv);
|
via_cmdbuf_reset(dev_priv);
|
||||||
|
via_cmdbuf_start(dev_priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void via_cmdbuf_flush(drm_via_private_t * dev_priv, uint32_t cmd_type)
|
static void via_cmdbuf_flush(drm_via_private_t * dev_priv, uint32_t cmd_type)
|
||||||
{
|
{
|
||||||
uint32_t agp_base;
|
uint32_t pause_addr_lo, pause_addr_hi;
|
||||||
uint32_t pause_addr, pause_addr_lo, pause_addr_hi;
|
|
||||||
uint32_t *vb;
|
|
||||||
uint32_t qw_pad_count;
|
|
||||||
|
|
||||||
via_cmdbuf_wait(dev_priv, 0x200);
|
via_align_cmd(dev_priv, cmd_type, 0, &pause_addr_hi, &pause_addr_lo);
|
||||||
|
via_hook_segment( dev_priv, pause_addr_hi, pause_addr_lo, 0);
|
||||||
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)
|
static void via_cmdbuf_pause(drm_via_private_t * dev_priv)
|
||||||
{
|
{
|
||||||
via_cmdbuf_flush(dev_priv, HC_HAGPBpID_PAUSE);
|
via_cmdbuf_flush(dev_priv, HC_HAGPBpID_PAUSE);
|
||||||
|
|
|
@ -28,11 +28,11 @@
|
||||||
|
|
||||||
#define DRIVER_NAME "via"
|
#define DRIVER_NAME "via"
|
||||||
#define DRIVER_DESC "VIA Unichrome"
|
#define DRIVER_DESC "VIA Unichrome"
|
||||||
#define DRIVER_DATE "20041012"
|
#define DRIVER_DATE "20041030"
|
||||||
|
|
||||||
#define DRIVER_MAJOR 2
|
#define DRIVER_MAJOR 2
|
||||||
#define DRIVER_MINOR 0
|
#define DRIVER_MINOR 0
|
||||||
#define DRIVER_PATCHLEVEL 1
|
#define DRIVER_PATCHLEVEL 2
|
||||||
|
|
||||||
typedef struct drm_via_ring_buffer {
|
typedef struct drm_via_ring_buffer {
|
||||||
drm_map_t map;
|
drm_map_t map;
|
||||||
|
@ -50,7 +50,7 @@ typedef struct drm_via_private {
|
||||||
unsigned int dma_low;
|
unsigned int dma_low;
|
||||||
unsigned int dma_high;
|
unsigned int dma_high;
|
||||||
unsigned int dma_offset;
|
unsigned int dma_offset;
|
||||||
uint32_t *last_pause_ptr;
|
volatile uint32_t *last_pause_ptr;
|
||||||
volatile uint32_t *hw_addr_ptr;
|
volatile uint32_t *hw_addr_ptr;
|
||||||
drm_via_ring_buffer_t ring;
|
drm_via_ring_buffer_t ring;
|
||||||
char pci_buf[VIA_PREALLOCATED_PCI_SIZE];
|
char pci_buf[VIA_PREALLOCATED_PCI_SIZE];
|
||||||
|
|
|
@ -30,11 +30,11 @@
|
||||||
|
|
||||||
#define DRIVER_NAME "via"
|
#define DRIVER_NAME "via"
|
||||||
#define DRIVER_DESC "VIA Unichrome"
|
#define DRIVER_DESC "VIA Unichrome"
|
||||||
#define DRIVER_DATE "20041012"
|
#define DRIVER_DATE "20041030"
|
||||||
|
|
||||||
#define DRIVER_MAJOR 2
|
#define DRIVER_MAJOR 2
|
||||||
#define DRIVER_MINOR 0
|
#define DRIVER_MINOR 0
|
||||||
#define DRIVER_PATCHLEVEL 1
|
#define DRIVER_PATCHLEVEL 2
|
||||||
|
|
||||||
#define DRIVER_IOCTLS \
|
#define DRIVER_IOCTLS \
|
||||||
[DRM_IOCTL_NR(DRM_IOCTL_VIA_ALLOCMEM)] = { via_mem_alloc, 1, 0 }, \
|
[DRM_IOCTL_NR(DRM_IOCTL_VIA_ALLOCMEM)] = { via_mem_alloc, 1, 0 }, \
|
||||||
|
|
212
shared/via_dma.c
212
shared/via_dma.c
|
@ -17,6 +17,14 @@
|
||||||
#include "via_drv.h"
|
#include "via_drv.h"
|
||||||
|
|
||||||
#define VIA_2D_CMD 0xF0000000
|
#define VIA_2D_CMD 0xF0000000
|
||||||
|
#define via_flush_write_combine() DRM_MEMORYBARRIER()
|
||||||
|
|
||||||
|
#define VIA_OUT_RING_QW(w1,w2) \
|
||||||
|
*vb++ = (w1); \
|
||||||
|
*vb++ = (w2); \
|
||||||
|
dev_priv->dma_low += 8;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void via_cmdbuf_start(drm_via_private_t * dev_priv);
|
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_pause(drm_via_private_t * dev_priv);
|
||||||
|
@ -24,6 +32,7 @@ static void via_cmdbuf_reset(drm_via_private_t * dev_priv);
|
||||||
static void via_cmdbuf_rewind(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);
|
static int via_wait_idle(drm_via_private_t * dev_priv);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function needs to be extended whenever a new command set
|
* This function needs to be extended whenever a new command set
|
||||||
* is implemented. Currently it works only for the 2D engine
|
* is implemented. Currently it works only for the 2D engine
|
||||||
|
@ -82,12 +91,7 @@ via_cmdbuf_wait(drm_via_private_t * dev_priv, unsigned int size)
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
hw_addr_ptr = dev_priv->hw_addr_ptr;
|
hw_addr_ptr = dev_priv->hw_addr_ptr;
|
||||||
cur_addr = dev_priv->dma_low;
|
cur_addr = dev_priv->dma_low;
|
||||||
/* At high resolution (i.e. 1280x1024) and with high workload within
|
next_addr = cur_addr + size;
|
||||||
* 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? */
|
count = 1000000; /* How long is this? */
|
||||||
do {
|
do {
|
||||||
hw_addr = *hw_addr_ptr - agp_base;
|
hw_addr = *hw_addr_ptr - agp_base;
|
||||||
|
@ -376,20 +380,16 @@ int via_pci_cmdbuffer(DRM_IOCTL_ARGS)
|
||||||
dev_priv->dma_low +=8; \
|
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,
|
static inline uint32_t *via_align_buffer(drm_via_private_t * dev_priv,
|
||||||
uint32_t * vb, int qw_count)
|
uint32_t * vb, int qw_count)
|
||||||
{
|
{
|
||||||
for (; qw_count > 0; --qw_count) {
|
for (; qw_count > 0; --qw_count) {
|
||||||
*vb++ = (0xcc000000 | (dev_priv->dma_low & 0xffffff));
|
VIA_OUT_RING_QW(HC_DUMMY, HC_DUMMY);
|
||||||
*vb++ = (0xdd400000 | via_swap_count);
|
|
||||||
dev_priv->dma_low += 8;
|
|
||||||
}
|
}
|
||||||
via_swap_count = (via_swap_count + 1) & 0xffff;
|
|
||||||
return vb;
|
return vb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function is used internally by ring buffer mangement code.
|
* This function is used internally by ring buffer mangement code.
|
||||||
*
|
*
|
||||||
|
@ -400,6 +400,58 @@ static inline uint32_t *via_get_dma(drm_via_private_t * dev_priv)
|
||||||
return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low);
|
return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hooks a segment of data into the tail of the ring-buffer by
|
||||||
|
* modifying the pause address stored in the buffer itself. If
|
||||||
|
* the regulator has already paused, restart it.
|
||||||
|
*/
|
||||||
|
static int via_hook_segment(drm_via_private_t *dev_priv,
|
||||||
|
uint32_t pause_addr_hi, uint32_t pause_addr_lo,
|
||||||
|
int no_pci_fire)
|
||||||
|
{
|
||||||
|
int paused, count;
|
||||||
|
|
||||||
|
via_flush_write_combine();
|
||||||
|
while(! *(via_get_dma(dev_priv)-1));
|
||||||
|
*dev_priv->last_pause_ptr = pause_addr_lo;
|
||||||
|
via_flush_write_combine();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The below statement is inserted to really force the flush.
|
||||||
|
* Not sure it is needed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
while(! *dev_priv->last_pause_ptr);
|
||||||
|
dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1;
|
||||||
|
|
||||||
|
paused = 0;
|
||||||
|
count = 3;
|
||||||
|
|
||||||
|
while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--);
|
||||||
|
if ((count < 1) && (count >= 0)) {
|
||||||
|
uint32_t rgtr, ptr;
|
||||||
|
rgtr = *(dev_priv->hw_addr_ptr);
|
||||||
|
ptr = ((char *)dev_priv->last_pause_ptr - dev_priv->dma_ptr) +
|
||||||
|
dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4 - 0x100;
|
||||||
|
if (rgtr <= ptr) {
|
||||||
|
DRM_ERROR("Command regulator\npaused at count %d, address %x, "
|
||||||
|
"while current pause address is %x.\n"
|
||||||
|
"Please mail this message to "
|
||||||
|
"<unichrome-devel@lists.sourceforge.net>\n",
|
||||||
|
count, rgtr, ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (paused && !no_pci_fire) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
return paused;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int via_wait_idle(drm_via_private_t * dev_priv)
|
static int via_wait_idle(drm_via_private_t * dev_priv)
|
||||||
{
|
{
|
||||||
int count = 10000000;
|
int count = 10000000;
|
||||||
|
@ -409,29 +461,50 @@ static int via_wait_idle(drm_via_private_t * dev_priv)
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void via_dummy_bitblt(drm_via_private_t * dev_priv)
|
static uint32_t *via_align_cmd(drm_via_private_t * dev_priv, uint32_t cmd_type,
|
||||||
|
uint32_t addr, uint32_t *cmd_addr_hi,
|
||||||
|
uint32_t *cmd_addr_lo)
|
||||||
{
|
{
|
||||||
uint32_t *vb = via_get_dma(dev_priv);
|
uint32_t agp_base;
|
||||||
/* GEDST */
|
uint32_t cmd_addr, addr_lo, addr_hi;
|
||||||
SetReg2DAGP(0x0C, (0 | (0 << 16)));
|
uint32_t *vb;
|
||||||
/* GEWD */
|
uint32_t qw_pad_count;
|
||||||
SetReg2DAGP(0x10, 0 | (0 << 16));
|
|
||||||
/* BITBLT */
|
via_cmdbuf_wait(dev_priv, 2*CMDBUF_ALIGNMENT_SIZE);
|
||||||
SetReg2DAGP(0x0, 0x1 | 0x2000 | 0xAA000000);
|
|
||||||
|
vb = via_get_dma(dev_priv);
|
||||||
|
VIA_OUT_RING_QW( HC_HEADER2 | ((VIA_REG_TRANSET >> 2) << 12) |
|
||||||
|
(VIA_REG_TRANSPACE >> 2), HC_ParaType_PreCR << 16);
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
cmd_addr = (addr) ? addr :
|
||||||
|
agp_base + dev_priv->dma_low - 8 + (qw_pad_count << 3);
|
||||||
|
addr_lo = ((HC_SubA_HAGPBpL << 24) | cmd_type |
|
||||||
|
(cmd_addr & 0xffffff));
|
||||||
|
addr_hi = ((HC_SubA_HAGPBpH << 24) | (cmd_addr >> 24));
|
||||||
|
|
||||||
|
vb = via_align_buffer(dev_priv, vb, qw_pad_count - 1);
|
||||||
|
VIA_OUT_RING_QW(*cmd_addr_hi = addr_hi,
|
||||||
|
*cmd_addr_lo = addr_lo);
|
||||||
|
return vb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void via_cmdbuf_start(drm_via_private_t * dev_priv)
|
static void via_cmdbuf_start(drm_via_private_t * dev_priv)
|
||||||
{
|
{
|
||||||
uint32_t agp_base;
|
uint32_t pause_addr_lo, pause_addr_hi;
|
||||||
uint32_t pause_addr, pause_addr_lo, pause_addr_hi;
|
|
||||||
uint32_t start_addr, start_addr_lo;
|
uint32_t start_addr, start_addr_lo;
|
||||||
uint32_t end_addr, end_addr_lo;
|
uint32_t end_addr, end_addr_lo;
|
||||||
uint32_t qw_pad_count;
|
|
||||||
uint32_t command;
|
uint32_t command;
|
||||||
uint32_t *vb;
|
uint32_t agp_base;
|
||||||
|
|
||||||
|
|
||||||
dev_priv->dma_low = 0;
|
dev_priv->dma_low = 0;
|
||||||
vb = via_get_dma(dev_priv);
|
|
||||||
|
|
||||||
agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
|
agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
|
||||||
start_addr = agp_base;
|
start_addr = agp_base;
|
||||||
|
@ -442,25 +515,12 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
|
||||||
command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) |
|
command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) |
|
||||||
((end_addr & 0xff000000) >> 16));
|
((end_addr & 0xff000000) >> 16));
|
||||||
|
|
||||||
*vb++ = HC_HEADER2 | ((VIA_REG_TRANSET >> 2) << 12) |
|
dev_priv->last_pause_ptr =
|
||||||
(VIA_REG_TRANSPACE >> 2);
|
via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0,
|
||||||
*vb++ = (HC_ParaType_PreCR << 16);
|
&pause_addr_hi, & pause_addr_lo) - 1;
|
||||||
dev_priv->dma_low += 8;
|
|
||||||
|
|
||||||
qw_pad_count = (CMDBUF_ALIGNMENT_SIZE >> 3) -
|
via_flush_write_combine();
|
||||||
((dev_priv->dma_low & CMDBUF_ALIGNMENT_MASK) >> 3);
|
while(! *dev_priv->last_pause_ptr);
|
||||||
|
|
||||||
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_TRANSET, (HC_ParaType_PreCR << 16));
|
||||||
VIA_WRITE(VIA_REG_TRANSPACE, command);
|
VIA_WRITE(VIA_REG_TRANSPACE, command);
|
||||||
|
@ -472,6 +532,17 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
|
||||||
|
|
||||||
VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
|
VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
|
||||||
}
|
}
|
||||||
|
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_jump(drm_via_private_t * dev_priv)
|
static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
|
||||||
{
|
{
|
||||||
|
@ -565,62 +636,27 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
|
||||||
*vb++ = pause_addr_hi;
|
*vb++ = pause_addr_hi;
|
||||||
*vb++ = pause_addr_lo;
|
*vb++ = pause_addr_lo;
|
||||||
dev_priv->dma_low += 8;
|
dev_priv->dma_low += 8;
|
||||||
|
via_hook_segment( dev_priv, jump_addr_hi, jump_addr_lo, 0);
|
||||||
*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)
|
static void via_cmdbuf_rewind(drm_via_private_t * dev_priv)
|
||||||
{
|
{
|
||||||
via_cmdbuf_pause(dev_priv);
|
/* via_cmdbuf_jump(dev_priv); */
|
||||||
via_cmdbuf_jump(dev_priv);
|
via_cmdbuf_reset(dev_priv);
|
||||||
|
via_cmdbuf_start(dev_priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void via_cmdbuf_flush(drm_via_private_t * dev_priv, uint32_t cmd_type)
|
static void via_cmdbuf_flush(drm_via_private_t * dev_priv, uint32_t cmd_type)
|
||||||
{
|
{
|
||||||
uint32_t agp_base;
|
uint32_t pause_addr_lo, pause_addr_hi;
|
||||||
uint32_t pause_addr, pause_addr_lo, pause_addr_hi;
|
|
||||||
uint32_t *vb;
|
|
||||||
uint32_t qw_pad_count;
|
|
||||||
|
|
||||||
via_cmdbuf_wait(dev_priv, 0x200);
|
via_align_cmd(dev_priv, cmd_type, 0, &pause_addr_hi, &pause_addr_lo);
|
||||||
|
via_hook_segment( dev_priv, pause_addr_hi, pause_addr_lo, 0);
|
||||||
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)
|
static void via_cmdbuf_pause(drm_via_private_t * dev_priv)
|
||||||
{
|
{
|
||||||
via_cmdbuf_flush(dev_priv, HC_HAGPBpID_PAUSE);
|
via_cmdbuf_flush(dev_priv, HC_HAGPBpID_PAUSE);
|
||||||
|
|
|
@ -42,7 +42,7 @@ typedef struct drm_via_private {
|
||||||
unsigned int dma_low;
|
unsigned int dma_low;
|
||||||
unsigned int dma_high;
|
unsigned int dma_high;
|
||||||
unsigned int dma_offset;
|
unsigned int dma_offset;
|
||||||
uint32_t *last_pause_ptr;
|
volatile uint32_t *last_pause_ptr;
|
||||||
volatile uint32_t *hw_addr_ptr;
|
volatile uint32_t *hw_addr_ptr;
|
||||||
drm_via_ring_buffer_t ring;
|
drm_via_ring_buffer_t ring;
|
||||||
char pci_buf[VIA_PREALLOCATED_PCI_SIZE];
|
char pci_buf[VIA_PREALLOCATED_PCI_SIZE];
|
||||||
|
|
Loading…
Reference in New Issue