Well. Now, I trust that the problem is in X initialization.

I've modified the driver that R.C. gently sent us. It didn't worked for me, 
because of the IRQ issues I posted yesterday. As the GUI DMA test doesn't 
need IRQs, I've taken out that initialization and modified the device_read 
function to make the GUI DMA test.

I'm attatching the code here, to compile just type:

gcc -O2 -D__KERNEL__ -DMODULE -DLINUX -I/usr/include/linux -I 
/usr/src/linux/include/ -c ati_mach64gui.c

You must also create the device file:
#mknod  atidma c 240 0

And here comes the results. I just rebooted my machine, logged in, and 
installed the driver:

# insmod ./ati_mach64gui.o
PCI: Found IRQ 11 for device 01:00.0
PCI: Sharing IRQ 11 with 00:02.0
PCI: Sharing IRQ 11 with 00:05.0
Found ATI card at 0xf5000000.
#

Now, WITHOUT STARTING X, test the GUI DMA transfer, for example, typing:
# dd if=/dev/atidma of=atiout.dat bs=512 count=1

It worked, the module dumped:
(Before DMA Transfer) PAT_REG0 = 0x11111111
(After DMA Transfer) PAT_REG0 = 0x22222222

Then, after a fresh reboot, I tried to make the same test, but under X. 
The results were:
 (Before DMA Transfer) PAT_REG0 = 0x11111111
do_wait_for_idle failed! GUI_STAT=0x01ff0001
(After DMA Transfer) PAT_REG0 = 0x11111111

Just the same behaviour we are suffering with the mach64 DRI driver. 
Furthermore, the graphic card hangs, only the cursor works, and I had to 
login from another computer and reboot the machine. I have tried to avoid 
this behaviour resetting the engine when the do_wait_for_idle fails, but no 
luck.

So, what next?

Have anybody any idea about the difference between XFree 3.x and XFree 4.x 
initialization?

Could the problem be some bad interlocking between X and the DRI module?

What do you think about this?

I'm going to put the dump_engine_info into this little module. I think that 
this module is a good way to test the DMAGUI Bus Mastering, comparing the 
register values out of X with the ones obtained under X.


Best regards.

--
M. Teira





#include <config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/pci_ids.h>
#include <linux/compatmac.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <asm/processor.h>
#include <asm-i386/io.h>

/*
1. Find the device. call pci_register_driver()

2. Enable devices: pci_enable_device()
   Call pci_set_master() to enable bus master.

A field, by default, is 640x240x2 (307200).  This corresponds
to exactly 75 pages when they are 4K sized (AFAIK the minimum page size).
The main restriction is that they must be 4K aligned.
*/
#define SUCCESS 0
#define MAJOR_NUM	240
#define DEVICE_NAME	"atidma"	
#define DEBUG		1

#define CAP_INT_CNTL    0x908
#define CAP_INT_STATUS  0x90C
#define RADEON_CAP0_VBI0_OFFSET           0x093C
#define RADEON_CAP0_VBI1_OFFSET           0x0940
#define RADEON_CAP0_VBI_V_WINDOW          0x0944
#define RADEON_CAP0_VBI_H_WINDOW          0x0948
#define RADEON_CAP0_CONFIG                0x0958

#define regw(a,b)       *(MMR+a)=b
#define regr(a)         *(MMR+a)
#define MEM_BASE        	0x02480000
#define BUS_CNTL        	0x28+(256)
#define CRTC_INT_CNTL   	0x06+(256)
#define BM_SYSTEM_TABLE 	0x6F
#define CAPTURE_BUF0_OFFSET	0x20
#define CAPTURE_BUF1_OFFSET	0x21
#define CAPTURE_DEBUG		0x19
#define SYSTEM_TO_FRAME_BUFFER  0x0
#define FRAME_BUFFER_TO_SYSTEM 	0x1
#define BM_ADDR			0x0648
#define SRC_CNTL		0x6D+(256)
#define PAT_REG0		0xA0+(256)
#define APERTURE_OFFSET         0x7ff800
#define BM_GUI_TABLE		0x6E
#define BUS_MASTER_DIS                    (1 << 6)
#define SRC_BM_ENABLE                     (1 << 8)
#define SRC_BM_SYNC                       (1 << 9)
#define SRC_BM_OP_FRAME_TO_SYSTEM         (0 << 10)
#define SRC_BM_OP_SYSTEM_TO_FRAME         (1 << 10)
#define SRC_BM_OP_REG_TO_SYSTEM           (2 << 10)
#define SRC_BM_OP_SYSTEM_TO_REG           (3 << 10)
#define DST_HEIGHT_WIDTH	0x46+(256)
#define FIFO_STAT		0xC4+(256)
#define FIFO_SLOT_MASK   0x0000ffff
#define GUI_STAT         0xCE + (256)
#define GUI_ACTIVE      (1 << 0)
#define GUI_ENGINE_ENABLE  (1 << 8)
#define GEN_TEST_CNTL		0x34+(256)

