2018-05-07 01:16:26 +02:00
// SPDX-License-Identifier: GPL-2.0 OR MIT
2009-12-10 00:19:58 +00:00
/**************************************************************************
*
2018-05-07 01:16:26 +02:00
* Copyright 2009 - 2015 VMware , Inc . , Palo Alto , CA . , USA
2009-12-10 00:19:58 +00:00
*
* 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 18:01:07 +01:00
# include <drm/drmP.h>
# include <drm/ttm/ttm_bo_driver.h>
2009-12-10 00:19:58 +00:00
2013-08-29 02:32:53 +02:00
# define VMW_PPN_SIZE (sizeof(unsigned long))
/* A future safe maximum remap size. */
# define VMW_PPN_PER_REMAP ((31 * 1024) / VMW_PPN_SIZE)
2013-10-24 01:49:26 -07:00
# define DMA_ADDR_INVALID ((dma_addr_t) 0)
# define DMA_PAGE_INVALID 0UL
2011-08-31 09:42:55 +02:00
static int vmw_gmr2_bind ( struct vmw_private * dev_priv ,
2013-10-24 01:49:26 -07:00
struct vmw_piter * iter ,
2011-08-31 09:42:55 +02:00
unsigned long num_pages ,
int gmr_id )
{
SVGAFifoCmdDefineGMR2 define_cmd ;
SVGAFifoCmdRemapGMR2 remap_cmd ;
uint32_t * cmd ;
uint32_t * cmd_orig ;
2013-08-29 02:32:53 +02:00
uint32_t define_size = sizeof ( define_cmd ) + sizeof ( * cmd ) ;
uint32_t remap_num = num_pages / VMW_PPN_PER_REMAP + ( ( num_pages % VMW_PPN_PER_REMAP ) > 0 ) ;
uint32_t remap_size = VMW_PPN_SIZE * num_pages + ( sizeof ( remap_cmd ) + sizeof ( * cmd ) ) * remap_num ;
uint32_t remap_pos = 0 ;
uint32_t cmd_size = define_size + remap_size ;
2011-08-31 09:42:55 +02:00
uint32_t i ;
2019-02-14 16:15:39 -08:00
cmd_orig = cmd = VMW_FIFO_RESERVE ( dev_priv , cmd_size ) ;
2011-08-31 09:42:55 +02:00
if ( unlikely ( cmd = = NULL ) )
return - ENOMEM ;
define_cmd . gmrId = gmr_id ;
define_cmd . numPages = num_pages ;
2013-08-29 02:32:53 +02:00
* cmd + + = SVGA_CMD_DEFINE_GMR2 ;
memcpy ( cmd , & define_cmd , sizeof ( define_cmd ) ) ;
cmd + = sizeof ( define_cmd ) / sizeof ( * cmd ) ;
/*
* Need to split the command if there are too many
* pages that goes into the gmr .
*/
2011-08-31 09:42:55 +02:00
remap_cmd . gmrId = gmr_id ;
remap_cmd . flags = ( VMW_PPN_SIZE > sizeof ( * cmd ) ) ?
SVGA_REMAP_GMR2_PPN64 : SVGA_REMAP_GMR2_PPN32 ;
2013-08-29 02:32:53 +02:00
while ( num_pages > 0 ) {
unsigned long nr = min ( num_pages , ( unsigned long ) VMW_PPN_PER_REMAP ) ;
remap_cmd . offsetPages = remap_pos ;
remap_cmd . numPages = nr ;
2011-08-31 09:42:55 +02:00
2013-08-29 02:32:53 +02:00
* cmd + + = SVGA_CMD_REMAP_GMR2 ;
memcpy ( cmd , & remap_cmd , sizeof ( remap_cmd ) ) ;
cmd + = sizeof ( remap_cmd ) / sizeof ( * cmd ) ;
2011-08-31 09:42:55 +02:00
2013-08-29 02:32:53 +02:00
for ( i = 0 ; i < nr ; + + i ) {
if ( VMW_PPN_SIZE < = 4 )
2013-10-24 01:49:26 -07:00
* cmd = vmw_piter_dma_addr ( iter ) > > PAGE_SHIFT ;
2013-08-29 02:32:53 +02:00
else
2013-10-24 01:49:26 -07:00
* ( ( uint64_t * ) cmd ) = vmw_piter_dma_addr ( iter ) > >
PAGE_SHIFT ;
2011-08-31 09:42:55 +02:00
2013-08-29 02:32:53 +02:00
cmd + = VMW_PPN_SIZE / sizeof ( * cmd ) ;
2013-10-24 01:49:26 -07:00
vmw_piter_next ( iter ) ;
2013-08-29 02:32:53 +02:00
}
num_pages - = nr ;
remap_pos + = nr ;
2011-08-31 09:42:55 +02:00
}
2013-08-29 02:32:53 +02:00
BUG_ON ( cmd ! = cmd_orig + cmd_size / sizeof ( * cmd ) ) ;
vmw_fifo_commit ( dev_priv , cmd_size ) ;
2011-08-31 09:42:55 +02:00
return 0 ;
}
static void vmw_gmr2_unbind ( struct vmw_private * dev_priv ,
int gmr_id )
{
SVGAFifoCmdDefineGMR2 define_cmd ;
uint32_t define_size = sizeof ( define_cmd ) + 4 ;
uint32_t * cmd ;
2019-02-14 16:15:39 -08:00
cmd = VMW_FIFO_RESERVE ( dev_priv , define_size ) ;
if ( unlikely ( cmd = = NULL ) )
2011-08-31 09:42:55 +02:00
return ;
2019-02-14 16:15:39 -08:00
2011-08-31 09:42:55 +02:00
define_cmd . gmrId = gmr_id ;
define_cmd . numPages = 0 ;
* cmd + + = SVGA_CMD_DEFINE_GMR2 ;
memcpy ( cmd , & define_cmd , sizeof ( define_cmd ) ) ;
vmw_fifo_commit ( dev_priv , define_size ) ;
}
2013-10-24 01:49:26 -07:00
2009-12-10 00:19:58 +00:00
int vmw_gmr_bind ( struct vmw_private * dev_priv ,
2013-10-24 01:49:26 -07:00
const struct vmw_sg_table * vsgt ,
2010-10-26 21:21:47 +02:00
unsigned long num_pages ,
int gmr_id )
2009-12-10 00:19:58 +00:00
{
2013-10-24 01:49:26 -07:00
struct vmw_piter data_iter ;
2009-12-10 00:19:58 +00:00
2013-10-24 01:49:26 -07:00
vmw_piter_start ( & data_iter , vsgt , 0 ) ;
if ( unlikely ( ! vmw_piter_next ( & data_iter ) ) )
return 0 ;
2014-01-15 20:19:53 +01:00
if ( unlikely ( ! ( dev_priv - > capabilities & SVGA_CAP_GMR2 ) ) )
2009-12-10 00:19:58 +00:00
return - EINVAL ;
2014-01-15 20:19:53 +01:00
return vmw_gmr2_bind ( dev_priv , & data_iter , num_pages , gmr_id ) ;
2009-12-10 00:19:58 +00:00
}
2010-10-26 21:21:47 +02:00
2009-12-10 00:19:58 +00:00
void vmw_gmr_unbind ( struct vmw_private * dev_priv , int gmr_id )
{
2014-01-15 20:19:53 +01:00
if ( likely ( dev_priv - > capabilities & SVGA_CAP_GMR2 ) )
2011-08-31 09:42:55 +02:00
vmw_gmr2_unbind ( dev_priv , gmr_id ) ;
2009-12-10 00:19:58 +00:00
}