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