@@ -56,7 +56,8 @@ i915-y += i915_cmd_parser.o \
# general-purpose microcontroller (GuC) support
i915-y += intel_guc_loader.o \
- i915_guc_submission.o
+ i915_guc_submission.o \
+ intel_slpc.o
# autogenerated null render state
i915-y += intel_renderstate_gen6.o \
@@ -1697,6 +1697,8 @@ static int i915_drm_resume_early(struct drm_device *dev)
hsw_disable_pc8(dev_priv);
}
+ dev_priv->guc.slpc.active = false;
+
intel_uncore_sanitize(dev_priv);
if (IS_BROXTON(dev_priv) ||
@@ -2687,6 +2687,14 @@ void i915_gem_reset(struct drm_i915_private *dev_priv)
i915_gem_restore_fences(&dev_priv->drm);
+ /*
+ * GPU is reset at this point, Hence mark SLPC as inactive to
+ * not send h2g action to shutdown SLPC as that will fail.
+ * enable_gt_powersave will setup RC6 and ring frequencies and
+ * SLPC will be enabled post GuC initialization.
+ */
+ dev_priv->guc.slpc.active = false;
+
if (dev_priv->gt.awake) {
intel_sanitize_gt_powersave(dev_priv);
intel_enable_gt_powersave(dev_priv);
@@ -1492,6 +1492,9 @@ int i915_guc_submission_init(struct drm_i915_private *dev_priv)
guc_log_create(guc);
guc_addon_create(guc);
+ if (i915.enable_slpc)
+ intel_slpc_init(dev_priv);
+
return 0;
}
@@ -27,6 +27,7 @@
#include "intel_guc_fwif.h"
#include "i915_guc_reg.h"
#include "intel_ringbuffer.h"
+#include "intel_slpc.h"
struct drm_i915_gem_request;
@@ -167,6 +168,8 @@ struct intel_guc {
/* To serialize the Host2GuC actions */
struct mutex action_lock;
+
+ struct intel_slpc slpc;
};
/* intel_guc_loader.c */
@@ -549,6 +549,16 @@ int intel_guc_setup(struct drm_device *dev)
intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status),
intel_guc_fw_status_repr(guc_fw->guc_fw_load_status));
+ /*
+ * SLPC is enabled by setting up the shared data structure and
+ * sending reset event to GuC SLPC. Initial data is setup in
+ * intel_slpc_init. Here we send the reset event. SLPC enabling
+ * in GuC can happen in parallel in GuC with other initialization
+ * being done in i915.
+ */
+ if (i915.enable_slpc)
+ intel_slpc_enable(dev_priv);
+
if (i915.enable_guc_submission) {
if (i915.guc_log_level >= 0)
gen9_enable_guc_interrupts(dev_priv);
@@ -5016,6 +5016,9 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
void gen6_rps_busy(struct drm_i915_private *dev_priv)
{
+ if (i915.enable_slpc)
+ return;
+
mutex_lock(&dev_priv->rps.hw_lock);
if (dev_priv->rps.enabled) {
if (dev_priv->pm_rps_events & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED))
@@ -5036,6 +5039,9 @@ void gen6_rps_busy(struct drm_i915_private *dev_priv)
void gen6_rps_idle(struct drm_i915_private *dev_priv)
{
+ if (i915.enable_slpc)
+ return;
+
/* Flush our bottom-half so that it does not race with us
* setting the idle frequency and so that it is bounded by
* our rpm wakeref. And then disable the interrupts to stop any
@@ -5065,6 +5071,9 @@ void gen6_rps_boost(struct drm_i915_private *dev_priv,
struct intel_rps_client *rps,
unsigned long submitted)
{
+ if (i915.enable_slpc)
+ return;
+
/* This is intentionally racy! We peek at the state here, then
* validate inside the RPS worker.
*/
@@ -6704,7 +6713,9 @@ void intel_init_gt_powersave(struct drm_i915_private *dev_priv)
void intel_cleanup_gt_powersave(struct drm_i915_private *dev_priv)
{
- if (IS_VALLEYVIEW(dev_priv))
+ if (i915.enable_slpc)
+ intel_slpc_cleanup(dev_priv);
+ else if (IS_VALLEYVIEW(dev_priv))
valleyview_cleanup_gt_powersave(dev_priv);
if (!i915.enable_rc6)
@@ -6728,33 +6739,51 @@ void intel_suspend_gt_powersave(struct drm_i915_private *dev_priv)
intel_runtime_pm_put(dev_priv);
/* gen6_rps_idle() will be called later to disable interrupts */
+
+ if (dev_priv->guc.slpc.active) {
+ intel_runtime_pm_get(dev_priv);
+ mutex_lock(&dev_priv->rps.hw_lock);
+ intel_slpc_suspend(dev_priv);
+ mutex_unlock(&dev_priv->rps.hw_lock);
+ intel_runtime_pm_put(dev_priv);
+ }
}
void intel_sanitize_gt_powersave(struct drm_i915_private *dev_priv)
{
- dev_priv->rps.enabled = true; /* force disabling */
+ if (!i915.enable_slpc)
+ dev_priv->rps.enabled = true; /* force disabling */
dev_priv->rps.rc6_enabled = true;
+
intel_disable_gt_powersave(dev_priv);
- gen6_reset_rps_interrupts(dev_priv);
+ if (!i915.enable_slpc)
+ gen6_reset_rps_interrupts(dev_priv);
}
void intel_disable_gt_powersave(struct drm_i915_private *dev_priv)
{
- if (!READ_ONCE(dev_priv->rps.enabled)) {
+ if (!i915.enable_slpc && !READ_ONCE(dev_priv->rps.enabled)) {
if (WARN_ON_ONCE(IS_GEN9(dev_priv) &&
READ_ONCE(dev_priv->rps.rc6_enabled)))
DRM_ERROR("RC6 not disabled.\n");
return;
}
+ if (i915.enable_slpc && !READ_ONCE(dev_priv->rps.rc6_enabled))
+ return;
mutex_lock(&dev_priv->rps.hw_lock);
if (INTEL_GEN(dev_priv) >= 9) {
if (READ_ONCE(dev_priv->rps.rc6_enabled))
gen9_disable_rc6(dev_priv);
- if (READ_ONCE(dev_priv->rps.enabled))
- gen9_disable_rps(dev_priv);
+ if (i915.enable_slpc) {
+ if (READ_ONCE(dev_priv->guc.slpc.active))
+ intel_slpc_disable(dev_priv);
+ } else {
+ if (READ_ONCE(dev_priv->rps.enabled))
+ gen9_disable_rps(dev_priv);
+ }
} else if (IS_CHERRYVIEW(dev_priv)) {
cherryview_disable_rps(dev_priv);
} else if (IS_VALLEYVIEW(dev_priv)) {
@@ -6773,12 +6802,14 @@ void intel_enable_gt_powersave(struct drm_i915_private *dev_priv)
/* We shouldn't be disabling as we submit, so this should be less
* racy than it appears!
*/
- if (READ_ONCE(dev_priv->rps.enabled)) {
+ if (!i915.enable_slpc && READ_ONCE(dev_priv->rps.enabled)) {
if (WARN_ON_ONCE(IS_GEN9(dev_priv) &&
!READ_ONCE(dev_priv->rps.rc6_enabled)))
DRM_ERROR("RC6 and ring frequencies not enabled.\n");
return;
}
+ if (i915.enable_slpc && READ_ONCE(dev_priv->rps.rc6_enabled))
+ return;
/* Powersaving is controlled by the host when inside a VM */
if (intel_vgpu_active(dev_priv))
@@ -6796,7 +6827,7 @@ void intel_enable_gt_powersave(struct drm_i915_private *dev_priv)
if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
gen6_update_ring_freq(dev_priv);
}
- if (!READ_ONCE(dev_priv->rps.enabled))
+ if (!i915.enable_slpc && !READ_ONCE(dev_priv->rps.enabled))
gen9_enable_rps(dev_priv);
} else if (IS_BROADWELL(dev_priv)) {
gen8_enable_rps(dev_priv);
@@ -6825,7 +6856,7 @@ static void __intel_autoenable_gt_powersave(struct work_struct *work)
struct intel_engine_cs *rcs;
struct drm_i915_gem_request *req;
- if (READ_ONCE(dev_priv->rps.enabled))
+ if (!i915.enable_slpc && READ_ONCE(dev_priv->rps.enabled))
goto out;
rcs = dev_priv->engine[RCS];
@@ -6855,7 +6886,7 @@ static void __intel_autoenable_gt_powersave(struct work_struct *work)
void intel_autoenable_gt_powersave(struct drm_i915_private *dev_priv)
{
- if (READ_ONCE(dev_priv->rps.enabled))
+ if (!i915.enable_slpc && READ_ONCE(dev_priv->rps.enabled))
return;
if (IS_IRONLAKE_M(dev_priv)) {
new file mode 100644
@@ -0,0 +1,46 @@
+/*
+ * Copyright © 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+#include <linux/firmware.h>
+#include "i915_drv.h"
+#include "intel_guc.h"
+
+void intel_slpc_init(struct drm_i915_private *dev_priv)
+{
+}
+
+void intel_slpc_cleanup(struct drm_i915_private *dev_priv)
+{
+}
+
+void intel_slpc_suspend(struct drm_i915_private *dev_priv)
+{
+}
+
+void intel_slpc_disable(struct drm_i915_private *dev_priv)
+{
+}
+
+void intel_slpc_enable(struct drm_i915_private *dev_priv)
+{
+}
new file mode 100644
@@ -0,0 +1,38 @@
+/*
+ * Copyright © 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+#ifndef _INTEL_SLPC_H_
+#define _INTEL_SLPC_H_
+
+struct intel_slpc {
+ bool active;
+};
+
+/* intel_slpc.c */
+void intel_slpc_init(struct drm_i915_private *dev_priv);
+void intel_slpc_cleanup(struct drm_i915_private *dev_priv);
+void intel_slpc_suspend(struct drm_i915_private *dev_priv);
+void intel_slpc_disable(struct drm_i915_private *dev_priv);
+void intel_slpc_enable(struct drm_i915_private *dev_priv);
+
+#endif