#define LAST_DESCRIPTOR 	1 << 31


#define NUM_BUFS		5

/* Should be multiple of 2. */
#define CHAR_BUF_SIZE		128

/* Should be a multiple of 4 */
#define H_SIZE			1560

#define FIELD_SIZE		307200
/*#define BUF_SIZE		H_SIZE*2*/


static unsigned int volatile * MMR = NULL, *BUFF0, *BUFF1, IRQ;
static unsigned const char volatile * ATIFB = NULL;
static unsigned int saved_bus_cntl, saved_crtc_cntl;

static volatile unsigned int * full_page = NULL;

static volatile int Device_Open = 0;

int ati_module_init();
void ati_module_remove();
void ati_bh(unsigned long);

static int ati_probe_pci(struct pci_dev *, const struct pci_device_id *);
static void ati_remove_pci(struct pci_dev *);


static int do_wait_for_fifo( int entries )
{
	int slots=0,i;
	for ( i = 0 ; i < 1000000 ; i++ ) {
		slots = regr( FIFO_STAT ) & FIFO_SLOT_MASK;
		if ( slots <= (0x8000 >> entries ) ) return 0;
		udelay( 1 );
	}
	printk( "do_wait_for_fifo failed. Slots=%d Entries=%d\n",
		slots, entries );
	return -EBUSY;
}

static int do_wait_for_idle( )
{
        int i, ret;

        ret = do_wait_for_fifo( 16 );
        if ( ret < 0 ) return ret;

        for ( i = 0 ; i < 1000000 ; i++ ) {
                if ( ! (regr( GUI_STAT ) & GUI_ACTIVE) ) {
                        return 0;
                }
                udelay( 1 );
        }

        printk( "do_wait_for_idle failed! GUI_STAT=0x%08x\n",
		regr( GUI_STAT ) );
	return -EBUSY;
}

static void do_engine_reset( void )
{
	unsigned int bus_cntl, gen_test_cntl;

	bus_cntl = regr( BUS_CNTL );
	regw( BUS_CNTL, bus_cntl | BUS_MASTER_DIS );

	gen_test_cntl = regr( GEN_TEST_CNTL );
	regw( GEN_TEST_CNTL, gen_test_cntl & ~GUI_ENGINE_ENABLE );

	gen_test_cntl = regr( GEN_TEST_CNTL );
	regw( GEN_TEST_CNTL, gen_test_cntl | GUI_ENGINE_ENABLE );
	
	bus_cntl = regr( BUS_CNTL );
	regw( BUS_CNTL, bus_cntl | 0x00a00000 );	
}

static void __devexit ati_remove_pci(struct pci_dev *pdev)
{
	int i;

	pci_release_regions(pdev);
	/* Cast to shut up the compiler. */
	iounmap((void *) ATIFB);
	iounmap((void *) MMR);
	devfs_unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
	pci_disable_device(pdev);
	
  	if (full_page != NULL)
  	  free_pages((unsigned long) full_page, 7);
	printk("Removed ATI card \n" );
}

static int device_open(struct inode *inode, 
                       struct file *file)
{
  unsigned int temp;
  int a;

  // This is not race proof.
  if (Device_Open)
    return -EBUSY;

  Device_Open++;
  // Set VBI Window size

  temp = regr (BUS_CNTL);
  saved_bus_cntl = temp;
  temp = (temp | 0x08000000) & ~BUS_MASTER_DIS; // enable mm regs and bus mastering.
  regw (BUS_CNTL, temp);

  temp = regr( CRTC_INT_CNTL);
  saved_crtc_cntl = temp;
  return SUCCESS;
}

static int device_release(struct inode *inode, 
                          struct file *file)
{
	/* Restore registers */
  regw (BUS_CNTL, saved_bus_cntl);

