Path: blob/master/drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c
26288 views
// SPDX-License-Identifier: GPL-2.0-only1/* Copyright (C) 2020 Marvell. */23#include "otx2_cptvf.h"4#include "otx2_cpt_common.h"56/* Default timeout when waiting for free pending entry in us */7#define CPT_PENTRY_TIMEOUT 10008#define CPT_PENTRY_STEP 50910/* Default threshold for stopping and resuming sender requests */11#define CPT_IQ_STOP_MARGIN 12812#define CPT_IQ_RESUME_MARGIN 5121314/* Default command timeout in seconds */15#define CPT_COMMAND_TIMEOUT 416#define CPT_TIME_IN_RESET_COUNT 51718static void otx2_cpt_dump_sg_list(struct pci_dev *pdev,19struct otx2_cpt_req_info *req)20{21int i;2223pr_debug("Gather list size %d\n", req->in_cnt);24for (i = 0; i < req->in_cnt; i++) {25pr_debug("Buffer %d size %d, vptr 0x%p, dmaptr 0x%llx\n", i,26req->in[i].size, req->in[i].vptr,27req->in[i].dma_addr);28pr_debug("Buffer hexdump (%d bytes)\n",29req->in[i].size);30print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1,31req->in[i].vptr, req->in[i].size, false);32}33pr_debug("Scatter list size %d\n", req->out_cnt);34for (i = 0; i < req->out_cnt; i++) {35pr_debug("Buffer %d size %d, vptr 0x%p, dmaptr 0x%llx\n", i,36req->out[i].size, req->out[i].vptr,37req->out[i].dma_addr);38pr_debug("Buffer hexdump (%d bytes)\n", req->out[i].size);39print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1,40req->out[i].vptr, req->out[i].size, false);41}42}4344static inline struct otx2_cpt_pending_entry *get_free_pending_entry(45struct otx2_cpt_pending_queue *q,46int qlen)47{48struct otx2_cpt_pending_entry *ent = NULL;4950ent = &q->head[q->rear];51if (unlikely(ent->busy))52return NULL;5354q->rear++;55if (unlikely(q->rear == qlen))56q->rear = 0;5758return ent;59}6061static inline u32 modulo_inc(u32 index, u32 length, u32 inc)62{63if (WARN_ON(inc > length))64inc = length;6566index += inc;67if (unlikely(index >= length))68index -= length;6970return index;71}7273static inline void free_pentry(struct otx2_cpt_pending_entry *pentry)74{75pentry->completion_addr = NULL;76pentry->info = NULL;77pentry->callback = NULL;78pentry->areq = NULL;79pentry->resume_sender = false;80pentry->busy = false;81}8283static int process_request(struct pci_dev *pdev, struct otx2_cpt_req_info *req,84struct otx2_cpt_pending_queue *pqueue,85struct otx2_cptlf_info *lf)86{87struct otx2_cptvf_request *cpt_req = &req->req;88struct otx2_cpt_pending_entry *pentry = NULL;89union otx2_cpt_ctrl_info *ctrl = &req->ctrl;90struct otx2_cpt_inst_info *info = NULL;91union otx2_cpt_res_s *result = NULL;92struct otx2_cpt_iq_command iq_cmd;93union otx2_cpt_inst_s cptinst;94int retry, ret = 0;95u8 resume_sender;96gfp_t gfp;9798gfp = (req->areq->flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL :99GFP_ATOMIC;100if (unlikely(!otx2_cptlf_started(lf->lfs)))101return -ENODEV;102103info = lf->lfs->ops->cpt_sg_info_create(pdev, req, gfp);104if (unlikely(!info)) {105dev_err(&pdev->dev, "Setting up cpt inst info failed");106return -ENOMEM;107}108cpt_req->dlen = info->dlen;109110result = info->completion_addr;111result->s.compcode = OTX2_CPT_COMPLETION_CODE_INIT;112113spin_lock_bh(&pqueue->lock);114pentry = get_free_pending_entry(pqueue, pqueue->qlen);115retry = CPT_PENTRY_TIMEOUT / CPT_PENTRY_STEP;116while (unlikely(!pentry) && retry--) {117spin_unlock_bh(&pqueue->lock);118udelay(CPT_PENTRY_STEP);119spin_lock_bh(&pqueue->lock);120pentry = get_free_pending_entry(pqueue, pqueue->qlen);121}122123if (unlikely(!pentry)) {124ret = -ENOSPC;125goto destroy_info;126}127128/*129* Check if we are close to filling in entire pending queue,130* if so then tell the sender to stop/sleep by returning -EBUSY131* We do it only for context which can sleep (GFP_KERNEL)132*/133if (gfp == GFP_KERNEL &&134pqueue->pending_count > (pqueue->qlen - CPT_IQ_STOP_MARGIN)) {135pentry->resume_sender = true;136} else137pentry->resume_sender = false;138resume_sender = pentry->resume_sender;139pqueue->pending_count++;140141pentry->completion_addr = info->completion_addr;142pentry->info = info;143pentry->callback = req->callback;144pentry->areq = req->areq;145pentry->busy = true;146info->pentry = pentry;147info->time_in = jiffies;148info->req = req;149150/* Fill in the command */151iq_cmd.cmd.u = 0;152iq_cmd.cmd.s.opcode = cpu_to_be16(cpt_req->opcode.flags);153iq_cmd.cmd.s.param1 = cpu_to_be16(cpt_req->param1);154iq_cmd.cmd.s.param2 = cpu_to_be16(cpt_req->param2);155iq_cmd.cmd.s.dlen = cpu_to_be16(cpt_req->dlen);156157/* 64-bit swap for microcode data reads, not needed for addresses*/158cpu_to_be64s(&iq_cmd.cmd.u);159iq_cmd.dptr = info->dptr_baddr | info->gthr_sz << 60;160iq_cmd.rptr = info->rptr_baddr | info->sctr_sz << 60;161iq_cmd.cptr.s.cptr = cpt_req->cptr_dma;162iq_cmd.cptr.s.grp = ctrl->s.grp;163164/* Fill in the CPT_INST_S type command for HW interpretation */165otx2_cpt_fill_inst(&cptinst, &iq_cmd, info->comp_baddr);166167/* Print debug info if enabled */168otx2_cpt_dump_sg_list(pdev, req);169pr_debug("Cpt_inst_s hexdump (%d bytes)\n", OTX2_CPT_INST_SIZE);170print_hex_dump_debug("", 0, 16, 1, &cptinst, OTX2_CPT_INST_SIZE, false);171pr_debug("Dptr hexdump (%d bytes)\n", cpt_req->dlen);172print_hex_dump_debug("", 0, 16, 1, info->in_buffer,173cpt_req->dlen, false);174175/* Send CPT command */176lf->lfs->ops->send_cmd(&cptinst, 1, lf);177178/*179* We allocate and prepare pending queue entry in critical section180* together with submitting CPT instruction to CPT instruction queue181* to make sure that order of CPT requests is the same in both182* pending and instruction queues183*/184spin_unlock_bh(&pqueue->lock);185186ret = resume_sender ? -EBUSY : -EINPROGRESS;187return ret;188189destroy_info:190spin_unlock_bh(&pqueue->lock);191otx2_cpt_info_destroy(pdev, info);192return ret;193}194195int otx2_cpt_do_request(struct pci_dev *pdev, struct otx2_cpt_req_info *req,196int cpu_num)197{198struct otx2_cptvf_dev *cptvf = pci_get_drvdata(pdev);199struct otx2_cptlfs_info *lfs = &cptvf->lfs;200201return process_request(lfs->pdev, req, &lfs->lf[cpu_num].pqueue,202&lfs->lf[cpu_num]);203}204205static int cpt_process_ccode(struct otx2_cptlfs_info *lfs,206union otx2_cpt_res_s *cpt_status,207struct otx2_cpt_inst_info *info,208u32 *res_code)209{210u8 uc_ccode = lfs->ops->cpt_get_uc_compcode(cpt_status);211u8 ccode = lfs->ops->cpt_get_compcode(cpt_status);212struct pci_dev *pdev = lfs->pdev;213214switch (ccode) {215case OTX2_CPT_COMP_E_FAULT:216dev_err(&pdev->dev,217"Request failed with DMA fault\n");218otx2_cpt_dump_sg_list(pdev, info->req);219break;220221case OTX2_CPT_COMP_E_HWERR:222dev_err(&pdev->dev,223"Request failed with hardware error\n");224otx2_cpt_dump_sg_list(pdev, info->req);225break;226227case OTX2_CPT_COMP_E_INSTERR:228dev_err(&pdev->dev,229"Request failed with instruction error\n");230otx2_cpt_dump_sg_list(pdev, info->req);231break;232233case OTX2_CPT_COMP_E_NOTDONE:234/* check for timeout */235if (time_after_eq(jiffies, info->time_in +236CPT_COMMAND_TIMEOUT * HZ))237dev_warn(&pdev->dev,238"Request timed out 0x%p", info->req);239else if (info->extra_time < CPT_TIME_IN_RESET_COUNT) {240info->time_in = jiffies;241info->extra_time++;242}243return 1;244245case OTX2_CPT_COMP_E_GOOD:246case OTX2_CPT_COMP_E_WARN:247/*248* Check microcode completion code, it is only valid249* when completion code is CPT_COMP_E::GOOD250*/251if (uc_ccode != OTX2_CPT_UCC_SUCCESS) {252/*253* If requested hmac is truncated and ucode returns254* s/g write length error then we report success255* because ucode writes as many bytes of calculated256* hmac as available in gather buffer and reports257* s/g write length error if number of bytes in gather258* buffer is less than full hmac size.259*/260if (info->req->is_trunc_hmac &&261uc_ccode == OTX2_CPT_UCC_SG_WRITE_LENGTH) {262*res_code = 0;263break;264}265266pr_debug("Request failed with software error code 0x%x: algo = %s driver = %s\n",267cpt_status->s.uc_compcode,268info->req->areq->tfm->__crt_alg->cra_name,269info->req->areq->tfm->__crt_alg->cra_driver_name);270otx2_cpt_dump_sg_list(pdev, info->req);271break;272}273/* Request has been processed with success */274*res_code = 0;275break;276277default:278dev_err(&pdev->dev,279"Request returned invalid status %d\n", ccode);280break;281}282return 0;283}284285static inline void process_pending_queue(struct otx2_cptlfs_info *lfs,286struct otx2_cpt_pending_queue *pqueue)287{288struct otx2_cpt_pending_entry *resume_pentry = NULL;289void (*callback)(int status, void *arg, void *req);290struct otx2_cpt_pending_entry *pentry = NULL;291union otx2_cpt_res_s *cpt_status = NULL;292struct otx2_cpt_inst_info *info = NULL;293struct otx2_cpt_req_info *req = NULL;294struct crypto_async_request *areq;295struct pci_dev *pdev = lfs->pdev;296u32 res_code, resume_index;297298while (1) {299spin_lock_bh(&pqueue->lock);300pentry = &pqueue->head[pqueue->front];301302if (WARN_ON(!pentry)) {303spin_unlock_bh(&pqueue->lock);304break;305}306307res_code = -EINVAL;308if (unlikely(!pentry->busy)) {309spin_unlock_bh(&pqueue->lock);310break;311}312313if (unlikely(!pentry->callback)) {314dev_err(&pdev->dev, "Callback NULL\n");315goto process_pentry;316}317318info = pentry->info;319if (unlikely(!info)) {320dev_err(&pdev->dev, "Pending entry post arg NULL\n");321goto process_pentry;322}323324req = info->req;325if (unlikely(!req)) {326dev_err(&pdev->dev, "Request NULL\n");327goto process_pentry;328}329330cpt_status = pentry->completion_addr;331if (unlikely(!cpt_status)) {332dev_err(&pdev->dev, "Completion address NULL\n");333goto process_pentry;334}335336if (cpt_process_ccode(lfs, cpt_status, info, &res_code)) {337spin_unlock_bh(&pqueue->lock);338return;339}340info->pdev = pdev;341342process_pentry:343/*344* Check if we should inform sending side to resume345* We do it CPT_IQ_RESUME_MARGIN elements in advance before346* pending queue becomes empty347*/348resume_index = modulo_inc(pqueue->front, pqueue->qlen,349CPT_IQ_RESUME_MARGIN);350resume_pentry = &pqueue->head[resume_index];351if (resume_pentry &&352resume_pentry->resume_sender) {353resume_pentry->resume_sender = false;354callback = resume_pentry->callback;355areq = resume_pentry->areq;356357if (callback) {358spin_unlock_bh(&pqueue->lock);359360/*361* EINPROGRESS is an indication for sending362* side that it can resume sending requests363*/364callback(-EINPROGRESS, areq, info);365spin_lock_bh(&pqueue->lock);366}367}368369callback = pentry->callback;370areq = pentry->areq;371free_pentry(pentry);372373pqueue->pending_count--;374pqueue->front = modulo_inc(pqueue->front, pqueue->qlen, 1);375spin_unlock_bh(&pqueue->lock);376377/*378* Call callback after current pending entry has been379* processed, we don't do it if the callback pointer is380* invalid.381*/382if (callback)383callback(res_code, areq, info);384}385}386387void otx2_cpt_post_process(struct otx2_cptlf_wqe *wqe)388{389process_pending_queue(wqe->lfs,390&wqe->lfs->lf[wqe->lf_num].pqueue);391}392393int otx2_cpt_get_eng_grp_num(struct pci_dev *pdev,394enum otx2_cpt_eng_type eng_type)395{396struct otx2_cptvf_dev *cptvf = pci_get_drvdata(pdev);397398switch (eng_type) {399case OTX2_CPT_SE_TYPES:400return cptvf->lfs.kcrypto_se_eng_grp_num;401case OTX2_CPT_AE_TYPES:402return cptvf->lfs.kcrypto_ae_eng_grp_num;403default:404dev_err(&cptvf->pdev->dev, "Unsupported engine type");405break;406}407return -ENXIO;408}409410411