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

Reply via email to