2009-12-10 03:19:58 +03:00
/**************************************************************************
*
* Copyright © 2009 VMware , Inc . , Palo Alto , CA . , USA
* 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 , 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 :
*
* 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 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 .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "vmwgfx_drv.h"
2012-10-02 21:01:07 +04:00
# include <drm/vmwgfx_drm.h>
2011-10-04 22:13:26 +04:00
# include "vmwgfx_kms.h"
2009-12-10 03:19:58 +03:00
int vmw_getparam_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
{
struct vmw_private * dev_priv = vmw_priv ( dev ) ;
struct drm_vmw_getparam_arg * param =
( struct drm_vmw_getparam_arg * ) data ;
switch ( param - > param ) {
case DRM_VMW_PARAM_NUM_STREAMS :
param - > value = vmw_overlay_num_overlays ( dev_priv ) ;
break ;
case DRM_VMW_PARAM_NUM_FREE_STREAMS :
param - > value = vmw_overlay_num_free_overlays ( dev_priv ) ;
break ;
case DRM_VMW_PARAM_3D :
2010-01-30 06:38:06 +03:00
param - > value = vmw_fifo_have_3d ( dev_priv ) ? 1 : 0 ;
2009-12-10 03:19:58 +03:00
break ;
2010-02-09 22:41:55 +03:00
case DRM_VMW_PARAM_HW_CAPS :
param - > value = dev_priv - > capabilities ;
break ;
case DRM_VMW_PARAM_FIFO_CAPS :
param - > value = dev_priv - > fifo . capabilities ;
break ;
2010-10-05 14:43:06 +04:00
case DRM_VMW_PARAM_MAX_FB_SIZE :
2012-11-21 13:32:36 +04:00
param - > value = dev_priv - > prim_bb_mem ;
2010-10-05 14:43:06 +04:00
break ;
2011-09-02 00:18:41 +04:00
case DRM_VMW_PARAM_FIFO_HW_VERSION :
{
__le32 __iomem * fifo_mem = dev_priv - > mmio_virt ;
2011-11-28 16:19:08 +04:00
const struct vmw_fifo_state * fifo = & dev_priv - > fifo ;
2011-09-02 00:18:41 +04:00
2011-11-28 16:19:08 +04:00
param - > value =
ioread32 ( fifo_mem +
( ( fifo - > capabilities &
SVGA_FIFO_CAP_3D_HWVERSION_REVISED ) ?
SVGA_FIFO_3D_HWVERSION_REVISED :
SVGA_FIFO_3D_HWVERSION ) ) ;
2011-09-02 00:18:41 +04:00
break ;
}
2009-12-10 03:19:58 +03:00
default :
DRM_ERROR ( " Illegal vmwgfx get param request: %d \n " ,
param - > param ) ;
return - EINVAL ;
}
return 0 ;
}
2011-09-02 00:18:41 +04:00
int vmw_get_cap_3d_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
{
struct drm_vmw_get_3d_cap_arg * arg =
( struct drm_vmw_get_3d_cap_arg * ) data ;
struct vmw_private * dev_priv = vmw_priv ( dev ) ;
uint32_t size ;
__le32 __iomem * fifo_mem ;
void __user * buffer = ( void __user * ) ( ( unsigned long ) ( arg - > buffer ) ) ;
void * bounce ;
int ret ;
if ( unlikely ( arg - > pad64 ! = 0 ) ) {
DRM_ERROR ( " Illegal GET_3D_CAP argument. \n " ) ;
return - EINVAL ;
}
size = ( SVGA_FIFO_3D_CAPS_LAST - SVGA_FIFO_3D_CAPS + 1 ) < < 2 ;
if ( arg - > max_size < size )
size = arg - > max_size ;
bounce = vmalloc ( size ) ;
if ( unlikely ( bounce = = NULL ) ) {
DRM_ERROR ( " Failed to allocate bounce buffer for 3D caps. \n " ) ;
return - ENOMEM ;
}
fifo_mem = dev_priv - > mmio_virt ;
memcpy_fromio ( bounce , & fifo_mem [ SVGA_FIFO_3D_CAPS ] , size ) ;
ret = copy_to_user ( buffer , bounce , size ) ;
2012-11-12 15:07:24 +04:00
if ( ret )
ret = - EFAULT ;
2011-09-02 00:18:41 +04:00
vfree ( bounce ) ;
if ( unlikely ( ret ! = 0 ) )
DRM_ERROR ( " Failed to report 3D caps info. \n " ) ;
return ret ;
}
2011-10-04 22:13:26 +04:00
int vmw_present_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
{
struct ttm_object_file * tfile = vmw_fpriv ( file_priv ) - > tfile ;
struct vmw_private * dev_priv = vmw_priv ( dev ) ;
struct drm_vmw_present_arg * arg =
( struct drm_vmw_present_arg * ) data ;
struct vmw_surface * surface ;
struct vmw_master * vmaster = vmw_master ( file_priv - > master ) ;
struct drm_vmw_rect __user * clips_ptr ;
struct drm_vmw_rect * clips = NULL ;
2012-12-03 00:53:40 +04:00
struct drm_framebuffer * fb ;
2011-10-04 22:13:26 +04:00
struct vmw_framebuffer * vfb ;
2012-11-20 16:19:35 +04:00
struct vmw_resource * res ;
2011-10-04 22:13:26 +04:00
uint32_t num_clips ;
int ret ;
num_clips = arg - > num_clips ;
clips_ptr = ( struct drm_vmw_rect * ) ( unsigned long ) arg - > clips_ptr ;
if ( unlikely ( num_clips = = 0 ) )
return 0 ;
if ( clips_ptr = = NULL ) {
DRM_ERROR ( " Variable clips_ptr must be specified. \n " ) ;
ret = - EINVAL ;
goto out_clips ;
}
2011-11-30 01:08:00 +04:00
clips = kcalloc ( num_clips , sizeof ( * clips ) , GFP_KERNEL ) ;
2011-10-04 22:13:26 +04:00
if ( clips = = NULL ) {
DRM_ERROR ( " Failed to allocate clip rect list. \n " ) ;
ret = - ENOMEM ;
goto out_clips ;
}
ret = copy_from_user ( clips , clips_ptr , num_clips * sizeof ( * clips ) ) ;
if ( ret ) {
DRM_ERROR ( " Failed to copy clip rects from userspace. \n " ) ;
2011-10-18 10:09:19 +04:00
ret = - EFAULT ;
2011-10-04 22:13:26 +04:00
goto out_no_copy ;
}
2012-12-02 04:48:38 +04:00
drm_modeset_lock_all ( dev ) ;
2011-10-04 22:13:26 +04:00
2012-12-03 00:53:40 +04:00
fb = drm_framebuffer_lookup ( dev , arg - > fb_id ) ;
if ( ! fb ) {
2011-10-04 22:13:26 +04:00
DRM_ERROR ( " Invalid framebuffer id. \n " ) ;
2013-10-17 14:35:06 +04:00
ret = - ENOENT ;
2011-10-04 22:13:26 +04:00
goto out_no_fb ;
}
2012-12-03 00:53:40 +04:00
vfb = vmw_framebuffer_to_vfb ( fb ) ;
2011-10-04 22:13:26 +04:00
ret = ttm_read_lock ( & vmaster - > lock , true ) ;
if ( unlikely ( ret ! = 0 ) )
goto out_no_ttm_lock ;
2012-11-20 16:19:35 +04:00
ret = vmw_user_resource_lookup_handle ( dev_priv , tfile , arg - > sid ,
user_surface_converter ,
& res ) ;
2011-10-04 22:13:26 +04:00
if ( ret )
goto out_no_surface ;
2012-11-20 16:19:35 +04:00
surface = vmw_res_to_srf ( res ) ;
2011-10-04 22:13:26 +04:00
ret = vmw_kms_present ( dev_priv , file_priv ,
vfb , surface , arg - > sid ,
arg - > dest_x , arg - > dest_y ,
clips , num_clips ) ;
/* vmw_user_surface_lookup takes one ref so does new_fb */
vmw_surface_unreference ( & surface ) ;
out_no_surface :
ttm_read_unlock ( & vmaster - > lock ) ;
out_no_ttm_lock :
2012-12-11 19:28:34 +04:00
drm_framebuffer_unreference ( fb ) ;
2011-10-04 22:13:26 +04:00
out_no_fb :
2012-12-02 04:48:38 +04:00
drm_modeset_unlock_all ( dev ) ;
2011-10-04 22:13:26 +04:00
out_no_copy :
kfree ( clips ) ;
out_clips :
return ret ;
}
int vmw_present_readback_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
{
struct vmw_private * dev_priv = vmw_priv ( dev ) ;
struct drm_vmw_present_readback_arg * arg =
( struct drm_vmw_present_readback_arg * ) data ;
struct drm_vmw_fence_rep __user * user_fence_rep =
( struct drm_vmw_fence_rep __user * )
( unsigned long ) arg - > fence_rep ;
struct vmw_master * vmaster = vmw_master ( file_priv - > master ) ;
struct drm_vmw_rect __user * clips_ptr ;
struct drm_vmw_rect * clips = NULL ;
2012-12-03 00:53:40 +04:00
struct drm_framebuffer * fb ;
2011-10-04 22:13:26 +04:00
struct vmw_framebuffer * vfb ;
uint32_t num_clips ;
int ret ;
num_clips = arg - > num_clips ;
clips_ptr = ( struct drm_vmw_rect * ) ( unsigned long ) arg - > clips_ptr ;
if ( unlikely ( num_clips = = 0 ) )
return 0 ;
if ( clips_ptr = = NULL ) {
DRM_ERROR ( " Argument clips_ptr must be specified. \n " ) ;
ret = - EINVAL ;
goto out_clips ;
}
2011-11-30 01:08:00 +04:00
clips = kcalloc ( num_clips , sizeof ( * clips ) , GFP_KERNEL ) ;
2011-10-04 22:13:26 +04:00
if ( clips = = NULL ) {
DRM_ERROR ( " Failed to allocate clip rect list. \n " ) ;
ret = - ENOMEM ;
goto out_clips ;
}
ret = copy_from_user ( clips , clips_ptr , num_clips * sizeof ( * clips ) ) ;
if ( ret ) {
DRM_ERROR ( " Failed to copy clip rects from userspace. \n " ) ;
2011-10-18 10:09:19 +04:00
ret = - EFAULT ;
2011-10-04 22:13:26 +04:00
goto out_no_copy ;
}
2012-12-02 04:48:38 +04:00
drm_modeset_lock_all ( dev ) ;
2011-10-04 22:13:26 +04:00
2012-12-03 00:53:40 +04:00
fb = drm_framebuffer_lookup ( dev , arg - > fb_id ) ;
if ( ! fb ) {
2011-10-04 22:13:26 +04:00
DRM_ERROR ( " Invalid framebuffer id. \n " ) ;
2013-10-17 14:35:06 +04:00
ret = - ENOENT ;
2011-10-04 22:13:26 +04:00
goto out_no_fb ;
}
2012-12-03 00:53:40 +04:00
vfb = vmw_framebuffer_to_vfb ( fb ) ;
2011-10-04 22:13:26 +04:00
if ( ! vfb - > dmabuf ) {
DRM_ERROR ( " Framebuffer not dmabuf backed. \n " ) ;
ret = - EINVAL ;
2012-12-11 19:28:34 +04:00
goto out_no_ttm_lock ;
2011-10-04 22:13:26 +04:00
}
ret = ttm_read_lock ( & vmaster - > lock , true ) ;
if ( unlikely ( ret ! = 0 ) )
goto out_no_ttm_lock ;
ret = vmw_kms_readback ( dev_priv , file_priv ,
vfb , user_fence_rep ,
clips , num_clips ) ;
ttm_read_unlock ( & vmaster - > lock ) ;
out_no_ttm_lock :
2012-12-11 19:28:34 +04:00
drm_framebuffer_unreference ( fb ) ;
2011-10-04 22:13:26 +04:00
out_no_fb :
2012-12-02 04:48:38 +04:00
drm_modeset_unlock_all ( dev ) ;
2011-10-04 22:13:26 +04:00
out_no_copy :
kfree ( clips ) ;
out_clips :
return ret ;
}
2011-10-10 14:23:27 +04:00
/**
* vmw_fops_poll - wrapper around the drm_poll function
*
* @ filp : See the linux fops poll documentation .
* @ wait : See the linux fops poll documentation .
*
* Wrapper around the drm_poll function that makes sure the device is
* processing the fifo if drm_poll decides to wait .
*/
unsigned int vmw_fops_poll ( struct file * filp , struct poll_table_struct * wait )
{
struct drm_file * file_priv = filp - > private_data ;
struct vmw_private * dev_priv =
vmw_priv ( file_priv - > minor - > dev ) ;
vmw_fifo_ping_host ( dev_priv , SVGA_SYNC_GENERIC ) ;
return drm_poll ( filp , wait ) ;
}
/**
* vmw_fops_read - wrapper around the drm_read function
*
* @ filp : See the linux fops read documentation .
* @ buffer : See the linux fops read documentation .
* @ count : See the linux fops read documentation .
* offset : See the linux fops read documentation .
*
* Wrapper around the drm_read function that makes sure the device is
* processing the fifo if drm_read decides to wait .
*/
ssize_t vmw_fops_read ( struct file * filp , char __user * buffer ,
size_t count , loff_t * offset )
{
struct drm_file * file_priv = filp - > private_data ;
struct vmw_private * dev_priv =
vmw_priv ( file_priv - > minor - > dev ) ;
vmw_fifo_ping_host ( dev_priv , SVGA_SYNC_GENERIC ) ;
return drm_read ( filp , buffer , count , offset ) ;
}