162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/gfp.h>
362306a36Sopenharmony_ci#include <linux/workqueue.h>
462306a36Sopenharmony_ci#include <crypto/internal/skcipher.h>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "nitrox_common.h"
762306a36Sopenharmony_ci#include "nitrox_dev.h"
862306a36Sopenharmony_ci#include "nitrox_req.h"
962306a36Sopenharmony_ci#include "nitrox_csr.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/* SLC_STORE_INFO */
1262306a36Sopenharmony_ci#define MIN_UDD_LEN 16
1362306a36Sopenharmony_ci/* PKT_IN_HDR + SLC_STORE_INFO */
1462306a36Sopenharmony_ci#define FDATA_SIZE 32
1562306a36Sopenharmony_ci/* Base destination port for the solicited requests */
1662306a36Sopenharmony_ci#define SOLICIT_BASE_DPORT 256
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define REQ_NOT_POSTED 1
1962306a36Sopenharmony_ci#define REQ_BACKLOG    2
2062306a36Sopenharmony_ci#define REQ_POSTED     3
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/*
2362306a36Sopenharmony_ci * Response codes from SE microcode
2462306a36Sopenharmony_ci * 0x00 - Success
2562306a36Sopenharmony_ci *   Completion with no error
2662306a36Sopenharmony_ci * 0x43 - ERR_GC_DATA_LEN_INVALID
2762306a36Sopenharmony_ci *   Invalid Data length if Encryption Data length is
2862306a36Sopenharmony_ci *   less than 16 bytes for AES-XTS and AES-CTS.
2962306a36Sopenharmony_ci * 0x45 - ERR_GC_CTX_LEN_INVALID
3062306a36Sopenharmony_ci *   Invalid context length: CTXL != 23 words.
3162306a36Sopenharmony_ci * 0x4F - ERR_GC_DOCSIS_CIPHER_INVALID
3262306a36Sopenharmony_ci *   DOCSIS support is enabled with other than
3362306a36Sopenharmony_ci *   AES/DES-CBC mode encryption.
3462306a36Sopenharmony_ci * 0x50 - ERR_GC_DOCSIS_OFFSET_INVALID
3562306a36Sopenharmony_ci *   Authentication offset is other than 0 with
3662306a36Sopenharmony_ci *   Encryption IV source = 0.
3762306a36Sopenharmony_ci *   Authentication offset is other than 8 (DES)/16 (AES)
3862306a36Sopenharmony_ci *   with Encryption IV source = 1
3962306a36Sopenharmony_ci * 0x51 - ERR_GC_CRC32_INVALID_SELECTION
4062306a36Sopenharmony_ci *   CRC32 is enabled for other than DOCSIS encryption.
4162306a36Sopenharmony_ci * 0x52 - ERR_GC_AES_CCM_FLAG_INVALID
4262306a36Sopenharmony_ci *   Invalid flag options in AES-CCM IV.
4362306a36Sopenharmony_ci */
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic inline int incr_index(int index, int count, int max)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	if ((index + count) >= max)
4862306a36Sopenharmony_ci		index = index + count - max;
4962306a36Sopenharmony_ci	else
5062306a36Sopenharmony_ci		index += count;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	return index;
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic void softreq_unmap_sgbufs(struct nitrox_softreq *sr)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	struct nitrox_device *ndev = sr->ndev;
5862306a36Sopenharmony_ci	struct device *dev = DEV(ndev);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	dma_unmap_sg(dev, sr->in.sg, sg_nents(sr->in.sg),
6262306a36Sopenharmony_ci		     DMA_BIDIRECTIONAL);
6362306a36Sopenharmony_ci	dma_unmap_single(dev, sr->in.sgcomp_dma, sr->in.sgcomp_len,
6462306a36Sopenharmony_ci			 DMA_TO_DEVICE);
6562306a36Sopenharmony_ci	kfree(sr->in.sgcomp);
6662306a36Sopenharmony_ci	sr->in.sg = NULL;
6762306a36Sopenharmony_ci	sr->in.sgmap_cnt = 0;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	dma_unmap_sg(dev, sr->out.sg, sg_nents(sr->out.sg),
7062306a36Sopenharmony_ci		     DMA_BIDIRECTIONAL);
7162306a36Sopenharmony_ci	dma_unmap_single(dev, sr->out.sgcomp_dma, sr->out.sgcomp_len,
7262306a36Sopenharmony_ci			 DMA_TO_DEVICE);
7362306a36Sopenharmony_ci	kfree(sr->out.sgcomp);
7462306a36Sopenharmony_ci	sr->out.sg = NULL;
7562306a36Sopenharmony_ci	sr->out.sgmap_cnt = 0;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic void softreq_destroy(struct nitrox_softreq *sr)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	softreq_unmap_sgbufs(sr);
8162306a36Sopenharmony_ci	kfree(sr);
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci/**
8562306a36Sopenharmony_ci * create_sg_component - create SG componets for N5 device.
8662306a36Sopenharmony_ci * @sr: Request structure
8762306a36Sopenharmony_ci * @sgtbl: SG table
8862306a36Sopenharmony_ci * @map_nents: number of dma mapped entries
8962306a36Sopenharmony_ci *
9062306a36Sopenharmony_ci * Component structure
9162306a36Sopenharmony_ci *
9262306a36Sopenharmony_ci *   63     48 47     32 31    16 15      0
9362306a36Sopenharmony_ci *   --------------------------------------
9462306a36Sopenharmony_ci *   |   LEN0  |  LEN1  |  LEN2  |  LEN3  |
9562306a36Sopenharmony_ci *   |-------------------------------------
9662306a36Sopenharmony_ci *   |               PTR0                 |
9762306a36Sopenharmony_ci *   --------------------------------------
9862306a36Sopenharmony_ci *   |               PTR1                 |
9962306a36Sopenharmony_ci *   --------------------------------------
10062306a36Sopenharmony_ci *   |               PTR2                 |
10162306a36Sopenharmony_ci *   --------------------------------------
10262306a36Sopenharmony_ci *   |               PTR3                 |
10362306a36Sopenharmony_ci *   --------------------------------------
10462306a36Sopenharmony_ci *
10562306a36Sopenharmony_ci *   Returns 0 if success or a negative errno code on error.
10662306a36Sopenharmony_ci */
10762306a36Sopenharmony_cistatic int create_sg_component(struct nitrox_softreq *sr,
10862306a36Sopenharmony_ci			       struct nitrox_sgtable *sgtbl, int map_nents)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	struct nitrox_device *ndev = sr->ndev;
11162306a36Sopenharmony_ci	struct nitrox_sgcomp *sgcomp;
11262306a36Sopenharmony_ci	struct scatterlist *sg;
11362306a36Sopenharmony_ci	dma_addr_t dma;
11462306a36Sopenharmony_ci	size_t sz_comp;
11562306a36Sopenharmony_ci	int i, j, nr_sgcomp;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	nr_sgcomp = roundup(map_nents, 4) / 4;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	/* each component holds 4 dma pointers */
12062306a36Sopenharmony_ci	sz_comp = nr_sgcomp * sizeof(*sgcomp);
12162306a36Sopenharmony_ci	sgcomp = kzalloc(sz_comp, sr->gfp);
12262306a36Sopenharmony_ci	if (!sgcomp)
12362306a36Sopenharmony_ci		return -ENOMEM;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	sgtbl->sgcomp = sgcomp;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	sg = sgtbl->sg;
12862306a36Sopenharmony_ci	/* populate device sg component */
12962306a36Sopenharmony_ci	for (i = 0; i < nr_sgcomp; i++) {
13062306a36Sopenharmony_ci		for (j = 0; j < 4 && sg; j++) {
13162306a36Sopenharmony_ci			sgcomp[i].len[j] = cpu_to_be16(sg_dma_len(sg));
13262306a36Sopenharmony_ci			sgcomp[i].dma[j] = cpu_to_be64(sg_dma_address(sg));
13362306a36Sopenharmony_ci			sg = sg_next(sg);
13462306a36Sopenharmony_ci		}
13562306a36Sopenharmony_ci	}
13662306a36Sopenharmony_ci	/* map the device sg component */
13762306a36Sopenharmony_ci	dma = dma_map_single(DEV(ndev), sgtbl->sgcomp, sz_comp, DMA_TO_DEVICE);
13862306a36Sopenharmony_ci	if (dma_mapping_error(DEV(ndev), dma)) {
13962306a36Sopenharmony_ci		kfree(sgtbl->sgcomp);
14062306a36Sopenharmony_ci		sgtbl->sgcomp = NULL;
14162306a36Sopenharmony_ci		return -ENOMEM;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	sgtbl->sgcomp_dma = dma;
14562306a36Sopenharmony_ci	sgtbl->sgcomp_len = sz_comp;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return 0;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/**
15162306a36Sopenharmony_ci * dma_map_inbufs - DMA map input sglist and creates sglist component
15262306a36Sopenharmony_ci *                  for N5 device.
15362306a36Sopenharmony_ci * @sr: Request structure
15462306a36Sopenharmony_ci * @req: Crypto request structre
15562306a36Sopenharmony_ci *
15662306a36Sopenharmony_ci * Returns 0 if successful or a negative errno code on error.
15762306a36Sopenharmony_ci */
15862306a36Sopenharmony_cistatic int dma_map_inbufs(struct nitrox_softreq *sr,
15962306a36Sopenharmony_ci			  struct se_crypto_request *req)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	struct device *dev = DEV(sr->ndev);
16262306a36Sopenharmony_ci	struct scatterlist *sg;
16362306a36Sopenharmony_ci	int i, nents, ret = 0;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	nents = dma_map_sg(dev, req->src, sg_nents(req->src),
16662306a36Sopenharmony_ci			   DMA_BIDIRECTIONAL);
16762306a36Sopenharmony_ci	if (!nents)
16862306a36Sopenharmony_ci		return -EINVAL;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	for_each_sg(req->src, sg, nents, i)
17162306a36Sopenharmony_ci		sr->in.total_bytes += sg_dma_len(sg);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	sr->in.sg = req->src;
17462306a36Sopenharmony_ci	sr->in.sgmap_cnt = nents;
17562306a36Sopenharmony_ci	ret = create_sg_component(sr, &sr->in, sr->in.sgmap_cnt);
17662306a36Sopenharmony_ci	if (ret)
17762306a36Sopenharmony_ci		goto incomp_err;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	return 0;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ciincomp_err:
18262306a36Sopenharmony_ci	dma_unmap_sg(dev, req->src, sg_nents(req->src), DMA_BIDIRECTIONAL);
18362306a36Sopenharmony_ci	sr->in.sgmap_cnt = 0;
18462306a36Sopenharmony_ci	return ret;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic int dma_map_outbufs(struct nitrox_softreq *sr,
18862306a36Sopenharmony_ci			   struct se_crypto_request *req)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	struct device *dev = DEV(sr->ndev);
19162306a36Sopenharmony_ci	int nents, ret = 0;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	nents = dma_map_sg(dev, req->dst, sg_nents(req->dst),
19462306a36Sopenharmony_ci			   DMA_BIDIRECTIONAL);
19562306a36Sopenharmony_ci	if (!nents)
19662306a36Sopenharmony_ci		return -EINVAL;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	sr->out.sg = req->dst;
19962306a36Sopenharmony_ci	sr->out.sgmap_cnt = nents;
20062306a36Sopenharmony_ci	ret = create_sg_component(sr, &sr->out, sr->out.sgmap_cnt);
20162306a36Sopenharmony_ci	if (ret)
20262306a36Sopenharmony_ci		goto outcomp_map_err;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	return 0;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cioutcomp_map_err:
20762306a36Sopenharmony_ci	dma_unmap_sg(dev, req->dst, sg_nents(req->dst), DMA_BIDIRECTIONAL);
20862306a36Sopenharmony_ci	sr->out.sgmap_cnt = 0;
20962306a36Sopenharmony_ci	sr->out.sg = NULL;
21062306a36Sopenharmony_ci	return ret;
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic inline int softreq_map_iobuf(struct nitrox_softreq *sr,
21462306a36Sopenharmony_ci				    struct se_crypto_request *creq)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	int ret;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	ret = dma_map_inbufs(sr, creq);
21962306a36Sopenharmony_ci	if (ret)
22062306a36Sopenharmony_ci		return ret;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	ret = dma_map_outbufs(sr, creq);
22362306a36Sopenharmony_ci	if (ret)
22462306a36Sopenharmony_ci		softreq_unmap_sgbufs(sr);
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	return ret;
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic inline void backlog_list_add(struct nitrox_softreq *sr,
23062306a36Sopenharmony_ci				    struct nitrox_cmdq *cmdq)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	INIT_LIST_HEAD(&sr->backlog);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	spin_lock_bh(&cmdq->backlog_qlock);
23562306a36Sopenharmony_ci	list_add_tail(&sr->backlog, &cmdq->backlog_head);
23662306a36Sopenharmony_ci	atomic_inc(&cmdq->backlog_count);
23762306a36Sopenharmony_ci	atomic_set(&sr->status, REQ_BACKLOG);
23862306a36Sopenharmony_ci	spin_unlock_bh(&cmdq->backlog_qlock);
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic inline void response_list_add(struct nitrox_softreq *sr,
24262306a36Sopenharmony_ci				     struct nitrox_cmdq *cmdq)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	INIT_LIST_HEAD(&sr->response);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	spin_lock_bh(&cmdq->resp_qlock);
24762306a36Sopenharmony_ci	list_add_tail(&sr->response, &cmdq->response_head);
24862306a36Sopenharmony_ci	spin_unlock_bh(&cmdq->resp_qlock);
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic inline void response_list_del(struct nitrox_softreq *sr,
25262306a36Sopenharmony_ci				     struct nitrox_cmdq *cmdq)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	spin_lock_bh(&cmdq->resp_qlock);
25562306a36Sopenharmony_ci	list_del(&sr->response);
25662306a36Sopenharmony_ci	spin_unlock_bh(&cmdq->resp_qlock);
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic struct nitrox_softreq *
26062306a36Sopenharmony_ciget_first_response_entry(struct nitrox_cmdq *cmdq)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	return list_first_entry_or_null(&cmdq->response_head,
26362306a36Sopenharmony_ci					struct nitrox_softreq, response);
26462306a36Sopenharmony_ci}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_cistatic inline bool cmdq_full(struct nitrox_cmdq *cmdq, int qlen)
26762306a36Sopenharmony_ci{
26862306a36Sopenharmony_ci	if (atomic_inc_return(&cmdq->pending_count) > qlen) {
26962306a36Sopenharmony_ci		atomic_dec(&cmdq->pending_count);
27062306a36Sopenharmony_ci		/* sync with other cpus */
27162306a36Sopenharmony_ci		smp_mb__after_atomic();
27262306a36Sopenharmony_ci		return true;
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci	/* sync with other cpus */
27562306a36Sopenharmony_ci	smp_mb__after_atomic();
27662306a36Sopenharmony_ci	return false;
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci/**
28062306a36Sopenharmony_ci * post_se_instr - Post SE instruction to Packet Input ring
28162306a36Sopenharmony_ci * @sr: Request structure
28262306a36Sopenharmony_ci * @cmdq: Command queue structure
28362306a36Sopenharmony_ci *
28462306a36Sopenharmony_ci * Returns 0 if successful or a negative error code,
28562306a36Sopenharmony_ci * if no space in ring.
28662306a36Sopenharmony_ci */
28762306a36Sopenharmony_cistatic void post_se_instr(struct nitrox_softreq *sr,
28862306a36Sopenharmony_ci			  struct nitrox_cmdq *cmdq)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	struct nitrox_device *ndev = sr->ndev;
29162306a36Sopenharmony_ci	int idx;
29262306a36Sopenharmony_ci	u8 *ent;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	spin_lock_bh(&cmdq->cmd_qlock);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	idx = cmdq->write_idx;
29762306a36Sopenharmony_ci	/* copy the instruction */
29862306a36Sopenharmony_ci	ent = cmdq->base + (idx * cmdq->instr_size);
29962306a36Sopenharmony_ci	memcpy(ent, &sr->instr, cmdq->instr_size);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	atomic_set(&sr->status, REQ_POSTED);
30262306a36Sopenharmony_ci	response_list_add(sr, cmdq);
30362306a36Sopenharmony_ci	sr->tstamp = jiffies;
30462306a36Sopenharmony_ci	/* flush the command queue updates */
30562306a36Sopenharmony_ci	dma_wmb();
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	/* Ring doorbell with count 1 */
30862306a36Sopenharmony_ci	writeq(1, cmdq->dbell_csr_addr);
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	cmdq->write_idx = incr_index(idx, 1, ndev->qlen);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	spin_unlock_bh(&cmdq->cmd_qlock);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	/* increment the posted command count */
31562306a36Sopenharmony_ci	atomic64_inc(&ndev->stats.posted);
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic int post_backlog_cmds(struct nitrox_cmdq *cmdq)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	struct nitrox_device *ndev = cmdq->ndev;
32162306a36Sopenharmony_ci	struct nitrox_softreq *sr, *tmp;
32262306a36Sopenharmony_ci	int ret = 0;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	if (!atomic_read(&cmdq->backlog_count))
32562306a36Sopenharmony_ci		return 0;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	spin_lock_bh(&cmdq->backlog_qlock);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	list_for_each_entry_safe(sr, tmp, &cmdq->backlog_head, backlog) {
33062306a36Sopenharmony_ci		/* submit until space available */
33162306a36Sopenharmony_ci		if (unlikely(cmdq_full(cmdq, ndev->qlen))) {
33262306a36Sopenharmony_ci			ret = -ENOSPC;
33362306a36Sopenharmony_ci			break;
33462306a36Sopenharmony_ci		}
33562306a36Sopenharmony_ci		/* delete from backlog list */
33662306a36Sopenharmony_ci		list_del(&sr->backlog);
33762306a36Sopenharmony_ci		atomic_dec(&cmdq->backlog_count);
33862306a36Sopenharmony_ci		/* sync with other cpus */
33962306a36Sopenharmony_ci		smp_mb__after_atomic();
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci		/* post the command */
34262306a36Sopenharmony_ci		post_se_instr(sr, cmdq);
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci	spin_unlock_bh(&cmdq->backlog_qlock);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	return ret;
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistatic int nitrox_enqueue_request(struct nitrox_softreq *sr)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	struct nitrox_cmdq *cmdq = sr->cmdq;
35262306a36Sopenharmony_ci	struct nitrox_device *ndev = sr->ndev;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	/* try to post backlog requests */
35562306a36Sopenharmony_ci	post_backlog_cmds(cmdq);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	if (unlikely(cmdq_full(cmdq, ndev->qlen))) {
35862306a36Sopenharmony_ci		if (!(sr->flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
35962306a36Sopenharmony_ci			/* increment drop count */
36062306a36Sopenharmony_ci			atomic64_inc(&ndev->stats.dropped);
36162306a36Sopenharmony_ci			return -ENOSPC;
36262306a36Sopenharmony_ci		}
36362306a36Sopenharmony_ci		/* add to backlog list */
36462306a36Sopenharmony_ci		backlog_list_add(sr, cmdq);
36562306a36Sopenharmony_ci		return -EINPROGRESS;
36662306a36Sopenharmony_ci	}
36762306a36Sopenharmony_ci	post_se_instr(sr, cmdq);
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	return -EINPROGRESS;
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci/**
37362306a36Sopenharmony_ci * nitrox_process_se_request - Send request to SE core
37462306a36Sopenharmony_ci * @ndev: NITROX device
37562306a36Sopenharmony_ci * @req: Crypto request
37662306a36Sopenharmony_ci * @callback: Completion callback
37762306a36Sopenharmony_ci * @cb_arg: Completion callback arguments
37862306a36Sopenharmony_ci *
37962306a36Sopenharmony_ci * Returns 0 on success, or a negative error code.
38062306a36Sopenharmony_ci */
38162306a36Sopenharmony_ciint nitrox_process_se_request(struct nitrox_device *ndev,
38262306a36Sopenharmony_ci			      struct se_crypto_request *req,
38362306a36Sopenharmony_ci			      completion_t callback,
38462306a36Sopenharmony_ci			      void *cb_arg)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	struct nitrox_softreq *sr;
38762306a36Sopenharmony_ci	dma_addr_t ctx_handle = 0;
38862306a36Sopenharmony_ci	int qno, ret = 0;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	if (!nitrox_ready(ndev))
39162306a36Sopenharmony_ci		return -ENODEV;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	sr = kzalloc(sizeof(*sr), req->gfp);
39462306a36Sopenharmony_ci	if (!sr)
39562306a36Sopenharmony_ci		return -ENOMEM;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	sr->ndev = ndev;
39862306a36Sopenharmony_ci	sr->flags = req->flags;
39962306a36Sopenharmony_ci	sr->gfp = req->gfp;
40062306a36Sopenharmony_ci	sr->callback = callback;
40162306a36Sopenharmony_ci	sr->cb_arg = cb_arg;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	atomic_set(&sr->status, REQ_NOT_POSTED);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	sr->resp.orh = req->orh;
40662306a36Sopenharmony_ci	sr->resp.completion = req->comp;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	ret = softreq_map_iobuf(sr, req);
40962306a36Sopenharmony_ci	if (ret) {
41062306a36Sopenharmony_ci		kfree(sr);
41162306a36Sopenharmony_ci		return ret;
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	/* get the context handle */
41562306a36Sopenharmony_ci	if (req->ctx_handle) {
41662306a36Sopenharmony_ci		struct ctx_hdr *hdr;
41762306a36Sopenharmony_ci		u8 *ctx_ptr;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci		ctx_ptr = (u8 *)(uintptr_t)req->ctx_handle;
42062306a36Sopenharmony_ci		hdr = (struct ctx_hdr *)(ctx_ptr - sizeof(struct ctx_hdr));
42162306a36Sopenharmony_ci		ctx_handle = hdr->ctx_dma;
42262306a36Sopenharmony_ci	}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	/* select the queue */
42562306a36Sopenharmony_ci	qno = smp_processor_id() % ndev->nr_queues;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	sr->cmdq = &ndev->pkt_inq[qno];
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	/*
43062306a36Sopenharmony_ci	 * 64-Byte Instruction Format
43162306a36Sopenharmony_ci	 *
43262306a36Sopenharmony_ci	 *  ----------------------
43362306a36Sopenharmony_ci	 *  |      DPTR0         | 8 bytes
43462306a36Sopenharmony_ci	 *  ----------------------
43562306a36Sopenharmony_ci	 *  |  PKT_IN_INSTR_HDR  | 8 bytes
43662306a36Sopenharmony_ci	 *  ----------------------
43762306a36Sopenharmony_ci	 *  |    PKT_IN_HDR      | 16 bytes
43862306a36Sopenharmony_ci	 *  ----------------------
43962306a36Sopenharmony_ci	 *  |    SLC_INFO        | 16 bytes
44062306a36Sopenharmony_ci	 *  ----------------------
44162306a36Sopenharmony_ci	 *  |   Front data       | 16 bytes
44262306a36Sopenharmony_ci	 *  ----------------------
44362306a36Sopenharmony_ci	 */
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	/* fill the packet instruction */
44662306a36Sopenharmony_ci	/* word 0 */
44762306a36Sopenharmony_ci	sr->instr.dptr0 = cpu_to_be64(sr->in.sgcomp_dma);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	/* word 1 */
45062306a36Sopenharmony_ci	sr->instr.ih.value = 0;
45162306a36Sopenharmony_ci	sr->instr.ih.s.g = 1;
45262306a36Sopenharmony_ci	sr->instr.ih.s.gsz = sr->in.sgmap_cnt;
45362306a36Sopenharmony_ci	sr->instr.ih.s.ssz = sr->out.sgmap_cnt;
45462306a36Sopenharmony_ci	sr->instr.ih.s.fsz = FDATA_SIZE + sizeof(struct gphdr);
45562306a36Sopenharmony_ci	sr->instr.ih.s.tlen = sr->instr.ih.s.fsz + sr->in.total_bytes;
45662306a36Sopenharmony_ci	sr->instr.ih.bev = cpu_to_be64(sr->instr.ih.value);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	/* word 2 */
45962306a36Sopenharmony_ci	sr->instr.irh.value[0] = 0;
46062306a36Sopenharmony_ci	sr->instr.irh.s.uddl = MIN_UDD_LEN;
46162306a36Sopenharmony_ci	/* context length in 64-bit words */
46262306a36Sopenharmony_ci	sr->instr.irh.s.ctxl = (req->ctrl.s.ctxl / 8);
46362306a36Sopenharmony_ci	/* offset from solicit base port 256 */
46462306a36Sopenharmony_ci	sr->instr.irh.s.destport = SOLICIT_BASE_DPORT + qno;
46562306a36Sopenharmony_ci	sr->instr.irh.s.ctxc = req->ctrl.s.ctxc;
46662306a36Sopenharmony_ci	sr->instr.irh.s.arg = req->ctrl.s.arg;
46762306a36Sopenharmony_ci	sr->instr.irh.s.opcode = req->opcode;
46862306a36Sopenharmony_ci	sr->instr.irh.bev[0] = cpu_to_be64(sr->instr.irh.value[0]);
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	/* word 3 */
47162306a36Sopenharmony_ci	sr->instr.irh.s.ctxp = cpu_to_be64(ctx_handle);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	/* word 4 */
47462306a36Sopenharmony_ci	sr->instr.slc.value[0] = 0;
47562306a36Sopenharmony_ci	sr->instr.slc.s.ssz = sr->out.sgmap_cnt;
47662306a36Sopenharmony_ci	sr->instr.slc.bev[0] = cpu_to_be64(sr->instr.slc.value[0]);
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	/* word 5 */
47962306a36Sopenharmony_ci	sr->instr.slc.s.rptr = cpu_to_be64(sr->out.sgcomp_dma);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	/*
48262306a36Sopenharmony_ci	 * No conversion for front data,
48362306a36Sopenharmony_ci	 * It goes into payload
48462306a36Sopenharmony_ci	 * put GP Header in front data
48562306a36Sopenharmony_ci	 */
48662306a36Sopenharmony_ci	sr->instr.fdata[0] = *((u64 *)&req->gph);
48762306a36Sopenharmony_ci	sr->instr.fdata[1] = 0;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	ret = nitrox_enqueue_request(sr);
49062306a36Sopenharmony_ci	if (ret == -ENOSPC)
49162306a36Sopenharmony_ci		goto send_fail;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	return ret;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cisend_fail:
49662306a36Sopenharmony_ci	softreq_destroy(sr);
49762306a36Sopenharmony_ci	return ret;
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cistatic inline int cmd_timeout(unsigned long tstamp, unsigned long timeout)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci	return time_after_eq(jiffies, (tstamp + timeout));
50362306a36Sopenharmony_ci}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_civoid backlog_qflush_work(struct work_struct *work)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	struct nitrox_cmdq *cmdq;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	cmdq = container_of(work, struct nitrox_cmdq, backlog_qflush);
51062306a36Sopenharmony_ci	post_backlog_cmds(cmdq);
51162306a36Sopenharmony_ci}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_cistatic bool sr_completed(struct nitrox_softreq *sr)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	u64 orh = READ_ONCE(*sr->resp.orh);
51662306a36Sopenharmony_ci	unsigned long timeout = jiffies + msecs_to_jiffies(1);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	if ((orh != PENDING_SIG) && (orh & 0xff))
51962306a36Sopenharmony_ci		return true;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	while (READ_ONCE(*sr->resp.completion) == PENDING_SIG) {
52262306a36Sopenharmony_ci		if (time_after(jiffies, timeout)) {
52362306a36Sopenharmony_ci			pr_err("comp not done\n");
52462306a36Sopenharmony_ci			return false;
52562306a36Sopenharmony_ci		}
52662306a36Sopenharmony_ci	}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	return true;
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci/**
53262306a36Sopenharmony_ci * process_response_list - process completed requests
53362306a36Sopenharmony_ci * @cmdq: Command queue structure
53462306a36Sopenharmony_ci *
53562306a36Sopenharmony_ci * Returns the number of responses processed.
53662306a36Sopenharmony_ci */
53762306a36Sopenharmony_cistatic void process_response_list(struct nitrox_cmdq *cmdq)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	struct nitrox_device *ndev = cmdq->ndev;
54062306a36Sopenharmony_ci	struct nitrox_softreq *sr;
54162306a36Sopenharmony_ci	int req_completed = 0, err = 0, budget;
54262306a36Sopenharmony_ci	completion_t callback;
54362306a36Sopenharmony_ci	void *cb_arg;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	/* check all pending requests */
54662306a36Sopenharmony_ci	budget = atomic_read(&cmdq->pending_count);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	while (req_completed < budget) {
54962306a36Sopenharmony_ci		sr = get_first_response_entry(cmdq);
55062306a36Sopenharmony_ci		if (!sr)
55162306a36Sopenharmony_ci			break;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci		if (atomic_read(&sr->status) != REQ_POSTED)
55462306a36Sopenharmony_ci			break;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci		/* check orh and completion bytes updates */
55762306a36Sopenharmony_ci		if (!sr_completed(sr)) {
55862306a36Sopenharmony_ci			/* request not completed, check for timeout */
55962306a36Sopenharmony_ci			if (!cmd_timeout(sr->tstamp, ndev->timeout))
56062306a36Sopenharmony_ci				break;
56162306a36Sopenharmony_ci			dev_err_ratelimited(DEV(ndev),
56262306a36Sopenharmony_ci					    "Request timeout, orh 0x%016llx\n",
56362306a36Sopenharmony_ci					    READ_ONCE(*sr->resp.orh));
56462306a36Sopenharmony_ci		}
56562306a36Sopenharmony_ci		atomic_dec(&cmdq->pending_count);
56662306a36Sopenharmony_ci		atomic64_inc(&ndev->stats.completed);
56762306a36Sopenharmony_ci		/* sync with other cpus */
56862306a36Sopenharmony_ci		smp_mb__after_atomic();
56962306a36Sopenharmony_ci		/* remove from response list */
57062306a36Sopenharmony_ci		response_list_del(sr, cmdq);
57162306a36Sopenharmony_ci		/* ORH error code */
57262306a36Sopenharmony_ci		err = READ_ONCE(*sr->resp.orh) & 0xff;
57362306a36Sopenharmony_ci		callback = sr->callback;
57462306a36Sopenharmony_ci		cb_arg = sr->cb_arg;
57562306a36Sopenharmony_ci		softreq_destroy(sr);
57662306a36Sopenharmony_ci		if (callback)
57762306a36Sopenharmony_ci			callback(cb_arg, err);
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci		req_completed++;
58062306a36Sopenharmony_ci	}
58162306a36Sopenharmony_ci}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci/*
58462306a36Sopenharmony_ci * pkt_slc_resp_tasklet - post processing of SE responses
58562306a36Sopenharmony_ci */
58662306a36Sopenharmony_civoid pkt_slc_resp_tasklet(unsigned long data)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	struct nitrox_q_vector *qvec = (void *)(uintptr_t)(data);
58962306a36Sopenharmony_ci	struct nitrox_cmdq *cmdq = qvec->cmdq;
59062306a36Sopenharmony_ci	union nps_pkt_slc_cnts slc_cnts;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	/* read completion count */
59362306a36Sopenharmony_ci	slc_cnts.value = readq(cmdq->compl_cnt_csr_addr);
59462306a36Sopenharmony_ci	/* resend the interrupt if more work to do */
59562306a36Sopenharmony_ci	slc_cnts.s.resend = 1;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	process_response_list(cmdq);
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	/*
60062306a36Sopenharmony_ci	 * clear the interrupt with resend bit enabled,
60162306a36Sopenharmony_ci	 * MSI-X interrupt generates if Completion count > Threshold
60262306a36Sopenharmony_ci	 */
60362306a36Sopenharmony_ci	writeq(slc_cnts.value, cmdq->compl_cnt_csr_addr);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	if (atomic_read(&cmdq->backlog_count))
60662306a36Sopenharmony_ci		schedule_work(&cmdq->backlog_qflush);
60762306a36Sopenharmony_ci}
608