xref: /openbmc/linux/drivers/crypto/n2_core.c (revision 65a23d67)
10a625fd2SDavid S. Miller /* n2_core.c: Niagara2 Stream Processing Unit (SPU) crypto support.
20a625fd2SDavid S. Miller  *
30a625fd2SDavid S. Miller  * Copyright (C) 2010 David S. Miller <davem@davemloft.net>
40a625fd2SDavid S. Miller  */
50a625fd2SDavid S. Miller 
60a625fd2SDavid S. Miller #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
70a625fd2SDavid S. Miller 
80a625fd2SDavid S. Miller #include <linux/kernel.h>
90a625fd2SDavid S. Miller #include <linux/module.h>
100a625fd2SDavid S. Miller #include <linux/of.h>
110a625fd2SDavid S. Miller #include <linux/of_device.h>
120a625fd2SDavid S. Miller #include <linux/cpumask.h>
130a625fd2SDavid S. Miller #include <linux/slab.h>
140a625fd2SDavid S. Miller #include <linux/interrupt.h>
150a625fd2SDavid S. Miller #include <linux/crypto.h>
160a625fd2SDavid S. Miller #include <crypto/md5.h>
170a625fd2SDavid S. Miller #include <crypto/sha.h>
180a625fd2SDavid S. Miller #include <crypto/aes.h>
190a625fd2SDavid S. Miller #include <crypto/des.h>
200a625fd2SDavid S. Miller #include <linux/mutex.h>
210a625fd2SDavid S. Miller #include <linux/delay.h>
220a625fd2SDavid S. Miller #include <linux/sched.h>
230a625fd2SDavid S. Miller 
240a625fd2SDavid S. Miller #include <crypto/internal/hash.h>
250a625fd2SDavid S. Miller #include <crypto/scatterwalk.h>
260a625fd2SDavid S. Miller #include <crypto/algapi.h>
270a625fd2SDavid S. Miller 
280a625fd2SDavid S. Miller #include <asm/hypervisor.h>
290a625fd2SDavid S. Miller #include <asm/mdesc.h>
300a625fd2SDavid S. Miller 
310a625fd2SDavid S. Miller #include "n2_core.h"
320a625fd2SDavid S. Miller 
330a625fd2SDavid S. Miller #define DRV_MODULE_NAME		"n2_crypto"
340a625fd2SDavid S. Miller #define DRV_MODULE_VERSION	"0.1"
350a625fd2SDavid S. Miller #define DRV_MODULE_RELDATE	"April 29, 2010"
360a625fd2SDavid S. Miller 
370a625fd2SDavid S. Miller static char version[] __devinitdata =
380a625fd2SDavid S. Miller 	DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
390a625fd2SDavid S. Miller 
400a625fd2SDavid S. Miller MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
410a625fd2SDavid S. Miller MODULE_DESCRIPTION("Niagara2 Crypto driver");
420a625fd2SDavid S. Miller MODULE_LICENSE("GPL");
430a625fd2SDavid S. Miller MODULE_VERSION(DRV_MODULE_VERSION);
440a625fd2SDavid S. Miller 
450a625fd2SDavid S. Miller #define N2_CRA_PRIORITY		300
460a625fd2SDavid S. Miller 
470a625fd2SDavid S. Miller static DEFINE_MUTEX(spu_lock);
480a625fd2SDavid S. Miller 
490a625fd2SDavid S. Miller struct spu_queue {
500a625fd2SDavid S. Miller 	cpumask_t		sharing;
510a625fd2SDavid S. Miller 	unsigned long		qhandle;
520a625fd2SDavid S. Miller 
530a625fd2SDavid S. Miller 	spinlock_t		lock;
540a625fd2SDavid S. Miller 	u8			q_type;
550a625fd2SDavid S. Miller 	void			*q;
560a625fd2SDavid S. Miller 	unsigned long		head;
570a625fd2SDavid S. Miller 	unsigned long		tail;
580a625fd2SDavid S. Miller 	struct list_head	jobs;
590a625fd2SDavid S. Miller 
600a625fd2SDavid S. Miller 	unsigned long		devino;
610a625fd2SDavid S. Miller 
620a625fd2SDavid S. Miller 	char			irq_name[32];
630a625fd2SDavid S. Miller 	unsigned int		irq;
640a625fd2SDavid S. Miller 
650a625fd2SDavid S. Miller 	struct list_head	list;
660a625fd2SDavid S. Miller };
670a625fd2SDavid S. Miller 
680a625fd2SDavid S. Miller static struct spu_queue **cpu_to_cwq;
690a625fd2SDavid S. Miller static struct spu_queue **cpu_to_mau;
700a625fd2SDavid S. Miller 
710a625fd2SDavid S. Miller static unsigned long spu_next_offset(struct spu_queue *q, unsigned long off)
720a625fd2SDavid S. Miller {
730a625fd2SDavid S. Miller 	if (q->q_type == HV_NCS_QTYPE_MAU) {
740a625fd2SDavid S. Miller 		off += MAU_ENTRY_SIZE;
750a625fd2SDavid S. Miller 		if (off == (MAU_ENTRY_SIZE * MAU_NUM_ENTRIES))
760a625fd2SDavid S. Miller 			off = 0;
770a625fd2SDavid S. Miller 	} else {
780a625fd2SDavid S. Miller 		off += CWQ_ENTRY_SIZE;
790a625fd2SDavid S. Miller 		if (off == (CWQ_ENTRY_SIZE * CWQ_NUM_ENTRIES))
800a625fd2SDavid S. Miller 			off = 0;
810a625fd2SDavid S. Miller 	}
820a625fd2SDavid S. Miller 	return off;
830a625fd2SDavid S. Miller }
840a625fd2SDavid S. Miller 
850a625fd2SDavid S. Miller struct n2_request_common {
860a625fd2SDavid S. Miller 	struct list_head	entry;
870a625fd2SDavid S. Miller 	unsigned int		offset;
880a625fd2SDavid S. Miller };
890a625fd2SDavid S. Miller #define OFFSET_NOT_RUNNING	(~(unsigned int)0)
900a625fd2SDavid S. Miller 
910a625fd2SDavid S. Miller /* An async job request records the final tail value it used in
920a625fd2SDavid S. Miller  * n2_request_common->offset, test to see if that offset is in
930a625fd2SDavid S. Miller  * the range old_head, new_head, inclusive.
940a625fd2SDavid S. Miller  */
950a625fd2SDavid S. Miller static inline bool job_finished(struct spu_queue *q, unsigned int offset,
960a625fd2SDavid S. Miller 				unsigned long old_head, unsigned long new_head)
970a625fd2SDavid S. Miller {
980a625fd2SDavid S. Miller 	if (old_head <= new_head) {
990a625fd2SDavid S. Miller 		if (offset > old_head && offset <= new_head)
1000a625fd2SDavid S. Miller 			return true;
1010a625fd2SDavid S. Miller 	} else {
1020a625fd2SDavid S. Miller 		if (offset > old_head || offset <= new_head)
1030a625fd2SDavid S. Miller 			return true;
1040a625fd2SDavid S. Miller 	}
1050a625fd2SDavid S. Miller 	return false;
1060a625fd2SDavid S. Miller }
1070a625fd2SDavid S. Miller 
1080a625fd2SDavid S. Miller /* When the HEAD marker is unequal to the actual HEAD, we get
1090a625fd2SDavid S. Miller  * a virtual device INO interrupt.  We should process the
1100a625fd2SDavid S. Miller  * completed CWQ entries and adjust the HEAD marker to clear
1110a625fd2SDavid S. Miller  * the IRQ.
1120a625fd2SDavid S. Miller  */
1130a625fd2SDavid S. Miller static irqreturn_t cwq_intr(int irq, void *dev_id)
1140a625fd2SDavid S. Miller {
1150a625fd2SDavid S. Miller 	unsigned long off, new_head, hv_ret;
1160a625fd2SDavid S. Miller 	struct spu_queue *q = dev_id;
1170a625fd2SDavid S. Miller 
1180a625fd2SDavid S. Miller 	pr_err("CPU[%d]: Got CWQ interrupt for qhdl[%lx]\n",
1190a625fd2SDavid S. Miller 	       smp_processor_id(), q->qhandle);
1200a625fd2SDavid S. Miller 
1210a625fd2SDavid S. Miller 	spin_lock(&q->lock);
1220a625fd2SDavid S. Miller 
1230a625fd2SDavid S. Miller 	hv_ret = sun4v_ncs_gethead(q->qhandle, &new_head);
1240a625fd2SDavid S. Miller 
1250a625fd2SDavid S. Miller 	pr_err("CPU[%d]: CWQ gethead[%lx] hv_ret[%lu]\n",
1260a625fd2SDavid S. Miller 	       smp_processor_id(), new_head, hv_ret);
1270a625fd2SDavid S. Miller 
1280a625fd2SDavid S. Miller 	for (off = q->head; off != new_head; off = spu_next_offset(q, off)) {
1290a625fd2SDavid S. Miller 		/* XXX ... XXX */
1300a625fd2SDavid S. Miller 	}
1310a625fd2SDavid S. Miller 
1320a625fd2SDavid S. Miller 	hv_ret = sun4v_ncs_sethead_marker(q->qhandle, new_head);
1330a625fd2SDavid S. Miller 	if (hv_ret == HV_EOK)
1340a625fd2SDavid S. Miller 		q->head = new_head;
1350a625fd2SDavid S. Miller 
1360a625fd2SDavid S. Miller 	spin_unlock(&q->lock);
1370a625fd2SDavid S. Miller 
1380a625fd2SDavid S. Miller 	return IRQ_HANDLED;
1390a625fd2SDavid S. Miller }
1400a625fd2SDavid S. Miller 
1410a625fd2SDavid S. Miller static irqreturn_t mau_intr(int irq, void *dev_id)
1420a625fd2SDavid S. Miller {
1430a625fd2SDavid S. Miller 	struct spu_queue *q = dev_id;
1440a625fd2SDavid S. Miller 	unsigned long head, hv_ret;
1450a625fd2SDavid S. Miller 
1460a625fd2SDavid S. Miller 	spin_lock(&q->lock);
1470a625fd2SDavid S. Miller 
1480a625fd2SDavid S. Miller 	pr_err("CPU[%d]: Got MAU interrupt for qhdl[%lx]\n",
1490a625fd2SDavid S. Miller 	       smp_processor_id(), q->qhandle);
1500a625fd2SDavid S. Miller 
1510a625fd2SDavid S. Miller 	hv_ret = sun4v_ncs_gethead(q->qhandle, &head);
1520a625fd2SDavid S. Miller 
1530a625fd2SDavid S. Miller 	pr_err("CPU[%d]: MAU gethead[%lx] hv_ret[%lu]\n",
1540a625fd2SDavid S. Miller 	       smp_processor_id(), head, hv_ret);
1550a625fd2SDavid S. Miller 
1560a625fd2SDavid S. Miller 	sun4v_ncs_sethead_marker(q->qhandle, head);
1570a625fd2SDavid S. Miller 
1580a625fd2SDavid S. Miller 	spin_unlock(&q->lock);
1590a625fd2SDavid S. Miller 
1600a625fd2SDavid S. Miller 	return IRQ_HANDLED;
1610a625fd2SDavid S. Miller }
1620a625fd2SDavid S. Miller 
1630a625fd2SDavid S. Miller static void *spu_queue_next(struct spu_queue *q, void *cur)
1640a625fd2SDavid S. Miller {
1650a625fd2SDavid S. Miller 	return q->q + spu_next_offset(q, cur - q->q);
1660a625fd2SDavid S. Miller }
1670a625fd2SDavid S. Miller 
1680a625fd2SDavid S. Miller static int spu_queue_num_free(struct spu_queue *q)
1690a625fd2SDavid S. Miller {
1700a625fd2SDavid S. Miller 	unsigned long head = q->head;
1710a625fd2SDavid S. Miller 	unsigned long tail = q->tail;
1720a625fd2SDavid S. Miller 	unsigned long end = (CWQ_ENTRY_SIZE * CWQ_NUM_ENTRIES);
1730a625fd2SDavid S. Miller 	unsigned long diff;
1740a625fd2SDavid S. Miller 
1750a625fd2SDavid S. Miller 	if (head > tail)
1760a625fd2SDavid S. Miller 		diff = head - tail;
1770a625fd2SDavid S. Miller 	else
1780a625fd2SDavid S. Miller 		diff = (end - tail) + head;
1790a625fd2SDavid S. Miller 
1800a625fd2SDavid S. Miller 	return (diff / CWQ_ENTRY_SIZE) - 1;
1810a625fd2SDavid S. Miller }
1820a625fd2SDavid S. Miller 
1830a625fd2SDavid S. Miller static void *spu_queue_alloc(struct spu_queue *q, int num_entries)
1840a625fd2SDavid S. Miller {
1850a625fd2SDavid S. Miller 	int avail = spu_queue_num_free(q);
1860a625fd2SDavid S. Miller 
1870a625fd2SDavid S. Miller 	if (avail >= num_entries)
1880a625fd2SDavid S. Miller 		return q->q + q->tail;
1890a625fd2SDavid S. Miller 
1900a625fd2SDavid S. Miller 	return NULL;
1910a625fd2SDavid S. Miller }
1920a625fd2SDavid S. Miller 
1930a625fd2SDavid S. Miller static unsigned long spu_queue_submit(struct spu_queue *q, void *last)
1940a625fd2SDavid S. Miller {
1950a625fd2SDavid S. Miller 	unsigned long hv_ret, new_tail;
1960a625fd2SDavid S. Miller 
1970a625fd2SDavid S. Miller 	new_tail = spu_next_offset(q, last - q->q);
1980a625fd2SDavid S. Miller 
1990a625fd2SDavid S. Miller 	hv_ret = sun4v_ncs_settail(q->qhandle, new_tail);
2000a625fd2SDavid S. Miller 	if (hv_ret == HV_EOK)
2010a625fd2SDavid S. Miller 		q->tail = new_tail;
2020a625fd2SDavid S. Miller 	return hv_ret;
2030a625fd2SDavid S. Miller }
2040a625fd2SDavid S. Miller 
2050a625fd2SDavid S. Miller static u64 control_word_base(unsigned int len, unsigned int hmac_key_len,
2060a625fd2SDavid S. Miller 			     int enc_type, int auth_type,
2070a625fd2SDavid S. Miller 			     unsigned int hash_len,
2080a625fd2SDavid S. Miller 			     bool sfas, bool sob, bool eob, bool encrypt,
2090a625fd2SDavid S. Miller 			     int opcode)
2100a625fd2SDavid S. Miller {
2110a625fd2SDavid S. Miller 	u64 word = (len - 1) & CONTROL_LEN;
2120a625fd2SDavid S. Miller 
2130a625fd2SDavid S. Miller 	word |= ((u64) opcode << CONTROL_OPCODE_SHIFT);
2140a625fd2SDavid S. Miller 	word |= ((u64) enc_type << CONTROL_ENC_TYPE_SHIFT);
2150a625fd2SDavid S. Miller 	word |= ((u64) auth_type << CONTROL_AUTH_TYPE_SHIFT);
2160a625fd2SDavid S. Miller 	if (sfas)
2170a625fd2SDavid S. Miller 		word |= CONTROL_STORE_FINAL_AUTH_STATE;
2180a625fd2SDavid S. Miller 	if (sob)
2190a625fd2SDavid S. Miller 		word |= CONTROL_START_OF_BLOCK;
2200a625fd2SDavid S. Miller 	if (eob)
2210a625fd2SDavid S. Miller 		word |= CONTROL_END_OF_BLOCK;
2220a625fd2SDavid S. Miller 	if (encrypt)
2230a625fd2SDavid S. Miller 		word |= CONTROL_ENCRYPT;
2240a625fd2SDavid S. Miller 	if (hmac_key_len)
2250a625fd2SDavid S. Miller 		word |= ((u64) (hmac_key_len - 1)) << CONTROL_HMAC_KEY_LEN_SHIFT;
2260a625fd2SDavid S. Miller 	if (hash_len)
2270a625fd2SDavid S. Miller 		word |= ((u64) (hash_len - 1)) << CONTROL_HASH_LEN_SHIFT;
2280a625fd2SDavid S. Miller 
2290a625fd2SDavid S. Miller 	return word;
2300a625fd2SDavid S. Miller }
2310a625fd2SDavid S. Miller 
2320a625fd2SDavid S. Miller #if 0
2330a625fd2SDavid S. Miller static inline bool n2_should_run_async(struct spu_queue *qp, int this_len)
2340a625fd2SDavid S. Miller {
2350a625fd2SDavid S. Miller 	if (this_len >= 64 ||
2360a625fd2SDavid S. Miller 	    qp->head != qp->tail)
2370a625fd2SDavid S. Miller 		return true;
2380a625fd2SDavid S. Miller 	return false;
2390a625fd2SDavid S. Miller }
2400a625fd2SDavid S. Miller #endif
2410a625fd2SDavid S. Miller 
2420a625fd2SDavid S. Miller struct n2_hash_ctx {
243c9aa55e5SDavid S. Miller 	struct crypto_ahash		*fallback_tfm;
244c9aa55e5SDavid S. Miller };
2450a625fd2SDavid S. Miller 
246c9aa55e5SDavid S. Miller struct n2_hash_req_ctx {
2470a625fd2SDavid S. Miller 	union {
2480a625fd2SDavid S. Miller 		struct md5_state	md5;
2490a625fd2SDavid S. Miller 		struct sha1_state	sha1;
2500a625fd2SDavid S. Miller 		struct sha256_state	sha256;
2510a625fd2SDavid S. Miller 	} u;
2520a625fd2SDavid S. Miller 
2530a625fd2SDavid S. Miller 	unsigned char			hash_key[64];
2540a625fd2SDavid S. Miller 	unsigned char			keyed_zero_hash[32];
255c9aa55e5SDavid S. Miller 
256c9aa55e5SDavid S. Miller 	struct ahash_request		fallback_req;
2570a625fd2SDavid S. Miller };
2580a625fd2SDavid S. Miller 
2590a625fd2SDavid S. Miller static int n2_hash_async_init(struct ahash_request *req)
2600a625fd2SDavid S. Miller {
261c9aa55e5SDavid S. Miller 	struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
2620a625fd2SDavid S. Miller 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
2630a625fd2SDavid S. Miller 	struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
2640a625fd2SDavid S. Miller 
265c9aa55e5SDavid S. Miller 	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
266c9aa55e5SDavid S. Miller 	rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
2670a625fd2SDavid S. Miller 
268c9aa55e5SDavid S. Miller 	return crypto_ahash_init(&rctx->fallback_req);
2690a625fd2SDavid S. Miller }
2700a625fd2SDavid S. Miller 
2710a625fd2SDavid S. Miller static int n2_hash_async_update(struct ahash_request *req)
2720a625fd2SDavid S. Miller {
273c9aa55e5SDavid S. Miller 	struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
2740a625fd2SDavid S. Miller 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
2750a625fd2SDavid S. Miller 	struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
2760a625fd2SDavid S. Miller 
277c9aa55e5SDavid S. Miller 	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
278c9aa55e5SDavid S. Miller 	rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
279c9aa55e5SDavid S. Miller 	rctx->fallback_req.nbytes = req->nbytes;
280c9aa55e5SDavid S. Miller 	rctx->fallback_req.src = req->src;
2810a625fd2SDavid S. Miller 
282c9aa55e5SDavid S. Miller 	return crypto_ahash_update(&rctx->fallback_req);
2830a625fd2SDavid S. Miller }
2840a625fd2SDavid S. Miller 
2850a625fd2SDavid S. Miller static int n2_hash_async_final(struct ahash_request *req)
2860a625fd2SDavid S. Miller {
287c9aa55e5SDavid S. Miller 	struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
2880a625fd2SDavid S. Miller 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
2890a625fd2SDavid S. Miller 	struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
2900a625fd2SDavid S. Miller 
291c9aa55e5SDavid S. Miller 	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
292c9aa55e5SDavid S. Miller 	rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
293c9aa55e5SDavid S. Miller 	rctx->fallback_req.result = req->result;
2940a625fd2SDavid S. Miller 
295c9aa55e5SDavid S. Miller 	return crypto_ahash_final(&rctx->fallback_req);
2960a625fd2SDavid S. Miller }
2970a625fd2SDavid S. Miller 
2980a625fd2SDavid S. Miller static int n2_hash_async_finup(struct ahash_request *req)
2990a625fd2SDavid S. Miller {
300c9aa55e5SDavid S. Miller 	struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
3010a625fd2SDavid S. Miller 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
3020a625fd2SDavid S. Miller 	struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
3030a625fd2SDavid S. Miller 
304c9aa55e5SDavid S. Miller 	ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
305c9aa55e5SDavid S. Miller 	rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
306c9aa55e5SDavid S. Miller 	rctx->fallback_req.nbytes = req->nbytes;
307c9aa55e5SDavid S. Miller 	rctx->fallback_req.src = req->src;
308c9aa55e5SDavid S. Miller 	rctx->fallback_req.result = req->result;
3090a625fd2SDavid S. Miller 
310c9aa55e5SDavid S. Miller 	return crypto_ahash_finup(&rctx->fallback_req);
3110a625fd2SDavid S. Miller }
3120a625fd2SDavid S. Miller 
3130a625fd2SDavid S. Miller static int n2_hash_cra_init(struct crypto_tfm *tfm)
3140a625fd2SDavid S. Miller {
3150a625fd2SDavid S. Miller 	const char *fallback_driver_name = tfm->__crt_alg->cra_name;
3160a625fd2SDavid S. Miller 	struct crypto_ahash *ahash = __crypto_ahash_cast(tfm);
3170a625fd2SDavid S. Miller 	struct n2_hash_ctx *ctx = crypto_ahash_ctx(ahash);
3180a625fd2SDavid S. Miller 	struct crypto_ahash *fallback_tfm;
3190a625fd2SDavid S. Miller 	int err;
3200a625fd2SDavid S. Miller 
3210a625fd2SDavid S. Miller 	fallback_tfm = crypto_alloc_ahash(fallback_driver_name, 0,
3220a625fd2SDavid S. Miller 					  CRYPTO_ALG_NEED_FALLBACK);
3230a625fd2SDavid S. Miller 	if (IS_ERR(fallback_tfm)) {
3240a625fd2SDavid S. Miller 		pr_warning("Fallback driver '%s' could not be loaded!\n",
3250a625fd2SDavid S. Miller 			   fallback_driver_name);
3260a625fd2SDavid S. Miller 		err = PTR_ERR(fallback_tfm);
3270a625fd2SDavid S. Miller 		goto out;
3280a625fd2SDavid S. Miller 	}
3290a625fd2SDavid S. Miller 
330c9aa55e5SDavid S. Miller 	crypto_ahash_set_reqsize(ahash, (sizeof(struct n2_hash_req_ctx) +
331c9aa55e5SDavid S. Miller 					 crypto_ahash_reqsize(fallback_tfm)));
332c9aa55e5SDavid S. Miller 
333c9aa55e5SDavid S. Miller 	ctx->fallback_tfm = fallback_tfm;
3340a625fd2SDavid S. Miller 	return 0;
3350a625fd2SDavid S. Miller 
3360a625fd2SDavid S. Miller out:
3370a625fd2SDavid S. Miller 	return err;
3380a625fd2SDavid S. Miller }
3390a625fd2SDavid S. Miller 
3400a625fd2SDavid S. Miller static void n2_hash_cra_exit(struct crypto_tfm *tfm)
3410a625fd2SDavid S. Miller {
3420a625fd2SDavid S. Miller 	struct crypto_ahash *ahash = __crypto_ahash_cast(tfm);
3430a625fd2SDavid S. Miller 	struct n2_hash_ctx *ctx = crypto_ahash_ctx(ahash);
3440a625fd2SDavid S. Miller 
345c9aa55e5SDavid S. Miller 	crypto_free_ahash(ctx->fallback_tfm);
3460a625fd2SDavid S. Miller }
3470a625fd2SDavid S. Miller 
3480a625fd2SDavid S. Miller static unsigned long wait_for_tail(struct spu_queue *qp)
3490a625fd2SDavid S. Miller {
3500a625fd2SDavid S. Miller 	unsigned long head, hv_ret;
3510a625fd2SDavid S. Miller 
3520a625fd2SDavid S. Miller 	do {
3530a625fd2SDavid S. Miller 		hv_ret = sun4v_ncs_gethead(qp->qhandle, &head);
3540a625fd2SDavid S. Miller 		if (hv_ret != HV_EOK) {
3550a625fd2SDavid S. Miller 			pr_err("Hypervisor error on gethead\n");
3560a625fd2SDavid S. Miller 			break;
3570a625fd2SDavid S. Miller 		}
3580a625fd2SDavid S. Miller 		if (head == qp->tail) {
3590a625fd2SDavid S. Miller 			qp->head = head;
3600a625fd2SDavid S. Miller 			break;
3610a625fd2SDavid S. Miller 		}
3620a625fd2SDavid S. Miller 	} while (1);
3630a625fd2SDavid S. Miller 	return hv_ret;
3640a625fd2SDavid S. Miller }
3650a625fd2SDavid S. Miller 
3660a625fd2SDavid S. Miller static unsigned long submit_and_wait_for_tail(struct spu_queue *qp,
3670a625fd2SDavid S. Miller 					      struct cwq_initial_entry *ent)
3680a625fd2SDavid S. Miller {
3690a625fd2SDavid S. Miller 	unsigned long hv_ret = spu_queue_submit(qp, ent);
3700a625fd2SDavid S. Miller 
3710a625fd2SDavid S. Miller 	if (hv_ret == HV_EOK)
3720a625fd2SDavid S. Miller 		hv_ret = wait_for_tail(qp);
3730a625fd2SDavid S. Miller 
3740a625fd2SDavid S. Miller 	return hv_ret;
3750a625fd2SDavid S. Miller }
3760a625fd2SDavid S. Miller 
3770a625fd2SDavid S. Miller static int n2_hash_async_digest(struct ahash_request *req,
3780a625fd2SDavid S. Miller 				unsigned int auth_type, unsigned int digest_size,
3790a625fd2SDavid S. Miller 				unsigned int result_size, void *hash_loc)
3800a625fd2SDavid S. Miller {
3810a625fd2SDavid S. Miller 	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
3820a625fd2SDavid S. Miller 	struct cwq_initial_entry *ent;
3830a625fd2SDavid S. Miller 	struct crypto_hash_walk walk;
3840a625fd2SDavid S. Miller 	struct spu_queue *qp;
3850a625fd2SDavid S. Miller 	unsigned long flags;
3860a625fd2SDavid S. Miller 	int err = -ENODEV;
3870a625fd2SDavid S. Miller 	int nbytes, cpu;
3880a625fd2SDavid S. Miller 
3890a625fd2SDavid S. Miller 	/* The total effective length of the operation may not
3900a625fd2SDavid S. Miller 	 * exceed 2^16.
3910a625fd2SDavid S. Miller 	 */
3920a625fd2SDavid S. Miller 	if (unlikely(req->nbytes > (1 << 16))) {
393c9aa55e5SDavid S. Miller 		struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
39465a23d67SDavid S. Miller 		struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
3950a625fd2SDavid S. Miller 
396c9aa55e5SDavid S. Miller 		ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
397c9aa55e5SDavid S. Miller 		rctx->fallback_req.base.flags =
398c9aa55e5SDavid S. Miller 			req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
399c9aa55e5SDavid S. Miller 		rctx->fallback_req.nbytes = req->nbytes;
400c9aa55e5SDavid S. Miller 		rctx->fallback_req.src = req->src;
401c9aa55e5SDavid S. Miller 		rctx->fallback_req.result = req->result;
402c9aa55e5SDavid S. Miller 
403c9aa55e5SDavid S. Miller 		return crypto_ahash_digest(&rctx->fallback_req);
4040a625fd2SDavid S. Miller 	}
4050a625fd2SDavid S. Miller 
4060a625fd2SDavid S. Miller 	nbytes = crypto_hash_walk_first(req, &walk);
4070a625fd2SDavid S. Miller 
4080a625fd2SDavid S. Miller 	cpu = get_cpu();
4090a625fd2SDavid S. Miller 	qp = cpu_to_cwq[cpu];
4100a625fd2SDavid S. Miller 	if (!qp)
4110a625fd2SDavid S. Miller 		goto out;
4120a625fd2SDavid S. Miller 
4130a625fd2SDavid S. Miller 	spin_lock_irqsave(&qp->lock, flags);
4140a625fd2SDavid S. Miller 
4150a625fd2SDavid S. Miller 	/* XXX can do better, improve this later by doing a by-hand scatterlist
4160a625fd2SDavid S. Miller 	 * XXX walk, etc.
4170a625fd2SDavid S. Miller 	 */
4180a625fd2SDavid S. Miller 	ent = qp->q + qp->tail;
4190a625fd2SDavid S. Miller 
4200a625fd2SDavid S. Miller 	ent->control = control_word_base(nbytes, 0, 0,
4210a625fd2SDavid S. Miller 					 auth_type, digest_size,
4220a625fd2SDavid S. Miller 					 false, true, false, false,
4230a625fd2SDavid S. Miller 					 OPCODE_INPLACE_BIT |
4240a625fd2SDavid S. Miller 					 OPCODE_AUTH_MAC);
4250a625fd2SDavid S. Miller 	ent->src_addr = __pa(walk.data);
4260a625fd2SDavid S. Miller 	ent->auth_key_addr = 0UL;
4270a625fd2SDavid S. Miller 	ent->auth_iv_addr = __pa(hash_loc);
4280a625fd2SDavid S. Miller 	ent->final_auth_state_addr = 0UL;
4290a625fd2SDavid S. Miller 	ent->enc_key_addr = 0UL;
4300a625fd2SDavid S. Miller 	ent->enc_iv_addr = 0UL;
4310a625fd2SDavid S. Miller 	ent->dest_addr = __pa(hash_loc);
4320a625fd2SDavid S. Miller 
4330a625fd2SDavid S. Miller 	nbytes = crypto_hash_walk_done(&walk, 0);
4340a625fd2SDavid S. Miller 	while (nbytes > 0) {
4350a625fd2SDavid S. Miller 		ent = spu_queue_next(qp, ent);
4360a625fd2SDavid S. Miller 
4370a625fd2SDavid S. Miller 		ent->control = (nbytes - 1);
4380a625fd2SDavid S. Miller 		ent->src_addr = __pa(walk.data);
4390a625fd2SDavid S. Miller 		ent->auth_key_addr = 0UL;
4400a625fd2SDavid S. Miller 		ent->auth_iv_addr = 0UL;
4410a625fd2SDavid S. Miller 		ent->final_auth_state_addr = 0UL;
4420a625fd2SDavid S. Miller 		ent->enc_key_addr = 0UL;
4430a625fd2SDavid S. Miller 		ent->enc_iv_addr = 0UL;
4440a625fd2SDavid S. Miller 		ent->dest_addr = 0UL;
4450a625fd2SDavid S. Miller 
4460a625fd2SDavid S. Miller 		nbytes = crypto_hash_walk_done(&walk, 0);
4470a625fd2SDavid S. Miller 	}
4480a625fd2SDavid S. Miller 	ent->control |= CONTROL_END_OF_BLOCK;
4490a625fd2SDavid S. Miller 
4500a625fd2SDavid S. Miller 	if (submit_and_wait_for_tail(qp, ent) != HV_EOK)
4510a625fd2SDavid S. Miller 		err = -EINVAL;
4520a625fd2SDavid S. Miller 	else
4530a625fd2SDavid S. Miller 		err = 0;
4540a625fd2SDavid S. Miller 
4550a625fd2SDavid S. Miller 	spin_unlock_irqrestore(&qp->lock, flags);
4560a625fd2SDavid S. Miller 
4570a625fd2SDavid S. Miller 	if (!err)
4580a625fd2SDavid S. Miller 		memcpy(req->result, hash_loc, result_size);
4590a625fd2SDavid S. Miller out:
4600a625fd2SDavid S. Miller 	put_cpu();
4610a625fd2SDavid S. Miller 
4620a625fd2SDavid S. Miller 	return err;
4630a625fd2SDavid S. Miller }
4640a625fd2SDavid S. Miller 
4650a625fd2SDavid S. Miller static int n2_md5_async_digest(struct ahash_request *req)
4660a625fd2SDavid S. Miller {
467c9aa55e5SDavid S. Miller 	struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
468c9aa55e5SDavid S. Miller 	struct md5_state *m = &rctx->u.md5;
4690a625fd2SDavid S. Miller 
4700a625fd2SDavid S. Miller 	if (unlikely(req->nbytes == 0)) {
4710a625fd2SDavid S. Miller 		static const char md5_zero[MD5_DIGEST_SIZE] = {
4720a625fd2SDavid S. Miller 			0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
4730a625fd2SDavid S. Miller 			0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e,
4740a625fd2SDavid S. Miller 		};
4750a625fd2SDavid S. Miller 
4760a625fd2SDavid S. Miller 		memcpy(req->result, md5_zero, MD5_DIGEST_SIZE);
4770a625fd2SDavid S. Miller 		return 0;
4780a625fd2SDavid S. Miller 	}
4790a625fd2SDavid S. Miller 	m->hash[0] = cpu_to_le32(0x67452301);
4800a625fd2SDavid S. Miller 	m->hash[1] = cpu_to_le32(0xefcdab89);
4810a625fd2SDavid S. Miller 	m->hash[2] = cpu_to_le32(0x98badcfe);
4820a625fd2SDavid S. Miller 	m->hash[3] = cpu_to_le32(0x10325476);
4830a625fd2SDavid S. Miller 
4840a625fd2SDavid S. Miller 	return n2_hash_async_digest(req, AUTH_TYPE_MD5,
4850a625fd2SDavid S. Miller 				    MD5_DIGEST_SIZE, MD5_DIGEST_SIZE,
4860a625fd2SDavid S. Miller 				    m->hash);
4870a625fd2SDavid S. Miller }
4880a625fd2SDavid S. Miller 
4890a625fd2SDavid S. Miller static int n2_sha1_async_digest(struct ahash_request *req)
4900a625fd2SDavid S. Miller {
491c9aa55e5SDavid S. Miller 	struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
492c9aa55e5SDavid S. Miller 	struct sha1_state *s = &rctx->u.sha1;
4930a625fd2SDavid S. Miller 
4940a625fd2SDavid S. Miller 	if (unlikely(req->nbytes == 0)) {
4950a625fd2SDavid S. Miller 		static const char sha1_zero[SHA1_DIGEST_SIZE] = {
4960a625fd2SDavid S. Miller 			0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32,
4970a625fd2SDavid S. Miller 			0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8,
4980a625fd2SDavid S. Miller 			0x07, 0x09
4990a625fd2SDavid S. Miller 		};
5000a625fd2SDavid S. Miller 
5010a625fd2SDavid S. Miller 		memcpy(req->result, sha1_zero, SHA1_DIGEST_SIZE);
5020a625fd2SDavid S. Miller 		return 0;
5030a625fd2SDavid S. Miller 	}
5040a625fd2SDavid S. Miller 	s->state[0] = SHA1_H0;
5050a625fd2SDavid S. Miller 	s->state[1] = SHA1_H1;
5060a625fd2SDavid S. Miller 	s->state[2] = SHA1_H2;
5070a625fd2SDavid S. Miller 	s->state[3] = SHA1_H3;
5080a625fd2SDavid S. Miller 	s->state[4] = SHA1_H4;
5090a625fd2SDavid S. Miller 
5100a625fd2SDavid S. Miller 	return n2_hash_async_digest(req, AUTH_TYPE_SHA1,
5110a625fd2SDavid S. Miller 				    SHA1_DIGEST_SIZE, SHA1_DIGEST_SIZE,
5120a625fd2SDavid S. Miller 				    s->state);
5130a625fd2SDavid S. Miller }
5140a625fd2SDavid S. Miller 
5150a625fd2SDavid S. Miller static int n2_sha256_async_digest(struct ahash_request *req)
5160a625fd2SDavid S. Miller {
517c9aa55e5SDavid S. Miller 	struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
518c9aa55e5SDavid S. Miller 	struct sha256_state *s = &rctx->u.sha256;
5190a625fd2SDavid S. Miller 
5200a625fd2SDavid S. Miller 	if (req->nbytes == 0) {
5210a625fd2SDavid S. Miller 		static const char sha256_zero[SHA256_DIGEST_SIZE] = {
5220a625fd2SDavid S. Miller 			0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a,
5230a625fd2SDavid S. Miller 			0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae,
5240a625fd2SDavid S. Miller 			0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99,
5250a625fd2SDavid S. Miller 			0x1b, 0x78, 0x52, 0xb8, 0x55
5260a625fd2SDavid S. Miller 		};
5270a625fd2SDavid S. Miller 
5280a625fd2SDavid S. Miller 		memcpy(req->result, sha256_zero, SHA256_DIGEST_SIZE);
5290a625fd2SDavid S. Miller 		return 0;
5300a625fd2SDavid S. Miller 	}
5310a625fd2SDavid S. Miller 	s->state[0] = SHA256_H0;
5320a625fd2SDavid S. Miller 	s->state[1] = SHA256_H1;
5330a625fd2SDavid S. Miller 	s->state[2] = SHA256_H2;
5340a625fd2SDavid S. Miller 	s->state[3] = SHA256_H3;
5350a625fd2SDavid S. Miller 	s->state[4] = SHA256_H4;
5360a625fd2SDavid S. Miller 	s->state[5] = SHA256_H5;
5370a625fd2SDavid S. Miller 	s->state[6] = SHA256_H6;
5380a625fd2SDavid S. Miller 	s->state[7] = SHA256_H7;
5390a625fd2SDavid S. Miller 
5400a625fd2SDavid S. Miller 	return n2_hash_async_digest(req, AUTH_TYPE_SHA256,
5410a625fd2SDavid S. Miller 				    SHA256_DIGEST_SIZE, SHA256_DIGEST_SIZE,
5420a625fd2SDavid S. Miller 				    s->state);
5430a625fd2SDavid S. Miller }
5440a625fd2SDavid S. Miller 
5450a625fd2SDavid S. Miller static int n2_sha224_async_digest(struct ahash_request *req)
5460a625fd2SDavid S. Miller {
547c9aa55e5SDavid S. Miller 	struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
548c9aa55e5SDavid S. Miller 	struct sha256_state *s = &rctx->u.sha256;
5490a625fd2SDavid S. Miller 
5500a625fd2SDavid S. Miller 	if (req->nbytes == 0) {
5510a625fd2SDavid S. Miller 		static const char sha224_zero[SHA224_DIGEST_SIZE] = {
5520a625fd2SDavid S. Miller 			0xd1, 0x4a, 0x02, 0x8c, 0x2a, 0x3a, 0x2b, 0xc9, 0x47,
5530a625fd2SDavid S. Miller 			0x61, 0x02, 0xbb, 0x28, 0x82, 0x34, 0xc4, 0x15, 0xa2,
5540a625fd2SDavid S. Miller 			0xb0, 0x1f, 0x82, 0x8e, 0xa6, 0x2a, 0xc5, 0xb3, 0xe4,
5550a625fd2SDavid S. Miller 			0x2f
5560a625fd2SDavid S. Miller 		};
5570a625fd2SDavid S. Miller 
5580a625fd2SDavid S. Miller 		memcpy(req->result, sha224_zero, SHA224_DIGEST_SIZE);
5590a625fd2SDavid S. Miller 		return 0;
5600a625fd2SDavid S. Miller 	}
5610a625fd2SDavid S. Miller 	s->state[0] = SHA224_H0;
5620a625fd2SDavid S. Miller 	s->state[1] = SHA224_H1;
5630a625fd2SDavid S. Miller 	s->state[2] = SHA224_H2;
5640a625fd2SDavid S. Miller 	s->state[3] = SHA224_H3;
5650a625fd2SDavid S. Miller 	s->state[4] = SHA224_H4;
5660a625fd2SDavid S. Miller 	s->state[5] = SHA224_H5;
5670a625fd2SDavid S. Miller 	s->state[6] = SHA224_H6;
5680a625fd2SDavid S. Miller 	s->state[7] = SHA224_H7;
5690a625fd2SDavid S. Miller 
5700a625fd2SDavid S. Miller 	return n2_hash_async_digest(req, AUTH_TYPE_SHA256,
5710a625fd2SDavid S. Miller 				    SHA256_DIGEST_SIZE, SHA224_DIGEST_SIZE,
5720a625fd2SDavid S. Miller 				    s->state);
5730a625fd2SDavid S. Miller }
5740a625fd2SDavid S. Miller 
5750a625fd2SDavid S. Miller struct n2_cipher_context {
5760a625fd2SDavid S. Miller 	int			key_len;
5770a625fd2SDavid S. Miller 	int			enc_type;
5780a625fd2SDavid S. Miller 	union {
5790a625fd2SDavid S. Miller 		u8		aes[AES_MAX_KEY_SIZE];
5800a625fd2SDavid S. Miller 		u8		des[DES_KEY_SIZE];
5810a625fd2SDavid S. Miller 		u8		des3[3 * DES_KEY_SIZE];
5820a625fd2SDavid S. Miller 		u8		arc4[258]; /* S-box, X, Y */
5830a625fd2SDavid S. Miller 	} key;
5840a625fd2SDavid S. Miller };
5850a625fd2SDavid S. Miller 
5860a625fd2SDavid S. Miller #define N2_CHUNK_ARR_LEN	16
5870a625fd2SDavid S. Miller 
5880a625fd2SDavid S. Miller struct n2_crypto_chunk {
5890a625fd2SDavid S. Miller 	struct list_head	entry;
5900a625fd2SDavid S. Miller 	unsigned long		iv_paddr : 44;
5910a625fd2SDavid S. Miller 	unsigned long		arr_len : 20;
5920a625fd2SDavid S. Miller 	unsigned long		dest_paddr;
5930a625fd2SDavid S. Miller 	unsigned long		dest_final;
5940a625fd2SDavid S. Miller 	struct {
5950a625fd2SDavid S. Miller 		unsigned long	src_paddr : 44;
5960a625fd2SDavid S. Miller 		unsigned long	src_len : 20;
5970a625fd2SDavid S. Miller 	} arr[N2_CHUNK_ARR_LEN];
5980a625fd2SDavid S. Miller };
5990a625fd2SDavid S. Miller 
6000a625fd2SDavid S. Miller struct n2_request_context {
6010a625fd2SDavid S. Miller 	struct ablkcipher_walk	walk;
6020a625fd2SDavid S. Miller 	struct list_head	chunk_list;
6030a625fd2SDavid S. Miller 	struct n2_crypto_chunk	chunk;
6040a625fd2SDavid S. Miller 	u8			temp_iv[16];
6050a625fd2SDavid S. Miller };
6060a625fd2SDavid S. Miller 
6070a625fd2SDavid S. Miller /* The SPU allows some level of flexibility for partial cipher blocks
6080a625fd2SDavid S. Miller  * being specified in a descriptor.
6090a625fd2SDavid S. Miller  *
6100a625fd2SDavid S. Miller  * It merely requires that every descriptor's length field is at least
6110a625fd2SDavid S. Miller  * as large as the cipher block size.  This means that a cipher block
6120a625fd2SDavid S. Miller  * can span at most 2 descriptors.  However, this does not allow a
6130a625fd2SDavid S. Miller  * partial block to span into the final descriptor as that would
6140a625fd2SDavid S. Miller  * violate the rule (since every descriptor's length must be at lest
6150a625fd2SDavid S. Miller  * the block size).  So, for example, assuming an 8 byte block size:
6160a625fd2SDavid S. Miller  *
6170a625fd2SDavid S. Miller  *	0xe --> 0xa --> 0x8
6180a625fd2SDavid S. Miller  *
6190a625fd2SDavid S. Miller  * is a valid length sequence, whereas:
6200a625fd2SDavid S. Miller  *
6210a625fd2SDavid S. Miller  *	0xe --> 0xb --> 0x7
6220a625fd2SDavid S. Miller  *
6230a625fd2SDavid S. Miller  * is not a valid sequence.
6240a625fd2SDavid S. Miller  */
6250a625fd2SDavid S. Miller 
6260a625fd2SDavid S. Miller struct n2_cipher_alg {
6270a625fd2SDavid S. Miller 	struct list_head	entry;
6280a625fd2SDavid S. Miller 	u8			enc_type;
6290a625fd2SDavid S. Miller 	struct crypto_alg	alg;
6300a625fd2SDavid S. Miller };
6310a625fd2SDavid S. Miller 
6320a625fd2SDavid S. Miller static inline struct n2_cipher_alg *n2_cipher_alg(struct crypto_tfm *tfm)
6330a625fd2SDavid S. Miller {
6340a625fd2SDavid S. Miller 	struct crypto_alg *alg = tfm->__crt_alg;
6350a625fd2SDavid S. Miller 
6360a625fd2SDavid S. Miller 	return container_of(alg, struct n2_cipher_alg, alg);
6370a625fd2SDavid S. Miller }
6380a625fd2SDavid S. Miller 
6390a625fd2SDavid S. Miller struct n2_cipher_request_context {
6400a625fd2SDavid S. Miller 	struct ablkcipher_walk	walk;
6410a625fd2SDavid S. Miller };
6420a625fd2SDavid S. Miller 
6430a625fd2SDavid S. Miller static int n2_aes_setkey(struct crypto_ablkcipher *cipher, const u8 *key,
6440a625fd2SDavid S. Miller 			 unsigned int keylen)
6450a625fd2SDavid S. Miller {
6460a625fd2SDavid S. Miller 	struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
6470a625fd2SDavid S. Miller 	struct n2_cipher_context *ctx = crypto_tfm_ctx(tfm);
6480a625fd2SDavid S. Miller 	struct n2_cipher_alg *n2alg = n2_cipher_alg(tfm);
6490a625fd2SDavid S. Miller 
6500a625fd2SDavid S. Miller 	ctx->enc_type = (n2alg->enc_type & ENC_TYPE_CHAINING_MASK);
6510a625fd2SDavid S. Miller 
6520a625fd2SDavid S. Miller 	switch (keylen) {
6530a625fd2SDavid S. Miller 	case AES_KEYSIZE_128:
6540a625fd2SDavid S. Miller 		ctx->enc_type |= ENC_TYPE_ALG_AES128;
6550a625fd2SDavid S. Miller 		break;
6560a625fd2SDavid S. Miller 	case AES_KEYSIZE_192:
6570a625fd2SDavid S. Miller 		ctx->enc_type |= ENC_TYPE_ALG_AES192;
6580a625fd2SDavid S. Miller 		break;
6590a625fd2SDavid S. Miller 	case AES_KEYSIZE_256:
6600a625fd2SDavid S. Miller 		ctx->enc_type |= ENC_TYPE_ALG_AES256;
6610a625fd2SDavid S. Miller 		break;
6620a625fd2SDavid S. Miller 	default:
6630a625fd2SDavid S. Miller 		crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
6640a625fd2SDavid S. Miller 		return -EINVAL;
6650a625fd2SDavid S. Miller 	}
6660a625fd2SDavid S. Miller 
6670a625fd2SDavid S. Miller 	ctx->key_len = keylen;
6680a625fd2SDavid S. Miller 	memcpy(ctx->key.aes, key, keylen);
6690a625fd2SDavid S. Miller 	return 0;
6700a625fd2SDavid S. Miller }
6710a625fd2SDavid S. Miller 
6720a625fd2SDavid S. Miller static int n2_des_setkey(struct crypto_ablkcipher *cipher, const u8 *key,
6730a625fd2SDavid S. Miller 			 unsigned int keylen)
6740a625fd2SDavid S. Miller {
6750a625fd2SDavid S. Miller 	struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
6760a625fd2SDavid S. Miller 	struct n2_cipher_context *ctx = crypto_tfm_ctx(tfm);
6770a625fd2SDavid S. Miller 	struct n2_cipher_alg *n2alg = n2_cipher_alg(tfm);
6780a625fd2SDavid S. Miller 	u32 tmp[DES_EXPKEY_WORDS];
6790a625fd2SDavid S. Miller 	int err;
6800a625fd2SDavid S. Miller 
6810a625fd2SDavid S. Miller 	ctx->enc_type = n2alg->enc_type;
6820a625fd2SDavid S. Miller 
6830a625fd2SDavid S. Miller 	if (keylen != DES_KEY_SIZE) {
6840a625fd2SDavid S. Miller 		crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
6850a625fd2SDavid S. Miller 		return -EINVAL;
6860a625fd2SDavid S. Miller 	}
6870a625fd2SDavid S. Miller 
6880a625fd2SDavid S. Miller 	err = des_ekey(tmp, key);
6890a625fd2SDavid S. Miller 	if (err == 0 && (tfm->crt_flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
6900a625fd2SDavid S. Miller 		tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY;
6910a625fd2SDavid S. Miller 		return -EINVAL;
6920a625fd2SDavid S. Miller 	}
6930a625fd2SDavid S. Miller 
6940a625fd2SDavid S. Miller 	ctx->key_len = keylen;
6950a625fd2SDavid S. Miller 	memcpy(ctx->key.des, key, keylen);
6960a625fd2SDavid S. Miller 	return 0;
6970a625fd2SDavid S. Miller }
6980a625fd2SDavid S. Miller 
6990a625fd2SDavid S. Miller static int n2_3des_setkey(struct crypto_ablkcipher *cipher, const u8 *key,
7000a625fd2SDavid S. Miller 			  unsigned int keylen)
7010a625fd2SDavid S. Miller {
7020a625fd2SDavid S. Miller 	struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
7030a625fd2SDavid S. Miller 	struct n2_cipher_context *ctx = crypto_tfm_ctx(tfm);
7040a625fd2SDavid S. Miller 	struct n2_cipher_alg *n2alg = n2_cipher_alg(tfm);
7050a625fd2SDavid S. Miller 
7060a625fd2SDavid S. Miller 	ctx->enc_type = n2alg->enc_type;
7070a625fd2SDavid S. Miller 
7080a625fd2SDavid S. Miller 	if (keylen != (3 * DES_KEY_SIZE)) {
7090a625fd2SDavid S. Miller 		crypto_ablkcipher_set_flags(cipher, CRYPTO_TFM_RES_BAD_KEY_LEN);
7100a625fd2SDavid S. Miller 		return -EINVAL;
7110a625fd2SDavid S. Miller 	}
7120a625fd2SDavid S. Miller 	ctx->key_len = keylen;
7130a625fd2SDavid S. Miller 	memcpy(ctx->key.des3, key, keylen);
7140a625fd2SDavid S. Miller 	return 0;
7150a625fd2SDavid S. Miller }
7160a625fd2SDavid S. Miller 
7170a625fd2SDavid S. Miller static int n2_arc4_setkey(struct crypto_ablkcipher *cipher, const u8 *key,
7180a625fd2SDavid S. Miller 			  unsigned int keylen)
7190a625fd2SDavid S. Miller {
7200a625fd2SDavid S. Miller 	struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
7210a625fd2SDavid S. Miller 	struct n2_cipher_context *ctx = crypto_tfm_ctx(tfm);
7220a625fd2SDavid S. Miller 	struct n2_cipher_alg *n2alg = n2_cipher_alg(tfm);
7230a625fd2SDavid S. Miller 	u8 *s = ctx->key.arc4;
7240a625fd2SDavid S. Miller 	u8 *x = s + 256;
7250a625fd2SDavid S. Miller 	u8 *y = x + 1;
7260a625fd2SDavid S. Miller 	int i, j, k;
7270a625fd2SDavid S. Miller 
7280a625fd2SDavid S. Miller 	ctx->enc_type = n2alg->enc_type;
7290a625fd2SDavid S. Miller 
7300a625fd2SDavid S. Miller 	j = k = 0;
7310a625fd2SDavid S. Miller 	*x = 0;
7320a625fd2SDavid S. Miller 	*y = 0;
7330a625fd2SDavid S. Miller 	for (i = 0; i < 256; i++)
7340a625fd2SDavid S. Miller 		s[i] = i;
7350a625fd2SDavid S. Miller 	for (i = 0; i < 256; i++) {
7360a625fd2SDavid S. Miller 		u8 a = s[i];
7370a625fd2SDavid S. Miller 		j = (j + key[k] + a) & 0xff;
7380a625fd2SDavid S. Miller 		s[i] = s[j];
7390a625fd2SDavid S. Miller 		s[j] = a;
7400a625fd2SDavid S. Miller 		if (++k >= keylen)
7410a625fd2SDavid S. Miller 			k = 0;
7420a625fd2SDavid S. Miller 	}
7430a625fd2SDavid S. Miller 
7440a625fd2SDavid S. Miller 	return 0;
7450a625fd2SDavid S. Miller }
7460a625fd2SDavid S. Miller 
7470a625fd2SDavid S. Miller static inline int cipher_descriptor_len(int nbytes, unsigned int block_size)
7480a625fd2SDavid S. Miller {
7490a625fd2SDavid S. Miller 	int this_len = nbytes;
7500a625fd2SDavid S. Miller 
7510a625fd2SDavid S. Miller 	this_len -= (nbytes & (block_size - 1));
7520a625fd2SDavid S. Miller 	return this_len > (1 << 16) ? (1 << 16) : this_len;
7530a625fd2SDavid S. Miller }
7540a625fd2SDavid S. Miller 
7550a625fd2SDavid S. Miller static int __n2_crypt_chunk(struct crypto_tfm *tfm, struct n2_crypto_chunk *cp,
7560a625fd2SDavid S. Miller 			    struct spu_queue *qp, bool encrypt)
7570a625fd2SDavid S. Miller {
7580a625fd2SDavid S. Miller 	struct n2_cipher_context *ctx = crypto_tfm_ctx(tfm);
7590a625fd2SDavid S. Miller 	struct cwq_initial_entry *ent;
7600a625fd2SDavid S. Miller 	bool in_place;
7610a625fd2SDavid S. Miller 	int i;
7620a625fd2SDavid S. Miller 
7630a625fd2SDavid S. Miller 	ent = spu_queue_alloc(qp, cp->arr_len);
7640a625fd2SDavid S. Miller 	if (!ent) {
7650a625fd2SDavid S. Miller 		pr_info("queue_alloc() of %d fails\n",
7660a625fd2SDavid S. Miller 			cp->arr_len);
7670a625fd2SDavid S. Miller 		return -EBUSY;
7680a625fd2SDavid S. Miller 	}
7690a625fd2SDavid S. Miller 
7700a625fd2SDavid S. Miller 	in_place = (cp->dest_paddr == cp->arr[0].src_paddr);
7710a625fd2SDavid S. Miller 
7720a625fd2SDavid S. Miller 	ent->control = control_word_base(cp->arr[0].src_len,
7730a625fd2SDavid S. Miller 					 0, ctx->enc_type, 0, 0,
7740a625fd2SDavid S. Miller 					 false, true, false, encrypt,
7750a625fd2SDavid S. Miller 					 OPCODE_ENCRYPT |
7760a625fd2SDavid S. Miller 					 (in_place ? OPCODE_INPLACE_BIT : 0));
7770a625fd2SDavid S. Miller 	ent->src_addr = cp->arr[0].src_paddr;
7780a625fd2SDavid S. Miller 	ent->auth_key_addr = 0UL;
7790a625fd2SDavid S. Miller 	ent->auth_iv_addr = 0UL;
7800a625fd2SDavid S. Miller 	ent->final_auth_state_addr = 0UL;
7810a625fd2SDavid S. Miller 	ent->enc_key_addr = __pa(&ctx->key);
7820a625fd2SDavid S. Miller 	ent->enc_iv_addr = cp->iv_paddr;
7830a625fd2SDavid S. Miller 	ent->dest_addr = (in_place ? 0UL : cp->dest_paddr);
7840a625fd2SDavid S. Miller 
7850a625fd2SDavid S. Miller 	for (i = 1; i < cp->arr_len; i++) {
7860a625fd2SDavid S. Miller 		ent = spu_queue_next(qp, ent);
7870a625fd2SDavid S. Miller 
7880a625fd2SDavid S. Miller 		ent->control = cp->arr[i].src_len - 1;
7890a625fd2SDavid S. Miller 		ent->src_addr = cp->arr[i].src_paddr;
7900a625fd2SDavid S. Miller 		ent->auth_key_addr = 0UL;
7910a625fd2SDavid S. Miller 		ent->auth_iv_addr = 0UL;
7920a625fd2SDavid S. Miller 		ent->final_auth_state_addr = 0UL;
7930a625fd2SDavid S. Miller 		ent->enc_key_addr = 0UL;
7940a625fd2SDavid S. Miller 		ent->enc_iv_addr = 0UL;
7950a625fd2SDavid S. Miller 		ent->dest_addr = 0UL;
7960a625fd2SDavid S. Miller 	}
7970a625fd2SDavid S. Miller 	ent->control |= CONTROL_END_OF_BLOCK;
7980a625fd2SDavid S. Miller 
7990a625fd2SDavid S. Miller 	return (spu_queue_submit(qp, ent) != HV_EOK) ? -EINVAL : 0;
8000a625fd2SDavid S. Miller }
8010a625fd2SDavid S. Miller 
8020a625fd2SDavid S. Miller static int n2_compute_chunks(struct ablkcipher_request *req)
8030a625fd2SDavid S. Miller {
8040a625fd2SDavid S. Miller 	struct n2_request_context *rctx = ablkcipher_request_ctx(req);
8050a625fd2SDavid S. Miller 	struct ablkcipher_walk *walk = &rctx->walk;
8060a625fd2SDavid S. Miller 	struct n2_crypto_chunk *chunk;
8070a625fd2SDavid S. Miller 	unsigned long dest_prev;
8080a625fd2SDavid S. Miller 	unsigned int tot_len;
8090a625fd2SDavid S. Miller 	bool prev_in_place;
8100a625fd2SDavid S. Miller 	int err, nbytes;
8110a625fd2SDavid S. Miller 
8120a625fd2SDavid S. Miller 	ablkcipher_walk_init(walk, req->dst, req->src, req->nbytes);
8130a625fd2SDavid S. Miller 	err = ablkcipher_walk_phys(req, walk);
8140a625fd2SDavid S. Miller 	if (err)
8150a625fd2SDavid S. Miller 		return err;
8160a625fd2SDavid S. Miller 
8170a625fd2SDavid S. Miller 	INIT_LIST_HEAD(&rctx->chunk_list);
8180a625fd2SDavid S. Miller 
8190a625fd2SDavid S. Miller 	chunk = &rctx->chunk;
8200a625fd2SDavid S. Miller 	INIT_LIST_HEAD(&chunk->entry);
8210a625fd2SDavid S. Miller 
8220a625fd2SDavid S. Miller 	chunk->iv_paddr = 0UL;
8230a625fd2SDavid S. Miller 	chunk->arr_len = 0;
8240a625fd2SDavid S. Miller 	chunk->dest_paddr = 0UL;
8250a625fd2SDavid S. Miller 
8260a625fd2SDavid S. Miller 	prev_in_place = false;
8270a625fd2SDavid S. Miller 	dest_prev = ~0UL;
8280a625fd2SDavid S. Miller 	tot_len = 0;
8290a625fd2SDavid S. Miller 
8300a625fd2SDavid S. Miller 	while ((nbytes = walk->nbytes) != 0) {
8310a625fd2SDavid S. Miller 		unsigned long dest_paddr, src_paddr;
8320a625fd2SDavid S. Miller 		bool in_place;
8330a625fd2SDavid S. Miller 		int this_len;
8340a625fd2SDavid S. Miller 
8350a625fd2SDavid S. Miller 		src_paddr = (page_to_phys(walk->src.page) +
8360a625fd2SDavid S. Miller 			     walk->src.offset);
8370a625fd2SDavid S. Miller 		dest_paddr = (page_to_phys(walk->dst.page) +
8380a625fd2SDavid S. Miller 			      walk->dst.offset);
8390a625fd2SDavid S. Miller 		in_place = (src_paddr == dest_paddr);
8400a625fd2SDavid S. Miller 		this_len = cipher_descriptor_len(nbytes, walk->blocksize);
8410a625fd2SDavid S. Miller 
8420a625fd2SDavid S. Miller 		if (chunk->arr_len != 0) {
8430a625fd2SDavid S. Miller 			if (in_place != prev_in_place ||
8440a625fd2SDavid S. Miller 			    (!prev_in_place &&
8450a625fd2SDavid S. Miller 			     dest_paddr != dest_prev) ||
8460a625fd2SDavid S. Miller 			    chunk->arr_len == N2_CHUNK_ARR_LEN ||
8470a625fd2SDavid S. Miller 			    tot_len + this_len > (1 << 16)) {
8480a625fd2SDavid S. Miller 				chunk->dest_final = dest_prev;
8490a625fd2SDavid S. Miller 				list_add_tail(&chunk->entry,
8500a625fd2SDavid S. Miller 					      &rctx->chunk_list);
8510a625fd2SDavid S. Miller 				chunk = kzalloc(sizeof(*chunk), GFP_ATOMIC);
8520a625fd2SDavid S. Miller 				if (!chunk) {
8530a625fd2SDavid S. Miller 					err = -ENOMEM;
8540a625fd2SDavid S. Miller 					break;
8550a625fd2SDavid S. Miller 				}
8560a625fd2SDavid S. Miller 				INIT_LIST_HEAD(&chunk->entry);
8570a625fd2SDavid S. Miller 			}
8580a625fd2SDavid S. Miller 		}
8590a625fd2SDavid S. Miller 		if (chunk->arr_len == 0) {
8600a625fd2SDavid S. Miller 			chunk->dest_paddr = dest_paddr;
8610a625fd2SDavid S. Miller 			tot_len = 0;
8620a625fd2SDavid S. Miller 		}
8630a625fd2SDavid S. Miller 		chunk->arr[chunk->arr_len].src_paddr = src_paddr;
8640a625fd2SDavid S. Miller 		chunk->arr[chunk->arr_len].src_len = this_len;
8650a625fd2SDavid S. Miller 		chunk->arr_len++;
8660a625fd2SDavid S. Miller 
8670a625fd2SDavid S. Miller 		dest_prev = dest_paddr + this_len;
8680a625fd2SDavid S. Miller 		prev_in_place = in_place;
8690a625fd2SDavid S. Miller 		tot_len += this_len;
8700a625fd2SDavid S. Miller 
8710a625fd2SDavid S. Miller 		err = ablkcipher_walk_done(req, walk, nbytes - this_len);
8720a625fd2SDavid S. Miller 		if (err)
8730a625fd2SDavid S. Miller 			break;
8740a625fd2SDavid S. Miller 	}
8750a625fd2SDavid S. Miller 	if (!err && chunk->arr_len != 0) {
8760a625fd2SDavid S. Miller 		chunk->dest_final = dest_prev;
8770a625fd2SDavid S. Miller 		list_add_tail(&chunk->entry, &rctx->chunk_list);
8780a625fd2SDavid S. Miller 	}
8790a625fd2SDavid S. Miller 
8800a625fd2SDavid S. Miller 	return err;
8810a625fd2SDavid S. Miller }
8820a625fd2SDavid S. Miller 
8830a625fd2SDavid S. Miller static void n2_chunk_complete(struct ablkcipher_request *req, void *final_iv)
8840a625fd2SDavid S. Miller {
8850a625fd2SDavid S. Miller 	struct n2_request_context *rctx = ablkcipher_request_ctx(req);
8860a625fd2SDavid S. Miller 	struct n2_crypto_chunk *c, *tmp;
8870a625fd2SDavid S. Miller 
8880a625fd2SDavid S. Miller 	if (final_iv)
8890a625fd2SDavid S. Miller 		memcpy(rctx->walk.iv, final_iv, rctx->walk.blocksize);
8900a625fd2SDavid S. Miller 
8910a625fd2SDavid S. Miller 	ablkcipher_walk_complete(&rctx->walk);
8920a625fd2SDavid S. Miller 	list_for_each_entry_safe(c, tmp, &rctx->chunk_list, entry) {
8930a625fd2SDavid S. Miller 		list_del(&c->entry);
8940a625fd2SDavid S. Miller 		if (unlikely(c != &rctx->chunk))
8950a625fd2SDavid S. Miller 			kfree(c);
8960a625fd2SDavid S. Miller 	}
8970a625fd2SDavid S. Miller 
8980a625fd2SDavid S. Miller }
8990a625fd2SDavid S. Miller 
9000a625fd2SDavid S. Miller static int n2_do_ecb(struct ablkcipher_request *req, bool encrypt)
9010a625fd2SDavid S. Miller {
9020a625fd2SDavid S. Miller 	struct n2_request_context *rctx = ablkcipher_request_ctx(req);
9030a625fd2SDavid S. Miller 	struct crypto_tfm *tfm = req->base.tfm;
9040a625fd2SDavid S. Miller 	int err = n2_compute_chunks(req);
9050a625fd2SDavid S. Miller 	struct n2_crypto_chunk *c, *tmp;
9060a625fd2SDavid S. Miller 	unsigned long flags, hv_ret;
9070a625fd2SDavid S. Miller 	struct spu_queue *qp;
9080a625fd2SDavid S. Miller 
9090a625fd2SDavid S. Miller 	if (err)
9100a625fd2SDavid S. Miller 		return err;
9110a625fd2SDavid S. Miller 
9120a625fd2SDavid S. Miller 	qp = cpu_to_cwq[get_cpu()];
9130a625fd2SDavid S. Miller 	err = -ENODEV;
9140a625fd2SDavid S. Miller 	if (!qp)
9150a625fd2SDavid S. Miller 		goto out;
9160a625fd2SDavid S. Miller 
9170a625fd2SDavid S. Miller 	spin_lock_irqsave(&qp->lock, flags);
9180a625fd2SDavid S. Miller 
9190a625fd2SDavid S. Miller 	list_for_each_entry_safe(c, tmp, &rctx->chunk_list, entry) {
9200a625fd2SDavid S. Miller 		err = __n2_crypt_chunk(tfm, c, qp, encrypt);
9210a625fd2SDavid S. Miller 		if (err)
9220a625fd2SDavid S. Miller 			break;
9230a625fd2SDavid S. Miller 		list_del(&c->entry);
9240a625fd2SDavid S. Miller 		if (unlikely(c != &rctx->chunk))
9250a625fd2SDavid S. Miller 			kfree(c);
9260a625fd2SDavid S. Miller 	}
9270a625fd2SDavid S. Miller 	if (!err) {
9280a625fd2SDavid S. Miller 		hv_ret = wait_for_tail(qp);
9290a625fd2SDavid S. Miller 		if (hv_ret != HV_EOK)
9300a625fd2SDavid S. Miller 			err = -EINVAL;
9310a625fd2SDavid S. Miller 	}
9320a625fd2SDavid S. Miller 
9330a625fd2SDavid S. Miller 	spin_unlock_irqrestore(&qp->lock, flags);
9340a625fd2SDavid S. Miller 
9350a625fd2SDavid S. Miller 	put_cpu();
9360a625fd2SDavid S. Miller 
9370a625fd2SDavid S. Miller out:
9380a625fd2SDavid S. Miller 	n2_chunk_complete(req, NULL);
9390a625fd2SDavid S. Miller 	return err;
9400a625fd2SDavid S. Miller }
9410a625fd2SDavid S. Miller 
9420a625fd2SDavid S. Miller static int n2_encrypt_ecb(struct ablkcipher_request *req)
9430a625fd2SDavid S. Miller {
9440a625fd2SDavid S. Miller 	return n2_do_ecb(req, true);
9450a625fd2SDavid S. Miller }
9460a625fd2SDavid S. Miller 
9470a625fd2SDavid S. Miller static int n2_decrypt_ecb(struct ablkcipher_request *req)
9480a625fd2SDavid S. Miller {
9490a625fd2SDavid S. Miller 	return n2_do_ecb(req, false);
9500a625fd2SDavid S. Miller }
9510a625fd2SDavid S. Miller 
9520a625fd2SDavid S. Miller static int n2_do_chaining(struct ablkcipher_request *req, bool encrypt)
9530a625fd2SDavid S. Miller {
9540a625fd2SDavid S. Miller 	struct n2_request_context *rctx = ablkcipher_request_ctx(req);
9550a625fd2SDavid S. Miller 	struct crypto_tfm *tfm = req->base.tfm;
9560a625fd2SDavid S. Miller 	unsigned long flags, hv_ret, iv_paddr;
9570a625fd2SDavid S. Miller 	int err = n2_compute_chunks(req);
9580a625fd2SDavid S. Miller 	struct n2_crypto_chunk *c, *tmp;
9590a625fd2SDavid S. Miller 	struct spu_queue *qp;
9600a625fd2SDavid S. Miller 	void *final_iv_addr;
9610a625fd2SDavid S. Miller 
9620a625fd2SDavid S. Miller 	final_iv_addr = NULL;
9630a625fd2SDavid S. Miller 
9640a625fd2SDavid S. Miller 	if (err)
9650a625fd2SDavid S. Miller 		return err;
9660a625fd2SDavid S. Miller 
9670a625fd2SDavid S. Miller 	qp = cpu_to_cwq[get_cpu()];
9680a625fd2SDavid S. Miller 	err = -ENODEV;
9690a625fd2SDavid S. Miller 	if (!qp)
9700a625fd2SDavid S. Miller 		goto out;
9710a625fd2SDavid S. Miller 
9720a625fd2SDavid S. Miller 	spin_lock_irqsave(&qp->lock, flags);
9730a625fd2SDavid S. Miller 
9740a625fd2SDavid S. Miller 	if (encrypt) {
9750a625fd2SDavid S. Miller 		iv_paddr = __pa(rctx->walk.iv);
9760a625fd2SDavid S. Miller 		list_for_each_entry_safe(c, tmp, &rctx->chunk_list,
9770a625fd2SDavid S. Miller 					 entry) {
9780a625fd2SDavid S. Miller 			c->iv_paddr = iv_paddr;
9790a625fd2SDavid S. Miller 			err = __n2_crypt_chunk(tfm, c, qp, true);
9800a625fd2SDavid S. Miller 			if (err)
9810a625fd2SDavid S. Miller 				break;
9820a625fd2SDavid S. Miller 			iv_paddr = c->dest_final - rctx->walk.blocksize;
9830a625fd2SDavid S. Miller 			list_del(&c->entry);
9840a625fd2SDavid S. Miller 			if (unlikely(c != &rctx->chunk))
9850a625fd2SDavid S. Miller 				kfree(c);
9860a625fd2SDavid S. Miller 		}
9870a625fd2SDavid S. Miller 		final_iv_addr = __va(iv_paddr);
9880a625fd2SDavid S. Miller 	} else {
9890a625fd2SDavid S. Miller 		list_for_each_entry_safe_reverse(c, tmp, &rctx->chunk_list,
9900a625fd2SDavid S. Miller 						 entry) {
9910a625fd2SDavid S. Miller 			if (c == &rctx->chunk) {
9920a625fd2SDavid S. Miller 				iv_paddr = __pa(rctx->walk.iv);
9930a625fd2SDavid S. Miller 			} else {
9940a625fd2SDavid S. Miller 				iv_paddr = (tmp->arr[tmp->arr_len-1].src_paddr +
9950a625fd2SDavid S. Miller 					    tmp->arr[tmp->arr_len-1].src_len -
9960a625fd2SDavid S. Miller 					    rctx->walk.blocksize);
9970a625fd2SDavid S. Miller 			}
9980a625fd2SDavid S. Miller 			if (!final_iv_addr) {
9990a625fd2SDavid S. Miller 				unsigned long pa;
10000a625fd2SDavid S. Miller 
10010a625fd2SDavid S. Miller 				pa = (c->arr[c->arr_len-1].src_paddr +
10020a625fd2SDavid S. Miller 				      c->arr[c->arr_len-1].src_len -
10030a625fd2SDavid S. Miller 				      rctx->walk.blocksize);
10040a625fd2SDavid S. Miller 				final_iv_addr = rctx->temp_iv;
10050a625fd2SDavid S. Miller 				memcpy(rctx->temp_iv, __va(pa),
10060a625fd2SDavid S. Miller 				       rctx->walk.blocksize);
10070a625fd2SDavid S. Miller 			}
10080a625fd2SDavid S. Miller 			c->iv_paddr = iv_paddr;
10090a625fd2SDavid S. Miller 			err = __n2_crypt_chunk(tfm, c, qp, false);
10100a625fd2SDavid S. Miller 			if (err)
10110a625fd2SDavid S. Miller 				break;
10120a625fd2SDavid S. Miller 			list_del(&c->entry);
10130a625fd2SDavid S. Miller 			if (unlikely(c != &rctx->chunk))
10140a625fd2SDavid S. Miller 				kfree(c);
10150a625fd2SDavid S. Miller 		}
10160a625fd2SDavid S. Miller 	}
10170a625fd2SDavid S. Miller 	if (!err) {
10180a625fd2SDavid S. Miller 		hv_ret = wait_for_tail(qp);
10190a625fd2SDavid S. Miller 		if (hv_ret != HV_EOK)
10200a625fd2SDavid S. Miller 			err = -EINVAL;
10210a625fd2SDavid S. Miller 	}
10220a625fd2SDavid S. Miller 
10230a625fd2SDavid S. Miller 	spin_unlock_irqrestore(&qp->lock, flags);
10240a625fd2SDavid S. Miller 
10250a625fd2SDavid S. Miller 	put_cpu();
10260a625fd2SDavid S. Miller 
10270a625fd2SDavid S. Miller out:
10280a625fd2SDavid S. Miller 	n2_chunk_complete(req, err ? NULL : final_iv_addr);
10290a625fd2SDavid S. Miller 	return err;
10300a625fd2SDavid S. Miller }
10310a625fd2SDavid S. Miller 
10320a625fd2SDavid S. Miller static int n2_encrypt_chaining(struct ablkcipher_request *req)
10330a625fd2SDavid S. Miller {
10340a625fd2SDavid S. Miller 	return n2_do_chaining(req, true);
10350a625fd2SDavid S. Miller }
10360a625fd2SDavid S. Miller 
10370a625fd2SDavid S. Miller static int n2_decrypt_chaining(struct ablkcipher_request *req)
10380a625fd2SDavid S. Miller {
10390a625fd2SDavid S. Miller 	return n2_do_chaining(req, false);
10400a625fd2SDavid S. Miller }
10410a625fd2SDavid S. Miller 
10420a625fd2SDavid S. Miller struct n2_cipher_tmpl {
10430a625fd2SDavid S. Miller 	const char		*name;
10440a625fd2SDavid S. Miller 	const char		*drv_name;
10450a625fd2SDavid S. Miller 	u8			block_size;
10460a625fd2SDavid S. Miller 	u8			enc_type;
10470a625fd2SDavid S. Miller 	struct ablkcipher_alg	ablkcipher;
10480a625fd2SDavid S. Miller };
10490a625fd2SDavid S. Miller 
10500a625fd2SDavid S. Miller static const struct n2_cipher_tmpl cipher_tmpls[] = {
10510a625fd2SDavid S. Miller 	/* ARC4: only ECB is supported (chaining bits ignored) */
10520a625fd2SDavid S. Miller 	{	.name		= "ecb(arc4)",
10530a625fd2SDavid S. Miller 		.drv_name	= "ecb-arc4",
10540a625fd2SDavid S. Miller 		.block_size	= 1,
10550a625fd2SDavid S. Miller 		.enc_type	= (ENC_TYPE_ALG_RC4_STREAM |
10560a625fd2SDavid S. Miller 				   ENC_TYPE_CHAINING_ECB),
10570a625fd2SDavid S. Miller 		.ablkcipher	= {
10580a625fd2SDavid S. Miller 			.min_keysize	= 1,
10590a625fd2SDavid S. Miller 			.max_keysize	= 256,
10600a625fd2SDavid S. Miller 			.setkey		= n2_arc4_setkey,
10610a625fd2SDavid S. Miller 			.encrypt	= n2_encrypt_ecb,
10620a625fd2SDavid S. Miller 			.decrypt	= n2_decrypt_ecb,
10630a625fd2SDavid S. Miller 		},
10640a625fd2SDavid S. Miller 	},
10650a625fd2SDavid S. Miller 
10660a625fd2SDavid S. Miller 	/* DES: ECB CBC and CFB are supported */
10670a625fd2SDavid S. Miller 	{	.name		= "ecb(des)",
10680a625fd2SDavid S. Miller 		.drv_name	= "ecb-des",
10690a625fd2SDavid S. Miller 		.block_size	= DES_BLOCK_SIZE,
10700a625fd2SDavid S. Miller 		.enc_type	= (ENC_TYPE_ALG_DES |
10710a625fd2SDavid S. Miller 				   ENC_TYPE_CHAINING_ECB),
10720a625fd2SDavid S. Miller 		.ablkcipher	= {
10730a625fd2SDavid S. Miller 			.min_keysize	= DES_KEY_SIZE,
10740a625fd2SDavid S. Miller 			.max_keysize	= DES_KEY_SIZE,
10750a625fd2SDavid S. Miller 			.setkey		= n2_des_setkey,
10760a625fd2SDavid S. Miller 			.encrypt	= n2_encrypt_ecb,
10770a625fd2SDavid S. Miller 			.decrypt	= n2_decrypt_ecb,
10780a625fd2SDavid S. Miller 		},
10790a625fd2SDavid S. Miller 	},
10800a625fd2SDavid S. Miller 	{	.name		= "cbc(des)",
10810a625fd2SDavid S. Miller 		.drv_name	= "cbc-des",
10820a625fd2SDavid S. Miller 		.block_size	= DES_BLOCK_SIZE,
10830a625fd2SDavid S. Miller 		.enc_type	= (ENC_TYPE_ALG_DES |
10840a625fd2SDavid S. Miller 				   ENC_TYPE_CHAINING_CBC),
10850a625fd2SDavid S. Miller 		.ablkcipher	= {
10860a625fd2SDavid S. Miller 			.ivsize		= DES_BLOCK_SIZE,
10870a625fd2SDavid S. Miller 			.min_keysize	= DES_KEY_SIZE,
10880a625fd2SDavid S. Miller 			.max_keysize	= DES_KEY_SIZE,
10890a625fd2SDavid S. Miller 			.setkey		= n2_des_setkey,
10900a625fd2SDavid S. Miller 			.encrypt	= n2_encrypt_chaining,
10910a625fd2SDavid S. Miller 			.decrypt	= n2_decrypt_chaining,
10920a625fd2SDavid S. Miller 		},
10930a625fd2SDavid S. Miller 	},
10940a625fd2SDavid S. Miller 	{	.name		= "cfb(des)",
10950a625fd2SDavid S. Miller 		.drv_name	= "cfb-des",
10960a625fd2SDavid S. Miller 		.block_size	= DES_BLOCK_SIZE,
10970a625fd2SDavid S. Miller 		.enc_type	= (ENC_TYPE_ALG_DES |
10980a625fd2SDavid S. Miller 				   ENC_TYPE_CHAINING_CFB),
10990a625fd2SDavid S. Miller 		.ablkcipher	= {
11000a625fd2SDavid S. Miller 			.min_keysize	= DES_KEY_SIZE,
11010a625fd2SDavid S. Miller 			.max_keysize	= DES_KEY_SIZE,
11020a625fd2SDavid S. Miller 			.setkey		= n2_des_setkey,
11030a625fd2SDavid S. Miller 			.encrypt	= n2_encrypt_chaining,
11040a625fd2SDavid S. Miller 			.decrypt	= n2_decrypt_chaining,
11050a625fd2SDavid S. Miller 		},
11060a625fd2SDavid S. Miller 	},
11070a625fd2SDavid S. Miller 
11080a625fd2SDavid S. Miller 	/* 3DES: ECB CBC and CFB are supported */
11090a625fd2SDavid S. Miller 	{	.name		= "ecb(des3_ede)",
11100a625fd2SDavid S. Miller 		.drv_name	= "ecb-3des",
11110a625fd2SDavid S. Miller 		.block_size	= DES_BLOCK_SIZE,
11120a625fd2SDavid S. Miller 		.enc_type	= (ENC_TYPE_ALG_3DES |
11130a625fd2SDavid S. Miller 				   ENC_TYPE_CHAINING_ECB),
11140a625fd2SDavid S. Miller 		.ablkcipher	= {
11150a625fd2SDavid S. Miller 			.min_keysize	= 3 * DES_KEY_SIZE,
11160a625fd2SDavid S. Miller 			.max_keysize	= 3 * DES_KEY_SIZE,
11170a625fd2SDavid S. Miller 			.setkey		= n2_3des_setkey,
11180a625fd2SDavid S. Miller 			.encrypt	= n2_encrypt_ecb,
11190a625fd2SDavid S. Miller 			.decrypt	= n2_decrypt_ecb,
11200a625fd2SDavid S. Miller 		},
11210a625fd2SDavid S. Miller 	},
11220a625fd2SDavid S. Miller 	{	.name		= "cbc(des3_ede)",
11230a625fd2SDavid S. Miller 		.drv_name	= "cbc-3des",
11240a625fd2SDavid S. Miller 		.block_size	= DES_BLOCK_SIZE,
11250a625fd2SDavid S. Miller 		.enc_type	= (ENC_TYPE_ALG_3DES |
11260a625fd2SDavid S. Miller 				   ENC_TYPE_CHAINING_CBC),
11270a625fd2SDavid S. Miller 		.ablkcipher	= {
11280a625fd2SDavid S. Miller 			.ivsize		= DES_BLOCK_SIZE,
11290a625fd2SDavid S. Miller 			.min_keysize	= 3 * DES_KEY_SIZE,
11300a625fd2SDavid S. Miller 			.max_keysize	= 3 * DES_KEY_SIZE,
11310a625fd2SDavid S. Miller 			.setkey		= n2_3des_setkey,
11320a625fd2SDavid S. Miller 			.encrypt	= n2_encrypt_chaining,
11330a625fd2SDavid S. Miller 			.decrypt	= n2_decrypt_chaining,
11340a625fd2SDavid S. Miller 		},
11350a625fd2SDavid S. Miller 	},
11360a625fd2SDavid S. Miller 	{	.name		= "cfb(des3_ede)",
11370a625fd2SDavid S. Miller 		.drv_name	= "cfb-3des",
11380a625fd2SDavid S. Miller 		.block_size	= DES_BLOCK_SIZE,
11390a625fd2SDavid S. Miller 		.enc_type	= (ENC_TYPE_ALG_3DES |
11400a625fd2SDavid S. Miller 				   ENC_TYPE_CHAINING_CFB),
11410a625fd2SDavid S. Miller 		.ablkcipher	= {
11420a625fd2SDavid S. Miller 			.min_keysize	= 3 * DES_KEY_SIZE,
11430a625fd2SDavid S. Miller 			.max_keysize	= 3 * DES_KEY_SIZE,
11440a625fd2SDavid S. Miller 			.setkey		= n2_3des_setkey,
11450a625fd2SDavid S. Miller 			.encrypt	= n2_encrypt_chaining,
11460a625fd2SDavid S. Miller 			.decrypt	= n2_decrypt_chaining,
11470a625fd2SDavid S. Miller 		},
11480a625fd2SDavid S. Miller 	},
11490a625fd2SDavid S. Miller 	/* AES: ECB CBC and CTR are supported */
11500a625fd2SDavid S. Miller 	{	.name		= "ecb(aes)",
11510a625fd2SDavid S. Miller 		.drv_name	= "ecb-aes",
11520a625fd2SDavid S. Miller 		.block_size	= AES_BLOCK_SIZE,
11530a625fd2SDavid S. Miller 		.enc_type	= (ENC_TYPE_ALG_AES128 |
11540a625fd2SDavid S. Miller 				   ENC_TYPE_CHAINING_ECB),
11550a625fd2SDavid S. Miller 		.ablkcipher	= {
11560a625fd2SDavid S. Miller 			.min_keysize	= AES_MIN_KEY_SIZE,
11570a625fd2SDavid S. Miller 			.max_keysize	= AES_MAX_KEY_SIZE,
11580a625fd2SDavid S. Miller 			.setkey		= n2_aes_setkey,
11590a625fd2SDavid S. Miller 			.encrypt	= n2_encrypt_ecb,
11600a625fd2SDavid S. Miller 			.decrypt	= n2_decrypt_ecb,
11610a625fd2SDavid S. Miller 		},
11620a625fd2SDavid S. Miller 	},
11630a625fd2SDavid S. Miller 	{	.name		= "cbc(aes)",
11640a625fd2SDavid S. Miller 		.drv_name	= "cbc-aes",
11650a625fd2SDavid S. Miller 		.block_size	= AES_BLOCK_SIZE,
11660a625fd2SDavid S. Miller 		.enc_type	= (ENC_TYPE_ALG_AES128 |
11670a625fd2SDavid S. Miller 				   ENC_TYPE_CHAINING_CBC),
11680a625fd2SDavid S. Miller 		.ablkcipher	= {
11690a625fd2SDavid S. Miller 			.ivsize		= AES_BLOCK_SIZE,
11700a625fd2SDavid S. Miller 			.min_keysize	= AES_MIN_KEY_SIZE,
11710a625fd2SDavid S. Miller 			.max_keysize	= AES_MAX_KEY_SIZE,
11720a625fd2SDavid S. Miller 			.setkey		= n2_aes_setkey,
11730a625fd2SDavid S. Miller 			.encrypt	= n2_encrypt_chaining,
11740a625fd2SDavid S. Miller 			.decrypt	= n2_decrypt_chaining,
11750a625fd2SDavid S. Miller 		},
11760a625fd2SDavid S. Miller 	},
11770a625fd2SDavid S. Miller 	{	.name		= "ctr(aes)",
11780a625fd2SDavid S. Miller 		.drv_name	= "ctr-aes",
11790a625fd2SDavid S. Miller 		.block_size	= AES_BLOCK_SIZE,
11800a625fd2SDavid S. Miller 		.enc_type	= (ENC_TYPE_ALG_AES128 |
11810a625fd2SDavid S. Miller 				   ENC_TYPE_CHAINING_COUNTER),
11820a625fd2SDavid S. Miller 		.ablkcipher	= {
11830a625fd2SDavid S. Miller 			.ivsize		= AES_BLOCK_SIZE,
11840a625fd2SDavid S. Miller 			.min_keysize	= AES_MIN_KEY_SIZE,
11850a625fd2SDavid S. Miller 			.max_keysize	= AES_MAX_KEY_SIZE,
11860a625fd2SDavid S. Miller 			.setkey		= n2_aes_setkey,
11870a625fd2SDavid S. Miller 			.encrypt	= n2_encrypt_chaining,
11880a625fd2SDavid S. Miller 			.decrypt	= n2_encrypt_chaining,
11890a625fd2SDavid S. Miller 		},
11900a625fd2SDavid S. Miller 	},
11910a625fd2SDavid S. Miller 
11920a625fd2SDavid S. Miller };
11930a625fd2SDavid S. Miller #define NUM_CIPHER_TMPLS ARRAY_SIZE(cipher_tmpls)
11940a625fd2SDavid S. Miller 
11950a625fd2SDavid S. Miller static LIST_HEAD(cipher_algs);
11960a625fd2SDavid S. Miller 
11970a625fd2SDavid S. Miller struct n2_hash_tmpl {
11980a625fd2SDavid S. Miller 	const char	*name;
11990a625fd2SDavid S. Miller 	int		(*digest)(struct ahash_request *req);
12000a625fd2SDavid S. Miller 	u8		digest_size;
12010a625fd2SDavid S. Miller 	u8		block_size;
12020a625fd2SDavid S. Miller };
12030a625fd2SDavid S. Miller static const struct n2_hash_tmpl hash_tmpls[] = {
12040a625fd2SDavid S. Miller 	{ .name		= "md5",
12050a625fd2SDavid S. Miller 	  .digest	= n2_md5_async_digest,
12060a625fd2SDavid S. Miller 	  .digest_size	= MD5_DIGEST_SIZE,
12070a625fd2SDavid S. Miller 	  .block_size	= MD5_HMAC_BLOCK_SIZE },
12080a625fd2SDavid S. Miller 	{ .name		= "sha1",
12090a625fd2SDavid S. Miller 	  .digest	= n2_sha1_async_digest,
12100a625fd2SDavid S. Miller 	  .digest_size	= SHA1_DIGEST_SIZE,
12110a625fd2SDavid S. Miller 	  .block_size	= SHA1_BLOCK_SIZE },
12120a625fd2SDavid S. Miller 	{ .name		= "sha256",
12130a625fd2SDavid S. Miller 	  .digest	= n2_sha256_async_digest,
12140a625fd2SDavid S. Miller 	  .digest_size	= SHA256_DIGEST_SIZE,
12150a625fd2SDavid S. Miller 	  .block_size	= SHA256_BLOCK_SIZE },
12160a625fd2SDavid S. Miller 	{ .name		= "sha224",
12170a625fd2SDavid S. Miller 	  .digest	= n2_sha224_async_digest,
12180a625fd2SDavid S. Miller 	  .digest_size	= SHA224_DIGEST_SIZE,
12190a625fd2SDavid S. Miller 	  .block_size	= SHA224_BLOCK_SIZE },
12200a625fd2SDavid S. Miller };
12210a625fd2SDavid S. Miller #define NUM_HASH_TMPLS ARRAY_SIZE(hash_tmpls)
12220a625fd2SDavid S. Miller 
12230a625fd2SDavid S. Miller struct n2_ahash_alg {
12240a625fd2SDavid S. Miller 	struct list_head	entry;
12250a625fd2SDavid S. Miller 	struct ahash_alg	alg;
12260a625fd2SDavid S. Miller };
12270a625fd2SDavid S. Miller static LIST_HEAD(ahash_algs);
12280a625fd2SDavid S. Miller 
12290a625fd2SDavid S. Miller static int algs_registered;
12300a625fd2SDavid S. Miller 
12310a625fd2SDavid S. Miller static void __n2_unregister_algs(void)
12320a625fd2SDavid S. Miller {
12330a625fd2SDavid S. Miller 	struct n2_cipher_alg *cipher, *cipher_tmp;
12340a625fd2SDavid S. Miller 	struct n2_ahash_alg *alg, *alg_tmp;
12350a625fd2SDavid S. Miller 
12360a625fd2SDavid S. Miller 	list_for_each_entry_safe(cipher, cipher_tmp, &cipher_algs, entry) {
12370a625fd2SDavid S. Miller 		crypto_unregister_alg(&cipher->alg);
12380a625fd2SDavid S. Miller 		list_del(&cipher->entry);
12390a625fd2SDavid S. Miller 		kfree(cipher);
12400a625fd2SDavid S. Miller 	}
12410a625fd2SDavid S. Miller 	list_for_each_entry_safe(alg, alg_tmp, &ahash_algs, entry) {
12420a625fd2SDavid S. Miller 		crypto_unregister_ahash(&alg->alg);
12430a625fd2SDavid S. Miller 		list_del(&alg->entry);
12440a625fd2SDavid S. Miller 		kfree(alg);
12450a625fd2SDavid S. Miller 	}
12460a625fd2SDavid S. Miller }
12470a625fd2SDavid S. Miller 
12480a625fd2SDavid S. Miller static int n2_cipher_cra_init(struct crypto_tfm *tfm)
12490a625fd2SDavid S. Miller {
12500a625fd2SDavid S. Miller 	tfm->crt_ablkcipher.reqsize = sizeof(struct n2_request_context);
12510a625fd2SDavid S. Miller 	return 0;
12520a625fd2SDavid S. Miller }
12530a625fd2SDavid S. Miller 
12540a625fd2SDavid S. Miller static int __devinit __n2_register_one_cipher(const struct n2_cipher_tmpl *tmpl)
12550a625fd2SDavid S. Miller {
12560a625fd2SDavid S. Miller 	struct n2_cipher_alg *p = kzalloc(sizeof(*p), GFP_KERNEL);
12570a625fd2SDavid S. Miller 	struct crypto_alg *alg;
12580a625fd2SDavid S. Miller 	int err;
12590a625fd2SDavid S. Miller 
12600a625fd2SDavid S. Miller 	if (!p)
12610a625fd2SDavid S. Miller 		return -ENOMEM;
12620a625fd2SDavid S. Miller 
12630a625fd2SDavid S. Miller 	alg = &p->alg;
12640a625fd2SDavid S. Miller 
12650a625fd2SDavid S. Miller 	snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", tmpl->name);
12660a625fd2SDavid S. Miller 	snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s-n2", tmpl->drv_name);
12670a625fd2SDavid S. Miller 	alg->cra_priority = N2_CRA_PRIORITY;
12680a625fd2SDavid S. Miller 	alg->cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC;
12690a625fd2SDavid S. Miller 	alg->cra_blocksize = tmpl->block_size;
12700a625fd2SDavid S. Miller 	p->enc_type = tmpl->enc_type;
12710a625fd2SDavid S. Miller 	alg->cra_ctxsize = sizeof(struct n2_cipher_context);
12720a625fd2SDavid S. Miller 	alg->cra_type = &crypto_ablkcipher_type;
12730a625fd2SDavid S. Miller 	alg->cra_u.ablkcipher = tmpl->ablkcipher;
12740a625fd2SDavid S. Miller 	alg->cra_init = n2_cipher_cra_init;
12750a625fd2SDavid S. Miller 	alg->cra_module = THIS_MODULE;
12760a625fd2SDavid S. Miller 
12770a625fd2SDavid S. Miller 	list_add(&p->entry, &cipher_algs);
12780a625fd2SDavid S. Miller 	err = crypto_register_alg(alg);
12790a625fd2SDavid S. Miller 	if (err) {
12800a625fd2SDavid S. Miller 		list_del(&p->entry);
12810a625fd2SDavid S. Miller 		kfree(p);
12820a625fd2SDavid S. Miller 	}
12830a625fd2SDavid S. Miller 	return err;
12840a625fd2SDavid S. Miller }
12850a625fd2SDavid S. Miller 
12860a625fd2SDavid S. Miller static int __devinit __n2_register_one_ahash(const struct n2_hash_tmpl *tmpl)
12870a625fd2SDavid S. Miller {
12880a625fd2SDavid S. Miller 	struct n2_ahash_alg *p = kzalloc(sizeof(*p), GFP_KERNEL);
12890a625fd2SDavid S. Miller 	struct hash_alg_common *halg;
12900a625fd2SDavid S. Miller 	struct crypto_alg *base;
12910a625fd2SDavid S. Miller 	struct ahash_alg *ahash;
12920a625fd2SDavid S. Miller 	int err;
12930a625fd2SDavid S. Miller 
12940a625fd2SDavid S. Miller 	if (!p)
12950a625fd2SDavid S. Miller 		return -ENOMEM;
12960a625fd2SDavid S. Miller 
12970a625fd2SDavid S. Miller 	ahash = &p->alg;
12980a625fd2SDavid S. Miller 	ahash->init = n2_hash_async_init;
12990a625fd2SDavid S. Miller 	ahash->update = n2_hash_async_update;
13000a625fd2SDavid S. Miller 	ahash->final = n2_hash_async_final;
13010a625fd2SDavid S. Miller 	ahash->finup = n2_hash_async_finup;
13020a625fd2SDavid S. Miller 	ahash->digest = tmpl->digest;
13030a625fd2SDavid S. Miller 
13040a625fd2SDavid S. Miller 	halg = &ahash->halg;
13050a625fd2SDavid S. Miller 	halg->digestsize = tmpl->digest_size;
13060a625fd2SDavid S. Miller 
13070a625fd2SDavid S. Miller 	base = &halg->base;
13080a625fd2SDavid S. Miller 	snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "%s", tmpl->name);
13090a625fd2SDavid S. Miller 	snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s-n2", tmpl->name);
13100a625fd2SDavid S. Miller 	base->cra_priority = N2_CRA_PRIORITY;
13110a625fd2SDavid S. Miller 	base->cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_NEED_FALLBACK;
13120a625fd2SDavid S. Miller 	base->cra_blocksize = tmpl->block_size;
13130a625fd2SDavid S. Miller 	base->cra_ctxsize = sizeof(struct n2_hash_ctx);
13140a625fd2SDavid S. Miller 	base->cra_module = THIS_MODULE;
13150a625fd2SDavid S. Miller 	base->cra_init = n2_hash_cra_init;
13160a625fd2SDavid S. Miller 	base->cra_exit = n2_hash_cra_exit;
13170a625fd2SDavid S. Miller 
13180a625fd2SDavid S. Miller 	list_add(&p->entry, &ahash_algs);
13190a625fd2SDavid S. Miller 	err = crypto_register_ahash(ahash);
13200a625fd2SDavid S. Miller 	if (err) {
13210a625fd2SDavid S. Miller 		list_del(&p->entry);
13220a625fd2SDavid S. Miller 		kfree(p);
13230a625fd2SDavid S. Miller 	}
13240a625fd2SDavid S. Miller 	return err;
13250a625fd2SDavid S. Miller }
13260a625fd2SDavid S. Miller 
13270a625fd2SDavid S. Miller static int __devinit n2_register_algs(void)
13280a625fd2SDavid S. Miller {
13290a625fd2SDavid S. Miller 	int i, err = 0;
13300a625fd2SDavid S. Miller 
13310a625fd2SDavid S. Miller 	mutex_lock(&spu_lock);
13320a625fd2SDavid S. Miller 	if (algs_registered++)
13330a625fd2SDavid S. Miller 		goto out;
13340a625fd2SDavid S. Miller 
13350a625fd2SDavid S. Miller 	for (i = 0; i < NUM_HASH_TMPLS; i++) {
13360a625fd2SDavid S. Miller 		err = __n2_register_one_ahash(&hash_tmpls[i]);
13370a625fd2SDavid S. Miller 		if (err) {
13380a625fd2SDavid S. Miller 			__n2_unregister_algs();
13390a625fd2SDavid S. Miller 			goto out;
13400a625fd2SDavid S. Miller 		}
13410a625fd2SDavid S. Miller 	}
13420a625fd2SDavid S. Miller 	for (i = 0; i < NUM_CIPHER_TMPLS; i++) {
13430a625fd2SDavid S. Miller 		err = __n2_register_one_cipher(&cipher_tmpls[i]);
13440a625fd2SDavid S. Miller 		if (err) {
13450a625fd2SDavid S. Miller 			__n2_unregister_algs();
13460a625fd2SDavid S. Miller 			goto out;
13470a625fd2SDavid S. Miller 		}
13480a625fd2SDavid S. Miller 	}
13490a625fd2SDavid S. Miller 
13500a625fd2SDavid S. Miller out:
13510a625fd2SDavid S. Miller 	mutex_unlock(&spu_lock);
13520a625fd2SDavid S. Miller 	return err;
13530a625fd2SDavid S. Miller }
13540a625fd2SDavid S. Miller 
13550a625fd2SDavid S. Miller static void __exit n2_unregister_algs(void)
13560a625fd2SDavid S. Miller {
13570a625fd2SDavid S. Miller 	mutex_lock(&spu_lock);
13580a625fd2SDavid S. Miller 	if (!--algs_registered)
13590a625fd2SDavid S. Miller 		__n2_unregister_algs();
13600a625fd2SDavid S. Miller 	mutex_unlock(&spu_lock);
13610a625fd2SDavid S. Miller }
13620a625fd2SDavid S. Miller 
13630a625fd2SDavid S. Miller /* To map CWQ queues to interrupt sources, the hypervisor API provides
13640a625fd2SDavid S. Miller  * a devino.  This isn't very useful to us because all of the
13650a625fd2SDavid S. Miller  * interrupts listed in the of_device node have been translated to
13660a625fd2SDavid S. Miller  * Linux virtual IRQ cookie numbers.
13670a625fd2SDavid S. Miller  *
13680a625fd2SDavid S. Miller  * So we have to back-translate, going through the 'intr' and 'ino'
13690a625fd2SDavid S. Miller  * property tables of the n2cp MDESC node, matching it with the OF
13700a625fd2SDavid S. Miller  * 'interrupts' property entries, in order to to figure out which
13710a625fd2SDavid S. Miller  * devino goes to which already-translated IRQ.
13720a625fd2SDavid S. Miller  */
13730a625fd2SDavid S. Miller static int find_devino_index(struct of_device *dev, struct spu_mdesc_info *ip,
13740a625fd2SDavid S. Miller 			     unsigned long dev_ino)
13750a625fd2SDavid S. Miller {
13760a625fd2SDavid S. Miller 	const unsigned int *dev_intrs;
13770a625fd2SDavid S. Miller 	unsigned int intr;
13780a625fd2SDavid S. Miller 	int i;
13790a625fd2SDavid S. Miller 
13800a625fd2SDavid S. Miller 	for (i = 0; i < ip->num_intrs; i++) {
13810a625fd2SDavid S. Miller 		if (ip->ino_table[i].ino == dev_ino)
13820a625fd2SDavid S. Miller 			break;
13830a625fd2SDavid S. Miller 	}
13840a625fd2SDavid S. Miller 	if (i == ip->num_intrs)
13850a625fd2SDavid S. Miller 		return -ENODEV;
13860a625fd2SDavid S. Miller 
13870a625fd2SDavid S. Miller 	intr = ip->ino_table[i].intr;
13880a625fd2SDavid S. Miller 
1389ff6c7341SDavid S. Miller 	dev_intrs = of_get_property(dev->dev.of_node, "interrupts", NULL);
13900a625fd2SDavid S. Miller 	if (!dev_intrs)
13910a625fd2SDavid S. Miller 		return -ENODEV;
13920a625fd2SDavid S. Miller 
13930a625fd2SDavid S. Miller 	for (i = 0; i < dev->num_irqs; i++) {
13940a625fd2SDavid S. Miller 		if (dev_intrs[i] == intr)
13950a625fd2SDavid S. Miller 			return i;
13960a625fd2SDavid S. Miller 	}
13970a625fd2SDavid S. Miller 
13980a625fd2SDavid S. Miller 	return -ENODEV;
13990a625fd2SDavid S. Miller }
14000a625fd2SDavid S. Miller 
14010a625fd2SDavid S. Miller static int spu_map_ino(struct of_device *dev, struct spu_mdesc_info *ip,
14020a625fd2SDavid S. Miller 		       const char *irq_name, struct spu_queue *p,
14030a625fd2SDavid S. Miller 		       irq_handler_t handler)
14040a625fd2SDavid S. Miller {
14050a625fd2SDavid S. Miller 	unsigned long herr;
14060a625fd2SDavid S. Miller 	int index;
14070a625fd2SDavid S. Miller 
14080a625fd2SDavid S. Miller 	herr = sun4v_ncs_qhandle_to_devino(p->qhandle, &p->devino);
14090a625fd2SDavid S. Miller 	if (herr)
14100a625fd2SDavid S. Miller 		return -EINVAL;
14110a625fd2SDavid S. Miller 
14120a625fd2SDavid S. Miller 	index = find_devino_index(dev, ip, p->devino);
14130a625fd2SDavid S. Miller 	if (index < 0)
14140a625fd2SDavid S. Miller 		return index;
14150a625fd2SDavid S. Miller 
14160a625fd2SDavid S. Miller 	p->irq = dev->irqs[index];
14170a625fd2SDavid S. Miller 
14180a625fd2SDavid S. Miller 	sprintf(p->irq_name, "%s-%d", irq_name, index);
14190a625fd2SDavid S. Miller 
14200a625fd2SDavid S. Miller 	return request_irq(p->irq, handler, IRQF_SAMPLE_RANDOM,
14210a625fd2SDavid S. Miller 			   p->irq_name, p);
14220a625fd2SDavid S. Miller }
14230a625fd2SDavid S. Miller 
14240a625fd2SDavid S. Miller static struct kmem_cache *queue_cache[2];
14250a625fd2SDavid S. Miller 
14260a625fd2SDavid S. Miller static void *new_queue(unsigned long q_type)
14270a625fd2SDavid S. Miller {
14280a625fd2SDavid S. Miller 	return kmem_cache_zalloc(queue_cache[q_type - 1], GFP_KERNEL);
14290a625fd2SDavid S. Miller }
14300a625fd2SDavid S. Miller 
14310a625fd2SDavid S. Miller static void free_queue(void *p, unsigned long q_type)
14320a625fd2SDavid S. Miller {
14330a625fd2SDavid S. Miller 	return kmem_cache_free(queue_cache[q_type - 1], p);
14340a625fd2SDavid S. Miller }
14350a625fd2SDavid S. Miller 
14360a625fd2SDavid S. Miller static int queue_cache_init(void)
14370a625fd2SDavid S. Miller {
14380a625fd2SDavid S. Miller 	if (!queue_cache[HV_NCS_QTYPE_MAU - 1])
14390a625fd2SDavid S. Miller 		queue_cache[HV_NCS_QTYPE_MAU - 1] =
1440527b9525SDavid S. Miller 			kmem_cache_create("mau_queue",
14410a625fd2SDavid S. Miller 					  (MAU_NUM_ENTRIES *
14420a625fd2SDavid S. Miller 					   MAU_ENTRY_SIZE),
14430a625fd2SDavid S. Miller 					  MAU_ENTRY_SIZE, 0, NULL);
14440a625fd2SDavid S. Miller 	if (!queue_cache[HV_NCS_QTYPE_MAU - 1])
14450a625fd2SDavid S. Miller 		return -ENOMEM;
14460a625fd2SDavid S. Miller 
14470a625fd2SDavid S. Miller 	if (!queue_cache[HV_NCS_QTYPE_CWQ - 1])
14480a625fd2SDavid S. Miller 		queue_cache[HV_NCS_QTYPE_CWQ - 1] =
14490a625fd2SDavid S. Miller 			kmem_cache_create("cwq_queue",
14500a625fd2SDavid S. Miller 					  (CWQ_NUM_ENTRIES *
14510a625fd2SDavid S. Miller 					   CWQ_ENTRY_SIZE),
14520a625fd2SDavid S. Miller 					  CWQ_ENTRY_SIZE, 0, NULL);
14530a625fd2SDavid S. Miller 	if (!queue_cache[HV_NCS_QTYPE_CWQ - 1]) {
14540a625fd2SDavid S. Miller 		kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_MAU - 1]);
14550a625fd2SDavid S. Miller 		return -ENOMEM;
14560a625fd2SDavid S. Miller 	}
14570a625fd2SDavid S. Miller 	return 0;
14580a625fd2SDavid S. Miller }
14590a625fd2SDavid S. Miller 
14600a625fd2SDavid S. Miller static void queue_cache_destroy(void)
14610a625fd2SDavid S. Miller {
14620a625fd2SDavid S. Miller 	kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_MAU - 1]);
14630a625fd2SDavid S. Miller 	kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_CWQ - 1]);
14640a625fd2SDavid S. Miller }
14650a625fd2SDavid S. Miller 
14660a625fd2SDavid S. Miller static int spu_queue_register(struct spu_queue *p, unsigned long q_type)
14670a625fd2SDavid S. Miller {
14680a625fd2SDavid S. Miller 	cpumask_var_t old_allowed;
14690a625fd2SDavid S. Miller 	unsigned long hv_ret;
14700a625fd2SDavid S. Miller 
14710a625fd2SDavid S. Miller 	if (cpumask_empty(&p->sharing))
14720a625fd2SDavid S. Miller 		return -EINVAL;
14730a625fd2SDavid S. Miller 
14740a625fd2SDavid S. Miller 	if (!alloc_cpumask_var(&old_allowed, GFP_KERNEL))
14750a625fd2SDavid S. Miller 		return -ENOMEM;
14760a625fd2SDavid S. Miller 
14770a625fd2SDavid S. Miller 	cpumask_copy(old_allowed, &current->cpus_allowed);
14780a625fd2SDavid S. Miller 
14790a625fd2SDavid S. Miller 	set_cpus_allowed_ptr(current, &p->sharing);
14800a625fd2SDavid S. Miller 
14810a625fd2SDavid S. Miller 	hv_ret = sun4v_ncs_qconf(q_type, __pa(p->q),
14820a625fd2SDavid S. Miller 				 CWQ_NUM_ENTRIES, &p->qhandle);
14830a625fd2SDavid S. Miller 	if (!hv_ret)
14840a625fd2SDavid S. Miller 		sun4v_ncs_sethead_marker(p->qhandle, 0);
14850a625fd2SDavid S. Miller 
14860a625fd2SDavid S. Miller 	set_cpus_allowed_ptr(current, old_allowed);
14870a625fd2SDavid S. Miller 
14880a625fd2SDavid S. Miller 	free_cpumask_var(old_allowed);
14890a625fd2SDavid S. Miller 
14900a625fd2SDavid S. Miller 	return (hv_ret ? -EINVAL : 0);
14910a625fd2SDavid S. Miller }
14920a625fd2SDavid S. Miller 
14930a625fd2SDavid S. Miller static int spu_queue_setup(struct spu_queue *p)
14940a625fd2SDavid S. Miller {
14950a625fd2SDavid S. Miller 	int err;
14960a625fd2SDavid S. Miller 
14970a625fd2SDavid S. Miller 	p->q = new_queue(p->q_type);
14980a625fd2SDavid S. Miller 	if (!p->q)
14990a625fd2SDavid S. Miller 		return -ENOMEM;
15000a625fd2SDavid S. Miller 
15010a625fd2SDavid S. Miller 	err = spu_queue_register(p, p->q_type);
15020a625fd2SDavid S. Miller 	if (err) {
15030a625fd2SDavid S. Miller 		free_queue(p->q, p->q_type);
15040a625fd2SDavid S. Miller 		p->q = NULL;
15050a625fd2SDavid S. Miller 	}
15060a625fd2SDavid S. Miller 
15070a625fd2SDavid S. Miller 	return err;
15080a625fd2SDavid S. Miller }
15090a625fd2SDavid S. Miller 
15100a625fd2SDavid S. Miller static void spu_queue_destroy(struct spu_queue *p)
15110a625fd2SDavid S. Miller {
15120a625fd2SDavid S. Miller 	unsigned long hv_ret;
15130a625fd2SDavid S. Miller 
15140a625fd2SDavid S. Miller 	if (!p->q)
15150a625fd2SDavid S. Miller 		return;
15160a625fd2SDavid S. Miller 
15170a625fd2SDavid S. Miller 	hv_ret = sun4v_ncs_qconf(p->q_type, p->qhandle, 0, &p->qhandle);
15180a625fd2SDavid S. Miller 
15190a625fd2SDavid S. Miller 	if (!hv_ret)
15200a625fd2SDavid S. Miller 		free_queue(p->q, p->q_type);
15210a625fd2SDavid S. Miller }
15220a625fd2SDavid S. Miller 
15230a625fd2SDavid S. Miller static void spu_list_destroy(struct list_head *list)
15240a625fd2SDavid S. Miller {
15250a625fd2SDavid S. Miller 	struct spu_queue *p, *n;
15260a625fd2SDavid S. Miller 
15270a625fd2SDavid S. Miller 	list_for_each_entry_safe(p, n, list, list) {
15280a625fd2SDavid S. Miller 		int i;
15290a625fd2SDavid S. Miller 
15300a625fd2SDavid S. Miller 		for (i = 0; i < NR_CPUS; i++) {
15310a625fd2SDavid S. Miller 			if (cpu_to_cwq[i] == p)
15320a625fd2SDavid S. Miller 				cpu_to_cwq[i] = NULL;
15330a625fd2SDavid S. Miller 		}
15340a625fd2SDavid S. Miller 
15350a625fd2SDavid S. Miller 		if (p->irq) {
15360a625fd2SDavid S. Miller 			free_irq(p->irq, p);
15370a625fd2SDavid S. Miller 			p->irq = 0;
15380a625fd2SDavid S. Miller 		}
15390a625fd2SDavid S. Miller 		spu_queue_destroy(p);
15400a625fd2SDavid S. Miller 		list_del(&p->list);
15410a625fd2SDavid S. Miller 		kfree(p);
15420a625fd2SDavid S. Miller 	}
15430a625fd2SDavid S. Miller }
15440a625fd2SDavid S. Miller 
15450a625fd2SDavid S. Miller /* Walk the backward arcs of a CWQ 'exec-unit' node,
15460a625fd2SDavid S. Miller  * gathering cpu membership information.
15470a625fd2SDavid S. Miller  */
15480a625fd2SDavid S. Miller static int spu_mdesc_walk_arcs(struct mdesc_handle *mdesc,
15490a625fd2SDavid S. Miller 			       struct of_device *dev,
15500a625fd2SDavid S. Miller 			       u64 node, struct spu_queue *p,
15510a625fd2SDavid S. Miller 			       struct spu_queue **table)
15520a625fd2SDavid S. Miller {
15530a625fd2SDavid S. Miller 	u64 arc;
15540a625fd2SDavid S. Miller 
15550a625fd2SDavid S. Miller 	mdesc_for_each_arc(arc, mdesc, node, MDESC_ARC_TYPE_BACK) {
15560a625fd2SDavid S. Miller 		u64 tgt = mdesc_arc_target(mdesc, arc);
15570a625fd2SDavid S. Miller 		const char *name = mdesc_node_name(mdesc, tgt);
15580a625fd2SDavid S. Miller 		const u64 *id;
15590a625fd2SDavid S. Miller 
15600a625fd2SDavid S. Miller 		if (strcmp(name, "cpu"))
15610a625fd2SDavid S. Miller 			continue;
15620a625fd2SDavid S. Miller 		id = mdesc_get_property(mdesc, tgt, "id", NULL);
15630a625fd2SDavid S. Miller 		if (table[*id] != NULL) {
15640a625fd2SDavid S. Miller 			dev_err(&dev->dev, "%s: SPU cpu slot already set.\n",
1565ff6c7341SDavid S. Miller 				dev->dev.of_node->full_name);
15660a625fd2SDavid S. Miller 			return -EINVAL;
15670a625fd2SDavid S. Miller 		}
15680a625fd2SDavid S. Miller 		cpu_set(*id, p->sharing);
15690a625fd2SDavid S. Miller 		table[*id] = p;
15700a625fd2SDavid S. Miller 	}
15710a625fd2SDavid S. Miller 	return 0;
15720a625fd2SDavid S. Miller }
15730a625fd2SDavid S. Miller 
15740a625fd2SDavid S. Miller /* Process an 'exec-unit' MDESC node of type 'cwq'.  */
15750a625fd2SDavid S. Miller static int handle_exec_unit(struct spu_mdesc_info *ip, struct list_head *list,
15760a625fd2SDavid S. Miller 			    struct of_device *dev, struct mdesc_handle *mdesc,
15770a625fd2SDavid S. Miller 			    u64 node, const char *iname, unsigned long q_type,
15780a625fd2SDavid S. Miller 			    irq_handler_t handler, struct spu_queue **table)
15790a625fd2SDavid S. Miller {
15800a625fd2SDavid S. Miller 	struct spu_queue *p;
15810a625fd2SDavid S. Miller 	int err;
15820a625fd2SDavid S. Miller 
15830a625fd2SDavid S. Miller 	p = kzalloc(sizeof(struct spu_queue), GFP_KERNEL);
15840a625fd2SDavid S. Miller 	if (!p) {
15850a625fd2SDavid S. Miller 		dev_err(&dev->dev, "%s: Could not allocate SPU queue.\n",
1586ff6c7341SDavid S. Miller 			dev->dev.of_node->full_name);
15870a625fd2SDavid S. Miller 		return -ENOMEM;
15880a625fd2SDavid S. Miller 	}
15890a625fd2SDavid S. Miller 
15900a625fd2SDavid S. Miller 	cpus_clear(p->sharing);
15910a625fd2SDavid S. Miller 	spin_lock_init(&p->lock);
15920a625fd2SDavid S. Miller 	p->q_type = q_type;
15930a625fd2SDavid S. Miller 	INIT_LIST_HEAD(&p->jobs);
15940a625fd2SDavid S. Miller 	list_add(&p->list, list);
15950a625fd2SDavid S. Miller 
15960a625fd2SDavid S. Miller 	err = spu_mdesc_walk_arcs(mdesc, dev, node, p, table);
15970a625fd2SDavid S. Miller 	if (err)
15980a625fd2SDavid S. Miller 		return err;
15990a625fd2SDavid S. Miller 
16000a625fd2SDavid S. Miller 	err = spu_queue_setup(p);
16010a625fd2SDavid S. Miller 	if (err)
16020a625fd2SDavid S. Miller 		return err;
16030a625fd2SDavid S. Miller 
16040a625fd2SDavid S. Miller 	return spu_map_ino(dev, ip, iname, p, handler);
16050a625fd2SDavid S. Miller }
16060a625fd2SDavid S. Miller 
16070a625fd2SDavid S. Miller static int spu_mdesc_scan(struct mdesc_handle *mdesc, struct of_device *dev,
16080a625fd2SDavid S. Miller 			  struct spu_mdesc_info *ip, struct list_head *list,
16090a625fd2SDavid S. Miller 			  const char *exec_name, unsigned long q_type,
16100a625fd2SDavid S. Miller 			  irq_handler_t handler, struct spu_queue **table)
16110a625fd2SDavid S. Miller {
16120a625fd2SDavid S. Miller 	int err = 0;
16130a625fd2SDavid S. Miller 	u64 node;
16140a625fd2SDavid S. Miller 
16150a625fd2SDavid S. Miller 	mdesc_for_each_node_by_name(mdesc, node, "exec-unit") {
16160a625fd2SDavid S. Miller 		const char *type;
16170a625fd2SDavid S. Miller 
16180a625fd2SDavid S. Miller 		type = mdesc_get_property(mdesc, node, "type", NULL);
16190a625fd2SDavid S. Miller 		if (!type || strcmp(type, exec_name))
16200a625fd2SDavid S. Miller 			continue;
16210a625fd2SDavid S. Miller 
16220a625fd2SDavid S. Miller 		err = handle_exec_unit(ip, list, dev, mdesc, node,
16230a625fd2SDavid S. Miller 				       exec_name, q_type, handler, table);
16240a625fd2SDavid S. Miller 		if (err) {
16250a625fd2SDavid S. Miller 			spu_list_destroy(list);
16260a625fd2SDavid S. Miller 			break;
16270a625fd2SDavid S. Miller 		}
16280a625fd2SDavid S. Miller 	}
16290a625fd2SDavid S. Miller 
16300a625fd2SDavid S. Miller 	return err;
16310a625fd2SDavid S. Miller }
16320a625fd2SDavid S. Miller 
16330a625fd2SDavid S. Miller static int __devinit get_irq_props(struct mdesc_handle *mdesc, u64 node,
16340a625fd2SDavid S. Miller 				   struct spu_mdesc_info *ip)
16350a625fd2SDavid S. Miller {
16360a625fd2SDavid S. Miller 	const u64 *intr, *ino;
16370a625fd2SDavid S. Miller 	int intr_len, ino_len;
16380a625fd2SDavid S. Miller 	int i;
16390a625fd2SDavid S. Miller 
16400a625fd2SDavid S. Miller 	intr = mdesc_get_property(mdesc, node, "intr", &intr_len);
16410a625fd2SDavid S. Miller 	if (!intr)
16420a625fd2SDavid S. Miller 		return -ENODEV;
16430a625fd2SDavid S. Miller 
16440a625fd2SDavid S. Miller 	ino = mdesc_get_property(mdesc, node, "ino", &ino_len);
16450a625fd2SDavid S. Miller 	if (!intr)
16460a625fd2SDavid S. Miller 		return -ENODEV;
16470a625fd2SDavid S. Miller 
16480a625fd2SDavid S. Miller 	if (intr_len != ino_len)
16490a625fd2SDavid S. Miller 		return -EINVAL;
16500a625fd2SDavid S. Miller 
16510a625fd2SDavid S. Miller 	ip->num_intrs = intr_len / sizeof(u64);
16520a625fd2SDavid S. Miller 	ip->ino_table = kzalloc((sizeof(struct ino_blob) *
16530a625fd2SDavid S. Miller 				 ip->num_intrs),
16540a625fd2SDavid S. Miller 				GFP_KERNEL);
16550a625fd2SDavid S. Miller 	if (!ip->ino_table)
16560a625fd2SDavid S. Miller 		return -ENOMEM;
16570a625fd2SDavid S. Miller 
16580a625fd2SDavid S. Miller 	for (i = 0; i < ip->num_intrs; i++) {
16590a625fd2SDavid S. Miller 		struct ino_blob *b = &ip->ino_table[i];
16600a625fd2SDavid S. Miller 		b->intr = intr[i];
16610a625fd2SDavid S. Miller 		b->ino = ino[i];
16620a625fd2SDavid S. Miller 	}
16630a625fd2SDavid S. Miller 
16640a625fd2SDavid S. Miller 	return 0;
16650a625fd2SDavid S. Miller }
16660a625fd2SDavid S. Miller 
16670a625fd2SDavid S. Miller static int __devinit grab_mdesc_irq_props(struct mdesc_handle *mdesc,
16680a625fd2SDavid S. Miller 					  struct of_device *dev,
16690a625fd2SDavid S. Miller 					  struct spu_mdesc_info *ip,
16700a625fd2SDavid S. Miller 					  const char *node_name)
16710a625fd2SDavid S. Miller {
16720a625fd2SDavid S. Miller 	const unsigned int *reg;
16730a625fd2SDavid S. Miller 	u64 node;
16740a625fd2SDavid S. Miller 
1675ff6c7341SDavid S. Miller 	reg = of_get_property(dev->dev.of_node, "reg", NULL);
16760a625fd2SDavid S. Miller 	if (!reg)
16770a625fd2SDavid S. Miller 		return -ENODEV;
16780a625fd2SDavid S. Miller 
16790a625fd2SDavid S. Miller 	mdesc_for_each_node_by_name(mdesc, node, "virtual-device") {
16800a625fd2SDavid S. Miller 		const char *name;
16810a625fd2SDavid S. Miller 		const u64 *chdl;
16820a625fd2SDavid S. Miller 
16830a625fd2SDavid S. Miller 		name = mdesc_get_property(mdesc, node, "name", NULL);
16840a625fd2SDavid S. Miller 		if (!name || strcmp(name, node_name))
16850a625fd2SDavid S. Miller 			continue;
16860a625fd2SDavid S. Miller 		chdl = mdesc_get_property(mdesc, node, "cfg-handle", NULL);
16870a625fd2SDavid S. Miller 		if (!chdl || (*chdl != *reg))
16880a625fd2SDavid S. Miller 			continue;
16890a625fd2SDavid S. Miller 		ip->cfg_handle = *chdl;
16900a625fd2SDavid S. Miller 		return get_irq_props(mdesc, node, ip);
16910a625fd2SDavid S. Miller 	}
16920a625fd2SDavid S. Miller 
16930a625fd2SDavid S. Miller 	return -ENODEV;
16940a625fd2SDavid S. Miller }
16950a625fd2SDavid S. Miller 
16960a625fd2SDavid S. Miller static unsigned long n2_spu_hvapi_major;
16970a625fd2SDavid S. Miller static unsigned long n2_spu_hvapi_minor;
16980a625fd2SDavid S. Miller 
16990a625fd2SDavid S. Miller static int __devinit n2_spu_hvapi_register(void)
17000a625fd2SDavid S. Miller {
17010a625fd2SDavid S. Miller 	int err;
17020a625fd2SDavid S. Miller 
17030a625fd2SDavid S. Miller 	n2_spu_hvapi_major = 2;
17040a625fd2SDavid S. Miller 	n2_spu_hvapi_minor = 0;
17050a625fd2SDavid S. Miller 
17060a625fd2SDavid S. Miller 	err = sun4v_hvapi_register(HV_GRP_NCS,
17070a625fd2SDavid S. Miller 				   n2_spu_hvapi_major,
17080a625fd2SDavid S. Miller 				   &n2_spu_hvapi_minor);
17090a625fd2SDavid S. Miller 
17100a625fd2SDavid S. Miller 	if (!err)
17110a625fd2SDavid S. Miller 		pr_info("Registered NCS HVAPI version %lu.%lu\n",
17120a625fd2SDavid S. Miller 			n2_spu_hvapi_major,
17130a625fd2SDavid S. Miller 			n2_spu_hvapi_minor);
17140a625fd2SDavid S. Miller 
17150a625fd2SDavid S. Miller 	return err;
17160a625fd2SDavid S. Miller }
17170a625fd2SDavid S. Miller 
17180a625fd2SDavid S. Miller static void n2_spu_hvapi_unregister(void)
17190a625fd2SDavid S. Miller {
17200a625fd2SDavid S. Miller 	sun4v_hvapi_unregister(HV_GRP_NCS);
17210a625fd2SDavid S. Miller }
17220a625fd2SDavid S. Miller 
17230a625fd2SDavid S. Miller static int global_ref;
17240a625fd2SDavid S. Miller 
17250a625fd2SDavid S. Miller static int __devinit grab_global_resources(void)
17260a625fd2SDavid S. Miller {
17270a625fd2SDavid S. Miller 	int err = 0;
17280a625fd2SDavid S. Miller 
17290a625fd2SDavid S. Miller 	mutex_lock(&spu_lock);
17300a625fd2SDavid S. Miller 
17310a625fd2SDavid S. Miller 	if (global_ref++)
17320a625fd2SDavid S. Miller 		goto out;
17330a625fd2SDavid S. Miller 
17340a625fd2SDavid S. Miller 	err = n2_spu_hvapi_register();
17350a625fd2SDavid S. Miller 	if (err)
17360a625fd2SDavid S. Miller 		goto out;
17370a625fd2SDavid S. Miller 
17380a625fd2SDavid S. Miller 	err = queue_cache_init();
17390a625fd2SDavid S. Miller 	if (err)
17400a625fd2SDavid S. Miller 		goto out_hvapi_release;
17410a625fd2SDavid S. Miller 
17420a625fd2SDavid S. Miller 	err = -ENOMEM;
17430a625fd2SDavid S. Miller 	cpu_to_cwq = kzalloc(sizeof(struct spu_queue *) * NR_CPUS,
17440a625fd2SDavid S. Miller 			     GFP_KERNEL);
17450a625fd2SDavid S. Miller 	if (!cpu_to_cwq)
17460a625fd2SDavid S. Miller 		goto out_queue_cache_destroy;
17470a625fd2SDavid S. Miller 
17480a625fd2SDavid S. Miller 	cpu_to_mau = kzalloc(sizeof(struct spu_queue *) * NR_CPUS,
17490a625fd2SDavid S. Miller 			     GFP_KERNEL);
17500a625fd2SDavid S. Miller 	if (!cpu_to_mau)
17510a625fd2SDavid S. Miller 		goto out_free_cwq_table;
17520a625fd2SDavid S. Miller 
17530a625fd2SDavid S. Miller 	err = 0;
17540a625fd2SDavid S. Miller 
17550a625fd2SDavid S. Miller out:
17560a625fd2SDavid S. Miller 	if (err)
17570a625fd2SDavid S. Miller 		global_ref--;
17580a625fd2SDavid S. Miller 	mutex_unlock(&spu_lock);
17590a625fd2SDavid S. Miller 	return err;
17600a625fd2SDavid S. Miller 
17610a625fd2SDavid S. Miller out_free_cwq_table:
17620a625fd2SDavid S. Miller 	kfree(cpu_to_cwq);
17630a625fd2SDavid S. Miller 	cpu_to_cwq = NULL;
17640a625fd2SDavid S. Miller 
17650a625fd2SDavid S. Miller out_queue_cache_destroy:
17660a625fd2SDavid S. Miller 	queue_cache_destroy();
17670a625fd2SDavid S. Miller 
17680a625fd2SDavid S. Miller out_hvapi_release:
17690a625fd2SDavid S. Miller 	n2_spu_hvapi_unregister();
17700a625fd2SDavid S. Miller 	goto out;
17710a625fd2SDavid S. Miller }
17720a625fd2SDavid S. Miller 
17730a625fd2SDavid S. Miller static void release_global_resources(void)
17740a625fd2SDavid S. Miller {
17750a625fd2SDavid S. Miller 	mutex_lock(&spu_lock);
17760a625fd2SDavid S. Miller 	if (!--global_ref) {
17770a625fd2SDavid S. Miller 		kfree(cpu_to_cwq);
17780a625fd2SDavid S. Miller 		cpu_to_cwq = NULL;
17790a625fd2SDavid S. Miller 
17800a625fd2SDavid S. Miller 		kfree(cpu_to_mau);
17810a625fd2SDavid S. Miller 		cpu_to_mau = NULL;
17820a625fd2SDavid S. Miller 
17830a625fd2SDavid S. Miller 		queue_cache_destroy();
17840a625fd2SDavid S. Miller 		n2_spu_hvapi_unregister();
17850a625fd2SDavid S. Miller 	}
17860a625fd2SDavid S. Miller 	mutex_unlock(&spu_lock);
17870a625fd2SDavid S. Miller }
17880a625fd2SDavid S. Miller 
17890a625fd2SDavid S. Miller static struct n2_crypto * __devinit alloc_n2cp(void)
17900a625fd2SDavid S. Miller {
17910a625fd2SDavid S. Miller 	struct n2_crypto *np = kzalloc(sizeof(struct n2_crypto), GFP_KERNEL);
17920a625fd2SDavid S. Miller 
17930a625fd2SDavid S. Miller 	if (np)
17940a625fd2SDavid S. Miller 		INIT_LIST_HEAD(&np->cwq_list);
17950a625fd2SDavid S. Miller 
17960a625fd2SDavid S. Miller 	return np;
17970a625fd2SDavid S. Miller }
17980a625fd2SDavid S. Miller 
17990a625fd2SDavid S. Miller static void free_n2cp(struct n2_crypto *np)
18000a625fd2SDavid S. Miller {
18010a625fd2SDavid S. Miller 	if (np->cwq_info.ino_table) {
18020a625fd2SDavid S. Miller 		kfree(np->cwq_info.ino_table);
18030a625fd2SDavid S. Miller 		np->cwq_info.ino_table = NULL;
18040a625fd2SDavid S. Miller 	}
18050a625fd2SDavid S. Miller 
18060a625fd2SDavid S. Miller 	kfree(np);
18070a625fd2SDavid S. Miller }
18080a625fd2SDavid S. Miller 
18090a625fd2SDavid S. Miller static void __devinit n2_spu_driver_version(void)
18100a625fd2SDavid S. Miller {
18110a625fd2SDavid S. Miller 	static int n2_spu_version_printed;
18120a625fd2SDavid S. Miller 
18130a625fd2SDavid S. Miller 	if (n2_spu_version_printed++ == 0)
18140a625fd2SDavid S. Miller 		pr_info("%s", version);
18150a625fd2SDavid S. Miller }
18160a625fd2SDavid S. Miller 
18170a625fd2SDavid S. Miller static int __devinit n2_crypto_probe(struct of_device *dev,
18180a625fd2SDavid S. Miller 				     const struct of_device_id *match)
18190a625fd2SDavid S. Miller {
18200a625fd2SDavid S. Miller 	struct mdesc_handle *mdesc;
18210a625fd2SDavid S. Miller 	const char *full_name;
18220a625fd2SDavid S. Miller 	struct n2_crypto *np;
18230a625fd2SDavid S. Miller 	int err;
18240a625fd2SDavid S. Miller 
18250a625fd2SDavid S. Miller 	n2_spu_driver_version();
18260a625fd2SDavid S. Miller 
1827ff6c7341SDavid S. Miller 	full_name = dev->dev.of_node->full_name;
18280a625fd2SDavid S. Miller 	pr_info("Found N2CP at %s\n", full_name);
18290a625fd2SDavid S. Miller 
18300a625fd2SDavid S. Miller 	np = alloc_n2cp();
18310a625fd2SDavid S. Miller 	if (!np) {
18320a625fd2SDavid S. Miller 		dev_err(&dev->dev, "%s: Unable to allocate n2cp.\n",
18330a625fd2SDavid S. Miller 			full_name);
18340a625fd2SDavid S. Miller 		return -ENOMEM;
18350a625fd2SDavid S. Miller 	}
18360a625fd2SDavid S. Miller 
18370a625fd2SDavid S. Miller 	err = grab_global_resources();
18380a625fd2SDavid S. Miller 	if (err) {
18390a625fd2SDavid S. Miller 		dev_err(&dev->dev, "%s: Unable to grab "
18400a625fd2SDavid S. Miller 			"global resources.\n", full_name);
18410a625fd2SDavid S. Miller 		goto out_free_n2cp;
18420a625fd2SDavid S. Miller 	}
18430a625fd2SDavid S. Miller 
18440a625fd2SDavid S. Miller 	mdesc = mdesc_grab();
18450a625fd2SDavid S. Miller 
18460a625fd2SDavid S. Miller 	if (!mdesc) {
18470a625fd2SDavid S. Miller 		dev_err(&dev->dev, "%s: Unable to grab MDESC.\n",
18480a625fd2SDavid S. Miller 			full_name);
18490a625fd2SDavid S. Miller 		err = -ENODEV;
18500a625fd2SDavid S. Miller 		goto out_free_global;
18510a625fd2SDavid S. Miller 	}
18520a625fd2SDavid S. Miller 	err = grab_mdesc_irq_props(mdesc, dev, &np->cwq_info, "n2cp");
18530a625fd2SDavid S. Miller 	if (err) {
18540a625fd2SDavid S. Miller 		dev_err(&dev->dev, "%s: Unable to grab IRQ props.\n",
18550a625fd2SDavid S. Miller 			full_name);
18560a625fd2SDavid S. Miller 		mdesc_release(mdesc);
18570a625fd2SDavid S. Miller 		goto out_free_global;
18580a625fd2SDavid S. Miller 	}
18590a625fd2SDavid S. Miller 
18600a625fd2SDavid S. Miller 	err = spu_mdesc_scan(mdesc, dev, &np->cwq_info, &np->cwq_list,
18610a625fd2SDavid S. Miller 			     "cwq", HV_NCS_QTYPE_CWQ, cwq_intr,
18620a625fd2SDavid S. Miller 			     cpu_to_cwq);
18630a625fd2SDavid S. Miller 	mdesc_release(mdesc);
18640a625fd2SDavid S. Miller 
18650a625fd2SDavid S. Miller 	if (err) {
18660a625fd2SDavid S. Miller 		dev_err(&dev->dev, "%s: CWQ MDESC scan failed.\n",
18670a625fd2SDavid S. Miller 			full_name);
18680a625fd2SDavid S. Miller 		goto out_free_global;
18690a625fd2SDavid S. Miller 	}
18700a625fd2SDavid S. Miller 
18710a625fd2SDavid S. Miller 	err = n2_register_algs();
18720a625fd2SDavid S. Miller 	if (err) {
18730a625fd2SDavid S. Miller 		dev_err(&dev->dev, "%s: Unable to register algorithms.\n",
18740a625fd2SDavid S. Miller 			full_name);
18750a625fd2SDavid S. Miller 		goto out_free_spu_list;
18760a625fd2SDavid S. Miller 	}
18770a625fd2SDavid S. Miller 
18780a625fd2SDavid S. Miller 	dev_set_drvdata(&dev->dev, np);
18790a625fd2SDavid S. Miller 
18800a625fd2SDavid S. Miller 	return 0;
18810a625fd2SDavid S. Miller 
18820a625fd2SDavid S. Miller out_free_spu_list:
18830a625fd2SDavid S. Miller 	spu_list_destroy(&np->cwq_list);
18840a625fd2SDavid S. Miller 
18850a625fd2SDavid S. Miller out_free_global:
18860a625fd2SDavid S. Miller 	release_global_resources();
18870a625fd2SDavid S. Miller 
18880a625fd2SDavid S. Miller out_free_n2cp:
18890a625fd2SDavid S. Miller 	free_n2cp(np);
18900a625fd2SDavid S. Miller 
18910a625fd2SDavid S. Miller 	return err;
18920a625fd2SDavid S. Miller }
18930a625fd2SDavid S. Miller 
18940a625fd2SDavid S. Miller static int __devexit n2_crypto_remove(struct of_device *dev)
18950a625fd2SDavid S. Miller {
18960a625fd2SDavid S. Miller 	struct n2_crypto *np = dev_get_drvdata(&dev->dev);
18970a625fd2SDavid S. Miller 
18980a625fd2SDavid S. Miller 	n2_unregister_algs();
18990a625fd2SDavid S. Miller 
19000a625fd2SDavid S. Miller 	spu_list_destroy(&np->cwq_list);
19010a625fd2SDavid S. Miller 
19020a625fd2SDavid S. Miller 	release_global_resources();
19030a625fd2SDavid S. Miller 
19040a625fd2SDavid S. Miller 	free_n2cp(np);
19050a625fd2SDavid S. Miller 
19060a625fd2SDavid S. Miller 	return 0;
19070a625fd2SDavid S. Miller }
19080a625fd2SDavid S. Miller 
19090a625fd2SDavid S. Miller static struct n2_mau * __devinit alloc_ncp(void)
19100a625fd2SDavid S. Miller {
19110a625fd2SDavid S. Miller 	struct n2_mau *mp = kzalloc(sizeof(struct n2_mau), GFP_KERNEL);
19120a625fd2SDavid S. Miller 
19130a625fd2SDavid S. Miller 	if (mp)
19140a625fd2SDavid S. Miller 		INIT_LIST_HEAD(&mp->mau_list);
19150a625fd2SDavid S. Miller 
19160a625fd2SDavid S. Miller 	return mp;
19170a625fd2SDavid S. Miller }
19180a625fd2SDavid S. Miller 
19190a625fd2SDavid S. Miller static void free_ncp(struct n2_mau *mp)
19200a625fd2SDavid S. Miller {
19210a625fd2SDavid S. Miller 	if (mp->mau_info.ino_table) {
19220a625fd2SDavid S. Miller 		kfree(mp->mau_info.ino_table);
19230a625fd2SDavid S. Miller 		mp->mau_info.ino_table = NULL;
19240a625fd2SDavid S. Miller 	}
19250a625fd2SDavid S. Miller 
19260a625fd2SDavid S. Miller 	kfree(mp);
19270a625fd2SDavid S. Miller }
19280a625fd2SDavid S. Miller 
19290a625fd2SDavid S. Miller static int __devinit n2_mau_probe(struct of_device *dev,
19300a625fd2SDavid S. Miller 				     const struct of_device_id *match)
19310a625fd2SDavid S. Miller {
19320a625fd2SDavid S. Miller 	struct mdesc_handle *mdesc;
19330a625fd2SDavid S. Miller 	const char *full_name;
19340a625fd2SDavid S. Miller 	struct n2_mau *mp;
19350a625fd2SDavid S. Miller 	int err;
19360a625fd2SDavid S. Miller 
19370a625fd2SDavid S. Miller 	n2_spu_driver_version();
19380a625fd2SDavid S. Miller 
1939ff6c7341SDavid S. Miller 	full_name = dev->dev.of_node->full_name;
19400a625fd2SDavid S. Miller 	pr_info("Found NCP at %s\n", full_name);
19410a625fd2SDavid S. Miller 
19420a625fd2SDavid S. Miller 	mp = alloc_ncp();
19430a625fd2SDavid S. Miller 	if (!mp) {
19440a625fd2SDavid S. Miller 		dev_err(&dev->dev, "%s: Unable to allocate ncp.\n",
19450a625fd2SDavid S. Miller 			full_name);
19460a625fd2SDavid S. Miller 		return -ENOMEM;
19470a625fd2SDavid S. Miller 	}
19480a625fd2SDavid S. Miller 
19490a625fd2SDavid S. Miller 	err = grab_global_resources();
19500a625fd2SDavid S. Miller 	if (err) {
19510a625fd2SDavid S. Miller 		dev_err(&dev->dev, "%s: Unable to grab "
19520a625fd2SDavid S. Miller 			"global resources.\n", full_name);
19530a625fd2SDavid S. Miller 		goto out_free_ncp;
19540a625fd2SDavid S. Miller 	}
19550a625fd2SDavid S. Miller 
19560a625fd2SDavid S. Miller 	mdesc = mdesc_grab();
19570a625fd2SDavid S. Miller 
19580a625fd2SDavid S. Miller 	if (!mdesc) {
19590a625fd2SDavid S. Miller 		dev_err(&dev->dev, "%s: Unable to grab MDESC.\n",
19600a625fd2SDavid S. Miller 			full_name);
19610a625fd2SDavid S. Miller 		err = -ENODEV;
19620a625fd2SDavid S. Miller 		goto out_free_global;
19630a625fd2SDavid S. Miller 	}
19640a625fd2SDavid S. Miller 
19650a625fd2SDavid S. Miller 	err = grab_mdesc_irq_props(mdesc, dev, &mp->mau_info, "ncp");
19660a625fd2SDavid S. Miller 	if (err) {
19670a625fd2SDavid S. Miller 		dev_err(&dev->dev, "%s: Unable to grab IRQ props.\n",
19680a625fd2SDavid S. Miller 			full_name);
19690a625fd2SDavid S. Miller 		mdesc_release(mdesc);
19700a625fd2SDavid S. Miller 		goto out_free_global;
19710a625fd2SDavid S. Miller 	}
19720a625fd2SDavid S. Miller 
19730a625fd2SDavid S. Miller 	err = spu_mdesc_scan(mdesc, dev, &mp->mau_info, &mp->mau_list,
19740a625fd2SDavid S. Miller 			     "mau", HV_NCS_QTYPE_MAU, mau_intr,
19750a625fd2SDavid S. Miller 			     cpu_to_mau);
19760a625fd2SDavid S. Miller 	mdesc_release(mdesc);
19770a625fd2SDavid S. Miller 
19780a625fd2SDavid S. Miller 	if (err) {
19790a625fd2SDavid S. Miller 		dev_err(&dev->dev, "%s: MAU MDESC scan failed.\n",
19800a625fd2SDavid S. Miller 			full_name);
19810a625fd2SDavid S. Miller 		goto out_free_global;
19820a625fd2SDavid S. Miller 	}
19830a625fd2SDavid S. Miller 
19840a625fd2SDavid S. Miller 	dev_set_drvdata(&dev->dev, mp);
19850a625fd2SDavid S. Miller 
19860a625fd2SDavid S. Miller 	return 0;
19870a625fd2SDavid S. Miller 
19880a625fd2SDavid S. Miller out_free_global:
19890a625fd2SDavid S. Miller 	release_global_resources();
19900a625fd2SDavid S. Miller 
19910a625fd2SDavid S. Miller out_free_ncp:
19920a625fd2SDavid S. Miller 	free_ncp(mp);
19930a625fd2SDavid S. Miller 
19940a625fd2SDavid S. Miller 	return err;
19950a625fd2SDavid S. Miller }
19960a625fd2SDavid S. Miller 
19970a625fd2SDavid S. Miller static int __devexit n2_mau_remove(struct of_device *dev)
19980a625fd2SDavid S. Miller {
19990a625fd2SDavid S. Miller 	struct n2_mau *mp = dev_get_drvdata(&dev->dev);
20000a625fd2SDavid S. Miller 
20010a625fd2SDavid S. Miller 	spu_list_destroy(&mp->mau_list);
20020a625fd2SDavid S. Miller 
20030a625fd2SDavid S. Miller 	release_global_resources();
20040a625fd2SDavid S. Miller 
20050a625fd2SDavid S. Miller 	free_ncp(mp);
20060a625fd2SDavid S. Miller 
20070a625fd2SDavid S. Miller 	return 0;
20080a625fd2SDavid S. Miller }
20090a625fd2SDavid S. Miller 
20100a625fd2SDavid S. Miller static struct of_device_id n2_crypto_match[] = {
20110a625fd2SDavid S. Miller 	{
20120a625fd2SDavid S. Miller 		.name = "n2cp",
20130a625fd2SDavid S. Miller 		.compatible = "SUNW,n2-cwq",
20140a625fd2SDavid S. Miller 	},
20150a625fd2SDavid S. Miller 	{
20160a625fd2SDavid S. Miller 		.name = "n2cp",
20170a625fd2SDavid S. Miller 		.compatible = "SUNW,vf-cwq",
20180a625fd2SDavid S. Miller 	},
20190a625fd2SDavid S. Miller 	{},
20200a625fd2SDavid S. Miller };
20210a625fd2SDavid S. Miller 
20220a625fd2SDavid S. Miller MODULE_DEVICE_TABLE(of, n2_crypto_match);
20230a625fd2SDavid S. Miller 
20240a625fd2SDavid S. Miller static struct of_platform_driver n2_crypto_driver = {
2025ff6c7341SDavid S. Miller 	.driver = {
20260a625fd2SDavid S. Miller 		.name		=	"n2cp",
2027ff6c7341SDavid S. Miller 		.owner		=	THIS_MODULE,
2028ff6c7341SDavid S. Miller 		.of_match_table	=	n2_crypto_match,
2029ff6c7341SDavid S. Miller 	},
20300a625fd2SDavid S. Miller 	.probe		=	n2_crypto_probe,
20310a625fd2SDavid S. Miller 	.remove		=	__devexit_p(n2_crypto_remove),
20320a625fd2SDavid S. Miller };
20330a625fd2SDavid S. Miller 
20340a625fd2SDavid S. Miller static struct of_device_id n2_mau_match[] = {
20350a625fd2SDavid S. Miller 	{
20360a625fd2SDavid S. Miller 		.name = "ncp",
20370a625fd2SDavid S. Miller 		.compatible = "SUNW,n2-mau",
20380a625fd2SDavid S. Miller 	},
20390a625fd2SDavid S. Miller 	{
20400a625fd2SDavid S. Miller 		.name = "ncp",
20410a625fd2SDavid S. Miller 		.compatible = "SUNW,vf-mau",
20420a625fd2SDavid S. Miller 	},
20430a625fd2SDavid S. Miller 	{},
20440a625fd2SDavid S. Miller };
20450a625fd2SDavid S. Miller 
20460a625fd2SDavid S. Miller MODULE_DEVICE_TABLE(of, n2_mau_match);
20470a625fd2SDavid S. Miller 
20480a625fd2SDavid S. Miller static struct of_platform_driver n2_mau_driver = {
2049ff6c7341SDavid S. Miller 	.driver = {
20500a625fd2SDavid S. Miller 		.name		=	"ncp",
2051ff6c7341SDavid S. Miller 		.owner		=	THIS_MODULE,
2052ff6c7341SDavid S. Miller 		.of_match_table	=	n2_mau_match,
2053ff6c7341SDavid S. Miller 	},
20540a625fd2SDavid S. Miller 	.probe		=	n2_mau_probe,
20550a625fd2SDavid S. Miller 	.remove		=	__devexit_p(n2_mau_remove),
20560a625fd2SDavid S. Miller };
20570a625fd2SDavid S. Miller 
20580a625fd2SDavid S. Miller static int __init n2_init(void)
20590a625fd2SDavid S. Miller {
20600a625fd2SDavid S. Miller 	int err = of_register_driver(&n2_crypto_driver, &of_bus_type);
20610a625fd2SDavid S. Miller 
20620a625fd2SDavid S. Miller 	if (!err) {
20630a625fd2SDavid S. Miller 		err = of_register_driver(&n2_mau_driver, &of_bus_type);
20640a625fd2SDavid S. Miller 		if (err)
20650a625fd2SDavid S. Miller 			of_unregister_driver(&n2_crypto_driver);
20660a625fd2SDavid S. Miller 	}
20670a625fd2SDavid S. Miller 	return err;
20680a625fd2SDavid S. Miller }
20690a625fd2SDavid S. Miller 
20700a625fd2SDavid S. Miller static void __exit n2_exit(void)
20710a625fd2SDavid S. Miller {
20720a625fd2SDavid S. Miller 	of_unregister_driver(&n2_mau_driver);
20730a625fd2SDavid S. Miller 	of_unregister_driver(&n2_crypto_driver);
20740a625fd2SDavid S. Miller }
20750a625fd2SDavid S. Miller 
20760a625fd2SDavid S. Miller module_init(n2_init);
20770a625fd2SDavid S. Miller module_exit(n2_exit);
2078