2021-09-24 12:14:42 -07:00
// SPDX-License-Identifier: MIT
/*
* Copyright ( c ) 2020 , Intel Corporation . All rights reserved .
*/
2021-11-16 15:58:13 +02:00
# include <drm/i915_drm.h>
2021-09-24 12:14:42 -07:00
# include "i915_drv.h"
# include "intel_pxp.h"
2021-09-24 12:14:43 -07:00
# include "intel_pxp_cmd.h"
2021-09-24 12:14:42 -07:00
# include "intel_pxp_session.h"
# include "intel_pxp_tee.h"
# include "intel_pxp_types.h"
# define ARB_SESSION I915_PROTECTED_CONTENT_DEFAULT_SESSION /* shorter define */
# define GEN12_KCR_SIP _MMIO(0x32260) /* KCR hwdrm session in play 0-31 */
2021-09-24 12:14:43 -07:00
/* PXP global terminate register for session termination */
# define PXP_GLOBAL_TERMINATE _MMIO(0x320f8)
2021-09-24 12:14:42 -07:00
static bool intel_pxp_session_is_in_play ( struct intel_pxp * pxp , u32 id )
{
2021-09-24 12:14:47 -07:00
struct intel_uncore * uncore = pxp_to_gt ( pxp ) - > uncore ;
2021-09-24 12:14:42 -07:00
intel_wakeref_t wakeref ;
u32 sip = 0 ;
2021-09-24 12:14:47 -07:00
/* if we're suspended the session is considered off */
with_intel_runtime_pm_if_in_use ( uncore - > rpm , wakeref )
sip = intel_uncore_read ( uncore , GEN12_KCR_SIP ) ;
2021-09-24 12:14:42 -07:00
return sip & BIT ( id ) ;
}
static int pxp_wait_for_session_state ( struct intel_pxp * pxp , u32 id , bool in_play )
{
2021-09-24 12:14:47 -07:00
struct intel_uncore * uncore = pxp_to_gt ( pxp ) - > uncore ;
2021-09-24 12:14:42 -07:00
intel_wakeref_t wakeref ;
u32 mask = BIT ( id ) ;
int ret ;
2021-09-24 12:14:47 -07:00
/* if we're suspended the session is considered off */
wakeref = intel_runtime_pm_get_if_in_use ( uncore - > rpm ) ;
if ( ! wakeref )
return in_play ? - ENODEV : 0 ;
ret = intel_wait_for_register ( uncore ,
GEN12_KCR_SIP ,
mask ,
in_play ? mask : 0 ,
100 ) ;
intel_runtime_pm_put ( uncore - > rpm , wakeref ) ;
2021-09-24 12:14:42 -07:00
return ret ;
}
2021-09-24 12:14:44 -07:00
static int pxp_create_arb_session ( struct intel_pxp * pxp )
2021-09-24 12:14:42 -07:00
{
struct intel_gt * gt = pxp_to_gt ( pxp ) ;
int ret ;
pxp - > arb_is_valid = false ;
if ( intel_pxp_session_is_in_play ( pxp , ARB_SESSION ) ) {
drm_err ( & gt - > i915 - > drm , " arb session already in play at creation time \n " ) ;
return - EEXIST ;
}
ret = intel_pxp_tee_cmd_create_arb_session ( pxp , ARB_SESSION ) ;
if ( ret ) {
drm_err ( & gt - > i915 - > drm , " tee cmd for arb session creation failed \n " ) ;
return ret ;
}
ret = pxp_wait_for_session_state ( pxp , ARB_SESSION , true ) ;
if ( ret ) {
drm_err ( & gt - > i915 - > drm , " arb session failed to go in play \n " ) ;
return ret ;
}
2021-09-24 12:14:45 -07:00
if ( ! + + pxp - > key_instance )
+ + pxp - > key_instance ;
2021-09-24 12:14:42 -07:00
pxp - > arb_is_valid = true ;
return 0 ;
}
2021-09-24 12:14:43 -07:00
2021-09-24 12:14:44 -07:00
static int pxp_terminate_arb_session_and_global ( struct intel_pxp * pxp )
2021-09-24 12:14:43 -07:00
{
int ret ;
struct intel_gt * gt = pxp_to_gt ( pxp ) ;
2021-09-24 12:14:44 -07:00
/* must mark termination in progress calling this function */
GEM_WARN_ON ( pxp - > arb_is_valid ) ;
2021-09-24 12:14:43 -07:00
/* terminate the hw sessions */
ret = intel_pxp_terminate_session ( pxp , ARB_SESSION ) ;
if ( ret ) {
drm_err ( & gt - > i915 - > drm , " Failed to submit session termination \n " ) ;
return ret ;
}
ret = pxp_wait_for_session_state ( pxp , ARB_SESSION , false ) ;
if ( ret ) {
drm_err ( & gt - > i915 - > drm , " Session state did not clear \n " ) ;
return ret ;
}
intel_uncore_write ( gt - > uncore , PXP_GLOBAL_TERMINATE , 1 ) ;
return ret ;
}
2021-09-24 12:14:44 -07:00
static void pxp_terminate ( struct intel_pxp * pxp )
{
int ret ;
pxp - > hw_state_invalidated = true ;
/*
* if we fail to submit the termination there is no point in waiting for
* it to complete . PXP will be marked as non - active until the next
* termination is issued .
*/
ret = pxp_terminate_arb_session_and_global ( pxp ) ;
if ( ret )
complete_all ( & pxp - > termination ) ;
}
static void pxp_terminate_complete ( struct intel_pxp * pxp )
{
/* Re-create the arb session after teardown handle complete */
if ( fetch_and_zero ( & pxp - > hw_state_invalidated ) )
pxp_create_arb_session ( pxp ) ;
complete_all ( & pxp - > termination ) ;
}
void intel_pxp_session_work ( struct work_struct * work )
{
struct intel_pxp * pxp = container_of ( work , typeof ( * pxp ) , session_work ) ;
struct intel_gt * gt = pxp_to_gt ( pxp ) ;
2021-09-24 12:14:47 -07:00
intel_wakeref_t wakeref ;
2021-09-24 12:14:44 -07:00
u32 events = 0 ;
spin_lock_irq ( & gt - > irq_lock ) ;
events = fetch_and_zero ( & pxp - > session_events ) ;
spin_unlock_irq ( & gt - > irq_lock ) ;
if ( ! events )
return ;
2021-09-24 12:14:46 -07:00
if ( events & PXP_INVAL_REQUIRED )
intel_pxp_invalidate ( pxp ) ;
2021-09-24 12:14:47 -07:00
/*
* If we ' re processing an event while suspending then don ' t bother ,
* we ' re going to re - init everything on resume anyway .
*/
wakeref = intel_runtime_pm_get_if_in_use ( gt - > uncore - > rpm ) ;
if ( ! wakeref )
return ;
2021-09-24 12:14:44 -07:00
if ( events & PXP_TERMINATION_REQUEST ) {
events & = ~ PXP_TERMINATION_COMPLETE ;
pxp_terminate ( pxp ) ;
}
if ( events & PXP_TERMINATION_COMPLETE )
pxp_terminate_complete ( pxp ) ;
2021-09-24 12:14:47 -07:00
intel_runtime_pm_put ( gt - > uncore - > rpm , wakeref ) ;
2021-09-24 12:14:44 -07:00
}