[Intel-gfx] [PATCH 06/18] drm/i915: Defer default hardware context initialisation until first open
Daniel Vetter
daniel at ffwll.ch
Fri Mar 27 01:45:27 PDT 2015
On Thu, Mar 26, 2015 at 12:41:13PM -0700, yu.dai at intel.com wrote:
> From: Dave Gordon <david.s.gordon at intel.com>
>
> In order to fully initialise the default contexts, we have to execute
> batchbuffer commands on the GPU engines. But we can't do that until any
> required firmware has been loaded, which may not be possible during
> driver load, because the filesystem(s) containing the firmware may not
> be mounted until later.
>
> Therefore, we now allow the first call to the firmware-loading code to
> return -EAGAIN to indicate that it's not yet ready, and that it should
> be retried when the device is first opened from user code, by which
> time we expect that all required filesystems will have been mounted.
> The late-retry code will then re-attempt to load the firmware if the
> early attempt failed.
We've tried a similar approach a while back and it doesn't work well in
conjunction with rps - the hw tends to fall over if the context state
isn't properly initialized when going into rc6.
Why exactly can't we load that firmware right at boot-up, or at least
stall correctly until it's there?
-Daniel
>
> Issue: VIZ-4884
> Signed-off-by: Dave Gordon <david.s.gordon at intel.com>
> Signed-off-by: Alex Dai <yu.dai at intel.com>
> ---
> drivers/gpu/drm/i915/i915_drv.h | 1 +
> drivers/gpu/drm/i915/i915_gem.c | 9 ++++++++-
> drivers/gpu/drm/i915/i915_gem_context.c | 35 ++++++++++++++++++++++++++++-----
> drivers/gpu/drm/i915/intel_guc.h | 2 +-
> drivers/gpu/drm/i915/intel_guc_loader.c | 22 ++++++++++++++++++---
> drivers/gpu/drm/i915/intel_uc_loader.c | 12 +++++++++--
> 6 files changed, 69 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 1a60f86..45bdf30 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -1755,6 +1755,7 @@ struct drm_i915_private {
> /* hda/i915 audio component */
> bool audio_component_registered;
>
> + bool contexts_ready;
> uint32_t hw_context_size;
> struct list_head context_list;
>
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 38e49d9..0037ccf 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -4828,8 +4828,15 @@ i915_gem_init_hw(struct drm_device *dev)
> i915_gem_cleanup_ringbuffer(dev);
> }
>
> + /* We can't enable contexts until all firmware is loaded */
> + ret = intel_guc_load_ucode(dev, false);
> + if (ret == -EAGAIN)
> + return 0; /* too early */
> +
> ret = i915_gem_context_enable(dev_priv);
> - if (ret && ret != -EIO) {
> + if (ret == 0) {
> + dev_priv->contexts_ready = true;
> + } else if (ret && ret != -EIO) {
> DRM_ERROR("Context enable failed %d\n", ret);
> i915_gem_cleanup_ringbuffer(dev);
>
> diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
> index f3e84c4..2353d8f 100644
> --- a/drivers/gpu/drm/i915/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/i915_gem_context.c
> @@ -445,23 +445,48 @@ static int context_idr_cleanup(int id, void *p, void *data)
> return 0;
> }
>
> +/* Complete any late initialisation here */
> +static int i915_gem_context_first_open(struct drm_device *dev)
> +{
> + struct drm_i915_private *dev_priv = dev->dev_private;
> + int ret;
> +
> + /* We can't enable contexts until all firmware is loaded */
> + ret = intel_guc_load_ucode(dev, true);
> + WARN_ON(ret == -EAGAIN);
> +
> + ret = i915_gem_context_enable(dev_priv);
> + if (ret == 0)
> + dev_priv->contexts_ready = true;
> + return ret;
> +}
> +
> int i915_gem_context_open(struct drm_device *dev, struct drm_file *file)
> {
> + struct drm_i915_private *dev_priv = dev->dev_private;
> struct drm_i915_file_private *file_priv = file->driver_priv;
> struct intel_context *ctx;
> + int ret = 0;
>
> idr_init(&file_priv->context_idr);
>
> mutex_lock(&dev->struct_mutex);
> - ctx = i915_gem_create_context(dev, file_priv);
> +
> + if (!dev_priv->contexts_ready)
> + ret = i915_gem_context_first_open(dev);
> +
> + if (ret == 0) {
> + ctx = i915_gem_create_context(dev, file_priv);
> + if (IS_ERR(ctx))
> + ret = PTR_ERR(ctx);
> + }
> +
> mutex_unlock(&dev->struct_mutex);
>
> - if (IS_ERR(ctx)) {
> + if (ret)
> idr_destroy(&file_priv->context_idr);
> - return PTR_ERR(ctx);
> - }
>
> - return 0;
> + return ret;
> }
>
> void i915_gem_context_close(struct drm_device *dev, struct drm_file *file)
> diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
> index a06a7b3..d8262cf 100644
> --- a/drivers/gpu/drm/i915/intel_guc.h
> +++ b/drivers/gpu/drm/i915/intel_guc.h
> @@ -89,7 +89,7 @@ struct intel_guc {
> GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA)
>
> /* intel_guc_loader.c */
> -extern int intel_guc_load_ucode(struct drm_device *dev);
> +extern int intel_guc_load_ucode(struct drm_device *dev, bool wait);
> extern void intel_guc_ucode_fini(struct drm_device *dev);
> extern void intel_guc_ucode_init(struct drm_device *dev);
>
> diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
> index b9923b7..315e5d9 100644
> --- a/drivers/gpu/drm/i915/intel_guc_loader.c
> +++ b/drivers/gpu/drm/i915/intel_guc_loader.c
> @@ -217,25 +217,41 @@ out:
> }
>
> /*
> - * Called from gem_init_hw() during driver loading and also after a GPU reset.
> * Check that the firmware fetching process has succeeded, and if so transfer
> * the loaded image to the hardware.
> + *
> + * However, there are a few checks to do first. The very first call should have
> + * (wait == FALSE), but the fetch_state will still be PENDING as the firmware may
> + * not be available that early. Therefore, on this first call, we just return.
> + *
> + * The second call should come from the first open of the device (wait == TRUE).
> + * This is a good time to load the firmware into the device, as by this point it
> + * must be available.
> + *
> + * Any subsequent calls are expected to have wait == FALSE, and indicate that the
> + * hardware has been reset and so the firmware should be reloaded.
> */
> -int intel_guc_load_ucode(struct drm_device *dev)
> +int intel_guc_load_ucode(struct drm_device *dev, bool wait)
> {
> struct drm_i915_private *dev_priv = dev->dev_private;
> struct intel_uc_fw *guc_fw = &dev_priv->guc.guc_fw;
> int err;
>
> + DRM_DEBUG_DRIVER("GuC: wait %d, fetch status %d, load status %d\n",
> + wait, guc_fw->uc_fw_fetch_status, guc_fw->uc_fw_load_status);
> +
> + if (guc_fw->uc_fw_fetch_status == INTEL_UC_FIRMWARE_PENDING && !wait)
> + return -EAGAIN;
> +
> guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_NONE;
> if (guc_fw->uc_fw_fetch_status == INTEL_UC_FIRMWARE_NONE)
> return 0;
>
> - guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_PENDING;
> err = intel_uc_fw_check(dev, guc_fw);
> if (err)
> goto fail;
>
> + guc_fw->uc_fw_load_status = INTEL_UC_FIRMWARE_PENDING;
> err = guc_load_ucode(dev);
> if (err)
> goto fail;
> diff --git a/drivers/gpu/drm/i915/intel_uc_loader.c b/drivers/gpu/drm/i915/intel_uc_loader.c
> index 986dcf3..bc4b1e5 100644
> --- a/drivers/gpu/drm/i915/intel_uc_loader.c
> +++ b/drivers/gpu/drm/i915/intel_uc_loader.c
> @@ -49,8 +49,16 @@ static void uc_fw_finish(struct drm_device *dev, struct intel_uc_fw *uc_fw)
> uc_fw->uc_name, uc_fw->uc_fw_fetch_status, uc_fw->uc_fw_blob);
>
> fw = uc_fw->uc_fw_blob;
> - if (!fw)
> - goto fail;
> + if (!fw) {
> + /* no firmware found; try again in case FS was not mounted */
> + DRM_DEBUG_DRIVER("retry fetching %s fw from <%s>\n",
> + uc_fw->uc_name, uc_fw->uc_fw_path);
> + if (request_firmware(&fw, uc_fw->uc_fw_path, &dev->pdev->dev))
> + goto fail;
> + DRM_DEBUG_DRIVER("fetch %s fw from <%s> succeeded, fw %p\n",
> + uc_fw->uc_name, uc_fw->uc_fw_path, fw);
> + uc_fw->uc_fw_blob = fw;
> + }
>
> if (uc_fw->uc_fw_check && !uc_fw->uc_fw_check(uc_fw))
> goto fail;
> --
> 1.9.1
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
More information about the Intel-gfx
mailing list