2005-04-16 15:20:36 -07:00
/**
2006-01-02 19:52:09 +11:00
* \ file drm_memory_debug . h
2005-04-16 15:20:36 -07:00
* Memory management wrappers for DRM .
*
* \ author Rickard E . ( Rik ) Faith < faith @ valinux . com >
* \ author Gareth Hughes < gareth @ valinux . com >
*/
/*
* Copyright 1999 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
* 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
* OTHER DEALINGS IN THE SOFTWARE .
*/
# include "drmP.h"
typedef struct drm_mem_stats {
2005-09-25 14:28:13 +10:00
const char * name ;
int succeed_count ;
int free_count ;
int fail_count ;
unsigned long bytes_allocated ;
unsigned long bytes_freed ;
2005-04-16 15:20:36 -07:00
} drm_mem_stats_t ;
2006-06-27 02:53:55 -07:00
static DEFINE_SPINLOCK ( drm_mem_lock ) ;
2006-01-02 19:52:09 +11:00
static unsigned long drm_ram_available = 0 ; /* In pages */
static unsigned long drm_ram_used = 0 ;
static drm_mem_stats_t drm_mem_stats [ ] =
2005-09-25 14:28:13 +10:00
{
2006-01-02 19:52:09 +11:00
[ DRM_MEM_DMA ] = { " dmabufs " } ,
[ DRM_MEM_SAREA ] = { " sareas " } ,
[ DRM_MEM_DRIVER ] = { " driver " } ,
[ DRM_MEM_MAGIC ] = { " magic " } ,
[ DRM_MEM_IOCTLS ] = { " ioctltab " } ,
[ DRM_MEM_MAPS ] = { " maplist " } ,
[ DRM_MEM_VMAS ] = { " vmalist " } ,
[ DRM_MEM_BUFS ] = { " buflist " } ,
[ DRM_MEM_SEGS ] = { " seglist " } ,
[ DRM_MEM_PAGES ] = { " pagelist " } ,
[ DRM_MEM_FILES ] = { " files " } ,
[ DRM_MEM_QUEUES ] = { " queues " } ,
[ DRM_MEM_CMDS ] = { " commands " } ,
[ DRM_MEM_MAPPINGS ] = { " mappings " } ,
[ DRM_MEM_BUFLISTS ] = { " buflists " } ,
[ DRM_MEM_AGPLISTS ] = { " agplist " } ,
[ DRM_MEM_SGLISTS ] = { " sglist " } ,
[ DRM_MEM_TOTALAGP ] = { " totalagp " } ,
[ DRM_MEM_BOUNDAGP ] = { " boundagp " } ,
[ DRM_MEM_CTXBITMAP ] = { " ctxbitmap " } ,
[ DRM_MEM_CTXLIST ] = { " ctxlist " } ,
[ DRM_MEM_STUB ] = { " stub " } ,
{ NULL , 0 , } /* Last entry must be null */
2005-04-16 15:20:36 -07:00
} ;
2006-01-02 19:52:09 +11:00
void drm_mem_init ( void ) {
2005-04-16 15:20:36 -07:00
drm_mem_stats_t * mem ;
2005-09-25 14:28:13 +10:00
struct sysinfo si ;
2005-04-16 15:20:36 -07:00
2006-01-02 19:52:09 +11:00
for ( mem = drm_mem_stats ; mem - > name ; + + mem ) {
2005-09-25 14:28:13 +10:00
mem - > succeed_count = 0 ;
mem - > free_count = 0 ;
mem - > fail_count = 0 ;
2005-04-16 15:20:36 -07:00
mem - > bytes_allocated = 0 ;
2005-09-25 14:28:13 +10:00
mem - > bytes_freed = 0 ;
2005-04-16 15:20:36 -07:00
}
si_meminfo ( & si ) ;
2006-01-02 19:52:09 +11:00
drm_ram_available = si . totalram ;
drm_ram_used = 0 ;
2005-04-16 15:20:36 -07:00
}
/* drm_mem_info is called whenever a process reads /dev/drm/mem. */
2006-01-02 19:52:09 +11:00
static int drm__mem_info ( char * buf , char * * start , off_t offset ,
2005-09-25 14:28:13 +10:00
int request , int * eof , void * data ) {
2005-04-16 15:20:36 -07:00
drm_mem_stats_t * pt ;
2005-09-25 14:28:13 +10:00
int len = 0 ;
2005-04-16 15:20:36 -07:00
if ( offset > DRM_PROC_LIMIT ) {
* eof = 1 ;
return 0 ;
}
2005-09-25 14:28:13 +10:00
* eof = 0 ;
2005-04-16 15:20:36 -07:00
* start = & buf [ offset ] ;
DRM_PROC_PRINT ( " total counts "
" | outstanding \n " ) ;
DRM_PROC_PRINT ( " type alloc freed fail bytes freed "
" | allocs bytes \n \n " ) ;
DRM_PROC_PRINT ( " %-9.9s %5d %5d %4d %10lu kB | \n " ,
" system " , 0 , 0 , 0 ,
2006-01-02 19:52:09 +11:00
drm_ram_available < < ( PAGE_SHIFT - 10 ) ) ;
2005-04-16 15:20:36 -07:00
DRM_PROC_PRINT ( " %-9.9s %5d %5d %4d %10lu kB | \n " ,
2006-01-02 19:52:09 +11:00
" locked " , 0 , 0 , 0 , drm_ram_used > > 10 ) ;
2005-04-16 15:20:36 -07:00
DRM_PROC_PRINT ( " \n " ) ;
2006-01-02 19:52:09 +11:00
for ( pt = drm_mem_stats ; pt - > name ; pt + + ) {
2005-04-16 15:20:36 -07:00
DRM_PROC_PRINT ( " %-9.9s %5d %5d %4d %10lu %10lu | %6d %10ld \n " ,
pt - > name ,
pt - > succeed_count ,
pt - > free_count ,
pt - > fail_count ,
pt - > bytes_allocated ,
pt - > bytes_freed ,
pt - > succeed_count - pt - > free_count ,
( long ) pt - > bytes_allocated
- ( long ) pt - > bytes_freed ) ;
}
2005-09-25 14:28:13 +10:00
if ( len > request + offset )
return request ;
2005-04-16 15:20:36 -07:00
* eof = 1 ;
return len - offset ;
}
2006-01-02 19:52:09 +11:00
int drm_mem_info ( char * buf , char * * start , off_t offset ,
2005-09-25 14:28:13 +10:00
int len , int * eof , void * data ) {
2005-04-16 15:20:36 -07:00
int ret ;
2006-01-02 19:52:09 +11:00
spin_lock ( & drm_mem_lock ) ;
ret = drm__mem_info ( buf , start , offset , len , eof , data ) ;
spin_unlock ( & drm_mem_lock ) ;
2005-04-16 15:20:36 -07:00
return ret ;
}
2006-01-02 19:52:09 +11:00
void * drm_alloc ( size_t size , int area ) {
2005-04-16 15:20:36 -07:00
void * pt ;
if ( ! size ) {
DRM_MEM_ERROR ( area , " Allocating 0 bytes \n " ) ;
return NULL ;
}
if ( ! ( pt = kmalloc ( size , GFP_KERNEL ) ) ) {
2006-01-02 19:52:09 +11:00
spin_lock ( & drm_mem_lock ) ;
+ + drm_mem_stats [ area ] . fail_count ;
spin_unlock ( & drm_mem_lock ) ;
2005-04-16 15:20:36 -07:00
return NULL ;
}
2006-01-02 19:52:09 +11:00
spin_lock ( & drm_mem_lock ) ;
+ + drm_mem_stats [ area ] . succeed_count ;
drm_mem_stats [ area ] . bytes_allocated + = size ;
spin_unlock ( & drm_mem_lock ) ;
2005-04-16 15:20:36 -07:00
return pt ;
}
2006-01-02 19:52:09 +11:00
void * drm_calloc ( size_t nmemb , size_t size , int area ) {
2005-04-16 15:20:36 -07:00
void * addr ;
2006-01-02 19:52:09 +11:00
addr = drm_alloc ( nmemb * size , area ) ;
2005-04-16 15:20:36 -07:00
if ( addr ! = NULL )
memset ( ( void * ) addr , 0 , size * nmemb ) ;
return addr ;
}
2006-01-02 19:52:09 +11:00
void * drm_realloc ( void * oldpt , size_t oldsize , size_t size , int area ) {
2005-04-16 15:20:36 -07:00
void * pt ;
2006-01-02 19:52:09 +11:00
if ( ! ( pt = drm_alloc ( size , area ) ) )
2005-09-25 14:28:13 +10:00
return NULL ;
2005-04-16 15:20:36 -07:00
if ( oldpt & & oldsize ) {
memcpy ( pt , oldpt , oldsize ) ;
2006-01-02 19:52:09 +11:00
drm_free ( oldpt , oldsize , area ) ;
2005-04-16 15:20:36 -07:00
}
return pt ;
}
2006-01-02 19:52:09 +11:00
void drm_free ( void * pt , size_t size , int area ) {
2005-04-16 15:20:36 -07:00
int alloc_count ;
int free_count ;
2005-09-25 14:28:13 +10:00
if ( ! pt )
DRM_MEM_ERROR ( area , " Attempt to free NULL pointer \n " ) ;
else
kfree ( pt ) ;
2006-01-02 19:52:09 +11:00
spin_lock ( & drm_mem_lock ) ;
drm_mem_stats [ area ] . bytes_freed + = size ;
free_count = + + drm_mem_stats [ area ] . free_count ;
alloc_count = drm_mem_stats [ area ] . succeed_count ;
spin_unlock ( & drm_mem_lock ) ;
2005-04-16 15:20:36 -07:00
if ( free_count > alloc_count ) {
DRM_MEM_ERROR ( area , " Excess frees: %d frees, %d allocs \n " ,
free_count , alloc_count ) ;
}
}
# if __OS_HAS_AGP
2006-01-02 19:52:09 +11:00
DRM_AGP_MEM * drm_alloc_agp ( drm_device_t * dev , int pages , u32 type ) {
2005-04-16 15:20:36 -07:00
DRM_AGP_MEM * handle ;
if ( ! pages ) {
DRM_MEM_ERROR ( DRM_MEM_TOTALAGP , " Allocating 0 pages \n " ) ;
return NULL ;
}
2006-01-02 19:52:09 +11:00
if ( ( handle = drm_agp_allocate_memory ( pages , type ) ) ) {
spin_lock ( & drm_mem_lock ) ;
+ + drm_mem_stats [ DRM_MEM_TOTALAGP ] . succeed_count ;
drm_mem_stats [ DRM_MEM_TOTALAGP ] . bytes_allocated
2005-09-25 14:28:13 +10:00
+ = pages < < PAGE_SHIFT ;
2006-01-02 19:52:09 +11:00
spin_unlock ( & drm_mem_lock ) ;
2005-04-16 15:20:36 -07:00
return handle ;
}
2006-01-02 19:52:09 +11:00
spin_lock ( & drm_mem_lock ) ;
+ + drm_mem_stats [ DRM_MEM_TOTALAGP ] . fail_count ;
spin_unlock ( & drm_mem_lock ) ;
2005-04-16 15:20:36 -07:00
return NULL ;
}
2006-01-02 19:52:09 +11:00
int drm_free_agp ( DRM_AGP_MEM * handle , int pages ) {
2005-09-25 14:28:13 +10:00
int alloc_count ;
int free_count ;
int retval = - EINVAL ;
2005-04-16 15:20:36 -07:00
if ( ! handle ) {
DRM_MEM_ERROR ( DRM_MEM_TOTALAGP ,
" Attempt to free NULL AGP handle \n " ) ;
return retval ;
}
2006-01-02 19:52:09 +11:00
if ( drm_agp_free_memory ( handle ) ) {
spin_lock ( & drm_mem_lock ) ;
free_count = + + drm_mem_stats [ DRM_MEM_TOTALAGP ] . free_count ;
alloc_count = drm_mem_stats [ DRM_MEM_TOTALAGP ] . succeed_count ;
drm_mem_stats [ DRM_MEM_TOTALAGP ] . bytes_freed
2005-09-25 14:28:13 +10:00
+ = pages < < PAGE_SHIFT ;
2006-01-02 19:52:09 +11:00
spin_unlock ( & drm_mem_lock ) ;
2005-04-16 15:20:36 -07:00
if ( free_count > alloc_count ) {
DRM_MEM_ERROR ( DRM_MEM_TOTALAGP ,
" Excess frees: %d frees, %d allocs \n " ,
free_count , alloc_count ) ;
}
return 0 ;
}
return retval ;
}
2006-01-02 19:52:09 +11:00
int drm_bind_agp ( DRM_AGP_MEM * handle , unsigned int start ) {
2005-04-16 15:20:36 -07:00
int retcode = - EINVAL ;
if ( ! handle ) {
DRM_MEM_ERROR ( DRM_MEM_BOUNDAGP ,
" Attempt to bind NULL AGP handle \n " ) ;
return retcode ;
}
2006-01-02 19:52:09 +11:00
if ( ! ( retcode = drm_agp_bind_memory ( handle , start ) ) ) {
spin_lock ( & drm_mem_lock ) ;
+ + drm_mem_stats [ DRM_MEM_BOUNDAGP ] . succeed_count ;
drm_mem_stats [ DRM_MEM_BOUNDAGP ] . bytes_allocated
2005-09-25 14:28:13 +10:00
+ = handle - > page_count < < PAGE_SHIFT ;
2006-01-02 19:52:09 +11:00
spin_unlock ( & drm_mem_lock ) ;
2005-04-16 15:20:36 -07:00
return retcode ;
}
2006-01-02 19:52:09 +11:00
spin_lock ( & drm_mem_lock ) ;
+ + drm_mem_stats [ DRM_MEM_BOUNDAGP ] . fail_count ;
spin_unlock ( & drm_mem_lock ) ;
2005-04-16 15:20:36 -07:00
return retcode ;
}
2006-01-02 19:52:09 +11:00
int drm_unbind_agp ( DRM_AGP_MEM * handle ) {
2005-04-16 15:20:36 -07:00
int alloc_count ;
int free_count ;
int retcode = - EINVAL ;
if ( ! handle ) {
DRM_MEM_ERROR ( DRM_MEM_BOUNDAGP ,
" Attempt to unbind NULL AGP handle \n " ) ;
return retcode ;
}
2006-01-02 19:52:09 +11:00
if ( ( retcode = drm_agp_unbind_memory ( handle ) ) )
2005-09-25 14:28:13 +10:00
return retcode ;
2006-01-02 19:52:09 +11:00
spin_lock ( & drm_mem_lock ) ;
free_count = + + drm_mem_stats [ DRM_MEM_BOUNDAGP ] . free_count ;
alloc_count = drm_mem_stats [ DRM_MEM_BOUNDAGP ] . succeed_count ;
drm_mem_stats [ DRM_MEM_BOUNDAGP ] . bytes_freed
2005-09-25 14:28:13 +10:00
+ = handle - > page_count < < PAGE_SHIFT ;
2006-01-02 19:52:09 +11:00
spin_unlock ( & drm_mem_lock ) ;
2005-04-16 15:20:36 -07:00
if ( free_count > alloc_count ) {
DRM_MEM_ERROR ( DRM_MEM_BOUNDAGP ,
" Excess frees: %d frees, %d allocs \n " ,
free_count , alloc_count ) ;
}
return retcode ;
}
# endif