diff options
author | Frank C. Earl <svartalf@users.sourceforge.net> | 2002-05-01 00:25:30 +0000 |
---|---|---|
committer | Frank C. Earl <svartalf@users.sourceforge.net> | 2002-05-01 00:25:30 +0000 |
commit | 9f0e6cad0e0aebd6bae151ad946bf3a8ba4a4d5b (patch) | |
tree | 33aaaffe16f2db64f9d25f62859ebb68659ab128 | |
parent | 43fb03f135cf6774fb3f85ed5a2201e0044a77e3 (diff) |
Most of the first cut of the DMA code. It's got most of the dispatchmach64-0-0-3-dma-branch
architecture in place (Lacks actual DMA submission (The easy part,
really...)) so it's not done yet, but I promised people that done or
not, I'd do a check-in of this...
-rw-r--r-- | linux-core/drm_dma.c | 2 | ||||
-rw-r--r-- | linux/drm_dma.h | 2 | ||||
-rw-r--r-- | linux/mach64.h | 5 | ||||
-rw-r--r-- | linux/mach64_dma.c | 1097 | ||||
-rw-r--r-- | linux/mach64_drm.h | 3 | ||||
-rw-r--r-- | linux/mach64_drv.h | 39 | ||||
-rw-r--r-- | linux/mach64_state.c | 6 |
7 files changed, 797 insertions, 357 deletions
diff --git a/linux-core/drm_dma.c b/linux-core/drm_dma.c index dce376f6..cf9eeab6 100644 --- a/linux-core/drm_dma.c +++ b/linux-core/drm_dma.c @@ -18,7 +18,7 @@ * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL4 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR diff --git a/linux/drm_dma.h b/linux/drm_dma.h index dce376f6..cf9eeab6 100644 --- a/linux/drm_dma.h +++ b/linux/drm_dma.h @@ -18,7 +18,7 @@ * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL4 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR diff --git a/linux/mach64.h b/linux/mach64.h index 9f92f80e..7a29182c 100644 --- a/linux/mach64.h +++ b/linux/mach64.h @@ -37,7 +37,7 @@ /* General customization: */ #define __HAVE_AGP 1 -#define __MUST_HAVE_AGP 1 +#define __MUST_HAVE_AGP 0 #define __HAVE_MTRR 1 #define __HAVE_CTX_BITMAP 1 #define __HAVE_SG 1 @@ -46,6 +46,9 @@ /* DMA customization: */ #define __HAVE_DMA 1 +#define __HAVE_DMA_IRQ 1 +#define __HAVE_DMA_IRQ_BH 1 +#define __HAVE_SHARED_IRQ 1 /* Buffer customization: */ diff --git a/linux/mach64_dma.c b/linux/mach64_dma.c index b4a2fbe8..07435a8f 100644 --- a/linux/mach64_dma.c +++ b/linux/mach64_dma.c @@ -2,6 +2,7 @@ * Created: Sun Dec 03 19:20:26 2000 by gareth@valinux.com * * Copyright 2000 Gareth Hughes + * Copyright 2002 Frank C. Earl * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -24,419 +25,825 @@ * * Authors: * Gareth Hughes <gareth@valinux.com> + * Frank C. Earl <fearl@airmail.net> */ #include "mach64.h" #include "drmP.h" #include "mach64_drv.h" -#include <linux/interrupt.h> /* For task queue support */ +#include <linux/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> /* For task queue support */ #include <linux/delay.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/list.h> +#include <asm/processor.h> +#include <asm/io.h> + +int mach64_do_dma_cleanup( drm_device_t *dev ); +int mach64_do_engine_reset( drm_mach64_private_t *dev_priv ); +int mach64_handle_dma( drm_mach64_private_t *dev_priv ); +int mach64_do_dispatch_dma( drm_mach64_private_t *dev_priv ); +int mach64_do_complete_blit( drm_mach64_private_t *dev_priv ); +int mach64_do_wait_for_dma( drm_mach64_private_t *dev_priv ); +int mach64_do_release_used_buffers( drm_mach64_private_t *dev_priv ); +int mach64_init_freelist( drm_mach64_private_t *dev_priv ); +int mach64_dma_get_buffers( drm_device_t *dev, drm_dma_t *d ); + +static DECLARE_WAIT_QUEUE_HEAD(read_wait); /* ================================================================ - * Engine control + * Interrupt handler */ - -int mach64_do_wait_for_fifo( drm_mach64_private_t *dev_priv, int entries ) +void mach64_dma_service(int irq, void *device, struct pt_regs *regs) { - int slots = 0, i; + drm_device_t *dev = (drm_device_t *) device; + drm_mach64_private_t *dev_priv = (drm_mach64_private_t *)dev->dev_private; + + unsigned int flags; + + /* Check to see if we've been interrupted for VBLANK or the BLIT completion + and ack the interrupt accordingly... Set flags for the handler to + know that it needs to process accordingly... */ + flags = MACH64_READ(MACH64_CRTC_INT_CNTL); + if (flags & 0x00000004) + { + /* VBLANK -- GUI-master dispatch and polling... */ + MACH64_WRITE(MACH64_CRTC_INT_CNTL, flags | 0x000000004); + atomic_inc(&dev_priv->do_gui); + } + if (flags & 0x02000000) + { + /* Completion of BLIT op */ + MACH64_WRITE(MACH64_CRTC_INT_CNTL, flags | 0x02000000); + atomic_inc(&dev_priv->do_blit); + } + + /* Check for an error condition in the engine... */ + if (MACH64_READ(MACH64_FIFO_STAT) & 0x80000000) + { + /* This would be a failure to maintain FIFO discipline + per the SDK sources. Need to reset... */ + mach64_do_engine_reset(dev_priv); + } + if (MACH64_READ(MACH64_BUS_CNTL) & 0x00200000) + { + /* This would be a host data error, per information from + Vernon Chiang @ ATI (Thanks, Vernon!). Need to reset... */ + mach64_do_engine_reset(dev_priv); + } + + /* Ok, now that we've gotten that out of the way, schedule the bottom half accordingly... */ + queue_task(&dev->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + return; +} - for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { - slots = (MACH64_READ( MACH64_FIFO_STAT ) & - MACH64_FIFO_SLOT_MASK); - if ( slots <= (0x8000 >> entries) ) return 0; - udelay( 1 ); - } - DRM_INFO( "failed! slots=%d entries=%d\n", slots, entries ); - return -EBUSY; +/* Handle the DMA dispatch/completion */ +void DRM(dma_immediate_bh)(void *device) +{ + drm_device_t *dev = (drm_device_t *) device; + drm_mach64_private_t *dev_priv = (drm_mach64_private_t *)dev->dev_private; + + /* Handle the completion of a blit pass... */ + if (atomic_read(&dev_priv->do_blit) > 0) + { + atomic_set(&dev_priv->do_blit, 0); + mach64_do_complete_blit(dev_priv); + } + + /* Check to see if we've been told to handle gui-mastering... */ + if (atomic_read(&dev_priv->do_gui) > 0) + { + atomic_set(&dev_priv->do_gui, 0); + mach64_handle_dma(dev_priv); + } + + wake_up_interruptible(&read_wait); + return; } -int mach64_do_wait_for_idle( drm_mach64_private_t *dev_priv ) -{ - int i, ret; - ret = mach64_do_wait_for_fifo( dev_priv, 16 ); - if ( ret < 0 ) return ret; +/* ================================================================ + * Engine control + */ - for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { - if ( !(MACH64_READ( MACH64_GUI_STAT ) & MACH64_GUI_ACTIVE) ) { - return 0; - } - udelay( 1 ); - } +int mach64_do_wait_for_fifo( drm_mach64_private_t *dev_priv, int entries ) +{ + int slots = 0, i; + + for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) + { + slots = (MACH64_READ( MACH64_FIFO_STAT ) & + MACH64_FIFO_SLOT_MASK); + if ( slots <= (0x8000 >> entries) ) return 0; + udelay( 1 ); + } + + DRM_INFO( "do_wait_for_fifo failed! slots=%d entries=%d\n", slots, entries ); + return -EBUSY; +} - DRM_INFO( "failed! GUI_STAT=0x%08x\n", - MACH64_READ( MACH64_GUI_STAT ) ); - return -EBUSY; +int mach64_do_wait_for_idle( drm_mach64_private_t *dev_priv ) +{ + int i, ret; + + ret = mach64_do_wait_for_fifo( dev_priv, 16 ); + if ( ret < 0 ) return ret; + + for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) + { + if ( !(MACH64_READ( MACH64_GUI_STAT ) & MACH64_GUI_ACTIVE) ) + { + return 0; + } + udelay( 1 ); + } + + DRM_INFO( "do_wait_for_idle failed! GUI_STAT=0x%08x\n", MACH64_READ( MACH64_GUI_STAT ) ); + return -EBUSY; } -static void scratch_reg0_test(drm_mach64_private_t *dev_priv ) +/* Wait until all DMA requests have been processed... */ +int mach64_do_wait_for_dma( drm_mach64_private_t *dev_priv ) { - u32 scratch_reg0; - scratch_reg0=MACH64_READ( MACH64_SCRATCH_REG0 ); + int i, ret; - MACH64_WRITE( MACH64_SCRATCH_REG0, 0x55555555 ); - if ( MACH64_READ( MACH64_SCRATCH_REG0 ) == 0x55555555 ) { - MACH64_WRITE( MACH64_SCRATCH_REG0, 0xaaaaaaaa ); + /* Assume we timeout... */ + ret = -EBUSY; - if ( MACH64_READ( MACH64_SCRATCH_REG0 ) != 0xaaaaaaaa ) { - DRM_ERROR( "2nd scratch reg failed!\n" ); + for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) + { + if ( list_empty(&dev_priv->dma_queue) ) + { + ret = mach64_do_wait_for_idle( dev_priv ); + break; } - } else { - DRM_ERROR( "1st scratch reg failed!\n" ); + udelay( 1 ); } - MACH64_WRITE( MACH64_SCRATCH_REG0, scratch_reg0 ); + + if (ret != 0) + DRM_INFO( "do_wait_for_dma failed! GUI_STAT=0x%08x\n", MACH64_READ( MACH64_GUI_STAT ) ); + + return ret; } -static void dump_engine_info( drm_mach64_private_t *dev_priv ) +void dump_engine_info( drm_mach64_private_t *dev_priv ) { - DRM_INFO( "\n" ); - DRM_INFO( " AGP_BASE = 0x%08x\n", MACH64_READ( MACH64_AGP_BASE ) ); - DRM_INFO( " AGP_CNTL = 0x%08x\n", MACH64_READ( MACH64_AGP_CNTL ) ); - DRM_INFO( " ALPHA_TST_CNTL = 0x%08x\n", MACH64_READ( MACH64_ALPHA_TST_CNTL ) ); - DRM_INFO( "\n" ); - DRM_INFO( " BM_COMMAND = 0x%08x\n", MACH64_READ( MACH64_BM_COMMAND ) ); - DRM_INFO( "BM_FRAME_BUF_OFFSET = 0x%08x\n", MACH64_READ( MACH64_BM_FRAME_BUF_OFFSET ) ); - DRM_INFO( " BM_GUI_TABLE = 0x%08x\n", MACH64_READ( MACH64_BM_GUI_TABLE ) ); - DRM_INFO( " BM_STATUS = 0x%08x\n", MACH64_READ( MACH64_BM_STATUS ) ); - DRM_INFO( " BM_SYSTEM_MEM_ADDR = 0x%08x\n", MACH64_READ( MACH64_BM_SYSTEM_MEM_ADDR ) ); - DRM_INFO( " BM_SYSTEM_TABLE = 0x%08x\n", MACH64_READ( MACH64_BM_SYSTEM_TABLE ) ); - DRM_INFO( " BUS_CNTL = 0x%08x\n", MACH64_READ( MACH64_BUS_CNTL ) ); - DRM_INFO( "\n" ); - /* DRM_INFO( " CLOCK_CNTL = 0x%08x\n", MACH64_READ( MACH64_CLOCK_CNTL ) ); */ - DRM_INFO( " CLR_CMP_CLR = 0x%08x\n", MACH64_READ( MACH64_CLR_CMP_CLR ) ); - DRM_INFO( " CLR_CMP_CNTL = 0x%08x\n", MACH64_READ( MACH64_CLR_CMP_CNTL ) ); - /* DRM_INFO( " CLR_CMP_MSK = 0x%08x\n", MACH64_READ( MACH64_CLR_CMP_MSK ) ); */ - DRM_INFO( " CONFIG_CHIP_ID = 0x%08x\n", MACH64_READ( MACH64_CONFIG_CHIP_ID ) ); - DRM_INFO( " CONFIG_CNTL = 0x%08x\n", MACH64_READ( MACH64_CONFIG_CNTL ) ); - DRM_INFO( " CONFIG_STAT0 = 0x%08x\n", MACH64_READ( MACH64_CONFIG_STAT0 ) ); - DRM_INFO( " CONFIG_STAT1 = 0x%08x\n", MACH64_READ( MACH64_CONFIG_STAT1 ) ); - DRM_INFO( " CONFIG_STAT2 = 0x%08x\n", MACH64_READ( MACH64_CONFIG_STAT2 ) ); - DRM_INFO( " CRC_SIG = 0x%08x\n", MACH64_READ( MACH64_CRC_SIG ) ); - DRM_INFO( " CUSTOM_MACRO_CNTL = 0x%08x\n", MACH64_READ( MACH64_CUSTOM_MACRO_CNTL ) ); - DRM_INFO( "\n" ); - /* DRM_INFO( " DAC_CNTL = 0x%08x\n", MACH64_READ( MACH64_DAC_CNTL ) ); */ - /* DRM_INFO( " DAC_REGS = 0x%08x\n", MACH64_READ( MACH64_DAC_REGS ) ); */ - DRM_INFO( " DP_BKGD_CLR = 0x%08x\n", MACH64_READ( MACH64_DP_BKGD_CLR ) ); - DRM_INFO( " DP_FRGD_CLR = 0x%08x\n", MACH64_READ( MACH64_DP_FRGD_CLR ) ); - DRM_INFO( " DP_MIX = 0x%08x\n", MACH64_READ( MACH64_DP_MIX ) ); - DRM_INFO( " DP_PIX_WIDTH = 0x%08x\n", MACH64_READ( MACH64_DP_PIX_WIDTH ) ); - DRM_INFO( " DP_SRC = 0x%08x\n", MACH64_READ( MACH64_DP_SRC ) ); - DRM_INFO( " DP_WRITE_MASK = 0x%08x\n", MACH64_READ( MACH64_DP_WRITE_MASK ) ); - DRM_INFO( " DSP_CONFIG = 0x%08x\n", MACH64_READ( MACH64_DSP_CONFIG ) ); - DRM_INFO( " DSP_ON_OFF = 0x%08x\n", MACH64_READ( MACH64_DSP_ON_OFF ) ); - DRM_INFO( " DST_CNTL = 0x%08x\n", MACH64_READ( MACH64_DST_CNTL ) ); - DRM_INFO( " DST_OFF_PITCH = 0x%08x\n", MACH64_READ( MACH64_DST_OFF_PITCH ) ); - DRM_INFO( "\n" ); - /* DRM_INFO( " EXT_DAC_REGS = 0x%08x\n", MACH64_READ( MACH64_EXT_DAC_REGS ) ); */ - DRM_INFO( " EXT_MEM_CNTL = 0x%08x\n", MACH64_READ( MACH64_EXT_MEM_CNTL ) ); - DRM_INFO( "\n" ); - DRM_INFO( " FIFO_STAT = 0x%08x\n", MACH64_READ( MACH64_FIFO_STAT ) ); - DRM_INFO( "\n" ); - DRM_INFO( " GEN_TEST_CNTL = 0x%08x\n", MACH64_READ( MACH64_GEN_TEST_CNTL ) ); - /* DRM_INFO( " GP_IO = 0x%08x\n", MACH64_READ( MACH64_GP_IO ) ); */ - DRM_INFO( " GUI_CMDFIFO_DATA = 0x%08x\n", MACH64_READ( MACH64_GUI_CMDFIFO_DATA ) ); - DRM_INFO( " GUI_CMDFIFO_DEBUG = 0x%08x\n", MACH64_READ( MACH64_GUI_CMDFIFO_DEBUG ) ); - DRM_INFO( " GUI_CNTL = 0x%08x\n", MACH64_READ( MACH64_GUI_CNTL ) ); - DRM_INFO( " GUI_STAT = 0x%08x\n", MACH64_READ( MACH64_GUI_STAT ) ); - DRM_INFO( " GUI_TRAJ_CNTL = 0x%08x\n", MACH64_READ( MACH64_GUI_TRAJ_CNTL ) ); - DRM_INFO( "\n" ); - DRM_INFO( " HOST_CNTL = 0x%08x\n", MACH64_READ( MACH64_HOST_CNTL ) ); - DRM_INFO( " HW_DEBUG = 0x%08x\n", MACH64_READ( MACH64_HW_DEBUG ) ); - DRM_INFO( "\n" ); - DRM_INFO( " MEM_ADDR_CONFIG = 0x%08x\n", MACH64_READ( MACH64_MEM_ADDR_CONFIG ) ); - DRM_INFO( " MEM_BUF_CNTL = 0x%08x\n", MACH64_READ( MACH64_MEM_BUF_CNTL ) ); - DRM_INFO( "\n" ); - DRM_INFO( " SCALE_3D_CNTL = 0x%08x\n", MACH64_READ( MACH64_SCALE_3D_CNTL ) ); - DRM_INFO( " SCRATCH_REG0 = 0x%08x\n", MACH64_READ( MACH64_SCRATCH_REG0 ) ); - DRM_INFO( " SCRATCH_REG1 = 0x%08x\n", MACH64_READ( MACH64_SCRATCH_REG1 ) ); - DRM_INFO( " SETUP_CNTL = 0x%08x\n", MACH64_READ( MACH64_SETUP_CNTL ) ); - DRM_INFO( " SRC_CNTL = 0x%08x\n", MACH64_READ( MACH64_SRC_CNTL ) ); - DRM_INFO( "\n" ); - DRM_INFO( " TEX_CNTL = 0x%08x\n", MACH64_READ( MACH64_TEX_CNTL ) ); - DRM_INFO( " TEX_SIZE_PITCH = 0x%08x\n", MACH64_READ( MACH64_TEX_SIZE_PITCH ) ); - DRM_INFO( " TIMER_CONFIG = 0x%08x\n", MACH64_READ( MACH64_TIMER_CONFIG ) ); - DRM_INFO( "\n" ); - DRM_INFO( " Z_CNTL = 0x%08x\n", MACH64_READ( MACH64_Z_CNTL ) ); - DRM_INFO( " Z_OFF_PITCH = 0x%08x\n", MACH64_READ( MACH64_Z_OFF_PITCH ) ); - DRM_INFO( "\n" ); + DRM_INFO( "\n" ); + if ( !dev_priv->is_pci) + { + DRM_INFO( " AGP_BASE = 0x%08x\n", MACH64_READ( MACH64_AGP_BASE ) ); + DRM_INFO( " AGP_CNTL = 0x%08x\n", MACH64_READ( MACH64_AGP_CNTL ) ); + } + DRM_INFO( " ALPHA_TST_CNTL = 0x%08x\n", MACH64_READ( MACH64_ALPHA_TST_CNTL ) ); + DRM_INFO( "\n" ); + DRM_INFO( " BM_COMMAND = 0x%08x\n", MACH64_READ( MACH64_BM_COMMAND ) ); + DRM_INFO( "BM_FRAME_BUF_OFFSET = 0x%08x\n", MACH64_READ( MACH64_BM_FRAME_BUF_OFFSET ) ); + DRM_INFO( " BM_GUI_TABLE = 0x%08x\n", MACH64_READ( MACH64_BM_GUI_TABLE ) ); + DRM_INFO( " BM_STATUS = 0x%08x\n", MACH64_READ( MACH64_BM_STATUS ) ); + DRM_INFO( " BM_SYSTEM_MEM_ADDR = 0x%08x\n", MACH64_READ( MACH64_BM_SYSTEM_MEM_ADDR ) ); + DRM_INFO( " BM_SYSTEM_TABLE = 0x%08x\n", MACH64_READ( MACH64_BM_SYSTEM_TABLE ) ); + DRM_INFO( " BUS_CNTL = 0x%08x\n", MACH64_READ( MACH64_BUS_CNTL ) ); + DRM_INFO( "\n" ); + /* DRM_INFO( " CLOCK_CNTL = 0x%08x\n", MACH64_READ( MACH64_CLOCK_CNTL ) ); */ + DRM_INFO( " CLR_CMP_CLR = 0x%08x\n", MACH64_READ( MACH64_CLR_CMP_CLR ) ); + DRM_INFO( " CLR_CMP_CNTL = 0x%08x\n", MACH64_READ( MACH64_CLR_CMP_CNTL ) ); + /* DRM_INFO( " CLR_CMP_MSK = 0x%08x\n", MACH64_READ( MACH64_CLR_CMP_MSK ) ); */ + DRM_INFO( " CONFIG_CHIP_ID = 0x%08x\n", MACH64_READ( MACH64_CONFIG_CHIP_ID ) ); + DRM_INFO( " CONFIG_CNTL = 0x%08x\n", MACH64_READ( MACH64_CONFIG_CNTL ) ); + DRM_INFO( " CONFIG_STAT0 = 0x%08x\n", MACH64_READ( MACH64_CONFIG_STAT0 ) ); + DRM_INFO( " CONFIG_STAT1 = 0x%08x\n", MACH64_READ( MACH64_CONFIG_STAT1 ) ); + DRM_INFO( " CONFIG_STAT2 = 0x%08x\n", MACH64_READ( MACH64_CONFIG_STAT2 ) ); + DRM_INFO( " CRC_SIG = 0x%08x\n", MACH64_READ( MACH64_CRC_SIG ) ); + DRM_INFO( " CUSTOM_MACRO_CNTL = 0x%08x\n", MACH64_READ( MACH64_CUSTOM_MACRO_CNTL ) ); + DRM_INFO( "\n" ); + /* DRM_INFO( " DAC_CNTL = 0x%08x\n", MACH64_READ( MACH64_DAC_CNTL ) ); */ + /* DRM_INFO( " DAC_REGS = 0x%08x\n", MACH64_READ( MACH64_DAC_REGS ) ); */ + DRM_INFO( " DP_BKGD_CLR = 0x%08x\n", MACH64_READ( MACH64_DP_BKGD_CLR ) ); + DRM_INFO( " DP_FRGD_CLR = 0x%08x\n", MACH64_READ( MACH64_DP_FRGD_CLR ) ); + DRM_INFO( " DP_MIX = 0x%08x\n", MACH64_READ( MACH64_DP_MIX ) ); + DRM_INFO( " DP_PIX_WIDTH = 0x%08x\n", MACH64_READ( MACH64_DP_PIX_WIDTH ) ); + DRM_INFO( " DP_SRC = 0x%08x\n", MACH64_READ( MACH64_DP_SRC ) ); + DRM_INFO( " DP_WRITE_MASK = 0x%08x\n", MACH64_READ( MACH64_DP_WRITE_MASK ) ); + DRM_INFO( " DSP_CONFIG = 0x%08x\n", MACH64_READ( MACH64_DSP_CONFIG ) ); + DRM_INFO( " DSP_ON_OFF = 0x%08x\n", MACH64_READ( MACH64_DSP_ON_OFF ) ); + DRM_INFO( " DST_CNTL = 0x%08x\n", MACH64_READ( MACH64_DST_CNTL ) ); + DRM_INFO( " DST_OFF_PITCH = 0x%08x\n", MACH64_READ( MACH64_DST_OFF_PITCH ) ); + DRM_INFO( "\n" ); + /* DRM_INFO( " EXT_DAC_REGS = 0x%08x\n", MACH64_READ( MACH64_EXT_DAC_REGS ) ); */ + DRM_INFO( " EXT_MEM_CNTL = 0x%08x\n", MACH64_READ( MACH64_EXT_MEM_CNTL ) ); + DRM_INFO( "\n" ); + DRM_INFO( " FIFO_STAT = 0x%08x\n", MACH64_READ( MACH64_FIFO_STAT ) ); + DRM_INFO( "\n" ); + DRM_INFO( " GEN_TEST_CNTL = 0x%08x\n", MACH64_READ( MACH64_GEN_TEST_CNTL ) ); + /* DRM_INFO( " GP_IO = 0x%08x\n", MACH64_READ( MACH64_GP_IO ) ); */ + DRM_INFO( " GUI_CMDFIFO_DATA = 0x%08x\n", MACH64_READ( MACH64_GUI_CMDFIFO_DATA ) ); + DRM_INFO( " GUI_CMDFIFO_DEBUG = 0x%08x\n", MACH64_READ( MACH64_GUI_CMDFIFO_DEBUG ) ); + DRM_INFO( " GUI_CNTL = 0x%08x\n", MACH64_READ( MACH64_GUI_CNTL ) ); + DRM_INFO( " GUI_STAT = 0x%08x\n", MACH64_READ( MACH64_GUI_STAT ) ); + DRM_INFO( " GUI_TRAJ_CNTL = 0x%08x\n", MACH64_READ( MACH64_GUI_TRAJ_CNTL ) ); + DRM_INFO( "\n" ); + DRM_INFO( " HOST_CNTL = 0x%08x\n", MACH64_READ( MACH64_HOST_CNTL ) ); + DRM_INFO( " HW_DEBUG = 0x%08x\n", MACH64_READ( MACH64_HW_DEBUG ) ); + DRM_INFO( "\n" ); + DRM_INFO( " MEM_ADDR_CONFIG = 0x%08x\n", MACH64_READ( MACH64_MEM_ADDR_CONFIG ) ); + DRM_INFO( " MEM_BUF_CNTL = 0x%08x\n", MACH64_READ( MACH64_MEM_BUF_CNTL ) ); + DRM_INFO( "\n" ); + DRM_INFO( " SCALE_3D_CNTL = 0x%08x\n", MACH64_READ( MACH64_SCALE_3D_CNTL ) ); + DRM_INFO( " SCRATCH_REG0 = 0x%08x\n", MACH64_READ( MACH64_SCRATCH_REG0 ) ); + DRM_INFO( " SCRATCH_REG1 = 0x%08x\n", MACH64_READ( MACH64_SCRATCH_REG1 ) ); + DRM_INFO( " SETUP_CNTL = 0x%08x\n", MACH64_READ( MACH64_SETUP_CNTL ) ); + DRM_INFO( " SRC_CNTL = 0x%08x\n", MACH64_READ( MACH64_SRC_CNTL ) ); + DRM_INFO( "\n" ); + DRM_INFO( " TEX_CNTL = 0x%08x\n", MACH64_READ( MACH64_TEX_CNTL ) ); + DRM_INFO( " TEX_SIZE_PITCH = 0x%08x\n", MACH64_READ( MACH64_TEX_SIZE_PITCH ) ); + DRM_INFO( " TIMER_CONFIG = 0x%08x\n", MACH64_READ( MACH64_TIMER_CONFIG ) ); + DRM_INFO( "\n" ); + DRM_INFO( " Z_CNTL = 0x%08x\n", MACH64_READ( MACH64_Z_CNTL ) ); + DRM_INFO( " Z_OFF_PITCH = 0x%08x\n", MACH64_READ( MACH64_Z_OFF_PITCH ) ); + DRM_INFO( "\n" ); } static void bm_dma_test(drm_mach64_private_t *dev_priv) { - struct pci_pool *pool; - dma_addr_t table_handle, data_handle; - u32 table_addr, data_addr; - u32 *table, *data; - - void *cpu_addr_table, *cpu_addr_data; - int i; - - DRM_INFO( "Creating pool ... \n"); - pool = pci_pool_create( "mach64", NULL, 0x4000, - 0x4000, 0x4000, SLAB_ATOMIC ); - - if (!pool) { - DRM_INFO( "pci_pool_create failed!\n" ); - return; - } - - DRM_INFO( "Allocating table memory ...\n" ); - cpu_addr_table = pci_pool_alloc( pool, SLAB_ATOMIC, &table_handle ); - if (!cpu_addr_table || !table_handle) { - DRM_INFO( "table-memory allocation failed!\n" ); - return; - } else { - table = (u32 *) cpu_addr_table; - table_addr = (u32) table_handle; - memset( cpu_addr_table, 0x0, 0x4000 ); - } - - DRM_INFO( "Allocating data memory ...\n" ); - cpu_addr_data = pci_pool_alloc( pool, SLAB_ATOMIC, &data_handle ); - if (!cpu_addr_data || !data_handle) { - DRM_INFO( "data-memory allocation failed!\n" ); - return; - } else { - data = (u32 *) cpu_addr_data; - data_addr = (u32) data_handle; - } - - MACH64_WRITE( MACH64_SRC_CNTL, 0x00000000 ); - MACH64_WRITE( MACH64_PAT_REG0, 0x11111111 ); - - DRM_INFO( "(Before DMA Transfer) PAT_REG0 = 0x%08x\n", - MACH64_READ( MACH64_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; - - DRM_INFO( "Preparing table ...\n" ); - table[0] = MACH64_BM_ADDR + APERTURE_OFFSET; - table[1] = data_addr; - table[2] = 8 * sizeof( u32 ) | 0x80000000 | 0x40000000; - table[3] = 0; - - DRM_INFO( "table[0] = 0x%08x\n", table[0] ); - DRM_INFO( "table[1] = 0x%08x\n", table[1] ); - DRM_INFO( "table[2] = 0x%08x\n", table[2] ); - DRM_INFO( "table[3] = 0x%08x\n", table[3] ); - - for ( i = 0 ; i < 8 ; i++) { - DRM_INFO( " data[%d] = 0x%08x\n", i, data[i] ); - } - - mb(); - - DRM_INFO( "waiting for idle...\n" ); - mach64_do_wait_for_idle( dev_priv ); - DRM_INFO( "waiting for idle... done.\n" ); - - DRM_INFO( "BUS_CNTL = 0x%08x\n", MACH64_READ( MACH64_BUS_CNTL ) ); - DRM_INFO( "SRC_CNTL = 0x%08x\n", MACH64_READ( MACH64_SRC_CNTL ) ); - DRM_INFO( "\n" ); - DRM_INFO( "data = 0x%08x\n", data_addr ); - DRM_INFO( "table = 0x%08x\n", table_addr ); - - DRM_INFO( "starting DMA transfer...\n" ); - MACH64_WRITE( MACH64_BM_GUI_TABLE, - 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_INFO( "starting DMA transfer... done.\n" ); - MACH64_WRITE( MACH64_DST_HEIGHT_WIDTH, 0 ); - MACH64_WRITE( MACH64_SRC_CNTL, 0 ); - - DRM_INFO( "waiting for idle [locked_after_dma??]...\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 ..."); - mach64_do_engine_reset( dev_priv ); - } - - DRM_INFO( "(After DMA Transfer) PAT_REG0 = 0x%08x\n", - MACH64_READ( MACH64_PAT_REG0 ) ); - - DRM_INFO( "freeing memory.\n" ); - pci_pool_free( pool, cpu_addr_table, table_handle ); - pci_pool_free( pool, cpu_addr_data, data_handle ); - pci_pool_destroy( pool ); - DRM_INFO( "returning ...\n" ); + dma_addr_t data_handle; + u32 data_addr; + u32 *data; + + void *cpu_addr_data; + int i; + + + DRM_INFO( "Allocating data memory ...\n" ); + cpu_addr_data = pci_pool_alloc( dev_priv->pool, SLAB_ATOMIC, &data_handle ); + if (!cpu_addr_data || !data_handle) + { + DRM_INFO( "data-memory allocation failed!\n" ); + return; + } + else + { + data = (u32 *) cpu_addr_data; + data_addr = (u32) data_handle; + } + + MACH64_WRITE( MACH64_SRC_CNTL, 0x00000000 ); + MACH64_WRITE( MACH64_PAT_REG0, 0x11111111 ); + + DRM_INFO( "(Before DMA Transfer) PAT_REG0 = 0x%08x\n", MACH64_READ( MACH64_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; + + DRM_INFO( "Preparing table ...\n" ); + memset( dev_priv->cpu_addr_table, 0x0, 0x4000 ); + dev_priv->table[0] = MACH64_BM_ADDR + APERTURE_OFFSET; + dev_priv->table[1] = data_addr; + dev_priv->table[2] = 8 * sizeof( u32 ) | 0x80000000 | 0x40000000; + dev_priv->table[3] = 0; + + DRM_INFO( "table[0] = 0x%08x\n", dev_priv->table[0] ); + DRM_INFO( "table[1] = 0x%08x\n", dev_priv->table[1] ); + DRM_INFO( "table[2] = 0x%08x\n", dev_priv->table[2] ); + DRM_INFO( "table[3] = 0x%08x\n", dev_priv->table[3] ); + + for ( i = 0 ; i < 8 ; i++) + { + DRM_INFO( " data[%d] = 0x%08x\n", i, data[i] ); + } + + mb(); + + DRM_INFO( "waiting for idle...\n" ); + mach64_do_wait_for_idle( dev_priv ); + DRM_INFO( "waiting for idle... done.\n" ); + + DRM_INFO( "BUS_CNTL = 0x%08x\n", MACH64_READ( MACH64_BUS_CNTL ) ); + DRM_INFO( "SRC_CNTL = 0x%08x\n", MACH64_READ( MACH64_SRC_CNTL ) ); + DRM_INFO( "\n" ); + DRM_INFO( "data = 0x%08x\n", data_addr ); + DRM_INFO( "table = 0x%08x\n", dev_priv->table_addr ); + + DRM_INFO( "starting DMA transfer...\n" ); + MACH64_WRITE( MACH64_BM_GUI_TABLE, + 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_INFO( "starting DMA transfer... done.\n" ); + MACH64_WRITE( MACH64_DST_HEIGHT_WIDTH, 0 ); + MACH64_WRITE( MACH64_SRC_CNTL, 0 ); + + DRM_INFO( "waiting for idle [locked_after_dma??]...\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 ..."); + mach64_do_engine_reset( dev_priv ); + } + + DRM_INFO( "(After DMA Transfer) PAT_REG0 = 0x%08x\n", MACH64_READ( MACH64_PAT_REG0 ) ); + + DRM_INFO( "freeing memory.\n" ); + pci_pool_free( dev_priv->pool, cpu_addr_data, data_handle ); + DRM_INFO( "returning ...\n" ); } int mach64_do_engine_reset( drm_mach64_private_t *dev_priv ) { - u32 bus_cntl, gen_test_cntl; - - /* Kill off any outstanding DMA transfers. - */ - bus_cntl = MACH64_READ( MACH64_BUS_CNTL ); - MACH64_WRITE( MACH64_BUS_CNTL, - bus_cntl | MACH64_BUS_MASTER_DIS ); - - /* Reset the GUI engine (high to low transition). - */ - gen_test_cntl = MACH64_READ( MACH64_GEN_TEST_CNTL ); - MACH64_WRITE( MACH64_GEN_TEST_CNTL, - gen_test_cntl & ~MACH64_GUI_ENGINE_ENABLE ); - /* Enable the GUI engine - */ - gen_test_cntl = MACH64_READ( MACH64_GEN_TEST_CNTL ); - MACH64_WRITE( MACH64_GEN_TEST_CNTL, - gen_test_cntl | MACH64_GUI_ENGINE_ENABLE ); - - /* ensure engine is not locked up by clearing any FIFO or HOST errors - */ - bus_cntl = MACH64_READ( MACH64_BUS_CNTL ); - MACH64_WRITE( MACH64_BUS_CNTL, bus_cntl | 0x00a00000 ); - - return 0; + u32 tmp; + + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + /* Kill off any outstanding DMA transfers. + */ + tmp = MACH64_READ( MACH64_BUS_CNTL ); + MACH64_WRITE( MACH64_BUS_CNTL, tmp | MACH64_BUS_MASTER_DIS ); + + /* Reset the GUI engine (high to low transition). + */ + tmp = MACH64_READ( MACH64_GEN_TEST_CNTL ); + MACH64_WRITE( MACH64_GEN_TEST_CNTL, tmp & ~MACH64_GUI_ENGINE_ENABLE ); + + /* Enable the GUI engine + */ + tmp = MACH64_READ( MACH64_GEN_TEST_CNTL ); + MACH64_WRITE( MACH64_GEN_TEST_CNTL, tmp | MACH64_GUI_ENGINE_ENABLE ); + + /* ensure engine is not locked up by clearing any FIFO or HOST errors + */ + tmp = MACH64_READ( MACH64_BUS_CNTL ); + MACH64_WRITE( MACH64_BUS_CNTL, tmp | 0x00a00000 ); + + return 0; } static int mach64_do_dma_init( drm_device_t *dev, drm_mach64_init_t *init ) { - drm_mach64_private_t *dev_priv; - struct list_head *list; - u32 tmp; - - DRM_DEBUG( "%s\n", __FUNCTION__ ); - - dev_priv = DRM(alloc)( sizeof(drm_mach64_private_t), DRM_MEM_DRIVER ); - if ( dev_priv == NULL ) - return -ENOMEM; - dev->dev_private = (void *) dev_priv; - - memset( dev_priv, 0, sizeof(drm_mach64_private_t) ); - - dev_priv->fb_bpp = init->fb_bpp; - dev_priv->front_offset = init->front_offset; - dev_priv->front_pitch = init->front_pitch; - dev_priv->back_offset = init->back_offset; - dev_priv->back_pitch = init->back_pitch; - - dev_priv->depth_bpp = init->depth_bpp; - dev_priv->depth_offset = init->depth_offset; - dev_priv->depth_pitch = init->depth_pitch; - - dev_priv->front_offset_pitch = (((dev_priv->front_pitch/8) << 22) | - (dev_priv->front_offset >> 3)); - dev_priv->back_offset_pitch = (((dev_priv->back_pitch/8) << 22) | - (dev_priv->back_offset >> 3)); - dev_priv->depth_offset_pitch = (((dev_priv->depth_pitch/8) << 22) | - (dev_priv->depth_offset >> 3)); - - dev_priv->usec_timeout = 1000000; - - list_for_each(list, &dev->maplist->head) { - drm_map_list_t *r_list = (drm_map_list_t *)list; - if( r_list->map && - r_list->map->type == _DRM_SHM && + drm_mach64_private_t *dev_priv; + struct list_head *list; + u32 tmp; + + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + dev_priv = DRM(alloc)( sizeof(drm_mach64_private_t), DRM_MEM_DRIVER ); + if ( dev_priv == NULL ) + return -ENOMEM; + + dev->dev_private = (void *) dev_priv; + + memset( dev_priv, 0, sizeof(drm_mach64_private_t) ); + + dev_priv->is_pci = init->is_pci; + + dev_priv->fb_bpp = init->fb_bpp; + dev_priv->front_offset = init->front_offset; + dev_priv->front_pitch = init->front_pitch; + dev_priv->back_offset = init->back_offset; + dev_priv->back_pitch = init->back_pitch; + + dev_priv->depth_bpp = init->depth_bpp; + dev_priv->depth_offset = init->depth_offset; + dev_priv->depth_pitch = init->depth_pitch; + + dev_priv->front_offset_pitch = (((dev_priv->front_pitch/8) << 22) | + (dev_priv->front_offset >> 3)); + dev_priv->back_offset_pitch = (((dev_priv->back_pitch/8) << 22) | + (dev_priv->back_offset >> 3)); + dev_priv->depth_offset_pitch = (((dev_priv->depth_pitch/8) << 22) | + (dev_priv->depth_offset >> 3)); + + dev_priv->usec_timeout = 1000000; + + list_for_each(list, &dev->maplist->head) { + drm_map_list_t *r_list = (drm_map_list_t *)list; + if( r_list->map && + r_list->map->type == _DRM_SHM && r_list->map->flags & _DRM_CONTAINS_LOCK ) { - dev_priv->sarea = r_list->map; - break; - } - } - - dev_priv->sarea_priv = (drm_mach64_sarea_t *) - ((u8 *)dev_priv->sarea->handle + - init->sarea_priv_offset); + dev_priv->sarea = r_list->map; + break; + } + } + if(!dev_priv->sarea) { + dev->dev_private = (void *)dev_priv; + mach64_do_dma_cleanup(dev); + DRM_ERROR("can not find sarea!\n"); + return -EINVAL; + } + DRM_FIND_MAP( dev_priv->fb, init->fb_offset ); + if(!dev_priv->fb) { + dev->dev_private = (void *)dev_priv; + mach64_do_dma_cleanup(dev); + DRM_ERROR("can not find frame buffer map!\n"); + return -EINVAL; + } + DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset ); + if(!dev_priv->mmio) { + dev->dev_private = (void *)dev_priv; + mach64_do_dma_cleanup(dev); + DRM_ERROR("can not find mmio map!\n"); + return -EINVAL; + } + + dev_priv->sarea_priv = (drm_mach64_sarea_t *) + ((u8 *)dev_priv->sarea->handle + + init->sarea_priv_offset); + + if( !dev_priv->is_pci ) { + DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset ); + if( !dev_priv->buffers ) { + dev->dev_private = (void *)dev_priv; + mach64_do_dma_cleanup( dev ); + DRM_ERROR( "can not find dma buffer map!\n" ); + return -EINVAL; + } + DRM_IOREMAP( dev_priv->buffers ); + if( !dev_priv->buffers->handle ) { + dev->dev_private = (void *) dev_priv; + mach64_do_dma_cleanup( dev ); + DRM_ERROR( "can not ioremap virtual address for" + " dma buffer\n" ); + return -ENOMEM; + } + } + + DRM_FIND_MAP( dev_priv->fb, init->fb_offset ); + DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset ); + DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset ); + + /* Set up our global descriptor table for DMA operation */ + DRM_INFO( "Creating pool ... \n"); + dev_priv->pool = pci_pool_create( "mach64", NULL, 0x4000, 0x4000, 0x4000, SLAB_ATOMIC ); + if (dev_priv->pool != NULL) + { + DRM_INFO( "pci_pool_create failed!\n" ); + return -ENOMEM; + } + DRM_INFO( "Allocating desctriptor table memory ...\n" ); + dev_priv->cpu_addr_table = pci_pool_alloc( dev_priv->pool, SLAB_ATOMIC, &dev_priv->table_handle ); + if ((dev_priv->cpu_addr_table != NULL) || !dev_priv->table_handle) + { + DRM_INFO( "Descriptor table memory allocation failed!\n" ); + pci_pool_destroy( dev_priv->pool ); + return -ENOMEM; + } + else + { + dev_priv->table = (u32 *) dev_priv->cpu_addr_table; + dev_priv->table_addr = (u32) dev_priv->table_handle; + } + + /* Turn on bus-mastering support in the GPU... */ + tmp = MACH64_READ( MACH64_BUS_CNTL ); + tmp = ( tmp | MACH64_BUS_EXT_REG_EN ) & ~MACH64_BUS_MASTER_DIS; + MACH64_WRITE( MACH64_BUS_CNTL, tmp ); + + /* For now, forcibly change the FIFO size back to the stock value- something about + the changes made by the XAA driver mess up DMA support badly (Locking up the + X server's NOT good, if you ask me...). */ + tmp = MACH64_READ( MACH64_GUI_CNTL ); + MACH64_WRITE(MACH64_GUI_CNTL, ((tmp & ~MACH64_CMDFIFO_SIZE_MASK) | MACH64_CMDFIFO_SIZE_128)); + DRM_INFO( "GUI_STAT=0x%08x\n", MACH64_READ( MACH64_GUI_STAT ) ); + DRM_INFO( "GUI_CNTL=0x%08x\n", MACH64_READ( MACH64_GUI_CNTL ) ); + + /* Set up the freelist, empty (placeholder), pending, and DMA request queues... */ + INIT_LIST_HEAD(&dev_priv->free_list); + INIT_LIST_HEAD(&dev_priv->empty_list); + INIT_LIST_HEAD(&dev_priv->pending); + INIT_LIST_HEAD(&dev_priv->dma_queue); + mach64_init_freelist( dev_priv ); + + /* Set up for interrupt handling proper- clear state on the handler and tell + the GPU that we want interrupts for VBLANK, BLIT, and Host data errors... */ + atomic_set(&dev_priv->do_gui, 0); + atomic_set(&dev_priv->do_blit, 0); + atomic_set(&dev_priv->dma_timeout, -1); + + /* Run a quick and dirty test of the engine */ + bm_dma_test( dev_priv ); + + return 0; +} - DRM_FIND_MAP( dev_priv->fb, init->fb_offset ); - DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset ); - DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset ); - DRM_IOREMAP( dev_priv->buffers ); +/* + Manage the GUI-Mastering operations of the chip. Since the GUI-Master + operation is slightly less intelligent than the BLIT operation (no interrupt + for completion), we have to provide the completion detection, etc. in + a state engine. +*/ +int mach64_handle_dma( drm_mach64_private_t *dev_priv ) +{ + struct list_head *ptr; + int i; + int timeout; + + timeout = atomic_read(&dev_priv->dma_timeout); + + /* Check for engine idle... */ + if (!(MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE)) + { + /* Check to see if we had a DMA pass going... */ + if ( timeout > -1) + { + /* Ok, do the clean up for the previous pass... */ + mach64_do_release_used_buffers(dev_priv); + atomic_set(&dev_priv->dma_timeout, -1); + } + + /* Now, check for queued buffers... */ + if (!list_empty(&dev_priv->dma_queue)) + { + ptr = dev_priv->dma_queue.next; + for(i = 0; i < MACH64_DMA_SIZE && !list_empty(&dev_priv->dma_queue); i++) + { + /* FIXME -- We REALLY need to be doing this based off of not just + a DMA-able size that's tolerable, but also rounding up/down by + what was submitted to us- if the client's submitting 3 buffer + submits, we really want to push all three at the same time to + the DMA channel. */ + list_del(ptr); + list_add_tail(&dev_priv->pending, ptr); + } + atomic_set(&dev_priv->dma_timeout, 0); + } + + /* Check to see if we've got a DMA pass set up */ + if (atomic_read(&dev_priv->dma_timeout) == 0) + { + /* Make sure we're locked and fire off the prepped pass */ + mach64_do_dispatch_dma(dev_priv); + } + } + else + { + /* Check to see if we've got a GUI-Master going... */ + if ((timeout > -1) && (MACH64_READ( MACH64_BUS_CNTL ) & ~ MACH64_BUS_MASTER_DIS)) + { + /* Check for DMA timeout */ + if (timeout > MACH64_DMA_TIMEOUT) + { + /* Assume the engine's hung bigtime... */ + mach64_do_engine_reset(dev_priv); + mach64_do_release_used_buffers(dev_priv); + atomic_set(&dev_priv->dma_timeout, -1); + } + else + { + atomic_inc(&dev_priv->dma_timeout); + } + } + } + + return 0; +} - DRM_INFO( "init->fb = 0x%08x\n", init->fb_offset ); - DRM_INFO( "init->mmio_offset = 0x%08x\n", init->mmio_offset ); - DRM_INFO( "mmio->offset=0x%08lx mmio->handle=0x%08lx\n", - dev_priv->mmio->offset, (unsigned long) dev_priv->mmio->handle ); - DRM_INFO( "buffers->offset=0x%08lx buffers->handle=0x%08lx\n", - dev_priv->buffers->offset, (unsigned long) dev_priv->buffers->handle ); +/* + Perform the clean-up for the blit operation- turn off DMA + operation (not support) and unlock the DRM. +*/ +int mach64_do_complete_blit( drm_mach64_private_t *dev_priv ) +{ + /* Turn off DMA mode -- we don't have anything going because the chip + tells us that it completed in this case (Why didn't they do this for + GUI Master operation?!) */ + MACH64_WRITE( MACH64_BUS_CNTL, MACH64_READ( MACH64_BUS_CNTL ) | MACH64_BUS_MASTER_DIS ); + + return 0; +} - tmp = MACH64_READ( MACH64_BUS_CNTL ); - tmp = ( tmp | 0x08000000 ) & ~MACH64_BUS_MASTER_DIS; - MACH64_WRITE( MACH64_BUS_CNTL, tmp ); - tmp = MACH64_READ( MACH64_GUI_CNTL ); - MACH64_WRITE( MACH64_GUI_CNTL, ( ( tmp & ~MACH64_CMDFIFO_SIZE_MASK ) \ - | MACH64_CMDFIFO_SIZE_128 ) ); - DRM_INFO( "GUI_STAT=0x%08x\n", MACH64_READ( MACH64_GUI_STAT ) ); - DRM_INFO( "GUI_CNTL=0x%08x\n", MACH64_READ( MACH64_GUI_CNTL ) ); +/* + Take the pending list and build up a descriptor table for + GUI-Master use, then fire off the DMA engine with the list. + (The list includes a register reset buffer that the DRM + only controls) +*/ +int mach64_do_dispatch_dma( drm_mach64_private_t *dev_priv ) +{ + struct list_head *ptr; + drm_mach64_freelist_t entry; + + /* Iterate the pending list build a descriptor table accordingly... */ + list_for_each(ptr, &dev_priv->pending) + { + + } + + /* Now, dispatch the whole lot to the gui-master engine */ - bm_dma_test( dev_priv ); - return 0; + return 0; } -static int mach64_do_dma_cleanup( drm_device_t *dev ) + +/* + Release completed, releaseable buffers to the freelist, currently + ignore flags for buffers that aren't flagged for release (shouldn't + be any, but you never know what someone's going to do to us...). +*/ +int mach64_do_release_used_buffers( drm_mach64_private_t *dev_priv ) { - DRM_DEBUG( "%s\n", __FUNCTION__ ); - dump_engine_info( dev->dev_private ); + struct list_head *ptr; + struct list_head *tmp; - if ( dev->dev_private ) { - drm_mach64_private_t *dev_priv = dev->dev_private; - - DRM_IOREMAPFREE( dev_priv->buffers ); - - DRM(free)( dev_priv, sizeof(drm_mach64_private_t), - DRM_MEM_DRIVER ); - dev->dev_private = NULL; + /* Iterate the pending list and shove the whole lot into the freelist... */ + list_for_each_safe(ptr, tmp, &dev_priv->pending) + { + list_del(ptr); + list_add_tail(&dev_priv->free_list, ptr); } - return 0; + return 0; } -int mach64_dma_init( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) + +int mach64_do_dma_cleanup( drm_device_t *dev ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_mach64_init_t init; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + if ( dev->dev_private ) + { + drm_mach64_private_t *dev_priv = dev->dev_private; + + /* First things, first- kill GPU interrupt support */ + + /* Discard the allocations for the descriptor table... */ + if ((dev_priv->cpu_addr_table != NULL) && !dev_priv->table_handle) + { + pci_pool_free( dev_priv->pool, dev_priv->cpu_addr_table, dev_priv->table_handle ); + } + if (dev_priv->pool != NULL) + { + pci_pool_destroy( dev_priv->pool ); + } + + if (dev_priv->buffers) + { + DRM_IOREMAPFREE( dev_priv->buffers ); + } - if ( copy_from_user( &init, (drm_mach64_init_t *)arg, sizeof(init) ) ) - return -EFAULT; - - switch ( init.func ) { - case MACH64_INIT_DMA: - return mach64_do_dma_init( dev, &init ); - case MACH64_CLEANUP_DMA: - return mach64_do_dma_cleanup( dev ); - } - - return -EINVAL; + DRM(free)( dev_priv, sizeof(drm_mach64_private_t), DRM_MEM_DRIVER ); + dev->dev_private = NULL; + } + + return 0; +} + +int mach64_dma_init( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_mach64_init_t init; + + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + if ( copy_from_user( &init, (drm_mach64_init_t *)arg, sizeof(init) ) ) + return -EFAULT; + + switch ( init.func ) + { + case MACH64_INIT_DMA: + return mach64_do_dma_init( dev, &init ); + case MACH64_CLEANUP_DMA: + return mach64_do_dma_cleanup( dev ); + } + + return -EINVAL; } int mach64_dma_idle( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) + unsigned int cmd, unsigned long arg ) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; - drm_mach64_private_t *dev_priv = dev->dev_private; - DRM_DEBUG( "%s\n", __FUNCTION__ ); + drm_mach64_private_t *dev_priv = dev->dev_private; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) + { + DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); + return -EINVAL; + } + + return mach64_do_wait_for_idle( dev_priv ); +} - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || - dev->lock.pid != current->pid ) { - DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); - return -EINVAL; - } - - return mach64_do_wait_for_idle( dev_priv ); + +/* + This is pretty simple- either the requested number of buffers exist in the + freelist or not. Fetch as many as available +*/ +int mach64_dma_get_buffers( drm_device_t *dev, drm_dma_t *d ) +{ + return 0; } + +/* + Through some pretty thorough testing, it has been found that the + RagePRO engine will pretty much ignore any "commands" sent + via the gui-master pathway that aren't gui operations (the register + gets set, but the actions that are normally associated with the setting + of those said registers doesn't happen.). So, it's safe to send us + buffers of gui commands from userspace (altering the buffer in mid- + execution will at worst scribble all over the screen and pushing + bogus commands will have no apparent effect...) + + FCE (03-08-2002) +*/ +int mach64_dma_buffers( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_device_dma_t *dma = dev->dma; + struct list_head *ptr; + drm_mach64_freelist_t *entry; + drm_mach64_private_t *dev_priv = (drm_mach64_private_t *)dev->dev_private; + drm_dma_t d; + int ret = 0; + int i; + + LOCK_TEST_WITH_RETURN( dev ); + + if ( copy_from_user( &d, (drm_dma_t *)arg, sizeof(d) ) ) + { + return -EFAULT; + } + + /* Queue up buffers sent to us... + */ + if ( d.send_count > 0 ) + { + for (i = 0; i < d.send_count ; i++) + { + if (!list_empty(&dev_priv->empty_list)) + { + ptr = dev_priv->empty_list.next; + list_del(ptr); + entry = list_entry(ptr, drm_mach64_freelist_t, list); + entry->buf = dma->buflist[d.send_indices[i]]; + list_add_tail(&dev_priv->dma_queue, ptr); + } + else + { + return -EFAULT; + } + } + } + else + { + /* Send the caller as many as they ask for, so long as we + have them in hand to give... + */ + if ( d.request_count < 0 || d.request_count > dma->buf_count ) + { + DRM_ERROR( "Process %d trying to get %d buffers (of %d max)\n", + current->pid, d.request_count, dma->buf_count ); + ret = -EINVAL; + } + else + { + d.granted_count = 0; + + if ( d.request_count ) + { + ret = mach64_dma_get_buffers( dev, &d ); + } + + if ( copy_to_user( (drm_dma_t *)arg, &d, sizeof(d) ) ) + { + ret = -EFAULT; + } + } + } + + return ret; +} diff --git a/linux/mach64_drm.h b/linux/mach64_drm.h index 8011f5df..5f6c5f9d 100644 --- a/linux/mach64_drm.h +++ b/linux/mach64_drm.h @@ -2,6 +2,7 @@ * Created: Thu Nov 30 20:04:32 2000 by gareth@valinux.com * * Copyright 2000 Gareth Hughes + * Copyright 2002 Frank C. Earl * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -24,6 +25,7 @@ * * Authors: * Gareth Hughes <gareth@valinux.com> + * Frank C. Earl <fearl@airmail.net> */ #ifndef __MACH64_DRM_H__ @@ -148,6 +150,7 @@ typedef struct drm_mach64_init { } func; unsigned int sarea_priv_offset; + int is_pci; unsigned int fb_bpp; unsigned int front_offset, front_pitch; diff --git a/linux/mach64_drv.h b/linux/mach64_drv.h index a552fc40..39f4dc87 100644 --- a/linux/mach64_drv.h +++ b/linux/mach64_drv.h @@ -2,6 +2,7 @@ * Created: Fri Nov 24 22:07:58 2000 by gareth@valinux.com * * Copyright 2000 Gareth Hughes + * Copyright 2002 Frank C. Earl * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a @@ -24,13 +25,26 @@ * * Authors: * Gareth Hughes <gareth@valinux.com> + * Frank C. Earl <fearl@airmail.net> */ #ifndef __MACH64_DRV_H__ #define __MACH64_DRV_H__ -typedef struct drm_mach64_private { +#include <linux/list.h> + + +/* Doesn't need much- the interrupt handler will manage "aging", etc. */ +typedef struct drm_mach64_freelist +{ + struct list_head list; /* Linux LIST structure... */ + struct drm_buf *buf; /* DMA buffer */ +} drm_mach64_freelist_t; + +typedef struct drm_mach64_private +{ drm_mach64_sarea_t *sarea_priv; + int is_pci; unsigned int fb_bpp; unsigned int front_offset, front_pitch; @@ -43,7 +57,21 @@ typedef struct drm_mach64_private { u32 back_offset_pitch; u32 depth_offset_pitch; - int usec_timeout; + u32 usec_timeout; /* Number of microseconds to wait for a timeout on the idle functions */ + atomic_t dma_timeout; /* Number of interrupt dispatches since last DMA dispatch... */ + atomic_t do_gui; /* Flag for the bottom half to know what to do... */ + atomic_t do_blit; /* Flag for the bottom half to know what to do... */ + + struct pci_pool *pool; + dma_addr_t table_handle; + u32 table_addr; + u32 *table; + void *cpu_addr_table; + + struct list_head free_list; /* Free-list head */ + struct list_head empty_list; /* Free-list placeholder list */ + struct list_head pending; /* Pending submission placeholder */ + struct list_head dma_queue; /* Submission queue head */ drm_map_t *sarea; drm_map_t *fb; @@ -51,10 +79,6 @@ typedef struct drm_mach64_private { drm_map_t *buffers; } drm_mach64_private_t; -typedef struct drm_mach64_buf_priv { - int age; -} drm_mach64_buf_priv_t; - /* mach64_drv.c */ extern int mach64_version( struct inode *inode, struct file *filp, @@ -398,6 +422,9 @@ do { \ * DMA macros */ +#define MACH64_DMA_TIMEOUT 10 /* 10 vertical retraces should be enough */ +#define MACH64_DMA_SIZE 8 /* 1 MB should be enough to make things happy */ + #define DMA_FRAME_BUF_OFFSET 0 #define DMA_SYS_MEM_ADDR 1 #define DMA_COMMAND 2 diff --git a/linux/mach64_state.c b/linux/mach64_state.c index 15971974..62f16eaf 100644 --- a/linux/mach64_state.c +++ b/linux/mach64_state.c @@ -1,4 +1,4 @@ -/* mach64_dma.c -- DMA support for mach64 (Rage Pro) driver -*- linux-c -*- +/* mach64_state.c -- State support for mach64 (Rage Pro) driver -*- linux-c -*- * Created: Sun Dec 03 19:20:26 2000 by gareth@valinux.com * * Copyright 2000 Gareth Hughes @@ -168,7 +168,7 @@ static void mach64_dma_dispatch_clear( drm_device_t *dev, if ( flags & MACH64_DEPTH ) { /* Setup for depth buffer clear */ - DMAGETPTR( dev_priv, 12 ); + DMAGETPTR( dev_priv, 14 ); DMAOUTREG( MACH64_Z_CNTL, 0 ); DMAOUTREG( MACH64_SCALE_3D_CNTL, 0 ); @@ -228,7 +228,7 @@ static void mach64_dma_dispatch_swap( drm_device_t *dev ) break; } - DMAGETPTR( dev_priv, 10 ); + DMAGETPTR( dev_priv, 12 ); DMAOUTREG( MACH64_Z_CNTL, 0 ); DMAOUTREG( MACH64_SCALE_3D_CNTL, 0 ); |