@@ -275,6 +275,7 @@ i915-$(CONFIG_DRM_I915_PXP) += \
pxp/intel_pxp.o \
pxp/intel_pxp_cmd.o \
pxp/intel_pxp_irq.o \
+ pxp/intel_pxp_pm.o \
pxp/intel_pxp_session.o \
pxp/intel_pxp_tee.o
@@ -19,6 +19,7 @@
#include "intel_rc6.h"
#include "intel_rps.h"
#include "intel_wakeref.h"
+#include "pxp/intel_pxp_pm.h"
static void user_forcewake(struct intel_gt *gt, bool suspend)
{
@@ -260,6 +261,8 @@ int intel_gt_resume(struct intel_gt *gt)
intel_uc_resume(>->uc);
+ intel_pxp_pm_resume(>->pxp);
+
user_forcewake(gt, false);
out_fw:
@@ -294,6 +297,7 @@ void intel_gt_suspend_prepare(struct intel_gt *gt)
user_forcewake(gt, true);
wait_for_suspend(gt);
+ intel_pxp_pm_prepare_suspend(>->pxp);
intel_uc_suspend(>->uc);
}
@@ -344,6 +348,7 @@ void intel_gt_suspend_late(struct intel_gt *gt)
void intel_gt_runtime_suspend(struct intel_gt *gt)
{
+ intel_pxp_runtime_suspend(>->pxp);
intel_uc_runtime_suspend(>->uc);
GT_TRACE(gt, "\n");
@@ -351,11 +356,18 @@ void intel_gt_runtime_suspend(struct intel_gt *gt)
int intel_gt_runtime_resume(struct intel_gt *gt)
{
+ int ret;
+
GT_TRACE(gt, "\n");
intel_gt_init_swizzling(gt);
intel_ggtt_restore_fences(gt->ggtt);
- return intel_uc_runtime_resume(>->uc);
+ ret = intel_uc_runtime_resume(>->uc);
+
+ if (!ret)
+ ret = intel_pxp_runtime_resume(>->pxp);
+
+ return ret;
}
ktime_t intel_gt_get_awake_time(const struct intel_gt *gt)
@@ -67,6 +67,8 @@
#include "gt/intel_gt_pm.h"
#include "gt/intel_rc6.h"
+#include "pxp/intel_pxp_pm.h"
+
#include "i915_debugfs.h"
#include "i915_drm_client.h"
#include "i915_drv.h"
@@ -125,11 +125,13 @@ void intel_pxp_irq_enable(struct intel_pxp *pxp)
struct intel_gt *gt = pxp_to_gt(pxp);
spin_lock_irq(>->irq_lock);
- if (!pxp->irq_enabled) {
+
+ if (!pxp->irq_enabled)
WARN_ON_ONCE(gen11_gt_reset_one_iir(gt, 0, GEN11_KCR));
- __pxp_set_interrupts(gt, GEN12_PXP_INTERRUPTS);
- pxp->irq_enabled = true;
- }
+
+ __pxp_set_interrupts(gt, GEN12_PXP_INTERRUPTS);
+ pxp->irq_enabled = true;
+
spin_unlock_irq(>->irq_lock);
}
new file mode 100644
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright(c) 2020 Intel Corporation.
+ */
+
+#include "intel_pxp.h"
+#include "intel_pxp_irq.h"
+#include "intel_pxp_pm.h"
+#include "intel_pxp_session.h"
+
+static void __pxp_suspend(struct intel_pxp *pxp)
+{
+ if (!intel_pxp_is_enabled(pxp))
+ return;
+
+ intel_pxp_irq_disable(pxp);
+
+ pxp->global_state_attacked = false;
+ pxp->arb_is_in_play = false;
+ pxp->global_state_in_suspend = true;
+}
+
+void intel_pxp_pm_prepare_suspend(struct intel_pxp *pxp)
+{
+ __pxp_suspend(pxp);
+}
+
+int intel_pxp_pm_resume(struct intel_pxp *pxp)
+{
+ struct intel_gt *gt = pxp_to_gt(pxp);
+ int ret = 0;
+
+ if (!intel_pxp_is_enabled(pxp))
+ return 0;
+
+ intel_pxp_irq_enable(pxp);
+
+ if (!pxp->global_state_in_suspend)
+ return 0;
+
+ mutex_lock(&pxp->mutex);
+
+ /*
+ * Note: we won't re-create the session as part of the irq generated by
+ * this termination because pxp->global_state_attacked is not set. The
+ * session will be recreated as part of the mei component re-binding.
+ */
+ intel_pxp_mark_termination_in_progress(pxp);
+ ret = intel_pxp_arb_terminate_session_with_global_terminate(pxp);
+ if (ret) {
+ drm_err(>->i915->drm,
+ "Failed to terminate the arb session on resume\n");
+ } else {
+ pxp->global_state_in_suspend = false;
+ }
+
+ mutex_unlock(&pxp->mutex);
+
+ if (!ret) {
+ ret = intel_pxp_wait_for_termination_completion(pxp);
+ if (ret) {
+ drm_err(>->i915->drm,
+ "Didn't recevive the PXP termination irq\n");
+ }
+ }
+
+ return ret;
+}
+
+void intel_pxp_runtime_suspend(struct intel_pxp *pxp)
+{
+ __pxp_suspend(pxp);
+}
+
+int intel_pxp_runtime_resume(struct intel_pxp *pxp)
+{
+ struct intel_gt *gt = pxp_to_gt(pxp);
+ int ret;
+
+ if (!intel_pxp_is_enabled(pxp))
+ return 0;
+
+ intel_pxp_irq_enable(pxp);
+ pxp->global_state_in_suspend = false;
+
+ /*
+ * if the display loses power during runtime suspend it will cause the
+ * session to become invalid, so to be safe we always re-create it. The
+ * MEI module is still bound, so this is the same as a teardown event,
+ * hence we can just pretend we received the irq.
+ */
+ intel_pxp_mark_termination_in_progress(pxp);
+
+ spin_lock_irq(>->irq_lock);
+ intel_pxp_irq_handler(pxp, GEN12_DISPLAY_PXP_STATE_TERMINATED_INTERRUPT);
+ spin_unlock_irq(>->irq_lock);
+
+ return ret;
+}
new file mode 100644
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright(c) 2020, Intel Corporation. All rights reserved.
+ */
+
+#ifndef __INTEL_PXP_PM_H__
+#define __INTEL_PXP_PM_H__
+
+#include "i915_drv.h"
+
+#ifdef CONFIG_DRM_I915_PXP
+void intel_pxp_pm_prepare_suspend(struct intel_pxp *pxp);
+int intel_pxp_pm_resume(struct intel_pxp *pxp);
+void intel_pxp_runtime_suspend(struct intel_pxp *pxp);
+int intel_pxp_runtime_resume(struct intel_pxp *pxp);
+#else
+static inline void intel_pxp_pm_prepare_suspend(struct intel_pxp *pxp)
+{
+}
+static inline int intel_pxp_pm_resume(struct intel_pxp *pxp)
+{
+ return 0;
+}
+static inline void intel_pxp_runtime_suspend(struct intel_pxp *pxp)
+{
+}
+static inline int intel_pxp_runtime_resume(struct intel_pxp *pxp)
+{
+ return 0;
+}
+#endif
+
+#endif /* __INTEL_PXP_PM_H__ */
@@ -25,8 +25,14 @@ static bool intel_pxp_session_is_in_play(struct intel_pxp *pxp, u32 id)
intel_wakeref_t wakeref;
u32 sip = 0;
- with_intel_runtime_pm(gt->uncore->rpm, wakeref)
- sip = intel_uncore_read(gt->uncore, GEN12_KCR_SIP);
+ /* if we're suspended the session is considered off */
+ wakeref = intel_runtime_pm_get_if_in_use(gt->uncore->rpm);
+ if (!wakeref)
+ return false;
+
+ sip = intel_uncore_read(gt->uncore, GEN12_KCR_SIP);
+
+ intel_runtime_pm_put(gt->uncore->rpm, wakeref);
return sip & BIT(id);
}
@@ -43,12 +49,18 @@ static int pxp_wait_for_session_state(struct intel_pxp *pxp, u32 id, bool in_pla
u32 mask = BIT(id);
int ret;
- with_intel_runtime_pm(gt->uncore->rpm, wakeref)
- ret = intel_wait_for_register(gt->uncore,
- GEN12_KCR_SIP,
- mask,
- in_play ? mask : 0,
- 100);
+ /* if we're suspended the session is considered off */
+ wakeref = intel_runtime_pm_get_if_in_use(gt->uncore->rpm);
+ if (!wakeref)
+ return in_play ? -ENODEV : 0;
+
+ ret = intel_wait_for_register(gt->uncore,
+ GEN12_KCR_SIP,
+ mask,
+ in_play ? mask : 0,
+ 100);
+
+ intel_runtime_pm_put(gt->uncore->rpm, wakeref);
return ret;
}
@@ -91,11 +91,17 @@ static int i915_pxp_tee_component_bind(struct device *i915_kdev,
{
struct drm_i915_private *i915 = kdev_to_i915(i915_kdev);
struct intel_pxp *pxp = i915_dev_to_pxp(i915_kdev);
+ intel_wakeref_t wakeref;
int ret = 0;
pxp->pxp_component = data;
pxp->pxp_component->tee_dev = tee_kdev;
+ /* if we are suspended, the session will be re-created on resume */
+ wakeref = intel_runtime_pm_get_if_in_use(&i915->runtime_pm);
+ if (!wakeref)
+ return 0;
+
mutex_lock(&pxp->mutex);
/* Create arb session only if tee is ready, during system boot or sleep/resume */
@@ -120,6 +126,8 @@ static int i915_pxp_tee_component_bind(struct device *i915_kdev,
return ret;
}
+ intel_runtime_pm_put(&i915->runtime_pm, wakeref);
+
return 0;
}
@@ -22,6 +22,7 @@ struct intel_pxp {
struct mutex mutex;
bool arb_is_in_play;
bool global_state_attacked;
+ bool global_state_in_suspend;
struct completion termination;
struct work_struct irq_work;