diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_uc.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_uc.c | 139 |
1 files changed, 125 insertions, 14 deletions
diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c index d82ca0f438f5..e5bf0d37bf43 100644 --- a/drivers/gpu/drm/i915/intel_uc.c +++ b/drivers/gpu/drm/i915/intel_uc.c @@ -27,6 +27,8 @@ #include "intel_guc.h" #include "i915_drv.h" +static void guc_free_load_err_log(struct intel_guc *guc); + /* Reset GuC providing us with fresh state for both GuC and HuC. */ static int __intel_uc_reset_hw(struct drm_i915_private *dev_priv) @@ -65,6 +67,21 @@ static int __get_platform_enable_guc(struct drm_i915_private *dev_priv) return enable_guc; } +static int __get_default_guc_log_level(struct drm_i915_private *dev_priv) +{ + int guc_log_level = 0; /* disabled */ + + /* Enable if we're running on platform with GuC and debug config */ + if (HAS_GUC(dev_priv) && intel_uc_is_using_guc() && + (IS_ENABLED(CONFIG_DRM_I915_DEBUG) || + IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM))) + guc_log_level = 1 + GUC_LOG_VERBOSITY_MAX; + + /* Any platform specific fine-tuning can be done here */ + + return guc_log_level; +} + /** * intel_uc_sanitize_options - sanitize uC related modparam options * @dev_priv: device private @@ -74,6 +91,13 @@ static int __get_platform_enable_guc(struct drm_i915_private *dev_priv) * modparam varies between platforms and it is hardcoded in driver code. * Any other modparam value is only monitored against availability of the * related hardware or firmware definitions. + * + * In case of "guc_log_level" option this function will attempt to modify + * it only if it was initially set to "auto(-1)" or if initial value was + * "enable(1..4)" on platforms without the GuC. Default value for this + * modparam varies between platforms and is usually set to "disable(0)" + * unless GuC is enabled on given platform and the driver is compiled with + * debug config when this modparam will default to "enable(1..4)". */ void intel_uc_sanitize_options(struct drm_i915_private *dev_priv) { @@ -91,22 +115,48 @@ void intel_uc_sanitize_options(struct drm_i915_private *dev_priv) /* Verify GuC firmware availability */ if (intel_uc_is_using_guc() && !intel_uc_fw_is_selected(guc_fw)) { - DRM_WARN("Incompatible option detected: enable_guc=%d, %s!\n", - i915_modparams.enable_guc, + DRM_WARN("Incompatible option detected: %s=%d, %s!\n", + "enable_guc", i915_modparams.enable_guc, !HAS_GUC(dev_priv) ? "no GuC hardware" : "no GuC firmware"); } /* Verify HuC firmware availability */ if (intel_uc_is_using_huc() && !intel_uc_fw_is_selected(huc_fw)) { - DRM_WARN("Incompatible option detected: enable_guc=%d, %s!\n", - i915_modparams.enable_guc, + DRM_WARN("Incompatible option detected: %s=%d, %s!\n", + "enable_guc", i915_modparams.enable_guc, !HAS_HUC(dev_priv) ? "no HuC hardware" : "no HuC firmware"); } + /* A negative value means "use platform/config default" */ + if (i915_modparams.guc_log_level < 0) + i915_modparams.guc_log_level = + __get_default_guc_log_level(dev_priv); + + if (i915_modparams.guc_log_level > 0 && !intel_uc_is_using_guc()) { + DRM_WARN("Incompatible option detected: %s=%d, %s!\n", + "guc_log_level", i915_modparams.guc_log_level, + !HAS_GUC(dev_priv) ? "no GuC hardware" : + "GuC not enabled"); + i915_modparams.guc_log_level = 0; + } + + if (i915_modparams.guc_log_level > 1 + GUC_LOG_VERBOSITY_MAX) { + DRM_WARN("Incompatible option detected: %s=%d, %s!\n", + "guc_log_level", i915_modparams.guc_log_level, + "verbosity too high"); + i915_modparams.guc_log_level = 1 + GUC_LOG_VERBOSITY_MAX; + } + + DRM_DEBUG_DRIVER("guc_log_level=%d (enabled:%s verbosity:%d)\n", + i915_modparams.guc_log_level, + yesno(i915_modparams.guc_log_level), + i915_modparams.guc_log_level - 1); + /* Make sure that sanitization was done */ GEM_BUG_ON(i915_modparams.enable_guc < 0); + GEM_BUG_ON(i915_modparams.guc_log_level < 0); } void intel_uc_init_early(struct drm_i915_private *dev_priv) @@ -135,6 +185,8 @@ void intel_uc_fini_fw(struct drm_i915_private *dev_priv) if (USES_HUC(dev_priv)) intel_uc_fw_fini(&dev_priv->huc.fw); + + guc_free_load_err_log(&dev_priv->guc); } /** @@ -152,7 +204,7 @@ void intel_uc_init_mmio(struct drm_i915_private *dev_priv) static void guc_capture_load_err_log(struct intel_guc *guc) { - if (!guc->log.vma || i915_modparams.guc_log_level < 0) + if (!guc->log.vma || !i915_modparams.guc_log_level) return; if (!guc->load_err_log) @@ -188,28 +240,44 @@ static void guc_disable_communication(struct intel_guc *guc) guc->send = intel_guc_send_nop; } -int intel_uc_init_wq(struct drm_i915_private *dev_priv) +int intel_uc_init_misc(struct drm_i915_private *dev_priv) { + struct intel_guc *guc = &dev_priv->guc; int ret; if (!USES_GUC(dev_priv)) return 0; - ret = intel_guc_init_wq(&dev_priv->guc); + ret = intel_guc_init_wq(guc); if (ret) { DRM_ERROR("Couldn't allocate workqueues for GuC\n"); - return ret; + goto err; + } + + ret = intel_guc_log_relay_create(guc); + if (ret) { + DRM_ERROR("Couldn't allocate relay for GuC log\n"); + goto err_relay; } return 0; + +err_relay: + intel_guc_fini_wq(guc); +err: + return ret; } -void intel_uc_fini_wq(struct drm_i915_private *dev_priv) +void intel_uc_fini_misc(struct drm_i915_private *dev_priv) { + struct intel_guc *guc = &dev_priv->guc; + if (!USES_GUC(dev_priv)) return; - intel_guc_fini_wq(&dev_priv->guc); + intel_guc_fini_wq(guc); + + intel_guc_log_relay_destroy(guc); } int intel_uc_init(struct drm_i915_private *dev_priv) @@ -293,7 +361,7 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv) goto err_out; if (USES_HUC(dev_priv)) { - ret = intel_huc_init_hw(huc); + ret = intel_huc_fw_upload(huc); if (ret) goto err_out; } @@ -322,7 +390,7 @@ int intel_uc_init_hw(struct drm_i915_private *dev_priv) } if (USES_GUC_SUBMISSION(dev_priv)) { - if (i915_modparams.guc_log_level >= 0) + if (i915_modparams.guc_log_level) gen9_enable_guc_interrupts(dev_priv); ret = intel_guc_submission_enable(guc); @@ -364,8 +432,6 @@ void intel_uc_fini_hw(struct drm_i915_private *dev_priv) { struct intel_guc *guc = &dev_priv->guc; - guc_free_load_err_log(guc); - if (!USES_GUC(dev_priv)) return; @@ -379,3 +445,48 @@ void intel_uc_fini_hw(struct drm_i915_private *dev_priv) if (USES_GUC_SUBMISSION(dev_priv)) gen9_disable_guc_interrupts(dev_priv); } + +int intel_uc_suspend(struct drm_i915_private *i915) +{ + struct intel_guc *guc = &i915->guc; + int err; + + if (!USES_GUC(i915)) + return 0; + + if (guc->fw.load_status != INTEL_UC_FIRMWARE_SUCCESS) + return 0; + + err = intel_guc_suspend(guc); + if (err) { + DRM_DEBUG_DRIVER("Failed to suspend GuC, err=%d", err); + return err; + } + + gen9_disable_guc_interrupts(i915); + + return 0; +} + +int intel_uc_resume(struct drm_i915_private *i915) +{ + struct intel_guc *guc = &i915->guc; + int err; + + if (!USES_GUC(i915)) + return 0; + + if (guc->fw.load_status != INTEL_UC_FIRMWARE_SUCCESS) + return 0; + + if (i915_modparams.guc_log_level) + gen9_enable_guc_interrupts(i915); + + err = intel_guc_resume(guc); + if (err) { + DRM_DEBUG_DRIVER("Failed to resume GuC, err=%d", err); + return err; + } + + return 0; +} |