2006-08-07 22:03:22 +10:00
/**************************************************************************
2005-04-16 15:20:36 -07:00
*
2006-08-07 22:03:22 +10:00
* Copyright 2006 Tungsten Graphics , Inc . , Bismarck , ND . , USA .
* All Rights Reserved .
2005-04-16 15:20:36 -07:00
*
* Permission is hereby granted , free of charge , to any person obtaining a
2006-08-07 22:03:22 +10:00
* 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 , sub license , 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 :
2005-09-25 14:28:13 +10:00
*
2006-08-07 22:03:22 +10:00
* The above copyright notice and this permission notice ( including the
* next paragraph ) shall be included in all copies or substantial portions
* of the Software .
2005-09-25 14:28:13 +10:00
*
2005-04-16 15:20:36 -07:00
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
2006-08-07 22:03:22 +10:00
* FITNESS FOR A PARTICULAR PURPOSE AND NON - INFRINGEMENT . IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS , AUTHORS 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 .
2005-09-25 14:28:13 +10:00
*
*
2006-08-07 22:03:22 +10:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Authors :
* Thomas Hellstr <EFBFBD> m < thomas - at - tungstengraphics - dot - com >
2005-04-16 15:20:36 -07:00
*/
# include "drmP.h"
# include "sis_drm.h"
# include "sis_drv.h"
2006-08-07 22:03:22 +10:00
2005-04-16 15:20:36 -07:00
# include <video/sisfb.h>
2005-09-25 14:28:13 +10:00
# define VIDEO_TYPE 0
2005-04-16 15:20:36 -07:00
# define AGP_TYPE 1
2006-08-07 22:03:22 +10:00
# if defined(CONFIG_FB_SIS)
/* fb management via fb device */
2005-09-25 14:28:13 +10:00
2006-08-07 22:03:22 +10:00
# define SIS_MM_ALIGN_SHIFT 0
# define SIS_MM_ALIGN_MASK 0
2005-04-16 15:20:36 -07:00
2006-08-07 22:03:22 +10:00
static void * sis_sman_mm_allocate ( void * private , unsigned long size ,
unsigned alignment )
2005-09-25 14:28:13 +10:00
{
2006-08-07 22:03:22 +10:00
struct sis_memreq req ;
2005-04-16 15:20:36 -07:00
2006-08-07 22:03:22 +10:00
req . size = size ;
sis_malloc ( & req ) ;
if ( req . size = = 0 )
return NULL ;
else
return ( void * ) ~ req . offset ;
2005-04-16 15:20:36 -07:00
}
2006-08-07 22:03:22 +10:00
static void sis_sman_mm_free ( void * private , void * ref )
2005-04-16 15:20:36 -07:00
{
2006-08-07 22:03:22 +10:00
sis_free ( ~ ( ( unsigned long ) ref ) ) ;
2005-04-16 15:20:36 -07:00
}
2006-08-07 22:03:22 +10:00
static void sis_sman_mm_destroy ( void * private )
2005-04-16 15:20:36 -07:00
{
2006-08-07 22:03:22 +10:00
;
2005-04-16 15:20:36 -07:00
}
2006-08-16 11:55:18 +10:00
static unsigned long sis_sman_mm_offset ( void * private , void * ref )
2005-04-16 15:20:36 -07:00
{
2006-08-07 22:03:22 +10:00
return ~ ( ( unsigned long ) ref ) ;
2005-04-16 15:20:36 -07:00
}
2006-08-16 11:55:18 +10:00
# else /* CONFIG_FB_SIS */
# define SIS_MM_ALIGN_SHIFT 4
# define SIS_MM_ALIGN_MASK ( (1 << SIS_MM_ALIGN_SHIFT) - 1)
# endif /* CONFIG_FB_SIS */
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
static int sis_fb_init ( DRM_IOCTL_ARGS )
2005-04-16 15:20:36 -07:00
{
DRM_DEVICE ;
drm_sis_private_t * dev_priv = dev - > dev_private ;
drm_sis_fb_t fb ;
2006-08-07 22:03:22 +10:00
int ret ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
DRM_COPY_FROM_USER_IOCTL ( fb , ( drm_sis_fb_t __user * ) data , sizeof ( fb ) ) ;
2005-04-16 15:20:36 -07:00
2006-08-07 22:03:22 +10:00
mutex_lock ( & dev - > struct_mutex ) ;
# if defined(CONFIG_FB_SIS)
{
drm_sman_mm_t sman_mm ;
sman_mm . private = ( void * ) 0xFFFFFFFF ;
sman_mm . allocate = sis_sman_mm_allocate ;
sman_mm . free = sis_sman_mm_free ;
sman_mm . destroy = sis_sman_mm_destroy ;
sman_mm . offset = sis_sman_mm_offset ;
ret =
drm_sman_set_manager ( & dev_priv - > sman , VIDEO_TYPE , & sman_mm ) ;
2005-04-16 15:20:36 -07:00
}
2006-08-07 22:03:22 +10:00
# else
ret = drm_sman_set_range ( & dev_priv - > sman , VIDEO_TYPE , 0 ,
fb . size > > SIS_MM_ALIGN_SHIFT ) ;
# endif
2005-04-16 15:20:36 -07:00
2006-08-07 22:03:22 +10:00
if ( ret ) {
DRM_ERROR ( " VRAM memory manager initialisation error \n " ) ;
mutex_unlock ( & dev - > struct_mutex ) ;
return ret ;
}
2005-04-16 15:20:36 -07:00
2006-08-14 11:35:15 +10:00
dev_priv - > vram_initialized = 1 ;
2006-08-07 22:03:22 +10:00
dev_priv - > vram_offset = fb . offset ;
2005-04-16 15:20:36 -07:00
2006-08-07 22:03:22 +10:00
mutex_unlock ( & dev - > struct_mutex ) ;
2005-04-16 15:20:36 -07:00
DRM_DEBUG ( " offset = %u, size = %u " , fb . offset , fb . size ) ;
return 0 ;
}
2006-08-07 22:03:22 +10:00
static int sis_drm_alloc ( drm_device_t * dev , drm_file_t * priv ,
unsigned long data , int pool )
2005-04-16 15:20:36 -07:00
{
drm_sis_private_t * dev_priv = dev - > dev_private ;
2006-08-07 22:03:22 +10:00
drm_sis_mem_t __user * argp = ( drm_sis_mem_t __user * ) data ;
drm_sis_mem_t mem ;
2005-04-16 15:20:36 -07:00
int retval = 0 ;
2006-08-07 22:03:22 +10:00
drm_memblock_item_t * item ;
2005-04-16 15:20:36 -07:00
2006-08-07 22:03:22 +10:00
DRM_COPY_FROM_USER_IOCTL ( mem , argp , sizeof ( mem ) ) ;
mutex_lock ( & dev - > struct_mutex ) ;
2006-08-14 11:35:15 +10:00
if ( 0 = = ( ( pool = = 0 ) ? dev_priv - > vram_initialized :
2006-08-07 22:03:22 +10:00
dev_priv - > agp_initialized ) ) {
DRM_ERROR
( " Attempt to allocate from uninitialized memory manager. \n " ) ;
2005-04-16 15:20:36 -07:00
return DRM_ERR ( EINVAL ) ;
2006-08-07 22:03:22 +10:00
}
2005-09-25 14:28:13 +10:00
2006-08-07 22:03:22 +10:00
mem . size = ( mem . size + SIS_MM_ALIGN_MASK ) > > SIS_MM_ALIGN_SHIFT ;
item = drm_sman_alloc ( & dev_priv - > sman , pool , mem . size , 0 ,
( unsigned long ) priv ) ;
mutex_unlock ( & dev - > struct_mutex ) ;
if ( item ) {
mem . offset = ( ( pool = = 0 ) ?
dev_priv - > vram_offset : dev_priv - > agp_offset ) +
( item - > mm - >
offset ( item - > mm , item - > mm_info ) < < SIS_MM_ALIGN_SHIFT ) ;
mem . free = item - > user_hash . key ;
mem . size = mem . size < < SIS_MM_ALIGN_SHIFT ;
2005-04-16 15:20:36 -07:00
} else {
2006-08-07 22:03:22 +10:00
mem . offset = 0 ;
mem . size = 0 ;
mem . free = 0 ;
retval = DRM_ERR ( ENOMEM ) ;
2005-04-16 15:20:36 -07:00
}
2006-08-07 22:03:22 +10:00
DRM_COPY_TO_USER_IOCTL ( argp , mem , sizeof ( mem ) ) ;
2005-04-16 15:20:36 -07:00
2006-08-07 22:03:22 +10:00
DRM_DEBUG ( " alloc %d, size = %d, offset = %d \n " , pool , mem . size ,
mem . offset ) ;
2005-04-16 15:20:36 -07:00
return retval ;
}
2006-08-07 22:03:22 +10:00
static int sis_drm_free ( DRM_IOCTL_ARGS )
2005-04-16 15:20:36 -07:00
{
DRM_DEVICE ;
drm_sis_private_t * dev_priv = dev - > dev_private ;
2006-08-07 22:03:22 +10:00
drm_sis_mem_t mem ;
int ret ;
2005-04-16 15:20:36 -07:00
2006-08-07 22:03:22 +10:00
DRM_COPY_FROM_USER_IOCTL ( mem , ( drm_sis_mem_t __user * ) data ,
sizeof ( mem ) ) ;
2005-04-16 15:20:36 -07:00
2006-08-07 22:03:22 +10:00
mutex_lock ( & dev - > struct_mutex ) ;
ret = drm_sman_free_key ( & dev_priv - > sman , mem . free ) ;
mutex_unlock ( & dev - > struct_mutex ) ;
DRM_DEBUG ( " free = 0x%lx \n " , mem . free ) ;
2005-04-16 15:20:36 -07:00
2006-08-07 22:03:22 +10:00
return ret ;
2005-04-16 15:20:36 -07:00
}
2006-08-07 22:03:22 +10:00
static int sis_fb_alloc ( DRM_IOCTL_ARGS )
{
DRM_DEVICE ;
return sis_drm_alloc ( dev , priv , data , VIDEO_TYPE ) ;
}
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
static int sis_ioctl_agp_init ( DRM_IOCTL_ARGS )
2005-04-16 15:20:36 -07:00
{
DRM_DEVICE ;
drm_sis_private_t * dev_priv = dev - > dev_private ;
drm_sis_agp_t agp ;
2006-08-07 22:03:22 +10:00
int ret ;
dev_priv = dev - > dev_private ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
DRM_COPY_FROM_USER_IOCTL ( agp , ( drm_sis_agp_t __user * ) data ,
sizeof ( agp ) ) ;
2006-08-07 22:03:22 +10:00
mutex_lock ( & dev - > struct_mutex ) ;
ret = drm_sman_set_range ( & dev_priv - > sman , AGP_TYPE , 0 ,
agp . size > > SIS_MM_ALIGN_SHIFT ) ;
if ( ret ) {
DRM_ERROR ( " AGP memory manager initialisation error \n " ) ;
mutex_unlock ( & dev - > struct_mutex ) ;
return ret ;
}
2005-04-16 15:20:36 -07:00
2006-08-14 11:35:15 +10:00
dev_priv - > agp_initialized = 1 ;
2006-08-07 22:03:22 +10:00
dev_priv - > agp_offset = agp . offset ;
mutex_unlock ( & dev - > struct_mutex ) ;
2005-04-16 15:20:36 -07:00
DRM_DEBUG ( " offset = %u, size = %u " , agp . offset , agp . size ) ;
return 0 ;
}
2005-09-25 14:28:13 +10:00
static int sis_ioctl_agp_alloc ( DRM_IOCTL_ARGS )
2005-04-16 15:20:36 -07:00
{
DRM_DEVICE ;
2006-08-07 22:03:22 +10:00
return sis_drm_alloc ( dev , priv , data , AGP_TYPE ) ;
2005-04-16 15:20:36 -07:00
}
2006-08-08 21:34:46 +10:00
static drm_local_map_t * sis_reg_init ( drm_device_t * dev )
{
drm_map_list_t * entry ;
drm_local_map_t * map ;
list_for_each_entry ( entry , & dev - > maplist - > head , head ) {
map = entry - > map ;
if ( ! map )
continue ;
if ( map - > type = = _DRM_REGISTERS ) {
return map ;
}
}
return NULL ;
}
int sis_idle ( drm_device_t * dev )
{
drm_sis_private_t * dev_priv = dev - > dev_private ;
uint32_t idle_reg ;
unsigned long end ;
int i ;
if ( dev_priv - > idle_fault )
return 0 ;
if ( dev_priv - > mmio = = NULL ) {
dev_priv - > mmio = sis_reg_init ( dev ) ;
if ( dev_priv - > mmio = = NULL ) {
DRM_ERROR ( " Could not find register map. \n " ) ;
return 0 ;
}
}
/*
* Implement a device switch here if needed
*/
if ( dev_priv - > chipset ! = SIS_CHIP_315 )
return 0 ;
/*
* Timeout after 3 seconds . We cannot use DRM_WAIT_ON here
* because its polling frequency is too low .
*/
end = jiffies + ( DRM_HZ * 3 ) ;
for ( i = 0 ; i < 4 ; + + i ) {
do {
idle_reg = SIS_READ ( 0x85cc ) ;
} while ( ! time_after_eq ( jiffies , end ) & &
( ( idle_reg & 0x80000000 ) ! = 0x80000000 ) ) ;
}
if ( time_after_eq ( jiffies , end ) ) {
DRM_ERROR ( " Graphics engine idle timeout. "
" Disabling idle check \n " ) ;
2006-08-14 11:35:15 +10:00
dev_priv - > idle_fault = 1 ;
2006-08-08 21:34:46 +10:00
}
/*
* The caller never sees an error code . It gets trapped
* in libdrm .
*/
return 0 ;
}
2006-08-07 22:03:22 +10:00
void sis_lastclose ( struct drm_device * dev )
2005-04-16 15:20:36 -07:00
{
drm_sis_private_t * dev_priv = dev - > dev_private ;
2006-08-07 22:03:22 +10:00
if ( ! dev_priv )
return ;
2005-04-16 15:20:36 -07:00
2006-08-07 22:03:22 +10:00
mutex_lock ( & dev - > struct_mutex ) ;
drm_sman_cleanup ( & dev_priv - > sman ) ;
2006-08-14 11:35:15 +10:00
dev_priv - > vram_initialized = 0 ;
dev_priv - > agp_initialized = 0 ;
2006-08-08 21:34:46 +10:00
dev_priv - > mmio = NULL ;
2006-08-07 22:03:22 +10:00
mutex_unlock ( & dev - > struct_mutex ) ;
2005-04-16 15:20:36 -07:00
}
2006-08-07 22:03:22 +10:00
void sis_reclaim_buffers_locked ( drm_device_t * dev , struct file * filp )
2005-04-16 15:20:36 -07:00
{
2006-08-07 22:03:22 +10:00
drm_sis_private_t * dev_priv = dev - > dev_private ;
drm_file_t * priv = filp - > private_data ;
2005-04-16 15:20:36 -07:00
2006-08-07 22:03:22 +10:00
mutex_lock ( & dev - > struct_mutex ) ;
if ( drm_sman_owner_clean ( & dev_priv - > sman , ( unsigned long ) priv ) ) {
mutex_unlock ( & dev - > struct_mutex ) ;
return ;
2005-04-16 15:20:36 -07:00
}
2006-08-07 22:03:22 +10:00
if ( dev - > driver - > dma_quiescent ) {
dev - > driver - > dma_quiescent ( dev ) ;
2005-09-25 14:28:13 +10:00
}
2006-08-07 22:03:22 +10:00
drm_sman_owner_cleanup ( & dev_priv - > sman , ( unsigned long ) priv ) ;
mutex_unlock ( & dev - > struct_mutex ) ;
return ;
2005-04-16 15:20:36 -07:00
}
drm_ioctl_desc_t sis_ioctls [ ] = {
2006-01-02 13:54:04 +11:00
[ DRM_IOCTL_NR ( DRM_SIS_FB_ALLOC ) ] = { sis_fb_alloc , DRM_AUTH } ,
2006-08-07 22:03:22 +10:00
[ DRM_IOCTL_NR ( DRM_SIS_FB_FREE ) ] = { sis_drm_free , DRM_AUTH } ,
[ DRM_IOCTL_NR ( DRM_SIS_AGP_INIT ) ] =
{ sis_ioctl_agp_init , DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY } ,
2006-01-02 13:54:04 +11:00
[ DRM_IOCTL_NR ( DRM_SIS_AGP_ALLOC ) ] = { sis_ioctl_agp_alloc , DRM_AUTH } ,
2006-08-07 22:03:22 +10:00
[ DRM_IOCTL_NR ( DRM_SIS_AGP_FREE ) ] = { sis_drm_free , DRM_AUTH } ,
[ DRM_IOCTL_NR ( DRM_SIS_FB_INIT ) ] =
{ sis_fb_init , DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY }
2005-04-16 15:20:36 -07:00
} ;
int sis_max_ioctl = DRM_ARRAY_SIZE ( sis_ioctls ) ;