diff --git a/crypto/Kconfig b/crypto/Kconfig
index 5575d48473bd..956379b24c74 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -119,6 +119,14 @@ config CRYPTO_MANAGER
 	  Create default cryptographic template instantiations such as
 	  cbc(aes).
 
+config CRYPTO_MANAGER_RUNTESTS
+	tristate "Cryptographic algorithm manager: test module"
+	depends on CRYPTO_MANAGER2 && !CRYPTO_MANAGER_DISABLE_TESTS
+	default m
+	help
+	  Build a module that runs the tests from cryptographic algorithm
+	  manager when loaded.
+
 config CRYPTO_MANAGER2
 	def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y)
 	select CRYPTO_AEAD2
diff --git a/crypto/Makefile b/crypto/Makefile
index 4ca12b6044f7..c296b27da29e 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -47,6 +47,9 @@ crypto_acompress-y += scompress.o
 obj-$(CONFIG_CRYPTO_ACOMP2) += crypto_acompress.o
 
 cryptomgr-y := algboss.o testmgr.o
+cryptomgr_runtests-y := testmgr_runtests.o algboss_runtests.o
+
+obj-$(CONFIG_CRYPTO_MANAGER_RUNTESTS) += cryptomgr_runtests.o
 
 obj-$(CONFIG_CRYPTO_MANAGER2) += cryptomgr.o
 obj-$(CONFIG_CRYPTO_USER) += crypto_user.o
