18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * AMD Cryptographic Coprocessor (CCP) crypto API support
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2013,2017 Advanced Micro Devices, Inc.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Author: Tom Lendacky <thomas.lendacky@amd.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/list.h>
148c2ecf20Sopenharmony_ci#include <linux/ccp.h>
158c2ecf20Sopenharmony_ci#include <linux/scatterlist.h>
168c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h>
178c2ecf20Sopenharmony_ci#include <crypto/internal/akcipher.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "ccp-crypto.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ciMODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>");
228c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
238c2ecf20Sopenharmony_ciMODULE_VERSION("1.0.0");
248c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("AMD Cryptographic Coprocessor crypto API support");
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic unsigned int aes_disable;
278c2ecf20Sopenharmony_cimodule_param(aes_disable, uint, 0444);
288c2ecf20Sopenharmony_ciMODULE_PARM_DESC(aes_disable, "Disable use of AES - any non-zero value");
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic unsigned int sha_disable;
318c2ecf20Sopenharmony_cimodule_param(sha_disable, uint, 0444);
328c2ecf20Sopenharmony_ciMODULE_PARM_DESC(sha_disable, "Disable use of SHA - any non-zero value");
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic unsigned int des3_disable;
358c2ecf20Sopenharmony_cimodule_param(des3_disable, uint, 0444);
368c2ecf20Sopenharmony_ciMODULE_PARM_DESC(des3_disable, "Disable use of 3DES - any non-zero value");
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic unsigned int rsa_disable;
398c2ecf20Sopenharmony_cimodule_param(rsa_disable, uint, 0444);
408c2ecf20Sopenharmony_ciMODULE_PARM_DESC(rsa_disable, "Disable use of RSA - any non-zero value");
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/* List heads for the supported algorithms */
438c2ecf20Sopenharmony_cistatic LIST_HEAD(hash_algs);
448c2ecf20Sopenharmony_cistatic LIST_HEAD(skcipher_algs);
458c2ecf20Sopenharmony_cistatic LIST_HEAD(aead_algs);
468c2ecf20Sopenharmony_cistatic LIST_HEAD(akcipher_algs);
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/* For any tfm, requests for that tfm must be returned on the order
498c2ecf20Sopenharmony_ci * received.  With multiple queues available, the CCP can process more
508c2ecf20Sopenharmony_ci * than one cmd at a time.  Therefore we must maintain a cmd list to insure
518c2ecf20Sopenharmony_ci * the proper ordering of requests on a given tfm.
528c2ecf20Sopenharmony_ci */
538c2ecf20Sopenharmony_cistruct ccp_crypto_queue {
548c2ecf20Sopenharmony_ci	struct list_head cmds;
558c2ecf20Sopenharmony_ci	struct list_head *backlog;
568c2ecf20Sopenharmony_ci	unsigned int cmd_count;
578c2ecf20Sopenharmony_ci};
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci#define CCP_CRYPTO_MAX_QLEN	100
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic struct ccp_crypto_queue req_queue;
628c2ecf20Sopenharmony_cistatic spinlock_t req_queue_lock;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistruct ccp_crypto_cmd {
658c2ecf20Sopenharmony_ci	struct list_head entry;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	struct ccp_cmd *cmd;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	/* Save the crypto_tfm and crypto_async_request addresses
708c2ecf20Sopenharmony_ci	 * separately to avoid any reference to a possibly invalid
718c2ecf20Sopenharmony_ci	 * crypto_async_request structure after invoking the request
728c2ecf20Sopenharmony_ci	 * callback
738c2ecf20Sopenharmony_ci	 */
748c2ecf20Sopenharmony_ci	struct crypto_async_request *req;
758c2ecf20Sopenharmony_ci	struct crypto_tfm *tfm;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	/* Used for held command processing to determine state */
788c2ecf20Sopenharmony_ci	int ret;
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistruct ccp_crypto_cpu {
828c2ecf20Sopenharmony_ci	struct work_struct work;
838c2ecf20Sopenharmony_ci	struct completion completion;
848c2ecf20Sopenharmony_ci	struct ccp_crypto_cmd *crypto_cmd;
858c2ecf20Sopenharmony_ci	int err;
868c2ecf20Sopenharmony_ci};
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic inline bool ccp_crypto_success(int err)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	if (err && (err != -EINPROGRESS) && (err != -EBUSY))
918c2ecf20Sopenharmony_ci		return false;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	return true;
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic struct ccp_crypto_cmd *ccp_crypto_cmd_complete(
978c2ecf20Sopenharmony_ci	struct ccp_crypto_cmd *crypto_cmd, struct ccp_crypto_cmd **backlog)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	struct ccp_crypto_cmd *held = NULL, *tmp;
1008c2ecf20Sopenharmony_ci	unsigned long flags;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	*backlog = NULL;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	spin_lock_irqsave(&req_queue_lock, flags);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	/* Held cmds will be after the current cmd in the queue so start
1078c2ecf20Sopenharmony_ci	 * searching for a cmd with a matching tfm for submission.
1088c2ecf20Sopenharmony_ci	 */
1098c2ecf20Sopenharmony_ci	tmp = crypto_cmd;
1108c2ecf20Sopenharmony_ci	list_for_each_entry_continue(tmp, &req_queue.cmds, entry) {
1118c2ecf20Sopenharmony_ci		if (crypto_cmd->tfm != tmp->tfm)
1128c2ecf20Sopenharmony_ci			continue;
1138c2ecf20Sopenharmony_ci		held = tmp;
1148c2ecf20Sopenharmony_ci		break;
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	/* Process the backlog:
1188c2ecf20Sopenharmony_ci	 *   Because cmds can be executed from any point in the cmd list
1198c2ecf20Sopenharmony_ci	 *   special precautions have to be taken when handling the backlog.
1208c2ecf20Sopenharmony_ci	 */
1218c2ecf20Sopenharmony_ci	if (req_queue.backlog != &req_queue.cmds) {
1228c2ecf20Sopenharmony_ci		/* Skip over this cmd if it is the next backlog cmd */
1238c2ecf20Sopenharmony_ci		if (req_queue.backlog == &crypto_cmd->entry)
1248c2ecf20Sopenharmony_ci			req_queue.backlog = crypto_cmd->entry.next;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci		*backlog = container_of(req_queue.backlog,
1278c2ecf20Sopenharmony_ci					struct ccp_crypto_cmd, entry);
1288c2ecf20Sopenharmony_ci		req_queue.backlog = req_queue.backlog->next;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci		/* Skip over this cmd if it is now the next backlog cmd */
1318c2ecf20Sopenharmony_ci		if (req_queue.backlog == &crypto_cmd->entry)
1328c2ecf20Sopenharmony_ci			req_queue.backlog = crypto_cmd->entry.next;
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	/* Remove the cmd entry from the list of cmds */
1368c2ecf20Sopenharmony_ci	req_queue.cmd_count--;
1378c2ecf20Sopenharmony_ci	list_del(&crypto_cmd->entry);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&req_queue_lock, flags);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	return held;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic void ccp_crypto_complete(void *data, int err)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	struct ccp_crypto_cmd *crypto_cmd = data;
1478c2ecf20Sopenharmony_ci	struct ccp_crypto_cmd *held, *next, *backlog;
1488c2ecf20Sopenharmony_ci	struct crypto_async_request *req = crypto_cmd->req;
1498c2ecf20Sopenharmony_ci	struct ccp_ctx *ctx = crypto_tfm_ctx(req->tfm);
1508c2ecf20Sopenharmony_ci	int ret;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	if (err == -EINPROGRESS) {
1538c2ecf20Sopenharmony_ci		/* Only propagate the -EINPROGRESS if necessary */
1548c2ecf20Sopenharmony_ci		if (crypto_cmd->ret == -EBUSY) {
1558c2ecf20Sopenharmony_ci			crypto_cmd->ret = -EINPROGRESS;
1568c2ecf20Sopenharmony_ci			req->complete(req, -EINPROGRESS);
1578c2ecf20Sopenharmony_ci		}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci		return;
1608c2ecf20Sopenharmony_ci	}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	/* Operation has completed - update the queue before invoking
1638c2ecf20Sopenharmony_ci	 * the completion callbacks and retrieve the next cmd (cmd with
1648c2ecf20Sopenharmony_ci	 * a matching tfm) that can be submitted to the CCP.
1658c2ecf20Sopenharmony_ci	 */
1668c2ecf20Sopenharmony_ci	held = ccp_crypto_cmd_complete(crypto_cmd, &backlog);
1678c2ecf20Sopenharmony_ci	if (backlog) {
1688c2ecf20Sopenharmony_ci		backlog->ret = -EINPROGRESS;
1698c2ecf20Sopenharmony_ci		backlog->req->complete(backlog->req, -EINPROGRESS);
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	/* Transition the state from -EBUSY to -EINPROGRESS first */
1738c2ecf20Sopenharmony_ci	if (crypto_cmd->ret == -EBUSY)
1748c2ecf20Sopenharmony_ci		req->complete(req, -EINPROGRESS);
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	/* Completion callbacks */
1778c2ecf20Sopenharmony_ci	ret = err;
1788c2ecf20Sopenharmony_ci	if (ctx->complete)
1798c2ecf20Sopenharmony_ci		ret = ctx->complete(req, ret);
1808c2ecf20Sopenharmony_ci	req->complete(req, ret);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	/* Submit the next cmd */
1838c2ecf20Sopenharmony_ci	while (held) {
1848c2ecf20Sopenharmony_ci		/* Since we have already queued the cmd, we must indicate that
1858c2ecf20Sopenharmony_ci		 * we can backlog so as not to "lose" this request.
1868c2ecf20Sopenharmony_ci		 */
1878c2ecf20Sopenharmony_ci		held->cmd->flags |= CCP_CMD_MAY_BACKLOG;
1888c2ecf20Sopenharmony_ci		ret = ccp_enqueue_cmd(held->cmd);
1898c2ecf20Sopenharmony_ci		if (ccp_crypto_success(ret))
1908c2ecf20Sopenharmony_ci			break;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci		/* Error occurred, report it and get the next entry */
1938c2ecf20Sopenharmony_ci		ctx = crypto_tfm_ctx(held->req->tfm);
1948c2ecf20Sopenharmony_ci		if (ctx->complete)
1958c2ecf20Sopenharmony_ci			ret = ctx->complete(held->req, ret);
1968c2ecf20Sopenharmony_ci		held->req->complete(held->req, ret);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci		next = ccp_crypto_cmd_complete(held, &backlog);
1998c2ecf20Sopenharmony_ci		if (backlog) {
2008c2ecf20Sopenharmony_ci			backlog->ret = -EINPROGRESS;
2018c2ecf20Sopenharmony_ci			backlog->req->complete(backlog->req, -EINPROGRESS);
2028c2ecf20Sopenharmony_ci		}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci		kfree(held);
2058c2ecf20Sopenharmony_ci		held = next;
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	kfree(crypto_cmd);
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic int ccp_crypto_enqueue_cmd(struct ccp_crypto_cmd *crypto_cmd)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	struct ccp_crypto_cmd *active = NULL, *tmp;
2148c2ecf20Sopenharmony_ci	unsigned long flags;
2158c2ecf20Sopenharmony_ci	bool free_cmd = true;
2168c2ecf20Sopenharmony_ci	int ret;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	spin_lock_irqsave(&req_queue_lock, flags);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	/* Check if the cmd can/should be queued */
2218c2ecf20Sopenharmony_ci	if (req_queue.cmd_count >= CCP_CRYPTO_MAX_QLEN) {
2228c2ecf20Sopenharmony_ci		if (!(crypto_cmd->cmd->flags & CCP_CMD_MAY_BACKLOG)) {
2238c2ecf20Sopenharmony_ci			ret = -ENOSPC;
2248c2ecf20Sopenharmony_ci			goto e_lock;
2258c2ecf20Sopenharmony_ci		}
2268c2ecf20Sopenharmony_ci	}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	/* Look for an entry with the same tfm.  If there is a cmd
2298c2ecf20Sopenharmony_ci	 * with the same tfm in the list then the current cmd cannot
2308c2ecf20Sopenharmony_ci	 * be submitted to the CCP yet.
2318c2ecf20Sopenharmony_ci	 */
2328c2ecf20Sopenharmony_ci	list_for_each_entry(tmp, &req_queue.cmds, entry) {
2338c2ecf20Sopenharmony_ci		if (crypto_cmd->tfm != tmp->tfm)
2348c2ecf20Sopenharmony_ci			continue;
2358c2ecf20Sopenharmony_ci		active = tmp;
2368c2ecf20Sopenharmony_ci		break;
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	ret = -EINPROGRESS;
2408c2ecf20Sopenharmony_ci	if (!active) {
2418c2ecf20Sopenharmony_ci		ret = ccp_enqueue_cmd(crypto_cmd->cmd);
2428c2ecf20Sopenharmony_ci		if (!ccp_crypto_success(ret))
2438c2ecf20Sopenharmony_ci			goto e_lock;	/* Error, don't queue it */
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	if (req_queue.cmd_count >= CCP_CRYPTO_MAX_QLEN) {
2478c2ecf20Sopenharmony_ci		ret = -EBUSY;
2488c2ecf20Sopenharmony_ci		if (req_queue.backlog == &req_queue.cmds)
2498c2ecf20Sopenharmony_ci			req_queue.backlog = &crypto_cmd->entry;
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci	crypto_cmd->ret = ret;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	req_queue.cmd_count++;
2548c2ecf20Sopenharmony_ci	list_add_tail(&crypto_cmd->entry, &req_queue.cmds);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	free_cmd = false;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cie_lock:
2598c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&req_queue_lock, flags);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	if (free_cmd)
2628c2ecf20Sopenharmony_ci		kfree(crypto_cmd);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	return ret;
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci/**
2688c2ecf20Sopenharmony_ci * ccp_crypto_enqueue_request - queue an crypto async request for processing
2698c2ecf20Sopenharmony_ci *				by the CCP
2708c2ecf20Sopenharmony_ci *
2718c2ecf20Sopenharmony_ci * @req: crypto_async_request struct to be processed
2728c2ecf20Sopenharmony_ci * @cmd: ccp_cmd struct to be sent to the CCP
2738c2ecf20Sopenharmony_ci */
2748c2ecf20Sopenharmony_ciint ccp_crypto_enqueue_request(struct crypto_async_request *req,
2758c2ecf20Sopenharmony_ci			       struct ccp_cmd *cmd)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	struct ccp_crypto_cmd *crypto_cmd;
2788c2ecf20Sopenharmony_ci	gfp_t gfp;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	gfp = req->flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : GFP_ATOMIC;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	crypto_cmd = kzalloc(sizeof(*crypto_cmd), gfp);
2838c2ecf20Sopenharmony_ci	if (!crypto_cmd)
2848c2ecf20Sopenharmony_ci		return -ENOMEM;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	/* The tfm pointer must be saved and not referenced from the
2878c2ecf20Sopenharmony_ci	 * crypto_async_request (req) pointer because it is used after
2888c2ecf20Sopenharmony_ci	 * completion callback for the request and the req pointer
2898c2ecf20Sopenharmony_ci	 * might not be valid anymore.
2908c2ecf20Sopenharmony_ci	 */
2918c2ecf20Sopenharmony_ci	crypto_cmd->cmd = cmd;
2928c2ecf20Sopenharmony_ci	crypto_cmd->req = req;
2938c2ecf20Sopenharmony_ci	crypto_cmd->tfm = req->tfm;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	cmd->callback = ccp_crypto_complete;
2968c2ecf20Sopenharmony_ci	cmd->data = crypto_cmd;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	if (req->flags & CRYPTO_TFM_REQ_MAY_BACKLOG)
2998c2ecf20Sopenharmony_ci		cmd->flags |= CCP_CMD_MAY_BACKLOG;
3008c2ecf20Sopenharmony_ci	else
3018c2ecf20Sopenharmony_ci		cmd->flags &= ~CCP_CMD_MAY_BACKLOG;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	return ccp_crypto_enqueue_cmd(crypto_cmd);
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistruct scatterlist *ccp_crypto_sg_table_add(struct sg_table *table,
3078c2ecf20Sopenharmony_ci					    struct scatterlist *sg_add)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	struct scatterlist *sg, *sg_last = NULL;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	for (sg = table->sgl; sg; sg = sg_next(sg))
3128c2ecf20Sopenharmony_ci		if (!sg_page(sg))
3138c2ecf20Sopenharmony_ci			break;
3148c2ecf20Sopenharmony_ci	if (WARN_ON(!sg))
3158c2ecf20Sopenharmony_ci		return NULL;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	for (; sg && sg_add; sg = sg_next(sg), sg_add = sg_next(sg_add)) {
3188c2ecf20Sopenharmony_ci		sg_set_page(sg, sg_page(sg_add), sg_add->length,
3198c2ecf20Sopenharmony_ci			    sg_add->offset);
3208c2ecf20Sopenharmony_ci		sg_last = sg;
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci	if (WARN_ON(sg_add))
3238c2ecf20Sopenharmony_ci		return NULL;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	return sg_last;
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_cistatic int ccp_register_algs(void)
3298c2ecf20Sopenharmony_ci{
3308c2ecf20Sopenharmony_ci	int ret;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	if (!aes_disable) {
3338c2ecf20Sopenharmony_ci		ret = ccp_register_aes_algs(&skcipher_algs);
3348c2ecf20Sopenharmony_ci		if (ret)
3358c2ecf20Sopenharmony_ci			return ret;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci		ret = ccp_register_aes_cmac_algs(&hash_algs);
3388c2ecf20Sopenharmony_ci		if (ret)
3398c2ecf20Sopenharmony_ci			return ret;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci		ret = ccp_register_aes_xts_algs(&skcipher_algs);
3428c2ecf20Sopenharmony_ci		if (ret)
3438c2ecf20Sopenharmony_ci			return ret;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci		ret = ccp_register_aes_aeads(&aead_algs);
3468c2ecf20Sopenharmony_ci		if (ret)
3478c2ecf20Sopenharmony_ci			return ret;
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	if (!des3_disable) {
3518c2ecf20Sopenharmony_ci		ret = ccp_register_des3_algs(&skcipher_algs);
3528c2ecf20Sopenharmony_ci		if (ret)
3538c2ecf20Sopenharmony_ci			return ret;
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if (!sha_disable) {
3578c2ecf20Sopenharmony_ci		ret = ccp_register_sha_algs(&hash_algs);
3588c2ecf20Sopenharmony_ci		if (ret)
3598c2ecf20Sopenharmony_ci			return ret;
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	if (!rsa_disable) {
3638c2ecf20Sopenharmony_ci		ret = ccp_register_rsa_algs(&akcipher_algs);
3648c2ecf20Sopenharmony_ci		if (ret)
3658c2ecf20Sopenharmony_ci			return ret;
3668c2ecf20Sopenharmony_ci	}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	return 0;
3698c2ecf20Sopenharmony_ci}
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_cistatic void ccp_unregister_algs(void)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	struct ccp_crypto_ahash_alg *ahash_alg, *ahash_tmp;
3748c2ecf20Sopenharmony_ci	struct ccp_crypto_skcipher_alg *ablk_alg, *ablk_tmp;
3758c2ecf20Sopenharmony_ci	struct ccp_crypto_aead *aead_alg, *aead_tmp;
3768c2ecf20Sopenharmony_ci	struct ccp_crypto_akcipher_alg *akc_alg, *akc_tmp;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	list_for_each_entry_safe(ahash_alg, ahash_tmp, &hash_algs, entry) {
3798c2ecf20Sopenharmony_ci		crypto_unregister_ahash(&ahash_alg->alg);
3808c2ecf20Sopenharmony_ci		list_del(&ahash_alg->entry);
3818c2ecf20Sopenharmony_ci		kfree(ahash_alg);
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	list_for_each_entry_safe(ablk_alg, ablk_tmp, &skcipher_algs, entry) {
3858c2ecf20Sopenharmony_ci		crypto_unregister_skcipher(&ablk_alg->alg);
3868c2ecf20Sopenharmony_ci		list_del(&ablk_alg->entry);
3878c2ecf20Sopenharmony_ci		kfree(ablk_alg);
3888c2ecf20Sopenharmony_ci	}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	list_for_each_entry_safe(aead_alg, aead_tmp, &aead_algs, entry) {
3918c2ecf20Sopenharmony_ci		crypto_unregister_aead(&aead_alg->alg);
3928c2ecf20Sopenharmony_ci		list_del(&aead_alg->entry);
3938c2ecf20Sopenharmony_ci		kfree(aead_alg);
3948c2ecf20Sopenharmony_ci	}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	list_for_each_entry_safe(akc_alg, akc_tmp, &akcipher_algs, entry) {
3978c2ecf20Sopenharmony_ci		crypto_unregister_akcipher(&akc_alg->alg);
3988c2ecf20Sopenharmony_ci		list_del(&akc_alg->entry);
3998c2ecf20Sopenharmony_ci		kfree(akc_alg);
4008c2ecf20Sopenharmony_ci	}
4018c2ecf20Sopenharmony_ci}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_cistatic int ccp_crypto_init(void)
4048c2ecf20Sopenharmony_ci{
4058c2ecf20Sopenharmony_ci	int ret;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	ret = ccp_present();
4088c2ecf20Sopenharmony_ci	if (ret) {
4098c2ecf20Sopenharmony_ci		pr_err("Cannot load: there are no available CCPs\n");
4108c2ecf20Sopenharmony_ci		return ret;
4118c2ecf20Sopenharmony_ci	}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	spin_lock_init(&req_queue_lock);
4148c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&req_queue.cmds);
4158c2ecf20Sopenharmony_ci	req_queue.backlog = &req_queue.cmds;
4168c2ecf20Sopenharmony_ci	req_queue.cmd_count = 0;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	ret = ccp_register_algs();
4198c2ecf20Sopenharmony_ci	if (ret)
4208c2ecf20Sopenharmony_ci		ccp_unregister_algs();
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	return ret;
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistatic void ccp_crypto_exit(void)
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	ccp_unregister_algs();
4288c2ecf20Sopenharmony_ci}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_cimodule_init(ccp_crypto_init);
4318c2ecf20Sopenharmony_cimodule_exit(ccp_crypto_exit);
432