2014-05-14 17:02:16 +03:00
/*
* Copyright © 2014 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 :
* Mika Kuoppala < mika . kuoppala @ intel . com >
*
*/
# include "i915_drv.h"
# include "intel_renderstate.h"
static const struct intel_renderstate_rodata *
render_state_get_rodata ( struct drm_device * dev , const int gen )
{
switch ( gen ) {
case 6 :
return & gen6_null_state ;
case 7 :
return & gen7_null_state ;
case 8 :
return & gen8_null_state ;
2014-10-23 08:34:28 -07:00
case 9 :
return & gen9_null_state ;
2014-05-14 17:02:16 +03:00
}
return NULL ;
}
2014-06-10 11:23:33 +01:00
static int render_state_init ( struct render_state * so , struct drm_device * dev )
2014-05-14 17:02:16 +03:00
{
int ret ;
2014-06-10 11:23:33 +01:00
so - > gen = INTEL_INFO ( dev ) - > gen ;
so - > rodata = render_state_get_rodata ( dev , so - > gen ) ;
if ( so - > rodata = = NULL )
return 0 ;
if ( so - > rodata - > batch_items * 4 > 4096 )
2014-05-14 17:02:16 +03:00
return - EINVAL ;
2016-04-22 19:14:32 +01:00
so - > obj = i915_gem_object_create ( dev , 4096 ) ;
2014-06-10 11:23:33 +01:00
if ( so - > obj = = NULL )
return - ENOMEM ;
ret = i915_gem_obj_ggtt_pin ( so - > obj , 4096 , 0 ) ;
if ( ret )
goto free_gem ;
so - > ggtt_offset = i915_gem_obj_ggtt_offset ( so - > obj ) ;
return 0 ;
free_gem :
drm_gem_object_unreference ( & so - > obj - > base ) ;
return ret ;
}
2015-07-20 10:46:10 +01:00
/*
* Macro to add commands to auxiliary batch .
* This macro only checks for page overflow before inserting the commands ,
* this is sufficient as the null state generator makes the final batch
* with two passes to build command and state separately . At this point
* the size of both are known and it compacts them by relocating the state
* right after the commands taking care of aligment so we should sufficient
* space below them for adding new commands .
*/
# define OUT_BATCH(batch, i, val) \
do { \
if ( WARN_ON ( ( i ) > = PAGE_SIZE / sizeof ( u32 ) ) ) { \
ret = - ENOSPC ; \
goto err_out ; \
} \
( batch ) [ ( i ) + + ] = ( val ) ; \
} while ( 0 )
2014-06-10 11:23:33 +01:00
static int render_state_setup ( struct render_state * so )
{
const struct intel_renderstate_rodata * rodata = so - > rodata ;
unsigned int i = 0 , reloc_index = 0 ;
struct page * page ;
u32 * d ;
int ret ;
2014-05-14 17:02:16 +03:00
ret = i915_gem_object_set_to_cpu_domain ( so - > obj , true ) ;
if ( ret )
return ret ;
2015-12-10 18:51:23 +00:00
page = i915_gem_object_get_dirty_page ( so - > obj , 0 ) ;
2014-06-10 11:23:33 +01:00
d = kmap ( page ) ;
2014-05-14 17:02:16 +03:00
while ( i < rodata - > batch_items ) {
u32 s = rodata - > batch [ i ] ;
2014-06-10 11:23:33 +01:00
if ( i * 4 = = rodata - > reloc [ reloc_index ] ) {
u64 r = s + so - > ggtt_offset ;
s = lower_32_bits ( r ) ;
if ( so - > gen > = 8 ) {
2014-05-14 17:02:16 +03:00
if ( i + 1 > = rodata - > batch_items | |
2015-07-17 17:08:51 +01:00
rodata - > batch [ i + 1 ] ! = 0 ) {
ret = - EINVAL ;
goto err_out ;
}
2014-05-14 17:02:16 +03:00
2014-06-10 11:23:33 +01:00
d [ i + + ] = s ;
s = upper_32_bits ( r ) ;
2014-05-14 17:02:16 +03:00
}
reloc_index + + ;
}
2014-06-10 11:23:33 +01:00
d [ i + + ] = s ;
2014-05-14 17:02:16 +03:00
}
2015-07-20 10:46:10 +01:00
while ( i % CACHELINE_DWORDS )
OUT_BATCH ( d , i , MI_NOOP ) ;
so - > aux_batch_offset = i * sizeof ( u32 ) ;
OUT_BATCH ( d , i , MI_BATCH_BUFFER_END ) ;
so - > aux_batch_size = ( i * sizeof ( u32 ) ) - so - > aux_batch_offset ;
/*
* Since we are sending length , we need to strictly conform to
* all requirements . For Gen2 this must be a multiple of 8.
*/
so - > aux_batch_size = ALIGN ( so - > aux_batch_size , 8 ) ;
2014-06-10 11:23:33 +01:00
kunmap ( page ) ;
2014-05-14 17:02:16 +03:00
ret = i915_gem_object_set_to_gtt_domain ( so - > obj , false ) ;
if ( ret )
return ret ;
2014-06-10 11:23:33 +01:00
if ( rodata - > reloc [ reloc_index ] ! = - 1 ) {
DRM_ERROR ( " only %d relocs resolved \n " , reloc_index ) ;
2014-05-14 17:02:16 +03:00
return - EINVAL ;
}
return 0 ;
2015-07-17 17:08:51 +01:00
err_out :
kunmap ( page ) ;
return ret ;
2014-05-14 17:02:16 +03:00
}
2015-07-20 10:46:10 +01:00
# undef OUT_BATCH
2014-08-21 11:40:54 +01:00
void i915_gem_render_state_fini ( struct render_state * so )
2014-06-10 11:23:33 +01:00
{
i915_gem_object_ggtt_unpin ( so - > obj ) ;
drm_gem_object_unreference ( & so - > obj - > base ) ;
}
2016-03-16 11:00:37 +00:00
int i915_gem_render_state_prepare ( struct intel_engine_cs * engine ,
2014-08-21 11:40:54 +01:00
struct render_state * so )
2014-05-14 17:02:16 +03:00
{
int ret ;
2016-03-16 11:00:37 +00:00
if ( WARN_ON ( engine - > id ! = RCS ) )
2014-05-21 19:01:06 +03:00
return - ENOENT ;
2016-03-16 11:00:37 +00:00
ret = render_state_init ( so , engine - > dev ) ;
2014-06-10 11:23:33 +01:00
if ( ret )
return ret ;
2014-05-14 17:02:16 +03:00
2014-08-21 11:40:54 +01:00
if ( so - > rodata = = NULL )
2014-06-10 11:23:33 +01:00
return 0 ;
2014-05-14 17:02:16 +03:00
2014-08-21 11:40:54 +01:00
ret = render_state_setup ( so ) ;
if ( ret ) {
i915_gem_render_state_fini ( so ) ;
return ret ;
}
return 0 ;
}
2015-05-29 17:43:45 +01:00
int i915_gem_render_state_init ( struct drm_i915_gem_request * req )
2014-08-21 11:40:54 +01:00
{
struct render_state so ;
int ret ;
2016-03-16 11:00:38 +00:00
ret = i915_gem_render_state_prepare ( req - > engine , & so ) ;
2014-05-14 17:02:16 +03:00
if ( ret )
2014-08-21 11:40:54 +01:00
return ret ;
if ( so . rodata = = NULL )
return 0 ;
2014-05-14 17:02:16 +03:00
2016-03-16 11:00:38 +00:00
ret = req - > engine - > dispatch_execbuffer ( req , so . ggtt_offset ,
2015-05-29 17:43:45 +01:00
so . rodata - > batch_items * 4 ,
I915_DISPATCH_SECURE ) ;
2014-05-14 17:02:16 +03:00
if ( ret )
goto out ;
2015-07-20 10:46:10 +01:00
if ( so . aux_batch_size > 8 ) {
2016-03-16 11:00:38 +00:00
ret = req - > engine - > dispatch_execbuffer ( req ,
2015-07-20 10:46:10 +01:00
( so . ggtt_offset +
so . aux_batch_offset ) ,
so . aux_batch_size ,
I915_DISPATCH_SECURE ) ;
if ( ret )
goto out ;
}
2015-05-29 17:43:50 +01:00
i915_vma_move_to_active ( i915_gem_obj_to_ggtt ( so . obj ) , req ) ;
2014-05-14 17:02:16 +03:00
out :
2014-08-21 11:40:54 +01:00
i915_gem_render_state_fini ( & so ) ;
2014-05-14 17:02:16 +03:00
return ret ;
}