static int qat_dh_set_secret(struct crypto_kpp *tfm, const void *buf, unsigned int len) { struct qat_dh_ctx *ctx = kpp_tfm_ctx(tfm); struct device *dev = &GET_DEV(ctx->inst->accel_dev); struct dh params; int ret; if (crypto_dh_decode_key(buf, len, ¶ms) < 0) return -EINVAL; /* Free old secret if any */ qat_dh_clear_ctx(dev, ctx); ret = qat_dh_set_params(ctx, ¶ms); if (ret < 0) return ret; ctx->xa = dma_zalloc_coherent(dev, ctx->p_size, &ctx->dma_xa, GFP_KERNEL); if (!ctx->xa) { qat_dh_clear_ctx(dev, ctx); return -ENOMEM; } memcpy(ctx->xa + (ctx->p_size - params.key_size), params.key, params.key_size); return 0; }
static void qat_dh_exit_tfm(struct crypto_kpp *tfm) { struct qat_dh_ctx *ctx = kpp_tfm_ctx(tfm); struct device *dev = &GET_DEV(ctx->inst->accel_dev); qat_dh_clear_ctx(dev, ctx); qat_crypto_put_instance(ctx->inst); }
static int qat_dh_init_tfm(struct crypto_kpp *tfm) { struct qat_dh_ctx *ctx = kpp_tfm_ctx(tfm); struct qat_crypto_instance *inst = qat_crypto_get_instance_node(get_current_node()); if (!inst) return -EINVAL; ctx->p_size = 0; ctx->g2 = false; ctx->inst = inst; return 0; }
static inline struct dh_ctx *dh_get_ctx(struct crypto_kpp *tfm) { return kpp_tfm_ctx(tfm); }
static int qat_dh_max_size(struct crypto_kpp *tfm) { struct qat_dh_ctx *ctx = kpp_tfm_ctx(tfm); return ctx->p ? ctx->p_size : -EINVAL; }
static int qat_dh_compute_value(struct kpp_request *req) { struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); struct qat_dh_ctx *ctx = kpp_tfm_ctx(tfm); struct qat_crypto_instance *inst = ctx->inst; struct device *dev = &GET_DEV(inst->accel_dev); struct qat_asym_request *qat_req = PTR_ALIGN(kpp_request_ctx(req), 64); struct icp_qat_fw_pke_request *msg = &qat_req->req; int ret, ctr = 0; int n_input_params = 0; if (unlikely(!ctx->xa)) return -EINVAL; if (req->dst_len < ctx->p_size) { req->dst_len = ctx->p_size; return -EOVERFLOW; } memset(msg, '\0', sizeof(*msg)); ICP_QAT_FW_PKE_HDR_VALID_FLAG_SET(msg->pke_hdr, ICP_QAT_FW_COMN_REQ_FLAG_SET); msg->pke_hdr.cd_pars.func_id = qat_dh_fn_id(ctx->p_size, !req->src && ctx->g2); if (unlikely(!msg->pke_hdr.cd_pars.func_id)) return -EINVAL; qat_req->cb = qat_dh_cb; qat_req->ctx.dh = ctx; qat_req->areq.dh = req; msg->pke_hdr.service_type = ICP_QAT_FW_COMN_REQ_CPM_FW_PKE; msg->pke_hdr.comn_req_flags = ICP_QAT_FW_COMN_FLAGS_BUILD(QAT_COMN_PTR_TYPE_FLAT, QAT_COMN_CD_FLD_TYPE_64BIT_ADR); /* * If no source is provided use g as base */ if (req->src) { qat_req->in.dh.in.xa = ctx->dma_xa; qat_req->in.dh.in.p = ctx->dma_p; n_input_params = 3; } else { if (ctx->g2) { qat_req->in.dh.in_g2.xa = ctx->dma_xa; qat_req->in.dh.in_g2.p = ctx->dma_p; n_input_params = 2; } else { qat_req->in.dh.in.b = ctx->dma_g; qat_req->in.dh.in.xa = ctx->dma_xa; qat_req->in.dh.in.p = ctx->dma_p; n_input_params = 3; } } ret = -ENOMEM; if (req->src) { /* * src can be of any size in valid range, but HW expects it to * be the same as modulo p so in case it is different we need * to allocate a new buf and copy src data. * In other case we just need to map the user provided buffer. * Also need to make sure that it is in contiguous buffer. */ if (sg_is_last(req->src) && req->src_len == ctx->p_size) { qat_req->src_align = NULL; qat_req->in.dh.in.b = dma_map_single(dev, sg_virt(req->src), req->src_len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(dev, qat_req->in.dh.in.b))) return ret; } else { int shift = ctx->p_size - req->src_len; qat_req->src_align = dma_zalloc_coherent(dev, ctx->p_size, &qat_req->in.dh.in.b, GFP_KERNEL); if (unlikely(!qat_req->src_align)) return ret; scatterwalk_map_and_copy(qat_req->src_align + shift, req->src, 0, req->src_len, 0); } } /* * dst can be of any size in valid range, but HW expects it to be the * same as modulo m so in case it is different we need to allocate a * new buf and copy src data. * In other case we just need to map the user provided buffer. * Also need to make sure that it is in contiguous buffer. */ if (sg_is_last(req->dst) && req->dst_len == ctx->p_size) { qat_req->dst_align = NULL; qat_req->out.dh.r = dma_map_single(dev, sg_virt(req->dst), req->dst_len, DMA_FROM_DEVICE); if (unlikely(dma_mapping_error(dev, qat_req->out.dh.r))) goto unmap_src; } else { qat_req->dst_align = dma_zalloc_coherent(dev, ctx->p_size, &qat_req->out.dh.r, GFP_KERNEL); if (unlikely(!qat_req->dst_align)) goto unmap_src; } qat_req->in.dh.in_tab[n_input_params] = 0; qat_req->out.dh.out_tab[1] = 0; /* Mapping in.in.b or in.in_g2.xa is the same */ qat_req->phy_in = dma_map_single(dev, &qat_req->in.dh.in.b, sizeof(struct qat_dh_input_params), DMA_TO_DEVICE); if (unlikely(dma_mapping_error(dev, qat_req->phy_in))) goto unmap_dst; qat_req->phy_out = dma_map_single(dev, &qat_req->out.dh.r, sizeof(struct qat_dh_output_params), DMA_TO_DEVICE); if (unlikely(dma_mapping_error(dev, qat_req->phy_out))) goto unmap_in_params; msg->pke_mid.src_data_addr = qat_req->phy_in; msg->pke_mid.dest_data_addr = qat_req->phy_out; msg->pke_mid.opaque = (uint64_t)(__force long)qat_req; msg->input_param_count = n_input_params; msg->output_param_count = 1; do { ret = adf_send_message(ctx->inst->pke_tx, (uint32_t *)msg); } while (ret == -EBUSY && ctr++ < 100); if (!ret) return -EINPROGRESS; if (!dma_mapping_error(dev, qat_req->phy_out)) dma_unmap_single(dev, qat_req->phy_out, sizeof(struct qat_dh_output_params), DMA_TO_DEVICE); unmap_in_params: if (!dma_mapping_error(dev, qat_req->phy_in)) dma_unmap_single(dev, qat_req->phy_in, sizeof(struct qat_dh_input_params), DMA_TO_DEVICE); unmap_dst: if (qat_req->dst_align) dma_free_coherent(dev, ctx->p_size, qat_req->dst_align, qat_req->out.dh.r); else if (!dma_mapping_error(dev, qat_req->out.dh.r)) dma_unmap_single(dev, qat_req->out.dh.r, ctx->p_size, DMA_FROM_DEVICE); unmap_src: if (req->src) { if (qat_req->src_align) dma_free_coherent(dev, ctx->p_size, qat_req->src_align, qat_req->in.dh.in.b); else if (!dma_mapping_error(dev, qat_req->in.dh.in.b)) dma_unmap_single(dev, qat_req->in.dh.in.b, ctx->p_size, DMA_TO_DEVICE); } return ret; }
static inline struct qat_dh_ctx *qat_dh_get_params(struct crypto_kpp *tfm) { return kpp_tfm_ctx(tfm); }