Re: [PATCH 3/8] drm/i915/skl: Add DC5 Trigger Sequence.

Imre Deak
2015-04-02T19:33:05Z

On Wed, 2015-04-01 at 16:22 +0530, Animesh Manna wrote:
> From: Suketu Shah <suketu.j.shah@intel.com>
>
> Add triggers as per expectations mentioned in gen9_enable_dc5
> and gen9_disable_dc5 patch.
>
> Also call POSTING_READ for every write to a register to ensure that
> its written immediately.
>
> v1: Remove POSTING_READ calls as they've already been added in previous patches.
>
> v2: Rebase to move all runtime pm specific changes to intel_runtime_pm.c file.
>
> Modified as per review comments from Imre:
> 1] Change variable name 'dc5_allowed' to 'dc5_enabled' to correspond to relevant
> functions.
> 2] Move the check dc5_enabled in skl_set_power_well() to disable DC5 into
> gen9_disable_DC5 which is a more appropriate place.
> 3] Convert checks for 'pm.dc5_enabled' and 'pm.suspended' in skl_set_power_well()
> to warnings. However, removing them for now as they'll be included in a future patch
> asserting DC-state entry/exit criteria.
> 4] Enable DC5, only when CSR firmware is verified to be loaded. Create new structure
> to track 'enabled' and 'deferred' status of DC5.
> 5] Ensure runtime PM reference is obtained, if CSR is not loaded, to avoid entering
> runtime-suspend and release it when it's loaded.
> 6] Protect necessary CSR-related code with locks.
> 7] Move CSR-loading call to runtime PM initialization, as power domains needed to be
> accessed during deferred DC5-enabling, are not initialized earlier.
>
> v3: Rebase to latest.
>
> Modified as per review comments from Imre:
> 1] Use blocking wait for CSR-loading to finish to enable DC5 for simplicity, instead of
> deferring enabling DC5 until CSR is loaded.
> 2] Obtain runtime PM reference during CSR-loading initialization itself as deferred DC5-
> enabling is removed and release it at the end of CSR-loading functionality.
> 3] Revert calling CSR-loading functionality to the beginning of i915 driver-load
> functionality to avoid any delay in loading.
> 4] Define another variable to track whether CSR-loading failed and use it to avoid enabling
> DC5 if it's true.
> 5] Define CSR-load-status accessor functions for use later.
>
> v4:
> 1] Disable DC5 before enabling PG2 instead of after it.
> 2] DC5 was being mistaken enabled even when CSR-loading timed-out. Fix that.
> 3] Enable DC5-related functionality using a macro.
> 4] Remove dc5_enabled tracking variable and its use as it's not needed now.
>
> v5:
> 1] Mark CSR failed to load where necessary in finish_csr_load function.
> 2] Use mutex-protected accessor function to check if CSR loaded instead of directly
> accessing the variable.
> 3] Prefix csr_load_status_get/set function names with intel_.
>
> v6: rebase to latest.
> v7: Rebase on top of nightly (Damien)
> v8: Squashed the patch from Imre - added csr helper pointers to simplify the code. (Imre)
> v9: After adding dmc ver 1.0 support rebased on top of nightly. (Animesh)
>
> Issue: VIZ-2819
> Signed-off-by: A.Sunil Kamath <sunil.kamath@intel.com>
> Signed-off-by: Suketu Shah <suketu.j.shah@intel.com>
> Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>
> Signed-off-by: Imre Deak <imre.deak@intel.com>
> Signed-off-by: Animesh Manna <animesh.manna@intel.com>
> ---
> drivers/gpu/drm/i915/i915_drv.h | 2 ++
> drivers/gpu/drm/i915/intel_csr.c | 50 ++++++++++++++++++++++++++++++++-
> drivers/gpu/drm/i915/intel_drv.h | 2 ++
> drivers/gpu/drm/i915/intel_runtime_pm.c | 31 ++++++++++++++++++++
> 4 files changed, 84 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index dd572a0..3320fb4 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -669,6 +669,8 @@ struct intel_uncore {
> struct intel_csr {
> int csr_size;
> u8 *csr_buf;
> + bool loaded;
> + bool failed;

Nitpick: just using an enum with loading, loaded, failed states would be
clearer.

> const char *fw_path;
> };
>
> diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c
> index f44f1cd..87d393a 100644
> --- a/drivers/gpu/drm/i915/intel_csr.c
> +++ b/drivers/gpu/drm/i915/intel_csr.c
> @@ -60,6 +60,25 @@ char intel_get_substepping(struct drm_device *dev)
> else
> return -ENODATA;
> }
> +
> +bool intel_csr_load_status_get(struct drm_i915_private *dev_priv)
> +{
> + bool val = false;
> +
> + mutex_lock(&dev_priv->csr_lock);
> + val = dev_priv->csr.loaded;
> + mutex_unlock(&dev_priv->csr_lock);
> +
> + return val;
> +}
> +
> +void intel_csr_load_status_set(struct drm_i915_private *dev_priv, bool val)
> +{
> + mutex_lock(&dev_priv->csr_lock);
> + dev_priv->csr.loaded = val;
> + mutex_unlock(&dev_priv->csr_lock);
> +}
> +
> void intel_csr_load_program(struct drm_device *dev)
> {
> struct drm_i915_private *dev_priv = dev->dev_private;
> @@ -91,6 +110,8 @@ void intel_csr_load_program(struct drm_device *dev)
> I915_WRITE(dev_priv->dmc_info.mmioaddr[i],
> dev_priv->dmc_info.mmiodata[i]);
> }
> +
> + dev_priv->csr.loaded = true;
> mutex_unlock(&dev_priv->csr_lock);
> }
>
> @@ -110,11 +131,13 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>
> if (!fw) {
> i915_firmware_load_error_print(csr->fw_path, 0);
> + csr->failed = true;
> goto out;
> }
>
> if ((stepping == -ENODATA) || (substepping == -ENODATA)) {
> DRM_ERROR("Unknown stepping info, firmware loading failed\n");
> + csr->failed = true;
> goto out;
> }
>
> @@ -131,6 +154,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> (css_header->header_len * 4)) {
> DRM_ERROR("Firmware has wrong CSS header length %u bytes\n",
> (css_header->header_len * 4));
> + csr->failed = true;
> goto out;
> }
> readcount += sizeof(struct intel_css_header);
> @@ -142,6 +166,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> (package_header->header_len * 4)) {
> DRM_ERROR("Firmware has wrong package header length %u bytes\n",
> (package_header->header_len * 4));
> + csr->failed = true;
> goto out;
> }
> readcount += sizeof(struct intel_package_header);
> @@ -162,6 +187,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> }
> if (dmc_offset == CSR_DEFAULT_FW_OFFSET) {
> DRM_ERROR("Firmware not supported for %c stepping\n", stepping);
> + csr->failed = true;
> goto out;
> }
> readcount += dmc_offset;
> @@ -171,6 +197,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> if (sizeof(struct intel_dmc_header) != (dmc_header->header_len)) {
> DRM_ERROR("Firmware has wrong dmc header length %u bytes\n",
> (dmc_header->header_len));
> + csr->failed = true;
> goto out;
> }
> readcount += sizeof(struct intel_dmc_header);
> @@ -179,6 +206,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> if (dmc_header->mmio_count > CSR_MAX_MMIO_COUNT) {
> DRM_ERROR("Firmware has wrong mmio count %u\n",
> dmc_header->mmio_count);
> + csr->failed = true;
> goto out;
> }
> dev_priv->dmc_info.mmio_count = dmc_header->mmio_count;
> @@ -187,6 +215,7 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> dmc_header->mmioaddr[i] <= CSR_MMIO_END_RANGE) {
> DRM_ERROR(" Firmware has wrong mmio address 0x%x\n",
> dmc_header->mmioaddr[i]);
> + csr->failed = true;
> goto out;
> }
> dev_priv->dmc_info.mmioaddr[i] = dmc_header->mmioaddr[i];
> @@ -197,11 +226,13 @@ static void finish_csr_load(const struct firmware *fw, void *context)
> nbytes = dmc_header->fw_size * 4;
> if (nbytes > CSR_MAX_FW_SIZE) {
> DRM_ERROR("CSR firmware too big (%u) bytes\n", nbytes);
> + csr->failed = true;
> goto out;
> }
> dev_priv->dmc_info.dmc_payload = kmalloc(nbytes, GFP_KERNEL);
> if (!dev_priv->dmc_info.dmc_payload) {
> DRM_ERROR("Memory allocation failed for dmc payload\n");
> + csr->failed = true;
> goto out;
> }

Nitpick: the above could be simplified by setting the state to 'failed'
once on the top and to 'loaded' in intel_csr_load_program.

>
> @@ -218,7 +249,14 @@ static void finish_csr_load(const struct firmware *fw, void *context)
>
> /* load csr program during system boot, as needed for DC states */
> intel_csr_load_program(dev);
> +
> out:
> + /*
> + * Release the runtime pm reference obtained when
> + * CSR wasn't loaded.
> + */
> + intel_runtime_pm_put(dev_priv);
> +
> kfree(csr->csr_buf);
> csr->csr_buf = NULL;
> }
> @@ -236,16 +274,25 @@ int intel_csr_ucode_init(struct drm_device *dev)
> csr->fw_path = I915_CSR_SKL;
> else {
> DRM_ERROR("Unexpected: no known CSR firmware for platform\n");
> + csr->failed = true;
> return 0;
> }
>
> + /*
> + * Obtain a runtime pm reference, until CSR is loaded,
> + * to avoid entering runtime-suspend.
> + */
> + intel_runtime_pm_get(dev_priv);
> +
> /* CSR supported for platform, load firmware */
> ret = request_firmware_nowait(THIS_MODULE, true, csr->fw_path,
> &dev_priv->dev->pdev->dev,
> GFP_KERNEL, dev_priv,
> finish_csr_load);
> - if (ret)
> + if (ret) {
> i915_firmware_load_error_print(csr->fw_path, ret);
> + csr->failed = true;
> + }
>
> return ret;
> }
> @@ -257,6 +304,7 @@ void intel_csr_ucode_fini(struct drm_device *dev)
> if (!HAS_CSR(dev))
> return;
>
> + intel_csr_load_status_set(dev_priv, false);
> kfree(dev_priv->dmc_info.dmc_payload);
> memset(&dev_priv->dmc_info, 0, sizeof(struct intel_dmc_info));
> }
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index cd20b6a..39cb2dc 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1061,6 +1061,8 @@ unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane,
>
> /* intel_csr.c */
> int intel_csr_ucode_init(struct drm_device *dev);
> +bool intel_csr_load_status_get(struct drm_i915_private *dev_priv);
> +void intel_csr_load_status_set(struct drm_i915_private *dev_priv, bool val);
> void intel_csr_load_program(struct drm_device *dev);
> void intel_csr_ucode_fini(struct drm_device *dev);
>
> diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
> index bc6cee9..8b917e2 100644
> --- a/drivers/gpu/drm/i915/intel_runtime_pm.c
> +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
> @@ -49,6 +49,8 @@
> * present for a given platform.
> */
>
> +#define GEN9_ENABLE_DC5(dev) (IS_SKYLAKE(dev))
> +
> #define for_each_power_well(i, power_well, domain_mask, power_domains) \
> for (i = 0; \
> i < (power_domains)->power_well_count && \
> @@ -369,6 +371,7 @@ static void gen9_disable_dc5(struct drm_i915_private *dev_priv)
> static void skl_set_power_well(struct drm_i915_private *dev_priv,
> struct i915_power_well *power_well, bool enable)
> {
> + struct drm_device *dev = dev_priv->dev;
> uint32_t tmp, fuse_status;
> uint32_t req_mask, state_mask;
> bool is_enabled, enable_requested, check_fuse_status = false;
> @@ -408,6 +411,13 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv,
>
> if (enable) {
> if (!enable_requested) {
> + WARN((tmp & state_mask) &&
> + !I915_READ(HSW_PWR_WELL_BIOS), "Invalid for \
> + power well status to be enabled, unless done \
> + by the BIOS, when request is to disable!\n");

This would look ugly in dmesg. You don't need to break the string, the
80 character limit doesn't apply here. I would also just leave out the
message part, the condition itself is self descriptive.

> + if (GEN9_ENABLE_DC5(dev) &&
> + power_well->data == SKL_DISP_PW_2)
> + gen9_disable_dc5(dev_priv);
> I915_WRITE(HSW_PWR_WELL_DRIVER, tmp | req_mask);
> }
>
> @@ -424,6 +434,27 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv,
> I915_WRITE(HSW_PWR_WELL_DRIVER, tmp & ~req_mask);
> POSTING_READ(HSW_PWR_WELL_DRIVER);
> DRM_DEBUG_KMS("Disabling %s\n", power_well->name);
> +
> + if (GEN9_ENABLE_DC5(dev) &&
> + power_well->data == SKL_DISP_PW_2) {
> + if (!dev_priv->csr.failed) {
> + /*
> + * TODO: wait for a completion event or
> + * similar here instead of busy
> + * waiting using wait_for function.
> + */
> + if (wait_for(
> + intel_csr_load_status_get(
> + dev_priv), 1000))
> + DRM_ERROR("Timed out waiting \
> + for CSR to be loaded!");
> + else
> + gen9_enable_dc5(dev_priv);
> + } else {
> + DRM_ERROR("Cannot enable DC5 as CSR \
> + failed to load!");

Again, the above error messages shouldn't be broken into multiple lines.

With the above fixed (not considering the nitpicks), this is:
Reviewed-by: Imre Deak <imre.deak@intel.com>

> + }
> + }
> }
> }