2009-06-05 14:42:42 +02:00
/*
* Copyright 2008 Advanced Micro Devices , Inc .
* Copyright 2008 Red Hat Inc .
* Copyright 2009 Jerome Glisse .
*
* 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 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
* THE COPYRIGHT HOLDER ( S ) OR AUTHOR ( S ) 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 : Dave Airlie
* Alex Deucher
* Jerome Glisse
*/
# include "drmP.h"
# include "drm.h"
# include "radeon_drm.h"
# include "radeon.h"
int radeon_gem_object_init ( struct drm_gem_object * obj )
{
/* we do nothings here */
return 0 ;
}
void radeon_gem_object_free ( struct drm_gem_object * gobj )
{
2009-11-20 14:29:23 +01:00
struct radeon_bo * robj = gobj - > driver_private ;
2009-06-05 14:42:42 +02:00
gobj - > driver_private = NULL ;
if ( robj ) {
2009-11-20 14:29:23 +01:00
radeon_bo_unref ( & robj ) ;
2009-06-05 14:42:42 +02:00
}
2010-04-09 19:05:05 +00:00
drm_gem_object_release ( gobj ) ;
kfree ( gobj ) ;
2009-06-05 14:42:42 +02:00
}
int radeon_gem_object_create ( struct radeon_device * rdev , int size ,
2009-11-20 14:29:23 +01:00
int alignment , int initial_domain ,
bool discardable , bool kernel ,
struct drm_gem_object * * obj )
2009-06-05 14:42:42 +02:00
{
struct drm_gem_object * gobj ;
2009-11-20 14:29:23 +01:00
struct radeon_bo * robj ;
2009-06-05 14:42:42 +02:00
int r ;
* obj = NULL ;
gobj = drm_gem_object_alloc ( rdev - > ddev , size ) ;
if ( ! gobj ) {
return - ENOMEM ;
}
/* At least align on page size */
if ( alignment < PAGE_SIZE ) {
alignment = PAGE_SIZE ;
}
2009-11-20 14:29:23 +01:00
r = radeon_bo_create ( rdev , gobj , size , kernel , initial_domain , & robj ) ;
2009-06-05 14:42:42 +02:00
if ( r ) {
2009-12-15 10:39:48 +10:00
if ( r ! = - ERESTARTSYS )
DRM_ERROR ( " Failed to allocate GEM object (%d, %d, %u, %d) \n " ,
size , initial_domain , alignment , r ) ;
2010-02-09 05:49:12 +00:00
drm_gem_object_unreference_unlocked ( gobj ) ;
2009-06-05 14:42:42 +02:00
return r ;
}
gobj - > driver_private = robj ;
* obj = gobj ;
return 0 ;
}
int radeon_gem_object_pin ( struct drm_gem_object * obj , uint32_t pin_domain ,
uint64_t * gpu_addr )
{
2009-11-20 14:29:23 +01:00
struct radeon_bo * robj = obj - > driver_private ;
int r ;
2009-06-05 14:42:42 +02:00
2009-11-20 14:29:23 +01:00
r = radeon_bo_reserve ( robj , false ) ;
if ( unlikely ( r ! = 0 ) )
return r ;
r = radeon_bo_pin ( robj , pin_domain , gpu_addr ) ;
radeon_bo_unreserve ( robj ) ;
return r ;
2009-06-05 14:42:42 +02:00
}
void radeon_gem_object_unpin ( struct drm_gem_object * obj )
{
2009-11-20 14:29:23 +01:00
struct radeon_bo * robj = obj - > driver_private ;
int r ;
r = radeon_bo_reserve ( robj , false ) ;
if ( likely ( r = = 0 ) ) {
radeon_bo_unpin ( robj ) ;
radeon_bo_unreserve ( robj ) ;
}
2009-06-05 14:42:42 +02:00
}
int radeon_gem_set_domain ( struct drm_gem_object * gobj ,
uint32_t rdomain , uint32_t wdomain )
{
2009-11-20 14:29:23 +01:00
struct radeon_bo * robj ;
2009-06-05 14:42:42 +02:00
uint32_t domain ;
int r ;
/* FIXME: reeimplement */
robj = gobj - > driver_private ;
/* work out where to validate the buffer to */
domain = wdomain ;
if ( ! domain ) {
domain = rdomain ;
}
if ( ! domain ) {
/* Do nothings */
printk ( KERN_WARNING " Set domain withou domain ! \n " ) ;
return 0 ;
}
if ( domain = = RADEON_GEM_DOMAIN_CPU ) {
/* Asking for cpu access wait for object idle */
2009-11-20 14:29:23 +01:00
r = radeon_bo_wait ( robj , NULL , false ) ;
2009-06-05 14:42:42 +02:00
if ( r ) {
printk ( KERN_ERR " Failed to wait for object ! \n " ) ;
return r ;
}
}
return 0 ;
}
int radeon_gem_init ( struct radeon_device * rdev )
{
INIT_LIST_HEAD ( & rdev - > gem . objects ) ;
return 0 ;
}
void radeon_gem_fini ( struct radeon_device * rdev )
{
2009-11-20 14:29:23 +01:00
radeon_bo_force_delete ( rdev ) ;
2009-06-05 14:42:42 +02:00
}
/*
* GEM ioctls .
*/
int radeon_gem_info_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * filp )
{
struct radeon_device * rdev = dev - > dev_private ;
struct drm_radeon_gem_info * args = data ;
2009-07-21 20:39:30 +10:00
args - > vram_size = rdev - > mc . real_vram_size ;
2009-08-05 00:19:51 +02:00
args - > vram_visible = rdev - > mc . real_vram_size ;
if ( rdev - > stollen_vga_memory )
2009-11-20 14:29:23 +01:00
args - > vram_visible - = radeon_bo_size ( rdev - > stollen_vga_memory ) ;
2010-03-30 05:34:13 +00:00
args - > vram_visible - = radeon_fbdev_total_size ( rdev ) ;
2009-08-05 00:19:51 +02:00
args - > gart_size = rdev - > mc . gtt_size - rdev - > cp . ring_size - 4096 -
RADEON_IB_POOL_SIZE * 64 * 1024 ;
2009-06-05 14:42:42 +02:00
return 0 ;
}
int radeon_gem_pread_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * filp )
{
/* TODO: implement */
DRM_ERROR ( " unimplemented %s \n " , __func__ ) ;
return - ENOSYS ;
}
int radeon_gem_pwrite_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * filp )
{
/* TODO: implement */
DRM_ERROR ( " unimplemented %s \n " , __func__ ) ;
return - ENOSYS ;
}
int radeon_gem_create_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * filp )
{
struct radeon_device * rdev = dev - > dev_private ;
struct drm_radeon_gem_create * args = data ;
struct drm_gem_object * gobj ;
uint32_t handle ;
int r ;
/* create a gem object to contain this object in */
args - > size = roundup ( args - > size , PAGE_SIZE ) ;
r = radeon_gem_object_create ( rdev , args - > size , args - > alignment ,
2009-11-20 14:29:23 +01:00
args - > initial_domain , false ,
false , & gobj ) ;
2009-06-05 14:42:42 +02:00
if ( r ) {
return r ;
}
r = drm_gem_handle_create ( filp , gobj , & handle ) ;
if ( r ) {
2010-02-09 05:49:12 +00:00
drm_gem_object_unreference_unlocked ( gobj ) ;
2009-06-05 14:42:42 +02:00
return r ;
}
2010-02-09 05:49:12 +00:00
drm_gem_object_handle_unreference_unlocked ( gobj ) ;
2009-06-05 14:42:42 +02:00
args - > handle = handle ;
return 0 ;
}
int radeon_gem_set_domain_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * filp )
{
/* transition the BO to a domain -
* just validate the BO into a certain domain */
struct drm_radeon_gem_set_domain * args = data ;
struct drm_gem_object * gobj ;
2009-11-20 14:29:23 +01:00
struct radeon_bo * robj ;
2009-06-05 14:42:42 +02:00
int r ;
/* for now if someone requests domain CPU -
* just make sure the buffer is finished with */
/* just do a BO wait for now */
gobj = drm_gem_object_lookup ( dev , filp , args - > handle ) ;
if ( gobj = = NULL ) {
2010-08-04 14:19:46 +01:00
return - ENOENT ;
2009-06-05 14:42:42 +02:00
}
robj = gobj - > driver_private ;
r = radeon_gem_set_domain ( gobj , args - > read_domains , args - > write_domain ) ;
2010-02-09 05:49:12 +00:00
drm_gem_object_unreference_unlocked ( gobj ) ;
2009-06-05 14:42:42 +02:00
return r ;
}
int radeon_gem_mmap_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * filp )
{
struct drm_radeon_gem_mmap * args = data ;
struct drm_gem_object * gobj ;
2009-11-20 14:29:23 +01:00
struct radeon_bo * robj ;
2009-06-05 14:42:42 +02:00
gobj = drm_gem_object_lookup ( dev , filp , args - > handle ) ;
if ( gobj = = NULL ) {
2010-08-04 14:19:46 +01:00
return - ENOENT ;
2009-06-05 14:42:42 +02:00
}
robj = gobj - > driver_private ;
2009-11-20 14:29:23 +01:00
args - > addr_ptr = radeon_bo_mmap_offset ( robj ) ;
2010-02-09 05:49:12 +00:00
drm_gem_object_unreference_unlocked ( gobj ) ;
2009-11-20 14:29:23 +01:00
return 0 ;
2009-06-05 14:42:42 +02:00
}
int radeon_gem_busy_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * filp )
{
2009-08-16 21:05:45 +10:00
struct drm_radeon_gem_busy * args = data ;
struct drm_gem_object * gobj ;
2009-11-20 14:29:23 +01:00
struct radeon_bo * robj ;
2009-08-16 21:05:45 +10:00
int r ;
2009-12-10 15:59:32 +10:00
uint32_t cur_placement = 0 ;
2009-08-16 21:05:45 +10:00
gobj = drm_gem_object_lookup ( dev , filp , args - > handle ) ;
if ( gobj = = NULL ) {
2010-08-04 14:19:46 +01:00
return - ENOENT ;
2009-08-16 21:05:45 +10:00
}
robj = gobj - > driver_private ;
2009-11-20 14:29:23 +01:00
r = radeon_bo_wait ( robj , & cur_placement , true ) ;
2009-08-22 17:38:23 +02:00
switch ( cur_placement ) {
case TTM_PL_VRAM :
2009-08-16 21:05:45 +10:00
args - > domain = RADEON_GEM_DOMAIN_VRAM ;
2009-08-22 17:38:23 +02:00
break ;
case TTM_PL_TT :
2009-08-16 21:05:45 +10:00
args - > domain = RADEON_GEM_DOMAIN_GTT ;
2009-08-22 17:38:23 +02:00
break ;
case TTM_PL_SYSTEM :
2009-08-16 21:05:45 +10:00
args - > domain = RADEON_GEM_DOMAIN_CPU ;
2009-08-22 17:38:23 +02:00
default :
break ;
}
2010-02-09 05:49:12 +00:00
drm_gem_object_unreference_unlocked ( gobj ) ;
2009-08-21 09:47:45 +10:00
return r ;
2009-06-05 14:42:42 +02:00
}
int radeon_gem_wait_idle_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * filp )
{
struct drm_radeon_gem_wait_idle * args = data ;
struct drm_gem_object * gobj ;
2009-11-20 14:29:23 +01:00
struct radeon_bo * robj ;
2009-06-05 14:42:42 +02:00
int r ;
gobj = drm_gem_object_lookup ( dev , filp , args - > handle ) ;
if ( gobj = = NULL ) {
2010-08-04 14:19:46 +01:00
return - ENOENT ;
2009-06-05 14:42:42 +02:00
}
robj = gobj - > driver_private ;
2009-11-20 14:29:23 +01:00
r = radeon_bo_wait ( robj , NULL , false ) ;
2010-02-04 20:36:39 +01:00
/* callback hw specific functions if any */
if ( robj - > rdev - > asic - > ioctl_wait_idle )
robj - > rdev - > asic - > ioctl_wait_idle ( robj - > rdev , robj ) ;
2010-02-09 05:49:12 +00:00
drm_gem_object_unreference_unlocked ( gobj ) ;
2009-06-05 14:42:42 +02:00
return r ;
}
2009-06-24 09:48:08 +10:00
int radeon_gem_set_tiling_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * filp )
{
struct drm_radeon_gem_set_tiling * args = data ;
struct drm_gem_object * gobj ;
2009-11-20 14:29:23 +01:00
struct radeon_bo * robj ;
2009-06-24 09:48:08 +10:00
int r = 0 ;
DRM_DEBUG ( " %d \n " , args - > handle ) ;
gobj = drm_gem_object_lookup ( dev , filp , args - > handle ) ;
if ( gobj = = NULL )
2010-08-04 14:19:46 +01:00
return - ENOENT ;
2009-06-24 09:48:08 +10:00
robj = gobj - > driver_private ;
2009-11-20 14:29:23 +01:00
r = radeon_bo_set_tiling_flags ( robj , args - > tiling_flags , args - > pitch ) ;
2010-02-09 05:49:12 +00:00
drm_gem_object_unreference_unlocked ( gobj ) ;
2009-06-24 09:48:08 +10:00
return r ;
}
int radeon_gem_get_tiling_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * filp )
{
struct drm_radeon_gem_get_tiling * args = data ;
struct drm_gem_object * gobj ;
2009-11-20 14:29:23 +01:00
struct radeon_bo * rbo ;
2009-06-24 09:48:08 +10:00
int r = 0 ;
DRM_DEBUG ( " \n " ) ;
gobj = drm_gem_object_lookup ( dev , filp , args - > handle ) ;
if ( gobj = = NULL )
2010-08-04 14:19:46 +01:00
return - ENOENT ;
2009-11-20 14:29:23 +01:00
rbo = gobj - > driver_private ;
r = radeon_bo_reserve ( rbo , false ) ;
if ( unlikely ( r ! = 0 ) )
2009-12-16 13:10:43 +10:00
goto out ;
2009-11-20 14:29:23 +01:00
radeon_bo_get_tiling_flags ( rbo , & args - > tiling_flags , & args - > pitch ) ;
radeon_bo_unreserve ( rbo ) ;
2009-12-16 13:10:43 +10:00
out :
2010-02-09 05:49:12 +00:00
drm_gem_object_unreference_unlocked ( gobj ) ;
2009-06-24 09:48:08 +10:00
return r ;
}