162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Handle async block request by crypto hardware engine. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2016 Linaro, Inc. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Baolin Wang <baolin.wang@linaro.org> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <crypto/internal/aead.h> 1162306a36Sopenharmony_ci#include <crypto/internal/akcipher.h> 1262306a36Sopenharmony_ci#include <crypto/internal/engine.h> 1362306a36Sopenharmony_ci#include <crypto/internal/hash.h> 1462306a36Sopenharmony_ci#include <crypto/internal/kpp.h> 1562306a36Sopenharmony_ci#include <crypto/internal/skcipher.h> 1662306a36Sopenharmony_ci#include <linux/err.h> 1762306a36Sopenharmony_ci#include <linux/delay.h> 1862306a36Sopenharmony_ci#include <linux/device.h> 1962306a36Sopenharmony_ci#include <linux/kernel.h> 2062306a36Sopenharmony_ci#include <linux/module.h> 2162306a36Sopenharmony_ci#include <uapi/linux/sched/types.h> 2262306a36Sopenharmony_ci#include "internal.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define CRYPTO_ENGINE_MAX_QLEN 10 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* Temporary algorithm flag used to indicate an updated driver. */ 2762306a36Sopenharmony_ci#define CRYPTO_ALG_ENGINE 0x200 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistruct crypto_engine_alg { 3062306a36Sopenharmony_ci struct crypto_alg base; 3162306a36Sopenharmony_ci struct crypto_engine_op op; 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/** 3562306a36Sopenharmony_ci * crypto_finalize_request - finalize one request if the request is done 3662306a36Sopenharmony_ci * @engine: the hardware engine 3762306a36Sopenharmony_ci * @req: the request need to be finalized 3862306a36Sopenharmony_ci * @err: error number 3962306a36Sopenharmony_ci */ 4062306a36Sopenharmony_cistatic void crypto_finalize_request(struct crypto_engine *engine, 4162306a36Sopenharmony_ci struct crypto_async_request *req, int err) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci unsigned long flags; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci /* 4662306a36Sopenharmony_ci * If hardware cannot enqueue more requests 4762306a36Sopenharmony_ci * and retry mechanism is not supported 4862306a36Sopenharmony_ci * make sure we are completing the current request 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_ci if (!engine->retry_support) { 5162306a36Sopenharmony_ci spin_lock_irqsave(&engine->queue_lock, flags); 5262306a36Sopenharmony_ci if (engine->cur_req == req) { 5362306a36Sopenharmony_ci engine->cur_req = NULL; 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci spin_unlock_irqrestore(&engine->queue_lock, flags); 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci lockdep_assert_in_softirq(); 5962306a36Sopenharmony_ci crypto_request_complete(req, err); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci kthread_queue_work(engine->kworker, &engine->pump_requests); 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/** 6562306a36Sopenharmony_ci * crypto_pump_requests - dequeue one request from engine queue to process 6662306a36Sopenharmony_ci * @engine: the hardware engine 6762306a36Sopenharmony_ci * @in_kthread: true if we are in the context of the request pump thread 6862306a36Sopenharmony_ci * 6962306a36Sopenharmony_ci * This function checks if there is any request in the engine queue that 7062306a36Sopenharmony_ci * needs processing and if so call out to the driver to initialize hardware 7162306a36Sopenharmony_ci * and handle each request. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_cistatic void crypto_pump_requests(struct crypto_engine *engine, 7462306a36Sopenharmony_ci bool in_kthread) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci struct crypto_async_request *async_req, *backlog; 7762306a36Sopenharmony_ci struct crypto_engine_alg *alg; 7862306a36Sopenharmony_ci struct crypto_engine_op *op; 7962306a36Sopenharmony_ci unsigned long flags; 8062306a36Sopenharmony_ci bool was_busy = false; 8162306a36Sopenharmony_ci int ret; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci spin_lock_irqsave(&engine->queue_lock, flags); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* Make sure we are not already running a request */ 8662306a36Sopenharmony_ci if (!engine->retry_support && engine->cur_req) 8762306a36Sopenharmony_ci goto out; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* If another context is idling then defer */ 9062306a36Sopenharmony_ci if (engine->idling) { 9162306a36Sopenharmony_ci kthread_queue_work(engine->kworker, &engine->pump_requests); 9262306a36Sopenharmony_ci goto out; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* Check if the engine queue is idle */ 9662306a36Sopenharmony_ci if (!crypto_queue_len(&engine->queue) || !engine->running) { 9762306a36Sopenharmony_ci if (!engine->busy) 9862306a36Sopenharmony_ci goto out; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci /* Only do teardown in the thread */ 10162306a36Sopenharmony_ci if (!in_kthread) { 10262306a36Sopenharmony_ci kthread_queue_work(engine->kworker, 10362306a36Sopenharmony_ci &engine->pump_requests); 10462306a36Sopenharmony_ci goto out; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci engine->busy = false; 10862306a36Sopenharmony_ci engine->idling = true; 10962306a36Sopenharmony_ci spin_unlock_irqrestore(&engine->queue_lock, flags); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (engine->unprepare_crypt_hardware && 11262306a36Sopenharmony_ci engine->unprepare_crypt_hardware(engine)) 11362306a36Sopenharmony_ci dev_err(engine->dev, "failed to unprepare crypt hardware\n"); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci spin_lock_irqsave(&engine->queue_lock, flags); 11662306a36Sopenharmony_ci engine->idling = false; 11762306a36Sopenharmony_ci goto out; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistart_request: 12162306a36Sopenharmony_ci /* Get the fist request from the engine queue to handle */ 12262306a36Sopenharmony_ci backlog = crypto_get_backlog(&engine->queue); 12362306a36Sopenharmony_ci async_req = crypto_dequeue_request(&engine->queue); 12462306a36Sopenharmony_ci if (!async_req) 12562306a36Sopenharmony_ci goto out; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* 12862306a36Sopenharmony_ci * If hardware doesn't support the retry mechanism, 12962306a36Sopenharmony_ci * keep track of the request we are processing now. 13062306a36Sopenharmony_ci * We'll need it on completion (crypto_finalize_request). 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_ci if (!engine->retry_support) 13362306a36Sopenharmony_ci engine->cur_req = async_req; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (engine->busy) 13662306a36Sopenharmony_ci was_busy = true; 13762306a36Sopenharmony_ci else 13862306a36Sopenharmony_ci engine->busy = true; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci spin_unlock_irqrestore(&engine->queue_lock, flags); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* Until here we get the request need to be encrypted successfully */ 14362306a36Sopenharmony_ci if (!was_busy && engine->prepare_crypt_hardware) { 14462306a36Sopenharmony_ci ret = engine->prepare_crypt_hardware(engine); 14562306a36Sopenharmony_ci if (ret) { 14662306a36Sopenharmony_ci dev_err(engine->dev, "failed to prepare crypt hardware\n"); 14762306a36Sopenharmony_ci goto req_err_1; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (async_req->tfm->__crt_alg->cra_flags & CRYPTO_ALG_ENGINE) { 15262306a36Sopenharmony_ci alg = container_of(async_req->tfm->__crt_alg, 15362306a36Sopenharmony_ci struct crypto_engine_alg, base); 15462306a36Sopenharmony_ci op = &alg->op; 15562306a36Sopenharmony_ci } else { 15662306a36Sopenharmony_ci dev_err(engine->dev, "failed to do request\n"); 15762306a36Sopenharmony_ci ret = -EINVAL; 15862306a36Sopenharmony_ci goto req_err_1; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci ret = op->do_one_request(engine, async_req); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* Request unsuccessfully executed by hardware */ 16462306a36Sopenharmony_ci if (ret < 0) { 16562306a36Sopenharmony_ci /* 16662306a36Sopenharmony_ci * If hardware queue is full (-ENOSPC), requeue request 16762306a36Sopenharmony_ci * regardless of backlog flag. 16862306a36Sopenharmony_ci * Otherwise, unprepare and complete the request. 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_ci if (!engine->retry_support || 17162306a36Sopenharmony_ci (ret != -ENOSPC)) { 17262306a36Sopenharmony_ci dev_err(engine->dev, 17362306a36Sopenharmony_ci "Failed to do one request from queue: %d\n", 17462306a36Sopenharmony_ci ret); 17562306a36Sopenharmony_ci goto req_err_1; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci spin_lock_irqsave(&engine->queue_lock, flags); 17862306a36Sopenharmony_ci /* 17962306a36Sopenharmony_ci * If hardware was unable to execute request, enqueue it 18062306a36Sopenharmony_ci * back in front of crypto-engine queue, to keep the order 18162306a36Sopenharmony_ci * of requests. 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_ci crypto_enqueue_request_head(&engine->queue, async_req); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci kthread_queue_work(engine->kworker, &engine->pump_requests); 18662306a36Sopenharmony_ci goto out; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci goto retry; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cireq_err_1: 19262306a36Sopenharmony_ci crypto_request_complete(async_req, ret); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ciretry: 19562306a36Sopenharmony_ci if (backlog) 19662306a36Sopenharmony_ci crypto_request_complete(backlog, -EINPROGRESS); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* If retry mechanism is supported, send new requests to engine */ 19962306a36Sopenharmony_ci if (engine->retry_support) { 20062306a36Sopenharmony_ci spin_lock_irqsave(&engine->queue_lock, flags); 20162306a36Sopenharmony_ci goto start_request; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci return; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ciout: 20662306a36Sopenharmony_ci spin_unlock_irqrestore(&engine->queue_lock, flags); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* 20962306a36Sopenharmony_ci * Batch requests is possible only if 21062306a36Sopenharmony_ci * hardware can enqueue multiple requests 21162306a36Sopenharmony_ci */ 21262306a36Sopenharmony_ci if (engine->do_batch_requests) { 21362306a36Sopenharmony_ci ret = engine->do_batch_requests(engine); 21462306a36Sopenharmony_ci if (ret) 21562306a36Sopenharmony_ci dev_err(engine->dev, "failed to do batch requests: %d\n", 21662306a36Sopenharmony_ci ret); 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci return; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic void crypto_pump_work(struct kthread_work *work) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci struct crypto_engine *engine = 22562306a36Sopenharmony_ci container_of(work, struct crypto_engine, pump_requests); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci crypto_pump_requests(engine, true); 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci/** 23162306a36Sopenharmony_ci * crypto_transfer_request - transfer the new request into the engine queue 23262306a36Sopenharmony_ci * @engine: the hardware engine 23362306a36Sopenharmony_ci * @req: the request need to be listed into the engine queue 23462306a36Sopenharmony_ci * @need_pump: indicates whether queue the pump of request to kthread_work 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_cistatic int crypto_transfer_request(struct crypto_engine *engine, 23762306a36Sopenharmony_ci struct crypto_async_request *req, 23862306a36Sopenharmony_ci bool need_pump) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci unsigned long flags; 24162306a36Sopenharmony_ci int ret; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci spin_lock_irqsave(&engine->queue_lock, flags); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (!engine->running) { 24662306a36Sopenharmony_ci spin_unlock_irqrestore(&engine->queue_lock, flags); 24762306a36Sopenharmony_ci return -ESHUTDOWN; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci ret = crypto_enqueue_request(&engine->queue, req); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci if (!engine->busy && need_pump) 25362306a36Sopenharmony_ci kthread_queue_work(engine->kworker, &engine->pump_requests); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci spin_unlock_irqrestore(&engine->queue_lock, flags); 25662306a36Sopenharmony_ci return ret; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci/** 26062306a36Sopenharmony_ci * crypto_transfer_request_to_engine - transfer one request to list 26162306a36Sopenharmony_ci * into the engine queue 26262306a36Sopenharmony_ci * @engine: the hardware engine 26362306a36Sopenharmony_ci * @req: the request need to be listed into the engine queue 26462306a36Sopenharmony_ci */ 26562306a36Sopenharmony_cistatic int crypto_transfer_request_to_engine(struct crypto_engine *engine, 26662306a36Sopenharmony_ci struct crypto_async_request *req) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci return crypto_transfer_request(engine, req, true); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci/** 27262306a36Sopenharmony_ci * crypto_transfer_aead_request_to_engine - transfer one aead_request 27362306a36Sopenharmony_ci * to list into the engine queue 27462306a36Sopenharmony_ci * @engine: the hardware engine 27562306a36Sopenharmony_ci * @req: the request need to be listed into the engine queue 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_ciint crypto_transfer_aead_request_to_engine(struct crypto_engine *engine, 27862306a36Sopenharmony_ci struct aead_request *req) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci return crypto_transfer_request_to_engine(engine, &req->base); 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_transfer_aead_request_to_engine); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci/** 28562306a36Sopenharmony_ci * crypto_transfer_akcipher_request_to_engine - transfer one akcipher_request 28662306a36Sopenharmony_ci * to list into the engine queue 28762306a36Sopenharmony_ci * @engine: the hardware engine 28862306a36Sopenharmony_ci * @req: the request need to be listed into the engine queue 28962306a36Sopenharmony_ci */ 29062306a36Sopenharmony_ciint crypto_transfer_akcipher_request_to_engine(struct crypto_engine *engine, 29162306a36Sopenharmony_ci struct akcipher_request *req) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci return crypto_transfer_request_to_engine(engine, &req->base); 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_transfer_akcipher_request_to_engine); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci/** 29862306a36Sopenharmony_ci * crypto_transfer_hash_request_to_engine - transfer one ahash_request 29962306a36Sopenharmony_ci * to list into the engine queue 30062306a36Sopenharmony_ci * @engine: the hardware engine 30162306a36Sopenharmony_ci * @req: the request need to be listed into the engine queue 30262306a36Sopenharmony_ci */ 30362306a36Sopenharmony_ciint crypto_transfer_hash_request_to_engine(struct crypto_engine *engine, 30462306a36Sopenharmony_ci struct ahash_request *req) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci return crypto_transfer_request_to_engine(engine, &req->base); 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_transfer_hash_request_to_engine); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci/** 31162306a36Sopenharmony_ci * crypto_transfer_kpp_request_to_engine - transfer one kpp_request to list 31262306a36Sopenharmony_ci * into the engine queue 31362306a36Sopenharmony_ci * @engine: the hardware engine 31462306a36Sopenharmony_ci * @req: the request need to be listed into the engine queue 31562306a36Sopenharmony_ci */ 31662306a36Sopenharmony_ciint crypto_transfer_kpp_request_to_engine(struct crypto_engine *engine, 31762306a36Sopenharmony_ci struct kpp_request *req) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci return crypto_transfer_request_to_engine(engine, &req->base); 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_transfer_kpp_request_to_engine); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci/** 32462306a36Sopenharmony_ci * crypto_transfer_skcipher_request_to_engine - transfer one skcipher_request 32562306a36Sopenharmony_ci * to list into the engine queue 32662306a36Sopenharmony_ci * @engine: the hardware engine 32762306a36Sopenharmony_ci * @req: the request need to be listed into the engine queue 32862306a36Sopenharmony_ci */ 32962306a36Sopenharmony_ciint crypto_transfer_skcipher_request_to_engine(struct crypto_engine *engine, 33062306a36Sopenharmony_ci struct skcipher_request *req) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci return crypto_transfer_request_to_engine(engine, &req->base); 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_transfer_skcipher_request_to_engine); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci/** 33762306a36Sopenharmony_ci * crypto_finalize_aead_request - finalize one aead_request if 33862306a36Sopenharmony_ci * the request is done 33962306a36Sopenharmony_ci * @engine: the hardware engine 34062306a36Sopenharmony_ci * @req: the request need to be finalized 34162306a36Sopenharmony_ci * @err: error number 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_civoid crypto_finalize_aead_request(struct crypto_engine *engine, 34462306a36Sopenharmony_ci struct aead_request *req, int err) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci return crypto_finalize_request(engine, &req->base, err); 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_finalize_aead_request); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci/** 35162306a36Sopenharmony_ci * crypto_finalize_akcipher_request - finalize one akcipher_request if 35262306a36Sopenharmony_ci * the request is done 35362306a36Sopenharmony_ci * @engine: the hardware engine 35462306a36Sopenharmony_ci * @req: the request need to be finalized 35562306a36Sopenharmony_ci * @err: error number 35662306a36Sopenharmony_ci */ 35762306a36Sopenharmony_civoid crypto_finalize_akcipher_request(struct crypto_engine *engine, 35862306a36Sopenharmony_ci struct akcipher_request *req, int err) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci return crypto_finalize_request(engine, &req->base, err); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_finalize_akcipher_request); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci/** 36562306a36Sopenharmony_ci * crypto_finalize_hash_request - finalize one ahash_request if 36662306a36Sopenharmony_ci * the request is done 36762306a36Sopenharmony_ci * @engine: the hardware engine 36862306a36Sopenharmony_ci * @req: the request need to be finalized 36962306a36Sopenharmony_ci * @err: error number 37062306a36Sopenharmony_ci */ 37162306a36Sopenharmony_civoid crypto_finalize_hash_request(struct crypto_engine *engine, 37262306a36Sopenharmony_ci struct ahash_request *req, int err) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci return crypto_finalize_request(engine, &req->base, err); 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_finalize_hash_request); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci/** 37962306a36Sopenharmony_ci * crypto_finalize_kpp_request - finalize one kpp_request if the request is done 38062306a36Sopenharmony_ci * @engine: the hardware engine 38162306a36Sopenharmony_ci * @req: the request need to be finalized 38262306a36Sopenharmony_ci * @err: error number 38362306a36Sopenharmony_ci */ 38462306a36Sopenharmony_civoid crypto_finalize_kpp_request(struct crypto_engine *engine, 38562306a36Sopenharmony_ci struct kpp_request *req, int err) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci return crypto_finalize_request(engine, &req->base, err); 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_finalize_kpp_request); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci/** 39262306a36Sopenharmony_ci * crypto_finalize_skcipher_request - finalize one skcipher_request if 39362306a36Sopenharmony_ci * the request is done 39462306a36Sopenharmony_ci * @engine: the hardware engine 39562306a36Sopenharmony_ci * @req: the request need to be finalized 39662306a36Sopenharmony_ci * @err: error number 39762306a36Sopenharmony_ci */ 39862306a36Sopenharmony_civoid crypto_finalize_skcipher_request(struct crypto_engine *engine, 39962306a36Sopenharmony_ci struct skcipher_request *req, int err) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci return crypto_finalize_request(engine, &req->base, err); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_finalize_skcipher_request); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci/** 40662306a36Sopenharmony_ci * crypto_engine_start - start the hardware engine 40762306a36Sopenharmony_ci * @engine: the hardware engine need to be started 40862306a36Sopenharmony_ci * 40962306a36Sopenharmony_ci * Return 0 on success, else on fail. 41062306a36Sopenharmony_ci */ 41162306a36Sopenharmony_ciint crypto_engine_start(struct crypto_engine *engine) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci unsigned long flags; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci spin_lock_irqsave(&engine->queue_lock, flags); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci if (engine->running || engine->busy) { 41862306a36Sopenharmony_ci spin_unlock_irqrestore(&engine->queue_lock, flags); 41962306a36Sopenharmony_ci return -EBUSY; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci engine->running = true; 42362306a36Sopenharmony_ci spin_unlock_irqrestore(&engine->queue_lock, flags); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci kthread_queue_work(engine->kworker, &engine->pump_requests); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci return 0; 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_start); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci/** 43262306a36Sopenharmony_ci * crypto_engine_stop - stop the hardware engine 43362306a36Sopenharmony_ci * @engine: the hardware engine need to be stopped 43462306a36Sopenharmony_ci * 43562306a36Sopenharmony_ci * Return 0 on success, else on fail. 43662306a36Sopenharmony_ci */ 43762306a36Sopenharmony_ciint crypto_engine_stop(struct crypto_engine *engine) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci unsigned long flags; 44062306a36Sopenharmony_ci unsigned int limit = 500; 44162306a36Sopenharmony_ci int ret = 0; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci spin_lock_irqsave(&engine->queue_lock, flags); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci /* 44662306a36Sopenharmony_ci * If the engine queue is not empty or the engine is on busy state, 44762306a36Sopenharmony_ci * we need to wait for a while to pump the requests of engine queue. 44862306a36Sopenharmony_ci */ 44962306a36Sopenharmony_ci while ((crypto_queue_len(&engine->queue) || engine->busy) && limit--) { 45062306a36Sopenharmony_ci spin_unlock_irqrestore(&engine->queue_lock, flags); 45162306a36Sopenharmony_ci msleep(20); 45262306a36Sopenharmony_ci spin_lock_irqsave(&engine->queue_lock, flags); 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (crypto_queue_len(&engine->queue) || engine->busy) 45662306a36Sopenharmony_ci ret = -EBUSY; 45762306a36Sopenharmony_ci else 45862306a36Sopenharmony_ci engine->running = false; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci spin_unlock_irqrestore(&engine->queue_lock, flags); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if (ret) 46362306a36Sopenharmony_ci dev_warn(engine->dev, "could not stop engine\n"); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci return ret; 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_stop); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci/** 47062306a36Sopenharmony_ci * crypto_engine_alloc_init_and_set - allocate crypto hardware engine structure 47162306a36Sopenharmony_ci * and initialize it by setting the maximum number of entries in the software 47262306a36Sopenharmony_ci * crypto-engine queue. 47362306a36Sopenharmony_ci * @dev: the device attached with one hardware engine 47462306a36Sopenharmony_ci * @retry_support: whether hardware has support for retry mechanism 47562306a36Sopenharmony_ci * @cbk_do_batch: pointer to a callback function to be invoked when executing 47662306a36Sopenharmony_ci * a batch of requests. 47762306a36Sopenharmony_ci * This has the form: 47862306a36Sopenharmony_ci * callback(struct crypto_engine *engine) 47962306a36Sopenharmony_ci * where: 48062306a36Sopenharmony_ci * engine: the crypto engine structure. 48162306a36Sopenharmony_ci * @rt: whether this queue is set to run as a realtime task 48262306a36Sopenharmony_ci * @qlen: maximum size of the crypto-engine queue 48362306a36Sopenharmony_ci * 48462306a36Sopenharmony_ci * This must be called from context that can sleep. 48562306a36Sopenharmony_ci * Return: the crypto engine structure on success, else NULL. 48662306a36Sopenharmony_ci */ 48762306a36Sopenharmony_cistruct crypto_engine *crypto_engine_alloc_init_and_set(struct device *dev, 48862306a36Sopenharmony_ci bool retry_support, 48962306a36Sopenharmony_ci int (*cbk_do_batch)(struct crypto_engine *engine), 49062306a36Sopenharmony_ci bool rt, int qlen) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci struct crypto_engine *engine; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (!dev) 49562306a36Sopenharmony_ci return NULL; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci engine = devm_kzalloc(dev, sizeof(*engine), GFP_KERNEL); 49862306a36Sopenharmony_ci if (!engine) 49962306a36Sopenharmony_ci return NULL; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci engine->dev = dev; 50262306a36Sopenharmony_ci engine->rt = rt; 50362306a36Sopenharmony_ci engine->running = false; 50462306a36Sopenharmony_ci engine->busy = false; 50562306a36Sopenharmony_ci engine->idling = false; 50662306a36Sopenharmony_ci engine->retry_support = retry_support; 50762306a36Sopenharmony_ci engine->priv_data = dev; 50862306a36Sopenharmony_ci /* 50962306a36Sopenharmony_ci * Batch requests is possible only if 51062306a36Sopenharmony_ci * hardware has support for retry mechanism. 51162306a36Sopenharmony_ci */ 51262306a36Sopenharmony_ci engine->do_batch_requests = retry_support ? cbk_do_batch : NULL; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci snprintf(engine->name, sizeof(engine->name), 51562306a36Sopenharmony_ci "%s-engine", dev_name(dev)); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci crypto_init_queue(&engine->queue, qlen); 51862306a36Sopenharmony_ci spin_lock_init(&engine->queue_lock); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci engine->kworker = kthread_create_worker(0, "%s", engine->name); 52162306a36Sopenharmony_ci if (IS_ERR(engine->kworker)) { 52262306a36Sopenharmony_ci dev_err(dev, "failed to create crypto request pump task\n"); 52362306a36Sopenharmony_ci return NULL; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci kthread_init_work(&engine->pump_requests, crypto_pump_work); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci if (engine->rt) { 52862306a36Sopenharmony_ci dev_info(dev, "will run requests pump with realtime priority\n"); 52962306a36Sopenharmony_ci sched_set_fifo(engine->kworker->task); 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci return engine; 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_alloc_init_and_set); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci/** 53762306a36Sopenharmony_ci * crypto_engine_alloc_init - allocate crypto hardware engine structure and 53862306a36Sopenharmony_ci * initialize it. 53962306a36Sopenharmony_ci * @dev: the device attached with one hardware engine 54062306a36Sopenharmony_ci * @rt: whether this queue is set to run as a realtime task 54162306a36Sopenharmony_ci * 54262306a36Sopenharmony_ci * This must be called from context that can sleep. 54362306a36Sopenharmony_ci * Return: the crypto engine structure on success, else NULL. 54462306a36Sopenharmony_ci */ 54562306a36Sopenharmony_cistruct crypto_engine *crypto_engine_alloc_init(struct device *dev, bool rt) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci return crypto_engine_alloc_init_and_set(dev, false, NULL, rt, 54862306a36Sopenharmony_ci CRYPTO_ENGINE_MAX_QLEN); 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_alloc_init); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci/** 55362306a36Sopenharmony_ci * crypto_engine_exit - free the resources of hardware engine when exit 55462306a36Sopenharmony_ci * @engine: the hardware engine need to be freed 55562306a36Sopenharmony_ci * 55662306a36Sopenharmony_ci * Return 0 for success. 55762306a36Sopenharmony_ci */ 55862306a36Sopenharmony_ciint crypto_engine_exit(struct crypto_engine *engine) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci int ret; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci ret = crypto_engine_stop(engine); 56362306a36Sopenharmony_ci if (ret) 56462306a36Sopenharmony_ci return ret; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci kthread_destroy_worker(engine->kworker); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci return 0; 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_exit); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ciint crypto_engine_register_aead(struct aead_engine_alg *alg) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci if (!alg->op.do_one_request) 57562306a36Sopenharmony_ci return -EINVAL; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci alg->base.base.cra_flags |= CRYPTO_ALG_ENGINE; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci return crypto_register_aead(&alg->base); 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_register_aead); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_civoid crypto_engine_unregister_aead(struct aead_engine_alg *alg) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci crypto_unregister_aead(&alg->base); 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_unregister_aead); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ciint crypto_engine_register_aeads(struct aead_engine_alg *algs, int count) 59062306a36Sopenharmony_ci{ 59162306a36Sopenharmony_ci int i, ret; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci for (i = 0; i < count; i++) { 59462306a36Sopenharmony_ci ret = crypto_engine_register_aead(&algs[i]); 59562306a36Sopenharmony_ci if (ret) 59662306a36Sopenharmony_ci goto err; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci return 0; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cierr: 60262306a36Sopenharmony_ci crypto_engine_unregister_aeads(algs, i); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci return ret; 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_register_aeads); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_civoid crypto_engine_unregister_aeads(struct aead_engine_alg *algs, int count) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci int i; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci for (i = count - 1; i >= 0; --i) 61362306a36Sopenharmony_ci crypto_engine_unregister_aead(&algs[i]); 61462306a36Sopenharmony_ci} 61562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_unregister_aeads); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ciint crypto_engine_register_ahash(struct ahash_engine_alg *alg) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci if (!alg->op.do_one_request) 62062306a36Sopenharmony_ci return -EINVAL; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci alg->base.halg.base.cra_flags |= CRYPTO_ALG_ENGINE; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci return crypto_register_ahash(&alg->base); 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_register_ahash); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_civoid crypto_engine_unregister_ahash(struct ahash_engine_alg *alg) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci crypto_unregister_ahash(&alg->base); 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_unregister_ahash); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ciint crypto_engine_register_ahashes(struct ahash_engine_alg *algs, int count) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci int i, ret; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci for (i = 0; i < count; i++) { 63962306a36Sopenharmony_ci ret = crypto_engine_register_ahash(&algs[i]); 64062306a36Sopenharmony_ci if (ret) 64162306a36Sopenharmony_ci goto err; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci return 0; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cierr: 64762306a36Sopenharmony_ci crypto_engine_unregister_ahashes(algs, i); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci return ret; 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_register_ahashes); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_civoid crypto_engine_unregister_ahashes(struct ahash_engine_alg *algs, 65462306a36Sopenharmony_ci int count) 65562306a36Sopenharmony_ci{ 65662306a36Sopenharmony_ci int i; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci for (i = count - 1; i >= 0; --i) 65962306a36Sopenharmony_ci crypto_engine_unregister_ahash(&algs[i]); 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_unregister_ahashes); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ciint crypto_engine_register_akcipher(struct akcipher_engine_alg *alg) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci if (!alg->op.do_one_request) 66662306a36Sopenharmony_ci return -EINVAL; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci alg->base.base.cra_flags |= CRYPTO_ALG_ENGINE; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci return crypto_register_akcipher(&alg->base); 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_register_akcipher); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_civoid crypto_engine_unregister_akcipher(struct akcipher_engine_alg *alg) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci crypto_unregister_akcipher(&alg->base); 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_unregister_akcipher); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ciint crypto_engine_register_kpp(struct kpp_engine_alg *alg) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci if (!alg->op.do_one_request) 68362306a36Sopenharmony_ci return -EINVAL; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci alg->base.base.cra_flags |= CRYPTO_ALG_ENGINE; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci return crypto_register_kpp(&alg->base); 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_register_kpp); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_civoid crypto_engine_unregister_kpp(struct kpp_engine_alg *alg) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci crypto_unregister_kpp(&alg->base); 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_unregister_kpp); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ciint crypto_engine_register_skcipher(struct skcipher_engine_alg *alg) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci if (!alg->op.do_one_request) 70062306a36Sopenharmony_ci return -EINVAL; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci alg->base.base.cra_flags |= CRYPTO_ALG_ENGINE; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci return crypto_register_skcipher(&alg->base); 70562306a36Sopenharmony_ci} 70662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_register_skcipher); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_civoid crypto_engine_unregister_skcipher(struct skcipher_engine_alg *alg) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci return crypto_unregister_skcipher(&alg->base); 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_unregister_skcipher); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ciint crypto_engine_register_skciphers(struct skcipher_engine_alg *algs, 71562306a36Sopenharmony_ci int count) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci int i, ret; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci for (i = 0; i < count; i++) { 72062306a36Sopenharmony_ci ret = crypto_engine_register_skcipher(&algs[i]); 72162306a36Sopenharmony_ci if (ret) 72262306a36Sopenharmony_ci goto err; 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci return 0; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_cierr: 72862306a36Sopenharmony_ci crypto_engine_unregister_skciphers(algs, i); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci return ret; 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_register_skciphers); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_civoid crypto_engine_unregister_skciphers(struct skcipher_engine_alg *algs, 73562306a36Sopenharmony_ci int count) 73662306a36Sopenharmony_ci{ 73762306a36Sopenharmony_ci int i; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci for (i = count - 1; i >= 0; --i) 74062306a36Sopenharmony_ci crypto_engine_unregister_skcipher(&algs[i]); 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(crypto_engine_unregister_skciphers); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 74562306a36Sopenharmony_ciMODULE_DESCRIPTION("Crypto hardware engine framework"); 746