/** * intel_guc_fw_select() - selects GuC firmware for uploading * * @guc: intel_guc struct * * Return: zero when we know firmware, non-zero in other case */ int intel_guc_fw_select(struct intel_guc *guc) { struct drm_i915_private *dev_priv = guc_to_i915(guc); intel_uc_fw_init(&guc->fw, INTEL_UC_FW_TYPE_GUC); if (i915_modparams.guc_firmware_path) { guc->fw.path = i915_modparams.guc_firmware_path; guc->fw.major_ver_wanted = 0; guc->fw.minor_ver_wanted = 0; } else if (IS_SKYLAKE(dev_priv)) { guc->fw.path = I915_SKL_GUC_UCODE; guc->fw.major_ver_wanted = SKL_FW_MAJOR; guc->fw.minor_ver_wanted = SKL_FW_MINOR; } else if (IS_BROXTON(dev_priv)) { guc->fw.path = I915_BXT_GUC_UCODE; guc->fw.major_ver_wanted = BXT_FW_MAJOR; guc->fw.minor_ver_wanted = BXT_FW_MINOR; } else if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) { guc->fw.path = I915_KBL_GUC_UCODE; guc->fw.major_ver_wanted = KBL_FW_MAJOR; guc->fw.minor_ver_wanted = KBL_FW_MINOR; } else if (IS_GEMINILAKE(dev_priv)) { guc->fw.path = I915_GLK_GUC_UCODE; guc->fw.major_ver_wanted = GLK_FW_MAJOR; guc->fw.minor_ver_wanted = GLK_FW_MINOR; } else { DRM_ERROR("No GuC firmware known for platform with GuC!\n"); return -ENOENT; } return 0; }
static void huc_fw_select(struct intel_uc_fw *huc_fw) { struct intel_huc *huc = container_of(huc_fw, struct intel_huc, fw); struct drm_i915_private *dev_priv = huc_to_i915(huc); GEM_BUG_ON(huc_fw->type != INTEL_UC_FW_TYPE_HUC); if (!HAS_HUC(dev_priv)) return; if (i915_modparams.huc_firmware_path) { huc_fw->path = i915_modparams.huc_firmware_path; huc_fw->major_ver_wanted = 0; huc_fw->minor_ver_wanted = 0; } else if (IS_SKYLAKE(dev_priv)) { huc_fw->path = I915_SKL_HUC_UCODE; huc_fw->major_ver_wanted = SKL_HUC_FW_MAJOR; huc_fw->minor_ver_wanted = SKL_HUC_FW_MINOR; } else if (IS_BROXTON(dev_priv)) { huc_fw->path = I915_BXT_HUC_UCODE; huc_fw->major_ver_wanted = BXT_HUC_FW_MAJOR; huc_fw->minor_ver_wanted = BXT_HUC_FW_MINOR; } else if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) { huc_fw->path = I915_KBL_HUC_UCODE; huc_fw->major_ver_wanted = KBL_HUC_FW_MAJOR; huc_fw->minor_ver_wanted = KBL_HUC_FW_MINOR; } }
void intel_gt_workarounds_apply(struct drm_i915_private *dev_priv) { if (INTEL_GEN(dev_priv) < 8) return; else if (IS_BROADWELL(dev_priv)) bdw_gt_workarounds_apply(dev_priv); else if (IS_CHERRYVIEW(dev_priv)) chv_gt_workarounds_apply(dev_priv); else if (IS_SKYLAKE(dev_priv)) skl_gt_workarounds_apply(dev_priv); else if (IS_BROXTON(dev_priv)) bxt_gt_workarounds_apply(dev_priv); else if (IS_KABYLAKE(dev_priv)) kbl_gt_workarounds_apply(dev_priv); else if (IS_GEMINILAKE(dev_priv)) glk_gt_workarounds_apply(dev_priv); else if (IS_COFFEELAKE(dev_priv)) cfl_gt_workarounds_apply(dev_priv); else if (IS_CANNONLAKE(dev_priv)) cnl_gt_workarounds_apply(dev_priv); else if (IS_ICELAKE(dev_priv)) icl_gt_workarounds_apply(dev_priv); else MISSING_CASE(INTEL_GEN(dev_priv)); }
static struct whitelist *whitelist_build(struct intel_engine_cs *engine, struct whitelist *w) { struct drm_i915_private *i915 = engine->i915; GEM_BUG_ON(engine->id != RCS); w->count = 0; w->nopid = i915_mmio_reg_offset(RING_NOPID(engine->mmio_base)); if (INTEL_GEN(i915) < 8) return NULL; else if (IS_BROADWELL(i915)) bdw_whitelist_build(w); else if (IS_CHERRYVIEW(i915)) chv_whitelist_build(w); else if (IS_SKYLAKE(i915)) skl_whitelist_build(w); else if (IS_BROXTON(i915)) bxt_whitelist_build(w); else if (IS_KABYLAKE(i915)) kbl_whitelist_build(w); else if (IS_GEMINILAKE(i915)) glk_whitelist_build(w); else if (IS_COFFEELAKE(i915)) cfl_whitelist_build(w); else if (IS_CANNONLAKE(i915)) cnl_whitelist_build(w); else if (IS_ICELAKE(i915)) icl_whitelist_build(w); else MISSING_CASE(INTEL_GEN(i915)); return w; }
int intel_ctx_workarounds_init(struct drm_i915_private *dev_priv) { int err = 0; dev_priv->workarounds.count = 0; if (INTEL_GEN(dev_priv) < 8) err = 0; else if (IS_BROADWELL(dev_priv)) err = bdw_ctx_workarounds_init(dev_priv); else if (IS_CHERRYVIEW(dev_priv)) err = chv_ctx_workarounds_init(dev_priv); else if (IS_SKYLAKE(dev_priv)) err = skl_ctx_workarounds_init(dev_priv); else if (IS_BROXTON(dev_priv)) err = bxt_ctx_workarounds_init(dev_priv); else if (IS_KABYLAKE(dev_priv)) err = kbl_ctx_workarounds_init(dev_priv); else if (IS_GEMINILAKE(dev_priv)) err = glk_ctx_workarounds_init(dev_priv); else if (IS_COFFEELAKE(dev_priv)) err = cfl_ctx_workarounds_init(dev_priv); else if (IS_CANNONLAKE(dev_priv)) err = cnl_ctx_workarounds_init(dev_priv); else if (IS_ICELAKE(dev_priv)) err = icl_ctx_workarounds_init(dev_priv); else MISSING_CASE(INTEL_GEN(dev_priv)); if (err) return err; DRM_DEBUG_DRIVER("Number of context specific w/a: %d\n", dev_priv->workarounds.count); return 0; }
static void guc_fw_select(struct intel_uc_fw *guc_fw) { struct intel_guc *guc = container_of(guc_fw, struct intel_guc, fw); struct drm_i915_private *dev_priv = guc_to_i915(guc); GEM_BUG_ON(guc_fw->type != INTEL_UC_FW_TYPE_GUC); if (!HAS_GUC(dev_priv)) return; if (i915_modparams.guc_firmware_path) { guc_fw->path = i915_modparams.guc_firmware_path; guc_fw->major_ver_wanted = 0; guc_fw->minor_ver_wanted = 0; } else if (IS_SKYLAKE(dev_priv)) { guc_fw->path = I915_SKL_GUC_UCODE; guc_fw->major_ver_wanted = SKL_FW_MAJOR; guc_fw->minor_ver_wanted = SKL_FW_MINOR; } else if (IS_BROXTON(dev_priv)) { guc_fw->path = I915_BXT_GUC_UCODE; guc_fw->major_ver_wanted = BXT_FW_MAJOR; guc_fw->minor_ver_wanted = BXT_FW_MINOR; } else if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) { guc_fw->path = I915_KBL_GUC_UCODE; guc_fw->major_ver_wanted = KBL_FW_MAJOR; guc_fw->minor_ver_wanted = KBL_FW_MINOR; } else { DRM_WARN("%s: No firmware known for this platform!\n", intel_uc_fw_type_repr(guc_fw->type)); } }
static void gen9_gt_workarounds_apply(struct drm_i915_private *dev_priv) { /* WaContextSwitchWithConcurrentTLBInvalidate:skl,bxt,kbl,glk,cfl */ I915_WRITE(GEN9_CSFE_CHICKEN1_RCS, _MASKED_BIT_ENABLE(GEN9_PREEMPT_GPGPU_SYNC_SWITCH_DISABLE)); /* WaEnableLbsSlaRetryTimerDecrement:skl,bxt,kbl,glk,cfl */ I915_WRITE(BDW_SCRATCH1, I915_READ(BDW_SCRATCH1) | GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE); /* WaDisableKillLogic:bxt,skl,kbl */ if (!IS_COFFEELAKE(dev_priv)) I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | ECOCHK_DIS_TLB); if (HAS_LLC(dev_priv)) { /* WaCompressedResourceSamplerPbeMediaNewHashMode:skl,kbl * * Must match Display Engine. See * WaCompressedResourceDisplayNewHashMode. */ I915_WRITE(MMCD_MISC_CTRL, I915_READ(MMCD_MISC_CTRL) | MMCD_PCLA | MMCD_HOTSPOT_EN); } /* WaDisableHDCInvalidation:skl,bxt,kbl,cfl */ I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | BDW_DISABLE_HDC_INVALIDATION); /* WaProgramL3SqcReg1DefaultForPerf:bxt,glk */ if (IS_GEN9_LP(dev_priv)) { u32 val = I915_READ(GEN8_L3SQCREG1); val &= ~L3_PRIO_CREDITS_MASK; val |= L3_GENERAL_PRIO_CREDITS(62) | L3_HIGH_PRIO_CREDITS(2); I915_WRITE(GEN8_L3SQCREG1, val); } /* WaOCLCoherentLineFlush:skl,bxt,kbl,cfl */ I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) | GEN8_LQSC_FLUSH_COHERENT_LINES); /* WaEnablePreemptionGranularityControlByUMD:skl,bxt,kbl,cfl,[cnl] */ I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1, _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL)); }
/** * intel_csr_ucode_init() - initialize the firmware loading. * @dev_priv: i915 drm device. * * This function is called at the time of loading the display driver to read * firmware from a .bin file and copied into a internal memory. */ void intel_csr_ucode_init(struct drm_i915_private *dev_priv) { struct intel_csr *csr = &dev_priv->csr; INIT_WORK(&dev_priv->csr.work, csr_load_work_fn); if (!HAS_CSR(dev_priv)) return; if (i915_modparams.dmc_firmware_path) csr->fw_path = i915_modparams.dmc_firmware_path; else if (IS_ICELAKE(dev_priv)) csr->fw_path = I915_CSR_ICL; else if (IS_CANNONLAKE(dev_priv)) csr->fw_path = I915_CSR_CNL; else if (IS_GEMINILAKE(dev_priv)) csr->fw_path = I915_CSR_GLK; else if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) csr->fw_path = I915_CSR_KBL; else if (IS_SKYLAKE(dev_priv)) csr->fw_path = I915_CSR_SKL; else if (IS_BROXTON(dev_priv)) csr->fw_path = I915_CSR_BXT; /* * Obtain a runtime pm reference, until CSR is loaded, * to avoid entering runtime-suspend. */ intel_display_power_get(dev_priv, POWER_DOMAIN_INIT); if (csr->fw_path == NULL) { DRM_DEBUG_KMS("No known CSR firmware for platform, disabling runtime PM\n"); WARN_ON(!IS_ALPHA_SUPPORT(INTEL_INFO(dev_priv))); return; } DRM_DEBUG_KMS("Loading %s\n", csr->fw_path); schedule_work(&dev_priv->csr.work); }
static void guc_fw_select(struct intel_uc_fw *guc_fw) { struct intel_guc *guc = container_of(guc_fw, struct intel_guc, fw); struct drm_i915_private *i915 = guc_to_i915(guc); GEM_BUG_ON(guc_fw->type != INTEL_UC_FW_TYPE_GUC); if (!HAS_GUC(i915)) return; if (i915_modparams.guc_firmware_path) { guc_fw->path = i915_modparams.guc_firmware_path; guc_fw->major_ver_wanted = 0; guc_fw->minor_ver_wanted = 0; } else if (IS_ICELAKE(i915)) { guc_fw->path = ICL_GUC_FIRMWARE_PATH; guc_fw->major_ver_wanted = ICL_GUC_FW_MAJOR; guc_fw->minor_ver_wanted = ICL_GUC_FW_MINOR; } else if (IS_GEMINILAKE(i915)) { guc_fw->path = GLK_GUC_FIRMWARE_PATH; guc_fw->major_ver_wanted = GLK_GUC_FW_MAJOR; guc_fw->minor_ver_wanted = GLK_GUC_FW_MINOR; } else if (IS_KABYLAKE(i915) || IS_COFFEELAKE(i915)) { guc_fw->path = KBL_GUC_FIRMWARE_PATH; guc_fw->major_ver_wanted = KBL_GUC_FW_MAJOR; guc_fw->minor_ver_wanted = KBL_GUC_FW_MINOR; } else if (IS_BROXTON(i915)) { guc_fw->path = BXT_GUC_FIRMWARE_PATH; guc_fw->major_ver_wanted = BXT_GUC_FW_MAJOR; guc_fw->minor_ver_wanted = BXT_GUC_FW_MINOR; } else if (IS_SKYLAKE(i915)) { guc_fw->path = SKL_GUC_FIRMWARE_PATH; guc_fw->major_ver_wanted = SKL_GUC_FW_MAJOR; guc_fw->minor_ver_wanted = SKL_GUC_FW_MINOR; } }
static int gen9_ctx_workarounds_init(struct drm_i915_private *dev_priv) { if (HAS_LLC(dev_priv)) { /* WaCompressedResourceSamplerPbeMediaNewHashMode:skl,kbl * * Must match Display Engine. See * WaCompressedResourceDisplayNewHashMode. */ WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, GEN9_PBE_COMPRESSED_HASH_SELECTION); WA_SET_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN7, GEN9_SAMPLER_HASH_COMPRESSED_READ_ADDR); } /* WaClearFlowControlGpgpuContextSave:skl,bxt,kbl,glk,cfl */ /* WaDisablePartialInstShootdown:skl,bxt,kbl,glk,cfl */ WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, FLOW_CONTROL_ENABLE | PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE); /* Syncing dependencies between camera and graphics:skl,bxt,kbl */ if (!IS_COFFEELAKE(dev_priv)) WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3, GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC); /* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt,kbl,glk,cfl */ /* WaEnableSamplerGPGPUPreemptionSupport:skl,bxt,kbl,cfl */ WA_SET_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN7, GEN9_ENABLE_YV12_BUGFIX | GEN9_ENABLE_GPGPU_PREEMPTION); /* Wa4x4STCOptimizationDisable:skl,bxt,kbl,glk,cfl */ /* WaDisablePartialResolveInVc:skl,bxt,kbl,cfl */ WA_SET_BIT_MASKED(CACHE_MODE_1, GEN8_4x4_STC_OPTIMIZATION_DISABLE | GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE); /* WaCcsTlbPrefetchDisable:skl,bxt,kbl,glk,cfl */ WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5, GEN9_CCS_TLB_PREFETCH_ENABLE); /* WaForceContextSaveRestoreNonCoherent:skl,bxt,kbl,cfl */ WA_SET_BIT_MASKED(HDC_CHICKEN0, HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT | HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE); /* WaForceEnableNonCoherent and WaDisableHDCInvalidation are * both tied to WaForceContextSaveRestoreNonCoherent * in some hsds for skl. We keep the tie for all gen9. The * documentation is a bit hazy and so we want to get common behaviour, * even though there is no clear evidence we would need both on kbl/bxt. * This area has been source of system hangs so we play it safe * and mimic the skl regardless of what bspec says. * * Use Force Non-Coherent whenever executing a 3D context. This * is a workaround for a possible hang in the unlikely event * a TLB invalidation occurs during a PSD flush. */ /* WaForceEnableNonCoherent:skl,bxt,kbl,cfl */ WA_SET_BIT_MASKED(HDC_CHICKEN0, HDC_FORCE_NON_COHERENT); /* WaDisableSamplerPowerBypassForSOPingPong:skl,bxt,kbl,cfl */ if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3, GEN8_SAMPLER_POWER_BYPASS_DIS); /* WaDisableSTUnitPowerOptimization:skl,bxt,kbl,glk,cfl */ WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN2, GEN8_ST_PO_DISABLE); /* * Supporting preemption with fine-granularity requires changes in the * batch buffer programming. Since we can't break old userspace, we * need to set our default preemption level to safe value. Userspace is * still able to use more fine-grained preemption levels, since in * WaEnablePreemptionGranularityControlByUMD we're whitelisting the * per-ctx register. As such, WaDisable{3D,GPGPU}MidCmdPreemption are * not real HW workarounds, but merely a way to start using preemption * while maintaining old contract with userspace. */ /* WaDisable3DMidCmdPreemption:skl,bxt,glk,cfl,[cnl] */ WA_CLR_BIT_MASKED(GEN8_CS_CHICKEN1, GEN9_PREEMPT_3D_OBJECT_LEVEL); /* WaDisableGPGPUMidCmdPreemption:skl,bxt,blk,cfl,[cnl] */ WA_SET_FIELD_MASKED(GEN8_CS_CHICKEN1, GEN9_PREEMPT_GPGPU_LEVEL_MASK, GEN9_PREEMPT_GPGPU_COMMAND_LEVEL); /* WaClearHIZ_WM_CHICKEN3:bxt,glk */ if (IS_GEN9_LP(dev_priv)) WA_SET_BIT_MASKED(GEN9_WM_CHICKEN3, GEN9_FACTOR_IN_CLR_VAL_HIZ); return 0; }
/** * intel_csr_ucode_init() - initialize the firmware loading. * @dev_priv: i915 drm device. * * This function is called at the time of loading the display driver to read * firmware from a .bin file and copied into a internal memory. */ void intel_csr_ucode_init(struct drm_i915_private *dev_priv) { struct intel_csr *csr = &dev_priv->csr; INIT_WORK(&dev_priv->csr.work, csr_load_work_fn); if (!HAS_CSR(dev_priv)) return; /* * Obtain a runtime pm reference, until CSR is loaded, to avoid entering * runtime-suspend. * * On error, we return with the rpm wakeref held to prevent runtime * suspend as runtime suspend *requires* a working CSR for whatever * reason. */ intel_csr_runtime_pm_get(dev_priv); if (INTEL_GEN(dev_priv) >= 12) { /* Allow to load fw via parameter using the last known size */ csr->max_fw_size = GEN12_CSR_MAX_FW_SIZE; } else if (IS_GEN(dev_priv, 11)) { csr->fw_path = ICL_CSR_PATH; csr->required_version = ICL_CSR_VERSION_REQUIRED; csr->max_fw_size = ICL_CSR_MAX_FW_SIZE; } else if (IS_CANNONLAKE(dev_priv)) { csr->fw_path = CNL_CSR_PATH; csr->required_version = CNL_CSR_VERSION_REQUIRED; csr->max_fw_size = CNL_CSR_MAX_FW_SIZE; } else if (IS_GEMINILAKE(dev_priv)) { csr->fw_path = GLK_CSR_PATH; csr->required_version = GLK_CSR_VERSION_REQUIRED; csr->max_fw_size = GLK_CSR_MAX_FW_SIZE; } else if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) { csr->fw_path = KBL_CSR_PATH; csr->required_version = KBL_CSR_VERSION_REQUIRED; csr->max_fw_size = KBL_CSR_MAX_FW_SIZE; } else if (IS_SKYLAKE(dev_priv)) { csr->fw_path = SKL_CSR_PATH; csr->required_version = SKL_CSR_VERSION_REQUIRED; csr->max_fw_size = SKL_CSR_MAX_FW_SIZE; } else if (IS_BROXTON(dev_priv)) { csr->fw_path = BXT_CSR_PATH; csr->required_version = BXT_CSR_VERSION_REQUIRED; csr->max_fw_size = BXT_CSR_MAX_FW_SIZE; } if (i915_modparams.dmc_firmware_path) { if (strlen(i915_modparams.dmc_firmware_path) == 0) { csr->fw_path = NULL; DRM_INFO("Disabling CSR firmware and runtime PM\n"); return; } csr->fw_path = i915_modparams.dmc_firmware_path; /* Bypass version check for firmware override. */ csr->required_version = 0; } if (csr->fw_path == NULL) { DRM_DEBUG_KMS("No known CSR firmware for platform, disabling runtime PM\n"); WARN_ON(!IS_ALPHA_SUPPORT(INTEL_INFO(dev_priv))); return; } DRM_DEBUG_KMS("Loading %s\n", csr->fw_path); schedule_work(&dev_priv->csr.work); }
static uint32_t *parse_csr_fw(struct drm_i915_private *dev_priv, const struct firmware *fw) { struct intel_css_header *css_header; struct intel_package_header *package_header; struct intel_dmc_header *dmc_header; struct intel_csr *csr = &dev_priv->csr; const struct stepping_info *si = intel_get_stepping_info(dev_priv); uint32_t dmc_offset = CSR_DEFAULT_FW_OFFSET, readcount = 0, nbytes; uint32_t max_fw_size = 0; uint32_t i; uint32_t *dmc_payload; uint32_t required_version; if (!fw) return NULL; /* Extract CSS Header information*/ css_header = (struct intel_css_header *)fw->data; if (sizeof(struct intel_css_header) != (css_header->header_len * 4)) { DRM_ERROR("DMC firmware has wrong CSS header length " "(%u bytes)\n", (css_header->header_len * 4)); return NULL; } csr->version = css_header->version; if (csr->fw_path == i915_modparams.dmc_firmware_path) { /* Bypass version check for firmware override. */ required_version = csr->version; } else if (IS_ICELAKE(dev_priv)) { required_version = ICL_CSR_VERSION_REQUIRED; } else if (IS_CANNONLAKE(dev_priv)) { required_version = CNL_CSR_VERSION_REQUIRED; } else if (IS_GEMINILAKE(dev_priv)) { required_version = GLK_CSR_VERSION_REQUIRED; } else if (IS_KABYLAKE(dev_priv) || IS_COFFEELAKE(dev_priv)) { required_version = KBL_CSR_VERSION_REQUIRED; } else if (IS_SKYLAKE(dev_priv)) { required_version = SKL_CSR_VERSION_REQUIRED; } else if (IS_BROXTON(dev_priv)) { required_version = BXT_CSR_VERSION_REQUIRED; } else { MISSING_CASE(INTEL_REVID(dev_priv)); required_version = 0; } if (csr->version != required_version) { DRM_INFO("Refusing to load DMC firmware v%u.%u," " please use v%u.%u\n", CSR_VERSION_MAJOR(csr->version), CSR_VERSION_MINOR(csr->version), CSR_VERSION_MAJOR(required_version), CSR_VERSION_MINOR(required_version)); return NULL; } readcount += sizeof(struct intel_css_header); /* Extract Package Header information*/ package_header = (struct intel_package_header *) &fw->data[readcount]; if (sizeof(struct intel_package_header) != (package_header->header_len * 4)) { DRM_ERROR("DMC firmware has wrong package header length " "(%u bytes)\n", (package_header->header_len * 4)); return NULL; } readcount += sizeof(struct intel_package_header); /* Search for dmc_offset to find firware binary. */ for (i = 0; i < package_header->num_entries; i++) { if (package_header->fw_info[i].substepping == '*' && si->stepping == package_header->fw_info[i].stepping) { dmc_offset = package_header->fw_info[i].offset; break; } else if (si->stepping == package_header->fw_info[i].stepping && si->substepping == package_header->fw_info[i].substepping) { dmc_offset = package_header->fw_info[i].offset; break; } else if (package_header->fw_info[i].stepping == '*' && package_header->fw_info[i].substepping == '*') dmc_offset = package_header->fw_info[i].offset; } if (dmc_offset == CSR_DEFAULT_FW_OFFSET) { DRM_ERROR("DMC firmware not supported for %c stepping\n", si->stepping); return NULL; } /* Convert dmc_offset into number of bytes. By default it is in dwords*/ dmc_offset *= 4; readcount += dmc_offset; /* Extract dmc_header information. */ dmc_header = (struct intel_dmc_header *)&fw->data[readcount]; if (sizeof(struct intel_dmc_header) != (dmc_header->header_len)) { DRM_ERROR("DMC firmware has wrong dmc header length " "(%u bytes)\n", (dmc_header->header_len)); return NULL; } readcount += sizeof(struct intel_dmc_header); /* Cache the dmc header info. */ if (dmc_header->mmio_count > ARRAY_SIZE(csr->mmioaddr)) { DRM_ERROR("DMC firmware has wrong mmio count %u\n", dmc_header->mmio_count); return NULL; } csr->mmio_count = dmc_header->mmio_count; for (i = 0; i < dmc_header->mmio_count; i++) { if (dmc_header->mmioaddr[i] < CSR_MMIO_START_RANGE || dmc_header->mmioaddr[i] > CSR_MMIO_END_RANGE) { DRM_ERROR("DMC firmware has wrong mmio address 0x%x\n", dmc_header->mmioaddr[i]); return NULL; } csr->mmioaddr[i] = _MMIO(dmc_header->mmioaddr[i]); csr->mmiodata[i] = dmc_header->mmiodata[i]; } /* fw_size is in dwords, so multiplied by 4 to convert into bytes. */ nbytes = dmc_header->fw_size * 4; if (INTEL_GEN(dev_priv) >= 11) max_fw_size = ICL_CSR_MAX_FW_SIZE; else if (IS_CANNONLAKE(dev_priv) || IS_GEMINILAKE(dev_priv)) max_fw_size = GLK_CSR_MAX_FW_SIZE; else if (IS_GEN9(dev_priv)) max_fw_size = BXT_CSR_MAX_FW_SIZE; else MISSING_CASE(INTEL_REVID(dev_priv)); if (nbytes > max_fw_size) { DRM_ERROR("DMC FW too big (%u bytes)\n", nbytes); return NULL; } csr->dmc_fw_size = dmc_header->fw_size; dmc_payload = kmalloc(nbytes, GFP_KERNEL); if (!dmc_payload) { DRM_ERROR("Memory allocation failed for dmc payload\n"); return NULL; } return memcpy(dmc_payload, &fw->data[readcount], nbytes); }