/* * Load the GuC firmware blob into the MinuteIA. */ static int guc_fw_xfer(struct intel_uc_fw *guc_fw, struct i915_vma *vma) { struct intel_guc *guc = container_of(guc_fw, struct intel_guc, fw); struct drm_i915_private *dev_priv = guc_to_i915(guc); int ret; GEM_BUG_ON(guc_fw->type != INTEL_UC_FW_TYPE_GUC); intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL); guc_prepare_xfer(guc); /* * Note that GuC needs the CSS header plus uKernel code to be copied * by the DMA engine in one operation, whereas the RSA signature is * loaded via MMIO. */ ret = guc_xfer_rsa(guc, vma); if (ret) DRM_WARN("GuC firmware signature xfer error %d\n", ret); ret = guc_xfer_ucode(guc, vma); if (ret) DRM_WARN("GuC firmware code xfer error %d\n", ret); ret = guc_wait_ucode(guc); if (ret) DRM_ERROR("GuC firmware xfer error %d\n", ret); intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); return ret; }
/* * Load the GuC firmware blob into the MinuteIA. */ static int guc_fw_xfer(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); int ret; GEM_BUG_ON(guc_fw->type != INTEL_UC_FW_TYPE_GUC); intel_uncore_forcewake_get(&dev_priv->uncore, FORCEWAKE_ALL); guc_prepare_xfer(guc); /* * Note that GuC needs the CSS header plus uKernel code to be copied * by the DMA engine in one operation, whereas the RSA signature is * loaded via MMIO. */ guc_xfer_rsa(guc); ret = guc_xfer_ucode(guc); intel_uncore_forcewake_put(&dev_priv->uncore, FORCEWAKE_ALL); return ret; }
/* * This function implements the MMIO based host to GuC interface. */ int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len) { struct drm_i915_private *dev_priv = guc_to_i915(guc); u32 status; int i; int ret; GEM_BUG_ON(!len); GEM_BUG_ON(len > guc->send_regs.count); /* If CT is available, we expect to use MMIO only during init/fini */ GEM_BUG_ON(HAS_GUC_CT(dev_priv) && *action != INTEL_GUC_ACTION_REGISTER_COMMAND_TRANSPORT_BUFFER && *action != INTEL_GUC_ACTION_DEREGISTER_COMMAND_TRANSPORT_BUFFER); mutex_lock(&guc->send_mutex); intel_uncore_forcewake_get(dev_priv, guc->send_regs.fw_domains); for (i = 0; i < len; i++) I915_WRITE(guc_send_reg(guc, i), action[i]); POSTING_READ(guc_send_reg(guc, i - 1)); intel_guc_notify(guc); /* * No GuC command should ever take longer than 10ms. * Fast commands should still complete in 10us. */ ret = __intel_wait_for_register_fw(dev_priv, guc_send_reg(guc, 0), INTEL_GUC_RECV_MASK, INTEL_GUC_RECV_MASK, 10, 10, &status); if (status != INTEL_GUC_STATUS_SUCCESS) { /* * Either the GuC explicitly returned an error (which * we convert to -EIO here) or no response at all was * received within the timeout limit (-ETIMEDOUT) */ if (ret != -ETIMEDOUT) ret = -EIO; DRM_WARN("INTEL_GUC_SEND: Action 0x%X failed;" " ret=%d status=0x%08X response=0x%08X\n", action[0], ret, status, I915_READ(SOFT_SCRATCH(15))); } intel_uncore_forcewake_put(dev_priv, guc->send_regs.fw_domains); mutex_unlock(&guc->send_mutex); return ret; }
/* * Load the GuC firmware blob into the MinuteIA. */ static int guc_ucode_xfer(struct intel_uc_fw *guc_fw, struct i915_vma *vma) { struct intel_guc *guc = container_of(guc_fw, struct intel_guc, fw); struct drm_i915_private *dev_priv = guc_to_i915(guc); int ret; GEM_BUG_ON(guc_fw->type != INTEL_UC_FW_TYPE_GUC); intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL); /* Enable MIA caching. GuC clock gating is disabled. */ I915_WRITE(GUC_SHIM_CONTROL, GUC_SHIM_CONTROL_VALUE); /* WaDisableMinuteIaClockGating:bxt */ if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) { I915_WRITE(GUC_SHIM_CONTROL, (I915_READ(GUC_SHIM_CONTROL) & ~GUC_ENABLE_MIA_CLOCK_GATING)); } /* WaC6DisallowByGfxPause:bxt */ if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_B0)) I915_WRITE(GEN6_GFXPAUSE, 0x30FFF); if (IS_GEN9_LP(dev_priv)) I915_WRITE(GEN9LP_GT_PM_CONFIG, GT_DOORBELL_ENABLE); else I915_WRITE(GEN9_GT_PM_CONFIG, GT_DOORBELL_ENABLE); if (IS_GEN9(dev_priv)) { /* DOP Clock Gating Enable for GuC clocks */ I915_WRITE(GEN7_MISCCPCTL, (GEN8_DOP_CLOCK_GATE_GUC_ENABLE | I915_READ(GEN7_MISCCPCTL))); /* allows for 5us (in 10ns units) before GT can go to RC6 */ I915_WRITE(GUC_ARAT_C6DIS, 0x1FF); } ret = guc_ucode_xfer_dma(dev_priv, vma); intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); return ret; }
for_each_engine(engine, i915, id) { i915_reg_t mmio = _MMIO(engine->mmio_base + r->offset); u32 __iomem *reg = uncore->regs + engine->mmio_base + r->offset; enum forcewake_domains fw_domains; u32 val; if (!engine->default_state) continue; fw_domains = intel_uncore_forcewake_for_reg(uncore, mmio, FW_REG_READ); if (!fw_domains) continue; for_each_fw_domain_masked(domain, fw_domains, uncore, tmp) { if (!domain->wake_count) continue; pr_err("fw_domain %s still active, aborting test!\n", intel_uncore_forcewake_domain_to_str(domain->id)); err = -EINVAL; goto out_rpm; } intel_uncore_forcewake_get(uncore, fw_domains); val = readl(reg); intel_uncore_forcewake_put(uncore, fw_domains); /* Flush the forcewake release (delayed onto a timer) */ for_each_fw_domain_masked(domain, fw_domains, uncore, tmp) { smp_store_mb(domain->active, false); if (hrtimer_cancel(&domain->timer)) intel_uncore_fw_release_timer(&domain->timer); preempt_disable(); err = wait_ack_clear(domain, FORCEWAKE_KERNEL); preempt_enable(); if (err) { pr_err("Failed to clear fw_domain %s\n", intel_uncore_forcewake_domain_to_str(domain->id)); goto out_rpm; } }
/** * huc_fw_xfer() - DMA's the firmware * @huc_fw: the firmware descriptor * @vma: the firmware image (bound into the GGTT) * * Transfer the firmware image to RAM for execution by the microcontroller. * * Return: 0 on success, non-zero on failure */ static int huc_fw_xfer(struct intel_uc_fw *huc_fw, struct i915_vma *vma) { struct intel_huc *huc = container_of(huc_fw, struct intel_huc, fw); struct drm_i915_private *dev_priv = huc_to_i915(huc); unsigned long offset = 0; u32 size; int ret; GEM_BUG_ON(huc_fw->type != INTEL_UC_FW_TYPE_HUC); intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL); /* Set the source address for the uCode */ offset = intel_guc_ggtt_offset(&dev_priv->guc, vma) + huc_fw->header_offset; I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset)); I915_WRITE(DMA_ADDR_0_HIGH, upper_32_bits(offset) & 0xFFFF); /* Hardware doesn't look at destination address for HuC. Set it to 0, * but still program the correct address space. */ I915_WRITE(DMA_ADDR_1_LOW, 0); I915_WRITE(DMA_ADDR_1_HIGH, DMA_ADDRESS_SPACE_WOPCM); size = huc_fw->header_size + huc_fw->ucode_size; I915_WRITE(DMA_COPY_SIZE, size); /* Start the DMA */ I915_WRITE(DMA_CTRL, _MASKED_BIT_ENABLE(HUC_UKERNEL | START_DMA)); /* Wait for DMA to finish */ ret = intel_wait_for_register_fw(dev_priv, DMA_CTRL, START_DMA, 0, 100); DRM_DEBUG_DRIVER("HuC DMA transfer wait over with ret %d\n", ret); /* Disable the bits once DMA is over */ I915_WRITE(DMA_CTRL, _MASKED_BIT_DISABLE(HUC_UKERNEL)); intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); return ret; }
static void whitelist_apply(struct intel_engine_cs *engine, const struct whitelist *w) { struct drm_i915_private *dev_priv = engine->i915; const u32 base = engine->mmio_base; unsigned int i; if (!w) return; intel_uncore_forcewake_get(engine->i915, FORCEWAKE_ALL); for (i = 0; i < w->count; i++) I915_WRITE_FW(RING_FORCE_TO_NONPRIV(base, i), i915_mmio_reg_offset(w->reg[i])); /* And clear the rest just in case of garbage */ for (; i < RING_MAX_NONPRIV_SLOTS; i++) I915_WRITE_FW(RING_FORCE_TO_NONPRIV(base, i), w->nopid); intel_uncore_forcewake_put(engine->i915, FORCEWAKE_ALL); }