2006-08-07 16:03:22 +04:00
/**************************************************************************
2005-04-17 02:20:36 +04:00
*
2006-08-07 16:03:22 +04:00
* Copyright 2006 Tungsten Graphics , Inc . , Bismarck , ND . , USA .
* All Rights Reserved .
2005-04-17 02:20:36 +04:00
*
* Permission is hereby granted , free of charge , to any person obtaining a
2006-08-07 16:03:22 +04: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 08:28:13 +04:00
*
2006-08-07 16:03:22 +04: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 08:28:13 +04:00
*
2005-04-17 02:20:36 +04: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 16:03:22 +04: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 08:28:13 +04:00
*
*
2006-08-07 16:03:22 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Authors :
2007-10-20 01:21:04 +04:00
* Thomas Hellström < thomas - at - tungstengraphics - dot - com >
2005-04-17 02:20:36 +04:00
*/
2012-10-02 21:01:07 +04:00
# include <drm/drmP.h>
# include <drm/sis_drm.h>
2005-04-17 02:20:36 +04:00
# include "sis_drv.h"
2006-08-07 16:03:22 +04:00
2005-04-17 02:20:36 +04:00
# include <video/sisfb.h>
2005-09-25 08:28:13 +04:00
# define VIDEO_TYPE 0
2005-04-17 02:20:36 +04:00
# define AGP_TYPE 1
2011-10-27 00:22:59 +04:00
struct sis_memblock {
struct drm_mm_node mm_node ;
struct sis_memreq req ;
struct list_head owner_list ;
} ;
2008-07-30 23:29:37 +04:00
# if defined(CONFIG_FB_SIS) || defined(CONFIG_FB_SIS_MODULE)
2006-08-07 16:03:22 +04:00
/* fb management via fb device */
2005-09-25 08:28:13 +04:00
2006-08-07 16:03:22 +04:00
# define SIS_MM_ALIGN_SHIFT 0
# define SIS_MM_ALIGN_MASK 0
2005-04-17 02:20:36 +04:00
2008-07-30 23:29:37 +04:00
# else /* CONFIG_FB_SIS[_MODULE] */
2006-08-16 05:55:18 +04:00
# define SIS_MM_ALIGN_SHIFT 4
2010-07-09 18:47:28 +04:00
# define SIS_MM_ALIGN_MASK ((1 << SIS_MM_ALIGN_SHIFT) - 1)
2006-08-16 05:55:18 +04:00
2008-07-30 23:29:37 +04:00
# endif /* CONFIG_FB_SIS[_MODULE] */
2005-04-17 02:20:36 +04:00
2007-09-03 06:06:45 +04:00
static int sis_fb_init ( struct drm_device * dev , void * data , struct drm_file * file_priv )
2005-04-17 02:20:36 +04:00
{
drm_sis_private_t * dev_priv = dev - > dev_private ;
2007-09-03 06:06:45 +04:00
drm_sis_fb_t * fb = data ;
2005-04-17 02:20:36 +04:00
2006-08-07 16:03:22 +04:00
mutex_lock ( & dev - > struct_mutex ) ;
2011-10-27 00:22:59 +04:00
/* Unconditionally init the drm_mm, even though we don't use it when the
* fb sis driver is available - make cleanup easier . */
drm_mm_init ( & dev_priv - > vram_mm , 0 , fb - > size > > SIS_MM_ALIGN_SHIFT ) ;
2005-04-17 02:20:36 +04:00
2006-08-14 05:35:15 +04:00
dev_priv - > vram_initialized = 1 ;
2007-09-03 06:06:45 +04:00
dev_priv - > vram_offset = fb - > offset ;
2005-04-17 02:20:36 +04:00
2006-08-07 16:03:22 +04:00
mutex_unlock ( & dev - > struct_mutex ) ;
2012-06-24 21:57:24 +04:00
DRM_DEBUG ( " offset = %lu, size = %lu \n " , fb - > offset , fb - > size ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2011-10-25 18:32:34 +04:00
static int sis_drm_alloc ( struct drm_device * dev , struct drm_file * file ,
2007-09-03 06:06:45 +04:00
void * data , int pool )
2005-04-17 02:20:36 +04:00
{
drm_sis_private_t * dev_priv = dev - > dev_private ;
2007-09-03 06:06:45 +04:00
drm_sis_mem_t * mem = data ;
2011-10-25 20:00:41 +04:00
int retval = 0 , user_key ;
2011-10-27 00:22:59 +04:00
struct sis_memblock * item ;
2011-10-25 18:32:34 +04:00
struct sis_file_private * file_priv = file - > driver_priv ;
2011-10-27 00:22:59 +04:00
unsigned long offset ;
2005-04-17 02:20:36 +04:00
2006-08-07 16:03:22 +04:00
mutex_lock ( & dev - > struct_mutex ) ;
2006-08-14 05:35:15 +04:00
if ( 0 = = ( ( pool = = 0 ) ? dev_priv - > vram_initialized :
2006-08-07 16:03:22 +04:00
dev_priv - > agp_initialized ) ) {
DRM_ERROR
( " Attempt to allocate from uninitialized memory manager. \n " ) ;
2007-11-05 03:53:18 +03:00
mutex_unlock ( & dev - > struct_mutex ) ;
2007-08-25 13:22:43 +04:00
return - EINVAL ;
2006-08-07 16:03:22 +04:00
}
2005-09-25 08:28:13 +04:00
2011-10-27 00:22:59 +04:00
item = kzalloc ( sizeof ( * item ) , GFP_KERNEL ) ;
2011-10-25 20:00:41 +04:00
if ( ! item ) {
retval = - ENOMEM ;
goto fail_alloc ;
}
2006-08-07 16:03:22 +04:00
2011-10-27 00:22:59 +04:00
mem - > size = ( mem - > size + SIS_MM_ALIGN_MASK ) > > SIS_MM_ALIGN_SHIFT ;
if ( pool = = AGP_TYPE ) {
retval = drm_mm_insert_node ( & dev_priv - > agp_mm ,
& item - > mm_node ,
2013-07-27 15:36:27 +04:00
mem - > size , 0 ,
DRM_MM_SEARCH_DEFAULT ) ;
2011-10-27 00:22:59 +04:00
offset = item - > mm_node . start ;
} else {
# if defined(CONFIG_FB_SIS) || defined(CONFIG_FB_SIS_MODULE)
item - > req . size = mem - > size ;
sis_malloc ( & item - > req ) ;
if ( item - > req . size = = 0 )
retval = - ENOMEM ;
offset = item - > req . offset ;
# else
retval = drm_mm_insert_node ( & dev_priv - > vram_mm ,
& item - > mm_node ,
2013-07-27 15:36:27 +04:00
mem - > size , 0 ,
DRM_MM_SEARCH_DEFAULT ) ;
2011-10-27 00:22:59 +04:00
offset = item - > mm_node . start ;
# endif
}
if ( retval )
goto fail_alloc ;
2013-02-28 05:04:11 +04:00
retval = idr_alloc ( & dev_priv - > object_idr , item , 1 , 0 , GFP_KERNEL ) ;
if ( retval < 0 )
2011-10-25 20:00:41 +04:00
goto fail_idr ;
2013-02-28 05:04:11 +04:00
user_key = retval ;
2011-10-25 20:00:41 +04:00
list_add ( & item - > owner_list , & file_priv - > obj_list ) ;
mutex_unlock ( & dev - > struct_mutex ) ;
mem - > offset = ( ( pool = = 0 ) ?
dev_priv - > vram_offset : dev_priv - > agp_offset ) +
2011-10-27 00:22:59 +04:00
( offset < < SIS_MM_ALIGN_SHIFT ) ;
2011-10-25 20:00:41 +04:00
mem - > free = user_key ;
mem - > size = mem - > size < < SIS_MM_ALIGN_SHIFT ;
return 0 ;
fail_idr :
2011-10-27 00:22:59 +04:00
drm_mm_remove_node ( & item - > mm_node ) ;
2011-10-25 20:00:41 +04:00
fail_alloc :
2011-10-27 00:22:59 +04:00
kfree ( item ) ;
2011-10-25 18:32:34 +04:00
mutex_unlock ( & dev - > struct_mutex ) ;
2005-04-17 02:20:36 +04:00
2011-10-25 20:00:41 +04:00
mem - > offset = 0 ;
mem - > size = 0 ;
mem - > free = 0 ;
2012-06-24 21:57:24 +04:00
DRM_DEBUG ( " alloc %d, size = %ld, offset = %ld \n " , pool , mem - > size ,
2007-09-03 06:06:45 +04:00
mem - > offset ) ;
2005-04-17 02:20:36 +04:00
return retval ;
}
2007-09-03 06:06:45 +04:00
static int sis_drm_free ( struct drm_device * dev , void * data , struct drm_file * file_priv )
2005-04-17 02:20:36 +04:00
{
drm_sis_private_t * dev_priv = dev - > dev_private ;
2007-09-03 06:06:45 +04:00
drm_sis_mem_t * mem = data ;
2011-10-27 00:22:59 +04:00
struct sis_memblock * obj ;
2005-04-17 02:20:36 +04:00
2006-08-07 16:03:22 +04:00
mutex_lock ( & dev - > struct_mutex ) ;
2011-10-25 20:00:41 +04:00
obj = idr_find ( & dev_priv - > object_idr , mem - > free ) ;
if ( obj = = NULL ) {
mutex_unlock ( & dev - > struct_mutex ) ;
return - EINVAL ;
}
idr_remove ( & dev_priv - > object_idr , mem - > free ) ;
2011-10-27 00:22:59 +04:00
list_del ( & obj - > owner_list ) ;
if ( drm_mm_node_allocated ( & obj - > mm_node ) )
drm_mm_remove_node ( & obj - > mm_node ) ;
# if defined(CONFIG_FB_SIS) || defined(CONFIG_FB_SIS_MODULE)
else
sis_free ( obj - > req . offset ) ;
# endif
kfree ( obj ) ;
2006-08-07 16:03:22 +04:00
mutex_unlock ( & dev - > struct_mutex ) ;
2007-09-03 06:06:45 +04:00
DRM_DEBUG ( " free = 0x%lx \n " , mem - > free ) ;
2005-04-17 02:20:36 +04:00
2012-01-09 01:42:27 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-09-03 06:06:45 +04:00
static int sis_fb_alloc ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2006-08-07 16:03:22 +04:00
{
2007-08-25 14:23:09 +04:00
return sis_drm_alloc ( dev , file_priv , data , VIDEO_TYPE ) ;
2006-08-07 16:03:22 +04:00
}
2005-04-17 02:20:36 +04:00
2007-09-03 06:06:45 +04:00
static int sis_ioctl_agp_init ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2005-04-17 02:20:36 +04:00
{
drm_sis_private_t * dev_priv = dev - > dev_private ;
2007-09-03 06:06:45 +04:00
drm_sis_agp_t * agp = data ;
2006-08-07 16:03:22 +04:00
dev_priv = dev - > dev_private ;
2005-04-17 02:20:36 +04:00
2006-08-07 16:03:22 +04:00
mutex_lock ( & dev - > struct_mutex ) ;
2011-10-27 00:22:59 +04:00
drm_mm_init ( & dev_priv - > agp_mm , 0 , agp - > size > > SIS_MM_ALIGN_SHIFT ) ;
2005-04-17 02:20:36 +04:00
2006-08-14 05:35:15 +04:00
dev_priv - > agp_initialized = 1 ;
2007-09-03 06:06:45 +04:00
dev_priv - > agp_offset = agp - > offset ;
2006-08-07 16:03:22 +04:00
mutex_unlock ( & dev - > struct_mutex ) ;
2005-04-17 02:20:36 +04:00
2012-06-24 21:57:24 +04:00
DRM_DEBUG ( " offset = %lu, size = %lu \n " , agp - > offset , agp - > size ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-09-03 06:06:45 +04:00
static int sis_ioctl_agp_alloc ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2005-04-17 02:20:36 +04:00
{
2007-08-25 14:23:09 +04:00
return sis_drm_alloc ( dev , file_priv , data , AGP_TYPE ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-11 09:53:27 +04:00
static drm_local_map_t * sis_reg_init ( struct drm_device * dev )
2006-08-08 15:34:46 +04:00
{
2007-07-11 10:53:40 +04:00
struct drm_map_list * entry ;
2006-08-08 15:34:46 +04:00
drm_local_map_t * map ;
2007-05-25 23:01:51 +04:00
list_for_each_entry ( entry , & dev - > maplist , head ) {
2006-08-08 15:34:46 +04:00
map = entry - > map ;
if ( ! map )
continue ;
2010-07-09 18:47:28 +04:00
if ( map - > type = = _DRM_REGISTERS )
2006-08-08 15:34:46 +04:00
return map ;
}
return NULL ;
}
2007-07-11 09:53:27 +04:00
int sis_idle ( struct drm_device * dev )
2006-08-08 15:34:46 +04:00
{
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 ;
}
}
2007-11-05 05:50:58 +03:00
2006-08-08 15:34:46 +04:00
/*
* 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 .
*/
2013-12-11 14:34:41 +04:00
end = jiffies + ( HZ * 3 ) ;
2006-08-08 15:34:46 +04:00
2010-07-09 18:47:28 +04:00
for ( i = 0 ; i < 4 ; + + i ) {
2006-08-08 15:34:46 +04:00
do {
idle_reg = SIS_READ ( 0x85cc ) ;
2010-07-09 18:47:28 +04:00
} while ( ! time_after_eq ( jiffies , end ) & &
2006-08-08 15:34:46 +04:00
( ( idle_reg & 0x80000000 ) ! = 0x80000000 ) ) ;
}
if ( time_after_eq ( jiffies , end ) ) {
DRM_ERROR ( " Graphics engine idle timeout. "
" Disabling idle check \n " ) ;
2006-08-14 05:35:15 +04:00
dev_priv - > idle_fault = 1 ;
2006-08-08 15:34:46 +04:00
}
/*
* The caller never sees an error code . It gets trapped
* in libdrm .
*/
return 0 ;
}
2006-08-07 16:03:22 +04:00
void sis_lastclose ( struct drm_device * dev )
2005-04-17 02:20:36 +04:00
{
drm_sis_private_t * dev_priv = dev - > dev_private ;
2006-08-07 16:03:22 +04:00
if ( ! dev_priv )
return ;
2005-04-17 02:20:36 +04:00
2006-08-07 16:03:22 +04:00
mutex_lock ( & dev - > struct_mutex ) ;
2011-10-27 00:22:59 +04:00
if ( dev_priv - > vram_initialized ) {
drm_mm_takedown ( & dev_priv - > vram_mm ) ;
dev_priv - > vram_initialized = 0 ;
}
if ( dev_priv - > agp_initialized ) {
drm_mm_takedown ( & dev_priv - > agp_mm ) ;
dev_priv - > agp_initialized = 0 ;
}
2006-08-08 15:34:46 +04:00
dev_priv - > mmio = NULL ;
2006-08-07 16:03:22 +04:00
mutex_unlock ( & dev - > struct_mutex ) ;
2005-04-17 02:20:36 +04:00
}
2010-07-09 18:47:28 +04:00
void sis_reclaim_buffers_locked ( struct drm_device * dev ,
2011-10-25 18:32:34 +04:00
struct drm_file * file )
2005-04-17 02:20:36 +04:00
{
2011-10-25 18:32:34 +04:00
struct sis_file_private * file_priv = file - > driver_priv ;
2011-10-27 00:22:59 +04:00
struct sis_memblock * entry , * next ;
2005-04-17 02:20:36 +04:00
2011-10-26 01:42:59 +04:00
if ( ! ( file - > minor - > master & & file - > master - > lock . hw_lock ) )
return ;
2014-08-29 14:12:46 +04:00
drm_legacy_idlelock_take ( & file - > master - > lock ) ;
2011-10-26 01:42:59 +04:00
2006-08-07 16:03:22 +04:00
mutex_lock ( & dev - > struct_mutex ) ;
2011-10-25 18:32:34 +04:00
if ( list_empty ( & file_priv - > obj_list ) ) {
2006-08-07 16:03:22 +04:00
mutex_unlock ( & dev - > struct_mutex ) ;
2014-08-29 14:12:46 +04:00
drm_legacy_idlelock_release ( & file - > master - > lock ) ;
2011-10-26 01:42:59 +04:00
2006-08-07 16:03:22 +04:00
return ;
2005-04-17 02:20:36 +04:00
}
2011-10-26 01:42:59 +04:00
sis_idle ( dev ) ;
2005-09-25 08:28:13 +04:00
2011-10-25 18:32:34 +04:00
list_for_each_entry_safe ( entry , next , & file_priv - > obj_list ,
owner_list ) {
2011-10-27 00:22:59 +04:00
list_del ( & entry - > owner_list ) ;
if ( drm_mm_node_allocated ( & entry - > mm_node ) )
drm_mm_remove_node ( & entry - > mm_node ) ;
# if defined(CONFIG_FB_SIS) || defined(CONFIG_FB_SIS_MODULE)
else
sis_free ( entry - > req . offset ) ;
# endif
kfree ( entry ) ;
2011-10-25 18:32:34 +04:00
}
2006-08-07 16:03:22 +04:00
mutex_unlock ( & dev - > struct_mutex ) ;
2011-10-26 01:42:59 +04:00
2014-08-29 14:12:46 +04:00
drm_legacy_idlelock_release ( & file - > master - > lock ) ;
2011-10-26 01:42:59 +04:00
2006-08-07 16:03:22 +04:00
return ;
2005-04-17 02:20:36 +04:00
}
2013-08-02 21:27:49 +04:00
const struct drm_ioctl_desc sis_ioctls [ ] = {
2010-08-14 14:20:34 +04:00
DRM_IOCTL_DEF_DRV ( SIS_FB_ALLOC , sis_fb_alloc , DRM_AUTH ) ,
DRM_IOCTL_DEF_DRV ( SIS_FB_FREE , sis_drm_free , DRM_AUTH ) ,
DRM_IOCTL_DEF_DRV ( SIS_AGP_INIT , sis_ioctl_agp_init , DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY ) ,
DRM_IOCTL_DEF_DRV ( SIS_AGP_ALLOC , sis_ioctl_agp_alloc , DRM_AUTH ) ,
DRM_IOCTL_DEF_DRV ( SIS_AGP_FREE , sis_drm_free , DRM_AUTH ) ,
DRM_IOCTL_DEF_DRV ( SIS_FB_INIT , sis_fb_init , DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY ) ,
2005-04-17 02:20:36 +04:00
} ;
2014-06-09 17:39:49 +04:00
int sis_max_ioctl = ARRAY_SIZE ( sis_ioctls ) ;