From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Badiuzzaman Iskhandar Date: Tue, 9 Oct 2018 15:51:18 +0800 Subject: [PATCH] MUST_REBASE [IOTG]: drm/i915: Allow late GuC/HuC loading This patch allows for the GuC and HuC to be loaded until the first device is open (instead of during the driver initialisation). Delaying the fw load prevents a load failure when the partition that the firmware is supposed to be on has not been mounted yet, as is the case in Android. During i915 init, if huc/guc enabled, the huc/guc fw sizes need to be known. As we defer the fw fetch later, the fw sizes can't be determined. ggtt_pin_bias relies on the fw size as well. MUST_REBASE: The hw_late code is part of a solution for loading firmware of a file system that has not been mounted yet. Only a problem on Android. This patch is a rewrote from similar patch in 4.11 Change-Id: Ic4f414deed9961d73c25434b3d8698ae9fbb425c Tracked-On: Signed-off-by: Badiuzzaman Iskhandar --- drivers/gpu/drm/i915/i915_drv.h | 3 ++ drivers/gpu/drm/i915/i915_gem.c | 48 ++++++++++++++++++++----- drivers/gpu/drm/i915/i915_gem_context.c | 44 +++++++++++++++++++---- drivers/gpu/drm/i915/intel_wopcm.c | 7 ++++ 4 files changed, 88 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3cd14d171c61..972b25e62711 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2148,6 +2148,8 @@ struct drm_i915_private { struct i915_pmu pmu; + bool contexts_ready; /* for deferred initialization */ + /* * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch * will be rejected. Instead look for a better place. @@ -3210,6 +3212,7 @@ void i915_gem_reset_engine(struct intel_engine_cs *engine, void i915_gem_init_mmio(struct drm_i915_private *i915); int __must_check i915_gem_init(struct drm_i915_private *dev_priv); int __must_check i915_gem_init_hw(struct drm_i915_private *dev_priv); +int __must_check i915_gem_init_hw_late(struct drm_i915_private *dev_priv); void i915_gem_init_swizzling(struct drm_i915_private *dev_priv); void i915_gem_fini(struct drm_i915_private *dev_priv); void i915_gem_cleanup_engines(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 402db0dac1c4..e9aad26ee653 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -6198,6 +6198,28 @@ static int __i915_gem_restart_engines(void *data) return 0; } +int i915_gem_init_hw_late(struct drm_i915_private *dev_priv) +{ + int ret; + + /* + * Place for things that can be delayed until the first context + * is open. For example, fw loading in android. + */ + + /* fetch firmware */ + intel_uc_init_misc(dev_priv); + + /* Load fw. We can't enable contexts until all firmware is loaded */ + ret = intel_uc_init_hw(dev_priv); + if (ret) { + DRM_ERROR("Late init: enabling uc failed (%d)\n", ret); + return ret; + } + + return 0; +} + int i915_gem_init_hw(struct drm_i915_private *dev_priv) { int ret; @@ -6256,11 +6278,17 @@ int i915_gem_init_hw(struct drm_i915_private *dev_priv) goto out; } - /* We can't enable contexts until all firmware is loaded */ - ret = intel_uc_init_hw(dev_priv); - if (ret) { - DRM_ERROR("Enabling uc failed (%d)\n", ret); - goto out; + /* + * Don't call i915_gem_init_hw_late() the very first time (during + * driver load); it will get called during first open instead. + * It should only be called on subsequent (re-initialization) passes. + */ + if (dev_priv->contexts_ready) { + ret = i915_gem_init_hw_late(dev_priv); + if (ret) + goto out; + } else { + DRM_DEBUG_DRIVER("Deferring late initialization\n"); } intel_mocs_init_l3cc_table(dev_priv); @@ -6424,9 +6452,13 @@ int i915_gem_init(struct drm_i915_private *dev_priv) if (ret) return ret; - ret = intel_uc_init_misc(dev_priv); - if (ret) - return ret; + /* + * ANDROID: fetch fw during drm_open instead + * due to filesystem is not up yet during driver init + * ret = intel_uc_init_misc(dev_priv); + * if (ret) + * return ret; + */ ret = intel_wopcm_init(&dev_priv->wopcm); if (ret) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 74917976d99e..29cd2281414b 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -567,23 +567,55 @@ static int context_idr_cleanup(int id, void *p, void *data) return 0; } +int i915_gem_context_first_open(struct drm_i915_private *dev_priv) +{ + int ret; + + lockdep_assert_held(&dev_priv->drm.struct_mutex); + + DRM_DEBUG_DRIVER("Late initialization starting\n"); + + intel_runtime_pm_get(dev_priv); + intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL); + + ret = i915_gem_init_hw_late(dev_priv); + if (ret == 0) + dev_priv->contexts_ready = true; + else + DRM_ERROR("Late initialization failed: %d\n", ret); + + intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); + intel_runtime_pm_put(dev_priv); + + return ret; +} + int i915_gem_context_open(struct drm_i915_private *i915, struct drm_file *file) { struct drm_i915_file_private *file_priv = file->driver_priv; struct i915_gem_context *ctx; + int ret = 0; idr_init(&file_priv->context_idr); mutex_lock(&i915->drm.struct_mutex); - ctx = i915_gem_create_context(i915, file_priv); - mutex_unlock(&i915->drm.struct_mutex); - if (IS_ERR(ctx)) { - idr_destroy(&file_priv->context_idr); - return PTR_ERR(ctx); + + if (!(i915->contexts_ready)) + ret = i915_gem_context_first_open(i915); + + if (ret == 0) { + ctx = i915_gem_create_context(i915, file_priv); + if (IS_ERR(ctx)) + ret = PTR_ERR(ctx); + + GEM_BUG_ON(i915_gem_context_is_kernel(ctx)); } - GEM_BUG_ON(i915_gem_context_is_kernel(ctx)); + mutex_unlock(&i915->drm.struct_mutex); + + if (ret) + idr_destroy(&file_priv->context_idr); return 0; } diff --git a/drivers/gpu/drm/i915/intel_wopcm.c b/drivers/gpu/drm/i915/intel_wopcm.c index 74bf76f3fddc..5ff877ed7b12 100644 --- a/drivers/gpu/drm/i915/intel_wopcm.c +++ b/drivers/gpu/drm/i915/intel_wopcm.c @@ -207,6 +207,13 @@ int intel_wopcm_init(struct intel_wopcm *wopcm) wopcm->guc.base = guc_wopcm_base; wopcm->guc.size = guc_wopcm_size; + /* + * In deferred fw loading, we defer the intel_guc_init which will + * initialize the guc.ggtt_pin_bias. As it relies on wopcm size, + * set the ggtt_pin_bias after wopcm initialization + */ + i915->guc.ggtt_pin_bias = i915->wopcm.size - i915->wopcm.guc.base; + return 0; } -- https://clearlinux.org