2008-07-30 12:06:12 -07:00
/*
* Copyright © 2008 Intel Corporation
*
* 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
* THE AUTHORS OR COPYRIGHT HOLDERS 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 :
* Eric Anholt < eric @ anholt . net >
*
*/
2012-10-02 18:01:07 +01:00
# include <linux/string.h>
# include <linux/bitops.h>
# include <drm/drmP.h>
# include <drm/i915_drm.h>
2008-07-30 12:06:12 -07:00
# include "i915_drv.h"
2015-07-24 17:40:15 +02:00
/**
* DOC : buffer object tiling
2008-07-30 12:06:12 -07:00
*
2015-07-24 17:40:15 +02:00
* i915_gem_set_tiling ( ) and i915_gem_get_tiling ( ) is the userspace interface to
* declare fence register requirements .
2008-07-30 12:06:12 -07:00
*
2015-07-24 17:40:15 +02:00
* In principle GEM doesn ' t care at all about the internal data layout of an
* object , and hence it also doesn ' t care about tiling or swizzling . There ' s two
* exceptions :
2008-07-30 12:06:12 -07:00
*
2015-07-24 17:40:15 +02:00
* - For X and Y tiling the hardware provides detilers for CPU access , so called
* fences . Since there ' s only a limited amount of them the kernel must manage
* these , and therefore userspace must tell the kernel the object tiling if it
* wants to use fences for detiling .
* - On gen3 and gen4 platforms have a swizzling pattern for tiled objects which
* depends upon the physical page frame number . When swapping such objects the
* page frame number might change and the kernel must be able to fix this up
* and hence now the tiling . Note that on a subset of platforms with
* asymmetric memory channel population the swizzling pattern changes in an
* unknown way , and for those the kernel simply forbids swapping completely .
2008-07-30 12:06:12 -07:00
*
2015-07-24 17:40:15 +02:00
* Since neither of this applies for new tiling layouts on modern platforms like
* W , Ys and Yf tiling GEM only allows object tiling to be set to X or Y tiled .
* Anything else can be handled in userspace entirely without the kernel ' s
* invovlement .
2008-07-30 12:06:12 -07:00
*/
2009-01-26 17:10:45 -08:00
/* Check pitch constriants for all chips & tiling formats */
2010-09-24 21:15:47 +01:00
static bool
2009-01-26 17:10:45 -08:00
i915_tiling_ok ( struct drm_device * dev , int stride , int size , int tiling_mode )
{
2011-03-06 09:03:16 +00:00
int tile_width ;
2009-01-26 17:10:45 -08:00
/* Linear is always fine */
if ( tiling_mode = = I915_TILING_NONE )
return true ;
2010-09-17 00:32:17 +01:00
if ( IS_GEN2 ( dev ) | |
2009-05-26 17:44:56 -07:00
( tiling_mode = = I915_TILING_Y & & HAS_128_BYTE_Y_TILING ( dev ) ) )
2009-01-26 17:10:45 -08:00
tile_width = 128 ;
else
tile_width = 512 ;
2009-03-29 14:09:41 +02:00
/* check maximum stride & object size */
2013-04-09 11:45:05 +03:00
/* i965+ stores the end address of the gtt mapping in the fence
* reg , so dont bother to check the size */
if ( INTEL_INFO ( dev ) - > gen > = 7 ) {
if ( stride / 128 > GEN7_FENCE_MAX_PITCH_VAL )
return false ;
} else if ( INTEL_INFO ( dev ) - > gen > = 4 ) {
2009-03-29 14:09:41 +02:00
if ( stride / 128 > I965_FENCE_MAX_PITCH_VAL )
return false ;
2010-09-17 00:32:17 +01:00
} else {
2010-04-17 15:12:03 +02:00
if ( stride > 8192 )
2009-03-29 14:09:41 +02:00
return false ;
2009-05-26 17:44:56 -07:00
2010-04-17 15:12:03 +02:00
if ( IS_GEN3 ( dev ) ) {
if ( size > I830_FENCE_MAX_SIZE_VAL < < 20 )
return false ;
} else {
if ( size > I830_FENCE_MAX_SIZE_VAL < < 19 )
return false ;
}
2009-03-29 14:09:41 +02:00
}
2013-04-09 20:09:13 +03:00
if ( stride < tile_width )
return false ;
2009-01-26 17:10:45 -08:00
/* 965+ just needs multiples of tile width */
2010-09-17 00:32:17 +01:00
if ( INTEL_INFO ( dev ) - > gen > = 4 ) {
2009-01-26 17:10:45 -08:00
if ( stride & ( tile_width - 1 ) )
return false ;
return true ;
}
/* Pre-965 needs power of two tile widths */
if ( stride & ( stride - 1 ) )
return false ;
return true ;
}
2010-09-24 21:15:47 +01:00
/* Is the current GTT allocation valid for the change in tiling? */
static bool
2010-11-08 19:18:58 +00:00
i915_gem_object_fence_ok ( struct drm_i915_gem_object * obj , int tiling_mode )
2009-06-06 09:46:01 +01:00
{
2010-09-24 21:15:47 +01:00
u32 size ;
2009-06-06 09:46:01 +01:00
if ( tiling_mode = = I915_TILING_NONE )
return true ;
2010-11-08 19:18:58 +00:00
if ( INTEL_INFO ( obj - > base . dev ) - > gen > = 4 )
2010-09-17 00:32:17 +01:00
return true ;
2016-05-10 10:57:06 +01:00
if ( IS_GEN3 ( obj - > base . dev ) ) {
2013-07-05 14:41:04 -07:00
if ( i915_gem_obj_ggtt_offset ( obj ) & ~ I915_FENCE_START_MASK )
2010-11-15 05:25:58 +00:00
return false ;
} else {
2013-07-05 14:41:04 -07:00
if ( i915_gem_obj_ggtt_offset ( obj ) & ~ I830_FENCE_START_MASK )
2010-11-15 05:25:58 +00:00
return false ;
}
2013-01-07 21:47:35 +02:00
size = i915_gem_get_gtt_size ( obj - > base . dev , obj - > base . size , tiling_mode ) ;
2013-07-05 14:41:04 -07:00
if ( i915_gem_obj_ggtt_size ( obj ) ! = size )
2010-09-17 00:32:17 +01:00
return false ;
2013-07-05 14:41:04 -07:00
if ( i915_gem_obj_ggtt_offset ( obj ) & ( size - 1 ) )
2010-11-15 05:25:58 +00:00
return false ;
2009-06-06 09:46:01 +01:00
return true ;
}
2008-07-30 12:06:12 -07:00
/**
2015-07-24 17:40:15 +02:00
* i915_gem_set_tiling - IOCTL handler to set tiling mode
* @ dev : DRM device
* @ data : data pointer for the ioctl
* @ file : DRM file for the ioctl call
*
2008-07-30 12:06:12 -07:00
* Sets the tiling mode of an object , returning the required swizzling of
* bit 6 of addresses in the object .
2015-07-24 17:40:15 +02:00
*
* Called by the user via ioctl .
*
* Returns :
* Zero on success , negative errno on failure .
2008-07-30 12:06:12 -07:00
*/
int
i915_gem_set_tiling ( struct drm_device * dev , void * data ,
2010-11-08 19:18:58 +00:00
struct drm_file * file )
2008-07-30 12:06:12 -07:00
{
struct drm_i915_gem_set_tiling * args = data ;
2014-03-31 14:27:21 +03:00
struct drm_i915_private * dev_priv = dev - > dev_private ;
2010-11-08 19:18:58 +00:00
struct drm_i915_gem_object * obj ;
2011-03-07 12:32:44 +00:00
int ret = 0 ;
2008-07-30 12:06:12 -07:00
2016-05-09 11:04:54 +01:00
obj = to_intel_bo ( drm_gem_object_lookup ( file , args - > handle ) ) ;
2011-02-19 11:31:06 +00:00
if ( & obj - > base = = NULL )
2010-08-04 14:19:46 +01:00
return - ENOENT ;
2008-07-30 12:06:12 -07:00
2010-11-08 19:18:58 +00:00
if ( ! i915_tiling_ok ( dev ,
args - > stride , obj - > base . size , args - > tiling_mode ) ) {
drm_gem_object_unreference_unlocked ( & obj - > base ) ;
2009-01-26 17:10:45 -08:00
return - EINVAL ;
2009-01-30 21:10:22 +00:00
}
2009-01-26 17:10:45 -08:00
2015-11-09 20:16:26 +02:00
intel_runtime_pm_get ( dev_priv ) ;
2015-02-12 07:53:18 +00:00
mutex_lock ( & dev - > struct_mutex ) ;
2015-04-15 16:39:59 +01:00
if ( obj - > pin_display | | obj - > framebuffer_references ) {
2015-02-12 07:53:18 +00:00
ret = - EBUSY ;
goto err ;
2010-04-23 23:01:01 +02:00
}
2008-07-30 12:06:12 -07:00
if ( args - > tiling_mode = = I915_TILING_NONE ) {
args - > swizzle_mode = I915_BIT_6_SWIZZLE_NONE ;
2009-06-06 09:46:01 +01:00
args - > stride = 0 ;
2008-07-30 12:06:12 -07:00
} else {
if ( args - > tiling_mode = = I915_TILING_X )
args - > swizzle_mode = dev_priv - > mm . bit_6_swizzle_x ;
else
args - > swizzle_mode = dev_priv - > mm . bit_6_swizzle_y ;
2009-03-12 16:56:27 -07:00
/* Hide bit 17 swizzling from the user. This prevents old Mesa
* from aborting the application on sw fallbacks to bit 17 ,
* and we use the pread / pwrite bit17 paths to swizzle for it .
* If there was a user that was relying on the swizzle
* information for drm_intel_bo_map ( ) ed reads / writes this would
* break it , but we don ' t have any of those .
*/
if ( args - > swizzle_mode = = I915_BIT_6_SWIZZLE_9_17 )
args - > swizzle_mode = I915_BIT_6_SWIZZLE_9 ;
if ( args - > swizzle_mode = = I915_BIT_6_SWIZZLE_9_10_17 )
args - > swizzle_mode = I915_BIT_6_SWIZZLE_9_10 ;
2008-07-30 12:06:12 -07:00
/* If we can't handle the swizzling, make it untiled. */
if ( args - > swizzle_mode = = I915_BIT_6_SWIZZLE_UNKNOWN ) {
args - > tiling_mode = I915_TILING_NONE ;
args - > swizzle_mode = I915_BIT_6_SWIZZLE_NONE ;
2009-06-06 09:46:01 +01:00
args - > stride = 0 ;
2008-07-30 12:06:12 -07:00
}
}
2009-01-26 17:10:45 -08:00
2010-11-08 19:18:58 +00:00
if ( args - > tiling_mode ! = obj - > tiling_mode | |
args - > stride ! = obj - > stride ) {
2009-06-06 09:46:01 +01:00
/* We need to rebind the object if its current allocation
* no longer meets the alignment restrictions for its new
* tiling mode . Otherwise we can just leave it alone , but
2012-04-21 16:23:24 +01:00
* need to ensure that any fence register is updated before
* the next fenced ( either through the GTT or by the BLT unit
* on older GPUs ) access .
2012-04-21 16:23:23 +01:00
*
* After updating the tiling parameters , we then flag whether
* we need to update an associated fence register . Note this
* has to also include the unfenced register the GPU uses
* whilst executing a fenced command for an untiled object .
2009-01-26 17:10:45 -08:00
*/
2014-11-06 08:40:35 +00:00
if ( obj - > map_and_fenceable & &
! i915_gem_object_fence_ok ( obj , args - > tiling_mode ) )
2016-04-28 12:24:51 +01:00
ret = i915_vma_unbind ( i915_gem_obj_to_ggtt ( obj ) ) ;
2011-03-07 10:42:03 +00:00
if ( ret = = 0 ) {
2014-11-20 09:26:30 +01:00
if ( obj - > pages & &
obj - > madv = = I915_MADV_WILLNEED & &
dev_priv - > quirks & QUIRK_PIN_SWIZZLED_PAGES ) {
if ( args - > tiling_mode = = I915_TILING_NONE )
i915_gem_object_unpin_pages ( obj ) ;
if ( obj - > tiling_mode = = I915_TILING_NONE )
i915_gem_object_pin_pages ( obj ) ;
}
2012-04-21 16:23:23 +01:00
obj - > fence_dirty =
2014-11-24 18:49:26 +00:00
obj - > last_fenced_req | |
2012-04-21 16:23:23 +01:00
obj - > fence_reg ! = I915_FENCE_REG_NONE ;
2011-03-07 10:42:03 +00:00
obj - > tiling_mode = args - > tiling_mode ;
obj - > stride = args - > stride ;
2012-04-21 16:23:24 +01:00
/* Force the fence to be reacquired for GTT access */
i915_gem_release_mmap ( obj ) ;
2011-03-07 10:42:03 +00:00
}
2009-01-26 17:10:45 -08:00
}
2011-03-07 10:42:03 +00:00
/* we have to maintain this existing ABI... */
args - > stride = obj - > stride ;
args - > tiling_mode = obj - > tiling_mode ;
2012-12-03 21:03:14 +00:00
/* Try to preallocate memory required to save swizzling on put-pages */
if ( i915_gem_object_needs_bit17_swizzle ( obj ) ) {
if ( obj - > bit_17 = = NULL ) {
2013-09-21 00:35:38 +02:00
obj - > bit_17 = kcalloc ( BITS_TO_LONGS ( obj - > base . size > > PAGE_SHIFT ) ,
2012-12-03 21:03:14 +00:00
sizeof ( long ) , GFP_KERNEL ) ;
}
} else {
kfree ( obj - > bit_17 ) ;
obj - > bit_17 = NULL ;
}
2015-02-12 07:53:18 +00:00
err :
2010-11-08 19:18:58 +00:00
drm_gem_object_unreference ( & obj - > base ) ;
2009-02-08 19:07:51 +00:00
mutex_unlock ( & dev - > struct_mutex ) ;
2008-07-30 12:06:12 -07:00
2015-11-09 20:16:26 +02:00
intel_runtime_pm_put ( dev_priv ) ;
2011-03-07 10:42:03 +00:00
return ret ;
2008-07-30 12:06:12 -07:00
}
/**
2015-07-24 17:40:15 +02:00
* i915_gem_get_tiling - IOCTL handler to get tiling mode
* @ dev : DRM device
* @ data : data pointer for the ioctl
* @ file : DRM file for the ioctl call
*
2008-07-30 12:06:12 -07:00
* Returns the current tiling mode and required bit 6 swizzling for the object .
2015-07-24 17:40:15 +02:00
*
* Called by the user via ioctl .
*
* Returns :
* Zero on success , negative errno on failure .
2008-07-30 12:06:12 -07:00
*/
int
i915_gem_get_tiling ( struct drm_device * dev , void * data ,
2010-11-08 19:18:58 +00:00
struct drm_file * file )
2008-07-30 12:06:12 -07:00
{
struct drm_i915_gem_get_tiling * args = data ;
2014-03-31 14:27:21 +03:00
struct drm_i915_private * dev_priv = dev - > dev_private ;
2010-11-08 19:18:58 +00:00
struct drm_i915_gem_object * obj ;
2008-07-30 12:06:12 -07:00
2016-05-09 11:04:54 +01:00
obj = to_intel_bo ( drm_gem_object_lookup ( file , args - > handle ) ) ;
2011-02-19 11:31:06 +00:00
if ( & obj - > base = = NULL )
2010-08-04 14:19:46 +01:00
return - ENOENT ;
2008-07-30 12:06:12 -07:00
mutex_lock ( & dev - > struct_mutex ) ;
2010-11-08 19:18:58 +00:00
args - > tiling_mode = obj - > tiling_mode ;
switch ( obj - > tiling_mode ) {
2008-07-30 12:06:12 -07:00
case I915_TILING_X :
args - > swizzle_mode = dev_priv - > mm . bit_6_swizzle_x ;
break ;
case I915_TILING_Y :
args - > swizzle_mode = dev_priv - > mm . bit_6_swizzle_y ;
break ;
case I915_TILING_NONE :
args - > swizzle_mode = I915_BIT_6_SWIZZLE_NONE ;
break ;
default :
DRM_ERROR ( " unknown tiling mode \n " ) ;
}
2009-03-12 16:56:27 -07:00
/* Hide bit 17 from the user -- see comment in i915_gem_set_tiling */
2015-06-28 09:19:26 +01:00
if ( dev_priv - > quirks & QUIRK_PIN_SWIZZLED_PAGES )
args - > phys_swizzle_mode = I915_BIT_6_SWIZZLE_UNKNOWN ;
else
args - > phys_swizzle_mode = args - > swizzle_mode ;
2009-03-12 16:56:27 -07:00
if ( args - > swizzle_mode = = I915_BIT_6_SWIZZLE_9_17 )
args - > swizzle_mode = I915_BIT_6_SWIZZLE_9 ;
if ( args - > swizzle_mode = = I915_BIT_6_SWIZZLE_9_10_17 )
args - > swizzle_mode = I915_BIT_6_SWIZZLE_9_10 ;
2010-11-08 19:18:58 +00:00
drm_gem_object_unreference ( & obj - > base ) ;
2009-02-08 19:07:51 +00:00
mutex_unlock ( & dev - > struct_mutex ) ;
2008-07-30 12:06:12 -07:00
return 0 ;
}