2011-10-04 20:13:21 +02:00
/**************************************************************************
*
2015-07-29 12:38:02 -07:00
* Copyright © 2011 - 2015 VMware , Inc . , Palo Alto , CA . , USA
2011-10-04 20:13:21 +02:00
* 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 .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-10-02 18:01:07 +01:00
# include <drm/ttm/ttm_placement.h>
2011-10-04 20:13:21 +02:00
2012-10-02 18:01:07 +01:00
# include <drm/drmP.h>
2011-10-04 20:13:21 +02:00
# include "vmwgfx_drv.h"
/**
2015-06-26 00:25:37 -07:00
* vmw_dmabuf_pin_in_placement - Validate a buffer to placement .
2011-10-04 20:13:21 +02:00
*
2011-10-04 20:13:28 +02:00
* @ dev_priv : Driver private .
* @ buf : DMA buffer to move .
2015-06-26 00:25:37 -07:00
* @ placement : The placement to pin it .
2011-10-04 20:13:28 +02:00
* @ interruptible : Use interruptible wait .
*
2011-10-04 20:13:21 +02:00
* Returns
* - ERESTARTSYS if interrupted by a signal .
*/
2015-06-26 00:25:37 -07:00
int vmw_dmabuf_pin_in_placement ( struct vmw_private * dev_priv ,
struct vmw_dma_buffer * buf ,
struct ttm_placement * placement ,
bool interruptible )
2011-10-04 20:13:21 +02:00
{
struct ttm_buffer_object * bo = & buf - > base ;
int ret ;
2016-06-29 13:20:26 -07:00
uint32_t new_flags ;
2011-10-04 20:13:21 +02:00
2014-02-27 12:34:51 +01:00
ret = ttm_write_lock ( & dev_priv - > reservation_sem , interruptible ) ;
2011-10-04 20:13:21 +02:00
if ( unlikely ( ret ! = 0 ) )
return ret ;
2012-11-20 12:19:35 +00:00
vmw_execbuf_release_pinned_bo ( dev_priv ) ;
2011-10-04 20:13:30 +02:00
2016-04-06 11:12:03 +02:00
ret = ttm_bo_reserve ( bo , interruptible , false , NULL ) ;
2011-10-04 20:13:21 +02:00
if ( unlikely ( ret ! = 0 ) )
goto err ;
2016-06-29 13:20:26 -07:00
if ( buf - > pin_count > 0 )
ret = ttm_bo_mem_compat ( placement , & bo - > mem ,
& new_flags ) = = true ? 0 : - EINVAL ;
else
ret = ttm_bo_validate ( bo , placement , interruptible , false ) ;
2015-06-26 00:25:37 -07:00
if ( ! ret )
vmw_bo_pin_reserved ( buf , true ) ;
2011-10-04 20:13:21 +02:00
ttm_bo_unreserve ( bo ) ;
err :
2014-02-27 12:34:51 +01:00
ttm_write_unlock ( & dev_priv - > reservation_sem ) ;
2011-10-04 20:13:21 +02:00
return ret ;
}
/**
2015-06-26 00:25:37 -07:00
* vmw_dmabuf_pin_in_vram_or_gmr - Move a buffer to vram or gmr .
2011-10-04 20:13:21 +02:00
*
2015-06-26 00:25:37 -07:00
* This function takes the reservation_sem in write mode .
* Flushes and unpins the query bo to avoid failures .
2011-10-04 20:13:21 +02:00
*
* @ dev_priv : Driver private .
* @ buf : DMA buffer to move .
* @ pin : Pin buffer if true .
* @ interruptible : Use interruptible wait .
*
* Returns
* - ERESTARTSYS if interrupted by a signal .
*/
2015-06-26 00:25:37 -07:00
int vmw_dmabuf_pin_in_vram_or_gmr ( struct vmw_private * dev_priv ,
struct vmw_dma_buffer * buf ,
bool interruptible )
2011-10-04 20:13:21 +02:00
{
struct ttm_buffer_object * bo = & buf - > base ;
int ret ;
2016-06-29 13:20:26 -07:00
uint32_t new_flags ;
2011-10-04 20:13:21 +02:00
2014-02-27 12:34:51 +01:00
ret = ttm_write_lock ( & dev_priv - > reservation_sem , interruptible ) ;
2011-10-04 20:13:21 +02:00
if ( unlikely ( ret ! = 0 ) )
return ret ;
2015-06-26 00:25:37 -07:00
vmw_execbuf_release_pinned_bo ( dev_priv ) ;
2011-10-04 20:13:30 +02:00
2016-04-06 11:12:03 +02:00
ret = ttm_bo_reserve ( bo , interruptible , false , NULL ) ;
2011-10-04 20:13:21 +02:00
if ( unlikely ( ret ! = 0 ) )
goto err ;
2016-06-29 13:20:26 -07:00
if ( buf - > pin_count > 0 ) {
ret = ttm_bo_mem_compat ( & vmw_vram_gmr_placement , & bo - > mem ,
& new_flags ) = = true ? 0 : - EINVAL ;
goto out_unreserve ;
}
2015-06-26 00:25:37 -07:00
ret = ttm_bo_validate ( bo , & vmw_vram_gmr_placement , interruptible ,
false ) ;
2011-10-04 20:13:21 +02:00
if ( likely ( ret = = 0 ) | | ret = = - ERESTARTSYS )
2015-06-26 00:25:37 -07:00
goto out_unreserve ;
2011-10-04 20:13:21 +02:00
2015-06-26 00:25:37 -07:00
ret = ttm_bo_validate ( bo , & vmw_vram_placement , interruptible , false ) ;
2011-10-04 20:13:21 +02:00
2015-06-26 00:25:37 -07:00
out_unreserve :
if ( ! ret )
vmw_bo_pin_reserved ( buf , true ) ;
2011-10-04 20:13:21 +02:00
ttm_bo_unreserve ( bo ) ;
err :
2014-02-27 12:34:51 +01:00
ttm_write_unlock ( & dev_priv - > reservation_sem ) ;
2011-10-04 20:13:21 +02:00
return ret ;
}
/**
2015-06-26 00:25:37 -07:00
* vmw_dmabuf_pin_in_vram - Move a buffer to vram .
2011-10-04 20:13:21 +02:00
*
2015-06-26 00:25:37 -07:00
* This function takes the reservation_sem in write mode .
* Flushes and unpins the query bo to avoid failures .
2011-10-04 20:13:21 +02:00
*
* @ dev_priv : Driver private .
* @ buf : DMA buffer to move .
* @ interruptible : Use interruptible wait .
*
* Returns
* - ERESTARTSYS if interrupted by a signal .
*/
2015-06-26 00:25:37 -07:00
int vmw_dmabuf_pin_in_vram ( struct vmw_private * dev_priv ,
struct vmw_dma_buffer * buf ,
bool interruptible )
2011-10-04 20:13:21 +02:00
{
2015-06-26 00:25:37 -07:00
return vmw_dmabuf_pin_in_placement ( dev_priv , buf , & vmw_vram_placement ,
interruptible ) ;
2011-10-04 20:13:21 +02:00
}
/**
2015-06-26 00:25:37 -07:00
* vmw_dmabuf_pin_in_start_of_vram - Move a buffer to start of vram .
2011-10-04 20:13:21 +02:00
*
2015-06-26 00:25:37 -07:00
* This function takes the reservation_sem in write mode .
* Flushes and unpins the query bo to avoid failures .
2011-10-04 20:13:21 +02:00
*
* @ dev_priv : Driver private .
2015-06-26 00:25:37 -07:00
* @ buf : DMA buffer to pin .
2011-10-04 20:13:21 +02:00
* @ interruptible : Use interruptible wait .
*
* Returns
* - ERESTARTSYS if interrupted by a signal .
*/
2015-06-26 00:25:37 -07:00
int vmw_dmabuf_pin_in_start_of_vram ( struct vmw_private * dev_priv ,
struct vmw_dma_buffer * buf ,
bool interruptible )
2011-10-04 20:13:21 +02:00
{
struct ttm_buffer_object * bo = & buf - > base ;
struct ttm_placement placement ;
2014-08-27 13:16:04 +02:00
struct ttm_place place ;
2011-10-04 20:13:21 +02:00
int ret = 0 ;
2016-06-29 13:20:26 -07:00
uint32_t new_flags ;
2011-10-04 20:13:21 +02:00
2015-06-26 00:25:37 -07:00
place = vmw_vram_placement . placement [ 0 ] ;
2014-08-27 13:16:04 +02:00
place . lpfn = bo - > num_pages ;
placement . num_placement = 1 ;
placement . placement = & place ;
placement . num_busy_placement = 1 ;
placement . busy_placement = & place ;
2011-10-04 20:13:21 +02:00
2014-02-27 12:34:51 +01:00
ret = ttm_write_lock ( & dev_priv - > reservation_sem , interruptible ) ;
2011-10-04 20:13:21 +02:00
if ( unlikely ( ret ! = 0 ) )
return ret ;
2015-06-26 00:25:37 -07:00
vmw_execbuf_release_pinned_bo ( dev_priv ) ;
2016-04-06 11:12:03 +02:00
ret = ttm_bo_reserve ( bo , interruptible , false , NULL ) ;
2011-10-04 20:13:21 +02:00
if ( unlikely ( ret ! = 0 ) )
goto err_unlock ;
2015-06-26 00:25:37 -07:00
/*
* Is this buffer already in vram but not at the start of it ?
* In that case , evict it first because TTM isn ' t good at handling
* that situation .
*/
2011-10-04 20:13:21 +02:00
if ( bo - > mem . mem_type = = TTM_PL_VRAM & &
bo - > mem . start < bo - > num_pages & &
2016-06-29 13:20:26 -07:00
bo - > mem . start > 0 & &
buf - > pin_count = = 0 )
2012-11-28 11:25:44 +00:00
( void ) ttm_bo_validate ( bo , & vmw_sys_placement , false , false ) ;
2011-10-04 20:13:21 +02:00
2016-06-29 13:20:26 -07:00
if ( buf - > pin_count > 0 )
ret = ttm_bo_mem_compat ( & placement , & bo - > mem ,
& new_flags ) = = true ? 0 : - EINVAL ;
else
ret = ttm_bo_validate ( bo , & placement , interruptible , false ) ;
2011-10-04 20:13:21 +02:00
2015-06-26 00:25:37 -07:00
/* For some reason we didn't end up at the start of vram */
2011-10-04 20:13:21 +02:00
WARN_ON ( ret = = 0 & & bo - > offset ! = 0 ) ;
2015-06-26 00:25:37 -07:00
if ( ! ret )
vmw_bo_pin_reserved ( buf , true ) ;
2011-10-04 20:13:21 +02:00
ttm_bo_unreserve ( bo ) ;
err_unlock :
2014-02-27 12:34:51 +01:00
ttm_write_unlock ( & dev_priv - > reservation_sem ) ;
2011-10-04 20:13:21 +02:00
return ret ;
}
/**
2015-06-26 00:25:37 -07:00
* vmw_dmabuf_unpin - Unpin the buffer given buffer , does not move the buffer .
2011-10-04 20:13:21 +02:00
*
2015-06-26 00:25:37 -07:00
* This function takes the reservation_sem in write mode .
2011-10-04 20:13:21 +02:00
*
* @ dev_priv : Driver private .
* @ buf : DMA buffer to unpin .
* @ interruptible : Use interruptible wait .
*
* Returns
* - ERESTARTSYS if interrupted by a signal .
*/
int vmw_dmabuf_unpin ( struct vmw_private * dev_priv ,
struct vmw_dma_buffer * buf ,
bool interruptible )
{
2015-06-26 00:25:37 -07:00
struct ttm_buffer_object * bo = & buf - > base ;
int ret ;
2011-10-04 20:13:21 +02:00
2015-06-26 00:25:37 -07:00
ret = ttm_read_lock ( & dev_priv - > reservation_sem , interruptible ) ;
if ( unlikely ( ret ! = 0 ) )
return ret ;
2016-04-06 11:12:03 +02:00
ret = ttm_bo_reserve ( bo , interruptible , false , NULL ) ;
2015-06-26 00:25:37 -07:00
if ( unlikely ( ret ! = 0 ) )
goto err ;
vmw_bo_pin_reserved ( buf , false ) ;
ttm_bo_unreserve ( bo ) ;
err :
ttm_read_unlock ( & dev_priv - > reservation_sem ) ;
return ret ;
}
2011-10-04 20:13:28 +02:00
2011-10-04 20:13:21 +02:00
/**
2011-10-04 20:13:28 +02:00
* vmw_bo_get_guest_ptr - Get the guest ptr representing the current placement
* of a buffer .
2011-10-04 20:13:21 +02:00
*
2011-10-04 20:13:28 +02:00
* @ bo : Pointer to a struct ttm_buffer_object . Must be pinned or reserved .
* @ ptr : SVGAGuestPtr returning the result .
2011-10-04 20:13:21 +02:00
*/
2011-10-04 20:13:28 +02:00
void vmw_bo_get_guest_ptr ( const struct ttm_buffer_object * bo ,
SVGAGuestPtr * ptr )
2011-10-04 20:13:21 +02:00
{
2011-10-04 20:13:28 +02:00
if ( bo - > mem . mem_type = = TTM_PL_VRAM ) {
2011-10-04 20:13:21 +02:00
ptr - > gmrId = SVGA_GMR_FRAMEBUFFER ;
2011-10-04 20:13:28 +02:00
ptr - > offset = bo - > offset ;
2011-10-04 20:13:21 +02:00
} else {
2011-10-04 20:13:28 +02:00
ptr - > gmrId = bo - > mem . start ;
2011-10-04 20:13:21 +02:00
ptr - > offset = 0 ;
}
}
2011-10-04 20:13:30 +02:00
/**
2015-06-26 00:25:37 -07:00
* vmw_bo_pin_reserved - Pin or unpin a buffer object without moving it .
2011-10-04 20:13:30 +02:00
*
2015-06-26 00:25:37 -07:00
* @ vbo : The buffer object . Must be reserved .
2011-10-04 20:13:30 +02:00
* @ pin : Whether to pin or unpin .
*
*/
2015-06-26 00:25:37 -07:00
void vmw_bo_pin_reserved ( struct vmw_dma_buffer * vbo , bool pin )
2011-10-04 20:13:30 +02:00
{
2014-08-27 13:16:04 +02:00
struct ttm_place pl ;
2011-10-04 20:13:30 +02:00
struct ttm_placement placement ;
2015-06-26 00:25:37 -07:00
struct ttm_buffer_object * bo = & vbo - > base ;
2011-10-04 20:13:30 +02:00
uint32_t old_mem_type = bo - > mem . mem_type ;
int ret ;
2013-06-27 13:48:27 +02:00
lockdep_assert_held ( & bo - > resv - > lock . base ) ;
2011-10-04 20:13:30 +02:00
2015-06-26 00:25:37 -07:00
if ( pin ) {
if ( vbo - > pin_count + + > 0 )
return ;
} else {
WARN_ON ( vbo - > pin_count < = 0 ) ;
if ( - - vbo - > pin_count > 0 )
return ;
}
2014-08-27 13:16:04 +02:00
pl . fpfn = 0 ;
pl . lpfn = 0 ;
pl . flags = TTM_PL_FLAG_VRAM | VMW_PL_FLAG_GMR | VMW_PL_FLAG_MOB
2013-10-10 09:52:52 -07:00
| TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED ;
2011-10-04 20:13:30 +02:00
if ( pin )
2014-08-27 13:16:04 +02:00
pl . flags | = TTM_PL_FLAG_NO_EVICT ;
2011-10-04 20:13:30 +02:00
memset ( & placement , 0 , sizeof ( placement ) ) ;
placement . num_placement = 1 ;
2014-08-27 13:16:04 +02:00
placement . placement = & pl ;
2011-10-04 20:13:30 +02:00
2012-11-28 11:25:44 +00:00
ret = ttm_bo_validate ( bo , & placement , false , true ) ;
2011-10-04 20:13:30 +02:00
BUG_ON ( ret ! = 0 | | bo - > mem . mem_type ! = old_mem_type ) ;
}