18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Handle async block request by crypto hardware engine. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2016 Linaro, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Baolin Wang <baolin.wang@linaro.org> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/err.h> 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <linux/device.h> 138c2ecf20Sopenharmony_ci#include <crypto/engine.h> 148c2ecf20Sopenharmony_ci#include <uapi/linux/sched/types.h> 158c2ecf20Sopenharmony_ci#include "internal.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define CRYPTO_ENGINE_MAX_QLEN 10 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/** 208c2ecf20Sopenharmony_ci * crypto_finalize_request - finalize one request if the request is done 218c2ecf20Sopenharmony_ci * @engine: the hardware engine 228c2ecf20Sopenharmony_ci * @req: the request need to be finalized 238c2ecf20Sopenharmony_ci * @err: error number 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_cistatic void crypto_finalize_request(struct crypto_engine *engine, 268c2ecf20Sopenharmony_ci struct crypto_async_request *req, int err) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci unsigned long flags; 298c2ecf20Sopenharmony_ci bool finalize_req = false; 308c2ecf20Sopenharmony_ci int ret; 318c2ecf20Sopenharmony_ci struct crypto_engine_ctx *enginectx; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci /* 348c2ecf20Sopenharmony_ci * If hardware cannot enqueue more requests 358c2ecf20Sopenharmony_ci * and retry mechanism is not supported 368c2ecf20Sopenharmony_ci * make sure we are completing the current request 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_ci if (!engine->retry_support) { 398c2ecf20Sopenharmony_ci spin_lock_irqsave(&engine->queue_lock, flags); 408c2ecf20Sopenharmony_ci if (engine->cur_req == req) { 418c2ecf20Sopenharmony_ci finalize_req = true; 428c2ecf20Sopenharmony_ci engine->cur_req = NULL; 438c2ecf20Sopenharmony_ci } 448c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&engine->queue_lock, flags); 458c2ecf20Sopenharmony_ci } 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (finalize_req || engine->retry_support) { 488c2ecf20Sopenharmony_ci enginectx = crypto_tfm_ctx(req->tfm); 498c2ecf20Sopenharmony_ci if (enginectx->op.prepare_request && 508c2ecf20Sopenharmony_ci enginectx->op.unprepare_request) { 518c2ecf20Sopenharmony_ci ret = enginectx->op.unprepare_request(engine, req); 528c2ecf20Sopenharmony_ci if (ret) 538c2ecf20Sopenharmony_ci dev_err(engine->dev, "failed to unprepare request\n"); 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci req->complete(req, err); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci kthread_queue_work(engine->kworker, &engine->pump_requests); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/** 628c2ecf20Sopenharmony_ci * crypto_pump_requests - dequeue one request from engine queue to process 638c2ecf20Sopenharmony_ci * @engine: the hardware engine 648c2ecf20Sopenharmony_ci * @in_kthread: true if we are in the context of the request pump thread 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * This function checks if there is any request in the engine queue that 678c2ecf20Sopenharmony_ci * needs processing and if so call out to the driver to initialize hardware 688c2ecf20Sopenharmony_ci * and handle each request. 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_cistatic void crypto_pump_requests(struct crypto_engine *engine, 718c2ecf20Sopenharmony_ci bool in_kthread) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct crypto_async_request *async_req, *backlog; 748c2ecf20Sopenharmony_ci unsigned long flags; 758c2ecf20Sopenharmony_ci bool was_busy = false; 768c2ecf20Sopenharmony_ci int ret; 778c2ecf20Sopenharmony_ci struct crypto_engine_ctx *enginectx; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci spin_lock_irqsave(&engine->queue_lock, flags); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* Make sure we are not already running a request */ 828c2ecf20Sopenharmony_ci if (!engine->retry_support && engine->cur_req) 838c2ecf20Sopenharmony_ci goto out; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* If another context is idling then defer */ 868c2ecf20Sopenharmony_ci if (engine->idling) { 878c2ecf20Sopenharmony_ci kthread_queue_work(engine->kworker, &engine->pump_requests); 888c2ecf20Sopenharmony_ci goto out; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* Check if the engine queue is idle */ 928c2ecf20Sopenharmony_ci if (!crypto_queue_len(&engine->queue) || !engine->running) { 938c2ecf20Sopenharmony_ci if (!engine->busy) 948c2ecf20Sopenharmony_ci goto out; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* Only do teardown in the thread */ 978c2ecf20Sopenharmony_ci if (!in_kthread) { 988c2ecf20Sopenharmony_ci kthread_queue_work(engine->kworker, 998c2ecf20Sopenharmony_ci &engine->pump_requests); 1008c2ecf20Sopenharmony_ci goto out; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci engine->busy = false; 1048c2ecf20Sopenharmony_ci engine->idling = true; 1058c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&engine->queue_lock, flags); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (engine->unprepare_crypt_hardware && 1088c2ecf20Sopenharmony_ci engine->unprepare_crypt_hardware(engine)) 1098c2ecf20Sopenharmony_ci dev_err(engine->dev, "failed to unprepare crypt hardware\n"); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci spin_lock_irqsave(&engine->queue_lock, flags); 1128c2ecf20Sopenharmony_ci engine->idling = false; 1138c2ecf20Sopenharmony_ci goto out; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistart_request: 1178c2ecf20Sopenharmony_ci /* Get the fist request from the engine queue to handle */ 1188c2ecf20Sopenharmony_ci backlog = crypto_get_backlog(&engine->queue); 1198c2ecf20Sopenharmony_ci async_req = crypto_dequeue_request(&engine->queue); 1208c2ecf20Sopenharmony_ci if (!async_req) 1218c2ecf20Sopenharmony_ci goto out; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* 1248c2ecf20Sopenharmony_ci * If hardware doesn't support the retry mechanism, 1258c2ecf20Sopenharmony_ci * keep track of the request we are processing now. 1268c2ecf20Sopenharmony_ci * We'll need it on completion (crypto_finalize_request). 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ci if (!engine->retry_support) 1298c2ecf20Sopenharmony_ci engine->cur_req = async_req; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (backlog) 1328c2ecf20Sopenharmony_ci backlog->complete(backlog, -EINPROGRESS); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (engine->busy) 1358c2ecf20Sopenharmony_ci was_busy = true; 1368c2ecf20Sopenharmony_ci else 1378c2ecf20Sopenharmony_ci engine->busy = true; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&engine->queue_lock, flags); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* Until here we get the request need to be encrypted successfully */ 1428c2ecf20Sopenharmony_ci if (!was_busy && engine->prepare_crypt_hardware) { 1438c2ecf20Sopenharmony_ci ret = engine->prepare_crypt_hardware(engine); 1448c2ecf20Sopenharmony_ci if (ret) { 1458c2ecf20Sopenharmony_ci dev_err(engine->dev, "failed to prepare crypt hardware\n"); 1468c2ecf20Sopenharmony_ci goto req_err_2; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci enginectx = crypto_tfm_ctx(async_req->tfm); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (enginectx->op.prepare_request) { 1538c2ecf20Sopenharmony_ci ret = enginectx->op.prepare_request(engine, async_req); 1548c2ecf20Sopenharmony_ci if (ret) { 1558c2ecf20Sopenharmony_ci dev_err(engine->dev, "failed to prepare request: %d\n", 1568c2ecf20Sopenharmony_ci ret); 1578c2ecf20Sopenharmony_ci goto req_err_2; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci if (!enginectx->op.do_one_request) { 1618c2ecf20Sopenharmony_ci dev_err(engine->dev, "failed to do request\n"); 1628c2ecf20Sopenharmony_ci ret = -EINVAL; 1638c2ecf20Sopenharmony_ci goto req_err_1; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci ret = enginectx->op.do_one_request(engine, async_req); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* Request unsuccessfully executed by hardware */ 1698c2ecf20Sopenharmony_ci if (ret < 0) { 1708c2ecf20Sopenharmony_ci /* 1718c2ecf20Sopenharmony_ci * If hardware queue is full (-ENOSPC), requeue request 1728c2ecf20Sopenharmony_ci * regardless of backlog flag. 1738c2ecf20Sopenharmony_ci * Otherwise, unprepare and complete the request. 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_ci if (!engine->retry_support || 1768c2ecf20Sopenharmony_ci (ret != -ENOSPC)) { 1778c2ecf20Sopenharmony_ci dev_err(engine->dev, 1788c2ecf20Sopenharmony_ci "Failed to do one request from queue: %d\n", 1798c2ecf20Sopenharmony_ci ret); 1808c2ecf20Sopenharmony_ci goto req_err_1; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci /* 1838c2ecf20Sopenharmony_ci * If retry mechanism is supported, 1848c2ecf20Sopenharmony_ci * unprepare current request and 1858c2ecf20Sopenharmony_ci * enqueue it back into crypto-engine queue. 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_ci if (enginectx->op.unprepare_request) { 1888c2ecf20Sopenharmony_ci ret = enginectx->op.unprepare_request(engine, 1898c2ecf20Sopenharmony_ci async_req); 1908c2ecf20Sopenharmony_ci if (ret) 1918c2ecf20Sopenharmony_ci dev_err(engine->dev, 1928c2ecf20Sopenharmony_ci "failed to unprepare request\n"); 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci spin_lock_irqsave(&engine->queue_lock, flags); 1958c2ecf20Sopenharmony_ci /* 1968c2ecf20Sopenharmony_ci * If hardware was unable to execute request, enqueue it 1978c2ecf20Sopenharmony_ci * back in front of crypto-engine queue, to keep the order 1988c2ecf20Sopenharmony_ci * of requests. 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_ci crypto_enqueue_request_head(&engine->queue, async_req); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci kthread_queue_work(engine->kworker, &engine->pump_requests); 2038c2ecf20Sopenharmony_ci goto out; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci goto retry; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cireq_err_1: 2098c2ecf20Sopenharmony_ci if (enginectx->op.unprepare_request) { 2108c2ecf20Sopenharmony_ci ret = enginectx->op.unprepare_request(engine, async_req); 2118c2ecf20Sopenharmony_ci if (ret) 2128c2ecf20Sopenharmony_ci dev_err(engine->dev, "failed to unprepare request\n"); 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cireq_err_2: 2168c2ecf20Sopenharmony_ci async_req->complete(async_req, ret); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ciretry: 2198c2ecf20Sopenharmony_ci /* If retry mechanism is supported, send new requests to engine */ 2208c2ecf20Sopenharmony_ci if (engine->retry_support) { 2218c2ecf20Sopenharmony_ci spin_lock_irqsave(&engine->queue_lock, flags); 2228c2ecf20Sopenharmony_ci goto start_request; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci return; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ciout: 2278c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&engine->queue_lock, flags); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* 2308c2ecf20Sopenharmony_ci * Batch requests is possible only if 2318c2ecf20Sopenharmony_ci * hardware can enqueue multiple requests 2328c2ecf20Sopenharmony_ci */ 2338c2ecf20Sopenharmony_ci if (engine->do_batch_requests) { 2348c2ecf20Sopenharmony_ci ret = engine->do_batch_requests(engine); 2358c2ecf20Sopenharmony_ci if (ret) 2368c2ecf20Sopenharmony_ci dev_err(engine->dev, "failed to do batch requests: %d\n", 2378c2ecf20Sopenharmony_ci ret); 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci return; 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic void crypto_pump_work(struct kthread_work *work) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci struct crypto_engine *engine = 2468c2ecf20Sopenharmony_ci container_of(work, struct crypto_engine, pump_requests); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci crypto_pump_requests(engine, true); 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci/** 2528c2ecf20Sopenharmony_ci * crypto_transfer_request - transfer the new request into the engine queue 2538c2ecf20Sopenharmony_ci * @engine: the hardware engine 2548c2ecf20Sopenharmony_ci * @req: the request need to be listed into the engine queue 2558c2ecf20Sopenharmony_ci */ 2568c2ecf20Sopenharmony_cistatic int crypto_transfer_request(struct crypto_engine *engine, 2578c2ecf20Sopenharmony_ci struct crypto_async_request *req, 2588c2ecf20Sopenharmony_ci bool need_pump) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci unsigned long flags; 2618c2ecf20Sopenharmony_ci int ret; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci spin_lock_irqsave(&engine->queue_lock, flags); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (!engine->running) { 2668c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&engine->queue_lock, flags); 2678c2ecf20Sopenharmony_ci return -ESHUTDOWN; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci ret = crypto_enqueue_request(&engine->queue, req); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (!engine->busy && need_pump) 2738c2ecf20Sopenharmony_ci kthread_queue_work(engine->kworker, &engine->pump_requests); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&engine->queue_lock, flags); 2768c2ecf20Sopenharmony_ci return ret; 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci/** 2808c2ecf20Sopenharmony_ci * crypto_transfer_request_to_engine - transfer one request to list 2818c2ecf20Sopenharmony_ci * into the engine queue 2828c2ecf20Sopenharmony_ci * @engine: the hardware engine 2838c2ecf20Sopenharmony_ci * @req: the request need to be listed into the engine queue 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_cistatic int crypto_transfer_request_to_engine(struct crypto_engine *engine, 2868c2ecf20Sopenharmony_ci struct crypto_async_request *req) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci return crypto_transfer_request(engine, req, true); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci/** 2928c2ecf20Sopenharmony_ci * crypto_transfer_aead_request_to_engine - transfer one aead_request 2938c2ecf20Sopenharmony_ci * to list into the engine queue 2948c2ecf20Sopenharmony_ci * @engine: the hardware engine 2958c2ecf20Sopenharmony_ci * @req: the request need to be listed into the engine queue 2968c2ecf20Sopenharmony_ci */ 2978c2ecf20Sopenharmony_ciint crypto_transfer_aead_request_to_engine(struct crypto_engine *engine, 2988c2ecf20Sopenharmony_ci struct aead_request *req) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci return crypto_transfer_request_to_engine(engine, &req->base); 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_transfer_aead_request_to_engine); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci/** 3058c2ecf20Sopenharmony_ci * crypto_transfer_akcipher_request_to_engine - transfer one akcipher_request 3068c2ecf20Sopenharmony_ci * to list into the engine queue 3078c2ecf20Sopenharmony_ci * @engine: the hardware engine 3088c2ecf20Sopenharmony_ci * @req: the request need to be listed into the engine queue 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_ciint crypto_transfer_akcipher_request_to_engine(struct crypto_engine *engine, 3118c2ecf20Sopenharmony_ci struct akcipher_request *req) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci return crypto_transfer_request_to_engine(engine, &req->base); 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_transfer_akcipher_request_to_engine); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci/** 3188c2ecf20Sopenharmony_ci * crypto_transfer_hash_request_to_engine - transfer one ahash_request 3198c2ecf20Sopenharmony_ci * to list into the engine queue 3208c2ecf20Sopenharmony_ci * @engine: the hardware engine 3218c2ecf20Sopenharmony_ci * @req: the request need to be listed into the engine queue 3228c2ecf20Sopenharmony_ci */ 3238c2ecf20Sopenharmony_ciint crypto_transfer_hash_request_to_engine(struct crypto_engine *engine, 3248c2ecf20Sopenharmony_ci struct ahash_request *req) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci return crypto_transfer_request_to_engine(engine, &req->base); 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_transfer_hash_request_to_engine); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci/** 3318c2ecf20Sopenharmony_ci * crypto_transfer_skcipher_request_to_engine - transfer one skcipher_request 3328c2ecf20Sopenharmony_ci * to list into the engine queue 3338c2ecf20Sopenharmony_ci * @engine: the hardware engine 3348c2ecf20Sopenharmony_ci * @req: the request need to be listed into the engine queue 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_ciint crypto_transfer_skcipher_request_to_engine(struct crypto_engine *engine, 3378c2ecf20Sopenharmony_ci struct skcipher_request *req) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci return crypto_transfer_request_to_engine(engine, &req->base); 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_transfer_skcipher_request_to_engine); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci/** 3448c2ecf20Sopenharmony_ci * crypto_finalize_aead_request - finalize one aead_request if 3458c2ecf20Sopenharmony_ci * the request is done 3468c2ecf20Sopenharmony_ci * @engine: the hardware engine 3478c2ecf20Sopenharmony_ci * @req: the request need to be finalized 3488c2ecf20Sopenharmony_ci * @err: error number 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_civoid crypto_finalize_aead_request(struct crypto_engine *engine, 3518c2ecf20Sopenharmony_ci struct aead_request *req, int err) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci return crypto_finalize_request(engine, &req->base, err); 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_finalize_aead_request); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci/** 3588c2ecf20Sopenharmony_ci * crypto_finalize_akcipher_request - finalize one akcipher_request if 3598c2ecf20Sopenharmony_ci * the request is done 3608c2ecf20Sopenharmony_ci * @engine: the hardware engine 3618c2ecf20Sopenharmony_ci * @req: the request need to be finalized 3628c2ecf20Sopenharmony_ci * @err: error number 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_civoid crypto_finalize_akcipher_request(struct crypto_engine *engine, 3658c2ecf20Sopenharmony_ci struct akcipher_request *req, int err) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci return crypto_finalize_request(engine, &req->base, err); 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_finalize_akcipher_request); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci/** 3728c2ecf20Sopenharmony_ci * crypto_finalize_hash_request - finalize one ahash_request if 3738c2ecf20Sopenharmony_ci * the request is done 3748c2ecf20Sopenharmony_ci * @engine: the hardware engine 3758c2ecf20Sopenharmony_ci * @req: the request need to be finalized 3768c2ecf20Sopenharmony_ci * @err: error number 3778c2ecf20Sopenharmony_ci */ 3788c2ecf20Sopenharmony_civoid crypto_finalize_hash_request(struct crypto_engine *engine, 3798c2ecf20Sopenharmony_ci struct ahash_request *req, int err) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci return crypto_finalize_request(engine, &req->base, err); 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_finalize_hash_request); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci/** 3868c2ecf20Sopenharmony_ci * crypto_finalize_skcipher_request - finalize one skcipher_request if 3878c2ecf20Sopenharmony_ci * the request is done 3888c2ecf20Sopenharmony_ci * @engine: the hardware engine 3898c2ecf20Sopenharmony_ci * @req: the request need to be finalized 3908c2ecf20Sopenharmony_ci * @err: error number 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_civoid crypto_finalize_skcipher_request(struct crypto_engine *engine, 3938c2ecf20Sopenharmony_ci struct skcipher_request *req, int err) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci return crypto_finalize_request(engine, &req->base, err); 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_finalize_skcipher_request); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci/** 4008c2ecf20Sopenharmony_ci * crypto_engine_start - start the hardware engine 4018c2ecf20Sopenharmony_ci * @engine: the hardware engine need to be started 4028c2ecf20Sopenharmony_ci * 4038c2ecf20Sopenharmony_ci * Return 0 on success, else on fail. 4048c2ecf20Sopenharmony_ci */ 4058c2ecf20Sopenharmony_ciint crypto_engine_start(struct crypto_engine *engine) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci unsigned long flags; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci spin_lock_irqsave(&engine->queue_lock, flags); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (engine->running || engine->busy) { 4128c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&engine->queue_lock, flags); 4138c2ecf20Sopenharmony_ci return -EBUSY; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci engine->running = true; 4178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&engine->queue_lock, flags); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci kthread_queue_work(engine->kworker, &engine->pump_requests); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci return 0; 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_start); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci/** 4268c2ecf20Sopenharmony_ci * crypto_engine_stop - stop the hardware engine 4278c2ecf20Sopenharmony_ci * @engine: the hardware engine need to be stopped 4288c2ecf20Sopenharmony_ci * 4298c2ecf20Sopenharmony_ci * Return 0 on success, else on fail. 4308c2ecf20Sopenharmony_ci */ 4318c2ecf20Sopenharmony_ciint crypto_engine_stop(struct crypto_engine *engine) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci unsigned long flags; 4348c2ecf20Sopenharmony_ci unsigned int limit = 500; 4358c2ecf20Sopenharmony_ci int ret = 0; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci spin_lock_irqsave(&engine->queue_lock, flags); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci /* 4408c2ecf20Sopenharmony_ci * If the engine queue is not empty or the engine is on busy state, 4418c2ecf20Sopenharmony_ci * we need to wait for a while to pump the requests of engine queue. 4428c2ecf20Sopenharmony_ci */ 4438c2ecf20Sopenharmony_ci while ((crypto_queue_len(&engine->queue) || engine->busy) && limit--) { 4448c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&engine->queue_lock, flags); 4458c2ecf20Sopenharmony_ci msleep(20); 4468c2ecf20Sopenharmony_ci spin_lock_irqsave(&engine->queue_lock, flags); 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (crypto_queue_len(&engine->queue) || engine->busy) 4508c2ecf20Sopenharmony_ci ret = -EBUSY; 4518c2ecf20Sopenharmony_ci else 4528c2ecf20Sopenharmony_ci engine->running = false; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&engine->queue_lock, flags); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (ret) 4578c2ecf20Sopenharmony_ci dev_warn(engine->dev, "could not stop engine\n"); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci return ret; 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_stop); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci/** 4648c2ecf20Sopenharmony_ci * crypto_engine_alloc_init_and_set - allocate crypto hardware engine structure 4658c2ecf20Sopenharmony_ci * and initialize it by setting the maximum number of entries in the software 4668c2ecf20Sopenharmony_ci * crypto-engine queue. 4678c2ecf20Sopenharmony_ci * @dev: the device attached with one hardware engine 4688c2ecf20Sopenharmony_ci * @retry_support: whether hardware has support for retry mechanism 4698c2ecf20Sopenharmony_ci * @cbk_do_batch: pointer to a callback function to be invoked when executing 4708c2ecf20Sopenharmony_ci * a batch of requests. 4718c2ecf20Sopenharmony_ci * This has the form: 4728c2ecf20Sopenharmony_ci * callback(struct crypto_engine *engine) 4738c2ecf20Sopenharmony_ci * where: 4748c2ecf20Sopenharmony_ci * @engine: the crypto engine structure. 4758c2ecf20Sopenharmony_ci * @rt: whether this queue is set to run as a realtime task 4768c2ecf20Sopenharmony_ci * @qlen: maximum size of the crypto-engine queue 4778c2ecf20Sopenharmony_ci * 4788c2ecf20Sopenharmony_ci * This must be called from context that can sleep. 4798c2ecf20Sopenharmony_ci * Return: the crypto engine structure on success, else NULL. 4808c2ecf20Sopenharmony_ci */ 4818c2ecf20Sopenharmony_cistruct crypto_engine *crypto_engine_alloc_init_and_set(struct device *dev, 4828c2ecf20Sopenharmony_ci bool retry_support, 4838c2ecf20Sopenharmony_ci int (*cbk_do_batch)(struct crypto_engine *engine), 4848c2ecf20Sopenharmony_ci bool rt, int qlen) 4858c2ecf20Sopenharmony_ci{ 4868c2ecf20Sopenharmony_ci struct crypto_engine *engine; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (!dev) 4898c2ecf20Sopenharmony_ci return NULL; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci engine = devm_kzalloc(dev, sizeof(*engine), GFP_KERNEL); 4928c2ecf20Sopenharmony_ci if (!engine) 4938c2ecf20Sopenharmony_ci return NULL; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci engine->dev = dev; 4968c2ecf20Sopenharmony_ci engine->rt = rt; 4978c2ecf20Sopenharmony_ci engine->running = false; 4988c2ecf20Sopenharmony_ci engine->busy = false; 4998c2ecf20Sopenharmony_ci engine->idling = false; 5008c2ecf20Sopenharmony_ci engine->retry_support = retry_support; 5018c2ecf20Sopenharmony_ci engine->priv_data = dev; 5028c2ecf20Sopenharmony_ci /* 5038c2ecf20Sopenharmony_ci * Batch requests is possible only if 5048c2ecf20Sopenharmony_ci * hardware has support for retry mechanism. 5058c2ecf20Sopenharmony_ci */ 5068c2ecf20Sopenharmony_ci engine->do_batch_requests = retry_support ? cbk_do_batch : NULL; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci snprintf(engine->name, sizeof(engine->name), 5098c2ecf20Sopenharmony_ci "%s-engine", dev_name(dev)); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci crypto_init_queue(&engine->queue, qlen); 5128c2ecf20Sopenharmony_ci spin_lock_init(&engine->queue_lock); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci engine->kworker = kthread_create_worker(0, "%s", engine->name); 5158c2ecf20Sopenharmony_ci if (IS_ERR(engine->kworker)) { 5168c2ecf20Sopenharmony_ci dev_err(dev, "failed to create crypto request pump task\n"); 5178c2ecf20Sopenharmony_ci return NULL; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci kthread_init_work(&engine->pump_requests, crypto_pump_work); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (engine->rt) { 5228c2ecf20Sopenharmony_ci dev_info(dev, "will run requests pump with realtime priority\n"); 5238c2ecf20Sopenharmony_ci sched_set_fifo(engine->kworker->task); 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci return engine; 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_alloc_init_and_set); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci/** 5318c2ecf20Sopenharmony_ci * crypto_engine_alloc_init - allocate crypto hardware engine structure and 5328c2ecf20Sopenharmony_ci * initialize it. 5338c2ecf20Sopenharmony_ci * @dev: the device attached with one hardware engine 5348c2ecf20Sopenharmony_ci * @rt: whether this queue is set to run as a realtime task 5358c2ecf20Sopenharmony_ci * 5368c2ecf20Sopenharmony_ci * This must be called from context that can sleep. 5378c2ecf20Sopenharmony_ci * Return: the crypto engine structure on success, else NULL. 5388c2ecf20Sopenharmony_ci */ 5398c2ecf20Sopenharmony_cistruct crypto_engine *crypto_engine_alloc_init(struct device *dev, bool rt) 5408c2ecf20Sopenharmony_ci{ 5418c2ecf20Sopenharmony_ci return crypto_engine_alloc_init_and_set(dev, false, NULL, rt, 5428c2ecf20Sopenharmony_ci CRYPTO_ENGINE_MAX_QLEN); 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_alloc_init); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci/** 5478c2ecf20Sopenharmony_ci * crypto_engine_exit - free the resources of hardware engine when exit 5488c2ecf20Sopenharmony_ci * @engine: the hardware engine need to be freed 5498c2ecf20Sopenharmony_ci * 5508c2ecf20Sopenharmony_ci * Return 0 for success. 5518c2ecf20Sopenharmony_ci */ 5528c2ecf20Sopenharmony_ciint crypto_engine_exit(struct crypto_engine *engine) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci int ret; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci ret = crypto_engine_stop(engine); 5578c2ecf20Sopenharmony_ci if (ret) 5588c2ecf20Sopenharmony_ci return ret; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci kthread_destroy_worker(engine->kworker); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci return 0; 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_exit); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 5678c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Crypto hardware engine framework"); 568