From ee71434eeb9c729c7e09911e1b69fc5baf498222 Mon Sep 17 00:00:00 2001 From: Aravind Iddamsetty Date: Mon, 7 Nov 2022 18:05:58 -0800 Subject: drm/i915/mtl: Handle wopcm per-GT and limit calculations. With MTL standalone media architecture the wopcm layout has changed, with separate partitioning in WOPCM for the root GT GuC and the media GT GuC. The size of WOPCM is 4MB with the lower 2MB reserved for the media GT and the upper 2MB for the root GT. Given that MTL has GuC deprivilege, the WOPCM registers are pre-locked by the bios. Therefore, we can skip all the math for the partitioning and just limit ourselves to sanity-checking the values. v2: fix makefile file ordering (Jani) v3: drop XELPM_SAMEDIA_WOPCM_SIZE, check huc instead of VDBOX (John) v4: further clarify commit message, remove blank line (John) Signed-off-by: Aravind Iddamsetty Signed-off-by: Daniele Ceraolo Spurio Cc: Matt Roper Cc: John Harrison Cc: Alan Previn Cc: Jani Nikula Reviewed-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20221108020600.3575467-5-daniele.ceraolospurio@intel.com --- Documentation/gpu/i915.rst | 2 +- drivers/gpu/drm/i915/Makefile | 5 +- drivers/gpu/drm/i915/gt/intel_ggtt.c | 2 +- drivers/gpu/drm/i915/gt/intel_gt.c | 1 + drivers/gpu/drm/i915/gt/intel_gt_types.h | 2 + drivers/gpu/drm/i915/gt/intel_wopcm.c | 322 +++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/gt/intel_wopcm.h | 60 ++++++ drivers/gpu/drm/i915/gt/uc/intel_uc.c | 4 +- drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c | 14 +- drivers/gpu/drm/i915/i915_driver.c | 2 - drivers/gpu/drm/i915/i915_drv.h | 3 - drivers/gpu/drm/i915/i915_gem.c | 5 +- drivers/gpu/drm/i915/intel_wopcm.c | 305 ----------------------------- drivers/gpu/drm/i915/intel_wopcm.h | 60 ------ 14 files changed, 403 insertions(+), 384 deletions(-) create mode 100644 drivers/gpu/drm/i915/gt/intel_wopcm.c create mode 100644 drivers/gpu/drm/i915/gt/intel_wopcm.h delete mode 100644 drivers/gpu/drm/i915/intel_wopcm.c delete mode 100644 drivers/gpu/drm/i915/intel_wopcm.h diff --git a/Documentation/gpu/i915.rst b/Documentation/gpu/i915.rst index 4e59db1cfb00..60ea21734902 100644 --- a/Documentation/gpu/i915.rst +++ b/Documentation/gpu/i915.rst @@ -494,7 +494,7 @@ WOPCM WOPCM Layout ~~~~~~~~~~~~ -.. kernel-doc:: drivers/gpu/drm/i915/intel_wopcm.c +.. kernel-doc:: drivers/gpu/drm/i915/gt/intel_wopcm.c :doc: WOPCM Layout GuC diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 51704b54317c..d09248c3b176 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -127,9 +127,11 @@ gt-y += \ gt/intel_sseu.o \ gt/intel_sseu_debugfs.o \ gt/intel_timeline.o \ + gt/intel_wopcm.o \ gt/intel_workarounds.o \ gt/shmem_utils.o \ gt/sysfs_engines.o + # x86 intel-gtt module support gt-$(CONFIG_X86) += gt/intel_ggtt_gmch.o # autogenerated null render state @@ -183,8 +185,7 @@ i915-y += \ i915_trace_points.o \ i915_ttm_buddy_manager.o \ i915_vma.o \ - i915_vma_resource.o \ - intel_wopcm.o + i915_vma_resource.o # general-purpose microcontroller (GuC) support i915-y += gt/uc/intel_uc.o \ diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c index 2518cebbf931..8145851ad23d 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c @@ -560,7 +560,7 @@ static int init_ggtt(struct i915_ggtt *ggtt) * why. */ ggtt->pin_bias = max_t(u32, I915_GTT_PAGE_SIZE, - intel_wopcm_guc_size(&ggtt->vm.i915->wopcm)); + intel_wopcm_guc_size(&ggtt->vm.gt->wopcm)); ret = intel_vgt_balloon(ggtt); if (ret) diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index 0ba7d6f36b28..04908f1d6564 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -54,6 +54,7 @@ void intel_gt_common_init_early(struct intel_gt *gt) seqcount_mutex_init(>->tlb.seqno, >->tlb.invalidate_lock); intel_gt_pm_init_early(gt); + intel_wopcm_init_early(>->wopcm); intel_uc_init_early(>->uc); intel_rps_init_early(>->rps); } diff --git a/drivers/gpu/drm/i915/gt/intel_gt_types.h b/drivers/gpu/drm/i915/gt/intel_gt_types.h index a0cc73b401ef..c1d9cd255e06 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_types.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_types.h @@ -31,6 +31,7 @@ #include "intel_migrate_types.h" #include "intel_wakeref.h" #include "pxp/intel_pxp_types.h" +#include "intel_wopcm.h" struct drm_i915_private; struct i915_ggtt; @@ -101,6 +102,7 @@ struct intel_gt { struct intel_uc uc; struct intel_gsc gsc; + struct intel_wopcm wopcm; struct { /* Serialize global tlb invalidations */ diff --git a/drivers/gpu/drm/i915/gt/intel_wopcm.c b/drivers/gpu/drm/i915/gt/intel_wopcm.c new file mode 100644 index 000000000000..7ebbcc191c2d --- /dev/null +++ b/drivers/gpu/drm/i915/gt/intel_wopcm.c @@ -0,0 +1,322 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2017-2019 Intel Corporation + */ + +#include "intel_wopcm.h" +#include "i915_drv.h" + +/** + * DOC: WOPCM Layout + * + * The layout of the WOPCM will be fixed after writing to GuC WOPCM size and + * offset registers whose values are calculated and determined by HuC/GuC + * firmware size and set of hardware requirements/restrictions as shown below: + * + * :: + * + * +=========> +====================+ <== WOPCM Top + * ^ | HW contexts RSVD | + * | +===> +====================+ <== GuC WOPCM Top + * | ^ | | + * | | | | + * | | | | + * | GuC | | + * | WOPCM | | + * | Size +--------------------+ + * WOPCM | | GuC FW RSVD | + * | | +--------------------+ + * | | | GuC Stack RSVD | + * | | +------------------- + + * | v | GuC WOPCM RSVD | + * | +===> +====================+ <== GuC WOPCM base + * | | WOPCM RSVD | + * | +------------------- + <== HuC Firmware Top + * v | HuC FW | + * +=========> +====================+ <== WOPCM Base + * + * GuC accessible WOPCM starts at GuC WOPCM base and ends at GuC WOPCM top. + * The top part of the WOPCM is reserved for hardware contexts (e.g. RC6 + * context). + */ + +/* Default WOPCM size is 2MB from Gen11, 1MB on previous platforms */ +#define GEN11_WOPCM_SIZE SZ_2M +#define GEN9_WOPCM_SIZE SZ_1M +#define MAX_WOPCM_SIZE SZ_8M +/* 16KB WOPCM (RSVD WOPCM) is reserved from HuC firmware top. */ +#define WOPCM_RESERVED_SIZE SZ_16K + +/* 16KB reserved at the beginning of GuC WOPCM. */ +#define GUC_WOPCM_RESERVED SZ_16K +/* 8KB from GUC_WOPCM_RESERVED is reserved for GuC stack. */ +#define GUC_WOPCM_STACK_RESERVED SZ_8K + +/* GuC WOPCM Offset value needs to be aligned to 16KB. */ +#define GUC_WOPCM_OFFSET_ALIGNMENT (1UL << GUC_WOPCM_OFFSET_SHIFT) + +/* 24KB at the end of WOPCM is reserved for RC6 CTX on BXT. */ +#define BXT_WOPCM_RC6_CTX_RESERVED (SZ_16K + SZ_8K) +/* 36KB WOPCM reserved at the end of WOPCM on ICL. */ +#define ICL_WOPCM_HW_CTX_RESERVED (SZ_32K + SZ_4K) + +/* 128KB from GUC_WOPCM_RESERVED is reserved for FW on Gen9. */ +#define GEN9_GUC_FW_RESERVED SZ_128K +#define GEN9_GUC_WOPCM_OFFSET (GUC_WOPCM_RESERVED + GEN9_GUC_FW_RESERVED) + +static inline struct intel_gt *wopcm_to_gt(struct intel_wopcm *wopcm) +{ + return container_of(wopcm, struct intel_gt, wopcm); +} + +/** + * intel_wopcm_init_early() - Early initialization of the WOPCM. + * @wopcm: pointer to intel_wopcm. + * + * Setup the size of WOPCM which will be used by later on WOPCM partitioning. + */ +void intel_wopcm_init_early(struct intel_wopcm *wopcm) +{ + struct intel_gt *gt = wopcm_to_gt(wopcm); + struct drm_i915_private *i915 = gt->i915; + + if (!HAS_GT_UC(i915)) + return; + + if (GRAPHICS_VER(i915) >= 11) + wopcm->size = GEN11_WOPCM_SIZE; + else + wopcm->size = GEN9_WOPCM_SIZE; + + drm_dbg(&i915->drm, "WOPCM: %uK\n", wopcm->size / 1024); +} + +static u32 context_reserved_size(struct drm_i915_private *i915) +{ + if (IS_GEN9_LP(i915)) + return BXT_WOPCM_RC6_CTX_RESERVED; + else if (GRAPHICS_VER(i915) >= 11) + return ICL_WOPCM_HW_CTX_RESERVED; + else + return 0; +} + +static bool gen9_check_dword_gap(struct drm_i915_private *i915, + u32 guc_wopcm_base, u32 guc_wopcm_size) +{ + u32 offset; + + /* + * GuC WOPCM size shall be at least a dword larger than the offset from + * WOPCM base (GuC WOPCM offset from WOPCM base + GEN9_GUC_WOPCM_OFFSET) + * due to hardware limitation on Gen9. + */ + offset = guc_wopcm_base + GEN9_GUC_WOPCM_OFFSET; + if (offset > guc_wopcm_size || + (guc_wopcm_size - offset) < sizeof(u32)) { + drm_err(&i915->drm, + "WOPCM: invalid GuC region size: %uK < %uK\n", + guc_wopcm_size / SZ_1K, + (u32)(offset + sizeof(u32)) / SZ_1K); + return false; + } + + return true; +} + +static bool gen9_check_huc_fw_fits(struct drm_i915_private *i915, + u32 guc_wopcm_size, u32 huc_fw_size) +{ + /* + * On Gen9, hardware requires the total available GuC WOPCM + * size to be larger than or equal to HuC firmware size. Otherwise, + * firmware uploading would fail. + */ + if (huc_fw_size > guc_wopcm_size - GUC_WOPCM_RESERVED) { + drm_err(&i915->drm, "WOPCM: no space for %s: %uK < %uK\n", + intel_uc_fw_type_repr(INTEL_UC_FW_TYPE_HUC), + (guc_wopcm_size - GUC_WOPCM_RESERVED) / SZ_1K, + huc_fw_size / 1024); + return false; + } + + return true; +} + +static bool check_hw_restrictions(struct drm_i915_private *i915, + u32 guc_wopcm_base, u32 guc_wopcm_size, + u32 huc_fw_size) +{ + if (GRAPHICS_VER(i915) == 9 && !gen9_check_dword_gap(i915, guc_wopcm_base, + guc_wopcm_size)) + return false; + + if (GRAPHICS_VER(i915) == 9 && + !gen9_check_huc_fw_fits(i915, guc_wopcm_size, huc_fw_size)) + return false; + + return true; +} + +static bool __check_layout(struct intel_gt *gt, u32 wopcm_size, + u32 guc_wopcm_base, u32 guc_wopcm_size, + u32 guc_fw_size, u32 huc_fw_size) +{ + struct drm_i915_private *i915 = gt->i915; + const u32 ctx_rsvd = context_reserved_size(i915); + u32 size; + + size = wopcm_size - ctx_rsvd; + if (unlikely(range_overflows(guc_wopcm_base, guc_wopcm_size, size))) { + drm_err(&i915->drm, + "WOPCM: invalid GuC region layout: %uK + %uK > %uK\n", + guc_wopcm_base / SZ_1K, guc_wopcm_size / SZ_1K, + size / SZ_1K); + return false; + } + + size = guc_fw_size + GUC_WOPCM_RESERVED + GUC_WOPCM_STACK_RESERVED; + if (unlikely(guc_wopcm_size < size)) { + drm_err(&i915->drm, "WOPCM: no space for %s: %uK < %uK\n", + intel_uc_fw_type_repr(INTEL_UC_FW_TYPE_GUC), + guc_wopcm_size / SZ_1K, size / SZ_1K); + return false; + } + + if (intel_uc_supports_huc(>->uc)) { + size = huc_fw_size + WOPCM_RESERVED_SIZE; + if (unlikely(guc_wopcm_base < size)) { + drm_err(&i915->drm, "WOPCM: no space for %s: %uK < %uK\n", + intel_uc_fw_type_repr(INTEL_UC_FW_TYPE_HUC), + guc_wopcm_base / SZ_1K, size / SZ_1K); + return false; + } + } + + return check_hw_restrictions(i915, guc_wopcm_base, guc_wopcm_size, + huc_fw_size); +} + +static bool __wopcm_regs_locked(struct intel_uncore *uncore, + u32 *guc_wopcm_base, u32 *guc_wopcm_size) +{ + u32 reg_base = intel_uncore_read(uncore, DMA_GUC_WOPCM_OFFSET); + u32 reg_size = intel_uncore_read(uncore, GUC_WOPCM_SIZE); + + if (!(reg_size & GUC_WOPCM_SIZE_LOCKED) || + !(reg_base & GUC_WOPCM_OFFSET_VALID)) + return false; + + *guc_wopcm_base = reg_base & GUC_WOPCM_OFFSET_MASK; + *guc_wopcm_size = reg_size & GUC_WOPCM_SIZE_MASK; + return true; +} + +static bool __wopcm_regs_writable(struct intel_uncore *uncore) +{ + if (!HAS_GUC_DEPRIVILEGE(uncore->i915)) + return true; + + return intel_uncore_read(uncore, GUC_SHIM_CONTROL2) & GUC_IS_PRIVILEGED; +} + +/** + * intel_wopcm_init() - Initialize the WOPCM structure. + * @wopcm: pointer to intel_wopcm. + * + * This function will partition WOPCM space based on GuC and HuC firmware sizes + * and will allocate max remaining for use by GuC. This function will also + * enforce platform dependent hardware restrictions on GuC WOPCM offset and + * size. It will fail the WOPCM init if any of these checks fail, so that the + * following WOPCM registers setup and GuC firmware uploading would be aborted. + */ +void intel_wopcm_init(struct intel_wopcm *wopcm) +{ + struct intel_gt *gt = wopcm_to_gt(wopcm); + struct drm_i915_private *i915 = gt->i915; + u32 guc_fw_size = intel_uc_fw_get_upload_size(>->uc.guc.fw); + u32 huc_fw_size = intel_uc_fw_get_upload_size(>->uc.huc.fw); + u32 ctx_rsvd = context_reserved_size(i915); + u32 wopcm_size = wopcm->size; + u32 guc_wopcm_base; + u32 guc_wopcm_size; + + if (!guc_fw_size) + return; + + GEM_BUG_ON(!wopcm_size); + GEM_BUG_ON(wopcm->guc.base); + GEM_BUG_ON(wopcm->guc.size); + GEM_BUG_ON(guc_fw_size >= wopcm_size); + GEM_BUG_ON(huc_fw_size >= wopcm_size); + GEM_BUG_ON(ctx_rsvd + WOPCM_RESERVED_SIZE >= wopcm_size); + + if (i915_inject_probe_failure(i915)) + return; + + if (__wopcm_regs_locked(gt->uncore, &guc_wopcm_base, &guc_wopcm_size)) { + drm_dbg(&i915->drm, "GuC WOPCM is already locked [%uK, %uK)\n", + guc_wopcm_base / SZ_1K, guc_wopcm_size / SZ_1K); + /* + * Note that to keep things simple (i.e. avoid different + * defines per platform) our WOPCM math doesn't always use the + * actual WOPCM size, but a value that is less or equal to it. + * This is perfectly fine when i915 programs the registers, but + * on platforms with GuC deprivilege the registers are not + * writable from i915 and are instead pre-programmed by the + * bios/IFWI, so there might be a mismatch of sizes. + * Instead of handling the size difference, we trust that the + * programmed values make sense and disable the relevant check + * by using the maximum possible WOPCM size in the verification + * math. In the extremely unlikely case that the registers + * were pre-programmed with an invalid value, we will still + * gracefully fail later during the GuC/HuC dma. + */ + if (!__wopcm_regs_writable(gt->uncore)) + wopcm_size = MAX_WOPCM_SIZE; + + goto check; + } + + /* + * On platforms with a media GT, the WOPCM is partitioned between the + * two GTs, so we would have to take that into account when doing the + * math below. There is also a new section reserved for the GSC context + * that would have to be factored in. However, all platforms with a + * media GT also have GuC depriv enabled, so the WOPCM regs are + * pre-locked and therefore we don't have to do the math ourselves. + */ + if (unlikely(i915->media_gt)) { + drm_err(&i915->drm, "Unlocked WOPCM regs with media GT\n"); + return; + } + + /* + * Aligned value of guc_wopcm_base will determine available WOPCM space + * for HuC firmware and mandatory reserved area. + */ + guc_wopcm_base = huc_fw_size + WOPCM_RESERVED_SIZE; + guc_wopcm_base = ALIGN(guc_wopcm_base, GUC_WOPCM_OFFSET_ALIGNMENT); + + /* + * Need to clamp guc_wopcm_base now to make sure the following math is + * correct. Formal check of whole WOPCM layout will be done below. + */ + guc_wopcm_base = min(guc_wopcm_base, wopcm_size - ctx_rsvd); + + /* Aligned remainings of usable WOPCM space can be assigned to GuC. */ + guc_wopcm_size = wopcm_size - ctx_rsvd - guc_wopcm_base; + guc_wopcm_size &= GUC_WOPCM_SIZE_MASK; + + drm_dbg(&i915->drm, "Calculated GuC WOPCM [%uK, %uK)\n", + guc_wopcm_base / SZ_1K, guc_wopcm_size / SZ_1K); + +check: + if (__check_layout(gt, wopcm_size, guc_wopcm_base, guc_wopcm_size, + guc_fw_size, huc_fw_size)) { + wopcm->guc.base = guc_wopcm_base; + wopcm->guc.size = guc_wopcm_size; + GEM_BUG_ON(!wopcm->guc.base); + GEM_BUG_ON(!wopcm->guc.size); + } +} diff --git a/drivers/gpu/drm/i915/gt/intel_wopcm.h b/drivers/gpu/drm/i915/gt/intel_wopcm.h new file mode 100644 index 000000000000..17d6aa86008a --- /dev/null +++ b/drivers/gpu/drm/i915/gt/intel_wopcm.h @@ -0,0 +1,60 @@ +/* + * SPDX-License-Identifier: MIT + * + * Copyright © 2017-2018 Intel Corporation + */ + +#ifndef _INTEL_WOPCM_H_ +#define _INTEL_WOPCM_H_ + +#include + +/** + * struct intel_wopcm - Overall WOPCM info and WOPCM regions. + * @size: Size of overall WOPCM. + * @guc: GuC WOPCM Region info. + * @guc.base: GuC WOPCM base which is offset from WOPCM base. + * @guc.size: Size of the GuC WOPCM region. + */ +struct intel_wopcm { + u32 size; + struct { + u32 base; + u32 size; + } guc; +}; + +/** + * intel_wopcm_guc_base() + * @wopcm: intel_wopcm structure + * + * Returns the base of the WOPCM shadowed region. + * + * Returns: + * 0 if GuC is not present or not in use. + * Otherwise, the GuC WOPCM base. + */ +static inline u32 intel_wopcm_guc_base(struct intel_wopcm *wopcm) +{ + return wopcm->guc.base; +} + +/** + * intel_wopcm_guc_size() + * @wopcm: intel_wopcm structure + * + * Returns size of the WOPCM shadowed region. + * + * Returns: + * 0 if GuC is not present or not in use. + * Otherwise, the GuC WOPCM size. + */ +static inline u32 intel_wopcm_guc_size(struct intel_wopcm *wopcm) +{ + return wopcm->guc.size; +} + +void intel_wopcm_init_early(struct intel_wopcm *wopcm); +void intel_wopcm_init(struct intel_wopcm *wopcm); + +#endif diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc.c b/drivers/gpu/drm/i915/gt/uc/intel_uc.c index dbd048b77e19..4cd8a787f9e5 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc.c @@ -357,8 +357,8 @@ static int uc_init_wopcm(struct intel_uc *uc) { struct intel_gt *gt = uc_to_gt(uc); struct intel_uncore *uncore = gt->uncore; - u32 base = intel_wopcm_guc_base(>->i915->wopcm); - u32 size = intel_wopcm_guc_size(>->i915->wopcm); + u32 base = intel_wopcm_guc_base(>->wopcm); + u32 size = intel_wopcm_guc_size(>->wopcm); u32 huc_agent = intel_uc_uses_huc(uc) ? HUC_LOADING_AGENT_GUC : 0; u32 mask; int err; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c index 81e06d71c1a8..0c80ba51a4bd 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c @@ -478,10 +478,11 @@ static int check_gsc_manifest(const struct firmware *fw, return 0; } -static int check_ccs_header(struct drm_i915_private *i915, +static int check_ccs_header(struct intel_gt *gt, const struct firmware *fw, struct intel_uc_fw *uc_fw) { + struct drm_i915_private *i915 = gt->i915; struct uc_css_header *css; size_t size; @@ -523,10 +524,10 @@ static int check_ccs_header(struct drm_i915_private *i915, /* Sanity check whether this fw is not larger than whole WOPCM memory */ size = __intel_uc_fw_get_upload_size(uc_fw); - if (unlikely(size >= i915->wopcm.size)) { + if (unlikely(size >= gt->wopcm.size)) { drm_warn(&i915->drm, "%s firmware %s: invalid size: %zu > %zu\n", intel_uc_fw_type_repr(uc_fw->type), uc_fw->file_selected.path, - size, (size_t)i915->wopcm.size); + size, (size_t)gt->wopcm.size); return -E2BIG; } @@ -554,7 +555,8 @@ static int check_ccs_header(struct drm_i915_private *i915, */ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw) { - struct drm_i915_private *i915 = __uc_fw_to_gt(uc_fw)->i915; + struct intel_gt *gt = __uc_fw_to_gt(uc_fw); + struct drm_i915_private *i915 = gt->i915; struct intel_uc_fw_file file_ideal; struct device *dev = i915->drm.dev; struct drm_i915_gem_object *obj; @@ -562,7 +564,7 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw) bool old_ver = false; int err; - GEM_BUG_ON(!i915->wopcm.size); + GEM_BUG_ON(!gt->wopcm.size); GEM_BUG_ON(!intel_uc_fw_is_enabled(uc_fw)); err = i915_inject_probe_error(i915, -ENXIO); @@ -615,7 +617,7 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw) if (uc_fw->loaded_via_gsc) err = check_gsc_manifest(fw, uc_fw); else - err = check_ccs_header(i915, fw, uc_fw); + err = check_ccs_header(gt, fw, uc_fw); if (err) goto fail; diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index c3d43f9b1e45..69103ae37779 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -372,8 +372,6 @@ static int i915_driver_early_probe(struct drm_i915_private *dev_priv) if (ret) goto err_ttm; - intel_wopcm_init_early(&dev_priv->wopcm); - ret = intel_root_gt_init_early(dev_priv); if (ret < 0) goto err_rootgt; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ff7b1b702394..7e3820d2c404 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -62,7 +62,6 @@ #include "intel_runtime_pm.h" #include "intel_step.h" #include "intel_uncore.h" -#include "intel_wopcm.h" struct drm_i915_clock_gating_funcs; struct drm_i915_gem_object; @@ -235,8 +234,6 @@ struct drm_i915_private { struct intel_gvt *gvt; - struct intel_wopcm wopcm; - struct pci_dev *bridge_dev; struct rb_root uabi_engines; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 76a8f24b3971..8468ca9885fd 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1140,9 +1140,10 @@ int i915_gem_init(struct drm_i915_private *dev_priv) if (ret) return ret; - for_each_gt(gt, dev_priv, i) + for_each_gt(gt, dev_priv, i) { intel_uc_fetch_firmwares(>->uc); - intel_wopcm_init(&dev_priv->wopcm); + intel_wopcm_init(>->wopcm); + } ret = i915_init_ggtt(dev_priv); if (ret) { diff --git a/drivers/gpu/drm/i915/intel_wopcm.c b/drivers/gpu/drm/i915/intel_wopcm.c deleted file mode 100644 index 322fb9eeb880..000000000000 --- a/drivers/gpu/drm/i915/intel_wopcm.c +++ /dev/null @@ -1,305 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Copyright © 2017-2019 Intel Corporation - */ - -#include "intel_wopcm.h" -#include "i915_drv.h" - -/** - * DOC: WOPCM Layout - * - * The layout of the WOPCM will be fixed after writing to GuC WOPCM size and - * offset registers whose values are calculated and determined by HuC/GuC - * firmware size and set of hardware requirements/restrictions as shown below: - * - * :: - * - * +=========> +====================+ <== WOPCM Top - * ^ | HW contexts RSVD | - * | +===> +====================+ <== GuC WOPCM Top - * | ^ | | - * | | | | - * | | | | - * | GuC | | - * | WOPCM | | - * | Size +--------------------+ - * WOPCM | | GuC FW RSVD | - * | | +--------------------+ - * | | | GuC Stack RSVD | - * | | +------------------- + - * | v | GuC WOPCM RSVD | - * | +===> +====================+ <== GuC WOPCM base - * | | WOPCM RSVD | - * | +------------------- + <== HuC Firmware Top - * v | HuC FW | - * +=========> +====================+ <== WOPCM Base - * - * GuC accessible WOPCM starts at GuC WOPCM base and ends at GuC WOPCM top. - * The top part of the WOPCM is reserved for hardware contexts (e.g. RC6 - * context). - */ - -/* Default WOPCM size is 2MB from Gen11, 1MB on previous platforms */ -#define GEN11_WOPCM_SIZE SZ_2M -#define GEN9_WOPCM_SIZE SZ_1M -#define MAX_WOPCM_SIZE SZ_8M -/* 16KB WOPCM (RSVD WOPCM) is reserved from HuC firmware top. */ -#define WOPCM_RESERVED_SIZE SZ_16K - -/* 16KB reserved at the beginning of GuC WOPCM. */ -#define GUC_WOPCM_RESERVED SZ_16K -/* 8KB from GUC_WOPCM_RESERVED is reserved for GuC stack. */ -#define GUC_WOPCM_STACK_RESERVED SZ_8K - -/* GuC WOPCM Offset value needs to be aligned to 16KB. */ -#define GUC_WOPCM_OFFSET_ALIGNMENT (1UL << GUC_WOPCM_OFFSET_SHIFT) - -/* 24KB at the end of WOPCM is reserved for RC6 CTX on BXT. */ -#define BXT_WOPCM_RC6_CTX_RESERVED (SZ_16K + SZ_8K) -/* 36KB WOPCM reserved at the end of WOPCM on ICL. */ -#define ICL_WOPCM_HW_CTX_RESERVED (SZ_32K + SZ_4K) - -/* 128KB from GUC_WOPCM_RESERVED is reserved for FW on Gen9. */ -#define GEN9_GUC_FW_RESERVED SZ_128K -#define GEN9_GUC_WOPCM_OFFSET (GUC_WOPCM_RESERVED + GEN9_GUC_FW_RESERVED) - -static inline struct drm_i915_private *wopcm_to_i915(struct intel_wopcm *wopcm) -{ - return container_of(wopcm, struct drm_i915_private, wopcm); -} - -/** - * intel_wopcm_init_early() - Early initialization of the WOPCM. - * @wopcm: pointer to intel_wopcm. - * - * Setup the size of WOPCM which will be used by later on WOPCM partitioning. - */ -void intel_wopcm_init_early(struct intel_wopcm *wopcm) -{ - struct drm_i915_private *i915 = wopcm_to_i915(wopcm); - - if (!HAS_GT_UC(i915)) - return; - - if (GRAPHICS_VER(i915) >= 11) - wopcm->size = GEN11_WOPCM_SIZE; - else - wopcm->size = GEN9_WOPCM_SIZE; - - drm_dbg(&i915->drm, "WOPCM: %uK\n", wopcm->size / 1024); -} - -static u32 context_reserved_size(struct drm_i915_private *i915) -{ - if (IS_GEN9_LP(i915)) - return BXT_WOPCM_RC6_CTX_RESERVED; - else if (GRAPHICS_VER(i915) >= 11) - return ICL_WOPCM_HW_CTX_RESERVED; - else - return 0; -} - -static bool gen9_check_dword_gap(struct drm_i915_private *i915, - u32 guc_wopcm_base, u32 guc_wopcm_size) -{ - u32 offset; - - /* - * GuC WOPCM size shall be at least a dword larger than the offset from - * WOPCM base (GuC WOPCM offset from WOPCM base + GEN9_GUC_WOPCM_OFFSET) - * due to hardware limitation on Gen9. - */ - offset = guc_wopcm_base + GEN9_GUC_WOPCM_OFFSET; - if (offset > guc_wopcm_size || - (guc_wopcm_size - offset) < sizeof(u32)) { - drm_err(&i915->drm, - "WOPCM: invalid GuC region size: %uK < %uK\n", - guc_wopcm_size / SZ_1K, - (u32)(offset + sizeof(u32)) / SZ_1K); - return false; - } - - return true; -} - -static bool gen9_check_huc_fw_fits(struct drm_i915_private *i915, - u32 guc_wopcm_size, u32 huc_fw_size) -{ - /* - * On Gen9, hardware requires the total available GuC WOPCM - * size to be larger than or equal to HuC firmware size. Otherwise, - * firmware uploading would fail. - */ - if (huc_fw_size > guc_wopcm_size - GUC_WOPCM_RESERVED) { - drm_err(&i915->drm, "WOPCM: no space for %s: %uK < %uK\n", - intel_uc_fw_type_repr(INTEL_UC_FW_TYPE_HUC), - (guc_wopcm_size - GUC_WOPCM_RESERVED) / SZ_1K, - huc_fw_size / 1024); - return false; - } - - return true; -} - -static bool check_hw_restrictions(struct drm_i915_private *i915, - u32 guc_wopcm_base, u32 guc_wopcm_size, - u32 huc_fw_size) -{ - if (GRAPHICS_VER(i915) == 9 && !gen9_check_dword_gap(i915, guc_wopcm_base, - guc_wopcm_size)) - return false; - - if (GRAPHICS_VER(i915) == 9 && - !gen9_check_huc_fw_fits(i915, guc_wopcm_size, huc_fw_size)) - return false; - - return true; -} - -static bool __check_layout(struct drm_i915_private *i915, u32 wopcm_size, - u32 guc_wopcm_base, u32 guc_wopcm_size, - u32 guc_fw_size, u32 huc_fw_size) -{ - const u32 ctx_rsvd = context_reserved_size(i915); - u32 size; - - size = wopcm_size - ctx_rsvd; - if (unlikely(range_overflows(guc_wopcm_base, guc_wopcm_size, size))) { - drm_err(&i915->drm, - "WOPCM: invalid GuC region layout: %uK + %uK > %uK\n", - guc_wopcm_base / SZ_1K, guc_wopcm_size / SZ_1K, - size / SZ_1K); - return false; - } - - size = guc_fw_size + GUC_WOPCM_RESERVED + GUC_WOPCM_STACK_RESERVED; - if (unlikely(guc_wopcm_size < size)) { - drm_err(&i915->drm, "WOPCM: no space for %s: %uK < %uK\n", - intel_uc_fw_type_repr(INTEL_UC_FW_TYPE_GUC), - guc_wopcm_size / SZ_1K, size / SZ_1K); - return false; - } - - size = huc_fw_size + WOPCM_RESERVED_SIZE; - if (unlikely(guc_wopcm_base < size)) { - drm_err(&i915->drm, "WOPCM: no space for %s: %uK < %uK\n", - intel_uc_fw_type_repr(INTEL_UC_FW_TYPE_HUC), - guc_wopcm_base / SZ_1K, size / SZ_1K); - return false; - } - - return check_hw_restrictions(i915, guc_wopcm_base, guc_wopcm_size, - huc_fw_size); -} - -static bool __wopcm_regs_locked(struct intel_uncore *uncore, - u32 *guc_wopcm_base, u32 *guc_wopcm_size) -{ - u32 reg_base = intel_uncore_read(uncore, DMA_GUC_WOPCM_OFFSET); - u32 reg_size = intel_uncore_read(uncore, GUC_WOPCM_SIZE); - - if (!(reg_size & GUC_WOPCM_SIZE_LOCKED) || - !(reg_base & GUC_WOPCM_OFFSET_VALID)) - return false; - - *guc_wopcm_base = reg_base & GUC_WOPCM_OFFSET_MASK; - *guc_wopcm_size = reg_size & GUC_WOPCM_SIZE_MASK; - return true; -} - -static bool __wopcm_regs_writable(struct intel_uncore *uncore) -{ - if (!HAS_GUC_DEPRIVILEGE(uncore->i915)) - return true; - - return intel_uncore_read(uncore, GUC_SHIM_CONTROL2) & GUC_IS_PRIVILEGED; -} - -/** - * intel_wopcm_init() - Initialize the WOPCM structure. - * @wopcm: pointer to intel_wopcm. - * - * This function will partition WOPCM space based on GuC and HuC firmware sizes - * and will allocate max remaining for use by GuC. This function will also - * enforce platform dependent hardware restrictions on GuC WOPCM offset and - * size. It will fail the WOPCM init if any of these checks fail, so that the - * following WOPCM registers setup and GuC firmware uploading would be aborted. - */ -void intel_wopcm_init(struct intel_wopcm *wopcm) -{ - struct drm_i915_private *i915 = wopcm_to_i915(wopcm); - struct intel_gt *gt = to_gt(i915); - u32 guc_fw_size = intel_uc_fw_get_upload_size(>->uc.guc.fw); - u32 huc_fw_size = intel_uc_fw_get_upload_size(>->uc.huc.fw); - u32 ctx_rsvd = context_reserved_size(i915); - u32 wopcm_size = wopcm->size; - u32 guc_wopcm_base; - u32 guc_wopcm_size; - - if (!guc_fw_size) - return; - - GEM_BUG_ON(!wopcm_size); - GEM_BUG_ON(wopcm->guc.base); - GEM_BUG_ON(wopcm->guc.size); - GEM_BUG_ON(guc_fw_size >= wopcm_size); - GEM_BUG_ON(huc_fw_size >= wopcm_size); - GEM_BUG_ON(ctx_rsvd + WOPCM_RESERVED_SIZE >= wopcm_size); - - if (i915_inject_probe_failure(i915)) - return; - - if (__wopcm_regs_locked(gt->uncore, &guc_wopcm_base, &guc_wopcm_size)) { - drm_dbg(&i915->drm, "GuC WOPCM is already locked [%uK, %uK)\n", - guc_wopcm_base / SZ_1K, guc_wopcm_size / SZ_1K); - /* - * Note that to keep things simple (i.e. avoid different - * defines per platform) our WOPCM math doesn't always use the - * actual WOPCM size, but a value that is less or equal to it. - * This is perfectly fine when i915 programs the registers, but - * on platforms with GuC deprivilege the registers are not - * writable from i915 and are instead pre-programmed by the - * bios/IFWI, so there might be a mismatch of sizes. - * Instead of handling the size difference, we trust that the - * programmed values make sense and disable the relevant check - * by using the maximum possible WOPCM size in the verification - * math. In the extremely unlikely case that the registers - * were pre-programmed with an invalid value, we will still - * gracefully fail later during the GuC/HuC dma. - */ - if (!__wopcm_regs_writable(gt->uncore)) - wopcm_size = MAX_WOPCM_SIZE; - - goto check; - } - - /* - * Aligned value of guc_wopcm_base will determine available WOPCM space - * for HuC firmware and mandatory reserved area. - */ - guc_wopcm_base = huc_fw_size + WOPCM_RESERVED_SIZE; - guc_wopcm_base = ALIGN(guc_wopcm_base, GUC_WOPCM_OFFSET_ALIGNMENT); - - /* - * Need to clamp guc_wopcm_base now to make sure the following math is - * correct. Formal check of whole WOPCM layout will be done below. - */ - guc_wopcm_base = min(guc_wopcm_base, wopcm_size - ctx_rsvd); - - /* Aligned remainings of usable WOPCM space can be assigned to GuC. */ - guc_wopcm_size = wopcm_size - ctx_rsvd - guc_wopcm_base; - guc_wopcm_size &= GUC_WOPCM_SIZE_MASK; - - drm_dbg(&i915->drm, "Calculated GuC WOPCM [%uK, %uK)\n", - guc_wopcm_base / SZ_1K, guc_wopcm_size / SZ_1K); - -check: - if (__check_layout(i915, wopcm_size, guc_wopcm_base, guc_wopcm_size, - guc_fw_size, huc_fw_size)) { - wopcm->guc.base = guc_wopcm_base; - wopcm->guc.size = guc_wopcm_size; - GEM_BUG_ON(!wopcm->guc.base); - GEM_BUG_ON(!wopcm->guc.size); - } -} diff --git a/drivers/gpu/drm/i915/intel_wopcm.h b/drivers/gpu/drm/i915/intel_wopcm.h deleted file mode 100644 index 17d6aa86008a..000000000000 --- a/drivers/gpu/drm/i915/intel_wopcm.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SPDX-License-Identifier: MIT - * - * Copyright © 2017-2018 Intel Corporation - */ - -#ifndef _INTEL_WOPCM_H_ -#define _INTEL_WOPCM_H_ - -#include - -/** - * struct intel_wopcm - Overall WOPCM info and WOPCM regions. - * @size: Size of overall WOPCM. - * @guc: GuC WOPCM Region info. - * @guc.base: GuC WOPCM base which is offset from WOPCM base. - * @guc.size: Size of the GuC WOPCM region. - */ -struct intel_wopcm { - u32 size; - struct { - u32 base; - u32 size; - } guc; -}; - -/** - * intel_wopcm_guc_base() - * @wopcm: intel_wopcm structure - * - * Returns the base of the WOPCM shadowed region. - * - * Returns: - * 0 if GuC is not present or not in use. - * Otherwise, the GuC WOPCM base. - */ -static inline u32 intel_wopcm_guc_base(struct intel_wopcm *wopcm) -{ - return wopcm->guc.base; -} - -/** - * intel_wopcm_guc_size() - * @wopcm: intel_wopcm structure - * - * Returns size of the WOPCM shadowed region. - * - * Returns: - * 0 if GuC is not present or not in use. - * Otherwise, the GuC WOPCM size. - */ -static inline u32 intel_wopcm_guc_size(struct intel_wopcm *wopcm) -{ - return wopcm->guc.size; -} - -void intel_wopcm_init_early(struct intel_wopcm *wopcm); -void intel_wopcm_init(struct intel_wopcm *wopcm); - -#endif -- cgit v1.2.3