  regw (CRTC_INT_CNTL, saved_crtc_cntl);
  
  Device_Open --;

  return 0;
}

static ssize_t device_read(
	struct file *file,
	char *u_buffer,
	size_t length,
	loff_t *offset)
{
	struct pci_pool *pool;
	unsigned int table_addr, data_addr;
	unsigned int *table,*data;

	void *cpu_addr_table, *cpu_addr_data;
	int i;

	unsigned int bus_cntl, src_cntl;

	pool = pci_pool_create( "mach64", NULL, 0x4000, 0x4000, 0x4000,
				SLAB_ATOMIC );
	cpu_addr_table = pci_pool_alloc( pool, SLAB_ATOMIC, &table_addr );
	if ( !cpu_addr_table ) {
		printk( "table-memory alloc failed\n" );
		return -ENOMEM;
	}
	table = cpu_addr_table;
	memset( cpu_addr_table, 0x0, 0x4000 );

	cpu_addr_data = pci_pool_alloc( pool, SLAB_ATOMIC, &data_addr );
	if ( !cpu_addr_data ) {
		printk( "data-memory alloc failed\n" );
		return -ENOMEM;
	}
	data = cpu_addr_data;

	regw( SRC_CNTL, 0x00000000 );

	regw( PAT_REG0, 0x11111111 );

	printk( "(Before DMA Transfer) PAT_REG0 = 0x%08x\n", regr( PAT_REG0 ) );

	data[0] = 0x000000a0;
	data[1] = 0x22222222;
	data[2] = 0x000000a0;
	data[3] = 0x22222222;
	data[4] = 0x000000a0;
	data[5] = 0x22222222;
	data[6] = 0x0000006d;
	data[7] = 0x00000000;

	table[0] = BM_ADDR + APERTURE_OFFSET;
	table[1] = data_addr;
	table[2] = 8 * sizeof( unsigned int ) | 0x80000000 | 0x40000000;
	table[3] = 0;

	regw( BM_GUI_TABLE, table_addr );

	regw( SRC_CNTL, SRC_BM_ENABLE |
			SRC_BM_SYNC   |
			SRC_BM_OP_SYSTEM_TO_REG );

	regw( DST_HEIGHT_WIDTH, 0 );

	regw( SRC_CNTL, 0 );

	if (do_wait_for_idle()!=0) {
		do_engine_reset();
	}

	/* Look the value in PAT_REG0 */
	printk( "(After DMA Transfer) PAT_REG0 = 0x%08x\n", regr( PAT_REG0 ) );

	pci_pool_free( pool, cpu_addr_table, table_addr );
	pci_pool_free( pool, cpu_addr_data, data_addr );
	pci_pool_destroy( pool );
}

static struct file_operations Fops = {
release:device_release,
open:device_open,
read:device_read
};

static struct pci_device_id ati_pci_tbl[] __devinitdata = {
	{0x1002, 0x4c4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0},
	{0,}
};

MODULE_DEVICE_TABLE(pci, ati_pci_tbl);

static struct pci_driver ati_driver = {
name:"atidma",
id_table:ati_pci_tbl,
probe:ati_probe_pci,
remove:ati_remove_pci
};

static int ati_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent)
{
	int err, i;

	if ((err = pci_enable_device(pdev)))
	{
		printk("Cannot enable device!\n");
		return -EIO;
	}
	pci_set_master(pdev);
	printk("Found ATI card at 0x%.8lx.\n", pci_resource_start(pdev, 0));
	if (pci_request_regions(pdev, "atidma") != 0)
	{
		printk("Could not request IO regions!\n");
		return -EBUSY;
	}
	ATIFB = __ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev,0),
			0);
	MMR = __ioremap(pci_resource_start(pdev, 2), pci_resource_len(pdev,2),
			0);
	BUFF0 = MMR + 0x20;
	BUFF1 = MMR + 0x21;
	return 0;
}



int __init ati_module_init()
{
	int retval;
	retval = devfs_register_chrdev(MAJOR_NUM, DEVICE_NAME, &Fops);
	if (retval >= 0)
		return pci_module_init(&ati_driver);
	else
		return retval;
}

void __exit ati_module_remove()
{
	pci_unregister_driver(&ati_driver);
	return ;
}

module_init(ati_module_init);
module_exit(ati_module_remove);

Reply via email to