crypto: introduce generic dynamic software fallback and EIP93 support
cover crypto: introduce generic dynamic software fallback and EIP93 support
This series introduces a generic in-kernel Crypto API proxy for dynamic CPU software fallback, inspired by tcrypt's in-kernel benchmarking and RAID6's algorithm selection at module load time. It also adds support for using the proxy with EIP93.
The recent QCE discussion [1][2][3] makes it clear that a crypto device cannot be evaluated solely by whether there is any performance improvement over the CPU software path. But at the same time, performance remains one of the main factors.
Crypto accelerators generally incur submission, DMA, interrupt, and completion costs. Legacy devices pair those costs with lower hardware throughput, so small requests can be slower than CPU software. This series lets drivers describe algorithm groups that share similar scaling behavior, then opt in at runtime to dispatch requests only to the implementation that provides a measured performance benefit. This is possible because Crypto API requests of different sizes have no dependency on one another, allowing the proxy to select a provider independently for each request while keeping each stateful operation on one provider.
EIP93 was chosen as the first target not only because I own and use it, but also because it illustrates this problem. It still improves performance for large requests, yet it is much slower for small requests even when compared with a relatively weak CPU by modern standards, such as the one in the AN7581. Community patches such as [4] have previously addressed this with a static size override for AES only. They provide a useful workaround, but neither determine the crossover point systematically nor offer a generic framework that is easy to extend to other devices or algorithms.
The control is exposed through a per-crypto-device sysfs "enabled" attribute and is disabled by default. While disabled, the proxy providers are unregistered, so newly allocated transforms bind directly to the hardware providers and the existing hardware hot path is unaffected. Proxy generations that still have live transforms are retained until those transforms are released.
Adding dynamic fallback to a driver
===================================
Select CRYPTO_DYNAMIC_FALLBACK and the software algorithms used for benchmarking in the driver's Kconfig. Define a crypto_fallback_group table that groups hardware driver names with similar request-size scaling. For each group, choose one representative hardware/software pair and provide the benchmark key and parameters. The CRYPTO_FALLBACK_GROUP() and CRYPTO_FALLBACK_GROUP_AUTHENC() macros can be used to initialize these entries.
After registering the hardware algorithms, call crypto_fallback_register(THIS_MODULE, dev, groups, ARRAY_SIZE(groups)) and keep the returned handle. Call crypto_fallback_unregister() with that handle before unregistering the hardware algorithms. The framework creates the per-device enable and group threshold sysfs attributes and manages the proxy providers, so the driver's request path needs no changes.
Benchmark method
================
Whenever fallback is enabled or re-enabled, one representative hardware implementation from each group and its CPU software equivalent are tested at these request sizes:
16, 64, 128, 256, 512, 1024, 1420, 2048, 4096, 8192, 16384 bytes
Each implementation gets four warm-up operations followed by eight measured operations. If their cycle totals differ by at most 10% of the lower total, both get 16 additional measurements. Equal totals count as a software win.
The threshold is the tested size before hardware first becomes strictly faster. It is 0 if hardware wins at 16 bytes and -1 if hardware never wins. At request time:
use_software = T < 0 || (T > 0 && request_size <= T)
A failed benchmark uses T = 0, selecting hardware only. Each algorithm group's threshold can also be overridden by writing to its sysfs attribute.
Testing
=======
This series was integrated into an OpenWrt community image based on Linux 6.18 and tested on a W1700K2 HW2.1 equipped with an Airoha AN7581 E2 SoC. Results from tcrypt and OpenSSL:
Enabling fallback took 0.82 seconds and selected these thresholds. A value of -1 means that software was faster at every tested size.
Group Threshold (bytes)
raw_aes 512
raw_des 256
raw_3des 64 hash_md5 -1 hash_sha1 -1 hash_sha2 -1
authenc_aes 512
authenc_des 128
authenc_3des 64
The tcrypt AES-128-CBC results are median cycles from five runs. Lower is better. Disabled uses cbc(aes-eip93) directly, while enabled uses fallback(cbc(aes-eip93)).
Request Disabled Enabled Cycle reduction
(bytes) (cycles) (cycles)
16 322 18 94.4%
64 274 43 84.3%
128 292 74 74.7%
256 312 138 55.8%
1024 434 439 -1.2%
1424 492 488 0.8%
4096 980 1023 -4.4%OpenSSL 3.5.7 AF_ALG AES-128-CBC throughput is the mean of two two-second runs at each request size.
Request Disabled Enabled Throughput gain
(bytes) (MB/s) (MB/s)
16 0.560 1.257 124.5%
64 2.430 4.639 90.9%
256 9.106 14.168 55.6%
1024 30.279 30.332 0.2%
8192 88.807 89.383 0.6%
16384 101.220 102.068 0.8%All tcrypt KATs and OpenSSL AF_ALG round-trip tests passed with fallback both disabled and enabled.
LLM disclosure
==============
Development of patch 2/4 was aided by an LLM, while patch 4/4 was developed more extensively with LLM assistance. All testing was performed by me.
[1] https://lore.kernel.org/linux-crypto/[email protected]/
[2] https://lore.kernel.org/linux-crypto/[email protected]/
[3] https://lore.kernel.org/linux-crypto/[email protected]/
[4] https://github.com/stevenj/ph-openwrt-mtk-eip93
Sincerely,
Jihong Min
Jihong Min (4):
crypto: move cycle benchmark helpers out of tcrypt
crypto: introduce dynamic software fallback
crypto: eip93 - add dynamic software fallback support
crypto: eliminate fallback proxy overhead while disabled
crypto/Kconfig | 24 +- crypto/Makefile | 3 + crypto/benchmark.c | 180 ++ crypto/fallback.c | 1479 +++++++++++++++++ crypto/tcrypt.c | 213 +-- drivers/crypto/inside-secure/eip93/Kconfig | 7 + drivers/crypto/inside-secure/eip93/Makefile | 1 + .../inside-secure/eip93/eip93-fallback.c | 164 ++ .../inside-secure/eip93/eip93-fallback.h | 10 + .../crypto/inside-secure/eip93/eip93-main.c | 19 +- include/crypto/benchmark.h | 24 + include/crypto/fallback.h | 96 ++ 12 files changed, 2024 insertions(+), 196 deletions(-) create mode 100644 crypto/benchmark.c create mode 100644 crypto/fallback.c create mode 100644 drivers/crypto/inside-secure/eip93/eip93-fallback.c create mode 100644 drivers/crypto/inside-secure/eip93/eip93-fallback.h create mode 100644 include/crypto/benchmark.h create mode 100644 include/crypto/fallback.h
base-commit: 1163a476a568f6c0f852d469c8e4c5a5f805adac
Signature · 1 line
2.53.0
PATCH 1/4 crypto: move cycle benchmark helpers out of tcrypt
Move the reusable AEAD, ahash, and skcipher cycle measurement loops into a dedicated benchmark module. Preserve tcrypt's existing output and benchmark behavior while allowing crypto drivers to use the same helpers for runtime comparisons.
--- crypto/Kconfig | 15 ++- crypto/Makefile | 2 + crypto/benchmark.c | 180 +++++++++++++++++++++++++++++++ crypto/tcrypt.c | 213 +++++-------------------------------- include/crypto/benchmark.h | 24 +++++ 5 files changed, 242 insertions(+), 192 deletions(-) create mode 100644 crypto/benchmark.c create mode 100644 include/crypto/benchmark.h
crypto/Kconfig +12 -3
@@ -244,13 +244,22 @@ config CRYPTO_KRB5ENC profile. This is required for Kerberos 5-style encryption, used by sunrpc/NFS and rxrpc/AFS. -config CRYPTO_BENCHMARK - tristate "Crypto benchmarking module" - depends on m || EXPERT +config CRYPTO_BENCHMARK_LIB + tristate select CRYPTO_AEAD select CRYPTO_HASH select CRYPTO_MANAGER select CRYPTO_SKCIPHER + help + Build reusable benchmark helpers for Crypto API algorithms. This + internal library is shared by tcrypt and drivers that select + implementations from measurements made while their devices are + initialized. + +config CRYPTO_BENCHMARK + tristate "Crypto benchmarking module" + depends on m || EXPERT + select CRYPTO_BENCHMARK_LIB help Quick & dirty crypto benchmarking module.
crypto/Makefile +2 -0
@@ -165,6 +165,8 @@ UBSAN_SANITIZE_jitterentropy.o = n jitterentropy_rng-y := jitterentropy.o jitterentropy-kcapi.o obj-$(CONFIG_CRYPTO_JITTERENTROPY_TESTINTERFACE) += jitterentropy-testing.o obj-$(CONFIG_CRYPTO_BENCHMARK) += tcrypt.o +obj-$(CONFIG_CRYPTO_BENCHMARK_LIB) += crypt-benchmark.o +crypt-benchmark-y := benchmark.o obj-$(CONFIG_CRYPTO_USER_API) += af_alg.o obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.o obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
crypto/benchmark.c new file +180 -0
180 lines not on this page · raw message
crypto/tcrypt.c +24 -189
255 lines not on this page · raw message
include/crypto/benchmark.h new file +24 -0
@@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _CRYPTO_BENCHMARK_H +#define _CRYPTO_BENCHMARK_H + +#include <linux/types.h> + +struct aead_request ; +struct ahash_request ; +struct skcipher_request ; + +/* Requests must use crypto_req_done() with struct crypto_wait callback data. */ +int crypto_benchmark_aead_cycles (struct aead_request *req,bool encrypt, +unsigned int warmup_runs,unsigned int runs, +u64 *total_cycles); +int crypto_benchmark_ahash_cycles (struct ahash_request *req, +unsigned int block_size, +unsigned int update_size, +unsigned int warmup_runs,unsigned int runs, +u64 *total_cycles); +int crypto_benchmark_skcipher_cycles (struct skcipher_request *req,bool encrypt, +unsigned int warmup_runs, +unsigned int runs,u64 *total_cycles); + +#endif /* _CRYPTO_BENCHMARK_H */
Signature · 1 line
2.53.0
PATCH 2/4 crypto: introduce dynamic software fallback
In reply to Jihong MinAdd an opt-in framework that lets crypto drivers compare hardware and software implementations for algorithm groups whose members share similar hardware scaling characteristics. Benchmark each group at fixed block sizes from 16 to 16384 bytes, then expose the resulting per-device CPU fallback thresholds through sysfs.
Use four warm-up runs and eight measured runs for each implementation. Extend results within ten percent with sixteen additional runs. Treat equal totals as a software win. After any software win, continue with the next block size if one remains; otherwise select software-only fallback. Select software or hardware per request using the threshold computed at sysfs (re-)enablement for each crypto device.
--- crypto/Kconfig | 9 + crypto/Makefile | 1 + crypto/fallback.c | 1335 +++++++++++++++++++++++++++++++++++++ include/crypto/fallback.h | 96 +++ 4 files changed, 1441 insertions(+) create mode 100644 crypto/fallback.c create mode 100644 include/crypto/fallback.h
crypto/Kconfig +9 -0
@@ -267,6 +267,15 @@ config CRYPTO_BENCHMARK algorithms in the kernel. It should not be enabled in production kernels. +config CRYPTO_DYNAMIC_FALLBACK + tristate + select CRYPTO_BENCHMARK_LIB + help + Build generic support for selecting software fallback thresholds + from Crypto API benchmark results. Crypto drivers select this + internal library when they support runtime fallback tuning for + their hardware implementations. + config CRYPTO_SIMD tristate select CRYPTO_AEAD
crypto/Makefile +1 -0
@@ -167,6 +167,7 @@ obj-$(CONFIG_CRYPTO_JITTERENTROPY_TESTINTERFACE) += jitterentropy-testing.o obj-$(CONFIG_CRYPTO_BENCHMARK) += tcrypt.o obj-$(CONFIG_CRYPTO_BENCHMARK_LIB) += crypt-benchmark.o crypt-benchmark-y := benchmark.o +obj-$(CONFIG_CRYPTO_DYNAMIC_FALLBACK) += fallback.o obj-$(CONFIG_CRYPTO_USER_API) += af_alg.o obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.o obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
crypto/fallback.c new file +1335 -0
1,335 lines not on this page · raw message
include/crypto/fallback.h new file +96 -0
96 lines not on this page · raw message
Signature · 1 line
2.53.0
PATCH 3/4 crypto: eip93 - add dynamic software fallback support
In reply to Jihong MinGroup EIP93 skcipher, ahash, and authenc implementations by their request-size performance trends. Register generic fallback proxies that use one representative benchmark per group and dispatch each request to EIP93 or software according to the per-device threshold.
Expose the fallback controls through the EIP93 device sysfs hierarchy and add the software algorithm dependencies required for benchmarking.
Unregister the fallback proxies before removing the hardware providers.
--- drivers/crypto/inside-secure/eip93/Kconfig | 7 + drivers/crypto/inside-secure/eip93/Makefile | 1 + .../inside-secure/eip93/eip93-fallback.c | 164 ++++++++++++++++++ .../inside-secure/eip93/eip93-fallback.h | 10 ++ .../crypto/inside-secure/eip93/eip93-main.c | 19 +- 5 files changed, 197 insertions(+), 4 deletions(-) create mode 100644 drivers/crypto/inside-secure/eip93/eip93-fallback.c create mode 100644 drivers/crypto/inside-secure/eip93/eip93-fallback.h
drivers/crypto/inside-secure/eip93/Kconfig +7 -0
@@ -10,6 +10,13 @@ config CRYPTO_DEV_EIP93 select CRYPTO_MD5 select CRYPTO_SHA1 select CRYPTO_SHA256 + select CRYPTO_DYNAMIC_FALLBACK + select CRYPTO_AES + select CRYPTO_CBC + select CRYPTO_CTR + select CRYPTO_DES + select CRYPTO_ECB + select CRYPTO_HMAC help EIP93 have various crypto HW accelerators. Select this if you want to use the EIP93 modules for any of the crypto algorithms.
drivers/crypto/inside-secure/eip93/Makefile +1 -0
@@ -3,3 +3,4 @@ obj-$(CONFIG_CRYPTO_DEV_EIP93) += crypto-hw-eip93.o crypto-hw-eip93-y += eip93-main.o eip93-common.o crypto-hw-eip93-y += eip93-cipher.o eip93-aead.o crypto-hw-eip93-y += eip93-hash.o +crypto-hw-eip93-y += eip93-fallback.o
drivers/crypto/inside-secure/eip93/eip93-fallback.c new file +164 -0
164 lines not on this page · raw message
drivers/crypto/inside-secure/eip93/eip93-fallback.h new file +10 -0
@@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _EIP93_FALLBACK_H_ +#define _EIP93_FALLBACK_H_ + +struct eip93_device ; + +int eip93_fallback_register (struct eip93_device *eip93); +void eip93_fallback_unregister (void ); + +#endif /* _EIP93_FALLBACK_H_ */
drivers/crypto/inside-secure/eip93/eip93-main.c +15 -4
@@ -25,6 +25,7 @@#include "eip93-aes.h" #include "eip93-des.h" #include "eip93-aead.h" +#include "eip93-fallback.h" #include "eip93-hash.h" static struct eip93_alg_template *eip93_algs[] = {
@@ -460,10 +461,12 @@ static int eip93_crypto_probe(struct platform_device *pdev)eip93_irq_enable (eip93,EIP93_INT_RDR_THRESH ); ret =eip93_register_algs (eip93, algo_flags); -if (ret) { -eip93_cleanup (eip93); -return ret; - } +if (ret) + goto err_cleanup; + + ret =eip93_fallback_register (eip93); +if (ret) + goto err_unregister_algs; ver =readl (eip93->base +EIP93_REG_PE_REVISION );/* EIP_EIP_NO:MAJOR_HW_REV:MINOR_HW_REV:HW_PATCH,PE(ALGO_FLAGS) */
@@ -476,6 +479,13 @@ static int eip93_crypto_probe(struct platform_device *pdev) readl(eip93->base + EIP93_REG_PE_OPTION_0));return 0 ; + +err_unregister_algs: +eip93_unregister_algs (algo_flags,ARRAY_SIZE (eip93_algs)); +err_cleanup: +eip93_cleanup (eip93); + +return ret; }static void eip93_crypto_remove (struct platform_device *pdev)
@@ -485,6 +495,7 @@ static void eip93_crypto_remove(struct platform_device *pdev) algo_flags =readl (eip93->base +EIP93_REG_PE_OPTION_1 ); +eip93_fallback_unregister ();eip93_unregister_algs (algo_flags,ARRAY_SIZE (eip93_algs));eip93_cleanup (eip93); }
Signature · 1 line
2.53.0
PATCH 4/4 crypto: eliminate fallback proxy overhead while disabled
In reply to Jihong MinRegister fallback proxy providers only when the per-device control is enabled. Unregister them again on disable so newly allocated transforms select the hardware provider directly.
Allocate proxy algorithms per enable cycle and retain retired generations until existing transforms release them. This keeps repeated runtime enable and disable transitions safe while forcing retired proxies to use hardware after disable.
The Crypto API cannot migrate an already allocated transform between providers. A transform created while disabled remains bound to its native hardware provider after enable. A transform created while enabled keeps its proxy after disable until it is released, with its threshold forced to hardware. Newly allocated transforms follow the current enabled state.
--- crypto/fallback.c | 284 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 214 insertions(+), 70 deletions(-)
crypto/fallback.c +214 -70
@@ -9,13 +9,16 @@#include <linux/device.h> #include <linux/err.h> #include <linux/kernel.h> +#include <linux/kref.h> #include <linux/limits.h> +#include <linux/list.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/random.h> #include <linux/rtnetlink.h> #include <linux/scatterlist.h> #include <linux/slab.h> +#include <linux/spinlock.h> #include <linux/string.h> #include <linux/sysfs.h>
@@ -48,10 +51,12 @@ struct crypto_fallback {struct attribute_group sysfs_group;struct attribute **sysfs_attrs;struct device_attribute enabled_attr; +struct kref refcount;struct mutex lock;/* Serializes tuning and sysfs writes. */ -struct fallback_alg *algs; +spinlock_t alg_lock;/* Protects algs and fallback_alg state. */ +struct list_head algs; +struct module *owner;unsigned int num_groups; -unsigned int num_algs;bool enabled; };
@@ -422,6 +427,9 @@ static int crypto_fallback_tune_group(const struct crypto_fallback_group *group,return 0 ; } +static int fallback_register_algs (struct crypto_fallback *fallback); +static void fallback_unregister_algs (struct crypto_fallback *fallback); +static ssize_t fallback_enabled_show (struct device *dev,struct device_attribute *attr,char *buf) {
@@ -451,9 +459,6 @@ static ssize_t fallback_enabled_store(struct device *dev, goto out_unlock;if (enabled) { -for (i =0 ; i < fallback->num_groups; i++) -WRITE_ONCE (fallback->groups[i].threshold.value,0 ); -for (i =0 ; i < fallback->num_groups; i++) {struct crypto_fallback_group_state *state;int threshold;
@@ -463,9 +468,10 @@ static ssize_t fallback_enabled_store(struct device *dev, &threshold);if (err) {dev_warn (fallback->dev, -"%s benchmark failed: %d; using hardware\n" , - state->group.name, err); +"%s benchmark failed: %d; using hardware\n" , + state->group.name, err); threshold =0 ; + err =0 ; }WRITE_ONCE (state->value, threshold); dev_info(fallback->dev,
@@ -476,28 +482,39 @@ static ssize_t fallback_enabled_store(struct device *dev,for (i =0 ; i < fallback->num_groups; i++)WRITE_ONCE (fallback->groups[i].threshold.value, fallback->groups[i].value); + +if (!fallback->enabled) { + err =fallback_register_algs (fallback); +if (err) { +for (i =0 ; i < fallback->num_groups; i++) +WRITE_ONCE (fallback->groups[i].threshold.value, +0 ); + goto out_unlock; + } + } }else { +WRITE_ONCE (fallback->enabled, false);for (i =0 ; i < fallback->num_groups; i++)WRITE_ONCE (fallback->groups[i].threshold.value,0 ); +fallback_unregister_algs (fallback); }WRITE_ONCE (fallback->enabled, enabled); out_unlock:mutex_unlock (&fallback->lock); -return count; +return err ?: count; } -static void crypto_fallback_free (struct crypto_fallback *fallback) +static void crypto_fallback_free (struct kref *ref) { +struct crypto_fallback *fallback;unsigned int i; -if (!fallback) -return ; + fallback = container_of(ref, struct crypto_fallback, refcount);for (i =0 ; i < fallback->num_groups; i++)kfree_const (fallback->groups[i].group.name); -kfree (fallback->algs);kfree (fallback->sysfs_attrs);kfree (fallback->groups);mutex_destroy (&fallback->lock);
@@ -506,7 +523,8 @@ static void crypto_fallback_free(struct crypto_fallback *fallback) }static struct crypto_fallback * -fallback_alloc (struct device *dev,const struct crypto_fallback_group *groups, +fallback_alloc (struct module *owner,struct device *dev, +const struct crypto_fallback_group *groups,unsigned int num_groups) {struct crypto_fallback *fallback;
@@ -520,8 +538,12 @@ fallback_alloc(struct device *dev, const struct crypto_fallback_group *groups,if (!fallback)return ERR_PTR (-ENOMEM ); +kref_init (&fallback->refcount);mutex_init (&fallback->lock); +spin_lock_init (&fallback->alg_lock); +INIT_LIST_HEAD (&fallback->algs); fallback->dev =get_device (dev); + fallback->owner = owner; fallback->num_groups = num_groups; fallback->groups =kcalloc (num_groups,sizeof (*fallback->groups),GFP_KERNEL );
@@ -583,20 +605,11 @@ fallback_alloc(struct device *dev, const struct crypto_fallback_group *groups,return fallback; err_free: -crypto_fallback_free (fallback); +kref_put (&fallback->refcount, crypto_fallback_free);return ERR_PTR (err); } -static void fallback_release (struct crypto_fallback *fallback) -{ -if (!fallback ||IS_ERR (fallback)) -return ; - -sysfs_remove_group (&fallback->dev->kobj, &fallback->sysfs_group); -crypto_fallback_free (fallback); -} -static bool fallback_use_software (const struct fallback_threshold *threshold,unsigned int input_size) {
@@ -630,10 +643,20 @@ struct fallback_ahash_state { u8 state[] CRYPTO_MINALIGN_ATTR; }; +/* +* Allocate proxy algorithms per enable cycle because their destruction can be +* deferred until transforms allocated before disable release them. +*/ struct fallback_alg { +struct list_head list; +struct crypto_fallback *fallback; +struct kref refcount;const struct fallback_threshold *threshold;char driver_name[CRYPTO_MAX_ALG_NAME ];enum crypto_fallback_alg_type type; +bool registration_complete; +bool registered; +bool dead;union {struct skcipher_alg skcipher;struct aead_alg aead;
@@ -641,6 +664,87 @@ struct fallback_alg { } alg; }; +static void fallback_alg_release (struct kref *ref) +{ +struct fallback_alg *alg; +struct crypto_fallback *fallback; + + alg = container_of(ref, struct fallback_alg, refcount); + fallback = alg->fallback; +kfree (alg); +kref_put (&fallback->refcount, crypto_fallback_free); +} + +static void fallback_alg_destroy (struct fallback_alg *alg) +{ +struct crypto_fallback *fallback = alg->fallback; +unsigned long flags; +bool release = false; + +spin_lock_irqsave (&fallback->alg_lock, flags); + alg->dead = true; + alg->registered = false; +if (alg->registration_complete) { +list_del_init (&alg->list); + release = true; + } +spin_unlock_irqrestore (&fallback->alg_lock, flags); + +if (release) +kref_put (&alg->refcount, fallback_alg_release); +} + +static void fallback_skcipher_destroy (struct crypto_alg *base) +{ +struct skcipher_alg *alg; + + alg = container_of(base, struct skcipher_alg, base); +fallback_alg_destroy (container_of(alg ,struct fallback_alg , + alg.skcipher)); +} + +static void fallback_aead_destroy (struct crypto_alg *base) +{ +struct aead_alg *alg; + + alg = container_of(base, struct aead_alg, base); + fallback_alg_destroy(container_of(alg, struct fallback_alg, alg.aead)); +} + +static void fallback_ahash_destroy (struct crypto_alg *base) +{ +struct hash_alg_common *halg; +struct ahash_alg *alg; + + halg = container_of(base, struct hash_alg_common, base); + alg = container_of(halg, struct ahash_alg, halg); + fallback_alg_destroy(container_of(alg, struct fallback_alg, alg.ahash)); +} + +static int fallback_alg_complete_registration (struct fallback_alg *alg,int err) +{ +struct crypto_fallback *fallback = alg->fallback; +unsigned long flags; +bool release = false; + +spin_lock_irqsave (&fallback->alg_lock, flags); + alg->registration_complete = true; +if (err || alg->dead) { +list_del_init (&alg->list); + release = true; +if (!err) + err = -ENODEV ; + }else { + alg->registered = true; + } +spin_unlock_irqrestore (&fallback->alg_lock, flags); + +if (release) +kref_put (&alg->refcount, fallback_alg_release); + +return err; +} +static struct fallback_alg *fallback_skcipher_alg (struct crypto_skcipher *tfm) { return container_of(crypto_skcipher_alg(tfm), struct fallback_alg,
@@ -1068,6 +1172,7 @@ static int fallback_register_skcipher(struct fallback_alg *entry,if (err) goto out_free_software;fallback_init_base (&alg->base, &hcommon->base, &scommon->base, owner); + alg->base.cra_destroy = fallback_skcipher_destroy; alg->min_keysize =max (hcommon->min_keysize, scommon->min_keysize); alg->max_keysize =min (hcommon->max_keysize, scommon->max_keysize);if (alg->min_keysize > alg->max_keysize) {
@@ -1129,6 +1234,7 @@ static int fallback_register_aead(struct fallback_alg *entry,if (err) goto out_free_software;fallback_init_base (&alg->base, &halg->base, &salg->base, owner); + alg->base.cra_destroy = fallback_aead_destroy; alg->ivsize = halg->ivsize; alg->maxauthsize =min (halg->maxauthsize, salg->maxauthsize); alg->chunksize =max (halg->chunksize, salg->chunksize);
@@ -1187,6 +1293,7 @@ static int fallback_register_ahash(struct fallback_alg *entry, goto out_free_software;fallback_init_base (&alg->halg.base, &hcommon->base, &scommon->base, owner); + alg->halg.base.cra_destroy = fallback_ahash_destroy; alg->halg.base.cra_flags |=CRYPTO_ALG_REQ_VIRT ; alg->halg.base.cra_flags |= hcommon->base.cra_flags &CRYPTO_ALG_OPTIONAL_KEY ;
@@ -1246,87 +1353,124 @@ static void fallback_unregister_alg(struct fallback_alg *alg) } } -struct crypto_fallback * -crypto_fallback_register (struct module *owner,struct device *dev, -const struct crypto_fallback_group *groups, -unsigned int num_groups) +static void fallback_unregister_algs (struct crypto_fallback *fallback) { -struct crypto_fallback *fallback; -unsigned int num_algs =0 ; -unsigned int i, j; -int err; +struct fallback_alg *alg; +struct fallback_alg *candidate; +unsigned long flags; + +for (;;) { + alg =NULL ; +spin_lock_irqsave (&fallback->alg_lock, flags); +list_for_each_entry (candidate, &fallback->algs, list) { +if (!candidate->registered) +continue ; -if (!dev || !groups || !num_groups) -return ERR_PTR (-EINVAL ); + alg = candidate; + alg->registered = false; +kref_get (&alg->refcount); +break ; + } +spin_unlock_irqrestore (&fallback->alg_lock, flags); -for (i =0 ; i < num_groups; i++) { -if (!groups[i].algs || !groups[i].num_algs) -return ERR_PTR (-EINVAL ); -if (groups[i].num_algs >UINT_MAX - num_algs) -return ERR_PTR (-EOVERFLOW ); - num_algs += groups[i].num_algs; +if (!alg) +break ; + +fallback_unregister_alg (alg); +kref_put (&alg->refcount, fallback_alg_release); } +} - fallback =fallback_alloc (dev, groups, num_groups); -if (IS_ERR (fallback)) -return fallback; +static int fallback_register_algs (struct crypto_fallback *fallback) +{ +unsigned int i, j; +int err; - fallback->algs =kcalloc (num_algs,sizeof (*fallback->algs),GFP_KERNEL ); -if (!fallback->algs) { - err = -ENOMEM ; - goto err_release; - } -for (i =0 ; i < num_groups; i++) { -const struct fallback_threshold *threshold; +for (i =0 ; i < fallback->num_groups; i++) { +const struct crypto_fallback_group *group; - threshold = &fallback->groups[i].threshold; -for (j =0 ; j < groups[i].num_algs; j++) { -const char *driver_name = groups[i].algs[j]; -struct fallback_alg *alg = - &fallback->algs[fallback->num_algs]; + group = &fallback->groups[i].group; +for (j =0 ; j < group->num_algs; j++) { +struct fallback_alg *alg; +unsigned long flags; -if (!driver_name) { - err = -EINVAL ; + alg =kzalloc_obj (*alg,GFP_KERNEL ); +if (!alg) { + err = -ENOMEM ; goto err_unregister_algs; } - alg->type = groups[i].benchmark.type; - alg->threshold = threshold; -if (strscpy (alg->driver_name, driver_name, +INIT_LIST_HEAD (&alg->list); +kref_init (&alg->refcount); + alg->fallback = fallback; + alg->threshold = &fallback->groups[i].threshold; + alg->type = group->benchmark.type; +if (strscpy (alg->driver_name, group->algs[j],sizeof (alg->driver_name)) <0 ) { +kfree (alg); err = -ENAMETOOLONG ; goto err_unregister_algs; } - err =fallback_register_alg (alg, owner); +kref_get (&fallback->refcount); +spin_lock_irqsave (&fallback->alg_lock, flags); +list_add_tail (&alg->list, &fallback->algs); +spin_unlock_irqrestore (&fallback->alg_lock, flags); + + err =fallback_register_alg (alg, fallback->owner); + err =fallback_alg_complete_registration (alg, err);if (err == -ENOENT )continue ;if (err) goto err_unregister_algs; - fallback->num_algs++; } } -return fallback; +return 0 ; err_unregister_algs: -while (fallback->num_algs) -fallback_unregister_alg (&fallback->algs[--fallback->num_algs]); -err_release: -fallback_release (fallback); +fallback_unregister_algs (fallback); -return ERR_PTR (err); +return err; +} + +struct crypto_fallback * +crypto_fallback_register (struct module *owner,struct device *dev, +const struct crypto_fallback_group *groups, +unsigned int num_groups) +{ +unsigned int i, j; + +if (!owner || !dev || !groups || !num_groups) +return ERR_PTR (-EINVAL ); + +for (i =0 ; i < num_groups; i++) { +if (!groups[i].algs || !groups[i].num_algs) +return ERR_PTR (-EINVAL ); +for (j =0 ; j < groups[i].num_algs; j++) +if (!groups[i].algs[j]) +return ERR_PTR (-EINVAL ); + } + +return fallback_alloc (owner, dev, groups, num_groups); }EXPORT_SYMBOL_GPL (crypto_fallback_register);void crypto_fallback_unregister (struct crypto_fallback *fallback) { +unsigned int i; +if (!fallback ||IS_ERR (fallback))return ; -while (fallback->num_algs) -fallback_unregister_alg (&fallback->algs[--fallback->num_algs]); -fallback_release (fallback); +sysfs_remove_group (&fallback->dev->kobj, &fallback->sysfs_group); +mutex_lock (&fallback->lock); +WRITE_ONCE (fallback->enabled, false); +for (i =0 ; i < fallback->num_groups; i++) +WRITE_ONCE (fallback->groups[i].threshold.value,0 ); +fallback_unregister_algs (fallback); +mutex_unlock (&fallback->lock); +kref_put (&fallback->refcount, crypto_fallback_free); }EXPORT_SYMBOL_GPL (crypto_fallback_unregister);
Signature · 1 line
2.53.0
Herbert Xu
maintainerQuoted 7 lines · Jihong Min
The tcrypt AES-128-CBC results are median cycles from five runs. Lower is better. Disabled uses cbc(aes-eip93) directly, while enabled uses fallback(cbc(aes-eip93)).
Request Disabled Enabled Cycle reduction
(bytes) (cycles) (cycles)
Quoted 7 lines
16 322 18 94.4%
64 274 43 84.3%
128 292 74 74.7%
256 312 138 55.8%
1024 434 439 -1.2%
1424 492 488 0.8%
4096 980 1023 -4.4%Do these results vary that much at run-time that requires a run-time test? Surely you can predict the outcome for the platforms involved?
It appears to me that you're simply adding complexity for something that can already be easily tuned by the administrator through the algorithm priorities.
In fact, why not implement the benchmark in user-space and then based on that result adjust the priorities?
Cheers,
Signature · 3 lines
Email: Herbert Xu <[email protected]> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
Hi,
Quoted 16 lines · Herbert Xu
Quoted 7 lines · Jihong Min
The tcrypt AES-128-CBC results are median cycles from five runs. Lower is better. Disabled uses cbc(aes-eip93) directly, while enabled uses fallback(cbc(aes-eip93)).
Request Disabled Enabled Cycle reduction
(bytes) (cycles) (cycles)Quoted 7 lines
16 322 18 94.4% 64 274 43 84.3% 128 292 74 74.7% 256 312 138 55.8% 1024 434 439 -1.2% 1424 492 488 0.8% 4096 980 1023 -4.4%
Quoted 5 lines
Do these results vary that much at run-time that requires a run-time test? Surely you can predict the outcome for the platforms involved?> It appears to me that you're simply adding complexity for something that can already be easily tuned by the administrator through the algorithm priorities.
Many crypto IP including EIP93 can have different host CPU performance. This idea is directly from in-kernel raid6 module to dynamically calculate this host CPU performance to set the boundaries.
Quoted 3 lines
In fact, why not implement the benchmark in user-space and then based on that result adjust the priorities?
The same reason why there is the kernel crypto API. It is a single point (both AF_ALG and devcrypto) of entrance to each crypto device implementation. It is best to control within them.
Quoted 2 lines
Cheers,
Sincerely,
Jihong Min