/* * Transfer the firmware image to RAM for execution by the microcontroller. * * Architecturally, the DMA engine is bidirectional, and can potentially even * transfer between GTT locations. This functionality is left out of the API * for now as there is no need for it. * * 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. */ static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv, struct i915_vma *vma) { struct intel_uc_fw *guc_fw = &dev_priv->guc.fw; unsigned long offset; struct sg_table *sg = vma->pages; u32 status, rsa[UOS_RSA_SCRATCH_MAX_COUNT]; int i, ret = 0; /* where RSA signature starts */ offset = guc_fw->rsa_offset; /* Copy RSA signature from the fw image to HW for verification */ sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, sizeof(rsa), offset); for (i = 0; i < UOS_RSA_SCRATCH_MAX_COUNT; i++) I915_WRITE(UOS_RSA_SCRATCH(i), rsa[i]); /* The header plus uCode will be copied to WOPCM via DMA, excluding any * other components */ I915_WRITE(DMA_COPY_SIZE, guc_fw->header_size + guc_fw->ucode_size); /* Set the source address for the new blob */ offset = guc_ggtt_offset(vma) + guc_fw->header_offset; I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset)); I915_WRITE(DMA_ADDR_0_HIGH, upper_32_bits(offset) & 0xFFFF); /* * Set the DMA destination. Current uCode expects the code to be * loaded at 8k; locations below this are used for the stack. */ I915_WRITE(DMA_ADDR_1_LOW, 0x2000); I915_WRITE(DMA_ADDR_1_HIGH, DMA_ADDRESS_SPACE_WOPCM); /* Finally start the DMA */ I915_WRITE(DMA_CTRL, _MASKED_BIT_ENABLE(UOS_MOVE | START_DMA)); /* * Wait for the DMA to complete & the GuC to start up. * NB: Docs recommend not using the interrupt for completion. * Measurements indicate this should take no more than 20ms, so a * timeout here indicates that the GuC has failed and is unusable. * (Higher levels of the driver will attempt to fall back to * execlist mode if this happens.) */ ret = wait_for(guc_ucode_response(dev_priv, &status), 100); DRM_DEBUG_DRIVER("DMA status 0x%x, GuC status 0x%x\n", I915_READ(DMA_CTRL), status); if ((status & GS_BOOTROM_MASK) == GS_BOOTROM_RSA_FAILED) { DRM_ERROR("GuC firmware signature verification failed\n"); ret = -ENOEXEC; } DRM_DEBUG_DRIVER("returning %d\n", ret); return ret; }
/* Copy RSA signature from the fw image to HW for verification */ static void guc_xfer_rsa(struct intel_guc *guc, struct i915_vma *vma) { struct drm_i915_private *dev_priv = guc_to_i915(guc); u32 rsa[UOS_RSA_SCRATCH_COUNT]; int i; sg_pcopy_to_buffer(vma->pages->sgl, vma->pages->nents, rsa, sizeof(rsa), guc->fw.rsa_offset); for (i = 0; i < UOS_RSA_SCRATCH_COUNT; i++) I915_WRITE(UOS_RSA_SCRATCH(i), rsa[i]); }
/* Copy RSA signature from the fw image to HW for verification */ static void guc_xfer_rsa(struct intel_guc *guc) { struct drm_i915_private *dev_priv = guc_to_i915(guc); struct intel_uc_fw *fw = &guc->fw; struct sg_table *pages = fw->obj->mm.pages; u32 rsa[UOS_RSA_SCRATCH_COUNT]; int i; sg_pcopy_to_buffer(pages->sgl, pages->nents, rsa, sizeof(rsa), fw->rsa_offset); for (i = 0; i < UOS_RSA_SCRATCH_COUNT; i++) I915_WRITE(UOS_RSA_SCRATCH(i), rsa[i]); }
static void mv_cesa_ahash_req_cleanup(struct crypto_async_request *req) { struct ahash_request *ahashreq = ahash_request_cast(req); struct mv_cesa_ahash_req *creq = ahash_request_ctx(ahashreq); if (creq->last_req) mv_cesa_ahash_last_cleanup(ahashreq); mv_cesa_ahash_cleanup(ahashreq); if (creq->cache_ptr) sg_pcopy_to_buffer(ahashreq->src, creq->src_nents, creq->cache, creq->cache_ptr, ahashreq->nbytes - creq->cache_ptr); }
/* Copy RSA signature from the fw image to HW for verification */ static int guc_xfer_rsa(struct intel_guc *guc, struct i915_vma *vma) { struct drm_i915_private *dev_priv = guc_to_i915(guc); struct intel_uc_fw *guc_fw = &guc->fw; struct sg_table *sg = vma->pages; u32 rsa[UOS_RSA_SCRATCH_COUNT]; int i; if (sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, sizeof(rsa), guc_fw->rsa_offset) != sizeof(rsa)) return -EINVAL; for (i = 0; i < UOS_RSA_SCRATCH_COUNT; i++) I915_WRITE(UOS_RSA_SCRATCH(i), rsa[i]); return 0; }
static int mv_cesa_ahash_cache_req(struct ahash_request *req, bool *cached) { struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); if (creq->cache_ptr + req->nbytes < 64 && !creq->last_req) { *cached = true; if (!req->nbytes) return 0; sg_pcopy_to_buffer(req->src, creq->src_nents, creq->cache + creq->cache_ptr, req->nbytes, 0); creq->cache_ptr += req->nbytes; } return 0; }
static int rk_load_data(struct rk_crypto_info *dev, struct scatterlist *sg_src, struct scatterlist *sg_dst) { unsigned int count; dev->aligned = dev->aligned ? check_alignment(sg_src, sg_dst, dev->align_size) : dev->aligned; if (dev->aligned) { count = min(dev->left_bytes, sg_src->length); dev->left_bytes -= count; if (!dma_map_sg(dev->dev, sg_src, 1, DMA_TO_DEVICE)) { dev_err(dev->dev, "[%s:%d] dma_map_sg(src) error\n", __func__, __LINE__); return -EINVAL; } dev->addr_in = sg_dma_address(sg_src); if (sg_dst) { if (!dma_map_sg(dev->dev, sg_dst, 1, DMA_FROM_DEVICE)) { dev_err(dev->dev, "[%s:%d] dma_map_sg(dst) error\n", __func__, __LINE__); dma_unmap_sg(dev->dev, sg_src, 1, DMA_TO_DEVICE); return -EINVAL; } dev->addr_out = sg_dma_address(sg_dst); } } else { count = (dev->left_bytes > PAGE_SIZE) ? PAGE_SIZE : dev->left_bytes; if (!sg_pcopy_to_buffer(dev->first, dev->nents, dev->addr_vir, count, dev->total - dev->left_bytes)) { dev_err(dev->dev, "[%s:%d] pcopy err\n", __func__, __LINE__); return -EINVAL; } dev->left_bytes -= count; sg_init_one(&dev->sg_tmp, dev->addr_vir, count); if (!dma_map_sg(dev->dev, &dev->sg_tmp, 1, DMA_TO_DEVICE)) { dev_err(dev->dev, "[%s:%d] dma_map_sg(sg_tmp) error\n", __func__, __LINE__); return -ENOMEM; } dev->addr_in = sg_dma_address(&dev->sg_tmp); if (sg_dst) { if (!dma_map_sg(dev->dev, &dev->sg_tmp, 1, DMA_FROM_DEVICE)) { dev_err(dev->dev, "[%s:%d] dma_map_sg(sg_tmp) error\n", __func__, __LINE__); dma_unmap_sg(dev->dev, &dev->sg_tmp, 1, DMA_TO_DEVICE); return -ENOMEM; } dev->addr_out = sg_dma_address(&dev->sg_tmp); } } dev->count = count; return 0; }
static void mv_cesa_ahash_std_step(struct ahash_request *req) { struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); struct mv_cesa_ahash_std_req *sreq = &creq->req.std; struct mv_cesa_engine *engine = creq->base.engine; struct mv_cesa_op_ctx *op; unsigned int new_cache_ptr = 0; u32 frag_mode; size_t len; unsigned int digsize; int i; mv_cesa_adjust_op(engine, &creq->op_tmpl); memcpy_toio(engine->sram, &creq->op_tmpl, sizeof(creq->op_tmpl)); digsize = crypto_ahash_digestsize(crypto_ahash_reqtfm(req)); for (i = 0; i < digsize / 4; i++) writel_relaxed(creq->state[i], engine->regs + CESA_IVDIG(i)); mv_cesa_adjust_op(engine, &creq->op_tmpl); memcpy_toio(engine->sram, &creq->op_tmpl, sizeof(creq->op_tmpl)); if (creq->cache_ptr) memcpy_toio(engine->sram + CESA_SA_DATA_SRAM_OFFSET, creq->cache, creq->cache_ptr); len = min_t(size_t, req->nbytes + creq->cache_ptr - sreq->offset, CESA_SA_SRAM_PAYLOAD_SIZE); if (!creq->last_req) { new_cache_ptr = len & CESA_HASH_BLOCK_SIZE_MSK; len &= ~CESA_HASH_BLOCK_SIZE_MSK; } if (len - creq->cache_ptr) sreq->offset += sg_pcopy_to_buffer(req->src, creq->src_nents, engine->sram + CESA_SA_DATA_SRAM_OFFSET + creq->cache_ptr, len - creq->cache_ptr, sreq->offset); op = &creq->op_tmpl; frag_mode = mv_cesa_get_op_cfg(op) & CESA_SA_DESC_CFG_FRAG_MSK; if (creq->last_req && sreq->offset == req->nbytes && creq->len <= CESA_SA_DESC_MAC_SRC_TOTAL_LEN_MAX) { if (frag_mode == CESA_SA_DESC_CFG_FIRST_FRAG) frag_mode = CESA_SA_DESC_CFG_NOT_FRAG; else if (frag_mode == CESA_SA_DESC_CFG_MID_FRAG) frag_mode = CESA_SA_DESC_CFG_LAST_FRAG; } if (frag_mode == CESA_SA_DESC_CFG_NOT_FRAG || frag_mode == CESA_SA_DESC_CFG_LAST_FRAG) { if (len && creq->len <= CESA_SA_DESC_MAC_SRC_TOTAL_LEN_MAX) { mv_cesa_set_mac_op_total_len(op, creq->len); } else { int trailerlen = mv_cesa_ahash_pad_len(creq) + 8; if (len + trailerlen > CESA_SA_SRAM_PAYLOAD_SIZE) { len &= CESA_HASH_BLOCK_SIZE_MSK; new_cache_ptr = 64 - trailerlen; memcpy_fromio(creq->cache, engine->sram + CESA_SA_DATA_SRAM_OFFSET + len, new_cache_ptr); } else { len += mv_cesa_ahash_pad_req(creq, engine->sram + len + CESA_SA_DATA_SRAM_OFFSET); } if (frag_mode == CESA_SA_DESC_CFG_LAST_FRAG) frag_mode = CESA_SA_DESC_CFG_MID_FRAG; else frag_mode = CESA_SA_DESC_CFG_FIRST_FRAG; } } mv_cesa_set_mac_op_frag_len(op, len); mv_cesa_update_op_cfg(op, frag_mode, CESA_SA_DESC_CFG_FRAG_MSK); /* FIXME: only update enc_len field */ memcpy_toio(engine->sram, op, sizeof(*op)); if (frag_mode == CESA_SA_DESC_CFG_FIRST_FRAG) mv_cesa_update_op_cfg(op, CESA_SA_DESC_CFG_MID_FRAG, CESA_SA_DESC_CFG_FRAG_MSK); creq->cache_ptr = new_cache_ptr; mv_cesa_set_int_mask(engine, CESA_SA_INT_ACCEL0_DONE); writel_relaxed(CESA_SA_CFG_PARA_DIS, engine->regs + CESA_SA_CFG); BUG_ON(readl(engine->regs + CESA_SA_CMD) & CESA_SA_CMD_EN_CESA_SA_ACCL0); writel(CESA_SA_CMD_EN_CESA_SA_ACCL0, engine->regs + CESA_SA_CMD); }