18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Cavium, Inc. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include "cptvf.h" 78c2ecf20Sopenharmony_ci#include "cptvf_algs.h" 88c2ecf20Sopenharmony_ci#include "request_manager.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/** 118c2ecf20Sopenharmony_ci * get_free_pending_entry - get free entry from pending queue 128c2ecf20Sopenharmony_ci * @param pqinfo: pending_qinfo structure 138c2ecf20Sopenharmony_ci * @param qno: queue number 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_cistatic struct pending_entry *get_free_pending_entry(struct pending_queue *q, 168c2ecf20Sopenharmony_ci int qlen) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci struct pending_entry *ent = NULL; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci ent = &q->head[q->rear]; 218c2ecf20Sopenharmony_ci if (unlikely(ent->busy)) { 228c2ecf20Sopenharmony_ci ent = NULL; 238c2ecf20Sopenharmony_ci goto no_free_entry; 248c2ecf20Sopenharmony_ci } 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci q->rear++; 278c2ecf20Sopenharmony_ci if (unlikely(q->rear == qlen)) 288c2ecf20Sopenharmony_ci q->rear = 0; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cino_free_entry: 318c2ecf20Sopenharmony_ci return ent; 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic inline void pending_queue_inc_front(struct pending_qinfo *pqinfo, 358c2ecf20Sopenharmony_ci int qno) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci struct pending_queue *queue = &pqinfo->queue[qno]; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci queue->front++; 408c2ecf20Sopenharmony_ci if (unlikely(queue->front == pqinfo->qlen)) 418c2ecf20Sopenharmony_ci queue->front = 0; 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic int setup_sgio_components(struct cpt_vf *cptvf, struct buf_ptr *list, 458c2ecf20Sopenharmony_ci int buf_count, u8 *buffer) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci int ret = 0, i, j; 488c2ecf20Sopenharmony_ci int components; 498c2ecf20Sopenharmony_ci struct sglist_component *sg_ptr = NULL; 508c2ecf20Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (unlikely(!list)) { 538c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Input List pointer is NULL\n"); 548c2ecf20Sopenharmony_ci return -EFAULT; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci for (i = 0; i < buf_count; i++) { 588c2ecf20Sopenharmony_ci if (likely(list[i].vptr)) { 598c2ecf20Sopenharmony_ci list[i].dma_addr = dma_map_single(&pdev->dev, 608c2ecf20Sopenharmony_ci list[i].vptr, 618c2ecf20Sopenharmony_ci list[i].size, 628c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 638c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(&pdev->dev, 648c2ecf20Sopenharmony_ci list[i].dma_addr))) { 658c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "DMA map kernel buffer failed for component: %d\n", 668c2ecf20Sopenharmony_ci i); 678c2ecf20Sopenharmony_ci ret = -EIO; 688c2ecf20Sopenharmony_ci goto sg_cleanup; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci components = buf_count / 4; 748c2ecf20Sopenharmony_ci sg_ptr = (struct sglist_component *)buffer; 758c2ecf20Sopenharmony_ci for (i = 0; i < components; i++) { 768c2ecf20Sopenharmony_ci sg_ptr->u.s.len0 = cpu_to_be16(list[i * 4 + 0].size); 778c2ecf20Sopenharmony_ci sg_ptr->u.s.len1 = cpu_to_be16(list[i * 4 + 1].size); 788c2ecf20Sopenharmony_ci sg_ptr->u.s.len2 = cpu_to_be16(list[i * 4 + 2].size); 798c2ecf20Sopenharmony_ci sg_ptr->u.s.len3 = cpu_to_be16(list[i * 4 + 3].size); 808c2ecf20Sopenharmony_ci sg_ptr->ptr0 = cpu_to_be64(list[i * 4 + 0].dma_addr); 818c2ecf20Sopenharmony_ci sg_ptr->ptr1 = cpu_to_be64(list[i * 4 + 1].dma_addr); 828c2ecf20Sopenharmony_ci sg_ptr->ptr2 = cpu_to_be64(list[i * 4 + 2].dma_addr); 838c2ecf20Sopenharmony_ci sg_ptr->ptr3 = cpu_to_be64(list[i * 4 + 3].dma_addr); 848c2ecf20Sopenharmony_ci sg_ptr++; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci components = buf_count % 4; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci switch (components) { 908c2ecf20Sopenharmony_ci case 3: 918c2ecf20Sopenharmony_ci sg_ptr->u.s.len2 = cpu_to_be16(list[i * 4 + 2].size); 928c2ecf20Sopenharmony_ci sg_ptr->ptr2 = cpu_to_be64(list[i * 4 + 2].dma_addr); 938c2ecf20Sopenharmony_ci fallthrough; 948c2ecf20Sopenharmony_ci case 2: 958c2ecf20Sopenharmony_ci sg_ptr->u.s.len1 = cpu_to_be16(list[i * 4 + 1].size); 968c2ecf20Sopenharmony_ci sg_ptr->ptr1 = cpu_to_be64(list[i * 4 + 1].dma_addr); 978c2ecf20Sopenharmony_ci fallthrough; 988c2ecf20Sopenharmony_ci case 1: 998c2ecf20Sopenharmony_ci sg_ptr->u.s.len0 = cpu_to_be16(list[i * 4 + 0].size); 1008c2ecf20Sopenharmony_ci sg_ptr->ptr0 = cpu_to_be64(list[i * 4 + 0].dma_addr); 1018c2ecf20Sopenharmony_ci break; 1028c2ecf20Sopenharmony_ci default: 1038c2ecf20Sopenharmony_ci break; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return ret; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cisg_cleanup: 1098c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) { 1108c2ecf20Sopenharmony_ci if (list[j].dma_addr) { 1118c2ecf20Sopenharmony_ci dma_unmap_single(&pdev->dev, list[i].dma_addr, 1128c2ecf20Sopenharmony_ci list[i].size, DMA_BIDIRECTIONAL); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci list[j].dma_addr = 0; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci return ret; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic inline int setup_sgio_list(struct cpt_vf *cptvf, 1228c2ecf20Sopenharmony_ci struct cpt_info_buffer *info, 1238c2ecf20Sopenharmony_ci struct cpt_request_info *req) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci u16 g_sz_bytes = 0, s_sz_bytes = 0; 1268c2ecf20Sopenharmony_ci int ret = 0; 1278c2ecf20Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (req->incnt > MAX_SG_IN_CNT || req->outcnt > MAX_SG_OUT_CNT) { 1308c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Request SG components are higher than supported\n"); 1318c2ecf20Sopenharmony_ci ret = -EINVAL; 1328c2ecf20Sopenharmony_ci goto scatter_gather_clean; 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* Setup gather (input) components */ 1368c2ecf20Sopenharmony_ci g_sz_bytes = ((req->incnt + 3) / 4) * sizeof(struct sglist_component); 1378c2ecf20Sopenharmony_ci info->gather_components = kzalloc(g_sz_bytes, req->may_sleep ? GFP_KERNEL : GFP_ATOMIC); 1388c2ecf20Sopenharmony_ci if (!info->gather_components) { 1398c2ecf20Sopenharmony_ci ret = -ENOMEM; 1408c2ecf20Sopenharmony_ci goto scatter_gather_clean; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci ret = setup_sgio_components(cptvf, req->in, 1448c2ecf20Sopenharmony_ci req->incnt, 1458c2ecf20Sopenharmony_ci info->gather_components); 1468c2ecf20Sopenharmony_ci if (ret) { 1478c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to setup gather list\n"); 1488c2ecf20Sopenharmony_ci ret = -EFAULT; 1498c2ecf20Sopenharmony_ci goto scatter_gather_clean; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* Setup scatter (output) components */ 1538c2ecf20Sopenharmony_ci s_sz_bytes = ((req->outcnt + 3) / 4) * sizeof(struct sglist_component); 1548c2ecf20Sopenharmony_ci info->scatter_components = kzalloc(s_sz_bytes, req->may_sleep ? GFP_KERNEL : GFP_ATOMIC); 1558c2ecf20Sopenharmony_ci if (!info->scatter_components) { 1568c2ecf20Sopenharmony_ci ret = -ENOMEM; 1578c2ecf20Sopenharmony_ci goto scatter_gather_clean; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci ret = setup_sgio_components(cptvf, req->out, 1618c2ecf20Sopenharmony_ci req->outcnt, 1628c2ecf20Sopenharmony_ci info->scatter_components); 1638c2ecf20Sopenharmony_ci if (ret) { 1648c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to setup gather list\n"); 1658c2ecf20Sopenharmony_ci ret = -EFAULT; 1668c2ecf20Sopenharmony_ci goto scatter_gather_clean; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* Create and initialize DPTR */ 1708c2ecf20Sopenharmony_ci info->dlen = g_sz_bytes + s_sz_bytes + SG_LIST_HDR_SIZE; 1718c2ecf20Sopenharmony_ci info->in_buffer = kzalloc(info->dlen, req->may_sleep ? GFP_KERNEL : GFP_ATOMIC); 1728c2ecf20Sopenharmony_ci if (!info->in_buffer) { 1738c2ecf20Sopenharmony_ci ret = -ENOMEM; 1748c2ecf20Sopenharmony_ci goto scatter_gather_clean; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci ((__be16 *)info->in_buffer)[0] = cpu_to_be16(req->outcnt); 1788c2ecf20Sopenharmony_ci ((__be16 *)info->in_buffer)[1] = cpu_to_be16(req->incnt); 1798c2ecf20Sopenharmony_ci ((__be16 *)info->in_buffer)[2] = 0; 1808c2ecf20Sopenharmony_ci ((__be16 *)info->in_buffer)[3] = 0; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci memcpy(&info->in_buffer[8], info->gather_components, 1838c2ecf20Sopenharmony_ci g_sz_bytes); 1848c2ecf20Sopenharmony_ci memcpy(&info->in_buffer[8 + g_sz_bytes], 1858c2ecf20Sopenharmony_ci info->scatter_components, s_sz_bytes); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci info->dptr_baddr = dma_map_single(&pdev->dev, 1888c2ecf20Sopenharmony_ci (void *)info->in_buffer, 1898c2ecf20Sopenharmony_ci info->dlen, 1908c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 1918c2ecf20Sopenharmony_ci if (dma_mapping_error(&pdev->dev, info->dptr_baddr)) { 1928c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Mapping DPTR Failed %d\n", info->dlen); 1938c2ecf20Sopenharmony_ci ret = -EIO; 1948c2ecf20Sopenharmony_ci goto scatter_gather_clean; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* Create and initialize RPTR */ 1988c2ecf20Sopenharmony_ci info->out_buffer = kzalloc(COMPLETION_CODE_SIZE, req->may_sleep ? GFP_KERNEL : GFP_ATOMIC); 1998c2ecf20Sopenharmony_ci if (!info->out_buffer) { 2008c2ecf20Sopenharmony_ci ret = -ENOMEM; 2018c2ecf20Sopenharmony_ci goto scatter_gather_clean; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci *((u64 *)info->out_buffer) = ~((u64)COMPLETION_CODE_INIT); 2058c2ecf20Sopenharmony_ci info->alternate_caddr = (u64 *)info->out_buffer; 2068c2ecf20Sopenharmony_ci info->rptr_baddr = dma_map_single(&pdev->dev, 2078c2ecf20Sopenharmony_ci (void *)info->out_buffer, 2088c2ecf20Sopenharmony_ci COMPLETION_CODE_SIZE, 2098c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 2108c2ecf20Sopenharmony_ci if (dma_mapping_error(&pdev->dev, info->rptr_baddr)) { 2118c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Mapping RPTR Failed %d\n", 2128c2ecf20Sopenharmony_ci COMPLETION_CODE_SIZE); 2138c2ecf20Sopenharmony_ci ret = -EIO; 2148c2ecf20Sopenharmony_ci goto scatter_gather_clean; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci return 0; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ciscatter_gather_clean: 2208c2ecf20Sopenharmony_ci return ret; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic int send_cpt_command(struct cpt_vf *cptvf, union cpt_inst_s *cmd, 2248c2ecf20Sopenharmony_ci u32 qno) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 2278c2ecf20Sopenharmony_ci struct command_qinfo *qinfo = NULL; 2288c2ecf20Sopenharmony_ci struct command_queue *queue; 2298c2ecf20Sopenharmony_ci struct command_chunk *chunk; 2308c2ecf20Sopenharmony_ci u8 *ent; 2318c2ecf20Sopenharmony_ci int ret = 0; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if (unlikely(qno >= cptvf->nr_queues)) { 2348c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Invalid queue (qno: %d, nr_queues: %d)\n", 2358c2ecf20Sopenharmony_ci qno, cptvf->nr_queues); 2368c2ecf20Sopenharmony_ci return -EINVAL; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci qinfo = &cptvf->cqinfo; 2408c2ecf20Sopenharmony_ci queue = &qinfo->queue[qno]; 2418c2ecf20Sopenharmony_ci /* lock commad queue */ 2428c2ecf20Sopenharmony_ci spin_lock(&queue->lock); 2438c2ecf20Sopenharmony_ci ent = &queue->qhead->head[queue->idx * qinfo->cmd_size]; 2448c2ecf20Sopenharmony_ci memcpy(ent, (void *)cmd, qinfo->cmd_size); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (++queue->idx >= queue->qhead->size / 64) { 2478c2ecf20Sopenharmony_ci struct hlist_node *node; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci hlist_for_each(node, &queue->chead) { 2508c2ecf20Sopenharmony_ci chunk = hlist_entry(node, struct command_chunk, 2518c2ecf20Sopenharmony_ci nextchunk); 2528c2ecf20Sopenharmony_ci if (chunk == queue->qhead) { 2538c2ecf20Sopenharmony_ci continue; 2548c2ecf20Sopenharmony_ci } else { 2558c2ecf20Sopenharmony_ci queue->qhead = chunk; 2568c2ecf20Sopenharmony_ci break; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci queue->idx = 0; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci /* make sure all memory stores are done before ringing doorbell */ 2628c2ecf20Sopenharmony_ci smp_wmb(); 2638c2ecf20Sopenharmony_ci cptvf_write_vq_doorbell(cptvf, 1); 2648c2ecf20Sopenharmony_ci /* unlock command queue */ 2658c2ecf20Sopenharmony_ci spin_unlock(&queue->lock); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci return ret; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic void do_request_cleanup(struct cpt_vf *cptvf, 2718c2ecf20Sopenharmony_ci struct cpt_info_buffer *info) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci int i; 2748c2ecf20Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 2758c2ecf20Sopenharmony_ci struct cpt_request_info *req; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (info->dptr_baddr) 2788c2ecf20Sopenharmony_ci dma_unmap_single(&pdev->dev, info->dptr_baddr, 2798c2ecf20Sopenharmony_ci info->dlen, DMA_BIDIRECTIONAL); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (info->rptr_baddr) 2828c2ecf20Sopenharmony_ci dma_unmap_single(&pdev->dev, info->rptr_baddr, 2838c2ecf20Sopenharmony_ci COMPLETION_CODE_SIZE, DMA_BIDIRECTIONAL); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (info->comp_baddr) 2868c2ecf20Sopenharmony_ci dma_unmap_single(&pdev->dev, info->comp_baddr, 2878c2ecf20Sopenharmony_ci sizeof(union cpt_res_s), DMA_BIDIRECTIONAL); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (info->req) { 2908c2ecf20Sopenharmony_ci req = info->req; 2918c2ecf20Sopenharmony_ci for (i = 0; i < req->outcnt; i++) { 2928c2ecf20Sopenharmony_ci if (req->out[i].dma_addr) 2938c2ecf20Sopenharmony_ci dma_unmap_single(&pdev->dev, 2948c2ecf20Sopenharmony_ci req->out[i].dma_addr, 2958c2ecf20Sopenharmony_ci req->out[i].size, 2968c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci for (i = 0; i < req->incnt; i++) { 3008c2ecf20Sopenharmony_ci if (req->in[i].dma_addr) 3018c2ecf20Sopenharmony_ci dma_unmap_single(&pdev->dev, 3028c2ecf20Sopenharmony_ci req->in[i].dma_addr, 3038c2ecf20Sopenharmony_ci req->in[i].size, 3048c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci kfree_sensitive(info->scatter_components); 3098c2ecf20Sopenharmony_ci kfree_sensitive(info->gather_components); 3108c2ecf20Sopenharmony_ci kfree_sensitive(info->out_buffer); 3118c2ecf20Sopenharmony_ci kfree_sensitive(info->in_buffer); 3128c2ecf20Sopenharmony_ci kfree_sensitive((void *)info->completion_addr); 3138c2ecf20Sopenharmony_ci kfree_sensitive(info); 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic void do_post_process(struct cpt_vf *cptvf, struct cpt_info_buffer *info) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (!info) { 3218c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "incorrect cpt_info_buffer for post processing\n"); 3228c2ecf20Sopenharmony_ci return; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci do_request_cleanup(cptvf, info); 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic inline void process_pending_queue(struct cpt_vf *cptvf, 3298c2ecf20Sopenharmony_ci struct pending_qinfo *pqinfo, 3308c2ecf20Sopenharmony_ci int qno) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 3338c2ecf20Sopenharmony_ci struct pending_queue *pqueue = &pqinfo->queue[qno]; 3348c2ecf20Sopenharmony_ci struct pending_entry *pentry = NULL; 3358c2ecf20Sopenharmony_ci struct cpt_info_buffer *info = NULL; 3368c2ecf20Sopenharmony_ci union cpt_res_s *status = NULL; 3378c2ecf20Sopenharmony_ci unsigned char ccode; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci while (1) { 3408c2ecf20Sopenharmony_ci spin_lock_bh(&pqueue->lock); 3418c2ecf20Sopenharmony_ci pentry = &pqueue->head[pqueue->front]; 3428c2ecf20Sopenharmony_ci if (unlikely(!pentry->busy)) { 3438c2ecf20Sopenharmony_ci spin_unlock_bh(&pqueue->lock); 3448c2ecf20Sopenharmony_ci break; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci info = (struct cpt_info_buffer *)pentry->post_arg; 3488c2ecf20Sopenharmony_ci if (unlikely(!info)) { 3498c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Pending Entry post arg NULL\n"); 3508c2ecf20Sopenharmony_ci pending_queue_inc_front(pqinfo, qno); 3518c2ecf20Sopenharmony_ci spin_unlock_bh(&pqueue->lock); 3528c2ecf20Sopenharmony_ci continue; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci status = (union cpt_res_s *)pentry->completion_addr; 3568c2ecf20Sopenharmony_ci ccode = status->s.compcode; 3578c2ecf20Sopenharmony_ci if ((status->s.compcode == CPT_COMP_E_FAULT) || 3588c2ecf20Sopenharmony_ci (status->s.compcode == CPT_COMP_E_SWERR)) { 3598c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Request failed with %s\n", 3608c2ecf20Sopenharmony_ci (status->s.compcode == CPT_COMP_E_FAULT) ? 3618c2ecf20Sopenharmony_ci "DMA Fault" : "Software error"); 3628c2ecf20Sopenharmony_ci pentry->completion_addr = NULL; 3638c2ecf20Sopenharmony_ci pentry->busy = false; 3648c2ecf20Sopenharmony_ci atomic64_dec((&pqueue->pending_count)); 3658c2ecf20Sopenharmony_ci pentry->post_arg = NULL; 3668c2ecf20Sopenharmony_ci pending_queue_inc_front(pqinfo, qno); 3678c2ecf20Sopenharmony_ci do_request_cleanup(cptvf, info); 3688c2ecf20Sopenharmony_ci spin_unlock_bh(&pqueue->lock); 3698c2ecf20Sopenharmony_ci break; 3708c2ecf20Sopenharmony_ci } else if (status->s.compcode == COMPLETION_CODE_INIT) { 3718c2ecf20Sopenharmony_ci /* check for timeout */ 3728c2ecf20Sopenharmony_ci if (time_after_eq(jiffies, 3738c2ecf20Sopenharmony_ci (info->time_in + 3748c2ecf20Sopenharmony_ci (CPT_COMMAND_TIMEOUT * HZ)))) { 3758c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Request timed out"); 3768c2ecf20Sopenharmony_ci pentry->completion_addr = NULL; 3778c2ecf20Sopenharmony_ci pentry->busy = false; 3788c2ecf20Sopenharmony_ci atomic64_dec((&pqueue->pending_count)); 3798c2ecf20Sopenharmony_ci pentry->post_arg = NULL; 3808c2ecf20Sopenharmony_ci pending_queue_inc_front(pqinfo, qno); 3818c2ecf20Sopenharmony_ci do_request_cleanup(cptvf, info); 3828c2ecf20Sopenharmony_ci spin_unlock_bh(&pqueue->lock); 3838c2ecf20Sopenharmony_ci break; 3848c2ecf20Sopenharmony_ci } else if ((*info->alternate_caddr == 3858c2ecf20Sopenharmony_ci (~COMPLETION_CODE_INIT)) && 3868c2ecf20Sopenharmony_ci (info->extra_time < TIME_IN_RESET_COUNT)) { 3878c2ecf20Sopenharmony_ci info->time_in = jiffies; 3888c2ecf20Sopenharmony_ci info->extra_time++; 3898c2ecf20Sopenharmony_ci spin_unlock_bh(&pqueue->lock); 3908c2ecf20Sopenharmony_ci break; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci pentry->completion_addr = NULL; 3958c2ecf20Sopenharmony_ci pentry->busy = false; 3968c2ecf20Sopenharmony_ci pentry->post_arg = NULL; 3978c2ecf20Sopenharmony_ci atomic64_dec((&pqueue->pending_count)); 3988c2ecf20Sopenharmony_ci pending_queue_inc_front(pqinfo, qno); 3998c2ecf20Sopenharmony_ci spin_unlock_bh(&pqueue->lock); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci do_post_process(info->cptvf, info); 4028c2ecf20Sopenharmony_ci /* 4038c2ecf20Sopenharmony_ci * Calling callback after we find 4048c2ecf20Sopenharmony_ci * that the request has been serviced 4058c2ecf20Sopenharmony_ci */ 4068c2ecf20Sopenharmony_ci pentry->callback(ccode, pentry->callback_arg); 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ciint process_request(struct cpt_vf *cptvf, struct cpt_request_info *req) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci int ret = 0, clear = 0, queue = 0; 4138c2ecf20Sopenharmony_ci struct cpt_info_buffer *info = NULL; 4148c2ecf20Sopenharmony_ci struct cptvf_request *cpt_req = NULL; 4158c2ecf20Sopenharmony_ci union ctrl_info *ctrl = NULL; 4168c2ecf20Sopenharmony_ci union cpt_res_s *result = NULL; 4178c2ecf20Sopenharmony_ci struct pending_entry *pentry = NULL; 4188c2ecf20Sopenharmony_ci struct pending_queue *pqueue = NULL; 4198c2ecf20Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 4208c2ecf20Sopenharmony_ci u8 group = 0; 4218c2ecf20Sopenharmony_ci struct cpt_vq_command vq_cmd; 4228c2ecf20Sopenharmony_ci union cpt_inst_s cptinst; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci info = kzalloc(sizeof(*info), req->may_sleep ? GFP_KERNEL : GFP_ATOMIC); 4258c2ecf20Sopenharmony_ci if (unlikely(!info)) { 4268c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unable to allocate memory for info_buffer\n"); 4278c2ecf20Sopenharmony_ci return -ENOMEM; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci cpt_req = (struct cptvf_request *)&req->req; 4318c2ecf20Sopenharmony_ci ctrl = (union ctrl_info *)&req->ctrl; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci info->cptvf = cptvf; 4348c2ecf20Sopenharmony_ci group = ctrl->s.grp; 4358c2ecf20Sopenharmony_ci ret = setup_sgio_list(cptvf, info, req); 4368c2ecf20Sopenharmony_ci if (ret) { 4378c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Setting up SG list failed"); 4388c2ecf20Sopenharmony_ci goto request_cleanup; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci cpt_req->dlen = info->dlen; 4428c2ecf20Sopenharmony_ci /* 4438c2ecf20Sopenharmony_ci * Get buffer for union cpt_res_s response 4448c2ecf20Sopenharmony_ci * structure and its physical address 4458c2ecf20Sopenharmony_ci */ 4468c2ecf20Sopenharmony_ci info->completion_addr = kzalloc(sizeof(union cpt_res_s), req->may_sleep ? GFP_KERNEL : GFP_ATOMIC); 4478c2ecf20Sopenharmony_ci if (unlikely(!info->completion_addr)) { 4488c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unable to allocate memory for completion_addr\n"); 4498c2ecf20Sopenharmony_ci ret = -ENOMEM; 4508c2ecf20Sopenharmony_ci goto request_cleanup; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci result = (union cpt_res_s *)info->completion_addr; 4548c2ecf20Sopenharmony_ci result->s.compcode = COMPLETION_CODE_INIT; 4558c2ecf20Sopenharmony_ci info->comp_baddr = dma_map_single(&pdev->dev, 4568c2ecf20Sopenharmony_ci (void *)info->completion_addr, 4578c2ecf20Sopenharmony_ci sizeof(union cpt_res_s), 4588c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 4598c2ecf20Sopenharmony_ci if (dma_mapping_error(&pdev->dev, info->comp_baddr)) { 4608c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "mapping compptr Failed %lu\n", 4618c2ecf20Sopenharmony_ci sizeof(union cpt_res_s)); 4628c2ecf20Sopenharmony_ci ret = -EFAULT; 4638c2ecf20Sopenharmony_ci goto request_cleanup; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* Fill the VQ command */ 4678c2ecf20Sopenharmony_ci vq_cmd.cmd.u64 = 0; 4688c2ecf20Sopenharmony_ci vq_cmd.cmd.s.opcode = cpu_to_be16(cpt_req->opcode.flags); 4698c2ecf20Sopenharmony_ci vq_cmd.cmd.s.param1 = cpu_to_be16(cpt_req->param1); 4708c2ecf20Sopenharmony_ci vq_cmd.cmd.s.param2 = cpu_to_be16(cpt_req->param2); 4718c2ecf20Sopenharmony_ci vq_cmd.cmd.s.dlen = cpu_to_be16(cpt_req->dlen); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci vq_cmd.dptr = info->dptr_baddr; 4748c2ecf20Sopenharmony_ci vq_cmd.rptr = info->rptr_baddr; 4758c2ecf20Sopenharmony_ci vq_cmd.cptr.u64 = 0; 4768c2ecf20Sopenharmony_ci vq_cmd.cptr.s.grp = group; 4778c2ecf20Sopenharmony_ci /* Get Pending Entry to submit command */ 4788c2ecf20Sopenharmony_ci /* Always queue 0, because 1 queue per VF */ 4798c2ecf20Sopenharmony_ci queue = 0; 4808c2ecf20Sopenharmony_ci pqueue = &cptvf->pqinfo.queue[queue]; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (atomic64_read(&pqueue->pending_count) > PENDING_THOLD) { 4838c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "pending threshold reached\n"); 4848c2ecf20Sopenharmony_ci process_pending_queue(cptvf, &cptvf->pqinfo, queue); 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ciget_pending_entry: 4888c2ecf20Sopenharmony_ci spin_lock_bh(&pqueue->lock); 4898c2ecf20Sopenharmony_ci pentry = get_free_pending_entry(pqueue, cptvf->pqinfo.qlen); 4908c2ecf20Sopenharmony_ci if (unlikely(!pentry)) { 4918c2ecf20Sopenharmony_ci spin_unlock_bh(&pqueue->lock); 4928c2ecf20Sopenharmony_ci if (clear == 0) { 4938c2ecf20Sopenharmony_ci process_pending_queue(cptvf, &cptvf->pqinfo, queue); 4948c2ecf20Sopenharmony_ci clear = 1; 4958c2ecf20Sopenharmony_ci goto get_pending_entry; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Get free entry failed\n"); 4988c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "queue: %d, rear: %d, front: %d\n", 4998c2ecf20Sopenharmony_ci queue, pqueue->rear, pqueue->front); 5008c2ecf20Sopenharmony_ci ret = -EFAULT; 5018c2ecf20Sopenharmony_ci goto request_cleanup; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci pentry->completion_addr = info->completion_addr; 5058c2ecf20Sopenharmony_ci pentry->post_arg = (void *)info; 5068c2ecf20Sopenharmony_ci pentry->callback = req->callback; 5078c2ecf20Sopenharmony_ci pentry->callback_arg = req->callback_arg; 5088c2ecf20Sopenharmony_ci info->pentry = pentry; 5098c2ecf20Sopenharmony_ci pentry->busy = true; 5108c2ecf20Sopenharmony_ci atomic64_inc(&pqueue->pending_count); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci /* Send CPT command */ 5138c2ecf20Sopenharmony_ci info->pentry = pentry; 5148c2ecf20Sopenharmony_ci info->time_in = jiffies; 5158c2ecf20Sopenharmony_ci info->req = req; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci /* Create the CPT_INST_S type command for HW intrepretation */ 5188c2ecf20Sopenharmony_ci cptinst.s.doneint = true; 5198c2ecf20Sopenharmony_ci cptinst.s.res_addr = (u64)info->comp_baddr; 5208c2ecf20Sopenharmony_ci cptinst.s.tag = 0; 5218c2ecf20Sopenharmony_ci cptinst.s.grp = 0; 5228c2ecf20Sopenharmony_ci cptinst.s.wq_ptr = 0; 5238c2ecf20Sopenharmony_ci cptinst.s.ei0 = vq_cmd.cmd.u64; 5248c2ecf20Sopenharmony_ci cptinst.s.ei1 = vq_cmd.dptr; 5258c2ecf20Sopenharmony_ci cptinst.s.ei2 = vq_cmd.rptr; 5268c2ecf20Sopenharmony_ci cptinst.s.ei3 = vq_cmd.cptr.u64; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci ret = send_cpt_command(cptvf, &cptinst, queue); 5298c2ecf20Sopenharmony_ci spin_unlock_bh(&pqueue->lock); 5308c2ecf20Sopenharmony_ci if (unlikely(ret)) { 5318c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Send command failed for AE\n"); 5328c2ecf20Sopenharmony_ci ret = -EFAULT; 5338c2ecf20Sopenharmony_ci goto request_cleanup; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci return 0; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cirequest_cleanup: 5398c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "Failed to submit CPT command\n"); 5408c2ecf20Sopenharmony_ci do_request_cleanup(cptvf, info); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci return ret; 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_civoid vq_post_process(struct cpt_vf *cptvf, u32 qno) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (unlikely(qno > cptvf->nr_queues)) { 5508c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Request for post processing on invalid pending queue: %u\n", 5518c2ecf20Sopenharmony_ci qno); 5528c2ecf20Sopenharmony_ci return; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci process_pending_queue(cptvf, &cptvf->pqinfo, qno); 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ciint cptvf_do_request(void *vfdev, struct cpt_request_info *req) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci struct cpt_vf *cptvf = (struct cpt_vf *)vfdev; 5618c2ecf20Sopenharmony_ci struct pci_dev *pdev = cptvf->pdev; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci if (!cpt_device_ready(cptvf)) { 5648c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "CPT Device is not ready"); 5658c2ecf20Sopenharmony_ci return -ENODEV; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci if ((cptvf->vftype == SE_TYPES) && (!req->ctrl.s.se_req)) { 5698c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "CPTVF-%d of SE TYPE got AE request", 5708c2ecf20Sopenharmony_ci cptvf->vfid); 5718c2ecf20Sopenharmony_ci return -EINVAL; 5728c2ecf20Sopenharmony_ci } else if ((cptvf->vftype == AE_TYPES) && (req->ctrl.s.se_req)) { 5738c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "CPTVF-%d of AE TYPE got SE request", 5748c2ecf20Sopenharmony_ci cptvf->vfid); 5758c2ecf20Sopenharmony_ci return -EINVAL; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci return process_request(cptvf, req); 5798c2ecf20Sopenharmony_ci} 580