2005-04-16 15:20:36 -07:00
/**
2005-09-25 14:28:13 +10:00
* \ file drm_ioctl . c
2005-04-16 15:20:36 -07:00
* IOCTL processing for DRM
*
* \ author Rickard E . ( Rik ) Faith < faith @ valinux . com >
* \ author Gareth Hughes < gareth @ valinux . com >
*/
/*
* Created : Fri Jan 8 09 : 01 : 26 1999 by faith @ 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 .
*/
2012-10-02 18:01:07 +01:00
# include <drm/drmP.h>
# include <drm/drm_core.h>
2005-04-16 15:20:36 -07:00
2012-10-02 18:01:07 +01:00
# include <linux/pci.h>
# include <linux/export.h>
2013-05-13 23:58:48 +00:00
# ifdef CONFIG_X86
# include <asm/mtrr.h>
# endif
2005-04-16 15:20:36 -07:00
/**
* Get the bus id .
2005-09-25 14:28:13 +10:00
*
2005-04-16 15:20:36 -07:00
* \ param inode device inode .
2007-08-25 20:23:09 +10:00
* \ param file_priv DRM file private .
2005-04-16 15:20:36 -07:00
* \ param cmd command .
* \ param arg user argument , pointing to a drm_unique structure .
* \ return zero on success or a negative number on failure .
*
* Copies the bus id from drm_device : : unique into user space .
*/
2007-09-03 12:06:45 +10:00
int drm_getunique ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2005-04-16 15:20:36 -07:00
{
2007-09-03 12:06:45 +10:00
struct drm_unique * u = data ;
2008-11-28 14:22:24 +10:00
struct drm_master * master = file_priv - > master ;
2005-04-16 15:20:36 -07:00
2008-11-28 14:22:24 +10:00
if ( u - > unique_len > = master - > unique_len ) {
if ( copy_to_user ( u - > unique , master - > unique , master - > unique_len ) )
2005-04-16 15:20:36 -07:00
return - EFAULT ;
}
2008-11-28 14:22:24 +10:00
u - > unique_len = master - > unique_len ;
2007-09-03 12:06:45 +10:00
2005-04-16 15:20:36 -07:00
return 0 ;
}
2010-08-04 11:09:42 +01:00
static void
drm_unset_busid ( struct drm_device * dev ,
struct drm_master * master )
{
kfree ( dev - > devname ) ;
dev - > devname = NULL ;
kfree ( master - > unique ) ;
master - > unique = NULL ;
master - > unique_len = 0 ;
master - > unique_size = 0 ;
}
2005-04-16 15:20:36 -07:00
/**
* Set the bus id .
2005-09-25 14:28:13 +10:00
*
2005-04-16 15:20:36 -07:00
* \ param inode device inode .
2007-08-25 20:23:09 +10:00
* \ param file_priv DRM file private .
2005-04-16 15:20:36 -07:00
* \ param cmd command .
* \ param arg user argument , pointing to a drm_unique structure .
* \ return zero on success or a negative number on failure .
*
* Copies the bus id from userspace into drm_device : : unique , and verifies that
* it matches the device this DRM is attached to ( EINVAL otherwise ) . Deprecated
* in interface version 1.1 and will return EBUSY when setversion has requested
* version 1.1 or greater .
*/
2007-09-03 12:06:45 +10:00
int drm_setunique ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2005-04-16 15:20:36 -07:00
{
2007-09-03 12:06:45 +10:00
struct drm_unique * u = data ;
2008-11-28 14:22:24 +10:00
struct drm_master * master = file_priv - > master ;
2010-12-15 03:16:38 +10:00
int ret ;
2005-04-16 15:20:36 -07:00
2008-11-28 14:22:24 +10:00
if ( master - > unique_len | | master - > unique )
2005-09-25 14:28:13 +10:00
return - EBUSY ;
2005-04-16 15:20:36 -07:00
2007-09-03 12:06:45 +10:00
if ( ! u - > unique_len | | u - > unique_len > 1024 )
2005-09-25 14:28:13 +10:00
return - EINVAL ;
2005-04-16 15:20:36 -07:00
2010-12-15 03:16:38 +10:00
if ( ! dev - > driver - > bus - > set_unique )
return - EINVAL ;
2005-09-25 14:28:13 +10:00
2010-12-15 03:16:38 +10:00
ret = dev - > driver - > bus - > set_unique ( dev , master , u ) ;
if ( ret )
2010-08-04 11:09:42 +01:00
goto err ;
2005-04-16 15:20:36 -07:00
return 0 ;
2010-08-04 11:09:42 +01:00
err :
drm_unset_busid ( dev , master ) ;
return ret ;
2005-04-16 15:20:36 -07:00
}
2008-11-28 14:22:24 +10:00
static int drm_set_busid ( struct drm_device * dev , struct drm_file * file_priv )
2005-04-16 15:20:36 -07:00
{
2008-11-28 14:22:24 +10:00
struct drm_master * master = file_priv - > master ;
2010-12-15 03:16:38 +10:00
int ret ;
2010-08-04 11:09:42 +01:00
if ( master - > unique ! = NULL )
drm_unset_busid ( dev , master ) ;
2006-01-02 21:19:39 +11:00
2010-12-15 03:16:38 +10:00
ret = dev - > driver - > bus - > set_busid ( dev , master ) ;
if ( ret )
goto err ;
2005-04-16 15:20:36 -07:00
return 0 ;
2010-08-04 11:09:42 +01:00
err :
drm_unset_busid ( dev , master ) ;
return ret ;
2005-04-16 15:20:36 -07:00
}
/**
* Get a mapping information .
*
* \ param inode device inode .
2007-08-25 20:23:09 +10:00
* \ param file_priv DRM file private .
2005-04-16 15:20:36 -07:00
* \ param cmd command .
* \ param arg user argument , pointing to a drm_map structure .
2005-09-25 14:28:13 +10:00
*
2005-04-16 15:20:36 -07:00
* \ return zero on success or a negative number on failure .
*
* Searches for the mapping with the specified offset and copies its information
* into userspace
*/
2007-09-03 12:06:45 +10:00
int drm_getmap ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2005-04-16 15:20:36 -07:00
{
2007-09-03 12:06:45 +10:00
struct drm_map * map = data ;
2007-07-11 16:53:40 +10:00
struct drm_map_list * r_list = NULL ;
2005-04-16 15:20:36 -07:00
struct list_head * list ;
2005-09-25 14:28:13 +10:00
int idx ;
int i ;
2005-04-16 15:20:36 -07:00
2007-09-03 12:06:45 +10:00
idx = map - > offset ;
drm: make DRM_UNLOCKED ioctls with their own mutex
drm_getclient, drm_getstats and drm_getmap (with a few minor
adjustments) do not need global mutex, so fix that and
make the said ioctls DRM_UNLOCKED. Details:
drm_getclient: the only thing that should be protected here
is dev->filelist and that is already protected everywhere with
dev->struct_mutex.
drm_getstats: there is no need for any mutex here because the
loop runs through quasi-static (set at load time only)
data, and the actual count access is done with atomic_read()
drm_getmap already uses dev->struct_mutex to protect
dev->maplist, which also used to protect the same structure
everywhere else except at three places:
* drm_getsarea, which doesn't grab *any* mutex before
touching dev->maplist (so no drm_global_mutex doesn't help
here either; different issue for a different patch).
However, drivers seem to call it only at
initialization time so it probably doesn't matter
* drm_master_destroy, which is called from drm_master_put,
which in turn is protected with dev->struct_mutex
everywhere else in drm module, so we are good here too.
* drm_getsareactx, which releases the dev->struct_mutex
too early, but this patch includes the fix for that.
v2: * incorporate comments received from Daniel Vetter
* include the (long) explanation above to make it clear what
we are doing (and why), also at Daniel Vetter's request
* tighten up mutex grab/release locations to only
encompass real critical sections, rather than some
random code around them
Signed-off-by: Ilija Hadzic <ihadzic@research.bell-labs.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2011-10-28 17:43:28 -04:00
if ( idx < 0 )
2005-04-16 15:20:36 -07:00
return - EINVAL ;
i = 0 ;
drm: make DRM_UNLOCKED ioctls with their own mutex
drm_getclient, drm_getstats and drm_getmap (with a few minor
adjustments) do not need global mutex, so fix that and
make the said ioctls DRM_UNLOCKED. Details:
drm_getclient: the only thing that should be protected here
is dev->filelist and that is already protected everywhere with
dev->struct_mutex.
drm_getstats: there is no need for any mutex here because the
loop runs through quasi-static (set at load time only)
data, and the actual count access is done with atomic_read()
drm_getmap already uses dev->struct_mutex to protect
dev->maplist, which also used to protect the same structure
everywhere else except at three places:
* drm_getsarea, which doesn't grab *any* mutex before
touching dev->maplist (so no drm_global_mutex doesn't help
here either; different issue for a different patch).
However, drivers seem to call it only at
initialization time so it probably doesn't matter
* drm_master_destroy, which is called from drm_master_put,
which in turn is protected with dev->struct_mutex
everywhere else in drm module, so we are good here too.
* drm_getsareactx, which releases the dev->struct_mutex
too early, but this patch includes the fix for that.
v2: * incorporate comments received from Daniel Vetter
* include the (long) explanation above to make it clear what
we are doing (and why), also at Daniel Vetter's request
* tighten up mutex grab/release locations to only
encompass real critical sections, rather than some
random code around them
Signed-off-by: Ilija Hadzic <ihadzic@research.bell-labs.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2011-10-28 17:43:28 -04:00
mutex_lock ( & dev - > struct_mutex ) ;
2007-05-26 05:01:51 +10:00
list_for_each ( list , & dev - > maplist ) {
2005-09-25 14:28:13 +10:00
if ( i = = idx ) {
2007-07-11 16:53:40 +10:00
r_list = list_entry ( list , struct drm_map_list , head ) ;
2005-04-16 15:20:36 -07:00
break ;
}
i + + ;
}
2005-09-25 14:28:13 +10:00
if ( ! r_list | | ! r_list - > map ) {
2006-02-02 19:37:46 +11:00
mutex_unlock ( & dev - > struct_mutex ) ;
2005-04-16 15:20:36 -07:00
return - EINVAL ;
}
2007-09-03 12:06:45 +10:00
map - > offset = r_list - > map - > offset ;
map - > size = r_list - > map - > size ;
map - > type = r_list - > map - > type ;
map - > flags = r_list - > map - > flags ;
map - > handle = ( void * ) ( unsigned long ) r_list - > user_token ;
2013-05-13 23:58:48 +00:00
# ifdef CONFIG_X86
/*
* There appears to be exactly one user of the mtrr index : dritest .
* It ' s easy enough to keep it working on non - PAT systems .
*/
map - > mtrr = phys_wc_to_mtrr_index ( r_list - > map - > mtrr ) ;
# else
map - > mtrr = - 1 ;
# endif
2006-02-02 19:37:46 +11:00
mutex_unlock ( & dev - > struct_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
/**
* Get client information .
*
* \ param inode device inode .
2007-08-25 20:23:09 +10:00
* \ param file_priv DRM file private .
2005-04-16 15:20:36 -07:00
* \ param cmd command .
* \ param arg user argument , pointing to a drm_client structure .
2005-09-25 14:28:13 +10:00
*
2005-04-16 15:20:36 -07:00
* \ return zero on success or a negative number on failure .
*
* Searches for the client with the specified index and copies its information
* into userspace
*/
2007-09-03 12:06:45 +10:00
int drm_getclient ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2005-04-16 15:20:36 -07:00
{
2007-09-03 12:06:45 +10:00
struct drm_client * client = data ;
drm: make DRM_UNLOCKED ioctls with their own mutex
drm_getclient, drm_getstats and drm_getmap (with a few minor
adjustments) do not need global mutex, so fix that and
make the said ioctls DRM_UNLOCKED. Details:
drm_getclient: the only thing that should be protected here
is dev->filelist and that is already protected everywhere with
dev->struct_mutex.
drm_getstats: there is no need for any mutex here because the
loop runs through quasi-static (set at load time only)
data, and the actual count access is done with atomic_read()
drm_getmap already uses dev->struct_mutex to protect
dev->maplist, which also used to protect the same structure
everywhere else except at three places:
* drm_getsarea, which doesn't grab *any* mutex before
touching dev->maplist (so no drm_global_mutex doesn't help
here either; different issue for a different patch).
However, drivers seem to call it only at
initialization time so it probably doesn't matter
* drm_master_destroy, which is called from drm_master_put,
which in turn is protected with dev->struct_mutex
everywhere else in drm module, so we are good here too.
* drm_getsareactx, which releases the dev->struct_mutex
too early, but this patch includes the fix for that.
v2: * incorporate comments received from Daniel Vetter
* include the (long) explanation above to make it clear what
we are doing (and why), also at Daniel Vetter's request
* tighten up mutex grab/release locations to only
encompass real critical sections, rather than some
random code around them
Signed-off-by: Ilija Hadzic <ihadzic@research.bell-labs.com>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Dave Airlie <airlied@redhat.com>
2011-10-28 17:43:28 -04:00
2013-08-08 15:41:31 +02:00
/*
* Hollowed - out getclient ioctl to keep some dead old drm tests / tools
* not breaking completely . Userspace tools stop enumerating one they
* get - EINVAL , hence this is the return value we need to hand back for
* no clients tracked .
*
* Unfortunately some clients ( * cough * libva * cough * ) use this in a fun
* attempt to figure out whether they ' re authenticated or not . Since
* that ' s the only thing they care about , give it to the directly
* instead of walking one giant list .
*/
if ( client - > idx = = 0 ) {
client - > auth = file_priv - > authenticated ;
client - > pid = pid_vnr ( file_priv - > pid ) ;
client - > uid = from_kuid_munged ( current_user_ns ( ) ,
file_priv - > uid ) ;
client - > magic = 0 ;
client - > iocs = 0 ;
return 0 ;
} else {
return - EINVAL ;
2007-05-26 05:01:51 +10:00
}
2005-04-16 15:20:36 -07:00
}
2005-09-25 14:28:13 +10:00
/**
* Get statistics information .
*
2005-04-16 15:20:36 -07:00
* \ param inode device inode .
2007-08-25 20:23:09 +10:00
* \ param file_priv DRM file private .
2005-04-16 15:20:36 -07:00
* \ param cmd command .
* \ param arg user argument , pointing to a drm_stats structure .
2005-09-25 14:28:13 +10:00
*
2005-04-16 15:20:36 -07:00
* \ return zero on success or a negative number on failure .
*/
2007-09-03 12:06:45 +10:00
int drm_getstats ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2005-04-16 15:20:36 -07:00
{
2007-09-03 12:06:45 +10:00
struct drm_stats * stats = data ;
2005-04-16 15:20:36 -07:00
2013-08-08 15:41:32 +02:00
/* Clear stats to prevent userspace from eating its stack garbage. */
2007-11-05 12:53:09 +10:00
memset ( stats , 0 , sizeof ( * stats ) ) ;
2005-09-25 14:28:13 +10:00
2005-04-16 15:20:36 -07:00
return 0 ;
}
2011-02-21 11:17:35 +10:00
/**
* Get device / driver capabilities
*/
int drm_getcap ( struct drm_device * dev , void * data , struct drm_file * file_priv )
{
struct drm_get_cap * req = data ;
req - > value = 0 ;
2011-03-04 14:50:28 +10:00
switch ( req - > capability ) {
case DRM_CAP_DUMB_BUFFER :
if ( dev - > driver - > dumb_create )
req - > value = 1 ;
break ;
2011-03-24 20:54:35 +10:00
case DRM_CAP_VBLANK_HIGH_CRTC :
2011-03-18 16:58:04 -05:00
req - > value = 1 ;
break ;
2011-09-29 16:20:42 +01:00
case DRM_CAP_DUMB_PREFERRED_DEPTH :
req - > value = dev - > mode_config . preferred_depth ;
break ;
case DRM_CAP_DUMB_PREFER_SHADOW :
req - > value = dev - > mode_config . prefer_shadow ;
break ;
2012-04-02 14:11:50 +01:00
case DRM_CAP_PRIME :
req - > value | = dev - > driver - > prime_fd_to_handle ? DRM_PRIME_CAP_IMPORT : 0 ;
req - > value | = dev - > driver - > prime_handle_to_fd ? DRM_PRIME_CAP_EXPORT : 0 ;
break ;
2012-10-23 18:53:26 +00:00
case DRM_CAP_TIMESTAMP_MONOTONIC :
req - > value = drm_timestamp_monotonic ;
break ;
2013-07-22 18:50:00 -07:00
case DRM_CAP_ASYNC_PAGE_FLIP :
req - > value = dev - > mode_config . async_page_flip ;
break ;
2011-03-04 14:50:28 +10:00
default :
return - EINVAL ;
}
2011-02-21 11:17:35 +10:00
return 0 ;
}
2013-09-25 16:45:20 +01:00
/**
* Set device / driver capabilities
*/
int
drm_setclientcap ( struct drm_device * dev , void * data , struct drm_file * file_priv )
{
2013-09-25 16:45:22 +01:00
struct drm_set_client_cap * req = data ;
switch ( req - > capability ) {
case DRM_CLIENT_CAP_STEREO_3D :
if ( req - > value > 1 )
return - EINVAL ;
file_priv - > stereo_allowed = req - > value ;
break ;
default :
return - EINVAL ;
}
return 0 ;
2013-09-25 16:45:20 +01:00
}
2005-04-16 15:20:36 -07:00
/**
* Setversion ioctl .
*
* \ param inode device inode .
2007-08-25 20:23:09 +10:00
* \ param file_priv DRM file private .
2005-04-16 15:20:36 -07:00
* \ param cmd command .
* \ param arg user argument , pointing to a drm_lock structure .
* \ return zero on success or negative number on failure .
*
* Sets the requested interface version
*/
2007-09-03 12:06:45 +10:00
int drm_setversion ( struct drm_device * dev , void * data , struct drm_file * file_priv )
2005-04-16 15:20:36 -07:00
{
2007-09-03 12:06:45 +10:00
struct drm_set_version * sv = data ;
int if_version , retcode = 0 ;
if ( sv - > drm_di_major ! = - 1 ) {
if ( sv - > drm_di_major ! = DRM_IF_MAJOR | |
sv - > drm_di_minor < 0 | | sv - > drm_di_minor > DRM_IF_MINOR ) {
retcode = - EINVAL ;
goto done ;
}
if_version = DRM_IF_VERSION ( sv - > drm_di_major ,
sv - > drm_di_minor ) ;
2006-08-07 20:07:43 +10:00
dev - > if_version = max ( if_version , dev - > if_version ) ;
2007-09-03 12:06:45 +10:00
if ( sv - > drm_di_minor > = 1 ) {
2005-04-16 15:20:36 -07:00
/*
* Version 1.1 includes tying of DRM to specific device
2010-08-06 13:55:10 +10:00
* Version 1.4 has proper PCI domain support
2005-04-16 15:20:36 -07:00
*/
2010-08-04 11:09:42 +01:00
retcode = drm_set_busid ( dev , file_priv ) ;
if ( retcode )
goto done ;
2005-04-16 15:20:36 -07:00
}
}
2007-09-03 12:06:45 +10:00
if ( sv - > drm_dd_major ! = - 1 ) {
if ( sv - > drm_dd_major ! = dev - > driver - > major | |
sv - > drm_dd_minor < 0 | | sv - > drm_dd_minor >
dev - > driver - > minor ) {
retcode = - EINVAL ;
goto done ;
}
2005-04-16 15:20:36 -07:00
}
2007-09-03 12:06:45 +10:00
done :
sv - > drm_di_major = DRM_IF_MAJOR ;
sv - > drm_di_minor = DRM_IF_MINOR ;
sv - > drm_dd_major = dev - > driver - > major ;
sv - > drm_dd_minor = dev - > driver - > minor ;
return retcode ;
2005-04-16 15:20:36 -07:00
}
/** No-op ioctl. */
2007-09-03 12:06:45 +10:00
int drm_noop ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2005-04-16 15:20:36 -07:00
{
DRM_DEBUG ( " \n " ) ;
return 0 ;
}
2012-01-17 12:50:12 +01:00
EXPORT_SYMBOL ( drm_noop ) ;