2017-02-13 17:15:14 +00:00
/*
* Copyright © 2016 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 .
*
*/
# include "mock_engine.h"
2017-02-13 17:15:19 +00:00
# include "mock_request.h"
2017-02-13 17:15:14 +00:00
2017-02-13 17:15:19 +00:00
static struct mock_request * first_request ( struct mock_engine * engine )
2017-02-13 17:15:14 +00:00
{
2017-02-13 17:15:19 +00:00
return list_first_entry_or_null ( & engine - > hw_queue ,
struct mock_request ,
link ) ;
}
2017-10-24 23:08:54 +01:00
static void advance ( struct mock_engine * engine ,
struct mock_request * request )
{
list_del_init ( & request - > link ) ;
mock_seqno_advance ( & engine - > base , request - > base . global_seqno ) ;
}
2017-10-17 09:53:04 +03:00
static void hw_delay_complete ( struct timer_list * t )
2017-02-13 17:15:19 +00:00
{
2017-10-17 09:53:04 +03:00
struct mock_engine * engine = from_timer ( engine , t , hw_delay ) ;
2017-02-13 17:15:19 +00:00
struct mock_request * request ;
spin_lock ( & engine - > hw_lock ) ;
2017-10-24 23:08:54 +01:00
/* Timer fired, first request is complete */
2017-02-13 17:15:19 +00:00
request = first_request ( engine ) ;
if ( request )
2017-10-24 23:08:54 +01:00
advance ( engine , request ) ;
/*
* Also immediately signal any subsequent 0 - delay requests , but
* requeue the timer for the next delayed request .
*/
while ( ( request = first_request ( engine ) ) ) {
if ( request - > delay ) {
mod_timer ( & engine - > hw_delay , jiffies + request - > delay ) ;
break ;
}
advance ( engine , request ) ;
}
2017-02-13 17:15:19 +00:00
spin_unlock ( & engine - > hw_lock ) ;
}
2017-05-04 10:33:08 +01:00
static struct intel_ring *
mock_context_pin ( struct intel_engine_cs * engine ,
struct i915_gem_context * ctx )
2017-02-13 17:15:19 +00:00
{
2018-04-30 14:15:01 +01:00
struct intel_context * ce = to_intel_context ( ctx , engine ) ;
if ( ! ce - > pin_count + + )
i915_gem_context_get ( ctx ) ;
2017-05-04 10:33:08 +01:00
return engine - > buffer ;
2017-02-13 17:15:19 +00:00
}
static void mock_context_unpin ( struct intel_engine_cs * engine ,
struct i915_gem_context * ctx )
{
2018-04-30 14:15:01 +01:00
struct intel_context * ce = to_intel_context ( ctx , engine ) ;
if ( ! - - ce - > pin_count )
i915_gem_context_put ( ctx ) ;
2017-02-13 17:15:19 +00:00
}
2018-02-21 09:56:36 +00:00
static int mock_request_alloc ( struct i915_request * request )
2017-02-13 17:15:19 +00:00
{
struct mock_request * mock = container_of ( request , typeof ( * mock ) , base ) ;
INIT_LIST_HEAD ( & mock - > link ) ;
mock - > delay = 0 ;
return 0 ;
}
2018-02-21 09:56:36 +00:00
static int mock_emit_flush ( struct i915_request * request ,
2017-02-13 17:15:19 +00:00
unsigned int flags )
{
return 0 ;
}
2018-02-21 09:56:36 +00:00
static void mock_emit_breadcrumb ( struct i915_request * request ,
2017-02-13 17:15:19 +00:00
u32 * flags )
{
}
2018-02-21 09:56:36 +00:00
static void mock_submit_request ( struct i915_request * request )
2017-02-13 17:15:19 +00:00
{
struct mock_request * mock = container_of ( request , typeof ( * mock ) , base ) ;
struct mock_engine * engine =
container_of ( request - > engine , typeof ( * engine ) , base ) ;
2018-02-21 09:56:36 +00:00
i915_request_submit ( request ) ;
2017-02-13 17:15:19 +00:00
GEM_BUG_ON ( ! request - > global_seqno ) ;
spin_lock_irq ( & engine - > hw_lock ) ;
list_add_tail ( & mock - > link , & engine - > hw_queue ) ;
2017-10-24 23:08:54 +01:00
if ( mock - > link . prev = = & engine - > hw_queue ) {
if ( mock - > delay )
mod_timer ( & engine - > hw_delay , jiffies + mock - > delay ) ;
else
advance ( engine , mock ) ;
}
2017-02-13 17:15:19 +00:00
spin_unlock_irq ( & engine - > hw_lock ) ;
}
static struct intel_ring * mock_ring ( struct intel_engine_cs * engine )
{
2017-11-15 15:12:03 +00:00
const unsigned long sz = PAGE_SIZE / 2 ;
2017-02-13 17:15:19 +00:00
struct intel_ring * ring ;
2017-11-15 15:12:03 +00:00
BUILD_BUG_ON ( MIN_SPACE_FOR_ADD_REQUEST > sz ) ;
2017-02-13 17:15:19 +00:00
ring = kzalloc ( sizeof ( * ring ) + sz , GFP_KERNEL ) ;
if ( ! ring )
return NULL ;
ring - > size = sz ;
ring - > effective_size = sz ;
ring - > vaddr = ( void * ) ( ring + 1 ) ;
INIT_LIST_HEAD ( & ring - > request_list ) ;
intel_ring_update_space ( ring ) ;
return ring ;
}
struct intel_engine_cs * mock_engine ( struct drm_i915_private * i915 ,
2017-08-09 17:39:30 +01:00
const char * name ,
int id )
2017-02-13 17:15:19 +00:00
{
struct mock_engine * engine ;
2017-08-09 17:39:30 +01:00
GEM_BUG_ON ( id > = I915_NUM_ENGINES ) ;
2017-02-13 17:15:14 +00:00
engine = kzalloc ( sizeof ( * engine ) + PAGE_SIZE , GFP_KERNEL ) ;
if ( ! engine )
return NULL ;
2017-02-13 17:15:19 +00:00
engine - > base . buffer = mock_ring ( & engine - > base ) ;
if ( ! engine - > base . buffer ) {
kfree ( engine ) ;
return NULL ;
}
2017-02-13 17:15:14 +00:00
2017-02-13 17:15:19 +00:00
/* minimal engine setup for requests */
engine - > base . i915 = i915 ;
2017-04-10 07:34:31 -07:00
snprintf ( engine - > base . name , sizeof ( engine - > base . name ) , " %s " , name ) ;
2017-08-09 17:39:30 +01:00
engine - > base . id = id ;
2017-02-13 17:15:19 +00:00
engine - > base . status_page . page_addr = ( void * ) ( engine + 1 ) ;
2017-02-13 17:15:14 +00:00
2017-02-13 17:15:19 +00:00
engine - > base . context_pin = mock_context_pin ;
engine - > base . context_unpin = mock_context_unpin ;
engine - > base . request_alloc = mock_request_alloc ;
engine - > base . emit_flush = mock_emit_flush ;
engine - > base . emit_breadcrumb = mock_emit_breadcrumb ;
engine - > base . submit_request = mock_submit_request ;
engine - > base . timeline =
& i915 - > gt . global_timeline . engine [ engine - > base . id ] ;
intel_engine_init_breadcrumbs ( & engine - > base ) ;
engine - > base . breadcrumbs . mock = true ; /* prevent touching HW for irqs */
/* fake hw queue */
spin_lock_init ( & engine - > hw_lock ) ;
2017-10-17 09:53:04 +03:00
timer_setup ( & engine - > hw_delay , hw_delay_complete , 0 ) ;
2017-02-13 17:15:19 +00:00
INIT_LIST_HEAD ( & engine - > hw_queue ) ;
return & engine - > base ;
2017-02-13 17:15:14 +00:00
}
void mock_engine_flush ( struct intel_engine_cs * engine )
{
2017-02-13 17:15:19 +00:00
struct mock_engine * mock =
container_of ( engine , typeof ( * mock ) , base ) ;
struct mock_request * request , * rn ;
del_timer_sync ( & mock - > hw_delay ) ;
spin_lock_irq ( & mock - > hw_lock ) ;
list_for_each_entry_safe ( request , rn , & mock - > hw_queue , link ) {
list_del_init ( & request - > link ) ;
mock_seqno_advance ( & mock - > base , request - > base . global_seqno ) ;
}
spin_unlock_irq ( & mock - > hw_lock ) ;
2017-02-13 17:15:14 +00:00
}
void mock_engine_reset ( struct intel_engine_cs * engine )
{
intel_write_status_page ( engine , I915_GEM_HWS_INDEX , 0 ) ;
}
2017-02-13 17:15:19 +00:00
void mock_engine_free ( struct intel_engine_cs * engine )
{
struct mock_engine * mock =
container_of ( engine , typeof ( * mock ) , base ) ;
GEM_BUG_ON ( timer_pending ( & mock - > hw_delay ) ) ;
if ( engine - > last_retired_context )
2018-04-30 14:15:01 +01:00
intel_context_unpin ( engine - > last_retired_context , engine ) ;
2017-02-13 17:15:19 +00:00
intel_engine_fini_breadcrumbs ( engine ) ;
kfree ( engine - > buffer ) ;
kfree ( engine ) ;
}