On 2002.05.05 19:41 Frank C. Earl wrote:
> ...
>
> > I plan to build a test case for this, but I would like to hear
> preliminary
> > opinions about this, in case I'm missing something. Frank, have you
> tested
> > this before?
>
> Yes, pretty extensively, but I didn't have time to set up tests for
> spanning
> multiple pages- we ought to do that one last one before commiting to the
> path we're now looking at.
Ok. I've made a test to see if this is possible and it failed. It's best
that Leif and Frank made a quick review of the test I made (attached), to
see if is there any mistake I made, before we put a stone on this issue.
Basically I changed mach64_bm_dma_test to allocate a 2nd descriptor table
and 2 more data buffers. The first buffer attempts to override
MACH64_BM_GUI_TABLE to read the 2nd table (which points to a 3rd buffer
which fille the vertex registers with different values). The 2nd buffer is
the continuation of the 1st and has the regular cleanup.
Now I plan to reproduce the hang that we had when trying to draw a
multitextured triangle without the texture offset specified to see if the
engine can recover or not from the lock. Frank, on IRC I got the
impression that you were gonna try this. Did you?
Jos� Fonseca
static int mach64_bm_dma_test( drm_device_t *dev )
{
drm_mach64_private_t *dev_priv = dev->dev_private;
dma_addr_t data_handle, data2_handle, data3_handle, table2_handle;
void *cpu_addr_data, *cpu_addr_data2, *cpu_addr_data3, *cpu_addr_table2;
u32 data_addr, data2_addr, data3_addr, table2_addr;
u32 *table, *data, *table2, *data2, *data3;
u32 regs[3], expected[3];
int i;
DRM_DEBUG( "%s\n", __FUNCTION__ );
table = (u32 *) dev_priv->cpu_addr_table;
/* FIXME: get a dma buffer from the freelist here rather than using the pool */
DRM_DEBUG( "Allocating data memory ...\n" );
cpu_addr_data = pci_pool_alloc( dev_priv->pool, SLAB_ATOMIC, &data_handle );
cpu_addr_data2 = pci_pool_alloc( dev_priv->pool, SLAB_ATOMIC, &data2_handle );
cpu_addr_data3 = pci_pool_alloc( dev_priv->pool, SLAB_ATOMIC, &data3_handle );
cpu_addr_table2 = pci_pool_alloc( dev_priv->pool, SLAB_ATOMIC, &table2_handle
);
if (!cpu_addr_data || !data_handle || !cpu_addr_data2 || !data2_handle ||
!cpu_addr_data3 || !data3_handle || !cpu_addr_table2 || !table2_handle) {
DRM_INFO( "data-memory allocation failed!\n" );
return -ENOMEM;
} else {
data = (u32 *) cpu_addr_data;
data_addr = (u32) data_handle;
data2 = (u32 *) cpu_addr_data2;
data2_addr = (u32) data2_handle;
data3 = (u32 *) cpu_addr_data3;
data3_addr = (u32) data3_handle;
table2 = (u32 *) cpu_addr_table2;
table2_addr = (u32) table2_handle;
}
MACH64_WRITE( MACH64_SRC_CNTL, 0x00000000 );
MACH64_WRITE( MACH64_VERTEX_1_S, 0x00000000 );
MACH64_WRITE( MACH64_VERTEX_1_T, 0x00000000 );
MACH64_WRITE( MACH64_VERTEX_1_W, 0x00000000 );
for (i=0; i < 3; i++) {
DRM_DEBUG( "(Before DMA Transfer) reg %d = 0x%08x\n", i,
MACH64_READ( (MACH64_VERTEX_1_S + i*4) ) );
}
/* 1_90 = VERTEX_1_S, setup 3 sequential reg writes */
/* use only s,t,w vertex registers so we don't have to mask any results */
data[0] = cpu_to_le32(0x00020190);
data[1] = expected[0] = 0x11111111;
data[2] = expected[1] = 0x22222222;
data[3] = expected[2] = 0x33333333;
data[4] = cpu_to_le32(MACH64_BM_GUI_TABLE_CMD);
data[5] = cpu_to_le32(table2_addr | MACH64_CIRCULAR_BUF_SIZE_16KB);
data[6] = cpu_to_le32(MACH64_DST_HEIGHT_WIDTH);
data[7] = cpu_to_le32(0);
data2[8] = cpu_to_le32(0x0000006d); /* SRC_CNTL */
data2[9] = 0x00000000;
data3[0] = cpu_to_le32(0x00020190);
data3[1] = 0x44444444;
data3[2] = 0x55555555;
data3[3] = 0x66666666;
data3[4] = cpu_to_le32(0x0000006d); /* SRC_CNTL */
data3[5] = 0x00000000;
DRM_DEBUG( "Preparing table ...\n" );
table[0] = cpu_to_le32(MACH64_BM_ADDR + APERTURE_OFFSET);
table[1] = cpu_to_le32(data_addr);
table[2] = cpu_to_le32(8 * sizeof( u32 ) | 0x40000000);
table[3] = 0;
table[4] = cpu_to_le32(MACH64_BM_ADDR + APERTURE_OFFSET);
table[5] = cpu_to_le32(data2_addr);
table[6] = cpu_to_le32(2 * sizeof( u32 ) | 0x80000000 | 0x40000000);
table[7] = 0;
table2[0] = cpu_to_le32(MACH64_BM_ADDR + APERTURE_OFFSET);
table2[1] = cpu_to_le32(data3_addr);
table2[2] = cpu_to_le32(6 * sizeof( u32 ) | 0x80000000 | 0x40000000);
table2[3] = 0;
DRM_DEBUG( "table[0] = 0x%08x\n", table[0] );
DRM_DEBUG( "table[1] = 0x%08x\n", table[1] );
DRM_DEBUG( "table[2] = 0x%08x\n", table[2] );
DRM_DEBUG( "table[3] = 0x%08x\n", table[3] );
for ( i = 0 ; i < 6 ; i++) {
DRM_DEBUG( " data[%d] = 0x%08x\n", i, data[i] );
}
mach64_flush_write_combine();
DRM_DEBUG( "waiting for idle...\n" );
if ( ( i = mach64_do_wait_for_idle( dev_priv ) ) ) {
DRM_INFO( "mach64_do_wait_for_idle failed (result=%d)\n", i);
DRM_INFO( "resetting engine ...\n");
mach64_do_engine_reset( dev );
DRM_INFO( "freeing data buffer memory.\n" );
pci_pool_free( dev_priv->pool, cpu_addr_data, data_handle );
pci_pool_free( dev_priv->pool, cpu_addr_data2, data2_handle );
pci_pool_free( dev_priv->pool, cpu_addr_data3, data3_handle );
pci_pool_free( dev_priv->pool, cpu_addr_table2, table2_handle );
DRM_INFO( "returning ...\n" );
return i;
}
DRM_DEBUG( "waiting for idle...done\n" );
DRM_DEBUG( "BUS_CNTL = 0x%08x\n", MACH64_READ( MACH64_BUS_CNTL ) );
DRM_DEBUG( "SRC_CNTL = 0x%08x\n", MACH64_READ( MACH64_SRC_CNTL ) );
DRM_DEBUG( "\n" );
DRM_DEBUG( "data bus addr = 0x%08x\n", data_addr );
DRM_DEBUG( "table bus addr = 0x%08x\n", dev_priv->table_addr );
DRM_INFO( "starting DMA transfer...\n" );
MACH64_WRITE( MACH64_BM_GUI_TABLE_CMD,
dev_priv->table_addr |
MACH64_CIRCULAR_BUF_SIZE_16KB );
MACH64_WRITE( MACH64_SRC_CNTL,
MACH64_SRC_BM_ENABLE | MACH64_SRC_BM_SYNC |
MACH64_SRC_BM_OP_SYSTEM_TO_REG );
/* Kick off the transfer */
DRM_DEBUG( "starting DMA transfer... done.\n" );
MACH64_WRITE( MACH64_DST_HEIGHT_WIDTH, 0 );
DRM_INFO( "waiting for idle...\n" );
if ( ( i = mach64_do_wait_for_idle( dev_priv ) ) ) {
/* engine locked up, dump register state and reset */
DRM_INFO( "mach64_do_wait_for_idle failed (result=%d)\n", i);
mach64_dump_engine_info( dev_priv );
DRM_INFO( "resetting engine ...\n");
mach64_do_engine_reset( dev );
DRM_INFO( "freeing data buffer memory.\n" );
pci_pool_free( dev_priv->pool, cpu_addr_data, data_handle );
pci_pool_free( dev_priv->pool, cpu_addr_data2, data2_handle );
pci_pool_free( dev_priv->pool, cpu_addr_data3, data3_handle );
pci_pool_free( dev_priv->pool, cpu_addr_table2, table2_handle );
DRM_INFO( "returning ...\n" );
return i;
}
DRM_INFO( "waiting for idle...done\n" );
mach64_dump_engine_info( dev_priv );
/* Check register values to see if the GUI master operation succeeded */
for ( i = 0; i < 3; i++ ) {
regs[i] = MACH64_READ( (MACH64_VERTEX_1_S + i*4) );
DRM_INFO( "(After DMA Transfer) reg %d = 0x%08x\n", i, regs[i] );
DRM_DEBUG( "(After DMA Transfer) reg %d = 0x%08x\n", i, regs[i] );
if (regs[i] != expected[i])
return -1; /* GUI master operation failed */
}
DRM_DEBUG( "freeing data buffer memory.\n" );
pci_pool_free( dev_priv->pool, cpu_addr_data, data_handle );
pci_pool_free( dev_priv->pool, cpu_addr_data2, data2_handle );
pci_pool_free( dev_priv->pool, cpu_addr_data3, data3_handle );
pci_pool_free( dev_priv->pool, cpu_addr_table2, table2_handle );
DRM_DEBUG( "returning ...\n" );
return 0;
}