summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c
diff options
context:
space:
mode:
authorDaniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>2022-12-08 12:05:18 -0800
committerDaniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>2022-12-09 08:28:43 -0800
commit15bd4a67e914dbee6b6ba5dfd32a09cbf7419a5b (patch)
tree19ac247878b5bde8721d18a1e53c57e162528ba1 /drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c
parentf0ce5178a38918adfef728f43dd544616b05e3e3 (diff)
downloadlinux-stable-15bd4a67e914dbee6b6ba5dfd32a09cbf7419a5b.tar.gz
linux-stable-15bd4a67e914dbee6b6ba5dfd32a09cbf7419a5b.tar.bz2
linux-stable-15bd4a67e914dbee6b6ba5dfd32a09cbf7419a5b.zip
drm/i915/gsc: GSC firmware loading
GSC FW is loaded by submitting a dedicated command via the GSC engine. The memory area used for loading the FW is then re-purposed as local memory for the GSC itself, so we use a separate allocation instead of using the one where we keep the firmware stored for reload. The GSC is not reset as part of GT reset, so we only need to load it on first boot and S3/S4 exit. v2: use REG_* for register fields definitions (Rodrigo), move to WQ immediately v3: mark worker function as static Bspec: 63347, 65346 Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Cc: Alan Previn <alan.previn.teres.alexis@intel.com> Cc: John Harrison <John.C.Harrison@Intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Reviewed-by: Alan Previn <alan.previn.teres.alexis@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20221208200521.2928378-4-daniele.ceraolospurio@intel.com
Diffstat (limited to 'drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c')
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c69
1 files changed, 68 insertions, 1 deletions
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c b/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c
index 7abbbb09f432..fd21dbd2663b 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_gsc_uc.c
@@ -7,8 +7,19 @@
#include "gt/intel_gt.h"
#include "intel_gsc_uc.h"
+#include "intel_gsc_fw.h"
#include "i915_drv.h"
+static void gsc_work(struct work_struct *work)
+{
+ struct intel_gsc_uc *gsc = container_of(work, typeof(*gsc), work);
+ struct intel_gt *gt = gsc_uc_to_gt(gsc);
+ intel_wakeref_t wakeref;
+
+ with_intel_runtime_pm(gt->uncore->rpm, wakeref)
+ intel_gsc_uc_fw_upload(gsc);
+}
+
static bool gsc_engine_supported(struct intel_gt *gt)
{
intel_engine_mask_t mask;
@@ -32,6 +43,7 @@ static bool gsc_engine_supported(struct intel_gt *gt)
void intel_gsc_uc_init_early(struct intel_gsc_uc *gsc)
{
intel_uc_fw_init_early(&gsc->fw, INTEL_UC_FW_TYPE_GSC);
+ INIT_WORK(&gsc->work, gsc_work);
/* we can arrive here from i915_driver_early_probe for primary
* GT with it being not fully setup hence check device info's
@@ -45,17 +57,46 @@ void intel_gsc_uc_init_early(struct intel_gsc_uc *gsc)
int intel_gsc_uc_init(struct intel_gsc_uc *gsc)
{
- struct drm_i915_private *i915 = gsc_uc_to_gt(gsc)->i915;
+ static struct lock_class_key gsc_lock;
+ struct intel_gt *gt = gsc_uc_to_gt(gsc);
+ struct drm_i915_private *i915 = gt->i915;
+ struct intel_engine_cs *engine = gt->engine[GSC0];
+ struct intel_context *ce;
+ struct i915_vma *vma;
int err;
err = intel_uc_fw_init(&gsc->fw);
if (err)
goto out;
+ vma = intel_guc_allocate_vma(&gt->uc.guc, SZ_8M);
+ if (IS_ERR(vma)) {
+ err = PTR_ERR(vma);
+ goto out_fw;
+ }
+
+ gsc->local = vma;
+
+ ce = intel_engine_create_pinned_context(engine, engine->gt->vm, SZ_4K,
+ I915_GEM_HWS_GSC_ADDR,
+ &gsc_lock, "gsc_context");
+ if (IS_ERR(ce)) {
+ drm_err(&gt->i915->drm,
+ "failed to create GSC CS ctx for FW communication\n");
+ err = PTR_ERR(ce);
+ goto out_vma;
+ }
+
+ gsc->ce = ce;
+
intel_uc_fw_change_status(&gsc->fw, INTEL_UC_FIRMWARE_LOADABLE);
return 0;
+out_vma:
+ i915_vma_unpin_and_release(&gsc->local, 0);
+out_fw:
+ intel_uc_fw_fini(&gsc->fw);
out:
i915_probe_error(i915, "failed with %d\n", err);
return err;
@@ -66,5 +107,31 @@ void intel_gsc_uc_fini(struct intel_gsc_uc *gsc)
if (!intel_uc_fw_is_loadable(&gsc->fw))
return;
+ flush_work(&gsc->work);
+
+ if (gsc->ce)
+ intel_engine_destroy_pinned_context(fetch_and_zero(&gsc->ce));
+
+ i915_vma_unpin_and_release(&gsc->local, 0);
+
intel_uc_fw_fini(&gsc->fw);
}
+
+void intel_gsc_uc_suspend(struct intel_gsc_uc *gsc)
+{
+ if (!intel_uc_fw_is_loadable(&gsc->fw))
+ return;
+
+ flush_work(&gsc->work);
+}
+
+void intel_gsc_uc_load_start(struct intel_gsc_uc *gsc)
+{
+ if (!intel_uc_fw_is_loadable(&gsc->fw))
+ return;
+
+ if (intel_gsc_uc_fw_init_done(gsc))
+ return;
+
+ queue_work(system_unbound_wq, &gsc->work);
+}