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; }