diff --git a/crypto/alg_test_desc.h b/crypto/alg_test_desc.h
new file mode 100644
index 000000000000..a718092737d0
--- /dev/null
+++ b/crypto/alg_test_desc.h
@@ -0,0 +1,219 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef CRYPTO_ALG_TEST_DESC_H
+#define CRYPTO_ALG_TEST_DESC_H
+
+#include <linux/oid_registry.h>
+
+/*
+ * hash_testvec:	structure to describe a hash (message digest) test
+ * @key:	Pointer to key (NULL if none)
+ * @plaintext:	Pointer to source data
+ * @digest:	Pointer to expected digest
+ * @psize:	Length of source data in bytes
+ * @ksize:	Length of @key in bytes (0 if no key)
+ * @setkey_error: Expected error from setkey()
+ * @digest_error: Expected error from digest()
+ */
+struct hash_testvec {
+	const char *key;
+	const char *plaintext;
+	const char *digest;
+	unsigned int psize;
+	unsigned short ksize;
+	int setkey_error;
+	int digest_error;
+};
+
+/*
+ * cipher_testvec:	structure to describe a symmetric cipher test
+ * @key:	Pointer to key
+ * @klen:	Length of @key in bytes
+ * @iv:		Pointer to IV.  If NULL, an all-zeroes IV is used.
+ * @iv_out:	Pointer to output IV, if applicable for the cipher.
+ * @ptext:	Pointer to plaintext
+ * @ctext:	Pointer to ciphertext
+ * @len:	Length of @ptext and @ctext in bytes
+ * @wk:		Does the test need CRYPTO_TFM_REQ_FORBID_WEAK_KEYS?
+ *		( e.g. test needs to fail due to a weak key )
+ * @fips_skip:	Skip the test vector in FIPS mode
+ * @generates_iv: Encryption should ignore the given IV, and output @iv_out.
+ *		  Decryption takes @iv_out.  Needed for AES Keywrap ("kw(aes)").
+ * @setkey_error: Expected error from setkey()
+ * @crypt_error: Expected error from encrypt() and decrypt()
+ */
+struct cipher_testvec {
+	const char *key;
+	const char *iv;
+	const char *iv_out;
+	const char *ptext;
+	const char *ctext;
+	unsigned char wk; /* weak key flag */
+	unsigned short klen;
+	unsigned int len;
+	bool fips_skip;
+	bool generates_iv;
+	int setkey_error;
+	int crypt_error;
+};
+
+/*
+ * aead_testvec:	structure to describe an AEAD test
+ * @key:	Pointer to key
+ * @iv:		Pointer to IV.  If NULL, an all-zeroes IV is used.
+ * @ptext:	Pointer to plaintext
+ * @assoc:	Pointer to associated data
+ * @ctext:	Pointer to the full authenticated ciphertext.  For AEADs that
+ *		produce a separate "ciphertext" and "authentication tag", these
+ *		two parts are concatenated: ciphertext || tag.
+ * @novrfy:	Decryption verification failure expected?
+ * @wk:		Does the test need CRYPTO_TFM_REQ_FORBID_WEAK_KEYS?
+ *		(e.g. setkey() needs to fail due to a weak key)
+ * @klen:	Length of @key in bytes
+ * @plen:	Length of @ptext in bytes
+ * @alen:	Length of @assoc in bytes
+ * @clen:	Length of @ctext in bytes
+ * @setkey_error: Expected error from setkey()
+ * @setauthsize_error: Expected error from setauthsize()
+ * @crypt_error: Expected error from encrypt() and decrypt()
+ */
+struct aead_testvec {
+	const char *key;
+	const char *iv;
+	const char *ptext;
+	const char *assoc;
+	const char *ctext;
+	unsigned char novrfy;
+	unsigned char wk;
+	unsigned char klen;
+	unsigned int plen;
+	unsigned int clen;
+	unsigned int alen;
+	int setkey_error;
+	int setauthsize_error;
+	int crypt_error;
+};
+
+struct cprng_testvec {
+	const char *key;
+	const char *dt;
+	const char *v;
+	const char *result;
+	unsigned char klen;
+	unsigned short dtlen;
+	unsigned short vlen;
+	unsigned short rlen;
+	unsigned short loops;
+};
+
+struct drbg_testvec {
+	const unsigned char *entropy;
+	size_t entropylen;
+	const unsigned char *entpra;
+	const unsigned char *entprb;
+	size_t entprlen;
+	const unsigned char *addtla;
+	const unsigned char *addtlb;
+	size_t addtllen;
+	const unsigned char *pers;
+	size_t perslen;
+	const unsigned char *expected;
+	size_t expectedlen;
+};
+
+struct akcipher_testvec {
+	const unsigned char *key;
+	const unsigned char *params;
+	const unsigned char *m;
+	const unsigned char *c;
+	unsigned int key_len;
+	unsigned int param_len;
+	unsigned int m_size;
+	unsigned int c_size;
+	bool public_key_vec;
+	bool siggen_sigver_test;
+	enum OID algo;
+};
+
+struct kpp_testvec {
+	const unsigned char *secret;
+	const unsigned char *b_secret;
+	const unsigned char *b_public;
+	const unsigned char *expected_a_public;
+	const unsigned char *expected_ss;
+	unsigned short secret_size;
+	unsigned short b_secret_size;
+	unsigned short b_public_size;
+	unsigned short expected_a_public_size;
+	unsigned short expected_ss_size;
+	bool genkey;
+};
+
+
+struct aead_test_suite {
+	const struct aead_testvec *vecs;
+	unsigned int count;
+};
+
+struct cipher_test_suite {
+	const struct cipher_testvec *vecs;
+	unsigned int count;
+};
+
+struct comp_test_suite {
+	struct {
+		const struct comp_testvec *vecs;
+		unsigned int count;
+	} comp, decomp;
+};
+
+struct hash_test_suite {
+	const struct hash_testvec *vecs;
+	unsigned int count;
+};
+
+struct cprng_test_suite {
+	const struct cprng_testvec *vecs;
+	unsigned int count;
+};
+
+struct drbg_test_suite {
+	const struct drbg_testvec *vecs;
+	unsigned int count;
+};
+
+struct akcipher_test_suite {
+	const struct akcipher_testvec *vecs;
+	unsigned int count;
+};
+
+struct kpp_test_suite {
+	const struct kpp_testvec *vecs;
+	unsigned int count;
+};
+
+struct alg_test_desc {
+	const char *alg;
+	const char *generic_driver;
+	int (*test)(const struct alg_test_desc *desc, const char *driver,
+		    u32 type, u32 mask);
+	int fips_allowed;	/* set if alg is allowed in fips mode */
+
+	union {
+		struct aead_test_suite aead;
+		struct cipher_test_suite cipher;
+		struct comp_test_suite comp;
+		struct hash_test_suite hash;
+		struct cprng_test_suite cprng;
+		struct drbg_test_suite drbg;
+		struct akcipher_test_suite akcipher;
+		struct kpp_test_suite kpp;
+	} suite;
+};
+
+int alg_test_cipher(const struct alg_test_desc *desc,
+		    const char *driver, u32 type, u32 mask);
+
+extern const struct alg_test_desc alg_test_descs[];
+extern const int nr_alg_test_descs;
+
+#endif /* CRYPTO_ALG_TEST_DESC_H */
diff --git a/crypto/algboss.c b/crypto/algboss.c
index a62149d6c839..be37c78c7833 100644
--- a/crypto/algboss.c
+++ b/crypto/algboss.c
@@ -300,5 +300,7 @@ static void __exit cryptomgr_exit(void)
 arch_initcall(cryptomgr_init);
 module_exit(cryptomgr_exit);
 
