18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Marvell OcteonTX CPT driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2019 Marvell International Ltd. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 78c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License version 2 as 88c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "otx_cptvf.h" 128c2ecf20Sopenharmony_ci#include "otx_cptvf_algs.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* Completion code size and initial value */ 158c2ecf20Sopenharmony_ci#define COMPLETION_CODE_SIZE 8 168c2ecf20Sopenharmony_ci#define COMPLETION_CODE_INIT 0 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* SG list header size in bytes */ 198c2ecf20Sopenharmony_ci#define SG_LIST_HDR_SIZE 8 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* Default timeout when waiting for free pending entry in us */ 228c2ecf20Sopenharmony_ci#define CPT_PENTRY_TIMEOUT 1000 238c2ecf20Sopenharmony_ci#define CPT_PENTRY_STEP 50 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* Default threshold for stopping and resuming sender requests */ 268c2ecf20Sopenharmony_ci#define CPT_IQ_STOP_MARGIN 128 278c2ecf20Sopenharmony_ci#define CPT_IQ_RESUME_MARGIN 512 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define CPT_DMA_ALIGN 128 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_civoid otx_cpt_dump_sg_list(struct pci_dev *pdev, struct otx_cpt_req_info *req) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci int i; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci pr_debug("Gather list size %d\n", req->incnt); 368c2ecf20Sopenharmony_ci for (i = 0; i < req->incnt; i++) { 378c2ecf20Sopenharmony_ci pr_debug("Buffer %d size %d, vptr 0x%p, dmaptr 0x%p\n", i, 388c2ecf20Sopenharmony_ci req->in[i].size, req->in[i].vptr, 398c2ecf20Sopenharmony_ci (void *) req->in[i].dma_addr); 408c2ecf20Sopenharmony_ci pr_debug("Buffer hexdump (%d bytes)\n", 418c2ecf20Sopenharmony_ci req->in[i].size); 428c2ecf20Sopenharmony_ci print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, 438c2ecf20Sopenharmony_ci req->in[i].vptr, req->in[i].size, false); 448c2ecf20Sopenharmony_ci } 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci pr_debug("Scatter list size %d\n", req->outcnt); 478c2ecf20Sopenharmony_ci for (i = 0; i < req->outcnt; i++) { 488c2ecf20Sopenharmony_ci pr_debug("Buffer %d size %d, vptr 0x%p, dmaptr 0x%p\n", i, 498c2ecf20Sopenharmony_ci req->out[i].size, req->out[i].vptr, 508c2ecf20Sopenharmony_ci (void *) req->out[i].dma_addr); 518c2ecf20Sopenharmony_ci pr_debug("Buffer hexdump (%d bytes)\n", req->out[i].size); 528c2ecf20Sopenharmony_ci print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, 538c2ecf20Sopenharmony_ci req->out[i].vptr, req->out[i].size, false); 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic inline struct otx_cpt_pending_entry *get_free_pending_entry( 588c2ecf20Sopenharmony_ci struct otx_cpt_pending_queue *q, 598c2ecf20Sopenharmony_ci int qlen) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct otx_cpt_pending_entry *ent = NULL; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci ent = &q->head[q->rear]; 648c2ecf20Sopenharmony_ci if (unlikely(ent->busy)) 658c2ecf20Sopenharmony_ci return NULL; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci q->rear++; 688c2ecf20Sopenharmony_ci if (unlikely(q->rear == qlen)) 698c2ecf20Sopenharmony_ci q->rear = 0; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return ent; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic inline u32 modulo_inc(u32 index, u32 length, u32 inc) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci if (WARN_ON(inc > length)) 778c2ecf20Sopenharmony_ci inc = length; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci index += inc; 808c2ecf20Sopenharmony_ci if (unlikely(index >= length)) 818c2ecf20Sopenharmony_ci index -= length; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci return index; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic inline void free_pentry(struct otx_cpt_pending_entry *pentry) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci pentry->completion_addr = NULL; 898c2ecf20Sopenharmony_ci pentry->info = NULL; 908c2ecf20Sopenharmony_ci pentry->callback = NULL; 918c2ecf20Sopenharmony_ci pentry->areq = NULL; 928c2ecf20Sopenharmony_ci pentry->resume_sender = false; 938c2ecf20Sopenharmony_ci pentry->busy = false; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic inline int setup_sgio_components(struct pci_dev *pdev, 978c2ecf20Sopenharmony_ci struct otx_cpt_buf_ptr *list, 988c2ecf20Sopenharmony_ci int buf_count, u8 *buffer) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci struct otx_cpt_sglist_component *sg_ptr = NULL; 1018c2ecf20Sopenharmony_ci int ret = 0, i, j; 1028c2ecf20Sopenharmony_ci int components; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (unlikely(!list)) { 1058c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Input list pointer is NULL\n"); 1068c2ecf20Sopenharmony_ci return -EFAULT; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci for (i = 0; i < buf_count; i++) { 1108c2ecf20Sopenharmony_ci if (likely(list[i].vptr)) { 1118c2ecf20Sopenharmony_ci list[i].dma_addr = dma_map_single(&pdev->dev, 1128c2ecf20Sopenharmony_ci list[i].vptr, 1138c2ecf20Sopenharmony_ci list[i].size, 1148c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 1158c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(&pdev->dev, 1168c2ecf20Sopenharmony_ci list[i].dma_addr))) { 1178c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Dma mapping failed\n"); 1188c2ecf20Sopenharmony_ci ret = -EIO; 1198c2ecf20Sopenharmony_ci goto sg_cleanup; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci components = buf_count / 4; 1258c2ecf20Sopenharmony_ci sg_ptr = (struct otx_cpt_sglist_component *)buffer; 1268c2ecf20Sopenharmony_ci for (i = 0; i < components; i++) { 1278c2ecf20Sopenharmony_ci sg_ptr->u.s.len0 = cpu_to_be16(list[i * 4 + 0].size); 1288c2ecf20Sopenharmony_ci sg_ptr->u.s.len1 = cpu_to_be16(list[i * 4 + 1].size); 1298c2ecf20Sopenharmony_ci sg_ptr->u.s.len2 = cpu_to_be16(list[i * 4 + 2].size); 1308c2ecf20Sopenharmony_ci sg_ptr->u.s.len3 = cpu_to_be16(list[i * 4 + 3].size); 1318c2ecf20Sopenharmony_ci sg_ptr->ptr0 = cpu_to_be64(list[i * 4 + 0].dma_addr); 1328c2ecf20Sopenharmony_ci sg_ptr->ptr1 = cpu_to_be64(list[i * 4 + 1].dma_addr); 1338c2ecf20Sopenharmony_ci sg_ptr->ptr2 = cpu_to_be64(list[i * 4 + 2].dma_addr); 1348c2ecf20Sopenharmony_ci sg_ptr->ptr3 = cpu_to_be64(list[i * 4 + 3].dma_addr); 1358c2ecf20Sopenharmony_ci sg_ptr++; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci components = buf_count % 4; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci switch (components) { 1408c2ecf20Sopenharmony_ci case 3: 1418c2ecf20Sopenharmony_ci sg_ptr->u.s.len2 = cpu_to_be16(list[i * 4 + 2].size); 1428c2ecf20Sopenharmony_ci sg_ptr->ptr2 = cpu_to_be64(list[i * 4 + 2].dma_addr); 1438c2ecf20Sopenharmony_ci fallthrough; 1448c2ecf20Sopenharmony_ci case 2: 1458c2ecf20Sopenharmony_ci sg_ptr->u.s.len1 = cpu_to_be16(list[i * 4 + 1].size); 1468c2ecf20Sopenharmony_ci sg_ptr->ptr1 = cpu_to_be64(list[i * 4 + 1].dma_addr); 1478c2ecf20Sopenharmony_ci fallthrough; 1488c2ecf20Sopenharmony_ci case 1: 1498c2ecf20Sopenharmony_ci sg_ptr->u.s.len0 = cpu_to_be16(list[i * 4 + 0].size); 1508c2ecf20Sopenharmony_ci sg_ptr->ptr0 = cpu_to_be64(list[i * 4 + 0].dma_addr); 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci default: 1538c2ecf20Sopenharmony_ci break; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci return ret; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cisg_cleanup: 1588c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) { 1598c2ecf20Sopenharmony_ci if (list[j].dma_addr) { 1608c2ecf20Sopenharmony_ci dma_unmap_single(&pdev->dev, list[i].dma_addr, 1618c2ecf20Sopenharmony_ci list[i].size, DMA_BIDIRECTIONAL); 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci list[j].dma_addr = 0; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci return ret; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic inline int setup_sgio_list(struct pci_dev *pdev, 1708c2ecf20Sopenharmony_ci struct otx_cpt_info_buffer **pinfo, 1718c2ecf20Sopenharmony_ci struct otx_cpt_req_info *req, gfp_t gfp) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci u32 dlen, align_dlen, info_len, rlen; 1748c2ecf20Sopenharmony_ci struct otx_cpt_info_buffer *info; 1758c2ecf20Sopenharmony_ci u16 g_sz_bytes, s_sz_bytes; 1768c2ecf20Sopenharmony_ci int align = CPT_DMA_ALIGN; 1778c2ecf20Sopenharmony_ci u32 total_mem_len; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (unlikely(req->incnt > OTX_CPT_MAX_SG_IN_CNT || 1808c2ecf20Sopenharmony_ci req->outcnt > OTX_CPT_MAX_SG_OUT_CNT)) { 1818c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Error too many sg components\n"); 1828c2ecf20Sopenharmony_ci return -EINVAL; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci g_sz_bytes = ((req->incnt + 3) / 4) * 1868c2ecf20Sopenharmony_ci sizeof(struct otx_cpt_sglist_component); 1878c2ecf20Sopenharmony_ci s_sz_bytes = ((req->outcnt + 3) / 4) * 1888c2ecf20Sopenharmony_ci sizeof(struct otx_cpt_sglist_component); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci dlen = g_sz_bytes + s_sz_bytes + SG_LIST_HDR_SIZE; 1918c2ecf20Sopenharmony_ci align_dlen = ALIGN(dlen, align); 1928c2ecf20Sopenharmony_ci info_len = ALIGN(sizeof(*info), align); 1938c2ecf20Sopenharmony_ci rlen = ALIGN(sizeof(union otx_cpt_res_s), align); 1948c2ecf20Sopenharmony_ci total_mem_len = align_dlen + info_len + rlen + COMPLETION_CODE_SIZE; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci info = kzalloc(total_mem_len, gfp); 1978c2ecf20Sopenharmony_ci if (unlikely(!info)) { 1988c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Memory allocation failed\n"); 1998c2ecf20Sopenharmony_ci return -ENOMEM; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci *pinfo = info; 2028c2ecf20Sopenharmony_ci info->dlen = dlen; 2038c2ecf20Sopenharmony_ci info->in_buffer = (u8 *)info + info_len; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci ((__be16 *)info->in_buffer)[0] = cpu_to_be16(req->outcnt); 2068c2ecf20Sopenharmony_ci ((__be16 *)info->in_buffer)[1] = cpu_to_be16(req->incnt); 2078c2ecf20Sopenharmony_ci ((u16 *)info->in_buffer)[2] = 0; 2088c2ecf20Sopenharmony_ci ((u16 *)info->in_buffer)[3] = 0; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* Setup gather (input) components */ 2118c2ecf20Sopenharmony_ci if (setup_sgio_components(pdev, req->in, req->incnt, 2128c2ecf20Sopenharmony_ci &info->in_buffer[8])) { 2138c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to setup gather list\n"); 2148c2ecf20Sopenharmony_ci return -EFAULT; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (setup_sgio_components(pdev, req->out, req->outcnt, 2188c2ecf20Sopenharmony_ci &info->in_buffer[8 + g_sz_bytes])) { 2198c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to setup scatter list\n"); 2208c2ecf20Sopenharmony_ci return -EFAULT; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci info->dma_len = total_mem_len - info_len; 2248c2ecf20Sopenharmony_ci info->dptr_baddr = dma_map_single(&pdev->dev, (void *)info->in_buffer, 2258c2ecf20Sopenharmony_ci info->dma_len, DMA_BIDIRECTIONAL); 2268c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(&pdev->dev, info->dptr_baddr))) { 2278c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "DMA Mapping failed for cpt req\n"); 2288c2ecf20Sopenharmony_ci return -EIO; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci /* 2318c2ecf20Sopenharmony_ci * Get buffer for union otx_cpt_res_s response 2328c2ecf20Sopenharmony_ci * structure and its physical address 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_ci info->completion_addr = (u64 *)(info->in_buffer + align_dlen); 2358c2ecf20Sopenharmony_ci info->comp_baddr = info->dptr_baddr + align_dlen; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /* Create and initialize RPTR */ 2388c2ecf20Sopenharmony_ci info->out_buffer = (u8 *)info->completion_addr + rlen; 2398c2ecf20Sopenharmony_ci info->rptr_baddr = info->comp_baddr + rlen; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci *((u64 *) info->out_buffer) = ~((u64) COMPLETION_CODE_INIT); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci return 0; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic void cpt_fill_inst(union otx_cpt_inst_s *inst, 2488c2ecf20Sopenharmony_ci struct otx_cpt_info_buffer *info, 2498c2ecf20Sopenharmony_ci struct otx_cpt_iq_cmd *cmd) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci inst->u[0] = 0x0; 2528c2ecf20Sopenharmony_ci inst->s.doneint = true; 2538c2ecf20Sopenharmony_ci inst->s.res_addr = (u64)info->comp_baddr; 2548c2ecf20Sopenharmony_ci inst->u[2] = 0x0; 2558c2ecf20Sopenharmony_ci inst->s.wq_ptr = 0; 2568c2ecf20Sopenharmony_ci inst->s.ei0 = cmd->cmd.u64; 2578c2ecf20Sopenharmony_ci inst->s.ei1 = cmd->dptr; 2588c2ecf20Sopenharmony_ci inst->s.ei2 = cmd->rptr; 2598c2ecf20Sopenharmony_ci inst->s.ei3 = cmd->cptr.u64; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci/* 2638c2ecf20Sopenharmony_ci * On OcteonTX platform the parameter db_count is used as a count for ringing 2648c2ecf20Sopenharmony_ci * door bell. The valid values for db_count are: 2658c2ecf20Sopenharmony_ci * 0 - 1 CPT instruction will be enqueued however CPT will not be informed 2668c2ecf20Sopenharmony_ci * 1 - 1 CPT instruction will be enqueued and CPT will be informed 2678c2ecf20Sopenharmony_ci */ 2688c2ecf20Sopenharmony_cistatic void cpt_send_cmd(union otx_cpt_inst_s *cptinst, struct otx_cptvf *cptvf) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci struct otx_cpt_cmd_qinfo *qinfo = &cptvf->cqinfo; 2718c2ecf20Sopenharmony_ci struct otx_cpt_cmd_queue *queue; 2728c2ecf20Sopenharmony_ci struct otx_cpt_cmd_chunk *curr; 2738c2ecf20Sopenharmony_ci u8 *ent; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci queue = &qinfo->queue[0]; 2768c2ecf20Sopenharmony_ci /* 2778c2ecf20Sopenharmony_ci * cpt_send_cmd is currently called only from critical section 2788c2ecf20Sopenharmony_ci * therefore no locking is required for accessing instruction queue 2798c2ecf20Sopenharmony_ci */ 2808c2ecf20Sopenharmony_ci ent = &queue->qhead->head[queue->idx * OTX_CPT_INST_SIZE]; 2818c2ecf20Sopenharmony_ci memcpy(ent, (void *) cptinst, OTX_CPT_INST_SIZE); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (++queue->idx >= queue->qhead->size / 64) { 2848c2ecf20Sopenharmony_ci curr = queue->qhead; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci if (list_is_last(&curr->nextchunk, &queue->chead)) 2878c2ecf20Sopenharmony_ci queue->qhead = queue->base; 2888c2ecf20Sopenharmony_ci else 2898c2ecf20Sopenharmony_ci queue->qhead = list_next_entry(queue->qhead, nextchunk); 2908c2ecf20Sopenharmony_ci queue->idx = 0; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci /* make sure all memory stores are done before ringing doorbell */ 2938c2ecf20Sopenharmony_ci smp_wmb(); 2948c2ecf20Sopenharmony_ci otx_cptvf_write_vq_doorbell(cptvf, 1); 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic int process_request(struct pci_dev *pdev, struct otx_cpt_req_info *req, 2988c2ecf20Sopenharmony_ci struct otx_cpt_pending_queue *pqueue, 2998c2ecf20Sopenharmony_ci struct otx_cptvf *cptvf) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci struct otx_cptvf_request *cpt_req = &req->req; 3028c2ecf20Sopenharmony_ci struct otx_cpt_pending_entry *pentry = NULL; 3038c2ecf20Sopenharmony_ci union otx_cpt_ctrl_info *ctrl = &req->ctrl; 3048c2ecf20Sopenharmony_ci struct otx_cpt_info_buffer *info = NULL; 3058c2ecf20Sopenharmony_ci union otx_cpt_res_s *result = NULL; 3068c2ecf20Sopenharmony_ci struct otx_cpt_iq_cmd iq_cmd; 3078c2ecf20Sopenharmony_ci union otx_cpt_inst_s cptinst; 3088c2ecf20Sopenharmony_ci int retry, ret = 0; 3098c2ecf20Sopenharmony_ci u8 resume_sender; 3108c2ecf20Sopenharmony_ci gfp_t gfp; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci gfp = (req->areq->flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : 3138c2ecf20Sopenharmony_ci GFP_ATOMIC; 3148c2ecf20Sopenharmony_ci ret = setup_sgio_list(pdev, &info, req, gfp); 3158c2ecf20Sopenharmony_ci if (unlikely(ret)) { 3168c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Setting up SG list failed\n"); 3178c2ecf20Sopenharmony_ci goto request_cleanup; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci cpt_req->dlen = info->dlen; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci result = (union otx_cpt_res_s *) info->completion_addr; 3228c2ecf20Sopenharmony_ci result->s.compcode = COMPLETION_CODE_INIT; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci spin_lock_bh(&pqueue->lock); 3258c2ecf20Sopenharmony_ci pentry = get_free_pending_entry(pqueue, pqueue->qlen); 3268c2ecf20Sopenharmony_ci retry = CPT_PENTRY_TIMEOUT / CPT_PENTRY_STEP; 3278c2ecf20Sopenharmony_ci while (unlikely(!pentry) && retry--) { 3288c2ecf20Sopenharmony_ci spin_unlock_bh(&pqueue->lock); 3298c2ecf20Sopenharmony_ci udelay(CPT_PENTRY_STEP); 3308c2ecf20Sopenharmony_ci spin_lock_bh(&pqueue->lock); 3318c2ecf20Sopenharmony_ci pentry = get_free_pending_entry(pqueue, pqueue->qlen); 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (unlikely(!pentry)) { 3358c2ecf20Sopenharmony_ci ret = -ENOSPC; 3368c2ecf20Sopenharmony_ci spin_unlock_bh(&pqueue->lock); 3378c2ecf20Sopenharmony_ci goto request_cleanup; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci /* 3418c2ecf20Sopenharmony_ci * Check if we are close to filling in entire pending queue, 3428c2ecf20Sopenharmony_ci * if so then tell the sender to stop/sleep by returning -EBUSY 3438c2ecf20Sopenharmony_ci * We do it only for context which can sleep (GFP_KERNEL) 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_ci if (gfp == GFP_KERNEL && 3468c2ecf20Sopenharmony_ci pqueue->pending_count > (pqueue->qlen - CPT_IQ_STOP_MARGIN)) { 3478c2ecf20Sopenharmony_ci pentry->resume_sender = true; 3488c2ecf20Sopenharmony_ci } else 3498c2ecf20Sopenharmony_ci pentry->resume_sender = false; 3508c2ecf20Sopenharmony_ci resume_sender = pentry->resume_sender; 3518c2ecf20Sopenharmony_ci pqueue->pending_count++; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci pentry->completion_addr = info->completion_addr; 3548c2ecf20Sopenharmony_ci pentry->info = info; 3558c2ecf20Sopenharmony_ci pentry->callback = req->callback; 3568c2ecf20Sopenharmony_ci pentry->areq = req->areq; 3578c2ecf20Sopenharmony_ci pentry->busy = true; 3588c2ecf20Sopenharmony_ci info->pentry = pentry; 3598c2ecf20Sopenharmony_ci info->time_in = jiffies; 3608c2ecf20Sopenharmony_ci info->req = req; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* Fill in the command */ 3638c2ecf20Sopenharmony_ci iq_cmd.cmd.u64 = 0; 3648c2ecf20Sopenharmony_ci iq_cmd.cmd.s.opcode = cpu_to_be16(cpt_req->opcode.flags); 3658c2ecf20Sopenharmony_ci iq_cmd.cmd.s.param1 = cpu_to_be16(cpt_req->param1); 3668c2ecf20Sopenharmony_ci iq_cmd.cmd.s.param2 = cpu_to_be16(cpt_req->param2); 3678c2ecf20Sopenharmony_ci iq_cmd.cmd.s.dlen = cpu_to_be16(cpt_req->dlen); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci iq_cmd.dptr = info->dptr_baddr; 3708c2ecf20Sopenharmony_ci iq_cmd.rptr = info->rptr_baddr; 3718c2ecf20Sopenharmony_ci iq_cmd.cptr.u64 = 0; 3728c2ecf20Sopenharmony_ci iq_cmd.cptr.s.grp = ctrl->s.grp; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci /* Fill in the CPT_INST_S type command for HW interpretation */ 3758c2ecf20Sopenharmony_ci cpt_fill_inst(&cptinst, info, &iq_cmd); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci /* Print debug info if enabled */ 3788c2ecf20Sopenharmony_ci otx_cpt_dump_sg_list(pdev, req); 3798c2ecf20Sopenharmony_ci pr_debug("Cpt_inst_s hexdump (%d bytes)\n", OTX_CPT_INST_SIZE); 3808c2ecf20Sopenharmony_ci print_hex_dump_debug("", 0, 16, 1, &cptinst, OTX_CPT_INST_SIZE, false); 3818c2ecf20Sopenharmony_ci pr_debug("Dptr hexdump (%d bytes)\n", cpt_req->dlen); 3828c2ecf20Sopenharmony_ci print_hex_dump_debug("", 0, 16, 1, info->in_buffer, 3838c2ecf20Sopenharmony_ci cpt_req->dlen, false); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* Send CPT command */ 3868c2ecf20Sopenharmony_ci cpt_send_cmd(&cptinst, cptvf); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* 3898c2ecf20Sopenharmony_ci * We allocate and prepare pending queue entry in critical section 3908c2ecf20Sopenharmony_ci * together with submitting CPT instruction to CPT instruction queue 3918c2ecf20Sopenharmony_ci * to make sure that order of CPT requests is the same in both 3928c2ecf20Sopenharmony_ci * pending and instruction queues 3938c2ecf20Sopenharmony_ci */ 3948c2ecf20Sopenharmony_ci spin_unlock_bh(&pqueue->lock); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci ret = resume_sender ? -EBUSY : -EINPROGRESS; 3978c2ecf20Sopenharmony_ci return ret; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cirequest_cleanup: 4008c2ecf20Sopenharmony_ci do_request_cleanup(pdev, info); 4018c2ecf20Sopenharmony_ci return ret; 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ciint otx_cpt_do_request(struct pci_dev *pdev, struct otx_cpt_req_info *req, 4058c2ecf20Sopenharmony_ci int cpu_num) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci struct otx_cptvf *cptvf = pci_get_drvdata(pdev); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (!otx_cpt_device_ready(cptvf)) { 4108c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "CPT Device is not ready\n"); 4118c2ecf20Sopenharmony_ci return -ENODEV; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if ((cptvf->vftype == OTX_CPT_SE_TYPES) && (!req->ctrl.s.se_req)) { 4158c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "CPTVF-%d of SE TYPE got AE request\n", 4168c2ecf20Sopenharmony_ci cptvf->vfid); 4178c2ecf20Sopenharmony_ci return -EINVAL; 4188c2ecf20Sopenharmony_ci } else if ((cptvf->vftype == OTX_CPT_AE_TYPES) && 4198c2ecf20Sopenharmony_ci (req->ctrl.s.se_req)) { 4208c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "CPTVF-%d of AE TYPE got SE request\n", 4218c2ecf20Sopenharmony_ci cptvf->vfid); 4228c2ecf20Sopenharmony_ci return -EINVAL; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci return process_request(pdev, req, &cptvf->pqinfo.queue[0], cptvf); 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic int cpt_process_ccode(struct pci_dev *pdev, 4298c2ecf20Sopenharmony_ci union otx_cpt_res_s *cpt_status, 4308c2ecf20Sopenharmony_ci struct otx_cpt_info_buffer *cpt_info, 4318c2ecf20Sopenharmony_ci struct otx_cpt_req_info *req, u32 *res_code) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci u8 ccode = cpt_status->s.compcode; 4348c2ecf20Sopenharmony_ci union otx_cpt_error_code ecode; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci ecode.u = be64_to_cpup((__be64 *)cpt_info->out_buffer); 4378c2ecf20Sopenharmony_ci switch (ccode) { 4388c2ecf20Sopenharmony_ci case CPT_COMP_E_FAULT: 4398c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 4408c2ecf20Sopenharmony_ci "Request failed with DMA fault\n"); 4418c2ecf20Sopenharmony_ci otx_cpt_dump_sg_list(pdev, req); 4428c2ecf20Sopenharmony_ci break; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci case CPT_COMP_E_SWERR: 4458c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 4468c2ecf20Sopenharmony_ci "Request failed with software error code %d\n", 4478c2ecf20Sopenharmony_ci ecode.s.ccode); 4488c2ecf20Sopenharmony_ci otx_cpt_dump_sg_list(pdev, req); 4498c2ecf20Sopenharmony_ci break; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci case CPT_COMP_E_HWERR: 4528c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 4538c2ecf20Sopenharmony_ci "Request failed with hardware error\n"); 4548c2ecf20Sopenharmony_ci otx_cpt_dump_sg_list(pdev, req); 4558c2ecf20Sopenharmony_ci break; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci case COMPLETION_CODE_INIT: 4588c2ecf20Sopenharmony_ci /* check for timeout */ 4598c2ecf20Sopenharmony_ci if (time_after_eq(jiffies, cpt_info->time_in + 4608c2ecf20Sopenharmony_ci OTX_CPT_COMMAND_TIMEOUT * HZ)) 4618c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "Request timed out 0x%p\n", req); 4628c2ecf20Sopenharmony_ci else if (cpt_info->extra_time < OTX_CPT_TIME_IN_RESET_COUNT) { 4638c2ecf20Sopenharmony_ci cpt_info->time_in = jiffies; 4648c2ecf20Sopenharmony_ci cpt_info->extra_time++; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci return 1; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci case CPT_COMP_E_GOOD: 4698c2ecf20Sopenharmony_ci /* Check microcode completion code */ 4708c2ecf20Sopenharmony_ci if (ecode.s.ccode) { 4718c2ecf20Sopenharmony_ci /* 4728c2ecf20Sopenharmony_ci * If requested hmac is truncated and ucode returns 4738c2ecf20Sopenharmony_ci * s/g write length error then we report success 4748c2ecf20Sopenharmony_ci * because ucode writes as many bytes of calculated 4758c2ecf20Sopenharmony_ci * hmac as available in gather buffer and reports 4768c2ecf20Sopenharmony_ci * s/g write length error if number of bytes in gather 4778c2ecf20Sopenharmony_ci * buffer is less than full hmac size. 4788c2ecf20Sopenharmony_ci */ 4798c2ecf20Sopenharmony_ci if (req->is_trunc_hmac && 4808c2ecf20Sopenharmony_ci ecode.s.ccode == ERR_SCATTER_GATHER_WRITE_LENGTH) { 4818c2ecf20Sopenharmony_ci *res_code = 0; 4828c2ecf20Sopenharmony_ci break; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 4868c2ecf20Sopenharmony_ci "Request failed with software error code 0x%x\n", 4878c2ecf20Sopenharmony_ci ecode.s.ccode); 4888c2ecf20Sopenharmony_ci otx_cpt_dump_sg_list(pdev, req); 4898c2ecf20Sopenharmony_ci break; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* Request has been processed with success */ 4938c2ecf20Sopenharmony_ci *res_code = 0; 4948c2ecf20Sopenharmony_ci break; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci default: 4978c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Request returned invalid status\n"); 4988c2ecf20Sopenharmony_ci break; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci return 0; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic inline void process_pending_queue(struct pci_dev *pdev, 5058c2ecf20Sopenharmony_ci struct otx_cpt_pending_queue *pqueue) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci void (*callback)(int status, void *arg1, void *arg2); 5088c2ecf20Sopenharmony_ci struct otx_cpt_pending_entry *resume_pentry = NULL; 5098c2ecf20Sopenharmony_ci struct otx_cpt_pending_entry *pentry = NULL; 5108c2ecf20Sopenharmony_ci struct otx_cpt_info_buffer *cpt_info = NULL; 5118c2ecf20Sopenharmony_ci union otx_cpt_res_s *cpt_status = NULL; 5128c2ecf20Sopenharmony_ci struct otx_cpt_req_info *req = NULL; 5138c2ecf20Sopenharmony_ci struct crypto_async_request *areq; 5148c2ecf20Sopenharmony_ci u32 res_code, resume_index; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci while (1) { 5178c2ecf20Sopenharmony_ci spin_lock_bh(&pqueue->lock); 5188c2ecf20Sopenharmony_ci pentry = &pqueue->head[pqueue->front]; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (WARN_ON(!pentry)) { 5218c2ecf20Sopenharmony_ci spin_unlock_bh(&pqueue->lock); 5228c2ecf20Sopenharmony_ci break; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci res_code = -EINVAL; 5268c2ecf20Sopenharmony_ci if (unlikely(!pentry->busy)) { 5278c2ecf20Sopenharmony_ci spin_unlock_bh(&pqueue->lock); 5288c2ecf20Sopenharmony_ci break; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci if (unlikely(!pentry->callback)) { 5328c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Callback NULL\n"); 5338c2ecf20Sopenharmony_ci goto process_pentry; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci cpt_info = pentry->info; 5378c2ecf20Sopenharmony_ci if (unlikely(!cpt_info)) { 5388c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Pending entry post arg NULL\n"); 5398c2ecf20Sopenharmony_ci goto process_pentry; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci req = cpt_info->req; 5438c2ecf20Sopenharmony_ci if (unlikely(!req)) { 5448c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Request NULL\n"); 5458c2ecf20Sopenharmony_ci goto process_pentry; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci cpt_status = (union otx_cpt_res_s *) pentry->completion_addr; 5498c2ecf20Sopenharmony_ci if (unlikely(!cpt_status)) { 5508c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Completion address NULL\n"); 5518c2ecf20Sopenharmony_ci goto process_pentry; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (cpt_process_ccode(pdev, cpt_status, cpt_info, req, 5558c2ecf20Sopenharmony_ci &res_code)) { 5568c2ecf20Sopenharmony_ci spin_unlock_bh(&pqueue->lock); 5578c2ecf20Sopenharmony_ci return; 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci cpt_info->pdev = pdev; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ciprocess_pentry: 5628c2ecf20Sopenharmony_ci /* 5638c2ecf20Sopenharmony_ci * Check if we should inform sending side to resume 5648c2ecf20Sopenharmony_ci * We do it CPT_IQ_RESUME_MARGIN elements in advance before 5658c2ecf20Sopenharmony_ci * pending queue becomes empty 5668c2ecf20Sopenharmony_ci */ 5678c2ecf20Sopenharmony_ci resume_index = modulo_inc(pqueue->front, pqueue->qlen, 5688c2ecf20Sopenharmony_ci CPT_IQ_RESUME_MARGIN); 5698c2ecf20Sopenharmony_ci resume_pentry = &pqueue->head[resume_index]; 5708c2ecf20Sopenharmony_ci if (resume_pentry && 5718c2ecf20Sopenharmony_ci resume_pentry->resume_sender) { 5728c2ecf20Sopenharmony_ci resume_pentry->resume_sender = false; 5738c2ecf20Sopenharmony_ci callback = resume_pentry->callback; 5748c2ecf20Sopenharmony_ci areq = resume_pentry->areq; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (callback) { 5778c2ecf20Sopenharmony_ci spin_unlock_bh(&pqueue->lock); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /* 5808c2ecf20Sopenharmony_ci * EINPROGRESS is an indication for sending 5818c2ecf20Sopenharmony_ci * side that it can resume sending requests 5828c2ecf20Sopenharmony_ci */ 5838c2ecf20Sopenharmony_ci callback(-EINPROGRESS, areq, cpt_info); 5848c2ecf20Sopenharmony_ci spin_lock_bh(&pqueue->lock); 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci callback = pentry->callback; 5898c2ecf20Sopenharmony_ci areq = pentry->areq; 5908c2ecf20Sopenharmony_ci free_pentry(pentry); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci pqueue->pending_count--; 5938c2ecf20Sopenharmony_ci pqueue->front = modulo_inc(pqueue->front, pqueue->qlen, 1); 5948c2ecf20Sopenharmony_ci spin_unlock_bh(&pqueue->lock); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* 5978c2ecf20Sopenharmony_ci * Call callback after current pending entry has been 5988c2ecf20Sopenharmony_ci * processed, we don't do it if the callback pointer is 5998c2ecf20Sopenharmony_ci * invalid. 6008c2ecf20Sopenharmony_ci */ 6018c2ecf20Sopenharmony_ci if (callback) 6028c2ecf20Sopenharmony_ci callback(res_code, areq, cpt_info); 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_civoid otx_cpt_post_process(struct otx_cptvf_wqe *wqe) 6078c2ecf20Sopenharmony_ci{ 6088c2ecf20Sopenharmony_ci process_pending_queue(wqe->cptvf->pdev, &wqe->cptvf->pqinfo.queue[0]); 6098c2ecf20Sopenharmony_ci} 610