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
*
2017-01-10 12:10:44 +00:00
* i915_gem_set_tiling_ioctl ( ) and i915_gem_get_tiling_ioctl ( ) 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
*/
2017-01-09 16:16:13 +00:00
/**
* i915_gem_fence_size - required global GTT size for a fence
* @ i915 : i915 device
* @ size : object size
* @ tiling : tiling mode
* @ stride : tiling stride
*
* Return the required global GTT size for a fence ( view of a tiled object ) ,
* taking into account potential fence register mapping .
*/
u32 i915_gem_fence_size ( struct drm_i915_private * i915 ,
u32 size , unsigned int tiling , unsigned int stride )
{
u32 ggtt_size ;
GEM_BUG_ON ( ! size ) ;
if ( tiling = = I915_TILING_NONE )
return size ;
GEM_BUG_ON ( ! stride ) ;
if ( INTEL_GEN ( i915 ) > = 4 ) {
stride * = i915_gem_tile_height ( tiling ) ;
2017-01-10 14:47:34 +00:00
GEM_BUG_ON ( ! IS_ALIGNED ( stride , I965_FENCE_PAGE ) ) ;
2017-01-09 16:16:13 +00:00
return roundup ( size , stride ) ;
}
/* Previous chips need a power-of-two fence region when tiling */
if ( IS_GEN3 ( i915 ) )
ggtt_size = 1024 * 1024 ;
else
ggtt_size = 512 * 1024 ;
while ( ggtt_size < size )
ggtt_size < < = 1 ;
return ggtt_size ;
}
/**
* i915_gem_fence_alignment - required global GTT alignment for a fence
* @ i915 : i915 device
* @ size : object size
* @ tiling : tiling mode
* @ stride : tiling stride
*
* Return the required global GTT alignment for a fence ( a view of a tiled
* object ) , taking into account potential fence register mapping .
*/
u32 i915_gem_fence_alignment ( struct drm_i915_private * i915 , u32 size ,
unsigned int tiling , unsigned int stride )
{
GEM_BUG_ON ( ! size ) ;
/*
* Minimum alignment is 4 k ( GTT page size ) , but might be greater
* if a fence register is needed for the object .
*/
2017-01-10 14:47:34 +00:00
if ( tiling = = I915_TILING_NONE )
return I915_GTT_MIN_ALIGNMENT ;
if ( INTEL_GEN ( i915 ) > = 4 )
return I965_FENCE_PAGE ;
2017-01-09 16:16:13 +00:00
/*
* Previous chips need to be aligned to the size of the smallest
* fence register that can contain the object .
*/
return i915_gem_fence_size ( i915 , size , tiling , stride ) ;
}
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
2017-01-10 12:10:45 +00:00
i915_tiling_ok ( struct drm_i915_gem_object * obj ,
unsigned int tiling , unsigned int stride )
2009-01-26 17:10:45 -08:00
{
2017-01-10 12:10:45 +00:00
struct drm_i915_private * i915 = to_i915 ( obj - > base . dev ) ;
unsigned int tile_width ;
2009-01-26 17:10:45 -08:00
/* Linear is always fine */
2017-01-10 12:10:45 +00:00
if ( tiling = = I915_TILING_NONE )
2009-01-26 17:10:45 -08:00
return true ;
2017-01-10 12:10:45 +00:00
if ( tiling > I915_TILING_LAST )
2016-08-05 10:14:22 +01:00
return false ;
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 */
2017-01-10 12:10:45 +00:00
if ( INTEL_GEN ( i915 ) > = 7 ) {
2013-04-09 11:45:05 +03:00
if ( stride / 128 > GEN7_FENCE_MAX_PITCH_VAL )
return false ;
2017-01-10 12:10:45 +00:00
} else if ( INTEL_GEN ( i915 ) > = 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
2017-02-03 11:50:35 +00:00
if ( ! is_power_of_2 ( stride ) )
return false ;
2009-03-29 14:09:41 +02:00
}
2017-01-10 12:10:45 +00:00
if ( IS_GEN2 ( i915 ) | |
( tiling = = I915_TILING_Y & & HAS_128_BYTE_Y_TILING ( i915 ) ) )
tile_width = 128 ;
else
tile_width = 512 ;
2017-02-03 10:56:52 +00:00
if ( ! stride | | ! IS_ALIGNED ( stride , tile_width ) )
2013-04-09 20:09:13 +03:00
return false ;
2017-02-03 11:50:35 +00:00
return true ;
2009-01-26 17:10:45 -08:00
}
2017-01-09 16:16:09 +00:00
static bool i915_vma_fence_prepare ( struct i915_vma * vma ,
int tiling_mode , unsigned int stride )
2016-08-18 17:17:00 +01:00
{
2017-01-09 16:16:11 +00:00
struct drm_i915_private * i915 = vma - > vm - > i915 ;
u32 size , alignment ;
2016-08-18 17:17:00 +01:00
if ( ! i915_vma_is_map_and_fenceable ( vma ) )
return true ;
2017-01-09 16:16:13 +00:00
size = i915_gem_fence_size ( i915 , vma - > size , tiling_mode , stride ) ;
2016-08-18 17:17:00 +01:00
if ( vma - > node . size < size )
return false ;
2017-01-09 16:16:13 +00:00
alignment = i915_gem_fence_alignment ( i915 , vma - > size , tiling_mode , stride ) ;
2017-01-10 14:47:34 +00:00
if ( ! IS_ALIGNED ( vma - > node . start , alignment ) )
2016-08-18 17:17:00 +01:00
return false ;
return true ;
}
2016-08-15 10:48:53 +01:00
/* Make the current GTT allocation valid for the change in tiling. */
static int
2017-01-09 16:16:09 +00:00
i915_gem_object_fence_prepare ( struct drm_i915_gem_object * obj ,
int tiling_mode , unsigned int stride )
2009-06-06 09:46:01 +01:00
{
2016-08-15 10:48:53 +01:00
struct i915_vma * vma ;
2016-08-18 17:17:00 +01:00
int ret ;
2009-06-06 09:46:01 +01:00
if ( tiling_mode = = I915_TILING_NONE )
2016-08-15 10:48:53 +01:00
return 0 ;
2009-06-06 09:46:01 +01:00
2017-12-07 21:14:07 +00:00
for_each_ggtt_vma ( vma , obj ) {
2017-01-09 16:16:09 +00:00
if ( i915_vma_fence_prepare ( vma , tiling_mode , stride ) )
2016-08-18 17:17:00 +01:00
continue ;
2010-09-17 00:32:17 +01:00
2016-08-18 17:17:00 +01:00
ret = i915_vma_unbind ( vma ) ;
if ( ret )
return ret ;
2010-11-15 05:25:58 +00:00
}
2016-08-15 10:48:53 +01:00
return 0 ;
2009-06-06 09:46:01 +01:00
}
2017-01-10 12:10:45 +00:00
int
i915_gem_object_set_tiling ( struct drm_i915_gem_object * obj ,
unsigned int tiling , unsigned int stride )
{
struct drm_i915_private * i915 = to_i915 ( obj - > base . dev ) ;
struct i915_vma * vma ;
int err ;
/* Make sure we don't cross-contaminate obj->tiling_and_stride */
BUILD_BUG_ON ( I915_TILING_LAST & STRIDE_MASK ) ;
GEM_BUG_ON ( ! i915_tiling_ok ( obj , tiling , stride ) ) ;
GEM_BUG_ON ( ! stride ^ ( tiling = = I915_TILING_NONE ) ) ;
lockdep_assert_held ( & i915 - > drm . struct_mutex ) ;
if ( ( tiling | stride ) = = obj - > tiling_and_stride )
return 0 ;
2017-03-01 15:41:28 +00:00
if ( i915_gem_object_is_framebuffer ( obj ) )
2017-01-10 12:10:45 +00:00
return - EBUSY ;
/* 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
* 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 .
*
* 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 .
*/
err = i915_gem_object_fence_prepare ( obj , tiling , stride ) ;
if ( err )
return err ;
2017-03-01 15:41:28 +00:00
i915_gem_object_lock ( obj ) ;
if ( i915_gem_object_is_framebuffer ( obj ) ) {
i915_gem_object_unlock ( obj ) ;
return - EBUSY ;
}
2017-01-10 12:10:45 +00:00
/* If the memory has unknown (i.e. varying) swizzling, we pin the
* pages to prevent them being swapped out and causing corruption
* due to the change in swizzling .
*/
mutex_lock ( & obj - > mm . lock ) ;
2017-10-13 21:26:13 +01:00
if ( i915_gem_object_has_pages ( obj ) & &
2017-01-10 12:10:45 +00:00
obj - > mm . madv = = I915_MADV_WILLNEED & &
i915 - > quirks & QUIRK_PIN_SWIZZLED_PAGES ) {
if ( tiling = = I915_TILING_NONE ) {
GEM_BUG_ON ( ! obj - > mm . quirked ) ;
__i915_gem_object_unpin_pages ( obj ) ;
obj - > mm . quirked = false ;
}
if ( ! i915_gem_object_is_tiled ( obj ) ) {
2017-05-21 13:40:14 +01:00
GEM_BUG_ON ( obj - > mm . quirked ) ;
2017-01-10 12:10:45 +00:00
__i915_gem_object_pin_pages ( obj ) ;
obj - > mm . quirked = true ;
}
}
mutex_unlock ( & obj - > mm . lock ) ;
2017-12-07 21:14:07 +00:00
for_each_ggtt_vma ( vma , obj ) {
2017-01-10 12:10:45 +00:00
vma - > fence_size =
i915_gem_fence_size ( i915 , vma - > size , tiling , stride ) ;
vma - > fence_alignment =
i915_gem_fence_alignment ( i915 ,
vma - > size , tiling , stride ) ;
if ( vma - > fence )
vma - > fence - > dirty = true ;
}
obj - > tiling_and_stride = tiling | stride ;
2017-03-01 15:41:28 +00:00
i915_gem_object_unlock ( obj ) ;
2017-01-10 12:10:45 +00:00
/* Force the fence to be reacquired for GTT access */
i915_gem_release_mmap ( obj ) ;
/* Try to preallocate memory required to save swizzling on put-pages */
if ( i915_gem_object_needs_bit17_swizzle ( obj ) ) {
if ( ! obj - > bit_17 ) {
obj - > bit_17 = kcalloc ( BITS_TO_LONGS ( obj - > base . size > > PAGE_SHIFT ) ,
sizeof ( long ) , GFP_KERNEL ) ;
}
} else {
kfree ( obj - > bit_17 ) ;
obj - > bit_17 = NULL ;
}
return 0 ;
}
2008-07-30 12:06:12 -07:00
/**
2017-01-10 12:10:44 +00:00
* i915_gem_set_tiling_ioctl - IOCTL handler to set tiling mode
2015-07-24 17:40:15 +02:00
* @ 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
2017-01-10 12:10:44 +00:00
i915_gem_set_tiling_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * file )
2008-07-30 12:06:12 -07:00
{
struct drm_i915_gem_set_tiling * args = data ;
2010-11-08 19:18:58 +00:00
struct drm_i915_gem_object * obj ;
2017-01-10 12:10:45 +00:00
int err ;
2016-08-05 10:14:23 +01:00
2016-07-20 13:31:51 +01:00
obj = i915_gem_object_lookup ( file , args - > handle ) ;
if ( ! obj )
2010-08-04 14:19:46 +01:00
return - ENOENT ;
2008-07-30 12:06:12 -07:00
2017-11-14 10:25:13 +00:00
/*
* The tiling mode of proxy objects is handled by its generator , and
* not allowed to be changed by userspace .
*/
if ( i915_gem_object_is_proxy ( obj ) ) {
err = - ENXIO ;
goto err ;
}
2017-01-10 12:10:45 +00:00
if ( ! i915_tiling_ok ( obj , args - > tiling_mode , args - > stride ) ) {
err = - EINVAL ;
2015-02-12 07:53:18 +00:00
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 )
2017-01-10 12:10:45 +00:00
args - > swizzle_mode = to_i915 ( dev ) - > mm . bit_6_swizzle_x ;
2008-07-30 12:06:12 -07:00
else
2017-01-10 12:10:45 +00:00
args - > swizzle_mode = to_i915 ( dev ) - > 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
2017-01-10 12:10:45 +00:00
err = mutex_lock_interruptible ( & dev - > struct_mutex ) ;
if ( err )
goto err ;
2011-03-07 10:42:03 +00:00
2017-01-10 12:10:45 +00:00
err = i915_gem_object_set_tiling ( obj , args - > tiling_mode , args - > stride ) ;
mutex_unlock ( & dev - > struct_mutex ) ;
/* We have to maintain this existing ABI... */
2016-08-05 10:14:23 +01:00
args - > stride = i915_gem_object_get_stride ( obj ) ;
args - > tiling_mode = i915_gem_object_get_tiling ( obj ) ;
2012-12-03 21:03:14 +00:00
2015-02-12 07:53:18 +00:00
err :
2016-07-20 13:31:53 +01:00
i915_gem_object_put ( obj ) ;
2016-08-15 10:48:53 +01:00
return err ;
2008-07-30 12:06:12 -07:00
}
/**
2017-01-10 12:10:44 +00:00
* i915_gem_get_tiling_ioctl - IOCTL handler to get tiling mode
2015-07-24 17:40:15 +02:00
* @ 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
2017-01-10 12:10:44 +00:00
i915_gem_get_tiling_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * file )
2008-07-30 12:06:12 -07:00
{
struct drm_i915_gem_get_tiling * args = data ;
2016-07-04 11:34:36 +01:00
struct drm_i915_private * dev_priv = to_i915 ( dev ) ;
2010-11-08 19:18:58 +00:00
struct drm_i915_gem_object * obj ;
2016-10-28 13:58:42 +01:00
int err = - ENOENT ;
rcu_read_lock ( ) ;
obj = i915_gem_object_lookup_rcu ( file , args - > handle ) ;
if ( obj ) {
args - > tiling_mode =
READ_ONCE ( obj - > tiling_and_stride ) & TILING_MASK ;
err = 0 ;
}
rcu_read_unlock ( ) ;
if ( unlikely ( err ) )
return err ;
2008-07-30 12:06:12 -07:00
2016-08-05 10:14:21 +01:00
switch ( args - > 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 ;
2016-10-28 13:58:42 +01:00
default :
2008-07-30 12:06:12 -07:00
case I915_TILING_NONE :
args - > swizzle_mode = I915_BIT_6_SWIZZLE_NONE ;
break ;
}
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 ;
2008-07-30 12:06:12 -07:00
return 0 ;
}