2006-01-02 17:18:39 +11:00
/* r128_cce.c -- ATI Rage 128 driver -*- linux-c -*-
2005-04-16 15:20:36 -07:00
* Created : Wed Apr 5 19 : 24 : 19 2000 by kevin @ precisioninsight . com
2006-01-02 17:18:39 +11:00
*/
/*
2005-04-16 15:20:36 -07:00
* Copyright 2000 Precision Insight , Inc . , Cedar Park , Texas .
* Copyright 2000 VA Linux Systems , Inc . , Sunnyvale , California .
* All Rights Reserved .
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation
* the rights to use , copy , modify , merge , publish , distribute , sublicense ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice ( including the next
* paragraph ) shall be included in all copies or substantial portions of the
* Software .
*
* 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
* PRECISION INSIGHT 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 OTHER
* DEALINGS IN THE SOFTWARE .
*
* Authors :
* Gareth Hughes < gareth @ valinux . com >
*/
# include "drmP.h"
# include "drm.h"
# include "r128_drm.h"
# include "r128_drv.h"
# define R128_FIFO_DEBUG 0
/* CCE microcode (from ATI) */
static u32 r128_cce_microcode [ ] = {
0 , 276838400 , 0 , 268449792 , 2 , 142 , 2 , 145 , 0 , 1076765731 , 0 ,
1617039951 , 0 , 774592877 , 0 , 1987540286 , 0 , 2307490946U , 0 ,
599558925 , 0 , 589505315 , 0 , 596487092 , 0 , 589505315 , 1 ,
11544576 , 1 , 206848 , 1 , 311296 , 1 , 198656 , 2 , 912273422 , 11 ,
262144 , 0 , 0 , 1 , 33559837 , 1 , 7438 , 1 , 14809 , 1 , 6615 , 12 , 28 ,
1 , 6614 , 12 , 28 , 2 , 23 , 11 , 18874368 , 0 , 16790922 , 1 , 409600 , 9 ,
30 , 1 , 147854772 , 16 , 420483072 , 3 , 8192 , 0 , 10240 , 1 , 198656 ,
1 , 15630 , 1 , 51200 , 10 , 34858 , 9 , 42 , 1 , 33559823 , 2 , 10276 , 1 ,
15717 , 1 , 15718 , 2 , 43 , 1 , 15936948 , 1 , 570480831 , 1 , 14715071 ,
12 , 322123831 , 1 , 33953125 , 12 , 55 , 1 , 33559908 , 1 , 15718 , 2 ,
46 , 4 , 2099258 , 1 , 526336 , 1 , 442623 , 4 , 4194365 , 1 , 509952 , 1 ,
459007 , 3 , 0 , 12 , 92 , 2 , 46 , 12 , 176 , 1 , 15734 , 1 , 206848 , 1 ,
18432 , 1 , 133120 , 1 , 100670734 , 1 , 149504 , 1 , 165888 , 1 ,
15975928 , 1 , 1048576 , 6 , 3145806 , 1 , 15715 , 16 , 2150645232U , 2 ,
268449859 , 2 , 10307 , 12 , 176 , 1 , 15734 , 1 , 15735 , 1 , 15630 , 1 ,
15631 , 1 , 5253120 , 6 , 3145810 , 16 , 2150645232U , 1 , 15864 , 2 , 82 ,
1 , 343310 , 1 , 1064207 , 2 , 3145813 , 1 , 15728 , 1 , 7817 , 1 , 15729 ,
3 , 15730 , 12 , 92 , 2 , 98 , 1 , 16168 , 1 , 16167 , 1 , 16002 , 1 , 16008 ,
1 , 15974 , 1 , 15975 , 1 , 15990 , 1 , 15976 , 1 , 15977 , 1 , 15980 , 0 ,
15981 , 1 , 10240 , 1 , 5253120 , 1 , 15720 , 1 , 198656 , 6 , 110 , 1 ,
180224 , 1 , 103824738 , 2 , 112 , 2 , 3145839 , 0 , 536885440 , 1 ,
114880 , 14 , 125 , 12 , 206975 , 1 , 33559995 , 12 , 198784 , 0 ,
33570236 , 1 , 15803 , 0 , 15804 , 3 , 294912 , 1 , 294912 , 3 , 442370 ,
1 , 11544576 , 0 , 811612160 , 1 , 12593152 , 1 , 11536384 , 1 ,
14024704 , 7 , 310382726 , 0 , 10240 , 1 , 14796 , 1 , 14797 , 1 , 14793 ,
1 , 14794 , 0 , 14795 , 1 , 268679168 , 1 , 9437184 , 1 , 268449792 , 1 ,
198656 , 1 , 9452827 , 1 , 1075854602 , 1 , 1075854603 , 1 , 557056 , 1 ,
114880 , 14 , 159 , 12 , 198784 , 1 , 1109409213 , 12 , 198783 , 1 ,
1107312059 , 12 , 198784 , 1 , 1109409212 , 2 , 162 , 1 , 1075854781 , 1 ,
1073757627 , 1 , 1075854780 , 1 , 540672 , 1 , 10485760 , 6 , 3145894 ,
16 , 274741248 , 9 , 168 , 3 , 4194304 , 3 , 4209949 , 0 , 0 , 0 , 256 , 14 ,
174 , 1 , 114857 , 1 , 33560007 , 12 , 176 , 0 , 10240 , 1 , 114858 , 1 ,
33560018 , 1 , 114857 , 3 , 33560007 , 1 , 16008 , 1 , 114874 , 1 ,
33560360 , 1 , 114875 , 1 , 33560154 , 0 , 15963 , 0 , 256 , 0 , 4096 , 1 ,
409611 , 9 , 188 , 0 , 10240 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
} ;
2007-07-11 16:09:54 +10:00
static int R128_READ_PLL ( struct drm_device * dev , int addr )
2005-04-16 15:20:36 -07:00
{
drm_r128_private_t * dev_priv = dev - > dev_private ;
R128_WRITE8 ( R128_CLOCK_CNTL_INDEX , addr & 0x1f ) ;
return R128_READ ( R128_CLOCK_CNTL_DATA ) ;
}
# if R128_FIFO_DEBUG
2005-09-25 14:28:13 +10:00
static void r128_status ( drm_r128_private_t * dev_priv )
2005-04-16 15:20:36 -07:00
{
2005-09-25 14:28:13 +10:00
printk ( " GUI_STAT = 0x%08x \n " ,
( unsigned int ) R128_READ ( R128_GUI_STAT ) ) ;
printk ( " PM4_STAT = 0x%08x \n " ,
( unsigned int ) R128_READ ( R128_PM4_STAT ) ) ;
printk ( " PM4_BUFFER_DL_WPTR = 0x%08x \n " ,
( unsigned int ) R128_READ ( R128_PM4_BUFFER_DL_WPTR ) ) ;
printk ( " PM4_BUFFER_DL_RPTR = 0x%08x \n " ,
( unsigned int ) R128_READ ( R128_PM4_BUFFER_DL_RPTR ) ) ;
printk ( " PM4_MICRO_CNTL = 0x%08x \n " ,
( unsigned int ) R128_READ ( R128_PM4_MICRO_CNTL ) ) ;
printk ( " PM4_BUFFER_CNTL = 0x%08x \n " ,
( unsigned int ) R128_READ ( R128_PM4_BUFFER_CNTL ) ) ;
2005-04-16 15:20:36 -07:00
}
# endif
/* ================================================================
* Engine , FIFO control
*/
2005-09-25 14:28:13 +10:00
static int r128_do_pixcache_flush ( drm_r128_private_t * dev_priv )
2005-04-16 15:20:36 -07:00
{
u32 tmp ;
int i ;
2005-09-25 14:28:13 +10:00
tmp = R128_READ ( R128_PC_NGUI_CTLSTAT ) | R128_PC_FLUSH_ALL ;
R128_WRITE ( R128_PC_NGUI_CTLSTAT , tmp ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
for ( i = 0 ; i < dev_priv - > usec_timeout ; i + + ) {
if ( ! ( R128_READ ( R128_PC_NGUI_CTLSTAT ) & R128_PC_BUSY ) ) {
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-09-25 14:28:13 +10:00
DRM_UDELAY ( 1 ) ;
2005-04-16 15:20:36 -07:00
}
# if R128_FIFO_DEBUG
2005-09-25 14:28:13 +10:00
DRM_ERROR ( " failed! \n " ) ;
2005-04-16 15:20:36 -07:00
# endif
return DRM_ERR ( EBUSY ) ;
}
2005-09-25 14:28:13 +10:00
static int r128_do_wait_for_fifo ( drm_r128_private_t * dev_priv , int entries )
2005-04-16 15:20:36 -07:00
{
int i ;
2005-09-25 14:28:13 +10:00
for ( i = 0 ; i < dev_priv - > usec_timeout ; i + + ) {
int slots = R128_READ ( R128_GUI_STAT ) & R128_GUI_FIFOCNT_MASK ;
if ( slots > = entries )
return 0 ;
DRM_UDELAY ( 1 ) ;
2005-04-16 15:20:36 -07:00
}
# if R128_FIFO_DEBUG
2005-09-25 14:28:13 +10:00
DRM_ERROR ( " failed! \n " ) ;
2005-04-16 15:20:36 -07:00
# endif
return DRM_ERR ( EBUSY ) ;
}
2005-09-25 14:28:13 +10:00
static int r128_do_wait_for_idle ( drm_r128_private_t * dev_priv )
2005-04-16 15:20:36 -07:00
{
int i , ret ;
2005-09-25 14:28:13 +10:00
ret = r128_do_wait_for_fifo ( dev_priv , 64 ) ;
if ( ret )
return ret ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
for ( i = 0 ; i < dev_priv - > usec_timeout ; i + + ) {
if ( ! ( R128_READ ( R128_GUI_STAT ) & R128_GUI_ACTIVE ) ) {
r128_do_pixcache_flush ( dev_priv ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-09-25 14:28:13 +10:00
DRM_UDELAY ( 1 ) ;
2005-04-16 15:20:36 -07:00
}
# if R128_FIFO_DEBUG
2005-09-25 14:28:13 +10:00
DRM_ERROR ( " failed! \n " ) ;
2005-04-16 15:20:36 -07:00
# endif
return DRM_ERR ( EBUSY ) ;
}
/* ================================================================
* CCE control , initialization
*/
/* Load the microcode for the CCE */
2005-09-25 14:28:13 +10:00
static void r128_cce_load_microcode ( drm_r128_private_t * dev_priv )
2005-04-16 15:20:36 -07:00
{
int i ;
2005-09-25 14:28:13 +10:00
DRM_DEBUG ( " \n " ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
r128_do_wait_for_idle ( dev_priv ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
R128_WRITE ( R128_PM4_MICROCODE_ADDR , 0 ) ;
for ( i = 0 ; i < 256 ; i + + ) {
R128_WRITE ( R128_PM4_MICROCODE_DATAH , r128_cce_microcode [ i * 2 ] ) ;
R128_WRITE ( R128_PM4_MICROCODE_DATAL ,
r128_cce_microcode [ i * 2 + 1 ] ) ;
2005-04-16 15:20:36 -07:00
}
}
/* Flush any pending commands to the CCE. This should only be used just
* prior to a wait for idle , as it informs the engine that the command
* stream is ending .
*/
2005-09-25 14:28:13 +10:00
static void r128_do_cce_flush ( drm_r128_private_t * dev_priv )
2005-04-16 15:20:36 -07:00
{
u32 tmp ;
2005-09-25 14:28:13 +10:00
tmp = R128_READ ( R128_PM4_BUFFER_DL_WPTR ) | R128_PM4_BUFFER_DL_DONE ;
R128_WRITE ( R128_PM4_BUFFER_DL_WPTR , tmp ) ;
2005-04-16 15:20:36 -07:00
}
/* Wait for the CCE to go idle.
*/
2005-09-25 14:28:13 +10:00
int r128_do_cce_idle ( drm_r128_private_t * dev_priv )
2005-04-16 15:20:36 -07:00
{
int i ;
2005-09-25 14:28:13 +10:00
for ( i = 0 ; i < dev_priv - > usec_timeout ; i + + ) {
if ( GET_RING_HEAD ( dev_priv ) = = dev_priv - > ring . tail ) {
int pm4stat = R128_READ ( R128_PM4_STAT ) ;
if ( ( ( pm4stat & R128_PM4_FIFOCNT_MASK ) > =
dev_priv - > cce_fifo_size ) & &
! ( pm4stat & ( R128_PM4_BUSY |
R128_PM4_GUI_ACTIVE ) ) ) {
return r128_do_pixcache_flush ( dev_priv ) ;
2005-04-16 15:20:36 -07:00
}
}
2005-09-25 14:28:13 +10:00
DRM_UDELAY ( 1 ) ;
2005-04-16 15:20:36 -07:00
}
# if R128_FIFO_DEBUG
2005-09-25 14:28:13 +10:00
DRM_ERROR ( " failed! \n " ) ;
r128_status ( dev_priv ) ;
2005-04-16 15:20:36 -07:00
# endif
return DRM_ERR ( EBUSY ) ;
}
/* Start the Concurrent Command Engine.
*/
2005-09-25 14:28:13 +10:00
static void r128_do_cce_start ( drm_r128_private_t * dev_priv )
2005-04-16 15:20:36 -07:00
{
2005-09-25 14:28:13 +10:00
r128_do_wait_for_idle ( dev_priv ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
R128_WRITE ( R128_PM4_BUFFER_CNTL ,
dev_priv - > cce_mode | dev_priv - > ring . size_l2qw
| R128_PM4_BUFFER_CNTL_NOUPDATE ) ;
R128_READ ( R128_PM4_BUFFER_ADDR ) ; /* as per the sample code */
R128_WRITE ( R128_PM4_MICRO_CNTL , R128_PM4_MICRO_FREERUN ) ;
2005-04-16 15:20:36 -07:00
dev_priv - > cce_running = 1 ;
}
/* Reset the Concurrent Command Engine. This will not flush any pending
* commands , so you must wait for the CCE command stream to complete
* before calling this routine .
*/
2005-09-25 14:28:13 +10:00
static void r128_do_cce_reset ( drm_r128_private_t * dev_priv )
2005-04-16 15:20:36 -07:00
{
2005-09-25 14:28:13 +10:00
R128_WRITE ( R128_PM4_BUFFER_DL_WPTR , 0 ) ;
R128_WRITE ( R128_PM4_BUFFER_DL_RPTR , 0 ) ;
2005-04-16 15:20:36 -07:00
dev_priv - > ring . tail = 0 ;
}
/* Stop the Concurrent Command Engine. This will not flush any pending
* commands , so you must flush the command stream and wait for the CCE
* to go idle before calling this routine .
*/
2005-09-25 14:28:13 +10:00
static void r128_do_cce_stop ( drm_r128_private_t * dev_priv )
2005-04-16 15:20:36 -07:00
{
2005-09-25 14:28:13 +10:00
R128_WRITE ( R128_PM4_MICRO_CNTL , 0 ) ;
R128_WRITE ( R128_PM4_BUFFER_CNTL ,
R128_PM4_NONPM4 | R128_PM4_BUFFER_CNTL_NOUPDATE ) ;
2005-04-16 15:20:36 -07:00
dev_priv - > cce_running = 0 ;
}
/* Reset the engine. This will stop the CCE if it is running.
*/
2007-07-11 16:09:54 +10:00
static int r128_do_engine_reset ( struct drm_device * dev )
2005-04-16 15:20:36 -07:00
{
drm_r128_private_t * dev_priv = dev - > dev_private ;
u32 clock_cntl_index , mclk_cntl , gen_reset_cntl ;
2005-09-25 14:28:13 +10:00
r128_do_pixcache_flush ( dev_priv ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
clock_cntl_index = R128_READ ( R128_CLOCK_CNTL_INDEX ) ;
mclk_cntl = R128_READ_PLL ( dev , R128_MCLK_CNTL ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
R128_WRITE_PLL ( R128_MCLK_CNTL ,
mclk_cntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CP ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
gen_reset_cntl = R128_READ ( R128_GEN_RESET_CNTL ) ;
2005-04-16 15:20:36 -07:00
/* Taken from the sample code - do not change */
2005-09-25 14:28:13 +10:00
R128_WRITE ( R128_GEN_RESET_CNTL , gen_reset_cntl | R128_SOFT_RESET_GUI ) ;
R128_READ ( R128_GEN_RESET_CNTL ) ;
R128_WRITE ( R128_GEN_RESET_CNTL , gen_reset_cntl & ~ R128_SOFT_RESET_GUI ) ;
R128_READ ( R128_GEN_RESET_CNTL ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
R128_WRITE_PLL ( R128_MCLK_CNTL , mclk_cntl ) ;
R128_WRITE ( R128_CLOCK_CNTL_INDEX , clock_cntl_index ) ;
R128_WRITE ( R128_GEN_RESET_CNTL , gen_reset_cntl ) ;
2005-04-16 15:20:36 -07:00
/* Reset the CCE ring */
2005-09-25 14:28:13 +10:00
r128_do_cce_reset ( dev_priv ) ;
2005-04-16 15:20:36 -07:00
/* The CCE is no longer running after an engine reset */
dev_priv - > cce_running = 0 ;
/* Reset any pending vertex, indirect buffers */
2005-09-25 14:28:13 +10:00
r128_freelist_reset ( dev ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2007-07-11 16:09:54 +10:00
static void r128_cce_init_ring_buffer ( struct drm_device * dev ,
2005-09-25 14:28:13 +10:00
drm_r128_private_t * dev_priv )
2005-04-16 15:20:36 -07:00
{
u32 ring_start ;
u32 tmp ;
2005-09-25 14:28:13 +10:00
DRM_DEBUG ( " \n " ) ;
2005-04-16 15:20:36 -07:00
/* The manual (p. 2) says this address is in "VM space". This
* means it ' s an offset from the start of AGP space .
*/
# if __OS_HAS_AGP
2005-09-25 14:28:13 +10:00
if ( ! dev_priv - > is_pci )
2005-04-16 15:20:36 -07:00
ring_start = dev_priv - > cce_ring - > offset - dev - > agp - > base ;
else
# endif
2005-09-25 14:28:13 +10:00
ring_start = dev_priv - > cce_ring - > offset -
( unsigned long ) dev - > sg - > virtual ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
R128_WRITE ( R128_PM4_BUFFER_OFFSET , ring_start | R128_AGP_OFFSET ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
R128_WRITE ( R128_PM4_BUFFER_DL_WPTR , 0 ) ;
R128_WRITE ( R128_PM4_BUFFER_DL_RPTR , 0 ) ;
2005-04-16 15:20:36 -07:00
/* Set watermark control */
2005-09-25 14:28:13 +10:00
R128_WRITE ( R128_PM4_BUFFER_WM_CNTL ,
( ( R128_WATERMARK_L / 4 ) < < R128_WMA_SHIFT )
| ( ( R128_WATERMARK_M / 4 ) < < R128_WMB_SHIFT )
| ( ( R128_WATERMARK_N / 4 ) < < R128_WMC_SHIFT )
| ( ( R128_WATERMARK_K / 64 ) < < R128_WB_WM_SHIFT ) ) ;
2005-04-16 15:20:36 -07:00
/* Force read. Why? Because it's in the examples... */
2005-09-25 14:28:13 +10:00
R128_READ ( R128_PM4_BUFFER_ADDR ) ;
2005-04-16 15:20:36 -07:00
/* Turn on bus mastering */
2005-09-25 14:28:13 +10:00
tmp = R128_READ ( R128_BUS_CNTL ) & ~ R128_BUS_MASTER_DIS ;
R128_WRITE ( R128_BUS_CNTL , tmp ) ;
2005-04-16 15:20:36 -07:00
}
2007-07-11 16:09:54 +10:00
static int r128_do_init_cce ( struct drm_device * dev , drm_r128_init_t * init )
2005-04-16 15:20:36 -07:00
{
drm_r128_private_t * dev_priv ;
2005-09-25 14:28:13 +10:00
DRM_DEBUG ( " \n " ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
dev_priv = drm_alloc ( sizeof ( drm_r128_private_t ) , DRM_MEM_DRIVER ) ;
if ( dev_priv = = NULL )
2005-04-16 15:20:36 -07:00
return DRM_ERR ( ENOMEM ) ;
2005-09-25 14:28:13 +10:00
memset ( dev_priv , 0 , sizeof ( drm_r128_private_t ) ) ;
2005-04-16 15:20:36 -07:00
dev_priv - > is_pci = init - > is_pci ;
2005-09-25 14:28:13 +10:00
if ( dev_priv - > is_pci & & ! dev - > sg ) {
DRM_ERROR ( " PCI GART memory not allocated! \n " ) ;
2005-04-16 15:20:36 -07:00
dev - > dev_private = ( void * ) dev_priv ;
2005-09-25 14:28:13 +10:00
r128_do_cleanup_cce ( dev ) ;
2005-04-16 15:20:36 -07:00
return DRM_ERR ( EINVAL ) ;
}
dev_priv - > usec_timeout = init - > usec_timeout ;
2005-09-25 14:28:13 +10:00
if ( dev_priv - > usec_timeout < 1 | |
dev_priv - > usec_timeout > R128_MAX_USEC_TIMEOUT ) {
DRM_DEBUG ( " TIMEOUT problem! \n " ) ;
2005-04-16 15:20:36 -07:00
dev - > dev_private = ( void * ) dev_priv ;
2005-09-25 14:28:13 +10:00
r128_do_cleanup_cce ( dev ) ;
2005-04-16 15:20:36 -07:00
return DRM_ERR ( EINVAL ) ;
}
dev_priv - > cce_mode = init - > cce_mode ;
/* GH: Simple idle check.
*/
2005-09-25 14:28:13 +10:00
atomic_set ( & dev_priv - > idle_count , 0 ) ;
2005-04-16 15:20:36 -07:00
/* We don't support anything other than bus-mastering ring mode,
* but the ring can be in either AGP or PCI space for the ring
* read pointer .
*/
2005-09-25 14:28:13 +10:00
if ( ( init - > cce_mode ! = R128_PM4_192BM ) & &
( init - > cce_mode ! = R128_PM4_128BM_64INDBM ) & &
( init - > cce_mode ! = R128_PM4_64BM_128INDBM ) & &
( init - > cce_mode ! = R128_PM4_64BM_64VCBM_64INDBM ) ) {
DRM_DEBUG ( " Bad cce_mode! \n " ) ;
2005-04-16 15:20:36 -07:00
dev - > dev_private = ( void * ) dev_priv ;
2005-09-25 14:28:13 +10:00
r128_do_cleanup_cce ( dev ) ;
2005-04-16 15:20:36 -07:00
return DRM_ERR ( EINVAL ) ;
}
2005-09-25 14:28:13 +10:00
switch ( init - > cce_mode ) {
2005-04-16 15:20:36 -07:00
case R128_PM4_NONPM4 :
dev_priv - > cce_fifo_size = 0 ;
break ;
case R128_PM4_192PIO :
case R128_PM4_192BM :
dev_priv - > cce_fifo_size = 192 ;
break ;
case R128_PM4_128PIO_64INDBM :
case R128_PM4_128BM_64INDBM :
dev_priv - > cce_fifo_size = 128 ;
break ;
case R128_PM4_64PIO_128INDBM :
case R128_PM4_64BM_128INDBM :
case R128_PM4_64PIO_64VCBM_64INDBM :
case R128_PM4_64BM_64VCBM_64INDBM :
case R128_PM4_64PIO_64VCPIO_64INDPIO :
dev_priv - > cce_fifo_size = 64 ;
break ;
}
2005-09-25 14:28:13 +10:00
switch ( init - > fb_bpp ) {
2005-04-16 15:20:36 -07:00
case 16 :
dev_priv - > color_fmt = R128_DATATYPE_RGB565 ;
break ;
case 32 :
default :
dev_priv - > color_fmt = R128_DATATYPE_ARGB8888 ;
break ;
}
2005-09-25 14:28:13 +10:00
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 ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
switch ( init - > depth_bpp ) {
2005-04-16 15:20:36 -07:00
case 16 :
dev_priv - > depth_fmt = R128_DATATYPE_RGB565 ;
break ;
case 24 :
case 32 :
default :
dev_priv - > depth_fmt = R128_DATATYPE_ARGB8888 ;
break ;
}
2005-09-25 14:28:13 +10:00
dev_priv - > depth_offset = init - > depth_offset ;
dev_priv - > depth_pitch = init - > depth_pitch ;
dev_priv - > span_offset = init - > span_offset ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
dev_priv - > front_pitch_offset_c = ( ( ( dev_priv - > front_pitch / 8 ) < < 21 ) |
2005-04-16 15:20:36 -07:00
( dev_priv - > front_offset > > 5 ) ) ;
2005-09-25 14:28:13 +10:00
dev_priv - > back_pitch_offset_c = ( ( ( dev_priv - > back_pitch / 8 ) < < 21 ) |
2005-04-16 15:20:36 -07:00
( dev_priv - > back_offset > > 5 ) ) ;
2005-09-25 14:28:13 +10:00
dev_priv - > depth_pitch_offset_c = ( ( ( dev_priv - > depth_pitch / 8 ) < < 21 ) |
2005-04-16 15:20:36 -07:00
( dev_priv - > depth_offset > > 5 ) |
R128_DST_TILE ) ;
2005-09-25 14:28:13 +10:00
dev_priv - > span_pitch_offset_c = ( ( ( dev_priv - > depth_pitch / 8 ) < < 21 ) |
2005-04-16 15:20:36 -07:00
( dev_priv - > span_offset > > 5 ) ) ;
2007-05-26 05:04:51 +10:00
dev_priv - > sarea = drm_getsarea ( dev ) ;
2005-09-25 14:28:13 +10:00
if ( ! dev_priv - > sarea ) {
2005-04-16 15:20:36 -07:00
DRM_ERROR ( " could not find sarea! \n " ) ;
dev - > dev_private = ( void * ) dev_priv ;
2005-09-25 14:28:13 +10:00
r128_do_cleanup_cce ( dev ) ;
2005-04-16 15:20:36 -07:00
return DRM_ERR ( EINVAL ) ;
}
dev_priv - > mmio = drm_core_findmap ( dev , init - > mmio_offset ) ;
2005-09-25 14:28:13 +10:00
if ( ! dev_priv - > mmio ) {
2005-04-16 15:20:36 -07:00
DRM_ERROR ( " could not find mmio region! \n " ) ;
dev - > dev_private = ( void * ) dev_priv ;
2005-09-25 14:28:13 +10:00
r128_do_cleanup_cce ( dev ) ;
2005-04-16 15:20:36 -07:00
return DRM_ERR ( EINVAL ) ;
}
dev_priv - > cce_ring = drm_core_findmap ( dev , init - > ring_offset ) ;
2005-09-25 14:28:13 +10:00
if ( ! dev_priv - > cce_ring ) {
2005-04-16 15:20:36 -07:00
DRM_ERROR ( " could not find cce ring region! \n " ) ;
dev - > dev_private = ( void * ) dev_priv ;
2005-09-25 14:28:13 +10:00
r128_do_cleanup_cce ( dev ) ;
2005-04-16 15:20:36 -07:00
return DRM_ERR ( EINVAL ) ;
}
dev_priv - > ring_rptr = drm_core_findmap ( dev , init - > ring_rptr_offset ) ;
2005-09-25 14:28:13 +10:00
if ( ! dev_priv - > ring_rptr ) {
2005-04-16 15:20:36 -07:00
DRM_ERROR ( " could not find ring read pointer! \n " ) ;
dev - > dev_private = ( void * ) dev_priv ;
2005-09-25 14:28:13 +10:00
r128_do_cleanup_cce ( dev ) ;
2005-04-16 15:20:36 -07:00
return DRM_ERR ( EINVAL ) ;
}
2005-08-05 22:11:22 +10:00
dev - > agp_buffer_token = init - > buffers_offset ;
2005-04-16 15:20:36 -07:00
dev - > agp_buffer_map = drm_core_findmap ( dev , init - > buffers_offset ) ;
2005-09-25 14:28:13 +10:00
if ( ! dev - > agp_buffer_map ) {
2005-04-16 15:20:36 -07:00
DRM_ERROR ( " could not find dma buffer region! \n " ) ;
dev - > dev_private = ( void * ) dev_priv ;
2005-09-25 14:28:13 +10:00
r128_do_cleanup_cce ( dev ) ;
2005-04-16 15:20:36 -07:00
return DRM_ERR ( EINVAL ) ;
}
2005-09-25 14:28:13 +10:00
if ( ! dev_priv - > is_pci ) {
dev_priv - > agp_textures =
drm_core_findmap ( dev , init - > agp_textures_offset ) ;
if ( ! dev_priv - > agp_textures ) {
2005-04-16 15:20:36 -07:00
DRM_ERROR ( " could not find agp texture region! \n " ) ;
dev - > dev_private = ( void * ) dev_priv ;
2005-09-25 14:28:13 +10:00
r128_do_cleanup_cce ( dev ) ;
2005-04-16 15:20:36 -07:00
return DRM_ERR ( EINVAL ) ;
}
}
dev_priv - > sarea_priv =
2005-09-25 14:28:13 +10:00
( drm_r128_sarea_t * ) ( ( u8 * ) dev_priv - > sarea - > handle +
init - > sarea_priv_offset ) ;
2005-04-16 15:20:36 -07:00
# if __OS_HAS_AGP
2005-09-25 14:28:13 +10:00
if ( ! dev_priv - > is_pci ) {
drm_core_ioremap ( dev_priv - > cce_ring , dev ) ;
drm_core_ioremap ( dev_priv - > ring_rptr , dev ) ;
drm_core_ioremap ( dev - > agp_buffer_map , dev ) ;
if ( ! dev_priv - > cce_ring - > handle | |
! dev_priv - > ring_rptr - > handle | |
! dev - > agp_buffer_map - > handle ) {
2005-04-16 15:20:36 -07:00
DRM_ERROR ( " Could not ioremap agp regions! \n " ) ;
dev - > dev_private = ( void * ) dev_priv ;
2005-09-25 14:28:13 +10:00
r128_do_cleanup_cce ( dev ) ;
2005-04-16 15:20:36 -07:00
return DRM_ERR ( ENOMEM ) ;
}
} else
# endif
{
2005-09-25 14:28:13 +10:00
dev_priv - > cce_ring - > handle = ( void * ) dev_priv - > cce_ring - > offset ;
2005-04-16 15:20:36 -07:00
dev_priv - > ring_rptr - > handle =
2005-09-25 14:28:13 +10:00
( void * ) dev_priv - > ring_rptr - > offset ;
dev - > agp_buffer_map - > handle =
( void * ) dev - > agp_buffer_map - > offset ;
2005-04-16 15:20:36 -07:00
}
# if __OS_HAS_AGP
2005-09-25 14:28:13 +10:00
if ( ! dev_priv - > is_pci )
2005-04-16 15:20:36 -07:00
dev_priv - > cce_buffers_offset = dev - > agp - > base ;
else
# endif
2005-08-05 22:11:22 +10:00
dev_priv - > cce_buffers_offset = ( unsigned long ) dev - > sg - > virtual ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
dev_priv - > ring . start = ( u32 * ) dev_priv - > cce_ring - > handle ;
dev_priv - > ring . end = ( ( u32 * ) dev_priv - > cce_ring - > handle
2005-04-16 15:20:36 -07:00
+ init - > ring_size / sizeof ( u32 ) ) ;
dev_priv - > ring . size = init - > ring_size ;
2005-09-25 14:28:13 +10:00
dev_priv - > ring . size_l2qw = drm_order ( init - > ring_size / 8 ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
dev_priv - > ring . tail_mask = ( dev_priv - > ring . size / sizeof ( u32 ) ) - 1 ;
2005-04-16 15:20:36 -07:00
dev_priv - > ring . high_mark = 128 ;
dev_priv - > sarea_priv - > last_frame = 0 ;
2005-09-25 14:28:13 +10:00
R128_WRITE ( R128_LAST_FRAME_REG , dev_priv - > sarea_priv - > last_frame ) ;
2005-04-16 15:20:36 -07:00
dev_priv - > sarea_priv - > last_dispatch = 0 ;
2005-09-25 14:28:13 +10:00
R128_WRITE ( R128_LAST_DISPATCH_REG , dev_priv - > sarea_priv - > last_dispatch ) ;
2005-04-16 15:20:36 -07:00
# if __OS_HAS_AGP
2005-09-25 14:28:13 +10:00
if ( dev_priv - > is_pci ) {
2005-04-16 15:20:36 -07:00
# endif
2005-09-11 20:28:11 +10:00
dev_priv - > gart_info . gart_table_location = DRM_ATI_GART_MAIN ;
2007-05-08 15:19:23 +10:00
dev_priv - > gart_info . table_size = R128_PCIGART_TABLE_SIZE ;
2006-01-02 17:18:39 +11:00
dev_priv - > gart_info . addr = NULL ;
dev_priv - > gart_info . bus_addr = 0 ;
2007-05-08 15:19:23 +10:00
dev_priv - > gart_info . gart_reg_if = DRM_ATI_GART_PCI ;
2005-09-11 20:28:11 +10:00
if ( ! drm_ati_pcigart_init ( dev , & dev_priv - > gart_info ) ) {
2005-09-25 14:28:13 +10:00
DRM_ERROR ( " failed to init PCI GART! \n " ) ;
2005-04-16 15:20:36 -07:00
dev - > dev_private = ( void * ) dev_priv ;
2005-09-25 14:28:13 +10:00
r128_do_cleanup_cce ( dev ) ;
2005-04-16 15:20:36 -07:00
return DRM_ERR ( ENOMEM ) ;
}
2005-09-11 20:28:11 +10:00
R128_WRITE ( R128_PCI_GART_PAGE , dev_priv - > gart_info . bus_addr ) ;
2005-04-16 15:20:36 -07:00
# if __OS_HAS_AGP
}
# endif
2005-09-25 14:28:13 +10:00
r128_cce_init_ring_buffer ( dev , dev_priv ) ;
r128_cce_load_microcode ( dev_priv ) ;
2005-04-16 15:20:36 -07:00
dev - > dev_private = ( void * ) dev_priv ;
2005-09-25 14:28:13 +10:00
r128_do_engine_reset ( dev ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2007-07-11 16:09:54 +10:00
int r128_do_cleanup_cce ( struct drm_device * dev )
2005-04-16 15:20:36 -07:00
{
/* Make sure interrupts are disabled here because the uninstall ioctl
* may not have been called from userspace and after dev_private
* is freed , it ' s too late .
*/
2005-09-25 14:28:13 +10:00
if ( dev - > irq_enabled )
drm_irq_uninstall ( dev ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
if ( dev - > dev_private ) {
2005-04-16 15:20:36 -07:00
drm_r128_private_t * dev_priv = dev - > dev_private ;
# if __OS_HAS_AGP
2005-09-25 14:28:13 +10:00
if ( ! dev_priv - > is_pci ) {
if ( dev_priv - > cce_ring ! = NULL )
drm_core_ioremapfree ( dev_priv - > cce_ring , dev ) ;
if ( dev_priv - > ring_rptr ! = NULL )
drm_core_ioremapfree ( dev_priv - > ring_rptr , dev ) ;
2006-01-02 17:18:39 +11:00
if ( dev - > agp_buffer_map ! = NULL ) {
2005-09-25 14:28:13 +10:00
drm_core_ioremapfree ( dev - > agp_buffer_map , dev ) ;
2006-01-02 17:18:39 +11:00
dev - > agp_buffer_map = NULL ;
}
2005-04-16 15:20:36 -07:00
} else
# endif
{
2005-09-25 14:28:13 +10:00
if ( dev_priv - > gart_info . bus_addr )
if ( ! drm_ati_pcigart_cleanup ( dev ,
2006-01-02 17:18:39 +11:00
& dev_priv - > gart_info ) )
2005-09-25 14:28:13 +10:00
DRM_ERROR
( " failed to cleanup PCI GART! \n " ) ;
2005-04-16 15:20:36 -07:00
}
2005-09-25 14:28:13 +10:00
drm_free ( dev - > dev_private , sizeof ( drm_r128_private_t ) ,
DRM_MEM_DRIVER ) ;
2005-04-16 15:20:36 -07:00
dev - > dev_private = NULL ;
}
return 0 ;
}
2005-09-25 14:28:13 +10:00
int r128_cce_init ( DRM_IOCTL_ARGS )
2005-04-16 15:20:36 -07:00
{
DRM_DEVICE ;
drm_r128_init_t init ;
2005-09-25 14:28:13 +10:00
DRM_DEBUG ( " \n " ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
LOCK_TEST_WITH_RETURN ( dev , filp ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
DRM_COPY_FROM_USER_IOCTL ( init , ( drm_r128_init_t __user * ) data ,
sizeof ( init ) ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
switch ( init . func ) {
2005-04-16 15:20:36 -07:00
case R128_INIT_CCE :
2005-09-25 14:28:13 +10:00
return r128_do_init_cce ( dev , & init ) ;
2005-04-16 15:20:36 -07:00
case R128_CLEANUP_CCE :
2005-09-25 14:28:13 +10:00
return r128_do_cleanup_cce ( dev ) ;
2005-04-16 15:20:36 -07:00
}
return DRM_ERR ( EINVAL ) ;
}
2005-09-25 14:28:13 +10:00
int r128_cce_start ( DRM_IOCTL_ARGS )
2005-04-16 15:20:36 -07:00
{
DRM_DEVICE ;
drm_r128_private_t * dev_priv = dev - > dev_private ;
2005-09-25 14:28:13 +10:00
DRM_DEBUG ( " \n " ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
LOCK_TEST_WITH_RETURN ( dev , filp ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
if ( dev_priv - > cce_running | | dev_priv - > cce_mode = = R128_PM4_NONPM4 ) {
DRM_DEBUG ( " %s while CCE running \n " , __FUNCTION__ ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-09-25 14:28:13 +10:00
r128_do_cce_start ( dev_priv ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
/* Stop the CCE. The engine must have been idled before calling this
* routine .
*/
2005-09-25 14:28:13 +10:00
int r128_cce_stop ( DRM_IOCTL_ARGS )
2005-04-16 15:20:36 -07:00
{
DRM_DEVICE ;
drm_r128_private_t * dev_priv = dev - > dev_private ;
drm_r128_cce_stop_t stop ;
int ret ;
2005-09-25 14:28:13 +10:00
DRM_DEBUG ( " \n " ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
LOCK_TEST_WITH_RETURN ( dev , filp ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
DRM_COPY_FROM_USER_IOCTL ( stop , ( drm_r128_cce_stop_t __user * ) data ,
sizeof ( stop ) ) ;
2005-04-16 15:20:36 -07:00
/* Flush any pending CCE commands. This ensures any outstanding
* commands are exectuted by the engine before we turn it off .
*/
2005-09-25 14:28:13 +10:00
if ( stop . flush ) {
r128_do_cce_flush ( dev_priv ) ;
2005-04-16 15:20:36 -07:00
}
/* If we fail to make the engine go idle, we return an error
* code so that the DRM ioctl wrapper can try again .
*/
2005-09-25 14:28:13 +10:00
if ( stop . idle ) {
ret = r128_do_cce_idle ( dev_priv ) ;
if ( ret )
return ret ;
2005-04-16 15:20:36 -07:00
}
/* Finally, we can turn off the CCE. If the engine isn't idle,
* we will get some dropped triangles as they won ' t be fully
* rendered before the CCE is shut down .
*/
2005-09-25 14:28:13 +10:00
r128_do_cce_stop ( dev_priv ) ;
2005-04-16 15:20:36 -07:00
/* Reset the engine */
2005-09-25 14:28:13 +10:00
r128_do_engine_reset ( dev ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
/* Just reset the CCE ring. Called as part of an X Server engine reset.
*/
2005-09-25 14:28:13 +10:00
int r128_cce_reset ( DRM_IOCTL_ARGS )
2005-04-16 15:20:36 -07:00
{
DRM_DEVICE ;
drm_r128_private_t * dev_priv = dev - > dev_private ;
2005-09-25 14:28:13 +10:00
DRM_DEBUG ( " \n " ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
LOCK_TEST_WITH_RETURN ( dev , filp ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
if ( ! dev_priv ) {
DRM_DEBUG ( " %s called before init done \n " , __FUNCTION__ ) ;
2005-04-16 15:20:36 -07:00
return DRM_ERR ( EINVAL ) ;
}
2005-09-25 14:28:13 +10:00
r128_do_cce_reset ( dev_priv ) ;
2005-04-16 15:20:36 -07:00
/* The CCE is no longer running after an engine reset */
dev_priv - > cce_running = 0 ;
return 0 ;
}
2005-09-25 14:28:13 +10:00
int r128_cce_idle ( DRM_IOCTL_ARGS )
2005-04-16 15:20:36 -07:00
{
DRM_DEVICE ;
drm_r128_private_t * dev_priv = dev - > dev_private ;
2005-09-25 14:28:13 +10:00
DRM_DEBUG ( " \n " ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
LOCK_TEST_WITH_RETURN ( dev , filp ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
if ( dev_priv - > cce_running ) {
r128_do_cce_flush ( dev_priv ) ;
2005-04-16 15:20:36 -07:00
}
2005-09-25 14:28:13 +10:00
return r128_do_cce_idle ( dev_priv ) ;
2005-04-16 15:20:36 -07:00
}
2005-09-25 14:28:13 +10:00
int r128_engine_reset ( DRM_IOCTL_ARGS )
2005-04-16 15:20:36 -07:00
{
DRM_DEVICE ;
2005-09-25 14:28:13 +10:00
DRM_DEBUG ( " \n " ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
LOCK_TEST_WITH_RETURN ( dev , filp ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
return r128_do_engine_reset ( dev ) ;
2005-04-16 15:20:36 -07:00
}
2005-09-25 14:28:13 +10:00
int r128_fullscreen ( DRM_IOCTL_ARGS )
2005-04-16 15:20:36 -07:00
{
return DRM_ERR ( EINVAL ) ;
}
/* ================================================================
* Freelist management
*/
# define R128_BUFFER_USED 0xffffffff
# define R128_BUFFER_FREE 0
#if 0
2007-07-11 16:09:54 +10:00
static int r128_freelist_init ( struct drm_device * dev )
2005-04-16 15:20:36 -07:00
{
2007-07-11 16:32:08 +10:00
struct drm_device_dma * dma = dev - > dma ;
2005-04-16 15:20:36 -07:00
drm_r128_private_t * dev_priv = dev - > dev_private ;
2007-07-11 16:17:42 +10:00
struct drm_buf * buf ;
2005-04-16 15:20:36 -07:00
drm_r128_buf_priv_t * buf_priv ;
drm_r128_freelist_t * entry ;
int i ;
2005-09-25 14:28:13 +10:00
dev_priv - > head = drm_alloc ( sizeof ( drm_r128_freelist_t ) , DRM_MEM_DRIVER ) ;
if ( dev_priv - > head = = NULL )
2005-04-16 15:20:36 -07:00
return DRM_ERR ( ENOMEM ) ;
2005-09-25 14:28:13 +10:00
memset ( dev_priv - > head , 0 , sizeof ( drm_r128_freelist_t ) ) ;
2005-04-16 15:20:36 -07:00
dev_priv - > head - > age = R128_BUFFER_USED ;
2005-09-25 14:28:13 +10:00
for ( i = 0 ; i < dma - > buf_count ; i + + ) {
2005-04-16 15:20:36 -07:00
buf = dma - > buflist [ i ] ;
buf_priv = buf - > dev_private ;
2005-09-25 14:28:13 +10:00
entry = drm_alloc ( sizeof ( drm_r128_freelist_t ) , DRM_MEM_DRIVER ) ;
if ( ! entry )
return DRM_ERR ( ENOMEM ) ;
2005-04-16 15:20:36 -07:00
entry - > age = R128_BUFFER_FREE ;
entry - > buf = buf ;
entry - > prev = dev_priv - > head ;
entry - > next = dev_priv - > head - > next ;
2005-09-25 14:28:13 +10:00
if ( ! entry - > next )
2005-04-16 15:20:36 -07:00
dev_priv - > tail = entry ;
buf_priv - > discard = 0 ;
buf_priv - > dispatched = 0 ;
buf_priv - > list_entry = entry ;
dev_priv - > head - > next = entry ;
2005-09-25 14:28:13 +10:00
if ( dev_priv - > head - > next )
2005-04-16 15:20:36 -07:00
dev_priv - > head - > next - > prev = entry ;
}
return 0 ;
}
# endif
2007-07-11 16:17:42 +10:00
static struct drm_buf * r128_freelist_get ( struct drm_device * dev )
2005-04-16 15:20:36 -07:00
{
2007-07-11 16:32:08 +10:00
struct drm_device_dma * dma = dev - > dma ;
2005-04-16 15:20:36 -07:00
drm_r128_private_t * dev_priv = dev - > dev_private ;
drm_r128_buf_priv_t * buf_priv ;
2007-07-11 16:17:42 +10:00
struct drm_buf * buf ;
2005-04-16 15:20:36 -07:00
int i , t ;
/* FIXME: Optimize -- use freelist code */
2005-09-25 14:28:13 +10:00
for ( i = 0 ; i < dma - > buf_count ; i + + ) {
2005-04-16 15:20:36 -07:00
buf = dma - > buflist [ i ] ;
buf_priv = buf - > dev_private ;
2005-09-25 14:28:13 +10:00
if ( buf - > filp = = 0 )
2005-04-16 15:20:36 -07:00
return buf ;
}
2005-09-25 14:28:13 +10:00
for ( t = 0 ; t < dev_priv - > usec_timeout ; t + + ) {
u32 done_age = R128_READ ( R128_LAST_DISPATCH_REG ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
for ( i = 0 ; i < dma - > buf_count ; i + + ) {
2005-04-16 15:20:36 -07:00
buf = dma - > buflist [ i ] ;
buf_priv = buf - > dev_private ;
2005-09-25 14:28:13 +10:00
if ( buf - > pending & & buf_priv - > age < = done_age ) {
2005-04-16 15:20:36 -07:00
/* The buffer has been processed, so it
* can now be used .
*/
buf - > pending = 0 ;
return buf ;
}
}
2005-09-25 14:28:13 +10:00
DRM_UDELAY ( 1 ) ;
2005-04-16 15:20:36 -07:00
}
2005-09-25 14:28:13 +10:00
DRM_DEBUG ( " returning NULL! \n " ) ;
2005-04-16 15:20:36 -07:00
return NULL ;
}
2007-07-11 16:09:54 +10:00
void r128_freelist_reset ( struct drm_device * dev )
2005-04-16 15:20:36 -07:00
{
2007-07-11 16:32:08 +10:00
struct drm_device_dma * dma = dev - > dma ;
2005-04-16 15:20:36 -07:00
int i ;
2005-09-25 14:28:13 +10:00
for ( i = 0 ; i < dma - > buf_count ; i + + ) {
2007-07-11 16:17:42 +10:00
struct drm_buf * buf = dma - > buflist [ i ] ;
2005-04-16 15:20:36 -07:00
drm_r128_buf_priv_t * buf_priv = buf - > dev_private ;
buf_priv - > age = 0 ;
}
}
/* ================================================================
* CCE command submission
*/
2005-09-25 14:28:13 +10:00
int r128_wait_ring ( drm_r128_private_t * dev_priv , int n )
2005-04-16 15:20:36 -07:00
{
drm_r128_ring_buffer_t * ring = & dev_priv - > ring ;
int i ;
2005-09-25 14:28:13 +10:00
for ( i = 0 ; i < dev_priv - > usec_timeout ; i + + ) {
r128_update_ring_snapshot ( dev_priv ) ;
if ( ring - > space > = n )
2005-04-16 15:20:36 -07:00
return 0 ;
2005-09-25 14:28:13 +10:00
DRM_UDELAY ( 1 ) ;
2005-04-16 15:20:36 -07:00
}
/* FIXME: This is being ignored... */
2005-09-25 14:28:13 +10:00
DRM_ERROR ( " failed! \n " ) ;
2005-04-16 15:20:36 -07:00
return DRM_ERR ( EBUSY ) ;
}
2007-07-11 16:09:54 +10:00
static int r128_cce_get_buffers ( DRMFILE filp , struct drm_device * dev , struct drm_dma * d )
2005-04-16 15:20:36 -07:00
{
int i ;
2007-07-11 16:17:42 +10:00
struct drm_buf * buf ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
for ( i = d - > granted_count ; i < d - > request_count ; i + + ) {
buf = r128_freelist_get ( dev ) ;
if ( ! buf )
return DRM_ERR ( EAGAIN ) ;
2005-04-16 15:20:36 -07:00
buf - > filp = filp ;
2005-09-25 14:28:13 +10:00
if ( DRM_COPY_TO_USER ( & d - > request_indices [ i ] , & buf - > idx ,
sizeof ( buf - > idx ) ) )
2005-04-16 15:20:36 -07:00
return DRM_ERR ( EFAULT ) ;
2005-09-25 14:28:13 +10:00
if ( DRM_COPY_TO_USER ( & d - > request_sizes [ i ] , & buf - > total ,
sizeof ( buf - > total ) ) )
2005-04-16 15:20:36 -07:00
return DRM_ERR ( EFAULT ) ;
d - > granted_count + + ;
}
return 0 ;
}
2005-09-25 14:28:13 +10:00
int r128_cce_buffers ( DRM_IOCTL_ARGS )
2005-04-16 15:20:36 -07:00
{
DRM_DEVICE ;
2007-07-11 16:32:08 +10:00
struct drm_device_dma * dma = dev - > dma ;
2005-04-16 15:20:36 -07:00
int ret = 0 ;
2007-07-11 16:09:54 +10:00
struct drm_dma __user * argp = ( void __user * ) data ;
struct drm_dma d ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
LOCK_TEST_WITH_RETURN ( dev , filp ) ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
DRM_COPY_FROM_USER_IOCTL ( d , argp , sizeof ( d ) ) ;
2005-04-16 15:20:36 -07:00
/* Please don't send us buffers.
*/
2005-09-25 14:28:13 +10:00
if ( d . send_count ! = 0 ) {
DRM_ERROR ( " Process %d trying to send %d buffers via drmDMA \n " ,
DRM_CURRENTPID , d . send_count ) ;
2005-04-16 15:20:36 -07:00
return DRM_ERR ( EINVAL ) ;
}
/* We'll send you buffers.
*/
2005-09-25 14:28:13 +10:00
if ( d . request_count < 0 | | d . request_count > dma - > buf_count ) {
DRM_ERROR ( " Process %d trying to get %d buffers (of %d max) \n " ,
DRM_CURRENTPID , d . request_count , dma - > buf_count ) ;
2005-04-16 15:20:36 -07:00
return DRM_ERR ( EINVAL ) ;
}
d . granted_count = 0 ;
2005-09-25 14:28:13 +10:00
if ( d . request_count ) {
ret = r128_cce_get_buffers ( filp , dev , & d ) ;
2005-04-16 15:20:36 -07:00
}
2005-09-25 14:28:13 +10:00
DRM_COPY_TO_USER_IOCTL ( argp , d , sizeof ( d ) ) ;
2005-04-16 15:20:36 -07:00
return ret ;
}