+EXPORT_SYMBOL_GPL(alg_test);
+
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Crypto Algorithm Manager");
diff --git a/crypto/algboss_runtests.c b/crypto/algboss_runtests.c
new file mode 100644
index 000000000000..7aa3459cc4fc
--- /dev/null
+++ b/crypto/algboss_runtests.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/module.h>
+#include "alg_test_desc.h"
+
+static int __init testmgr_runtests_init(void)
+{
+	int i;
+	int ret = 0;
+
+	for (i = 0; i < nr_alg_test_descs; i++) {
+		const char *alg = alg_test_descs[i].alg;
+		int rc;
+
+		pr_info("Testing %s ...", alg);
+		rc = alg_test_descs[i].test(alg_test_descs + i, alg, 0, 0);
+		switch (rc) {
+		case 0:
+			pr_info("PASSED\n");
+			break;
+		case -2:
+			pr_info("SKIPPED\n");
+			break;
+
+		default:
+			ret = rc;
+			pr_err("%s FAILED(%i)\n", alg, rc);
+		}
+	}
+	return ret;
+}
+
+static void __exit testmgr_runtests_exit(void) {}
+
+module_init(testmgr_runtests_init);
+module_exit(testmgr_runtests_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Crypto Algorithm Manager Test Module");
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 82513b6b0abd..85d919285e81 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -79,67 +79,6 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
 #define ENCRYPT 1
 #define DECRYPT 0
 
-struct aead_test_suite {
-	const struct aead_testvec *vecs;
-	unsigned int count;
-};
-
-struct cipher_test_suite {
-	const struct cipher_testvec *vecs;
-	unsigned int count;
-};
-
-struct comp_test_suite {
-	struct {
-		const struct comp_testvec *vecs;
-		unsigned int count;
-	} comp, decomp;
-};
-
-struct hash_test_suite {
-	const struct hash_testvec *vecs;
-	unsigned int count;
-};
-
-struct cprng_test_suite {
-	const struct cprng_testvec *vecs;
-	unsigned int count;
-};
-
-struct drbg_test_suite {
-	const struct drbg_testvec *vecs;
-	unsigned int count;
-};
-
-struct akcipher_test_suite {
-	const struct akcipher_testvec *vecs;
-	unsigned int count;
-};
-
-struct kpp_test_suite {
-	const struct kpp_testvec *vecs;
-	unsigned int count;
-};
-
-struct alg_test_desc {
-	const char *alg;
-	const char *generic_driver;
-	int (*test)(const struct alg_test_desc *desc, const char *driver,
-		    u32 type, u32 mask);
-	int fips_allowed;	/* set if alg is allowed in fips mode */
-
-	union {
-		struct aead_test_suite aead;
-		struct cipher_test_suite cipher;
-		struct comp_test_suite comp;
-		struct hash_test_suite hash;
-		struct cprng_test_suite cprng;
-		struct drbg_test_suite drbg;
-		struct akcipher_test_suite akcipher;
-		struct kpp_test_suite kpp;
-	} suite;
-};
-
 static void hexdump(unsigned char *buf, unsigned int len)
 {
 	print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
@@ -3232,8 +3171,8 @@ static int test_cprng(struct crypto_rng *tfm,
 	return err;
 }
 
-static int alg_test_cipher(const struct alg_test_desc *desc,
-			   const char *driver, u32 type, u32 mask)
+int alg_test_cipher(const struct alg_test_desc *desc,
+		    const char *driver, u32 type, u32 mask)
 {
 	const struct cipher_test_suite *suite = &desc->suite.cipher;
 	struct crypto_cipher *tfm;
@@ -3865,7 +3804,7 @@ static int alg_test_null(const struct alg_test_desc *desc,
 #define __VECS(tv)	{ .vecs = tv, .count = ARRAY_SIZE(tv) }
 
 /* Please keep this list sorted by algorithm name. */
-static const struct alg_test_desc alg_test_descs[] = {
+const struct alg_test_desc alg_test_descs[] = {
 	{
 		.alg = "adiantum(xchacha12,aes)",
 		.generic_driver = "adiantum(xchacha12-generic,aes-generic,nhpoly1305-generic)",
@@ -5204,6 +5143,8 @@ static const struct alg_test_desc alg_test_descs[] = {
 	}
 };
 
+const int nr_alg_test_descs = ARRAY_SIZE(alg_test_descs);
+
 static void alg_check_test_descs_order(void)
 {
 	int i;
@@ -5341,5 +5282,3 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
 }
 
 #endif /* CONFIG_CRYPTO_MANAGER_DISABLE_TESTS */
-
-EXPORT_SYMBOL_GPL(alg_test);
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index 48da646651cb..378a1bdce74f 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -20,154 +20,10 @@
 #ifndef _CRYPTO_TESTMGR_H
 #define _CRYPTO_TESTMGR_H
 
-#include <linux/oid_registry.h>
+#include "alg_test_desc.h"
 
 #define MAX_IVLEN		32
 
-/*
- * hash_testvec:	structure to describe a hash (message digest) test
- * @key:	Pointer to key (NULL if none)
- * @plaintext:	Pointer to source data
- * @digest:	Pointer to expected digest
- * @psize:	Length of source data in bytes
- * @ksize:	Length of @key in bytes (0 if no key)
- * @setkey_error: Expected error from setkey()
- * @digest_error: Expected error from digest()
- */
-struct hash_testvec {
-	const char *key;
-	const char *plaintext;
-	const char *digest;
-	unsigned int psize;
-	unsigned short ksize;
-	int setkey_error;
-	int digest_error;
-};
-
-/*
- * cipher_testvec:	structure to describe a symmetric cipher test
- * @key:	Pointer to key
- * @klen:	Length of @key in bytes
- * @iv:		Pointer to IV.  If NULL, an all-zeroes IV is used.
- * @iv_out:	Pointer to output IV, if applicable for the cipher.
- * @ptext:	Pointer to plaintext
- * @ctext:	Pointer to ciphertext
- * @len:	Length of @ptext and @ctext in bytes
- * @wk:		Does the test need CRYPTO_TFM_REQ_FORBID_WEAK_KEYS?
- * 		( e.g. test needs to fail due to a weak key )
- * @fips_skip:	Skip the test vector in FIPS mode
- * @generates_iv: Encryption should ignore the given IV, and output @iv_out.
- *		  Decryption takes @iv_out.  Needed for AES Keywrap ("kw(aes)").
- * @setkey_error: Expected error from setkey()
- * @crypt_error: Expected error from encrypt() and decrypt()
- */
-struct cipher_testvec {
-	const char *key;
-	const char *iv;
-	const char *iv_out;
-	const char *ptext;
-	const char *ctext;
-	unsigned char wk; /* weak key flag */
-	unsigned short klen;
-	unsigned int len;
-	bool fips_skip;
-	bool generates_iv;
-	int setkey_error;
-	int crypt_error;
-};
-
-/*
- * aead_testvec:	structure to describe an AEAD test
- * @key:	Pointer to key
- * @iv:		Pointer to IV.  If NULL, an all-zeroes IV is used.
- * @ptext:	Pointer to plaintext
- * @assoc:	Pointer to associated data
- * @ctext:	Pointer to the full authenticated ciphertext.  For AEADs that
- *		produce a separate "ciphertext" and "authentication tag", these
- *		two parts are concatenated: ciphertext || tag.
- * @novrfy:	Decryption verification failure expected?
- * @wk:		Does the test need CRYPTO_TFM_REQ_FORBID_WEAK_KEYS?
- *		(e.g. setkey() needs to fail due to a weak key)
- * @klen:	Length of @key in bytes
- * @plen:	Length of @ptext in bytes
- * @alen:	Length of @assoc in bytes
- * @clen:	Length of @ctext in bytes
- * @setkey_error: Expected error from setkey()
- * @setauthsize_error: Expected error from setauthsize()
- * @crypt_error: Expected error from encrypt() and decrypt()
- */
-struct aead_testvec {
-	const char *key;
-	const char *iv;
-	const char *ptext;
-	const char *assoc;
-	const char *ctext;
-	unsigned char novrfy;
-	unsigned char wk;
-	unsigned char klen;
-	unsigned int plen;
-	unsigned int clen;
-	unsigned int alen;
-	int setkey_error;
-	int setauthsize_error;
-	int crypt_error;
-};
-
-struct cprng_testvec {
-	const char *key;
-	const char *dt;
-	const char *v;
-	const char *result;
-	unsigned char klen;
-	unsigned short dtlen;
-	unsigned short vlen;
-	unsigned short rlen;
-	unsigned short loops;
-};
-
-struct drbg_testvec {
-	const unsigned char *entropy;
-	size_t entropylen;
-	const unsigned char *entpra;
-	const unsigned char *entprb;
-	size_t entprlen;
-	const unsigned char *addtla;
-	const unsigned char *addtlb;
-	size_t addtllen;
-	const unsigned char *pers;
-	size_t perslen;
-	const unsigned char *expected;
-	size_t expectedlen;
-};
-
-struct akcipher_testvec {
-	const unsigned char *key;
-	const unsigned char *params;
-	const unsigned char *m;
-	const unsigned char *c;
-	unsigned int key_len;
-	unsigned int param_len;
-	unsigned int m_size;
-	unsigned int c_size;
-	bool public_key_vec;
-	bool siggen_sigver_test;
-	enum OID algo;
-};
-
-struct kpp_testvec {
-	const unsigned char *secret;
-	const unsigned char *b_secret;
-	const unsigned char *b_public;
-	const unsigned char *expected_a_public;
-	const unsigned char *expected_ss;
-	unsigned short secret_size;
-	unsigned short b_secret_size;
-	unsigned short b_public_size;
-	unsigned short expected_a_public_size;
-	unsigned short expected_ss_size;
-	bool genkey;
-};
-
 static const char zeroed_string[48];
 
 /*
diff --git a/crypto/testmgr_runtests.c b/crypto/testmgr_runtests.c
new file mode 120000
index 000000000000..e2a85037239d
--- /dev/null
+++ b/crypto/testmgr_runtests.c
@@ -0,0 +1 @@
+testmgr.c
\ No newline at end of file
