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