[Intel-gfx] [RFC-v9 14/23] drm/i915/pxp: Implement ioctl action to reserve session slots
Huang, Sean Z
sean.z.huang at intel.com
Tue Dec 15 01:07:17 UTC 2020
With this ioctl action, userspace driver can reserve one or
multiple session slot/id assigned by kernel PXP, as the first
step of PXP session establishment flow. The session info is
stored in the session list structure.
Signed-off-by: Huang, Sean Z <sean.z.huang at intel.com>
---
drivers/gpu/drm/i915/Makefile | 1 +
drivers/gpu/drm/i915/pxp/intel_pxp.c | 91 +++++++++
drivers/gpu/drm/i915/pxp/intel_pxp.h | 22 +++
drivers/gpu/drm/i915/pxp/intel_pxp_arb.c | 2 -
drivers/gpu/drm/i915/pxp/intel_pxp_cmd.c | 3 -
drivers/gpu/drm/i915/pxp/intel_pxp_context.c | 3 +
drivers/gpu/drm/i915/pxp/intel_pxp_context.h | 3 +
drivers/gpu/drm/i915/pxp/intel_pxp_sm.c | 194 +++++++++++++++++++
drivers/gpu/drm/i915/pxp/intel_pxp_sm.h | 43 ++++
9 files changed, 357 insertions(+), 5 deletions(-)
create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp_sm.c
create mode 100644 drivers/gpu/drm/i915/pxp/intel_pxp_sm.h
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index d419dfa4923d..f8ef435b35d4 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -262,6 +262,7 @@ i915-$(CONFIG_DRM_I915_PXP) += \
pxp/intel_pxp_cmd.o \
pxp/intel_pxp_context.o \
pxp/intel_pxp_pm.o \
+ pxp/intel_pxp_sm.o \
pxp/intel_pxp_tee.o
# Post-mortem debug and GPU hang state capture
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c b/drivers/gpu/drm/i915/pxp/intel_pxp.c
index ce3760206b76..e294134fef78 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp.c
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c
@@ -7,6 +7,7 @@
#include "intel_pxp_context.h"
#include "intel_pxp_tee.h"
#include "intel_pxp_arb.h"
+#include "intel_pxp_sm.h"
/* KCR register definitions */
#define KCR_INIT _MMIO(0x320f0)
@@ -14,6 +15,36 @@
/* Setting KCR Init bit is required after system boot */
#define KCR_INIT_ALLOW_DISPLAY_ME_WRITES (BIT(14) | (BIT(14) << KCR_INIT_MASK_SHIFT))
+#define PXP_ACTION_SET_SESSION_STATUS 1
+#define PXP_REQ_SESSION_ID_INIT 0
+
+/*
+ * struct pxp_set_session_status_params - Params to reserved, set or destroy
+ * the session from the PXP state machine.
+ */
+struct pxp_set_session_status_params {
+ u32 pxp_tag; /* in [optional], out pxp tag */
+ u32 session_type; /* in, session type */
+ u32 session_mode; /* in, session mode */
+ u32 req_session_state; /* in, new session state */
+};
+
+/* struct pxp_info - Params for PXP operation. */
+struct pxp_info {
+ u32 action; /* in - specified action of this operation */
+ u32 sm_status; /* out - status output for this operation */
+
+ /* in - action params to set the PXP session state */
+ struct pxp_set_session_status_params set_session_status;
+} __attribute__((packed));
+
+struct drm_i915_pxp_ops {
+ /* in - user space pointer to struct pxp_info */
+ struct pxp_info __user *info_ptr;
+ /* in - memory size that info_ptr points to */
+ u32 info_size;
+};
+
static void intel_pxp_write_irq_mask_reg(struct intel_gt *gt, u32 mask)
{
lockdep_assert_held(>->irq_lock);
@@ -152,3 +183,63 @@ bool intel_pxp_gem_object_status(struct drm_i915_private *i915)
else
return false;
}
+
+int i915_pxp_ops_ioctl(struct drm_device *dev, void *data, struct drm_file *drmfile)
+{
+ int ret;
+ struct pxp_info pxp_info = {0};
+ struct drm_i915_pxp_ops *pxp_ops = data;
+ struct drm_i915_private *i915 = to_i915(dev);
+ struct intel_pxp *pxp = &i915->gt.pxp;
+
+ if (pxp->ctx.id == 0 || !drmfile || !pxp_ops ||
+ pxp_ops->info_size != sizeof(pxp_info))
+ return -EINVAL;
+
+ if (copy_from_user(&pxp_info, pxp_ops->info_ptr, sizeof(pxp_info)) != 0)
+ return -EFAULT;
+
+ mutex_lock(&pxp->ctx.mutex);
+
+ if (pxp->ctx.global_state_in_suspend) {
+ drm_err(&i915->drm, "Return failure due to state in suspend\n");
+ pxp_info.sm_status = PXP_SM_STATUS_SESSION_NOT_AVAILABLE;
+ ret = 0;
+ goto end;
+ }
+
+ if (pxp->ctx.global_state_attacked) {
+ drm_err(&i915->drm, "Retry required due to state attacked\n");
+ pxp_info.sm_status = PXP_SM_STATUS_RETRY_REQUIRED;
+ ret = 0;
+ goto end;
+ }
+
+ if (pxp_info.action == PXP_ACTION_SET_SESSION_STATUS) {
+ struct pxp_set_session_status_params *params = &pxp_info.set_session_status;
+
+ if (params->req_session_state == PXP_REQ_SESSION_ID_INIT) {
+ ret = intel_pxp_sm_ioctl_reserve_session(pxp, drmfile,
+ params->session_type,
+ params->session_mode,
+ ¶ms->pxp_tag);
+ if (ret == PXP_SM_STATUS_RETRY_REQUIRED ||
+ ret == PXP_SM_STATUS_SESSION_NOT_AVAILABLE) {
+ pxp_info.sm_status = ret;
+ ret = 0;
+ }
+ } else {
+ ret = -EINVAL;
+ }
+ } else {
+ ret = -EINVAL;
+ }
+
+end:
+ mutex_unlock(&pxp->ctx.mutex);
+
+ if (ret == 0)
+ if (copy_to_user(pxp_ops->info_ptr, &pxp_info, sizeof(pxp_info)) != 0)
+ ret = -EFAULT;
+ return ret;
+}
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.h b/drivers/gpu/drm/i915/pxp/intel_pxp.h
index 027c0eb84a52..461b9321441f 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp.h
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp.h
@@ -7,12 +7,21 @@
#define __INTEL_PXP_H__
#include <linux/workqueue.h>
+#include <drm/drm_file.h>
#include "intel_pxp_context.h"
#define PXP_IRQ_VECTOR_DISPLAY_PXP_STATE_TERMINATED BIT(1)
#define PXP_IRQ_VECTOR_DISPLAY_APP_TERM_PER_FW_REQ BIT(2)
#define PXP_IRQ_VECTOR_PXP_DISP_STATE_RESET_COMPLETE BIT(3)
+#define GEN12_KCR_SIP _MMIO(0x32260) /* KCR type0 session in play 0-31 */
+
+#define PXP_MAX_TYPE0_SESSIONS 16
+#define PXP_MAX_TYPE1_SESSIONS 6
+
+/* we need to reserve one type0 slot for arbitrary session */
+#define PXP_MAX_NORMAL_TYPE0_SESSIONS (PXP_MAX_TYPE0_SESSIONS - 1)
+
enum pxp_session_types {
SESSION_TYPE_TYPE0 = 0,
SESSION_TYPE_TYPE1 = 1,
@@ -29,6 +38,13 @@ enum pxp_protection_modes {
PROTECTION_MODE_ALL
};
+enum pxp_sm_status {
+ PXP_SM_STATUS_SUCCESS,
+ PXP_SM_STATUS_RETRY_REQUIRED,
+ PXP_SM_STATUS_SESSION_NOT_AVAILABLE,
+ PXP_SM_STATUS_ERROR_UNKNOWN
+};
+
struct intel_pxp {
struct work_struct irq_work;
u32 handled_irr;
@@ -47,6 +63,7 @@ int i915_pxp_global_terminate_complete_callback(struct intel_pxp *pxp);
int intel_pxp_init(struct intel_pxp *pxp);
void intel_pxp_uninit(struct intel_pxp *pxp);
bool intel_pxp_gem_object_status(struct drm_i915_private *i915);
+int i915_pxp_ops_ioctl(struct drm_device *dev, void *data, struct drm_file *drmfile);
#else
static inline void intel_pxp_irq_handler(struct intel_pxp *pxp, u16 iir)
{
@@ -75,6 +92,11 @@ static inline bool intel_pxp_gem_object_status(struct drm_i915_private *i915)
{
return false;
}
+
+static inline int i915_pxp_ops_ioctl(struct drm_device *dev, void *data, struct drm_file *drmfile)
+{
+ return 0;
+}
#endif
#endif /* __INTEL_PXP_PM_H__ */
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_arb.c b/drivers/gpu/drm/i915/pxp/intel_pxp_arb.c
index d94b08fe9190..a3a1df42a869 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_arb.c
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_arb.c
@@ -12,8 +12,6 @@
#include "intel_pxp_tee.h"
#include "intel_pxp_cmd.h"
-#define GEN12_KCR_SIP _MMIO(0x32260) /* KCR type0 session in play 0-31 */
-
/* Arbitrary session */
#define ARB_SESSION_INDEX 0xf
#define ARB_SESSION_TYPE SESSION_TYPE_TYPE0
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.c b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.c
index ab9c5a1b826c..d304c704c943 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.c
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_cmd.c
@@ -24,9 +24,6 @@
/* CRYPTO_KEY_EXCHANGE */
#define CRYPTO_KEY_EXCHANGE ((0x3 << 29) | (0x01609 << 16))
-#define PXP_MAX_TYPE0_SESSIONS 16
-#define PXP_MAX_TYPE1_SESSIONS 6
-
static struct i915_vma *intel_pxp_cmd_get_batch(struct intel_pxp *pxp,
struct intel_context *ce,
struct intel_gt_buffer_pool_node *pool,
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_context.c b/drivers/gpu/drm/i915/pxp/intel_pxp_context.c
index d00f4e0b88ba..f690c1470bd5 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_context.c
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_context.c
@@ -17,6 +17,9 @@ void intel_pxp_ctx_init(struct pxp_context *ctx)
ctx->global_state_attacked = false;
mutex_init(&ctx->mutex);
+
+ INIT_LIST_HEAD(&ctx->type0_sessions);
+ INIT_LIST_HEAD(&ctx->type1_sessions);
}
/**
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_context.h b/drivers/gpu/drm/i915/pxp/intel_pxp_context.h
index 8d3308ac3120..4c583f831831 100644
--- a/drivers/gpu/drm/i915/pxp/intel_pxp_context.h
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_context.h
@@ -17,6 +17,9 @@ struct pxp_context {
struct pxp_protected_session arb_session;
u32 arb_session_pxp_tag;
+ struct list_head type0_sessions;
+ struct list_head type1_sessions;
+
int id;
bool global_state_attacked;
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_sm.c b/drivers/gpu/drm/i915/pxp/intel_pxp_sm.c
new file mode 100644
index 000000000000..e30be334d0dd
--- /dev/null
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_sm.c
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright(c) 2020, Intel Corporation. All rights reserved.
+ */
+#include "gt/intel_context.h"
+#include "gt/intel_engine_pm.h"
+#include "intel_pxp_sm.h"
+#include "intel_pxp.h"
+
+#define KCR_STATUS_1 _MMIO(0x320f4)
+#define KCR_STATUS_1_ATTACK_MASK 0x80000000
+
+#define GEN12_KCR_TSIP _MMIO(0x32264) /* KCR type1 session in play 0-63 */
+
+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)
+{
+ return (session_type == SESSION_TYPE_TYPE0) ?
+ &pxp->ctx.type0_sessions : &pxp->ctx.type1_sessions;
+}
+
+/**
+ * is_sw_session_active - Check if the given sw session id is active.
+ * @pxp: pointer to pxp struct
+ * @session_type: Specified session type
+ * @session_index: Numeric session identifier.
+ * @is_in_play: Set false to return true if the specified session is active.
+ * Set true to also check if the session is active and in_play.
+ *
+ * The caller needs to use mutex lock to protect the session list
+ * inside this function.
+ *
+ * Return : true if session with the same identifier is active (and in_play).
+ */
+static bool is_sw_session_active(struct intel_pxp *pxp, int session_type,
+ int session_index, bool is_in_play)
+{
+ struct intel_pxp_sm_session *curr, *n;
+
+ lockdep_assert_held(&pxp->ctx.mutex);
+
+ list_for_each_entry_safe(curr, n, session_list(pxp, session_type), list) {
+ if (curr->index == session_index) {
+ if (is_in_play && !curr->is_in_play)
+ return false;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool is_hw_session_in_play(struct intel_pxp *pxp,
+ int session_type, int session_index)
+{
+ u64 regval_sip = 0;
+ intel_wakeref_t wakeref;
+ struct intel_gt *gt = container_of(pxp, struct intel_gt, pxp);
+
+ with_intel_runtime_pm(>->i915->runtime_pm, wakeref) {
+ if (session_type == SESSION_TYPE_TYPE0)
+ regval_sip = intel_uncore_read(gt->uncore, GEN12_KCR_SIP);
+ else
+ regval_sip = intel_uncore_read64(gt->uncore, GEN12_KCR_TSIP);
+ }
+
+ return regval_sip & BIT(session_index);
+}
+
+/* wait hw session_in_play reg to match the current sw state */
+static int wait_hw_sw_state(struct intel_pxp *pxp, int session_index, int session_type)
+{
+ const int max_retry = 10;
+ int retry = 0;
+
+ for (retry = 0; retry < max_retry; retry++) {
+ if (is_hw_session_in_play(pxp, session_type, session_index) ==
+ is_sw_session_active(pxp, session_type, session_index, true))
+ return 0;
+
+ msleep(10);
+ }
+ return -EINVAL;
+}
+
+/**
+ * is_type0_session_attacked - To check if type0 active sessions are attacked.
+ * @pxp: pointer pxp struct
+ *
+ * Return: true if hardware sessions is attacked, false otherwise.
+ */
+static bool is_type0_session_attacked(struct intel_pxp *pxp)
+{
+ u32 regval = 0;
+ intel_wakeref_t wakeref;
+ struct intel_gt *gt = container_of(pxp, struct intel_gt, pxp);
+
+ if (pxp->ctx.global_state_attacked)
+ return true;
+
+ with_intel_runtime_pm(>->i915->runtime_pm, wakeref)
+ regval = intel_uncore_read(gt->uncore, KCR_STATUS_1);
+
+ return regval & KCR_STATUS_1_ATTACK_MASK;
+}
+
+/**
+ * create_session_entry - Create a new session entry with provided info.
+ * @pxp: pointer to pxp struct
+ * @drmfile: pointer to drm_file
+ * @context_id: Numeric identifier of the context created by the caller.
+ * @session_type: Type of the session requested. One of enum pxp_session_types.
+ * @protection_mode: Type of protection requested for the session.
+ * One of the enum pxp_protection_modes.
+ * @session_index: Numeric session identifier.
+ *
+ * Return: status. 0 means creation is successful.
+ */
+static int create_session_entry(struct intel_pxp *pxp, struct drm_file *drmfile,
+ int context_id, int session_type, int protection_mode,
+ int session_index)
+{
+ struct intel_pxp_sm_session *session = NULL;
+ int pid = 0;
+
+ if (drmfile)
+ pid = pid_nr(drmfile->pid);
+
+ session = kzalloc(sizeof(*session), GFP_KERNEL);
+ if (!session)
+ return -ENOMEM;
+
+ session->context_id = context_id;
+ session->type = session_type;
+ session->protection_mode = protection_mode;
+ session->index = session_index;
+ session->is_in_play = false;
+ session->drmfile = drmfile;
+ session->pid = pid;
+
+ list_add(&session->list, session_list(pxp, session_type));
+ return 0;
+}
+
+/**
+ * intel_pxp_sm_ioctl_reserve_session - To reserve an available protected session.
+ * @pxp: pointer to pxp struct
+ * @drmfile: pointer to drm_file.
+ * @session_type: Type of the session requested. One of enum pxp_session_types.
+ * @protection_mode: Type of protection requested for the session. One of the
+ * enum pxp_protection_modes.
+ * @pxp_tag: Numeric session identifier returned back to caller.
+ *
+ * Return: status. 0 means reserve is successful.
+ */
+int intel_pxp_sm_ioctl_reserve_session(struct intel_pxp *pxp, struct drm_file *drmfile,
+ int session_type, int protection_mode,
+ u32 *pxp_tag)
+{
+ int ret;
+ int idx = 0;
+
+ if (!drmfile || !pxp_tag)
+ return -EINVAL;
+
+ lockdep_assert_held(&pxp->ctx.mutex);
+
+ /* check if sessions are under attack. if so, don't allow creation */
+ if (session_type == SESSION_TYPE_TYPE0 &&
+ is_type0_session_attacked(pxp))
+ return -EPERM;
+
+ for (idx = 0; idx < 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)
+ return PXP_SM_STATUS_RETRY_REQUIRED;
+
+ ret = create_session_entry(pxp, drmfile, pxp->ctx.id,
+ session_type,
+ protection_mode, idx);
+ *pxp_tag = idx;
+ return ret;
+ }
+ }
+
+ return PXP_SM_STATUS_SESSION_NOT_AVAILABLE;
+}
diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_sm.h b/drivers/gpu/drm/i915/pxp/intel_pxp_sm.h
new file mode 100644
index 000000000000..75fffb7d8b0e
--- /dev/null
+++ b/drivers/gpu/drm/i915/pxp/intel_pxp_sm.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright(c) 2020, Intel Corporation. All rights reserved.
+ */
+
+#ifndef __INTEL_PXP_SM_H__
+#define __INTEL_PXP_SM_H__
+
+#include "intel_pxp.h"
+
+/**
+ * struct pxp_protected_session - linked list to track all active sessions.
+ */
+struct intel_pxp_sm_session {
+ /** @list: linked list infrastructure, do not change its order. */
+ struct list_head list;
+ /** @index: Numeric identifier for this protected session */
+ int index;
+ /** @type: Type of session */
+ int type;
+ /** @protection_mode: mode of protection requested */
+ int protection_mode;
+ /** @context_id: context identifier of the protected session requestor */
+ int context_id;
+ /** @pid: pid of this session's creator */
+ int pid;
+ /** @drmfile: pointer to drm_file, which is allocated on device file open() call */
+ struct drm_file *drmfile;
+
+ /**
+ * @is_in_play: indicates whether the session has been established
+ * in the HW root of trust if this flag is false, it
+ * indicates an application has reserved this session,
+ * but has not established the session in the hardware
+ * yet.
+ */
+ bool is_in_play;
+};
+
+int intel_pxp_sm_ioctl_reserve_session(struct intel_pxp *pxp, struct drm_file *drmfile,
+ int session_type, int protection_mode,
+ u32 *pxp_tag);
+#endif /* __INTEL_PXP_SM_H__ */
--
2.17.1
More information about the Intel-gfx
mailing list