Skip to content
Permalink
Browse files
drm/i915/pxp: Destroy all type0 sessions upon teardown
Teardown is triggered when the display topology changes and no
long meets the secure playback requirement, and hardware trashes
all the encryption keys for display. So as a result, ring0 PXP
should handle such case and terminate all the type0 sessions.

Signed-off-by: Huang, Sean Z <sean.z.huang@intel.com>
  • Loading branch information
seanzhua authored and intel-lab-lkp committed Nov 14, 2020
1 parent 4cfbd36 commit b2c5c38f134701a462cb7e880c4cebcd79e1d8c6
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 1 deletion.
@@ -134,18 +134,22 @@ static void intel_pxp_mask_irq(struct intel_gt *gt, u32 mask)

static int intel_pxp_teardown_required_callback(struct drm_i915_private *i915)
{
int ret;

drm_dbg(&i915->drm, "%s was called\n", __func__);

mutex_lock(&i915->pxp.r0ctx->ctx_mutex);

i915->pxp.r0ctx->global_state_attacked = true;
i915->pxp.r0ctx->flag_display_hm_surface_keys = false;

ret = intel_pxp_sm_terminate_all_active_sessions(i915, SESSION_TYPE_TYPE0);

intel_pxp_destroy_r3ctx_list(i915);

mutex_unlock(&i915->pxp.r0ctx->ctx_mutex);

return 0;
return ret;
}

static int intel_pxp_global_terminate_complete_callback(struct drm_i915_private *i915)
@@ -893,6 +893,73 @@ static int issue_hw_terminate_for_session(struct drm_i915_private *i915, int ses
return ret;
}

static int terminate_all_hw_sessions_with_global_termination(struct drm_i915_private *i915,
int session_type)
{
u32 *cmd = NULL;
u32 *cmd_ptr = NULL;
int cmd_size_in_dw = 0;
int ret;
int session_index;
const int session_num_max = pxp_session_max(session_type);

drm_dbg(&i915->drm, ">>> %s session_type=[%d]\n", __func__, session_type);

if (!i915) {
ret = -EINVAL;
drm_dbg(&i915->drm, "Failed to %s due to bad params\n", __func__);
goto end;
}

/* Calculate how many bytes need to be alloc */
for (session_index = 0; session_index < session_num_max; session_index++) {
if (is_hw_session_in_play(i915, session_type, session_index)) {
cmd_size_in_dw += add_pxp_prolog(i915, NULL, session_type, session_index);
cmd_size_in_dw += add_pxp_inline_termination(NULL);
}
}
cmd_size_in_dw += add_pxp_epilog(NULL);

cmd = kzalloc(cmd_size_in_dw * 4, GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
drm_dbg(&i915->drm, "Failed to kzalloc()\n");
goto end;
}

/* Program the command */
cmd_ptr = cmd;
for (session_index = 0; session_index < session_num_max; session_index++) {
if (is_hw_session_in_play(i915, session_type, session_index)) {
cmd_ptr += add_pxp_prolog(i915, cmd_ptr, session_type, session_index);
cmd_ptr += add_pxp_inline_termination(cmd_ptr);
}
}
cmd_ptr += add_pxp_epilog(cmd_ptr);

if (cmd_size_in_dw != (cmd_ptr - cmd)) {
ret = -EINVAL;
drm_dbg(&i915->drm, "Failed to %s\n", __func__);
goto end;
}

if (drm_debug_enabled(DRM_UT_DRIVER)) {
print_hex_dump(KERN_DEBUG, "global termination cmd binaries:",
DUMP_PREFIX_OFFSET, 4, 4, cmd, cmd_size_in_dw * 4, true);
}

ret = pxp_submit_cmd(i915, cmd, cmd_size_in_dw);
if (ret) {
drm_dbg(&i915->drm, "Failed to pxp_submit_cmd()\n");
goto end;
}

end:
kfree(cmd);
drm_dbg(&i915->drm, "<<< %s ret=[%d]\n", __func__, ret);
return ret;
}

/**
* terminate_protected_session - To terminate an active HW session and free its entry.
* @i915: i915 device handle.
@@ -1076,6 +1143,57 @@ int pxp_sm_terminate_protected_session_unsafe(struct drm_i915_private *i915, int
return ret;
}

int intel_pxp_sm_destroy_all_sw_sessions(struct drm_i915_private *i915, int session_type)
{
int ret = 0;
struct pxp_protected_session *current_session, *n;

list_for_each_entry_safe(current_session, n, pxp_session_list(i915, session_type), session_list) {
ret = pxp_set_pxp_tag(i915, session_type, current_session->session_index, PROTECTION_MODE_NONE);
if (ret)
drm_dbg(&i915->drm, "Failed to pxp_set_pxp_tag()\n");

list_del(&current_session->session_list);
kfree(current_session);
}

return ret;
}

/**
* intel_pxp_sm_terminate_all_active_sessions - Terminate all active HW sessions and their entries.
* @i915: i915 device handle.
* @session_type: Type of the sessions to be terminated.
* One of enum pxp_session_types.
*
* This function is NOT intended to be called from the ioctl, and need to be protected by
* ctx_mutex to ensure no SIP change during the call.
*
* Return: status. 0 means terminate is successful.
*/
int intel_pxp_sm_terminate_all_active_sessions(struct drm_i915_private *i915, int session_type)
{
int ret;

lockdep_assert_held(&i915->pxp.r0ctx->ctx_mutex);

/* terminate the hw sessions */
ret = terminate_all_hw_sessions_with_global_termination(i915, session_type);
if (ret) {
drm_dbg(&i915->drm, "Failed to terminate_all_hw_sessions_with_global_termination\n");
goto end;
}

ret = intel_pxp_sm_destroy_all_sw_sessions(i915, session_type);
if (ret) {
drm_dbg(&i915->drm, "Failed to intel_pxp_sm_destroy_all_sw_sessions\n");
goto end;
}

end:
return ret;
}

int pxp_sm_ioctl_query_pxp_tag(struct drm_i915_private *i915, u32 *session_is_alive, u32 *pxp_tag)
{
int session_type = 0;
@@ -108,6 +108,7 @@ int pxp_sm_terminate_protected_session_safe(struct drm_i915_private *i915, int c
int session_type, int session_id);
int pxp_sm_terminate_protected_session_unsafe(struct drm_i915_private *i915, int session_type,
int session_id);
int intel_pxp_sm_terminate_all_active_sessions(struct drm_i915_private *i915, int session_type);
int pxp_sm_ioctl_query_pxp_tag(struct drm_i915_private *i915, u32 *session_is_alive, u32 *pxp_tag);
int pxp_sm_set_kcr_init_reg(struct drm_i915_private *i915);
u32 intel_pxp_get_pxp_tag(struct drm_i915_private *i915, int session_idx,

0 comments on commit b2c5c38

Please sign in to comment.