2010-11-25 18:00:26 +00:00
/*
* Copyright © 2008 , 2010 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 >
* Chris Wilson < chris @ chris - wilson . co . uk >
*
*/
# include "drmP.h"
# include "drm.h"
# include "i915_drm.h"
# include "i915_drv.h"
# include "i915_trace.h"
# include "intel_drv.h"
2011-12-09 17:16:37 -08:00
# include <linux/dma_remapping.h>
2010-11-25 18:00:26 +00:00
2010-12-08 10:38:14 +00:00
struct eb_objects {
int and ;
struct hlist_head buckets [ 0 ] ;
} ;
static struct eb_objects *
eb_create ( int size )
{
struct eb_objects * eb ;
int count = PAGE_SIZE / sizeof ( struct hlist_head ) / 2 ;
while ( count > size )
count > > = 1 ;
eb = kzalloc ( count * sizeof ( struct hlist_head ) +
sizeof ( struct eb_objects ) ,
GFP_KERNEL ) ;
if ( eb = = NULL )
return eb ;
eb - > and = count - 1 ;
return eb ;
}
static void
eb_reset ( struct eb_objects * eb )
{
memset ( eb - > buckets , 0 , ( eb - > and + 1 ) * sizeof ( struct hlist_head ) ) ;
}
static void
eb_add_object ( struct eb_objects * eb , struct drm_i915_gem_object * obj )
{
hlist_add_head ( & obj - > exec_node ,
& eb - > buckets [ obj - > exec_handle & eb - > and ] ) ;
}
static struct drm_i915_gem_object *
eb_get_object ( struct eb_objects * eb , unsigned long handle )
{
struct hlist_head * head ;
struct hlist_node * node ;
struct drm_i915_gem_object * obj ;
head = & eb - > buckets [ handle & eb - > and ] ;
hlist_for_each ( node , head ) {
obj = hlist_entry ( node , struct drm_i915_gem_object , exec_node ) ;
if ( obj - > exec_handle = = handle )
return obj ;
}
return NULL ;
}
static void
eb_destroy ( struct eb_objects * eb )
{
kfree ( eb ) ;
}
2012-03-26 10:10:27 +02:00
static inline int use_cpu_reloc ( struct drm_i915_gem_object * obj )
{
return ( obj - > base . write_domain = = I915_GEM_DOMAIN_CPU | |
obj - > cache_level ! = I915_CACHE_NONE ) ;
}
2010-11-25 18:00:26 +00:00
static int
i915_gem_execbuffer_relocate_entry ( struct drm_i915_gem_object * obj ,
2010-12-08 10:38:14 +00:00
struct eb_objects * eb ,
2010-11-25 18:00:26 +00:00
struct drm_i915_gem_relocation_entry * reloc )
{
struct drm_device * dev = obj - > base . dev ;
struct drm_gem_object * target_obj ;
2012-02-15 23:50:23 +01:00
struct drm_i915_gem_object * target_i915_obj ;
2010-11-25 18:00:26 +00:00
uint32_t target_offset ;
int ret = - EINVAL ;
2010-12-08 10:38:14 +00:00
/* we've already hold a reference to all valid objects */
target_obj = & eb_get_object ( eb , reloc - > target_handle ) - > base ;
if ( unlikely ( target_obj = = NULL ) )
2010-11-25 18:00:26 +00:00
return - ENOENT ;
2012-02-15 23:50:23 +01:00
target_i915_obj = to_intel_bo ( target_obj ) ;
target_offset = target_i915_obj - > gtt_offset ;
2010-11-25 18:00:26 +00:00
/* The target buffer should have appeared before us in the
* exec_object list , so it should have a GTT space bound by now .
*/
2010-12-08 10:43:06 +00:00
if ( unlikely ( target_offset = = 0 ) ) {
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " No GTT space found for object %d \n " ,
2010-11-25 18:00:26 +00:00
reloc - > target_handle ) ;
2010-12-08 10:38:14 +00:00
return ret ;
2010-11-25 18:00:26 +00:00
}
/* Validate that the target is in a valid r/w GPU domain */
2010-12-08 10:43:06 +00:00
if ( unlikely ( reloc - > write_domain & ( reloc - > write_domain - 1 ) ) ) {
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " reloc with multiple write domains: "
2010-11-25 18:00:26 +00:00
" obj %p target %d offset %d "
" read %08x write %08x " ,
obj , reloc - > target_handle ,
( int ) reloc - > offset ,
reloc - > read_domains ,
reloc - > write_domain ) ;
2010-12-08 10:38:14 +00:00
return ret ;
2010-11-25 18:00:26 +00:00
}
2011-12-14 13:57:27 +01:00
if ( unlikely ( ( reloc - > write_domain | reloc - > read_domains )
& ~ I915_GEM_GPU_DOMAINS ) ) {
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " reloc with read/write non-GPU domains: "
2010-11-25 18:00:26 +00:00
" obj %p target %d offset %d "
" read %08x write %08x " ,
obj , reloc - > target_handle ,
( int ) reloc - > offset ,
reloc - > read_domains ,
reloc - > write_domain ) ;
2010-12-08 10:38:14 +00:00
return ret ;
2010-11-25 18:00:26 +00:00
}
2010-12-08 10:43:06 +00:00
if ( unlikely ( reloc - > write_domain & & target_obj - > pending_write_domain & &
reloc - > write_domain ! = target_obj - > pending_write_domain ) ) {
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " Write domain conflict: "
2010-11-25 18:00:26 +00:00
" obj %p target %d offset %d "
" new %08x old %08x \n " ,
obj , reloc - > target_handle ,
( int ) reloc - > offset ,
reloc - > write_domain ,
target_obj - > pending_write_domain ) ;
2010-12-08 10:38:14 +00:00
return ret ;
2010-11-25 18:00:26 +00:00
}
target_obj - > pending_read_domains | = reloc - > read_domains ;
target_obj - > pending_write_domain | = reloc - > write_domain ;
/* If the relocation already has the right value in it, no
* more work needs to be done .
*/
if ( target_offset = = reloc - > presumed_offset )
2010-12-08 10:38:14 +00:00
return 0 ;
2010-11-25 18:00:26 +00:00
/* Check that the relocation address is valid... */
2010-12-08 10:43:06 +00:00
if ( unlikely ( reloc - > offset > obj - > base . size - 4 ) ) {
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " Relocation beyond object bounds: "
2010-11-25 18:00:26 +00:00
" obj %p target %d offset %d size %d. \n " ,
obj , reloc - > target_handle ,
( int ) reloc - > offset ,
( int ) obj - > base . size ) ;
2010-12-08 10:38:14 +00:00
return ret ;
2010-11-25 18:00:26 +00:00
}
2010-12-08 10:43:06 +00:00
if ( unlikely ( reloc - > offset & 3 ) ) {
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " Relocation not 4-byte aligned: "
2010-11-25 18:00:26 +00:00
" obj %p target %d offset %d. \n " ,
obj , reloc - > target_handle ,
( int ) reloc - > offset ) ;
2010-12-08 10:38:14 +00:00
return ret ;
2010-11-25 18:00:26 +00:00
}
2012-03-26 10:10:27 +02:00
/* We can't wait for rendering with pagefaults disabled */
if ( obj - > active & & in_atomic ( ) )
return - EFAULT ;
2010-11-25 18:00:26 +00:00
reloc - > delta + = target_offset ;
2012-03-26 10:10:27 +02:00
if ( use_cpu_reloc ( obj ) ) {
2010-11-25 18:00:26 +00:00
uint32_t page_offset = reloc - > offset & ~ PAGE_MASK ;
char * vaddr ;
2012-03-26 10:10:27 +02:00
ret = i915_gem_object_set_to_cpu_domain ( obj , 1 ) ;
if ( ret )
return ret ;
2010-11-25 18:00:26 +00:00
vaddr = kmap_atomic ( obj - > pages [ reloc - > offset > > PAGE_SHIFT ] ) ;
* ( uint32_t * ) ( vaddr + page_offset ) = reloc - > delta ;
kunmap_atomic ( vaddr ) ;
} else {
struct drm_i915_private * dev_priv = dev - > dev_private ;
uint32_t __iomem * reloc_entry ;
void __iomem * reloc_page ;
2012-04-14 09:55:51 +01:00
ret = i915_gem_object_set_to_gtt_domain ( obj , true ) ;
if ( ret )
return ret ;
ret = i915_gem_object_put_fence ( obj ) ;
2010-11-25 18:00:26 +00:00
if ( ret )
2010-12-08 10:38:14 +00:00
return ret ;
2010-11-25 18:00:26 +00:00
/* Map the page containing the relocation we're going to perform. */
reloc - > offset + = obj - > gtt_offset ;
reloc_page = io_mapping_map_atomic_wc ( dev_priv - > mm . gtt_mapping ,
reloc - > offset & PAGE_MASK ) ;
reloc_entry = ( uint32_t __iomem * )
( reloc_page + ( reloc - > offset & ~ PAGE_MASK ) ) ;
iowrite32 ( reloc - > delta , reloc_entry ) ;
io_mapping_unmap_atomic ( reloc_page ) ;
}
2012-02-15 23:50:23 +01:00
/* Sandybridge PPGTT errata: We need a global gtt mapping for MI and
* pipe_control writes because the gpu doesn ' t properly redirect them
* through the ppgtt for non_secure batchbuffers . */
if ( unlikely ( IS_GEN6 ( dev ) & &
reloc - > write_domain = = I915_GEM_DOMAIN_INSTRUCTION & &
! target_i915_obj - > has_global_gtt_mapping ) ) {
i915_gem_gtt_bind_object ( target_i915_obj ,
target_i915_obj - > cache_level ) ;
}
2010-11-25 18:00:26 +00:00
/* and update the user's relocation entry */
reloc - > presumed_offset = target_offset ;
2010-12-08 10:38:14 +00:00
return 0 ;
2010-11-25 18:00:26 +00:00
}
static int
i915_gem_execbuffer_relocate_object ( struct drm_i915_gem_object * obj ,
2011-01-10 17:35:37 +00:00
struct eb_objects * eb )
2010-11-25 18:00:26 +00:00
{
2012-03-24 20:12:53 +00:00
# define N_RELOC(x) ((x) / sizeof(struct drm_i915_gem_relocation_entry))
struct drm_i915_gem_relocation_entry stack_reloc [ N_RELOC ( 512 ) ] ;
2010-11-25 18:00:26 +00:00
struct drm_i915_gem_relocation_entry __user * user_relocs ;
2011-01-10 17:35:37 +00:00
struct drm_i915_gem_exec_object2 * entry = obj - > exec_entry ;
2012-03-24 20:12:53 +00:00
int remain , ret ;
2010-11-25 18:00:26 +00:00
user_relocs = ( void __user * ) ( uintptr_t ) entry - > relocs_ptr ;
2012-03-24 20:12:53 +00:00
remain = entry - > relocation_count ;
while ( remain ) {
struct drm_i915_gem_relocation_entry * r = stack_reloc ;
int count = remain ;
if ( count > ARRAY_SIZE ( stack_reloc ) )
count = ARRAY_SIZE ( stack_reloc ) ;
remain - = count ;
if ( __copy_from_user_inatomic ( r , user_relocs , count * sizeof ( r [ 0 ] ) ) )
2010-11-25 18:00:26 +00:00
return - EFAULT ;
2012-03-24 20:12:53 +00:00
do {
u64 offset = r - > presumed_offset ;
2010-11-25 18:00:26 +00:00
2012-03-24 20:12:53 +00:00
ret = i915_gem_execbuffer_relocate_entry ( obj , eb , r ) ;
if ( ret )
return ret ;
if ( r - > presumed_offset ! = offset & &
__copy_to_user_inatomic ( & user_relocs - > presumed_offset ,
& r - > presumed_offset ,
sizeof ( r - > presumed_offset ) ) ) {
return - EFAULT ;
}
user_relocs + + ;
r + + ;
} while ( - - count ) ;
2010-11-25 18:00:26 +00:00
}
return 0 ;
2012-03-24 20:12:53 +00:00
# undef N_RELOC
2010-11-25 18:00:26 +00:00
}
static int
i915_gem_execbuffer_relocate_object_slow ( struct drm_i915_gem_object * obj ,
2010-12-08 10:38:14 +00:00
struct eb_objects * eb ,
2010-11-25 18:00:26 +00:00
struct drm_i915_gem_relocation_entry * relocs )
{
2011-01-10 17:35:37 +00:00
const struct drm_i915_gem_exec_object2 * entry = obj - > exec_entry ;
2010-11-25 18:00:26 +00:00
int i , ret ;
for ( i = 0 ; i < entry - > relocation_count ; i + + ) {
2011-01-10 17:35:37 +00:00
ret = i915_gem_execbuffer_relocate_entry ( obj , eb , & relocs [ i ] ) ;
2010-11-25 18:00:26 +00:00
if ( ret )
return ret ;
}
return 0 ;
}
static int
i915_gem_execbuffer_relocate ( struct drm_device * dev ,
2010-12-08 10:38:14 +00:00
struct eb_objects * eb ,
2011-01-10 17:35:37 +00:00
struct list_head * objects )
2010-11-25 18:00:26 +00:00
{
2010-11-25 19:32:06 +00:00
struct drm_i915_gem_object * obj ;
2011-03-14 15:11:24 +00:00
int ret = 0 ;
/* This is the fast path and we cannot handle a pagefault whilst
* holding the struct mutex lest the user pass in the relocations
* contained within a mmaped bo . For in such a case we , the page
* fault handler would call i915_gem_fault ( ) and we would try to
* acquire the struct mutex again . Obviously this is bad and so
* lockdep complains vehemently .
*/
pagefault_disable ( ) ;
2010-11-25 19:32:06 +00:00
list_for_each_entry ( obj , objects , exec_list ) {
2011-01-10 17:35:37 +00:00
ret = i915_gem_execbuffer_relocate_object ( obj , eb ) ;
2010-11-25 18:00:26 +00:00
if ( ret )
2011-03-14 15:11:24 +00:00
break ;
2010-11-25 18:00:26 +00:00
}
2011-03-14 15:11:24 +00:00
pagefault_enable ( ) ;
2010-11-25 18:00:26 +00:00
2011-03-14 15:11:24 +00:00
return ret ;
2010-11-25 18:00:26 +00:00
}
2011-12-14 13:57:08 +01:00
# define __EXEC_OBJECT_HAS_FENCE (1<<31)
2012-03-26 10:10:27 +02:00
static int
need_reloc_mappable ( struct drm_i915_gem_object * obj )
{
struct drm_i915_gem_exec_object2 * entry = obj - > exec_entry ;
return entry - > relocation_count & & ! use_cpu_reloc ( obj ) ;
}
2011-12-14 13:57:08 +01:00
static int
pin_and_fence_object ( struct drm_i915_gem_object * obj ,
struct intel_ring_buffer * ring )
{
struct drm_i915_gem_exec_object2 * entry = obj - > exec_entry ;
bool has_fenced_gpu_access = INTEL_INFO ( ring - > dev ) - > gen < 4 ;
bool need_fence , need_mappable ;
int ret ;
need_fence =
has_fenced_gpu_access & &
entry - > flags & EXEC_OBJECT_NEEDS_FENCE & &
obj - > tiling_mode ! = I915_TILING_NONE ;
2012-03-26 10:10:27 +02:00
need_mappable = need_fence | | need_reloc_mappable ( obj ) ;
2011-12-14 13:57:08 +01:00
ret = i915_gem_object_pin ( obj , entry - > alignment , need_mappable ) ;
if ( ret )
return ret ;
if ( has_fenced_gpu_access ) {
if ( entry - > flags & EXEC_OBJECT_NEEDS_FENCE ) {
2012-04-17 15:31:24 +01:00
ret = i915_gem_object_get_fence ( obj ) ;
2012-03-22 15:10:00 +00:00
if ( ret )
goto err_unpin ;
2011-12-14 13:57:08 +01:00
2012-03-22 15:10:00 +00:00
if ( i915_gem_object_pin_fence ( obj ) )
2011-12-14 13:57:08 +01:00
entry - > flags | = __EXEC_OBJECT_HAS_FENCE ;
2012-03-22 15:10:00 +00:00
2012-03-21 10:48:18 +00:00
obj - > pending_fenced_gpu_access = true ;
2011-12-14 13:57:08 +01:00
}
}
entry - > offset = obj - > gtt_offset ;
return 0 ;
err_unpin :
i915_gem_object_unpin ( obj ) ;
return ret ;
}
2010-11-25 18:00:26 +00:00
static int
2010-11-10 16:40:20 +00:00
i915_gem_execbuffer_reserve ( struct intel_ring_buffer * ring ,
2010-11-25 18:00:26 +00:00
struct drm_file * file ,
2011-01-10 17:35:37 +00:00
struct list_head * objects )
2010-11-25 18:00:26 +00:00
{
2012-02-09 17:15:47 +01:00
drm_i915_private_t * dev_priv = ring - > dev - > dev_private ;
2010-11-25 19:32:06 +00:00
struct drm_i915_gem_object * obj ;
int ret , retry ;
2010-12-05 17:11:54 +00:00
bool has_fenced_gpu_access = INTEL_INFO ( ring - > dev ) - > gen < 4 ;
2011-01-10 17:35:37 +00:00
struct list_head ordered_objects ;
INIT_LIST_HEAD ( & ordered_objects ) ;
while ( ! list_empty ( objects ) ) {
struct drm_i915_gem_exec_object2 * entry ;
bool need_fence , need_mappable ;
obj = list_first_entry ( objects ,
struct drm_i915_gem_object ,
exec_list ) ;
entry = obj - > exec_entry ;
need_fence =
has_fenced_gpu_access & &
entry - > flags & EXEC_OBJECT_NEEDS_FENCE & &
obj - > tiling_mode ! = I915_TILING_NONE ;
2012-03-26 10:10:27 +02:00
need_mappable = need_fence | | need_reloc_mappable ( obj ) ;
2011-01-10 17:35:37 +00:00
if ( need_mappable )
list_move ( & obj - > exec_list , & ordered_objects ) ;
else
list_move_tail ( & obj - > exec_list , & ordered_objects ) ;
2011-01-13 11:03:48 +00:00
obj - > base . pending_read_domains = 0 ;
obj - > base . pending_write_domain = 0 ;
2012-07-20 12:41:07 +01:00
obj - > pending_fenced_gpu_access = false ;
2011-01-10 17:35:37 +00:00
}
list_splice ( & ordered_objects , objects ) ;
2010-11-25 18:00:26 +00:00
/* Attempt to pin all of the buffers into the GTT.
* This is done in 3 phases :
*
* 1 a . Unbind all objects that do not match the GTT constraints for
* the execbuffer ( fenceable , mappable , alignment etc ) .
* 1 b . Increment pin count for already bound objects .
* 2. Bind new objects .
* 3. Decrement pin count .
*
* This avoid unnecessary unbinding of later objects in order to makr
* room for the earlier objects * unless * we need to defragment .
*/
retry = 0 ;
do {
ret = 0 ;
/* Unbind any ill-fitting objects or pin. */
2010-11-25 19:32:06 +00:00
list_for_each_entry ( obj , objects , exec_list ) {
2011-01-10 17:35:37 +00:00
struct drm_i915_gem_exec_object2 * entry = obj - > exec_entry ;
2010-11-25 18:00:26 +00:00
bool need_fence , need_mappable ;
2011-12-14 13:57:08 +01:00
2011-01-10 17:35:37 +00:00
if ( ! obj - > gtt_space )
2010-11-25 18:00:26 +00:00
continue ;
need_fence =
2010-12-05 17:11:54 +00:00
has_fenced_gpu_access & &
2010-11-25 18:00:26 +00:00
entry - > flags & EXEC_OBJECT_NEEDS_FENCE & &
obj - > tiling_mode ! = I915_TILING_NONE ;
2012-03-26 10:10:27 +02:00
need_mappable = need_fence | | need_reloc_mappable ( obj ) ;
2010-11-25 18:00:26 +00:00
if ( ( entry - > alignment & & obj - > gtt_offset & ( entry - > alignment - 1 ) ) | |
( need_mappable & & ! obj - > map_and_fenceable ) )
ret = i915_gem_object_unbind ( obj ) ;
else
2011-12-14 13:57:08 +01:00
ret = pin_and_fence_object ( obj , ring ) ;
2010-11-25 19:32:06 +00:00
if ( ret )
2010-11-25 18:00:26 +00:00
goto err ;
}
/* Bind fresh objects */
2010-11-25 19:32:06 +00:00
list_for_each_entry ( obj , objects , exec_list ) {
2011-12-14 13:57:08 +01:00
if ( obj - > gtt_space )
continue ;
2010-11-25 18:00:26 +00:00
2011-12-14 13:57:08 +01:00
ret = pin_and_fence_object ( obj , ring ) ;
if ( ret ) {
int ret_ignore ;
/* This can potentially raise a harmless
* - EINVAL if we failed to bind in the above
* call . It cannot raise - EINTR since we know
* that the bo is freshly bound and so will
* not need to be flushed or waited upon .
*/
ret_ignore = i915_gem_object_unbind ( obj ) ;
( void ) ret_ignore ;
WARN_ON ( obj - > gtt_space ) ;
break ;
2010-11-25 18:00:26 +00:00
}
}
2010-11-25 19:32:06 +00:00
/* Decrement pin count for bound objects */
list_for_each_entry ( obj , objects , exec_list ) {
2011-12-14 13:57:08 +01:00
struct drm_i915_gem_exec_object2 * entry ;
if ( ! obj - > gtt_space )
continue ;
entry = obj - > exec_entry ;
if ( entry - > flags & __EXEC_OBJECT_HAS_FENCE ) {
i915_gem_object_unpin_fence ( obj ) ;
entry - > flags & = ~ __EXEC_OBJECT_HAS_FENCE ;
}
i915_gem_object_unpin ( obj ) ;
2012-02-09 17:15:47 +01:00
/* ... and ensure ppgtt mapping exist if needed. */
if ( dev_priv - > mm . aliasing_ppgtt & & ! obj - > has_aliasing_ppgtt_mapping ) {
i915_ppgtt_bind_object ( dev_priv - > mm . aliasing_ppgtt ,
obj , obj - > cache_level ) ;
obj - > has_aliasing_ppgtt_mapping = 1 ;
}
2010-11-25 18:00:26 +00:00
}
if ( ret ! = - ENOSPC | | retry > 1 )
return ret ;
/* First attempt, just clear anything that is purgeable.
* Second attempt , clear the entire GTT .
*/
2010-11-10 16:40:20 +00:00
ret = i915_gem_evict_everything ( ring - > dev , retry = = 0 ) ;
2010-11-25 18:00:26 +00:00
if ( ret )
return ret ;
retry + + ;
} while ( 1 ) ;
2010-11-25 19:32:06 +00:00
err :
2011-12-14 13:57:08 +01:00
list_for_each_entry_continue_reverse ( obj , objects , exec_list ) {
struct drm_i915_gem_exec_object2 * entry ;
if ( ! obj - > gtt_space )
continue ;
entry = obj - > exec_entry ;
if ( entry - > flags & __EXEC_OBJECT_HAS_FENCE ) {
i915_gem_object_unpin_fence ( obj ) ;
entry - > flags & = ~ __EXEC_OBJECT_HAS_FENCE ;
}
2010-11-25 19:32:06 +00:00
2011-12-14 13:57:08 +01:00
i915_gem_object_unpin ( obj ) ;
2010-11-25 19:32:06 +00:00
}
return ret ;
2010-11-25 18:00:26 +00:00
}
static int
i915_gem_execbuffer_relocate_slow ( struct drm_device * dev ,
struct drm_file * file ,
2010-11-10 16:40:20 +00:00
struct intel_ring_buffer * ring ,
2010-11-25 19:32:06 +00:00
struct list_head * objects ,
2010-12-08 10:38:14 +00:00
struct eb_objects * eb ,
2010-11-25 19:32:06 +00:00
struct drm_i915_gem_exec_object2 * exec ,
2010-11-25 18:00:26 +00:00
int count )
{
struct drm_i915_gem_relocation_entry * reloc ;
2010-11-25 19:32:06 +00:00
struct drm_i915_gem_object * obj ;
2011-01-12 23:49:13 +00:00
int * reloc_offset ;
2010-11-25 18:00:26 +00:00
int i , total , ret ;
2010-12-08 10:38:14 +00:00
/* We may process another execbuffer during the unlock... */
2011-01-10 12:09:12 +00:00
while ( ! list_empty ( objects ) ) {
2010-12-08 10:38:14 +00:00
obj = list_first_entry ( objects ,
struct drm_i915_gem_object ,
exec_list ) ;
list_del_init ( & obj - > exec_list ) ;
drm_gem_object_unreference ( & obj - > base ) ;
}
2010-11-25 18:00:26 +00:00
mutex_unlock ( & dev - > struct_mutex ) ;
total = 0 ;
for ( i = 0 ; i < count ; i + + )
2010-11-25 19:32:06 +00:00
total + = exec [ i ] . relocation_count ;
2010-11-25 18:00:26 +00:00
2011-01-12 23:49:13 +00:00
reloc_offset = drm_malloc_ab ( count , sizeof ( * reloc_offset ) ) ;
2010-11-25 18:00:26 +00:00
reloc = drm_malloc_ab ( total , sizeof ( * reloc ) ) ;
2011-01-12 23:49:13 +00:00
if ( reloc = = NULL | | reloc_offset = = NULL ) {
drm_free_large ( reloc ) ;
drm_free_large ( reloc_offset ) ;
2010-11-25 18:00:26 +00:00
mutex_lock ( & dev - > struct_mutex ) ;
return - ENOMEM ;
}
total = 0 ;
for ( i = 0 ; i < count ; i + + ) {
struct drm_i915_gem_relocation_entry __user * user_relocs ;
2010-11-25 19:32:06 +00:00
user_relocs = ( void __user * ) ( uintptr_t ) exec [ i ] . relocs_ptr ;
2010-11-25 18:00:26 +00:00
if ( copy_from_user ( reloc + total , user_relocs ,
2010-11-25 19:32:06 +00:00
exec [ i ] . relocation_count * sizeof ( * reloc ) ) ) {
2010-11-25 18:00:26 +00:00
ret = - EFAULT ;
mutex_lock ( & dev - > struct_mutex ) ;
goto err ;
}
2011-01-12 23:49:13 +00:00
reloc_offset [ i ] = total ;
2010-11-25 19:32:06 +00:00
total + = exec [ i ] . relocation_count ;
2010-11-25 18:00:26 +00:00
}
ret = i915_mutex_lock_interruptible ( dev ) ;
if ( ret ) {
mutex_lock ( & dev - > struct_mutex ) ;
goto err ;
}
2010-12-08 10:38:14 +00:00
/* reacquire the objects */
eb_reset ( eb ) ;
for ( i = 0 ; i < count ; i + + ) {
obj = to_intel_bo ( drm_gem_object_lookup ( dev , file ,
exec [ i ] . handle ) ) ;
2011-02-19 11:31:06 +00:00
if ( & obj - > base = = NULL ) {
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " Invalid object handle %d at index %d \n " ,
2010-12-08 10:38:14 +00:00
exec [ i ] . handle , i ) ;
ret = - ENOENT ;
goto err ;
}
list_add_tail ( & obj - > exec_list , objects ) ;
obj - > exec_handle = exec [ i ] . handle ;
2011-01-10 17:35:37 +00:00
obj - > exec_entry = & exec [ i ] ;
2010-12-08 10:38:14 +00:00
eb_add_object ( eb , obj ) ;
}
2011-01-10 17:35:37 +00:00
ret = i915_gem_execbuffer_reserve ( ring , file , objects ) ;
2010-11-25 18:00:26 +00:00
if ( ret )
goto err ;
2010-11-25 19:32:06 +00:00
list_for_each_entry ( obj , objects , exec_list ) {
2011-01-12 23:49:13 +00:00
int offset = obj - > exec_entry - exec ;
2010-12-08 10:38:14 +00:00
ret = i915_gem_execbuffer_relocate_object_slow ( obj , eb ,
2011-01-12 23:49:13 +00:00
reloc + reloc_offset [ offset ] ) ;
2010-11-25 18:00:26 +00:00
if ( ret )
goto err ;
}
/* Leave the user relocations as are, this is the painfully slow path,
* and we want to avoid the complication of dropping the lock whilst
* having buffers reserved in the aperture and so causing spurious
* ENOSPC for random operations .
*/
err :
drm_free_large ( reloc ) ;
2011-01-12 23:49:13 +00:00
drm_free_large ( reloc_offset ) ;
2010-11-25 18:00:26 +00:00
return ret ;
}
2011-03-06 13:51:29 +00:00
static int
i915_gem_execbuffer_wait_for_flips ( struct intel_ring_buffer * ring , u32 flips )
{
u32 plane , flip_mask ;
int ret ;
/* Check for any pending flips. As we only maintain a flip queue depth
* of 1 , we can simply insert a WAIT for the next display flip prior
* to executing the batch and avoid stalling the CPU .
*/
for ( plane = 0 ; flips > > plane ; plane + + ) {
if ( ( ( flips > > plane ) & 1 ) = = 0 )
continue ;
if ( plane )
flip_mask = MI_WAIT_FOR_PLANE_B_FLIP ;
else
flip_mask = MI_WAIT_FOR_PLANE_A_FLIP ;
ret = intel_ring_begin ( ring , 2 ) ;
if ( ret )
return ret ;
intel_ring_emit ( ring , MI_WAIT_FOR_EVENT | flip_mask ) ;
intel_ring_emit ( ring , MI_NOOP ) ;
intel_ring_advance ( ring ) ;
}
return 0 ;
}
2010-11-25 18:00:26 +00:00
static int
2010-11-25 19:32:06 +00:00
i915_gem_execbuffer_move_to_gpu ( struct intel_ring_buffer * ring ,
struct list_head * objects )
2010-11-25 18:00:26 +00:00
{
2010-11-25 19:32:06 +00:00
struct drm_i915_gem_object * obj ;
2012-07-21 12:25:01 +02:00
uint32_t flush_domains = 0 ;
uint32_t flips = 0 ;
2010-11-25 19:32:06 +00:00
int ret ;
2010-11-25 18:00:26 +00:00
2012-07-21 12:25:01 +02:00
list_for_each_entry ( obj , objects , exec_list ) {
ret = i915_gem_object_sync ( obj , ring ) ;
2011-03-06 13:51:29 +00:00
if ( ret )
return ret ;
2012-07-21 12:25:01 +02:00
if ( obj - > base . write_domain & I915_GEM_DOMAIN_CPU )
i915_gem_clflush_object ( obj ) ;
if ( obj - > base . pending_write_domain )
flips | = atomic_read ( & obj - > pending_flip ) ;
flush_domains | = obj - > base . write_domain ;
2011-03-06 13:51:29 +00:00
}
2012-07-21 12:25:01 +02:00
if ( flips ) {
ret = i915_gem_execbuffer_wait_for_flips ( ring , flips ) ;
2010-12-04 11:30:53 +00:00
if ( ret )
return ret ;
2010-11-25 18:00:26 +00:00
}
2012-07-21 12:25:01 +02:00
if ( flush_domains & I915_GEM_DOMAIN_CPU )
intel_gtt_chipset_flush ( ) ;
if ( flush_domains & I915_GEM_DOMAIN_GTT )
wmb ( ) ;
2012-07-13 14:14:08 +01:00
/* Unconditionally invalidate gpu caches and ensure that we do flush
* any residual writes from the previous batch .
*/
ret = i915_gem_flush_ring ( ring ,
I915_GEM_GPU_DOMAINS ,
ring - > gpu_caches_dirty ? I915_GEM_GPU_DOMAINS : 0 ) ;
2012-06-13 20:45:19 +02:00
if ( ret )
return ret ;
2012-07-13 14:14:08 +01:00
ring - > gpu_caches_dirty = false ;
2010-11-25 18:00:26 +00:00
return 0 ;
}
2010-11-25 19:32:06 +00:00
static bool
i915_gem_check_execbuffer ( struct drm_i915_gem_execbuffer2 * exec )
2010-11-25 18:00:26 +00:00
{
2010-11-25 19:32:06 +00:00
return ( ( exec - > batch_start_offset | exec - > batch_len ) & 0x7 ) = = 0 ;
2010-11-25 18:00:26 +00:00
}
static int
validate_exec_list ( struct drm_i915_gem_exec_object2 * exec ,
int count )
{
int i ;
for ( i = 0 ; i < count ; i + + ) {
char __user * ptr = ( char __user * ) ( uintptr_t ) exec [ i ] . relocs_ptr ;
int length ; /* limited by fault_in_pages_readable() */
/* First check for malicious input causing overflow */
if ( exec [ i ] . relocation_count >
INT_MAX / sizeof ( struct drm_i915_gem_relocation_entry ) )
return - EINVAL ;
length = exec [ i ] . relocation_count *
sizeof ( struct drm_i915_gem_relocation_entry ) ;
if ( ! access_ok ( VERIFY_READ , ptr , length ) )
return - EFAULT ;
/* we may also need to update the presumed offsets */
if ( ! access_ok ( VERIFY_WRITE , ptr , length ) )
return - EFAULT ;
2012-03-25 19:47:41 +02:00
if ( fault_in_multipages_readable ( ptr , length ) )
2010-11-25 18:00:26 +00:00
return - EFAULT ;
}
return 0 ;
}
2010-11-25 19:32:06 +00:00
static void
i915_gem_execbuffer_move_to_active ( struct list_head * objects ,
2010-12-04 11:30:53 +00:00
struct intel_ring_buffer * ring ,
u32 seqno )
2010-11-25 19:32:06 +00:00
{
struct drm_i915_gem_object * obj ;
list_for_each_entry ( obj , objects , exec_list ) {
2012-07-20 12:41:03 +01:00
u32 old_read = obj - > base . read_domains ;
u32 old_write = obj - > base . write_domain ;
2011-02-03 11:57:46 +00:00
2010-11-25 19:32:06 +00:00
obj - > base . read_domains = obj - > base . pending_read_domains ;
obj - > base . write_domain = obj - > base . pending_write_domain ;
obj - > fenced_gpu_access = obj - > pending_fenced_gpu_access ;
2010-12-04 11:30:53 +00:00
i915_gem_object_move_to_active ( obj , ring , seqno ) ;
2010-11-25 19:32:06 +00:00
if ( obj - > base . write_domain ) {
obj - > dirty = 1 ;
2012-07-20 12:41:01 +01:00
obj - > last_write_seqno = seqno ;
2012-05-03 15:47:57 +01:00
if ( obj - > pin_count ) /* check for potential scanout */
intel_mark_busy ( ring - > dev , obj ) ;
2010-11-25 19:32:06 +00:00
}
2011-02-03 11:57:46 +00:00
trace_i915_gem_object_change_domain ( obj , old_read , old_write ) ;
2010-11-25 19:32:06 +00:00
}
2012-05-03 15:47:57 +01:00
intel_mark_busy ( ring - > dev , NULL ) ;
2010-11-25 19:32:06 +00:00
}
2010-11-25 18:00:26 +00:00
static void
i915_gem_execbuffer_retire_commands ( struct drm_device * dev ,
2010-11-25 19:32:06 +00:00
struct drm_file * file ,
2010-11-25 18:00:26 +00:00
struct intel_ring_buffer * ring )
{
2012-06-13 20:45:19 +02:00
/* Unconditionally force add_request to emit a full flush. */
ring - > gpu_caches_dirty = true ;
2010-11-25 18:00:26 +00:00
2010-11-25 19:32:06 +00:00
/* Add a breadcrumb for the completion of the batch buffer */
2012-07-20 12:40:59 +01:00
( void ) i915_add_request ( ring , file , NULL ) ;
2010-11-25 19:32:06 +00:00
}
2010-11-25 18:00:26 +00:00
2012-01-03 09:23:29 -08:00
static int
i915_reset_gen7_sol_offsets ( struct drm_device * dev ,
struct intel_ring_buffer * ring )
{
drm_i915_private_t * dev_priv = dev - > dev_private ;
int ret , i ;
if ( ! IS_GEN7 ( dev ) | | ring ! = & dev_priv - > ring [ RCS ] )
return 0 ;
ret = intel_ring_begin ( ring , 4 * 3 ) ;
if ( ret )
return ret ;
for ( i = 0 ; i < 4 ; i + + ) {
intel_ring_emit ( ring , MI_LOAD_REGISTER_IMM ( 1 ) ) ;
intel_ring_emit ( ring , GEN7_SO_WRITE_OFFSET ( i ) ) ;
intel_ring_emit ( ring , 0 ) ;
}
intel_ring_advance ( ring ) ;
return 0 ;
}
2010-11-25 18:00:26 +00:00
static int
i915_gem_do_execbuffer ( struct drm_device * dev , void * data ,
struct drm_file * file ,
struct drm_i915_gem_execbuffer2 * args ,
2010-11-25 19:32:06 +00:00
struct drm_i915_gem_exec_object2 * exec )
2010-11-25 18:00:26 +00:00
{
drm_i915_private_t * dev_priv = dev - > dev_private ;
2010-11-25 19:32:06 +00:00
struct list_head objects ;
2010-12-08 10:38:14 +00:00
struct eb_objects * eb ;
2010-11-25 18:00:26 +00:00
struct drm_i915_gem_object * batch_obj ;
struct drm_clip_rect * cliprects = NULL ;
struct intel_ring_buffer * ring ;
2012-06-04 14:42:55 -07:00
u32 ctx_id = i915_execbuffer2_get_context_id ( * args ) ;
2010-11-30 14:10:25 +00:00
u32 exec_start , exec_len ;
2010-12-04 11:30:53 +00:00
u32 seqno ;
2011-12-12 19:21:58 -08:00
u32 mask ;
2010-12-19 11:42:05 +00:00
int ret , mode , i ;
2010-11-25 18:00:26 +00:00
2010-11-25 19:32:06 +00:00
if ( ! i915_gem_check_execbuffer ( args ) ) {
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " execbuf with invalid offset/length \n " ) ;
2010-11-25 19:32:06 +00:00
return - EINVAL ;
}
ret = validate_exec_list ( exec , args - > buffer_count ) ;
2010-11-25 18:00:26 +00:00
if ( ret )
return ret ;
switch ( args - > flags & I915_EXEC_RING_MASK ) {
case I915_EXEC_DEFAULT :
case I915_EXEC_RENDER :
2010-12-04 11:30:53 +00:00
ring = & dev_priv - > ring [ RCS ] ;
2010-11-25 18:00:26 +00:00
break ;
case I915_EXEC_BSD :
2010-12-04 11:30:53 +00:00
ring = & dev_priv - > ring [ VCS ] ;
2012-06-04 14:42:55 -07:00
if ( ctx_id ! = 0 ) {
DRM_DEBUG ( " Ring %s doesn't support contexts \n " ,
ring - > name ) ;
return - EPERM ;
}
2010-11-25 18:00:26 +00:00
break ;
case I915_EXEC_BLT :
2010-12-04 11:30:53 +00:00
ring = & dev_priv - > ring [ BCS ] ;
2012-06-04 14:42:55 -07:00
if ( ctx_id ! = 0 ) {
DRM_DEBUG ( " Ring %s doesn't support contexts \n " ,
ring - > name ) ;
return - EPERM ;
}
2010-11-25 18:00:26 +00:00
break ;
default :
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " execbuf with unknown ring: %d \n " ,
2010-11-25 18:00:26 +00:00
( int ) ( args - > flags & I915_EXEC_RING_MASK ) ) ;
return - EINVAL ;
}
2012-05-11 14:29:31 +01:00
if ( ! intel_ring_initialized ( ring ) ) {
DRM_DEBUG ( " execbuf with invalid ring: %d \n " ,
( int ) ( args - > flags & I915_EXEC_RING_MASK ) ) ;
return - EINVAL ;
}
2010-11-25 18:00:26 +00:00
2010-12-19 11:42:05 +00:00
mode = args - > flags & I915_EXEC_CONSTANTS_MASK ;
2011-12-12 19:21:58 -08:00
mask = I915_EXEC_CONSTANTS_MASK ;
2010-12-19 11:42:05 +00:00
switch ( mode ) {
case I915_EXEC_CONSTANTS_REL_GENERAL :
case I915_EXEC_CONSTANTS_ABSOLUTE :
case I915_EXEC_CONSTANTS_REL_SURFACE :
if ( ring = = & dev_priv - > ring [ RCS ] & &
mode ! = dev_priv - > relative_constants_mode ) {
if ( INTEL_INFO ( dev ) - > gen < 4 )
return - EINVAL ;
if ( INTEL_INFO ( dev ) - > gen > 5 & &
mode = = I915_EXEC_CONSTANTS_REL_SURFACE )
return - EINVAL ;
2011-12-12 19:21:58 -08:00
/* The HW changed the meaning on this bit on gen6 */
if ( INTEL_INFO ( dev ) - > gen > = 6 )
mask & = ~ I915_EXEC_CONSTANTS_REL_SURFACE ;
2010-12-19 11:42:05 +00:00
}
break ;
default :
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " execbuf with unknown constants: %d \n " , mode ) ;
2010-12-19 11:42:05 +00:00
return - EINVAL ;
}
2010-11-25 18:00:26 +00:00
if ( args - > buffer_count < 1 ) {
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " execbuf with %d buffers \n " , args - > buffer_count ) ;
2010-11-25 18:00:26 +00:00
return - EINVAL ;
}
if ( args - > num_cliprects ! = 0 ) {
2010-12-04 11:30:53 +00:00
if ( ring ! = & dev_priv - > ring [ RCS ] ) {
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " clip rectangles are only valid with the render ring \n " ) ;
2010-11-30 14:10:25 +00:00
return - EINVAL ;
}
2012-04-26 23:28:11 +02:00
if ( INTEL_INFO ( dev ) - > gen > = 5 ) {
DRM_DEBUG ( " clip rectangles are only valid on pre-gen5 \n " ) ;
return - EINVAL ;
}
2012-04-23 04:06:42 -04:00
if ( args - > num_cliprects > UINT_MAX / sizeof ( * cliprects ) ) {
DRM_DEBUG ( " execbuf with %u cliprects \n " ,
args - > num_cliprects ) ;
return - EINVAL ;
}
2012-05-08 13:39:59 +02:00
2010-11-25 19:32:06 +00:00
cliprects = kmalloc ( args - > num_cliprects * sizeof ( * cliprects ) ,
2010-11-25 18:00:26 +00:00
GFP_KERNEL ) ;
if ( cliprects = = NULL ) {
ret = - ENOMEM ;
goto pre_mutex_err ;
}
2010-11-25 19:32:06 +00:00
if ( copy_from_user ( cliprects ,
( struct drm_clip_rect __user * ) ( uintptr_t )
args - > cliprects_ptr ,
sizeof ( * cliprects ) * args - > num_cliprects ) ) {
2010-11-25 18:00:26 +00:00
ret = - EFAULT ;
goto pre_mutex_err ;
}
}
ret = i915_mutex_lock_interruptible ( dev ) ;
if ( ret )
goto pre_mutex_err ;
if ( dev_priv - > mm . suspended ) {
mutex_unlock ( & dev - > struct_mutex ) ;
ret = - EBUSY ;
goto pre_mutex_err ;
}
2010-12-08 10:38:14 +00:00
eb = eb_create ( args - > buffer_count ) ;
if ( eb = = NULL ) {
mutex_unlock ( & dev - > struct_mutex ) ;
ret = - ENOMEM ;
goto pre_mutex_err ;
}
2010-11-25 18:00:26 +00:00
/* Look up object handles */
2010-11-25 19:32:06 +00:00
INIT_LIST_HEAD ( & objects ) ;
2010-11-25 18:00:26 +00:00
for ( i = 0 ; i < args - > buffer_count ; i + + ) {
struct drm_i915_gem_object * obj ;
2010-11-25 19:32:06 +00:00
obj = to_intel_bo ( drm_gem_object_lookup ( dev , file ,
exec [ i ] . handle ) ) ;
2011-02-19 11:31:06 +00:00
if ( & obj - > base = = NULL ) {
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " Invalid object handle %d at index %d \n " ,
2010-11-25 19:32:06 +00:00
exec [ i ] . handle , i ) ;
2010-11-25 18:00:26 +00:00
/* prevent error path from reading uninitialized data */
ret = - ENOENT ;
goto err ;
}
2010-11-25 19:32:06 +00:00
if ( ! list_empty ( & obj - > exec_list ) ) {
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " Object %p [handle %d, index %d] appears more than once in object list \n " ,
2010-11-25 19:32:06 +00:00
obj , exec [ i ] . handle , i ) ;
2010-11-25 18:00:26 +00:00
ret = - EINVAL ;
goto err ;
}
2010-11-25 19:32:06 +00:00
list_add_tail ( & obj - > exec_list , & objects ) ;
2010-12-08 10:38:14 +00:00
obj - > exec_handle = exec [ i ] . handle ;
2011-01-10 17:35:37 +00:00
obj - > exec_entry = & exec [ i ] ;
2010-12-08 10:38:14 +00:00
eb_add_object ( eb , obj ) ;
2010-11-25 18:00:26 +00:00
}
2011-01-10 17:35:37 +00:00
/* take note of the batch buffer before we might reorder the lists */
batch_obj = list_entry ( objects . prev ,
struct drm_i915_gem_object ,
exec_list ) ;
2010-11-25 18:00:26 +00:00
/* Move the objects en-masse into the GTT, evicting if necessary. */
2011-01-10 17:35:37 +00:00
ret = i915_gem_execbuffer_reserve ( ring , file , & objects ) ;
2010-11-25 18:00:26 +00:00
if ( ret )
goto err ;
/* The objects are in their final locations, apply the relocations. */
2011-01-10 17:35:37 +00:00
ret = i915_gem_execbuffer_relocate ( dev , eb , & objects ) ;
2010-11-25 18:00:26 +00:00
if ( ret ) {
if ( ret = = - EFAULT ) {
2010-11-10 16:40:20 +00:00
ret = i915_gem_execbuffer_relocate_slow ( dev , file , ring ,
2010-12-08 10:38:14 +00:00
& objects , eb ,
exec ,
2010-11-25 18:00:26 +00:00
args - > buffer_count ) ;
BUG_ON ( ! mutex_is_locked ( & dev - > struct_mutex ) ) ;
}
if ( ret )
goto err ;
}
/* Set the pending read domains for the batch buffer to COMMAND */
if ( batch_obj - > base . pending_write_domain ) {
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " Attempting to use self-modifying batch buffer \n " ) ;
2010-11-25 18:00:26 +00:00
ret = - EINVAL ;
goto err ;
}
batch_obj - > base . pending_read_domains | = I915_GEM_DOMAIN_COMMAND ;
2010-11-25 19:32:06 +00:00
ret = i915_gem_execbuffer_move_to_gpu ( ring , & objects ) ;
if ( ret )
2010-11-25 18:00:26 +00:00
goto err ;
2011-02-03 11:57:46 +00:00
seqno = i915_gem_next_request_seqno ( ring ) ;
2011-01-21 10:07:18 +00:00
for ( i = 0 ; i < ARRAY_SIZE ( ring - > sync_seqno ) ; i + + ) {
2010-12-04 11:30:53 +00:00
if ( seqno < ring - > sync_seqno [ i ] ) {
/* The GPU can not handle its semaphore value wrapping,
* so every billion or so execbuffers , we need to stall
* the GPU in order to reset the counters .
*/
2012-04-26 16:02:58 -07:00
ret = i915_gpu_idle ( dev ) ;
2010-12-04 11:30:53 +00:00
if ( ret )
goto err ;
2012-04-26 16:02:58 -07:00
i915_gem_retire_requests ( dev ) ;
2010-12-04 11:30:53 +00:00
BUG_ON ( ring - > sync_seqno [ i ] ) ;
}
}
2012-07-23 12:33:55 -07:00
ret = i915_switch_context ( ring , file , ctx_id ) ;
if ( ret )
goto err ;
2011-12-12 19:21:57 -08:00
if ( ring = = & dev_priv - > ring [ RCS ] & &
mode ! = dev_priv - > relative_constants_mode ) {
ret = intel_ring_begin ( ring , 4 ) ;
if ( ret )
goto err ;
intel_ring_emit ( ring , MI_NOOP ) ;
intel_ring_emit ( ring , MI_LOAD_REGISTER_IMM ( 1 ) ) ;
intel_ring_emit ( ring , INSTPM ) ;
2011-12-12 19:21:58 -08:00
intel_ring_emit ( ring , mask < < 16 | mode ) ;
2011-12-12 19:21:57 -08:00
intel_ring_advance ( ring ) ;
dev_priv - > relative_constants_mode = mode ;
}
2012-01-03 09:23:29 -08:00
if ( args - > flags & I915_EXEC_GEN7_SOL_RESET ) {
ret = i915_reset_gen7_sol_offsets ( dev , ring ) ;
if ( ret )
goto err ;
}
2011-02-03 11:57:46 +00:00
trace_i915_gem_ring_dispatch ( ring , seqno ) ;
2010-11-30 14:10:25 +00:00
exec_start = batch_obj - > gtt_offset + args - > batch_start_offset ;
exec_len = args - > batch_len ;
if ( cliprects ) {
for ( i = 0 ; i < args - > num_cliprects ; i + + ) {
ret = i915_emit_box ( dev , & cliprects [ i ] ,
args - > DR1 , args - > DR4 ) ;
if ( ret )
goto err ;
ret = ring - > dispatch_execbuffer ( ring ,
exec_start , exec_len ) ;
if ( ret )
goto err ;
}
} else {
ret = ring - > dispatch_execbuffer ( ring , exec_start , exec_len ) ;
if ( ret )
goto err ;
}
2010-11-25 18:00:26 +00:00
2010-12-04 11:30:53 +00:00
i915_gem_execbuffer_move_to_active ( & objects , ring , seqno ) ;
2010-11-25 19:32:06 +00:00
i915_gem_execbuffer_retire_commands ( dev , file , ring ) ;
2010-11-25 18:00:26 +00:00
err :
2010-12-08 10:38:14 +00:00
eb_destroy ( eb ) ;
2010-11-25 19:32:06 +00:00
while ( ! list_empty ( & objects ) ) {
struct drm_i915_gem_object * obj ;
obj = list_first_entry ( & objects ,
struct drm_i915_gem_object ,
exec_list ) ;
list_del_init ( & obj - > exec_list ) ;
drm_gem_object_unreference ( & obj - > base ) ;
2010-11-25 18:00:26 +00:00
}
mutex_unlock ( & dev - > struct_mutex ) ;
pre_mutex_err :
kfree ( cliprects ) ;
return ret ;
}
/*
* Legacy execbuffer just creates an exec2 list from the original exec object
* list array and passes it to the real function .
*/
int
i915_gem_execbuffer ( struct drm_device * dev , void * data ,
struct drm_file * file )
{
struct drm_i915_gem_execbuffer * args = data ;
struct drm_i915_gem_execbuffer2 exec2 ;
struct drm_i915_gem_exec_object * exec_list = NULL ;
struct drm_i915_gem_exec_object2 * exec2_list = NULL ;
int ret , i ;
if ( args - > buffer_count < 1 ) {
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " execbuf with %d buffers \n " , args - > buffer_count ) ;
2010-11-25 18:00:26 +00:00
return - EINVAL ;
}
/* Copy in the exec list from userland */
exec_list = drm_malloc_ab ( sizeof ( * exec_list ) , args - > buffer_count ) ;
exec2_list = drm_malloc_ab ( sizeof ( * exec2_list ) , args - > buffer_count ) ;
if ( exec_list = = NULL | | exec2_list = = NULL ) {
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " Failed to allocate exec list for %d buffers \n " ,
2010-11-25 18:00:26 +00:00
args - > buffer_count ) ;
drm_free_large ( exec_list ) ;
drm_free_large ( exec2_list ) ;
return - ENOMEM ;
}
ret = copy_from_user ( exec_list ,
( struct drm_i915_relocation_entry __user * )
( uintptr_t ) args - > buffers_ptr ,
sizeof ( * exec_list ) * args - > buffer_count ) ;
if ( ret ! = 0 ) {
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " copy %d exec entries failed %d \n " ,
2010-11-25 18:00:26 +00:00
args - > buffer_count , ret ) ;
drm_free_large ( exec_list ) ;
drm_free_large ( exec2_list ) ;
return - EFAULT ;
}
for ( i = 0 ; i < args - > buffer_count ; i + + ) {
exec2_list [ i ] . handle = exec_list [ i ] . handle ;
exec2_list [ i ] . relocation_count = exec_list [ i ] . relocation_count ;
exec2_list [ i ] . relocs_ptr = exec_list [ i ] . relocs_ptr ;
exec2_list [ i ] . alignment = exec_list [ i ] . alignment ;
exec2_list [ i ] . offset = exec_list [ i ] . offset ;
if ( INTEL_INFO ( dev ) - > gen < 4 )
exec2_list [ i ] . flags = EXEC_OBJECT_NEEDS_FENCE ;
else
exec2_list [ i ] . flags = 0 ;
}
exec2 . buffers_ptr = args - > buffers_ptr ;
exec2 . buffer_count = args - > buffer_count ;
exec2 . batch_start_offset = args - > batch_start_offset ;
exec2 . batch_len = args - > batch_len ;
exec2 . DR1 = args - > DR1 ;
exec2 . DR4 = args - > DR4 ;
exec2 . num_cliprects = args - > num_cliprects ;
exec2 . cliprects_ptr = args - > cliprects_ptr ;
exec2 . flags = I915_EXEC_RENDER ;
2012-06-04 14:42:55 -07:00
i915_execbuffer2_set_context_id ( exec2 , 0 ) ;
2010-11-25 18:00:26 +00:00
ret = i915_gem_do_execbuffer ( dev , data , file , & exec2 , exec2_list ) ;
if ( ! ret ) {
/* Copy the new buffer offsets back to the user's exec list. */
for ( i = 0 ; i < args - > buffer_count ; i + + )
exec_list [ i ] . offset = exec2_list [ i ] . offset ;
/* ... and back out to userspace */
ret = copy_to_user ( ( struct drm_i915_relocation_entry __user * )
( uintptr_t ) args - > buffers_ptr ,
exec_list ,
sizeof ( * exec_list ) * args - > buffer_count ) ;
if ( ret ) {
ret = - EFAULT ;
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " failed to copy %d exec entries "
2010-11-25 18:00:26 +00:00
" back to user (%d) \n " ,
args - > buffer_count , ret ) ;
}
}
drm_free_large ( exec_list ) ;
drm_free_large ( exec2_list ) ;
return ret ;
}
int
i915_gem_execbuffer2 ( struct drm_device * dev , void * data ,
struct drm_file * file )
{
struct drm_i915_gem_execbuffer2 * args = data ;
struct drm_i915_gem_exec_object2 * exec2_list = NULL ;
int ret ;
2012-04-23 04:06:41 -04:00
if ( args - > buffer_count < 1 | |
args - > buffer_count > UINT_MAX / sizeof ( * exec2_list ) ) {
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " execbuf2 with %d buffers \n " , args - > buffer_count ) ;
2010-11-25 18:00:26 +00:00
return - EINVAL ;
}
2011-02-21 12:54:48 +00:00
exec2_list = kmalloc ( sizeof ( * exec2_list ) * args - > buffer_count ,
GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY ) ;
if ( exec2_list = = NULL )
exec2_list = drm_malloc_ab ( sizeof ( * exec2_list ) ,
args - > buffer_count ) ;
2010-11-25 18:00:26 +00:00
if ( exec2_list = = NULL ) {
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " Failed to allocate exec list for %d buffers \n " ,
2010-11-25 18:00:26 +00:00
args - > buffer_count ) ;
return - ENOMEM ;
}
ret = copy_from_user ( exec2_list ,
( struct drm_i915_relocation_entry __user * )
( uintptr_t ) args - > buffers_ptr ,
sizeof ( * exec2_list ) * args - > buffer_count ) ;
if ( ret ! = 0 ) {
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " copy %d exec entries failed %d \n " ,
2010-11-25 18:00:26 +00:00
args - > buffer_count , ret ) ;
drm_free_large ( exec2_list ) ;
return - EFAULT ;
}
ret = i915_gem_do_execbuffer ( dev , data , file , args , exec2_list ) ;
if ( ! ret ) {
/* Copy the new buffer offsets back to the user's exec list. */
ret = copy_to_user ( ( struct drm_i915_relocation_entry __user * )
( uintptr_t ) args - > buffers_ptr ,
exec2_list ,
sizeof ( * exec2_list ) * args - > buffer_count ) ;
if ( ret ) {
ret = - EFAULT ;
2012-01-31 21:08:14 +01:00
DRM_DEBUG ( " failed to copy %d exec entries "
2010-11-25 18:00:26 +00:00
" back to user (%d) \n " ,
args - > buffer_count , ret ) ;
}
}
drm_free_large ( exec2_list ) ;
return ret ;
}