2020-01-20 19:47:24 +02:00
// SPDX-License-Identifier: MIT
/*
* Copyright © 2020 Intel Corporation
*/
# include <linux/string.h>
# include "i915_drv.h"
# include "intel_atomic.h"
# include "intel_display_types.h"
# include "intel_global_state.h"
2020-05-27 23:02:45 +03:00
static void __intel_atomic_global_state_free ( struct kref * kref )
{
struct intel_global_state * obj_state =
container_of ( kref , struct intel_global_state , ref ) ;
struct intel_global_obj * obj = obj_state - > obj ;
obj - > funcs - > atomic_destroy_state ( obj , obj_state ) ;
}
static void intel_atomic_global_state_put ( struct intel_global_state * obj_state )
{
kref_put ( & obj_state - > ref , __intel_atomic_global_state_free ) ;
}
static struct intel_global_state *
intel_atomic_global_state_get ( struct intel_global_state * obj_state )
{
kref_get ( & obj_state - > ref ) ;
return obj_state ;
}
2020-01-20 19:47:24 +02:00
void intel_atomic_global_obj_init ( struct drm_i915_private * dev_priv ,
struct intel_global_obj * obj ,
struct intel_global_state * state ,
const struct intel_global_state_funcs * funcs )
{
memset ( obj , 0 , sizeof ( * obj ) ) ;
2020-05-27 23:02:45 +03:00
state - > obj = obj ;
kref_init ( & state - > ref ) ;
2020-01-20 19:47:24 +02:00
obj - > state = state ;
obj - > funcs = funcs ;
list_add_tail ( & obj - > head , & dev_priv - > global_obj_list ) ;
}
void intel_atomic_global_obj_cleanup ( struct drm_i915_private * dev_priv )
{
struct intel_global_obj * obj , * next ;
list_for_each_entry_safe ( obj , next , & dev_priv - > global_obj_list , head ) {
list_del ( & obj - > head ) ;
2020-05-27 23:02:45 +03:00
drm_WARN_ON ( & dev_priv - > drm , kref_read ( & obj - > state - > ref ) ! = 1 ) ;
intel_atomic_global_state_put ( obj - > state ) ;
2020-01-20 19:47:24 +02:00
}
}
static void assert_global_state_write_locked ( struct drm_i915_private * dev_priv )
{
struct intel_crtc * crtc ;
for_each_intel_crtc ( & dev_priv - > drm , crtc )
drm_modeset_lock_assert_held ( & crtc - > base . mutex ) ;
}
static bool modeset_lock_is_held ( struct drm_modeset_acquire_ctx * ctx ,
struct drm_modeset_lock * lock )
{
struct drm_modeset_lock * l ;
list_for_each_entry ( l , & ctx - > locked , head ) {
if ( lock = = l )
return true ;
}
return false ;
}
static void assert_global_state_read_locked ( struct intel_atomic_state * state )
{
struct drm_modeset_acquire_ctx * ctx = state - > base . acquire_ctx ;
struct drm_i915_private * dev_priv = to_i915 ( state - > base . dev ) ;
struct intel_crtc * crtc ;
for_each_intel_crtc ( & dev_priv - > drm , crtc ) {
if ( modeset_lock_is_held ( ctx , & crtc - > base . mutex ) )
return ;
}
2020-04-06 16:57:51 +05:30
drm_WARN ( & dev_priv - > drm , 1 , " Global state not read locked \n " ) ;
2020-01-20 19:47:24 +02:00
}
struct intel_global_state *
intel_atomic_get_global_obj_state ( struct intel_atomic_state * state ,
struct intel_global_obj * obj )
{
2020-04-02 14:48:10 +03:00
struct drm_i915_private * i915 = to_i915 ( state - > base . dev ) ;
2020-01-20 19:47:24 +02:00
int index , num_objs , i ;
size_t size ;
struct __intel_global_objs_state * arr ;
struct intel_global_state * obj_state ;
for ( i = 0 ; i < state - > num_global_objs ; i + + )
if ( obj = = state - > global_objs [ i ] . ptr )
return state - > global_objs [ i ] . state ;
assert_global_state_read_locked ( state ) ;
num_objs = state - > num_global_objs + 1 ;
size = sizeof ( * state - > global_objs ) * num_objs ;
arr = krealloc ( state - > global_objs , size , GFP_KERNEL ) ;
if ( ! arr )
return ERR_PTR ( - ENOMEM ) ;
state - > global_objs = arr ;
index = state - > num_global_objs ;
memset ( & state - > global_objs [ index ] , 0 , sizeof ( * state - > global_objs ) ) ;
obj_state = obj - > funcs - > atomic_duplicate_state ( obj ) ;
if ( ! obj_state )
return ERR_PTR ( - ENOMEM ) ;
2020-05-27 23:02:45 +03:00
obj_state - > obj = obj ;
2020-01-20 19:47:24 +02:00
obj_state - > changed = false ;
2020-05-27 23:02:45 +03:00
kref_init ( & obj_state - > ref ) ;
2020-01-20 19:47:24 +02:00
state - > global_objs [ index ] . state = obj_state ;
2020-05-27 23:02:45 +03:00
state - > global_objs [ index ] . old_state =
intel_atomic_global_state_get ( obj - > state ) ;
2020-01-20 19:47:24 +02:00
state - > global_objs [ index ] . new_state = obj_state ;
state - > global_objs [ index ] . ptr = obj ;
obj_state - > state = state ;
state - > num_global_objs = num_objs ;
2020-04-02 14:48:10 +03:00
drm_dbg_atomic ( & i915 - > drm , " Added new global object %p state %p to %p \n " ,
obj , obj_state , state ) ;
2020-01-20 19:47:24 +02:00
return obj_state ;
}
struct intel_global_state *
intel_atomic_get_old_global_obj_state ( struct intel_atomic_state * state ,
struct intel_global_obj * obj )
{
int i ;
for ( i = 0 ; i < state - > num_global_objs ; i + + )
if ( obj = = state - > global_objs [ i ] . ptr )
return state - > global_objs [ i ] . old_state ;
return NULL ;
}
struct intel_global_state *
intel_atomic_get_new_global_obj_state ( struct intel_atomic_state * state ,
struct intel_global_obj * obj )
{
int i ;
for ( i = 0 ; i < state - > num_global_objs ; i + + )
if ( obj = = state - > global_objs [ i ] . ptr )
return state - > global_objs [ i ] . new_state ;
return NULL ;
}
void intel_atomic_swap_global_state ( struct intel_atomic_state * state )
{
struct drm_i915_private * dev_priv = to_i915 ( state - > base . dev ) ;
struct intel_global_state * old_obj_state , * new_obj_state ;
struct intel_global_obj * obj ;
int i ;
for_each_oldnew_global_obj_in_state ( state , obj , old_obj_state ,
new_obj_state , i ) {
2020-04-06 16:57:51 +05:30
drm_WARN_ON ( & dev_priv - > drm , obj - > state ! = old_obj_state ) ;
2020-01-20 19:47:24 +02:00
/*
* If the new state wasn ' t modified ( and properly
* locked for write access ) we throw it away .
*/
if ( ! new_obj_state - > changed )
continue ;
assert_global_state_write_locked ( dev_priv ) ;
old_obj_state - > state = state ;
new_obj_state - > state = NULL ;
state - > global_objs [ i ] . state = old_obj_state ;
2020-05-27 23:02:45 +03:00
intel_atomic_global_state_put ( obj - > state ) ;
obj - > state = intel_atomic_global_state_get ( new_obj_state ) ;
2020-01-20 19:47:24 +02:00
}
}
void intel_atomic_clear_global_state ( struct intel_atomic_state * state )
{
int i ;
for ( i = 0 ; i < state - > num_global_objs ; i + + ) {
2020-05-27 23:02:45 +03:00
intel_atomic_global_state_put ( state - > global_objs [ i ] . old_state ) ;
intel_atomic_global_state_put ( state - > global_objs [ i ] . new_state ) ;
2020-01-20 19:47:24 +02:00
state - > global_objs [ i ] . ptr = NULL ;
state - > global_objs [ i ] . state = NULL ;
state - > global_objs [ i ] . old_state = NULL ;
state - > global_objs [ i ] . new_state = NULL ;
}
state - > num_global_objs = 0 ;
}
int intel_atomic_lock_global_state ( struct intel_global_state * obj_state )
{
struct intel_atomic_state * state = obj_state - > state ;
struct drm_i915_private * dev_priv = to_i915 ( state - > base . dev ) ;
struct intel_crtc * crtc ;
for_each_intel_crtc ( & dev_priv - > drm , crtc ) {
int ret ;
ret = drm_modeset_lock ( & crtc - > base . mutex ,
state - > base . acquire_ctx ) ;
if ( ret )
return ret ;
}
obj_state - > changed = true ;
return 0 ;
}
int intel_atomic_serialize_global_state ( struct intel_global_state * obj_state )
{
struct intel_atomic_state * state = obj_state - > state ;
struct drm_i915_private * dev_priv = to_i915 ( state - > base . dev ) ;
struct intel_crtc * crtc ;
for_each_intel_crtc ( & dev_priv - > drm , crtc ) {
struct intel_crtc_state * crtc_state ;
crtc_state = intel_atomic_get_crtc_state ( & state - > base , crtc ) ;
if ( IS_ERR ( crtc_state ) )
return PTR_ERR ( crtc_state ) ;
}
obj_state - > changed = true ;
return 0 ;
}