xref: /kernel/linux/linux-5.10/drivers/crypto/caam/qi.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * CAAM/SEC 4.x QI transport/backend driver
48c2ecf20Sopenharmony_ci * Queue Interface backend functionality
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright 2013-2016 Freescale Semiconductor, Inc.
78c2ecf20Sopenharmony_ci * Copyright 2016-2017, 2019-2020 NXP
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/cpumask.h>
118c2ecf20Sopenharmony_ci#include <linux/kthread.h>
128c2ecf20Sopenharmony_ci#include <soc/fsl/qman.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "debugfs.h"
158c2ecf20Sopenharmony_ci#include "regs.h"
168c2ecf20Sopenharmony_ci#include "qi.h"
178c2ecf20Sopenharmony_ci#include "desc.h"
188c2ecf20Sopenharmony_ci#include "intern.h"
198c2ecf20Sopenharmony_ci#include "desc_constr.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define PREHDR_RSLS_SHIFT	31
228c2ecf20Sopenharmony_ci#define PREHDR_ABS		BIT(25)
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/*
258c2ecf20Sopenharmony_ci * Use a reasonable backlog of frames (per CPU) as congestion threshold,
268c2ecf20Sopenharmony_ci * so that resources used by the in-flight buffers do not become a memory hog.
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_ci#define MAX_RSP_FQ_BACKLOG_PER_CPU	256
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define CAAM_QI_ENQUEUE_RETRIES	10000
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define CAAM_NAPI_WEIGHT	63
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/*
358c2ecf20Sopenharmony_ci * caam_napi - struct holding CAAM NAPI-related params
368c2ecf20Sopenharmony_ci * @irqtask: IRQ task for QI backend
378c2ecf20Sopenharmony_ci * @p: QMan portal
388c2ecf20Sopenharmony_ci */
398c2ecf20Sopenharmony_cistruct caam_napi {
408c2ecf20Sopenharmony_ci	struct napi_struct irqtask;
418c2ecf20Sopenharmony_ci	struct qman_portal *p;
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/*
458c2ecf20Sopenharmony_ci * caam_qi_pcpu_priv - percpu private data structure to main list of pending
468c2ecf20Sopenharmony_ci *                     responses expected on each cpu.
478c2ecf20Sopenharmony_ci * @caam_napi: CAAM NAPI params
488c2ecf20Sopenharmony_ci * @net_dev: netdev used by NAPI
498c2ecf20Sopenharmony_ci * @rsp_fq: response FQ from CAAM
508c2ecf20Sopenharmony_ci */
518c2ecf20Sopenharmony_cistruct caam_qi_pcpu_priv {
528c2ecf20Sopenharmony_ci	struct caam_napi caam_napi;
538c2ecf20Sopenharmony_ci	struct net_device net_dev;
548c2ecf20Sopenharmony_ci	struct qman_fq *rsp_fq;
558c2ecf20Sopenharmony_ci} ____cacheline_aligned;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct caam_qi_pcpu_priv, pcpu_qipriv);
588c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(int, last_cpu);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci/*
618c2ecf20Sopenharmony_ci * caam_qi_priv - CAAM QI backend private params
628c2ecf20Sopenharmony_ci * @cgr: QMan congestion group
638c2ecf20Sopenharmony_ci */
648c2ecf20Sopenharmony_cistruct caam_qi_priv {
658c2ecf20Sopenharmony_ci	struct qman_cgr cgr;
668c2ecf20Sopenharmony_ci};
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic struct caam_qi_priv qipriv ____cacheline_aligned;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci/*
718c2ecf20Sopenharmony_ci * This is written by only one core - the one that initialized the CGR - and
728c2ecf20Sopenharmony_ci * read by multiple cores (all the others).
738c2ecf20Sopenharmony_ci */
748c2ecf20Sopenharmony_cibool caam_congested __read_mostly;
758c2ecf20Sopenharmony_ciEXPORT_SYMBOL(caam_congested);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/*
788c2ecf20Sopenharmony_ci * This is a a cache of buffers, from which the users of CAAM QI driver
798c2ecf20Sopenharmony_ci * can allocate short (CAAM_QI_MEMCACHE_SIZE) buffers. It's faster than
808c2ecf20Sopenharmony_ci * doing malloc on the hotpath.
818c2ecf20Sopenharmony_ci * NOTE: A more elegant solution would be to have some headroom in the frames
828c2ecf20Sopenharmony_ci *       being processed. This could be added by the dpaa-ethernet driver.
838c2ecf20Sopenharmony_ci *       This would pose a problem for userspace application processing which
848c2ecf20Sopenharmony_ci *       cannot know of this limitation. So for now, this will work.
858c2ecf20Sopenharmony_ci * NOTE: The memcache is SMP-safe. No need to handle spinlocks in-here
868c2ecf20Sopenharmony_ci */
878c2ecf20Sopenharmony_cistatic struct kmem_cache *qi_cache;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic void *caam_iova_to_virt(struct iommu_domain *domain,
908c2ecf20Sopenharmony_ci			       dma_addr_t iova_addr)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	phys_addr_t phys_addr;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	phys_addr = domain ? iommu_iova_to_phys(domain, iova_addr) : iova_addr;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	return phys_to_virt(phys_addr);
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ciint caam_qi_enqueue(struct device *qidev, struct caam_drv_req *req)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	struct qm_fd fd;
1028c2ecf20Sopenharmony_ci	dma_addr_t addr;
1038c2ecf20Sopenharmony_ci	int ret;
1048c2ecf20Sopenharmony_ci	int num_retries = 0;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	qm_fd_clear_fd(&fd);
1078c2ecf20Sopenharmony_ci	qm_fd_set_compound(&fd, qm_sg_entry_get_len(&req->fd_sgt[1]));
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	addr = dma_map_single(qidev, req->fd_sgt, sizeof(req->fd_sgt),
1108c2ecf20Sopenharmony_ci			      DMA_BIDIRECTIONAL);
1118c2ecf20Sopenharmony_ci	if (dma_mapping_error(qidev, addr)) {
1128c2ecf20Sopenharmony_ci		dev_err(qidev, "DMA mapping error for QI enqueue request\n");
1138c2ecf20Sopenharmony_ci		return -EIO;
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci	qm_fd_addr_set64(&fd, addr);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	do {
1188c2ecf20Sopenharmony_ci		ret = qman_enqueue(req->drv_ctx->req_fq, &fd);
1198c2ecf20Sopenharmony_ci		if (likely(!ret)) {
1208c2ecf20Sopenharmony_ci			refcount_inc(&req->drv_ctx->refcnt);
1218c2ecf20Sopenharmony_ci			return 0;
1228c2ecf20Sopenharmony_ci		}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci		if (ret != -EBUSY)
1258c2ecf20Sopenharmony_ci			break;
1268c2ecf20Sopenharmony_ci		num_retries++;
1278c2ecf20Sopenharmony_ci	} while (num_retries < CAAM_QI_ENQUEUE_RETRIES);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	dev_err(qidev, "qman_enqueue failed: %d\n", ret);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	return ret;
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(caam_qi_enqueue);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic void caam_fq_ern_cb(struct qman_portal *qm, struct qman_fq *fq,
1368c2ecf20Sopenharmony_ci			   const union qm_mr_entry *msg)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	const struct qm_fd *fd;
1398c2ecf20Sopenharmony_ci	struct caam_drv_req *drv_req;
1408c2ecf20Sopenharmony_ci	struct device *qidev = &(raw_cpu_ptr(&pcpu_qipriv)->net_dev.dev);
1418c2ecf20Sopenharmony_ci	struct caam_drv_private *priv = dev_get_drvdata(qidev);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	fd = &msg->ern.fd;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	drv_req = caam_iova_to_virt(priv->domain, qm_fd_addr_get64(fd));
1468c2ecf20Sopenharmony_ci	if (!drv_req) {
1478c2ecf20Sopenharmony_ci		dev_err(qidev,
1488c2ecf20Sopenharmony_ci			"Can't find original request for CAAM response\n");
1498c2ecf20Sopenharmony_ci		return;
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	refcount_dec(&drv_req->drv_ctx->refcnt);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	if (qm_fd_get_format(fd) != qm_fd_compound) {
1558c2ecf20Sopenharmony_ci		dev_err(qidev, "Non-compound FD from CAAM\n");
1568c2ecf20Sopenharmony_ci		return;
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	dma_unmap_single(drv_req->drv_ctx->qidev, qm_fd_addr(fd),
1608c2ecf20Sopenharmony_ci			 sizeof(drv_req->fd_sgt), DMA_BIDIRECTIONAL);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	if (fd->status)
1638c2ecf20Sopenharmony_ci		drv_req->cbk(drv_req, be32_to_cpu(fd->status));
1648c2ecf20Sopenharmony_ci	else
1658c2ecf20Sopenharmony_ci		drv_req->cbk(drv_req, JRSTA_SSRC_QI);
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic struct qman_fq *create_caam_req_fq(struct device *qidev,
1698c2ecf20Sopenharmony_ci					  struct qman_fq *rsp_fq,
1708c2ecf20Sopenharmony_ci					  dma_addr_t hwdesc,
1718c2ecf20Sopenharmony_ci					  int fq_sched_flag)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	int ret;
1748c2ecf20Sopenharmony_ci	struct qman_fq *req_fq;
1758c2ecf20Sopenharmony_ci	struct qm_mcc_initfq opts;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	req_fq = kzalloc(sizeof(*req_fq), GFP_ATOMIC);
1788c2ecf20Sopenharmony_ci	if (!req_fq)
1798c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	req_fq->cb.ern = caam_fq_ern_cb;
1828c2ecf20Sopenharmony_ci	req_fq->cb.fqs = NULL;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	ret = qman_create_fq(0, QMAN_FQ_FLAG_DYNAMIC_FQID |
1858c2ecf20Sopenharmony_ci				QMAN_FQ_FLAG_TO_DCPORTAL, req_fq);
1868c2ecf20Sopenharmony_ci	if (ret) {
1878c2ecf20Sopenharmony_ci		dev_err(qidev, "Failed to create session req FQ\n");
1888c2ecf20Sopenharmony_ci		goto create_req_fq_fail;
1898c2ecf20Sopenharmony_ci	}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	memset(&opts, 0, sizeof(opts));
1928c2ecf20Sopenharmony_ci	opts.we_mask = cpu_to_be16(QM_INITFQ_WE_FQCTRL | QM_INITFQ_WE_DESTWQ |
1938c2ecf20Sopenharmony_ci				   QM_INITFQ_WE_CONTEXTB |
1948c2ecf20Sopenharmony_ci				   QM_INITFQ_WE_CONTEXTA | QM_INITFQ_WE_CGID);
1958c2ecf20Sopenharmony_ci	opts.fqd.fq_ctrl = cpu_to_be16(QM_FQCTRL_CPCSTASH | QM_FQCTRL_CGE);
1968c2ecf20Sopenharmony_ci	qm_fqd_set_destwq(&opts.fqd, qm_channel_caam, 2);
1978c2ecf20Sopenharmony_ci	opts.fqd.context_b = cpu_to_be32(qman_fq_fqid(rsp_fq));
1988c2ecf20Sopenharmony_ci	qm_fqd_context_a_set64(&opts.fqd, hwdesc);
1998c2ecf20Sopenharmony_ci	opts.fqd.cgid = qipriv.cgr.cgrid;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	ret = qman_init_fq(req_fq, fq_sched_flag, &opts);
2028c2ecf20Sopenharmony_ci	if (ret) {
2038c2ecf20Sopenharmony_ci		dev_err(qidev, "Failed to init session req FQ\n");
2048c2ecf20Sopenharmony_ci		goto init_req_fq_fail;
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	dev_dbg(qidev, "Allocated request FQ %u for CPU %u\n", req_fq->fqid,
2088c2ecf20Sopenharmony_ci		smp_processor_id());
2098c2ecf20Sopenharmony_ci	return req_fq;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ciinit_req_fq_fail:
2128c2ecf20Sopenharmony_ci	qman_destroy_fq(req_fq);
2138c2ecf20Sopenharmony_cicreate_req_fq_fail:
2148c2ecf20Sopenharmony_ci	kfree(req_fq);
2158c2ecf20Sopenharmony_ci	return ERR_PTR(ret);
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_cistatic int empty_retired_fq(struct device *qidev, struct qman_fq *fq)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	int ret;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	ret = qman_volatile_dequeue(fq, QMAN_VOLATILE_FLAG_WAIT_INT |
2238c2ecf20Sopenharmony_ci				    QMAN_VOLATILE_FLAG_FINISH,
2248c2ecf20Sopenharmony_ci				    QM_VDQCR_PRECEDENCE_VDQCR |
2258c2ecf20Sopenharmony_ci				    QM_VDQCR_NUMFRAMES_TILLEMPTY);
2268c2ecf20Sopenharmony_ci	if (ret) {
2278c2ecf20Sopenharmony_ci		dev_err(qidev, "Volatile dequeue fail for FQ: %u\n", fq->fqid);
2288c2ecf20Sopenharmony_ci		return ret;
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	do {
2328c2ecf20Sopenharmony_ci		struct qman_portal *p;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci		p = qman_get_affine_portal(smp_processor_id());
2358c2ecf20Sopenharmony_ci		qman_p_poll_dqrr(p, 16);
2368c2ecf20Sopenharmony_ci	} while (fq->flags & QMAN_FQ_STATE_NE);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	return 0;
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic int kill_fq(struct device *qidev, struct qman_fq *fq)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	u32 flags;
2448c2ecf20Sopenharmony_ci	int ret;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	ret = qman_retire_fq(fq, &flags);
2478c2ecf20Sopenharmony_ci	if (ret < 0) {
2488c2ecf20Sopenharmony_ci		dev_err(qidev, "qman_retire_fq failed: %d\n", ret);
2498c2ecf20Sopenharmony_ci		return ret;
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	if (!ret)
2538c2ecf20Sopenharmony_ci		goto empty_fq;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	/* Async FQ retirement condition */
2568c2ecf20Sopenharmony_ci	if (ret == 1) {
2578c2ecf20Sopenharmony_ci		/* Retry till FQ gets in retired state */
2588c2ecf20Sopenharmony_ci		do {
2598c2ecf20Sopenharmony_ci			msleep(20);
2608c2ecf20Sopenharmony_ci		} while (fq->state != qman_fq_state_retired);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci		WARN_ON(fq->flags & QMAN_FQ_STATE_BLOCKOOS);
2638c2ecf20Sopenharmony_ci		WARN_ON(fq->flags & QMAN_FQ_STATE_ORL);
2648c2ecf20Sopenharmony_ci	}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ciempty_fq:
2678c2ecf20Sopenharmony_ci	if (fq->flags & QMAN_FQ_STATE_NE) {
2688c2ecf20Sopenharmony_ci		ret = empty_retired_fq(qidev, fq);
2698c2ecf20Sopenharmony_ci		if (ret) {
2708c2ecf20Sopenharmony_ci			dev_err(qidev, "empty_retired_fq fail for FQ: %u\n",
2718c2ecf20Sopenharmony_ci				fq->fqid);
2728c2ecf20Sopenharmony_ci			return ret;
2738c2ecf20Sopenharmony_ci		}
2748c2ecf20Sopenharmony_ci	}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	ret = qman_oos_fq(fq);
2778c2ecf20Sopenharmony_ci	if (ret)
2788c2ecf20Sopenharmony_ci		dev_err(qidev, "OOS of FQID: %u failed\n", fq->fqid);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	qman_destroy_fq(fq);
2818c2ecf20Sopenharmony_ci	kfree(fq);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	return ret;
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_cistatic int empty_caam_fq(struct qman_fq *fq, struct caam_drv_ctx *drv_ctx)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	int ret;
2898c2ecf20Sopenharmony_ci	int retries = 10;
2908c2ecf20Sopenharmony_ci	struct qm_mcr_queryfq_np np;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	/* Wait till the older CAAM FQ get empty */
2938c2ecf20Sopenharmony_ci	do {
2948c2ecf20Sopenharmony_ci		ret = qman_query_fq_np(fq, &np);
2958c2ecf20Sopenharmony_ci		if (ret)
2968c2ecf20Sopenharmony_ci			return ret;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci		if (!qm_mcr_np_get(&np, frm_cnt))
2998c2ecf20Sopenharmony_ci			break;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci		msleep(20);
3028c2ecf20Sopenharmony_ci	} while (1);
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	/* Wait until pending jobs from this FQ are processed by CAAM */
3058c2ecf20Sopenharmony_ci	do {
3068c2ecf20Sopenharmony_ci		if (refcount_read(&drv_ctx->refcnt) == 1)
3078c2ecf20Sopenharmony_ci			break;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci		msleep(20);
3108c2ecf20Sopenharmony_ci	} while (--retries);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	if (!retries)
3138c2ecf20Sopenharmony_ci		dev_warn_once(drv_ctx->qidev, "%d frames from FQID %u still pending in CAAM\n",
3148c2ecf20Sopenharmony_ci			      refcount_read(&drv_ctx->refcnt), fq->fqid);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	return 0;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ciint caam_drv_ctx_update(struct caam_drv_ctx *drv_ctx, u32 *sh_desc)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	int ret;
3228c2ecf20Sopenharmony_ci	u32 num_words;
3238c2ecf20Sopenharmony_ci	struct qman_fq *new_fq, *old_fq;
3248c2ecf20Sopenharmony_ci	struct device *qidev = drv_ctx->qidev;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	num_words = desc_len(sh_desc);
3278c2ecf20Sopenharmony_ci	if (num_words > MAX_SDLEN) {
3288c2ecf20Sopenharmony_ci		dev_err(qidev, "Invalid descriptor len: %d words\n", num_words);
3298c2ecf20Sopenharmony_ci		return -EINVAL;
3308c2ecf20Sopenharmony_ci	}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	/* Note down older req FQ */
3338c2ecf20Sopenharmony_ci	old_fq = drv_ctx->req_fq;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	/* Create a new req FQ in parked state */
3368c2ecf20Sopenharmony_ci	new_fq = create_caam_req_fq(drv_ctx->qidev, drv_ctx->rsp_fq,
3378c2ecf20Sopenharmony_ci				    drv_ctx->context_a, 0);
3388c2ecf20Sopenharmony_ci	if (IS_ERR(new_fq)) {
3398c2ecf20Sopenharmony_ci		dev_err(qidev, "FQ allocation for shdesc update failed\n");
3408c2ecf20Sopenharmony_ci		return PTR_ERR(new_fq);
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	/* Hook up new FQ to context so that new requests keep queuing */
3448c2ecf20Sopenharmony_ci	drv_ctx->req_fq = new_fq;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	/* Empty and remove the older FQ */
3478c2ecf20Sopenharmony_ci	ret = empty_caam_fq(old_fq, drv_ctx);
3488c2ecf20Sopenharmony_ci	if (ret) {
3498c2ecf20Sopenharmony_ci		dev_err(qidev, "Old CAAM FQ empty failed: %d\n", ret);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci		/* We can revert to older FQ */
3528c2ecf20Sopenharmony_ci		drv_ctx->req_fq = old_fq;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci		if (kill_fq(qidev, new_fq))
3558c2ecf20Sopenharmony_ci			dev_warn(qidev, "New CAAM FQ kill failed\n");
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci		return ret;
3588c2ecf20Sopenharmony_ci	}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	/*
3618c2ecf20Sopenharmony_ci	 * Re-initialise pre-header. Set RSLS and SDLEN.
3628c2ecf20Sopenharmony_ci	 * Update the shared descriptor for driver context.
3638c2ecf20Sopenharmony_ci	 */
3648c2ecf20Sopenharmony_ci	drv_ctx->prehdr[0] = cpu_to_caam32((1 << PREHDR_RSLS_SHIFT) |
3658c2ecf20Sopenharmony_ci					   num_words);
3668c2ecf20Sopenharmony_ci	drv_ctx->prehdr[1] = cpu_to_caam32(PREHDR_ABS);
3678c2ecf20Sopenharmony_ci	memcpy(drv_ctx->sh_desc, sh_desc, desc_bytes(sh_desc));
3688c2ecf20Sopenharmony_ci	dma_sync_single_for_device(qidev, drv_ctx->context_a,
3698c2ecf20Sopenharmony_ci				   sizeof(drv_ctx->sh_desc) +
3708c2ecf20Sopenharmony_ci				   sizeof(drv_ctx->prehdr),
3718c2ecf20Sopenharmony_ci				   DMA_BIDIRECTIONAL);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	/* Put the new FQ in scheduled state */
3748c2ecf20Sopenharmony_ci	ret = qman_schedule_fq(new_fq);
3758c2ecf20Sopenharmony_ci	if (ret) {
3768c2ecf20Sopenharmony_ci		dev_err(qidev, "Fail to sched new CAAM FQ, ecode = %d\n", ret);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci		/*
3798c2ecf20Sopenharmony_ci		 * We can kill new FQ and revert to old FQ.
3808c2ecf20Sopenharmony_ci		 * Since the desc is already modified, it is success case
3818c2ecf20Sopenharmony_ci		 */
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci		drv_ctx->req_fq = old_fq;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci		if (kill_fq(qidev, new_fq))
3868c2ecf20Sopenharmony_ci			dev_warn(qidev, "New CAAM FQ kill failed\n");
3878c2ecf20Sopenharmony_ci	} else if (kill_fq(qidev, old_fq)) {
3888c2ecf20Sopenharmony_ci		dev_warn(qidev, "Old CAAM FQ kill failed\n");
3898c2ecf20Sopenharmony_ci	}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	return 0;
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ciEXPORT_SYMBOL(caam_drv_ctx_update);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_cistruct caam_drv_ctx *caam_drv_ctx_init(struct device *qidev,
3968c2ecf20Sopenharmony_ci				       int *cpu,
3978c2ecf20Sopenharmony_ci				       u32 *sh_desc)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	size_t size;
4008c2ecf20Sopenharmony_ci	u32 num_words;
4018c2ecf20Sopenharmony_ci	dma_addr_t hwdesc;
4028c2ecf20Sopenharmony_ci	struct caam_drv_ctx *drv_ctx;
4038c2ecf20Sopenharmony_ci	const cpumask_t *cpus = qman_affine_cpus();
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	num_words = desc_len(sh_desc);
4068c2ecf20Sopenharmony_ci	if (num_words > MAX_SDLEN) {
4078c2ecf20Sopenharmony_ci		dev_err(qidev, "Invalid descriptor len: %d words\n",
4088c2ecf20Sopenharmony_ci			num_words);
4098c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	drv_ctx = kzalloc(sizeof(*drv_ctx), GFP_ATOMIC);
4138c2ecf20Sopenharmony_ci	if (!drv_ctx)
4148c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	/*
4178c2ecf20Sopenharmony_ci	 * Initialise pre-header - set RSLS and SDLEN - and shared descriptor
4188c2ecf20Sopenharmony_ci	 * and dma-map them.
4198c2ecf20Sopenharmony_ci	 */
4208c2ecf20Sopenharmony_ci	drv_ctx->prehdr[0] = cpu_to_caam32((1 << PREHDR_RSLS_SHIFT) |
4218c2ecf20Sopenharmony_ci					   num_words);
4228c2ecf20Sopenharmony_ci	drv_ctx->prehdr[1] = cpu_to_caam32(PREHDR_ABS);
4238c2ecf20Sopenharmony_ci	memcpy(drv_ctx->sh_desc, sh_desc, desc_bytes(sh_desc));
4248c2ecf20Sopenharmony_ci	size = sizeof(drv_ctx->prehdr) + sizeof(drv_ctx->sh_desc);
4258c2ecf20Sopenharmony_ci	hwdesc = dma_map_single(qidev, drv_ctx->prehdr, size,
4268c2ecf20Sopenharmony_ci				DMA_BIDIRECTIONAL);
4278c2ecf20Sopenharmony_ci	if (dma_mapping_error(qidev, hwdesc)) {
4288c2ecf20Sopenharmony_ci		dev_err(qidev, "DMA map error for preheader + shdesc\n");
4298c2ecf20Sopenharmony_ci		kfree(drv_ctx);
4308c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
4318c2ecf20Sopenharmony_ci	}
4328c2ecf20Sopenharmony_ci	drv_ctx->context_a = hwdesc;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	/* If given CPU does not own the portal, choose another one that does */
4358c2ecf20Sopenharmony_ci	if (!cpumask_test_cpu(*cpu, cpus)) {
4368c2ecf20Sopenharmony_ci		int *pcpu = &get_cpu_var(last_cpu);
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci		*pcpu = cpumask_next(*pcpu, cpus);
4398c2ecf20Sopenharmony_ci		if (*pcpu >= nr_cpu_ids)
4408c2ecf20Sopenharmony_ci			*pcpu = cpumask_first(cpus);
4418c2ecf20Sopenharmony_ci		*cpu = *pcpu;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci		put_cpu_var(last_cpu);
4448c2ecf20Sopenharmony_ci	}
4458c2ecf20Sopenharmony_ci	drv_ctx->cpu = *cpu;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	/* Find response FQ hooked with this CPU */
4488c2ecf20Sopenharmony_ci	drv_ctx->rsp_fq = per_cpu(pcpu_qipriv.rsp_fq, drv_ctx->cpu);
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	/* Attach request FQ */
4518c2ecf20Sopenharmony_ci	drv_ctx->req_fq = create_caam_req_fq(qidev, drv_ctx->rsp_fq, hwdesc,
4528c2ecf20Sopenharmony_ci					     QMAN_INITFQ_FLAG_SCHED);
4538c2ecf20Sopenharmony_ci	if (IS_ERR(drv_ctx->req_fq)) {
4548c2ecf20Sopenharmony_ci		dev_err(qidev, "create_caam_req_fq failed\n");
4558c2ecf20Sopenharmony_ci		dma_unmap_single(qidev, hwdesc, size, DMA_BIDIRECTIONAL);
4568c2ecf20Sopenharmony_ci		kfree(drv_ctx);
4578c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
4588c2ecf20Sopenharmony_ci	}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	/* init reference counter used to track references to request FQ */
4618c2ecf20Sopenharmony_ci	refcount_set(&drv_ctx->refcnt, 1);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	drv_ctx->qidev = qidev;
4648c2ecf20Sopenharmony_ci	return drv_ctx;
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ciEXPORT_SYMBOL(caam_drv_ctx_init);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_civoid *qi_cache_alloc(gfp_t flags)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	return kmem_cache_alloc(qi_cache, flags);
4718c2ecf20Sopenharmony_ci}
4728c2ecf20Sopenharmony_ciEXPORT_SYMBOL(qi_cache_alloc);
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_civoid qi_cache_free(void *obj)
4758c2ecf20Sopenharmony_ci{
4768c2ecf20Sopenharmony_ci	kmem_cache_free(qi_cache, obj);
4778c2ecf20Sopenharmony_ci}
4788c2ecf20Sopenharmony_ciEXPORT_SYMBOL(qi_cache_free);
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_cistatic int caam_qi_poll(struct napi_struct *napi, int budget)
4818c2ecf20Sopenharmony_ci{
4828c2ecf20Sopenharmony_ci	struct caam_napi *np = container_of(napi, struct caam_napi, irqtask);
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	int cleaned = qman_p_poll_dqrr(np->p, budget);
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	if (cleaned < budget) {
4878c2ecf20Sopenharmony_ci		napi_complete(napi);
4888c2ecf20Sopenharmony_ci		qman_p_irqsource_add(np->p, QM_PIRQ_DQRI);
4898c2ecf20Sopenharmony_ci	}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	return cleaned;
4928c2ecf20Sopenharmony_ci}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_civoid caam_drv_ctx_rel(struct caam_drv_ctx *drv_ctx)
4958c2ecf20Sopenharmony_ci{
4968c2ecf20Sopenharmony_ci	if (IS_ERR_OR_NULL(drv_ctx))
4978c2ecf20Sopenharmony_ci		return;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	/* Remove request FQ */
5008c2ecf20Sopenharmony_ci	if (kill_fq(drv_ctx->qidev, drv_ctx->req_fq))
5018c2ecf20Sopenharmony_ci		dev_err(drv_ctx->qidev, "Crypto session req FQ kill failed\n");
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	dma_unmap_single(drv_ctx->qidev, drv_ctx->context_a,
5048c2ecf20Sopenharmony_ci			 sizeof(drv_ctx->sh_desc) + sizeof(drv_ctx->prehdr),
5058c2ecf20Sopenharmony_ci			 DMA_BIDIRECTIONAL);
5068c2ecf20Sopenharmony_ci	kfree(drv_ctx);
5078c2ecf20Sopenharmony_ci}
5088c2ecf20Sopenharmony_ciEXPORT_SYMBOL(caam_drv_ctx_rel);
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cistatic void caam_qi_shutdown(void *data)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	int i;
5138c2ecf20Sopenharmony_ci	struct device *qidev = data;
5148c2ecf20Sopenharmony_ci	struct caam_qi_priv *priv = &qipriv;
5158c2ecf20Sopenharmony_ci	const cpumask_t *cpus = qman_affine_cpus();
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	for_each_cpu(i, cpus) {
5188c2ecf20Sopenharmony_ci		struct napi_struct *irqtask;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci		irqtask = &per_cpu_ptr(&pcpu_qipriv.caam_napi, i)->irqtask;
5218c2ecf20Sopenharmony_ci		napi_disable(irqtask);
5228c2ecf20Sopenharmony_ci		netif_napi_del(irqtask);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci		if (kill_fq(qidev, per_cpu(pcpu_qipriv.rsp_fq, i)))
5258c2ecf20Sopenharmony_ci			dev_err(qidev, "Rsp FQ kill failed, cpu: %d\n", i);
5268c2ecf20Sopenharmony_ci	}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	qman_delete_cgr_safe(&priv->cgr);
5298c2ecf20Sopenharmony_ci	qman_release_cgrid(priv->cgr.cgrid);
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	kmem_cache_destroy(qi_cache);
5328c2ecf20Sopenharmony_ci}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_cistatic void cgr_cb(struct qman_portal *qm, struct qman_cgr *cgr, int congested)
5358c2ecf20Sopenharmony_ci{
5368c2ecf20Sopenharmony_ci	caam_congested = congested;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	if (congested) {
5398c2ecf20Sopenharmony_ci		caam_debugfs_qi_congested();
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci		pr_debug_ratelimited("CAAM entered congestion\n");
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	} else {
5448c2ecf20Sopenharmony_ci		pr_debug_ratelimited("CAAM exited congestion\n");
5458c2ecf20Sopenharmony_ci	}
5468c2ecf20Sopenharmony_ci}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_cistatic int caam_qi_napi_schedule(struct qman_portal *p, struct caam_napi *np)
5498c2ecf20Sopenharmony_ci{
5508c2ecf20Sopenharmony_ci	/*
5518c2ecf20Sopenharmony_ci	 * In case of threaded ISR, for RT kernels in_irq() does not return
5528c2ecf20Sopenharmony_ci	 * appropriate value, so use in_serving_softirq to distinguish between
5538c2ecf20Sopenharmony_ci	 * softirq and irq contexts.
5548c2ecf20Sopenharmony_ci	 */
5558c2ecf20Sopenharmony_ci	if (unlikely(in_irq() || !in_serving_softirq())) {
5568c2ecf20Sopenharmony_ci		/* Disable QMan IRQ source and invoke NAPI */
5578c2ecf20Sopenharmony_ci		qman_p_irqsource_remove(p, QM_PIRQ_DQRI);
5588c2ecf20Sopenharmony_ci		np->p = p;
5598c2ecf20Sopenharmony_ci		napi_schedule(&np->irqtask);
5608c2ecf20Sopenharmony_ci		return 1;
5618c2ecf20Sopenharmony_ci	}
5628c2ecf20Sopenharmony_ci	return 0;
5638c2ecf20Sopenharmony_ci}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_cistatic enum qman_cb_dqrr_result caam_rsp_fq_dqrr_cb(struct qman_portal *p,
5668c2ecf20Sopenharmony_ci						    struct qman_fq *rsp_fq,
5678c2ecf20Sopenharmony_ci						    const struct qm_dqrr_entry *dqrr)
5688c2ecf20Sopenharmony_ci{
5698c2ecf20Sopenharmony_ci	struct caam_napi *caam_napi = raw_cpu_ptr(&pcpu_qipriv.caam_napi);
5708c2ecf20Sopenharmony_ci	struct caam_drv_req *drv_req;
5718c2ecf20Sopenharmony_ci	const struct qm_fd *fd;
5728c2ecf20Sopenharmony_ci	struct device *qidev = &(raw_cpu_ptr(&pcpu_qipriv)->net_dev.dev);
5738c2ecf20Sopenharmony_ci	struct caam_drv_private *priv = dev_get_drvdata(qidev);
5748c2ecf20Sopenharmony_ci	u32 status;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	if (caam_qi_napi_schedule(p, caam_napi))
5778c2ecf20Sopenharmony_ci		return qman_cb_dqrr_stop;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	fd = &dqrr->fd;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	drv_req = caam_iova_to_virt(priv->domain, qm_fd_addr_get64(fd));
5828c2ecf20Sopenharmony_ci	if (unlikely(!drv_req)) {
5838c2ecf20Sopenharmony_ci		dev_err(qidev,
5848c2ecf20Sopenharmony_ci			"Can't find original request for caam response\n");
5858c2ecf20Sopenharmony_ci		return qman_cb_dqrr_consume;
5868c2ecf20Sopenharmony_ci	}
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	refcount_dec(&drv_req->drv_ctx->refcnt);
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	status = be32_to_cpu(fd->status);
5918c2ecf20Sopenharmony_ci	if (unlikely(status)) {
5928c2ecf20Sopenharmony_ci		u32 ssrc = status & JRSTA_SSRC_MASK;
5938c2ecf20Sopenharmony_ci		u8 err_id = status & JRSTA_CCBERR_ERRID_MASK;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci		if (ssrc != JRSTA_SSRC_CCB_ERROR ||
5968c2ecf20Sopenharmony_ci		    err_id != JRSTA_CCBERR_ERRID_ICVCHK)
5978c2ecf20Sopenharmony_ci			dev_err_ratelimited(qidev,
5988c2ecf20Sopenharmony_ci					    "Error: %#x in CAAM response FD\n",
5998c2ecf20Sopenharmony_ci					    status);
6008c2ecf20Sopenharmony_ci	}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	if (unlikely(qm_fd_get_format(fd) != qm_fd_compound)) {
6038c2ecf20Sopenharmony_ci		dev_err(qidev, "Non-compound FD from CAAM\n");
6048c2ecf20Sopenharmony_ci		return qman_cb_dqrr_consume;
6058c2ecf20Sopenharmony_ci	}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	dma_unmap_single(drv_req->drv_ctx->qidev, qm_fd_addr(fd),
6088c2ecf20Sopenharmony_ci			 sizeof(drv_req->fd_sgt), DMA_BIDIRECTIONAL);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	drv_req->cbk(drv_req, status);
6118c2ecf20Sopenharmony_ci	return qman_cb_dqrr_consume;
6128c2ecf20Sopenharmony_ci}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_cistatic int alloc_rsp_fq_cpu(struct device *qidev, unsigned int cpu)
6158c2ecf20Sopenharmony_ci{
6168c2ecf20Sopenharmony_ci	struct qm_mcc_initfq opts;
6178c2ecf20Sopenharmony_ci	struct qman_fq *fq;
6188c2ecf20Sopenharmony_ci	int ret;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	fq = kzalloc(sizeof(*fq), GFP_KERNEL | GFP_DMA);
6218c2ecf20Sopenharmony_ci	if (!fq)
6228c2ecf20Sopenharmony_ci		return -ENOMEM;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	fq->cb.dqrr = caam_rsp_fq_dqrr_cb;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	ret = qman_create_fq(0, QMAN_FQ_FLAG_NO_ENQUEUE |
6278c2ecf20Sopenharmony_ci			     QMAN_FQ_FLAG_DYNAMIC_FQID, fq);
6288c2ecf20Sopenharmony_ci	if (ret) {
6298c2ecf20Sopenharmony_ci		dev_err(qidev, "Rsp FQ create failed\n");
6308c2ecf20Sopenharmony_ci		kfree(fq);
6318c2ecf20Sopenharmony_ci		return -ENODEV;
6328c2ecf20Sopenharmony_ci	}
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	memset(&opts, 0, sizeof(opts));
6358c2ecf20Sopenharmony_ci	opts.we_mask = cpu_to_be16(QM_INITFQ_WE_FQCTRL | QM_INITFQ_WE_DESTWQ |
6368c2ecf20Sopenharmony_ci				   QM_INITFQ_WE_CONTEXTB |
6378c2ecf20Sopenharmony_ci				   QM_INITFQ_WE_CONTEXTA | QM_INITFQ_WE_CGID);
6388c2ecf20Sopenharmony_ci	opts.fqd.fq_ctrl = cpu_to_be16(QM_FQCTRL_CTXASTASHING |
6398c2ecf20Sopenharmony_ci				       QM_FQCTRL_CPCSTASH | QM_FQCTRL_CGE);
6408c2ecf20Sopenharmony_ci	qm_fqd_set_destwq(&opts.fqd, qman_affine_channel(cpu), 3);
6418c2ecf20Sopenharmony_ci	opts.fqd.cgid = qipriv.cgr.cgrid;
6428c2ecf20Sopenharmony_ci	opts.fqd.context_a.stashing.exclusive =	QM_STASHING_EXCL_CTX |
6438c2ecf20Sopenharmony_ci						QM_STASHING_EXCL_DATA;
6448c2ecf20Sopenharmony_ci	qm_fqd_set_stashing(&opts.fqd, 0, 1, 1);
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	ret = qman_init_fq(fq, QMAN_INITFQ_FLAG_SCHED, &opts);
6478c2ecf20Sopenharmony_ci	if (ret) {
6488c2ecf20Sopenharmony_ci		dev_err(qidev, "Rsp FQ init failed\n");
6498c2ecf20Sopenharmony_ci		kfree(fq);
6508c2ecf20Sopenharmony_ci		return -ENODEV;
6518c2ecf20Sopenharmony_ci	}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	per_cpu(pcpu_qipriv.rsp_fq, cpu) = fq;
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	dev_dbg(qidev, "Allocated response FQ %u for CPU %u", fq->fqid, cpu);
6568c2ecf20Sopenharmony_ci	return 0;
6578c2ecf20Sopenharmony_ci}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_cistatic int init_cgr(struct device *qidev)
6608c2ecf20Sopenharmony_ci{
6618c2ecf20Sopenharmony_ci	int ret;
6628c2ecf20Sopenharmony_ci	struct qm_mcc_initcgr opts;
6638c2ecf20Sopenharmony_ci	const u64 val = (u64)cpumask_weight(qman_affine_cpus()) *
6648c2ecf20Sopenharmony_ci			MAX_RSP_FQ_BACKLOG_PER_CPU;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	ret = qman_alloc_cgrid(&qipriv.cgr.cgrid);
6678c2ecf20Sopenharmony_ci	if (ret) {
6688c2ecf20Sopenharmony_ci		dev_err(qidev, "CGR alloc failed for rsp FQs: %d\n", ret);
6698c2ecf20Sopenharmony_ci		return ret;
6708c2ecf20Sopenharmony_ci	}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	qipriv.cgr.cb = cgr_cb;
6738c2ecf20Sopenharmony_ci	memset(&opts, 0, sizeof(opts));
6748c2ecf20Sopenharmony_ci	opts.we_mask = cpu_to_be16(QM_CGR_WE_CSCN_EN | QM_CGR_WE_CS_THRES |
6758c2ecf20Sopenharmony_ci				   QM_CGR_WE_MODE);
6768c2ecf20Sopenharmony_ci	opts.cgr.cscn_en = QM_CGR_EN;
6778c2ecf20Sopenharmony_ci	opts.cgr.mode = QMAN_CGR_MODE_FRAME;
6788c2ecf20Sopenharmony_ci	qm_cgr_cs_thres_set64(&opts.cgr.cs_thres, val, 1);
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	ret = qman_create_cgr(&qipriv.cgr, QMAN_CGR_FLAG_USE_INIT, &opts);
6818c2ecf20Sopenharmony_ci	if (ret) {
6828c2ecf20Sopenharmony_ci		dev_err(qidev, "Error %d creating CAAM CGRID: %u\n", ret,
6838c2ecf20Sopenharmony_ci			qipriv.cgr.cgrid);
6848c2ecf20Sopenharmony_ci		return ret;
6858c2ecf20Sopenharmony_ci	}
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	dev_dbg(qidev, "Congestion threshold set to %llu\n", val);
6888c2ecf20Sopenharmony_ci	return 0;
6898c2ecf20Sopenharmony_ci}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_cistatic int alloc_rsp_fqs(struct device *qidev)
6928c2ecf20Sopenharmony_ci{
6938c2ecf20Sopenharmony_ci	int ret, i;
6948c2ecf20Sopenharmony_ci	const cpumask_t *cpus = qman_affine_cpus();
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	/*Now create response FQs*/
6978c2ecf20Sopenharmony_ci	for_each_cpu(i, cpus) {
6988c2ecf20Sopenharmony_ci		ret = alloc_rsp_fq_cpu(qidev, i);
6998c2ecf20Sopenharmony_ci		if (ret) {
7008c2ecf20Sopenharmony_ci			dev_err(qidev, "CAAM rsp FQ alloc failed, cpu: %u", i);
7018c2ecf20Sopenharmony_ci			return ret;
7028c2ecf20Sopenharmony_ci		}
7038c2ecf20Sopenharmony_ci	}
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	return 0;
7068c2ecf20Sopenharmony_ci}
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_cistatic void free_rsp_fqs(void)
7098c2ecf20Sopenharmony_ci{
7108c2ecf20Sopenharmony_ci	int i;
7118c2ecf20Sopenharmony_ci	const cpumask_t *cpus = qman_affine_cpus();
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	for_each_cpu(i, cpus)
7148c2ecf20Sopenharmony_ci		kfree(per_cpu(pcpu_qipriv.rsp_fq, i));
7158c2ecf20Sopenharmony_ci}
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ciint caam_qi_init(struct platform_device *caam_pdev)
7188c2ecf20Sopenharmony_ci{
7198c2ecf20Sopenharmony_ci	int err, i;
7208c2ecf20Sopenharmony_ci	struct device *ctrldev = &caam_pdev->dev, *qidev;
7218c2ecf20Sopenharmony_ci	struct caam_drv_private *ctrlpriv;
7228c2ecf20Sopenharmony_ci	const cpumask_t *cpus = qman_affine_cpus();
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	ctrlpriv = dev_get_drvdata(ctrldev);
7258c2ecf20Sopenharmony_ci	qidev = ctrldev;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	/* Initialize the congestion detection */
7288c2ecf20Sopenharmony_ci	err = init_cgr(qidev);
7298c2ecf20Sopenharmony_ci	if (err) {
7308c2ecf20Sopenharmony_ci		dev_err(qidev, "CGR initialization failed: %d\n", err);
7318c2ecf20Sopenharmony_ci		return err;
7328c2ecf20Sopenharmony_ci	}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	/* Initialise response FQs */
7358c2ecf20Sopenharmony_ci	err = alloc_rsp_fqs(qidev);
7368c2ecf20Sopenharmony_ci	if (err) {
7378c2ecf20Sopenharmony_ci		dev_err(qidev, "Can't allocate CAAM response FQs: %d\n", err);
7388c2ecf20Sopenharmony_ci		free_rsp_fqs();
7398c2ecf20Sopenharmony_ci		return err;
7408c2ecf20Sopenharmony_ci	}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	/*
7438c2ecf20Sopenharmony_ci	 * Enable the NAPI contexts on each of the core which has an affine
7448c2ecf20Sopenharmony_ci	 * portal.
7458c2ecf20Sopenharmony_ci	 */
7468c2ecf20Sopenharmony_ci	for_each_cpu(i, cpus) {
7478c2ecf20Sopenharmony_ci		struct caam_qi_pcpu_priv *priv = per_cpu_ptr(&pcpu_qipriv, i);
7488c2ecf20Sopenharmony_ci		struct caam_napi *caam_napi = &priv->caam_napi;
7498c2ecf20Sopenharmony_ci		struct napi_struct *irqtask = &caam_napi->irqtask;
7508c2ecf20Sopenharmony_ci		struct net_device *net_dev = &priv->net_dev;
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci		net_dev->dev = *qidev;
7538c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&net_dev->napi_list);
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci		netif_napi_add(net_dev, irqtask, caam_qi_poll,
7568c2ecf20Sopenharmony_ci			       CAAM_NAPI_WEIGHT);
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci		napi_enable(irqtask);
7598c2ecf20Sopenharmony_ci	}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	qi_cache = kmem_cache_create("caamqicache", CAAM_QI_MEMCACHE_SIZE, 0,
7628c2ecf20Sopenharmony_ci				     SLAB_CACHE_DMA, NULL);
7638c2ecf20Sopenharmony_ci	if (!qi_cache) {
7648c2ecf20Sopenharmony_ci		dev_err(qidev, "Can't allocate CAAM cache\n");
7658c2ecf20Sopenharmony_ci		free_rsp_fqs();
7668c2ecf20Sopenharmony_ci		return -ENOMEM;
7678c2ecf20Sopenharmony_ci	}
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	caam_debugfs_qi_init(ctrlpriv);
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	err = devm_add_action_or_reset(qidev, caam_qi_shutdown, ctrlpriv);
7728c2ecf20Sopenharmony_ci	if (err)
7738c2ecf20Sopenharmony_ci		return err;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	dev_info(qidev, "Linux CAAM Queue I/F driver initialised\n");
7768c2ecf20Sopenharmony_ci	return 0;
7778c2ecf20Sopenharmony_ci}
778