Commit d072bfa4 authored by Christian Lamparter's avatar Christian Lamparter Committed by Herbert Xu
Browse files

crypto: crypto4xx - add prng crypto support



This patch adds support for crypto4xx's ANSI X9.17 Annex C compliant
pseudo random number generator which provides a pseudo random source
for the purpose of generating  Initialization Vectors (IV's) for AES
algorithms to the Packet Engine and other pseudo random number
requirements.

Signed-off-by: default avatarChristian Lamparter <chunkeey@gmail.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 12b8567f
Loading
Loading
Loading
Loading
+87 −0
Original line number Diff line number Diff line
@@ -40,9 +40,11 @@
#include <crypto/ctr.h>
#include <crypto/gcm.h>
#include <crypto/sha.h>
#include <crypto/rng.h>
#include <crypto/scatterwalk.h>
#include <crypto/skcipher.h>
#include <crypto/internal/aead.h>
#include <crypto/internal/rng.h>
#include <crypto/internal/skcipher.h>
#include "crypto4xx_reg_def.h"
#include "crypto4xx_core.h"
@@ -1035,6 +1037,10 @@ static int crypto4xx_register_alg(struct crypto4xx_device *sec_dev,
			rc = crypto_register_ahash(&alg->alg.u.hash);
			break;

		case CRYPTO_ALG_TYPE_RNG:
			rc = crypto_register_rng(&alg->alg.u.rng);
			break;

		default:
			rc = crypto_register_skcipher(&alg->alg.u.cipher);
			break;
@@ -1064,6 +1070,10 @@ static void crypto4xx_unregister_alg(struct crypto4xx_device *sec_dev)
			crypto_unregister_aead(&alg->alg.u.aead);
			break;

		case CRYPTO_ALG_TYPE_RNG:
			crypto_unregister_rng(&alg->alg.u.rng);
			break;

		default:
			crypto_unregister_skcipher(&alg->alg.u.cipher);
		}
@@ -1122,6 +1132,69 @@ static irqreturn_t crypto4xx_ce_interrupt_handler_revb(int irq, void *data)
		PPC4XX_TMO_ERR_INT);
}

static int ppc4xx_prng_data_read(struct crypto4xx_device *dev,
				 u8 *data, unsigned int max)
{
	unsigned int i, curr = 0;
	u32 val[2];

	do {
		/* trigger PRN generation */
		writel(PPC4XX_PRNG_CTRL_AUTO_EN,
		       dev->ce_base + CRYPTO4XX_PRNG_CTRL);

		for (i = 0; i < 1024; i++) {
			/* usually 19 iterations are enough */
			if ((readl(dev->ce_base + CRYPTO4XX_PRNG_STAT) &
			     CRYPTO4XX_PRNG_STAT_BUSY))
				continue;

			val[0] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_0);
			val[1] = readl_be(dev->ce_base + CRYPTO4XX_PRNG_RES_1);
			break;
		}
		if (i == 1024)
			return -ETIMEDOUT;

		if ((max - curr) >= 8) {
			memcpy(data, &val, 8);
			data += 8;
			curr += 8;
		} else {
			/* copy only remaining bytes */
			memcpy(data, &val, max - curr);
			break;
		}
	} while (curr < max);

	return curr;
}

static int crypto4xx_prng_generate(struct crypto_rng *tfm,
				   const u8 *src, unsigned int slen,
				   u8 *dstn, unsigned int dlen)
{
	struct rng_alg *alg = crypto_rng_alg(tfm);
	struct crypto4xx_alg *amcc_alg;
	struct crypto4xx_device *dev;
	int ret;

	amcc_alg = container_of(alg, struct crypto4xx_alg, alg.u.rng);
	dev = amcc_alg->dev;

	mutex_lock(&dev->core_dev->rng_lock);
	ret = ppc4xx_prng_data_read(dev, dstn, dlen);
	mutex_unlock(&dev->core_dev->rng_lock);
	return ret;
}


static int crypto4xx_prng_seed(struct crypto_rng *tfm, const u8 *seed,
			unsigned int slen)
{
	return 0;
}

/**
 * Supported Crypto Algorithms
 */
@@ -1291,6 +1364,18 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = {
			.cra_module	= THIS_MODULE,
		},
	} },
	{ .type = CRYPTO_ALG_TYPE_RNG, .u.rng = {
		.base = {
			.cra_name		= "stdrng",
			.cra_driver_name        = "crypto4xx_rng",
			.cra_priority		= 300,
			.cra_ctxsize		= 0,
			.cra_module		= THIS_MODULE,
		},
		.generate               = crypto4xx_prng_generate,
		.seed                   = crypto4xx_prng_seed,
		.seedsize               = 0,
	} },
};

/**
@@ -1360,6 +1445,7 @@ static int crypto4xx_probe(struct platform_device *ofdev)
	core_dev->dev->core_dev = core_dev;
	core_dev->dev->is_revb = is_revb;
	core_dev->device = dev;
	mutex_init(&core_dev->rng_lock);
	spin_lock_init(&core_dev->lock);
	INIT_LIST_HEAD(&core_dev->dev->alg_list);
	ratelimit_default_init(&core_dev->dev->aead_ratelimit);
@@ -1439,6 +1525,7 @@ static int crypto4xx_remove(struct platform_device *ofdev)
	tasklet_kill(&core_dev->tasklet);
	/* Un-register with Linux CryptoAPI */
	crypto4xx_unregister_alg(core_dev->dev);
	mutex_destroy(&core_dev->rng_lock);
	/* Free all allocated memory */
	crypto4xx_stop_all(core_dev);

+4 −0
Original line number Diff line number Diff line
@@ -23,8 +23,10 @@
#define __CRYPTO4XX_CORE_H__

#include <linux/ratelimit.h>
#include <linux/mutex.h>
#include <crypto/internal/hash.h>
#include <crypto/internal/aead.h>
#include <crypto/internal/rng.h>
#include <crypto/internal/skcipher.h>
#include "crypto4xx_reg_def.h"
#include "crypto4xx_sa.h"
@@ -119,6 +121,7 @@ struct crypto4xx_core_device {
	u32 irq;
	struct tasklet_struct tasklet;
	spinlock_t lock;
	struct mutex rng_lock;
};

struct crypto4xx_ctx {
@@ -143,6 +146,7 @@ struct crypto4xx_alg_common {
		struct skcipher_alg cipher;
		struct ahash_alg hash;
		struct aead_alg aead;
		struct rng_alg rng;
	} u;
};

+1 −0
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@
#define CRYPTO4XX_ENDIAN_CFG			0x000600d8

#define CRYPTO4XX_PRNG_STAT			0x00070000
#define CRYPTO4XX_PRNG_STAT_BUSY		0x1
#define CRYPTO4XX_PRNG_CTRL			0x00070004
#define CRYPTO4XX_PRNG_SEED_L			0x00070008
#define CRYPTO4XX_PRNG_SEED_H			0x0007000c