Implement the PXP ioctl action to allow userspace driver to terminate the hardware session and cleanup its software session state. PXP sends the session termination command to GPU once receves this ioctl action.
Signed-off-by: Huang, Sean Z <sean.z.hu...@intel.com> --- drivers/gpu/drm/i915/pxp/intel_pxp.c | 10 +++ drivers/gpu/drm/i915/pxp/intel_pxp.h | 6 ++ drivers/gpu/drm/i915/pxp/intel_pxp_cmd.c | 56 ++++++++++++ drivers/gpu/drm/i915/pxp/intel_pxp_cmd.h | 2 + drivers/gpu/drm/i915/pxp/intel_pxp_pm.c | 7 ++ drivers/gpu/drm/i915/pxp/intel_pxp_sm.c | 109 ++++++++++++++++++++--- drivers/gpu/drm/i915/pxp/intel_pxp_sm.h | 6 ++ 7 files changed, 186 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c b/drivers/gpu/drm/i915/pxp/intel_pxp.c index e000a78b782e..c35011b84f5a 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c @@ -8,6 +8,7 @@ #include "intel_pxp_tee.h" #include "intel_pxp_arb.h" #include "intel_pxp_sm.h" +#include "intel_pxp_cmd.h" /* KCR register definitions */ #define KCR_INIT _MMIO(0x320f0) @@ -22,6 +23,8 @@ enum pxp_session_req { PXP_REQ_SESSION_ID_INIT = 0x0, /* Inform KMD that UMD has completed the initialization */ PXP_REQ_SESSION_IN_PLAY, + /* Request KMD to terminate the session */ + PXP_REQ_SESSION_TERMINATE }; /* @@ -68,7 +71,11 @@ static int intel_pxp_teardown_required_callback(struct intel_pxp *pxp) pxp->ctx.flag_display_hm_surface_keys = false; ret = intel_pxp_arb_terminate_session(pxp); + if (ret) + goto end; + ret = intel_pxp_sm_terminate_all_sessions(pxp, SESSION_TYPE_TYPE0); +end: mutex_unlock(&pxp->ctx.mutex); return ret; @@ -237,6 +244,9 @@ int i915_pxp_ops_ioctl(struct drm_device *dev, void *data, struct drm_file *drmf } else if (params->req_session_state == PXP_REQ_SESSION_IN_PLAY) { ret = intel_pxp_sm_ioctl_mark_session_in_play(pxp, params->session_type, params->pxp_tag); + } else if (params->req_session_state == PXP_REQ_SESSION_TERMINATE) { + ret = intel_pxp_sm_ioctl_terminate_session(pxp, params->session_type, + params->pxp_tag); } else { ret = -EINVAL; } diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.h b/drivers/gpu/drm/i915/pxp/intel_pxp.h index 461b9321441f..e68c035d8448 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.h @@ -53,6 +53,12 @@ struct intel_pxp { struct pxp_context ctx; }; +static inline int pxp_session_max(int session_type) +{ + return (session_type == SESSION_TYPE_TYPE0) ? + PXP_MAX_NORMAL_TYPE0_SESSIONS : PXP_MAX_TYPE1_SESSIONS; +} + struct drm_i915_private; #ifdef CONFIG_DRM_I915_PXP diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.c b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.c index d304c704c943..e38a8c36753e 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.c @@ -7,6 +7,7 @@ #include "i915_drv.h" #include "gt/intel_context.h" #include "gt/intel_engine_pm.h" +#include "intel_pxp_sm.h" /* PXP GPU command definitions */ @@ -273,3 +274,58 @@ int intel_pxp_cmd_add_inline_termination(u32 *cmd) increased_size_in_dw = (cmd_termin - cmd); return increased_size_in_dw; } + +int intel_pxp_cmd_terminate_all_hw_session(struct intel_pxp *pxp, + int session_type) +{ + u32 *cmd = NULL; + u32 *cmd_ptr = NULL; + int cmd_size_in_dw = 0; + int ret; + int idx; + struct intel_gt *gt = container_of(pxp, struct intel_gt, pxp); + + /* Calculate how many bytes need to be alloc */ + for (idx = 0; idx < pxp_session_max(session_type); idx++) { + if (intel_pxp_sm_is_hw_session_in_play(pxp, session_type, idx)) { + cmd_size_in_dw += intel_pxp_cmd_add_prolog(pxp, NULL, session_type, idx); + cmd_size_in_dw += intel_pxp_cmd_add_inline_termination(NULL); + } + } + cmd_size_in_dw += intel_pxp_cmd_add_epilog(NULL); + + cmd = kzalloc(cmd_size_in_dw * 4, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + /* Program the command */ + cmd_ptr = cmd; + for (idx = 0; idx < pxp_session_max(session_type); idx++) { + if (intel_pxp_sm_is_hw_session_in_play(pxp, session_type, idx)) { + cmd_ptr += intel_pxp_cmd_add_prolog(pxp, cmd_ptr, session_type, idx); + cmd_ptr += intel_pxp_cmd_add_inline_termination(cmd_ptr); + } + } + cmd_ptr += intel_pxp_cmd_add_epilog(cmd_ptr); + + if (cmd_size_in_dw != (cmd_ptr - cmd)) { + ret = -EINVAL; + drm_err(>->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 = intel_pxp_cmd_submit(pxp, cmd, cmd_size_in_dw); + if (ret) { + drm_err(>->i915->drm, "Failed to pxp_submit_cmd()\n"); + goto end; + } + +end: + kfree(cmd); + return ret; +} diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.h b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.h index 087f260034c4..ba008aa5df4e 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.h @@ -16,5 +16,7 @@ int intel_pxp_cmd_add_prolog(struct intel_pxp *pxp, u32 *cmd, int session_index); int intel_pxp_cmd_add_epilog(u32 *cmd); int intel_pxp_cmd_add_inline_termination(u32 *cmd); +int intel_pxp_cmd_terminate_all_hw_session(struct intel_pxp *pxp, + int session_type); #endif /* __INTEL_PXP_SM_H__ */ diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_pm.c b/drivers/gpu/drm/i915/pxp/intel_pxp_pm.c index 0da2ecbf3b4d..73ec5e47b485 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_pm.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_pm.c @@ -6,6 +6,7 @@ #include "intel_pxp_context.h" #include "intel_pxp_arb.h" #include "intel_pxp_pm.h" +#include "intel_pxp_sm.h" void intel_pxp_pm_prepare_suspend(struct intel_pxp *pxp) { @@ -55,6 +56,12 @@ int intel_pxp_pm_resume(struct intel_pxp *pxp) goto end; } + ret = intel_pxp_sm_terminate_all_sessions(pxp, SESSION_TYPE_TYPE0); + if (ret) { + drm_err(>->i915->drm, "Failed to terminate the sessions\n"); + goto end; + } + pxp->ctx.global_state_in_suspend = false; } diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_sm.c b/drivers/gpu/drm/i915/pxp/intel_pxp_sm.c index a657c5c7f013..a94897768c41 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_sm.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_sm.c @@ -6,6 +6,7 @@ #include "gt/intel_engine_pm.h" #include "intel_pxp_sm.h" #include "intel_pxp.h" +#include "intel_pxp_cmd.h" #define KCR_STATUS_1 _MMIO(0x320f4) #define KCR_STATUS_1_ATTACK_MASK 0x80000000 @@ -15,12 +16,6 @@ #define SESSION_TYPE_MASK BIT(7) #define SESSION_ID_MASK (BIT(7) - 1) -static inline int session_max(int session_type) -{ - return (session_type == SESSION_TYPE_TYPE0) ? - PXP_MAX_NORMAL_TYPE0_SESSIONS : PXP_MAX_TYPE1_SESSIONS; -} - static inline struct list_head *session_list(struct intel_pxp *pxp, int session_type) { @@ -59,8 +54,8 @@ static bool is_sw_session_active(struct intel_pxp *pxp, int session_type, return false; } -static bool is_hw_session_in_play(struct intel_pxp *pxp, - int session_type, int session_index) +bool intel_pxp_sm_is_hw_session_in_play(struct intel_pxp *pxp, + int session_type, int session_index) { u64 regval_sip = 0; intel_wakeref_t wakeref; @@ -83,7 +78,7 @@ static int wait_hw_sw_state(struct intel_pxp *pxp, int session_index, int sessio int retry = 0; for (retry = 0; retry < max_retry; retry++) { - if (is_hw_session_in_play(pxp, session_type, session_index) == + if (intel_pxp_sm_is_hw_session_in_play(pxp, session_type, session_index) == is_sw_session_active(pxp, session_type, session_index, true)) return 0; @@ -162,6 +157,45 @@ static int pxp_get_session_index(u32 session_id, int *index_out, int *type_out) return 0; } +static int pxp_terminate_hw_session(struct intel_pxp *pxp, int session_type, + int session_index) +{ + u32 *cmd = NULL; + u32 *cmd_ptr = NULL; + int cmd_size_in_dw = 0; + int ret; + struct intel_gt *gt = container_of(pxp, struct intel_gt, pxp); + + cmd_size_in_dw += intel_pxp_cmd_add_prolog(pxp, NULL, session_type, session_index); + cmd_size_in_dw += intel_pxp_cmd_add_inline_termination(NULL); + cmd_size_in_dw += intel_pxp_cmd_add_epilog(NULL); + + cmd = kzalloc(cmd_size_in_dw * 4, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd_ptr = cmd; + cmd_ptr += intel_pxp_cmd_add_prolog(pxp, cmd_ptr, session_type, session_index); + cmd_ptr += intel_pxp_cmd_add_inline_termination(cmd_ptr); + cmd_ptr += intel_pxp_cmd_add_epilog(cmd_ptr); + + if (cmd_size_in_dw != (cmd_ptr - cmd)) { + ret = -EINVAL; + drm_err(>->i915->drm, "Failed to %s\n", __func__); + goto end; + } + + ret = intel_pxp_cmd_submit(pxp, cmd, cmd_size_in_dw); + if (ret) { + drm_err(>->i915->drm, "Failed to submit cmd()\n"); + goto end; + } + +end: + kfree(cmd); + return ret; +} + /** * intel_pxp_sm_ioctl_reserve_session - To reserve an available protected session. * @pxp: pointer to pxp struct @@ -190,7 +224,7 @@ int intel_pxp_sm_ioctl_reserve_session(struct intel_pxp *pxp, struct drm_file *d is_type0_session_attacked(pxp)) return -EPERM; - for (idx = 0; idx < session_max(session_type); idx++) { + for (idx = 0; idx < pxp_session_max(session_type); idx++) { if (!is_sw_session_active(pxp, session_type, idx, false)) { ret = wait_hw_sw_state(pxp, idx, session_type); if (ret) @@ -243,3 +277,58 @@ int intel_pxp_sm_ioctl_mark_session_in_play(struct intel_pxp *pxp, int session_t drm_err(>->i915->drm, "Failed to %s couldn't find active session\n", __func__); return -EINVAL; } + +/** + * intel_pxp_sm_ioctl_terminate_session - To terminate an active HW session and free its entry. + * @pxp: pointer to pxp struct. + * @session_type: type of the session to be terminated. One of enum pxp_session_types. + * @session_id: Session identifier of the session, containing type and index info + * + * Return: 0 means terminate is successful, or didn't find the desired session. + */ +int intel_pxp_sm_ioctl_terminate_session(struct intel_pxp *pxp, int session_type, + int session_id) +{ + int ret; + struct intel_pxp_sm_session *curr, *n; + int session_type_in_id; + int session_index; + + lockdep_assert_held(&pxp->ctx.mutex); + + ret = pxp_get_session_index(session_id, &session_index, &session_type_in_id); + if (ret) + return ret; + + list_for_each_entry_safe(curr, n, session_list(pxp, session_type), list) { + if (curr->index == session_index) { + ret = pxp_terminate_hw_session(pxp, session_type, session_index); + if (ret) + return ret; + + list_del(&curr->list); + kfree(curr); + return 0; + } + } + return 0; +} + +int intel_pxp_sm_terminate_all_sessions(struct intel_pxp *pxp, int session_type) +{ + int ret; + struct intel_pxp_sm_session *curr, *n; + + lockdep_assert_held(&pxp->ctx.mutex); + + ret = intel_pxp_cmd_terminate_all_hw_session(pxp, session_type); + if (ret) + return ret; + + list_for_each_entry_safe(curr, n, session_list(pxp, session_type), list) { + list_del(&curr->list); + kfree(curr); + } + + return ret; +} diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_sm.h b/drivers/gpu/drm/i915/pxp/intel_pxp_sm.h index aaa44d365f39..e242b7566021 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_sm.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_sm.h @@ -42,4 +42,10 @@ int intel_pxp_sm_ioctl_reserve_session(struct intel_pxp *pxp, struct drm_file *d u32 *pxp_tag); int intel_pxp_sm_ioctl_mark_session_in_play(struct intel_pxp *pxp, int session_type, u32 session_id); +int intel_pxp_sm_ioctl_terminate_session(struct intel_pxp *pxp, int session_type, + int session_id); + +bool intel_pxp_sm_is_hw_session_in_play(struct intel_pxp *pxp, + int session_type, int session_index); +int intel_pxp_sm_terminate_all_sessions(struct intel_pxp *pxp, int session_type); #endif /* __INTEL_PXP_SM_H__ */ -- 2.17.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx