Message ID | 1429174334-12089-3-git-send-email-animesh.manna@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On to, 2015-04-16 at 14: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) > v10: Added a enum for different csr states, suggested by Imre. (Animesh) > > v11: Based on review comments from Imre, Damien and Daniel following changes done > - enum name chnaged to csr_state (singular form). > - FW_UNINITIALIZED used as zeroth element in enum csr_state. > - Prototype changed for helper function(set/get csr status), using enum csr_state instead of bool. > > 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 | 7 +++++ > drivers/gpu/drm/i915/intel_csr.c | 49 +++++++++++++++++++++++++++++++-- > drivers/gpu/drm/i915/intel_drv.h | 3 ++ > drivers/gpu/drm/i915/intel_runtime_pm.c | 33 ++++++++++++++++++++++ > 4 files changed, 90 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h > index 90e47a9..670e407 100644 > --- a/drivers/gpu/drm/i915/i915_drv.h > +++ b/drivers/gpu/drm/i915/i915_drv.h > @@ -667,6 +667,12 @@ struct intel_uncore { > #define for_each_fw_domain(domain__, dev_priv__, i__) \ > for_each_fw_domain_mask(domain__, FORCEWAKE_ALL, dev_priv__, i__) > > +enum csr_state { > + FW_UNINITIALIZED = 0, > + FW_LOADED, > + FW_FAILED > +}; > + > struct intel_csr { > const char *fw_path; > __be32 *dmc_payload; > @@ -674,6 +680,7 @@ struct intel_csr { > uint32_t mmio_count; > uint32_t mmioaddr[8]; > uint32_t mmiodata[8]; > + enum csr_state state; > }; > > #define DEV_INFO_FOR_EACH_FLAG(func, sep) \ > diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c > index f5fa574..fe6789f 100644 > --- a/drivers/gpu/drm/i915/intel_csr.c > +++ b/drivers/gpu/drm/i915/intel_csr.c > @@ -183,6 +183,25 @@ static char intel_get_substepping(struct drm_device *dev) > return -ENODATA; > } > > +enum csr_state intel_csr_load_status_get(struct drm_i915_private *dev_priv) > +{ > + enum csr_state state; > + > + mutex_lock(&dev_priv->csr_lock); > + state = dev_priv->csr.state; > + mutex_unlock(&dev_priv->csr_lock); > + > + return state; > +} > + > +void intel_csr_load_status_set(struct drm_i915_private *dev_priv, > + enum csr_state state) > +{ > + mutex_lock(&dev_priv->csr_lock); > + dev_priv->csr.state = state; > + mutex_unlock(&dev_priv->csr_lock); > +} > + > void intel_csr_load_program(struct drm_device *dev) > { > struct drm_i915_private *dev_priv = dev->dev_private; > @@ -204,6 +223,8 @@ void intel_csr_load_program(struct drm_device *dev) > I915_WRITE(dev_priv->csr.mmioaddr[i], > dev_priv->csr.mmiodata[i]); > } > + > + dev_priv->csr.state = FW_LOADED; > mutex_unlock(&dev_priv->csr_lock); > } > > @@ -223,11 +244,13 @@ static void finish_csr_load(const struct firmware *fw, void *context) > > if (!fw) { > i915_firmware_load_error_print(csr->fw_path, 0); > + intel_csr_load_status_set(dev_priv, FW_FAILED); > goto out; > } > > if ((stepping == -ENODATA) || (substepping == -ENODATA)) { > DRM_ERROR("Unknown stepping info, firmware loading failed\n"); > + intel_csr_load_status_set(dev_priv, FW_FAILED); > goto out; > } > > @@ -237,6 +260,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)); > + intel_csr_load_status_set(dev_priv, FW_FAILED); > goto out; > } > readcount += sizeof(struct intel_css_header); > @@ -248,6 +272,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)); > + intel_csr_load_status_set(dev_priv, FW_FAILED); > goto out; > } > readcount += sizeof(struct intel_package_header); > @@ -268,6 +293,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); > + intel_csr_load_status_set(dev_priv, FW_FAILED); > goto out; > } > readcount += dmc_offset; > @@ -277,6 +303,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)); > + intel_csr_load_status_set(dev_priv, FW_FAILED); > goto out; > } > readcount += sizeof(struct intel_dmc_header); > @@ -285,6 +312,7 @@ static void finish_csr_load(const struct firmware *fw, void *context) > if (dmc_header->mmio_count > ARRAY_SIZE(csr->mmioaddr)) { > DRM_ERROR("Firmware has wrong mmio count %u\n", > dmc_header->mmio_count); > + intel_csr_load_status_set(dev_priv, FW_FAILED); > goto out; > } > csr->mmio_count = dmc_header->mmio_count; > @@ -293,6 +321,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]); > + intel_csr_load_status_set(dev_priv, FW_FAILED); > goto out; > } > csr->mmioaddr[i] = dmc_header->mmioaddr[i]; > @@ -303,6 +332,7 @@ 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); > + intel_csr_load_status_set(dev_priv, FW_FAILED); > goto out; > } > csr->dmc_fw_size = dmc_header->fw_size; > @@ -310,6 +340,7 @@ static void finish_csr_load(const struct firmware *fw, void *context) > csr->dmc_payload = kmalloc(nbytes, GFP_KERNEL); > if (!csr->dmc_payload) { > DRM_ERROR("Memory allocation failed for dmc payload\n"); > + intel_csr_load_status_set(dev_priv, FW_FAILED); > goto out; > } > > @@ -327,6 +358,11 @@ 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); I'm not sure if runtime PM would work correctly without DC5/6, so let's not enable RPM if the firmware fails to load. This is also inconsistent with the error handling in intel_csr_ucode_init(). > release_firmware(fw); > } > > @@ -343,17 +379,25 @@ void 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"); > + intel_csr_load_status_set(dev_priv, FW_FAILED); > return; > } > > + /* > + * 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); > - > + intel_csr_load_status_set(dev_priv, FW_FAILED); > + } > } > > void intel_csr_ucode_fini(struct drm_device *dev) > @@ -363,5 +407,6 @@ void intel_csr_ucode_fini(struct drm_device *dev) > if (!HAS_CSR(dev)) > return; > > + intel_csr_load_status_set(dev_priv, FW_FAILED); > kfree(dev_priv->csr.dmc_payload); > } > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h > index f3a2d88..25d7956 100644 > --- a/drivers/gpu/drm/i915/intel_drv.h > +++ b/drivers/gpu/drm/i915/intel_drv.h > @@ -1064,6 +1064,9 @@ unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane, > > /* intel_csr.c */ > void intel_csr_ucode_init(struct drm_device *dev); > +enum csr_state intel_csr_load_status_get(struct drm_i915_private *dev_priv); > +void intel_csr_load_status_set(struct drm_i915_private *dev_priv, > + enum csr_state state); > 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 ce00e69..23f02a8 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 && \ > @@ -319,9 +321,20 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv, > SKL_DISPLAY_MISC_IO_POWER_DOMAINS)) | \ > BIT(POWER_DOMAIN_INIT)) > > +static void gen9_enable_dc5(struct drm_i915_private *dev_priv) > +{ > + /* TODO: Implementation to be done. */ > +} > + > +static void gen9_disable_dc5(struct drm_i915_private *dev_priv) > +{ > + /* TODO: Implementation to be done. */ > +} > + > 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; > @@ -361,6 +374,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"); > + 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); > } > > @@ -377,6 +397,19 @@ 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) { > + enum csr_state state; > + > + wait_for((state = intel_csr_load_status_get(dev_priv)) != > + FW_UNINITIALIZED, 1000); > + if (state != FW_LOADED) > + DRM_ERROR("CSR firmware not ready (%d)\n", > + state); > + else > + gen9_enable_dc5(dev_priv); > + } > } > } >
On to, 2015-04-16 at 12:25 +0300, Imre Deak wrote: > On to, 2015-04-16 at 14:22 +0530, Animesh Manna wrote: > > [...] > > @@ -223,11 +244,13 @@ static void finish_csr_load(const struct firmware *fw, void *context) > > > > if (!fw) { > > i915_firmware_load_error_print(csr->fw_path, 0); > > + intel_csr_load_status_set(dev_priv, FW_FAILED); > > goto out; > > } > > > > if ((stepping == -ENODATA) || (substepping == -ENODATA)) { > > DRM_ERROR("Unknown stepping info, firmware loading failed\n"); > > + intel_csr_load_status_set(dev_priv, FW_FAILED); > > goto out; > > } > > > > @@ -237,6 +260,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)); > > + intel_csr_load_status_set(dev_priv, FW_FAILED); > > goto out; > > } > > readcount += sizeof(struct intel_css_header); > > @@ -248,6 +272,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)); > > + intel_csr_load_status_set(dev_priv, FW_FAILED); > > goto out; > > } > > readcount += sizeof(struct intel_package_header); > > @@ -268,6 +293,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); > > + intel_csr_load_status_set(dev_priv, FW_FAILED); > > goto out; > > } > > readcount += dmc_offset; > > @@ -277,6 +303,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)); > > + intel_csr_load_status_set(dev_priv, FW_FAILED); > > goto out; > > } > > readcount += sizeof(struct intel_dmc_header); > > @@ -285,6 +312,7 @@ static void finish_csr_load(const struct firmware *fw, void *context) > > if (dmc_header->mmio_count > ARRAY_SIZE(csr->mmioaddr)) { > > DRM_ERROR("Firmware has wrong mmio count %u\n", > > dmc_header->mmio_count); > > + intel_csr_load_status_set(dev_priv, FW_FAILED); > > goto out; > > } > > csr->mmio_count = dmc_header->mmio_count; > > @@ -293,6 +321,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]); > > + intel_csr_load_status_set(dev_priv, FW_FAILED); > > goto out; > > } > > csr->mmioaddr[i] = dmc_header->mmioaddr[i]; > > @@ -303,6 +332,7 @@ 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); > > + intel_csr_load_status_set(dev_priv, FW_FAILED); > > goto out; > > } > > csr->dmc_fw_size = dmc_header->fw_size; > > @@ -310,6 +340,7 @@ static void finish_csr_load(const struct firmware *fw, void *context) > > csr->dmc_payload = kmalloc(nbytes, GFP_KERNEL); > > if (!csr->dmc_payload) { > > DRM_ERROR("Memory allocation failed for dmc payload\n"); > > + intel_csr_load_status_set(dev_priv, FW_FAILED); > > goto out; > > } > > > > @@ -327,6 +358,11 @@ 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: Also, since you have to anyway change the patch: could you replace all the above intel_csr_load_status_set(dev_priv, FW_FAILED); with one here using a fw_loaded bool that you set after intel_csr_load_program? > > + /* > > + * Release the runtime pm reference obtained when > > + * CSR wasn't loaded. > > + */ > > + intel_runtime_pm_put(dev_priv);
On 4/16/2015 3:18 PM, Imre Deak wrote: > On to, 2015-04-16 at 12:25 +0300, Imre Deak wrote: >> On to, 2015-04-16 at 14:22 +0530, Animesh Manna wrote: >>> [...] >>> @@ -223,11 +244,13 @@ static void finish_csr_load(const struct firmware *fw, void *context) >>> >>> if (!fw) { >>> i915_firmware_load_error_print(csr->fw_path, 0); >>> + intel_csr_load_status_set(dev_priv, FW_FAILED); >>> goto out; >>> } >>> >>> if ((stepping == -ENODATA) || (substepping == -ENODATA)) { >>> DRM_ERROR("Unknown stepping info, firmware loading failed\n"); >>> + intel_csr_load_status_set(dev_priv, FW_FAILED); >>> goto out; >>> } >>> >>> @@ -237,6 +260,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)); >>> + intel_csr_load_status_set(dev_priv, FW_FAILED); >>> goto out; >>> } >>> readcount += sizeof(struct intel_css_header); >>> @@ -248,6 +272,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)); >>> + intel_csr_load_status_set(dev_priv, FW_FAILED); >>> goto out; >>> } >>> readcount += sizeof(struct intel_package_header); >>> @@ -268,6 +293,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); >>> + intel_csr_load_status_set(dev_priv, FW_FAILED); >>> goto out; >>> } >>> readcount += dmc_offset; >>> @@ -277,6 +303,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)); >>> + intel_csr_load_status_set(dev_priv, FW_FAILED); >>> goto out; >>> } >>> readcount += sizeof(struct intel_dmc_header); >>> @@ -285,6 +312,7 @@ static void finish_csr_load(const struct firmware *fw, void *context) >>> if (dmc_header->mmio_count > ARRAY_SIZE(csr->mmioaddr)) { >>> DRM_ERROR("Firmware has wrong mmio count %u\n", >>> dmc_header->mmio_count); >>> + intel_csr_load_status_set(dev_priv, FW_FAILED); >>> goto out; >>> } >>> csr->mmio_count = dmc_header->mmio_count; >>> @@ -293,6 +321,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]); >>> + intel_csr_load_status_set(dev_priv, FW_FAILED); >>> goto out; >>> } >>> csr->mmioaddr[i] = dmc_header->mmioaddr[i]; >>> @@ -303,6 +332,7 @@ 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); >>> + intel_csr_load_status_set(dev_priv, FW_FAILED); >>> goto out; >>> } >>> csr->dmc_fw_size = dmc_header->fw_size; >>> @@ -310,6 +340,7 @@ static void finish_csr_load(const struct firmware *fw, void *context) >>> csr->dmc_payload = kmalloc(nbytes, GFP_KERNEL); >>> if (!csr->dmc_payload) { >>> DRM_ERROR("Memory allocation failed for dmc payload\n"); >>> + intel_csr_load_status_set(dev_priv, FW_FAILED); >>> goto out; >>> } >>> >>> @@ -327,6 +358,11 @@ 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: > Also, since you have to anyway change the patch: could you replace all > the above intel_csr_load_status_set(dev_priv, FW_FAILED); with one here > using a fw_loaded bool that you set after intel_csr_load_program? Now we do not have fw_loaded bool in current patch, enum csr_state is used to capture the current state. Want me to add fw_loaded bool and call intel_csr_load_status_set(dev_priv, FW_FAILED) based on that? Regards, Animesh > >>> + /* >>> + * Release the runtime pm reference obtained when >>> + * CSR wasn't loaded. >>> + */ >>> + intel_runtime_pm_put(dev_priv); >
On Fri, 2015-04-17 at 11:29 +0530, Animesh Manna wrote: > > On 4/16/2015 3:18 PM, Imre Deak wrote: > > On to, 2015-04-16 at 12:25 +0300, Imre Deak wrote: > >> On to, 2015-04-16 at 14:22 +0530, Animesh Manna wrote: > >>> [...] > >>> @@ -223,11 +244,13 @@ static void finish_csr_load(const struct firmware *fw, void *context) > >>> To clarify, I meant to add at the top of this function: bool fw_loaded = false; > >>> if (!fw) { > >>> i915_firmware_load_error_print(csr->fw_path, 0); > >>> + intel_csr_load_status_set(dev_priv, FW_FAILED); ... remove all the intel_csr_load_status_set(FW_FAILED) calls added in this function > >>> goto out; > >>> } > >>> > >>> if ((stepping == -ENODATA) || (substepping == -ENODATA)) { > >>> DRM_ERROR("Unknown stepping info, firmware loading failed\n"); > >>> + intel_csr_load_status_set(dev_priv, FW_FAILED); > >>> goto out; > >>> } > >>> > >>> @@ -237,6 +260,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)); > >>> + intel_csr_load_status_set(dev_priv, FW_FAILED); > >>> goto out; > >>> } > >>> readcount += sizeof(struct intel_css_header); > >>> @@ -248,6 +272,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)); > >>> + intel_csr_load_status_set(dev_priv, FW_FAILED); > >>> goto out; > >>> } > >>> readcount += sizeof(struct intel_package_header); > >>> @@ -268,6 +293,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); > >>> + intel_csr_load_status_set(dev_priv, FW_FAILED); > >>> goto out; > >>> } > >>> readcount += dmc_offset; > >>> @@ -277,6 +303,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)); > >>> + intel_csr_load_status_set(dev_priv, FW_FAILED); > >>> goto out; > >>> } > >>> readcount += sizeof(struct intel_dmc_header); > >>> @@ -285,6 +312,7 @@ static void finish_csr_load(const struct firmware *fw, void *context) > >>> if (dmc_header->mmio_count > ARRAY_SIZE(csr->mmioaddr)) { > >>> DRM_ERROR("Firmware has wrong mmio count %u\n", > >>> dmc_header->mmio_count); > >>> + intel_csr_load_status_set(dev_priv, FW_FAILED); > >>> goto out; > >>> } > >>> csr->mmio_count = dmc_header->mmio_count; > >>> @@ -293,6 +321,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]); > >>> + intel_csr_load_status_set(dev_priv, FW_FAILED); > >>> goto out; > >>> } > >>> csr->mmioaddr[i] = dmc_header->mmioaddr[i]; > >>> @@ -303,6 +332,7 @@ 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); > >>> + intel_csr_load_status_set(dev_priv, FW_FAILED); > >>> goto out; > >>> } > >>> csr->dmc_fw_size = dmc_header->fw_size; > >>> @@ -310,6 +340,7 @@ static void finish_csr_load(const struct firmware *fw, void *context) > >>> csr->dmc_payload = kmalloc(nbytes, GFP_KERNEL); > >>> if (!csr->dmc_payload) { > >>> DRM_ERROR("Memory allocation failed for dmc payload\n"); > >>> + intel_csr_load_status_set(dev_priv, FW_FAILED); > >>> goto out; > >>> } > >>> > >>> @@ -327,6 +358,11 @@ 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); ... set fw_loaded = true; here > >>> out: > > Also, since you have to anyway change the patch: could you replace all > > the above intel_csr_load_status_set(dev_priv, FW_FAILED); with one here > > using a fw_loaded bool that you set after intel_csr_load_program? > > Now we do not have fw_loaded bool in current patch, enum csr_state is > used to capture the current state. Want me to add fw_loaded bool and > call intel_csr_load_status_set(dev_priv, FW_FAILED) based on that? ... and add here if (!fw_loaded) intel_csr_load_status_set(dev_priv, FW_FAILED); to remove some duplication in the code. --Imre
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 90e47a9..670e407 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -667,6 +667,12 @@ struct intel_uncore { #define for_each_fw_domain(domain__, dev_priv__, i__) \ for_each_fw_domain_mask(domain__, FORCEWAKE_ALL, dev_priv__, i__) +enum csr_state { + FW_UNINITIALIZED = 0, + FW_LOADED, + FW_FAILED +}; + struct intel_csr { const char *fw_path; __be32 *dmc_payload; @@ -674,6 +680,7 @@ struct intel_csr { uint32_t mmio_count; uint32_t mmioaddr[8]; uint32_t mmiodata[8]; + enum csr_state state; }; #define DEV_INFO_FOR_EACH_FLAG(func, sep) \ diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c index f5fa574..fe6789f 100644 --- a/drivers/gpu/drm/i915/intel_csr.c +++ b/drivers/gpu/drm/i915/intel_csr.c @@ -183,6 +183,25 @@ static char intel_get_substepping(struct drm_device *dev) return -ENODATA; } +enum csr_state intel_csr_load_status_get(struct drm_i915_private *dev_priv) +{ + enum csr_state state; + + mutex_lock(&dev_priv->csr_lock); + state = dev_priv->csr.state; + mutex_unlock(&dev_priv->csr_lock); + + return state; +} + +void intel_csr_load_status_set(struct drm_i915_private *dev_priv, + enum csr_state state) +{ + mutex_lock(&dev_priv->csr_lock); + dev_priv->csr.state = state; + mutex_unlock(&dev_priv->csr_lock); +} + void intel_csr_load_program(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -204,6 +223,8 @@ void intel_csr_load_program(struct drm_device *dev) I915_WRITE(dev_priv->csr.mmioaddr[i], dev_priv->csr.mmiodata[i]); } + + dev_priv->csr.state = FW_LOADED; mutex_unlock(&dev_priv->csr_lock); } @@ -223,11 +244,13 @@ static void finish_csr_load(const struct firmware *fw, void *context) if (!fw) { i915_firmware_load_error_print(csr->fw_path, 0); + intel_csr_load_status_set(dev_priv, FW_FAILED); goto out; } if ((stepping == -ENODATA) || (substepping == -ENODATA)) { DRM_ERROR("Unknown stepping info, firmware loading failed\n"); + intel_csr_load_status_set(dev_priv, FW_FAILED); goto out; } @@ -237,6 +260,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)); + intel_csr_load_status_set(dev_priv, FW_FAILED); goto out; } readcount += sizeof(struct intel_css_header); @@ -248,6 +272,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)); + intel_csr_load_status_set(dev_priv, FW_FAILED); goto out; } readcount += sizeof(struct intel_package_header); @@ -268,6 +293,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); + intel_csr_load_status_set(dev_priv, FW_FAILED); goto out; } readcount += dmc_offset; @@ -277,6 +303,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)); + intel_csr_load_status_set(dev_priv, FW_FAILED); goto out; } readcount += sizeof(struct intel_dmc_header); @@ -285,6 +312,7 @@ static void finish_csr_load(const struct firmware *fw, void *context) if (dmc_header->mmio_count > ARRAY_SIZE(csr->mmioaddr)) { DRM_ERROR("Firmware has wrong mmio count %u\n", dmc_header->mmio_count); + intel_csr_load_status_set(dev_priv, FW_FAILED); goto out; } csr->mmio_count = dmc_header->mmio_count; @@ -293,6 +321,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]); + intel_csr_load_status_set(dev_priv, FW_FAILED); goto out; } csr->mmioaddr[i] = dmc_header->mmioaddr[i]; @@ -303,6 +332,7 @@ 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); + intel_csr_load_status_set(dev_priv, FW_FAILED); goto out; } csr->dmc_fw_size = dmc_header->fw_size; @@ -310,6 +340,7 @@ static void finish_csr_load(const struct firmware *fw, void *context) csr->dmc_payload = kmalloc(nbytes, GFP_KERNEL); if (!csr->dmc_payload) { DRM_ERROR("Memory allocation failed for dmc payload\n"); + intel_csr_load_status_set(dev_priv, FW_FAILED); goto out; } @@ -327,6 +358,11 @@ 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); release_firmware(fw); } @@ -343,17 +379,25 @@ void 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"); + intel_csr_load_status_set(dev_priv, FW_FAILED); return; } + /* + * 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); - + intel_csr_load_status_set(dev_priv, FW_FAILED); + } } void intel_csr_ucode_fini(struct drm_device *dev) @@ -363,5 +407,6 @@ void intel_csr_ucode_fini(struct drm_device *dev) if (!HAS_CSR(dev)) return; + intel_csr_load_status_set(dev_priv, FW_FAILED); kfree(dev_priv->csr.dmc_payload); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index f3a2d88..25d7956 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1064,6 +1064,9 @@ unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane, /* intel_csr.c */ void intel_csr_ucode_init(struct drm_device *dev); +enum csr_state intel_csr_load_status_get(struct drm_i915_private *dev_priv); +void intel_csr_load_status_set(struct drm_i915_private *dev_priv, + enum csr_state state); 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 ce00e69..23f02a8 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 && \ @@ -319,9 +321,20 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv, SKL_DISPLAY_MISC_IO_POWER_DOMAINS)) | \ BIT(POWER_DOMAIN_INIT)) +static void gen9_enable_dc5(struct drm_i915_private *dev_priv) +{ + /* TODO: Implementation to be done. */ +} + +static void gen9_disable_dc5(struct drm_i915_private *dev_priv) +{ + /* TODO: Implementation to be done. */ +} + 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; @@ -361,6 +374,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"); + 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); } @@ -377,6 +397,19 @@ 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) { + enum csr_state state; + + wait_for((state = intel_csr_load_status_get(dev_priv)) != + FW_UNINITIALIZED, 1000); + if (state != FW_LOADED) + DRM_ERROR("CSR firmware not ready (%d)\n", + state); + else + gen9_enable_dc5(dev_priv); + } } }