162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* n2_core.c: Niagara2 Stream Processing Unit (SPU) crypto support. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2010, 2011 David S. Miller <davem@davemloft.net> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/of.h> 1262306a36Sopenharmony_ci#include <linux/of_address.h> 1362306a36Sopenharmony_ci#include <linux/platform_device.h> 1462306a36Sopenharmony_ci#include <linux/cpumask.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/interrupt.h> 1762306a36Sopenharmony_ci#include <linux/crypto.h> 1862306a36Sopenharmony_ci#include <crypto/md5.h> 1962306a36Sopenharmony_ci#include <crypto/sha1.h> 2062306a36Sopenharmony_ci#include <crypto/sha2.h> 2162306a36Sopenharmony_ci#include <crypto/aes.h> 2262306a36Sopenharmony_ci#include <crypto/internal/des.h> 2362306a36Sopenharmony_ci#include <linux/mutex.h> 2462306a36Sopenharmony_ci#include <linux/delay.h> 2562306a36Sopenharmony_ci#include <linux/sched.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <crypto/internal/hash.h> 2862306a36Sopenharmony_ci#include <crypto/internal/skcipher.h> 2962306a36Sopenharmony_ci#include <crypto/scatterwalk.h> 3062306a36Sopenharmony_ci#include <crypto/algapi.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include <asm/hypervisor.h> 3362306a36Sopenharmony_ci#include <asm/mdesc.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include "n2_core.h" 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define DRV_MODULE_NAME "n2_crypto" 3862306a36Sopenharmony_ci#define DRV_MODULE_VERSION "0.2" 3962306a36Sopenharmony_ci#define DRV_MODULE_RELDATE "July 28, 2011" 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic const char version[] = 4262306a36Sopenharmony_ci DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ciMODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); 4562306a36Sopenharmony_ciMODULE_DESCRIPTION("Niagara2 Crypto driver"); 4662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 4762306a36Sopenharmony_ciMODULE_VERSION(DRV_MODULE_VERSION); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define N2_CRA_PRIORITY 200 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic DEFINE_MUTEX(spu_lock); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistruct spu_queue { 5462306a36Sopenharmony_ci cpumask_t sharing; 5562306a36Sopenharmony_ci unsigned long qhandle; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci spinlock_t lock; 5862306a36Sopenharmony_ci u8 q_type; 5962306a36Sopenharmony_ci void *q; 6062306a36Sopenharmony_ci unsigned long head; 6162306a36Sopenharmony_ci unsigned long tail; 6262306a36Sopenharmony_ci struct list_head jobs; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci unsigned long devino; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci char irq_name[32]; 6762306a36Sopenharmony_ci unsigned int irq; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci struct list_head list; 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistruct spu_qreg { 7362306a36Sopenharmony_ci struct spu_queue *queue; 7462306a36Sopenharmony_ci unsigned long type; 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic struct spu_queue **cpu_to_cwq; 7862306a36Sopenharmony_cistatic struct spu_queue **cpu_to_mau; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic unsigned long spu_next_offset(struct spu_queue *q, unsigned long off) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci if (q->q_type == HV_NCS_QTYPE_MAU) { 8362306a36Sopenharmony_ci off += MAU_ENTRY_SIZE; 8462306a36Sopenharmony_ci if (off == (MAU_ENTRY_SIZE * MAU_NUM_ENTRIES)) 8562306a36Sopenharmony_ci off = 0; 8662306a36Sopenharmony_ci } else { 8762306a36Sopenharmony_ci off += CWQ_ENTRY_SIZE; 8862306a36Sopenharmony_ci if (off == (CWQ_ENTRY_SIZE * CWQ_NUM_ENTRIES)) 8962306a36Sopenharmony_ci off = 0; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci return off; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistruct n2_request_common { 9562306a36Sopenharmony_ci struct list_head entry; 9662306a36Sopenharmony_ci unsigned int offset; 9762306a36Sopenharmony_ci}; 9862306a36Sopenharmony_ci#define OFFSET_NOT_RUNNING (~(unsigned int)0) 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* An async job request records the final tail value it used in 10162306a36Sopenharmony_ci * n2_request_common->offset, test to see if that offset is in 10262306a36Sopenharmony_ci * the range old_head, new_head, inclusive. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_cistatic inline bool job_finished(struct spu_queue *q, unsigned int offset, 10562306a36Sopenharmony_ci unsigned long old_head, unsigned long new_head) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci if (old_head <= new_head) { 10862306a36Sopenharmony_ci if (offset > old_head && offset <= new_head) 10962306a36Sopenharmony_ci return true; 11062306a36Sopenharmony_ci } else { 11162306a36Sopenharmony_ci if (offset > old_head || offset <= new_head) 11262306a36Sopenharmony_ci return true; 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci return false; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* When the HEAD marker is unequal to the actual HEAD, we get 11862306a36Sopenharmony_ci * a virtual device INO interrupt. We should process the 11962306a36Sopenharmony_ci * completed CWQ entries and adjust the HEAD marker to clear 12062306a36Sopenharmony_ci * the IRQ. 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_cistatic irqreturn_t cwq_intr(int irq, void *dev_id) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci unsigned long off, new_head, hv_ret; 12562306a36Sopenharmony_ci struct spu_queue *q = dev_id; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci pr_err("CPU[%d]: Got CWQ interrupt for qhdl[%lx]\n", 12862306a36Sopenharmony_ci smp_processor_id(), q->qhandle); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci spin_lock(&q->lock); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci hv_ret = sun4v_ncs_gethead(q->qhandle, &new_head); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci pr_err("CPU[%d]: CWQ gethead[%lx] hv_ret[%lu]\n", 13562306a36Sopenharmony_ci smp_processor_id(), new_head, hv_ret); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci for (off = q->head; off != new_head; off = spu_next_offset(q, off)) { 13862306a36Sopenharmony_ci /* XXX ... XXX */ 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci hv_ret = sun4v_ncs_sethead_marker(q->qhandle, new_head); 14262306a36Sopenharmony_ci if (hv_ret == HV_EOK) 14362306a36Sopenharmony_ci q->head = new_head; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci spin_unlock(&q->lock); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci return IRQ_HANDLED; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic irqreturn_t mau_intr(int irq, void *dev_id) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct spu_queue *q = dev_id; 15362306a36Sopenharmony_ci unsigned long head, hv_ret; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci spin_lock(&q->lock); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci pr_err("CPU[%d]: Got MAU interrupt for qhdl[%lx]\n", 15862306a36Sopenharmony_ci smp_processor_id(), q->qhandle); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci hv_ret = sun4v_ncs_gethead(q->qhandle, &head); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci pr_err("CPU[%d]: MAU gethead[%lx] hv_ret[%lu]\n", 16362306a36Sopenharmony_ci smp_processor_id(), head, hv_ret); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci sun4v_ncs_sethead_marker(q->qhandle, head); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci spin_unlock(&q->lock); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci return IRQ_HANDLED; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic void *spu_queue_next(struct spu_queue *q, void *cur) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci return q->q + spu_next_offset(q, cur - q->q); 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic int spu_queue_num_free(struct spu_queue *q) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci unsigned long head = q->head; 18062306a36Sopenharmony_ci unsigned long tail = q->tail; 18162306a36Sopenharmony_ci unsigned long end = (CWQ_ENTRY_SIZE * CWQ_NUM_ENTRIES); 18262306a36Sopenharmony_ci unsigned long diff; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (head > tail) 18562306a36Sopenharmony_ci diff = head - tail; 18662306a36Sopenharmony_ci else 18762306a36Sopenharmony_ci diff = (end - tail) + head; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci return (diff / CWQ_ENTRY_SIZE) - 1; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic void *spu_queue_alloc(struct spu_queue *q, int num_entries) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci int avail = spu_queue_num_free(q); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (avail >= num_entries) 19762306a36Sopenharmony_ci return q->q + q->tail; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci return NULL; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic unsigned long spu_queue_submit(struct spu_queue *q, void *last) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci unsigned long hv_ret, new_tail; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci new_tail = spu_next_offset(q, last - q->q); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci hv_ret = sun4v_ncs_settail(q->qhandle, new_tail); 20962306a36Sopenharmony_ci if (hv_ret == HV_EOK) 21062306a36Sopenharmony_ci q->tail = new_tail; 21162306a36Sopenharmony_ci return hv_ret; 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic u64 control_word_base(unsigned int len, unsigned int hmac_key_len, 21562306a36Sopenharmony_ci int enc_type, int auth_type, 21662306a36Sopenharmony_ci unsigned int hash_len, 21762306a36Sopenharmony_ci bool sfas, bool sob, bool eob, bool encrypt, 21862306a36Sopenharmony_ci int opcode) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci u64 word = (len - 1) & CONTROL_LEN; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci word |= ((u64) opcode << CONTROL_OPCODE_SHIFT); 22362306a36Sopenharmony_ci word |= ((u64) enc_type << CONTROL_ENC_TYPE_SHIFT); 22462306a36Sopenharmony_ci word |= ((u64) auth_type << CONTROL_AUTH_TYPE_SHIFT); 22562306a36Sopenharmony_ci if (sfas) 22662306a36Sopenharmony_ci word |= CONTROL_STORE_FINAL_AUTH_STATE; 22762306a36Sopenharmony_ci if (sob) 22862306a36Sopenharmony_ci word |= CONTROL_START_OF_BLOCK; 22962306a36Sopenharmony_ci if (eob) 23062306a36Sopenharmony_ci word |= CONTROL_END_OF_BLOCK; 23162306a36Sopenharmony_ci if (encrypt) 23262306a36Sopenharmony_ci word |= CONTROL_ENCRYPT; 23362306a36Sopenharmony_ci if (hmac_key_len) 23462306a36Sopenharmony_ci word |= ((u64) (hmac_key_len - 1)) << CONTROL_HMAC_KEY_LEN_SHIFT; 23562306a36Sopenharmony_ci if (hash_len) 23662306a36Sopenharmony_ci word |= ((u64) (hash_len - 1)) << CONTROL_HASH_LEN_SHIFT; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return word; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci#if 0 24262306a36Sopenharmony_cistatic inline bool n2_should_run_async(struct spu_queue *qp, int this_len) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci if (this_len >= 64 || 24562306a36Sopenharmony_ci qp->head != qp->tail) 24662306a36Sopenharmony_ci return true; 24762306a36Sopenharmony_ci return false; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci#endif 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistruct n2_ahash_alg { 25262306a36Sopenharmony_ci struct list_head entry; 25362306a36Sopenharmony_ci const u8 *hash_zero; 25462306a36Sopenharmony_ci const u8 *hash_init; 25562306a36Sopenharmony_ci u8 hw_op_hashsz; 25662306a36Sopenharmony_ci u8 digest_size; 25762306a36Sopenharmony_ci u8 auth_type; 25862306a36Sopenharmony_ci u8 hmac_type; 25962306a36Sopenharmony_ci struct ahash_alg alg; 26062306a36Sopenharmony_ci}; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic inline struct n2_ahash_alg *n2_ahash_alg(struct crypto_tfm *tfm) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci struct crypto_alg *alg = tfm->__crt_alg; 26562306a36Sopenharmony_ci struct ahash_alg *ahash_alg; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci ahash_alg = container_of(alg, struct ahash_alg, halg.base); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci return container_of(ahash_alg, struct n2_ahash_alg, alg); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistruct n2_hmac_alg { 27362306a36Sopenharmony_ci const char *child_alg; 27462306a36Sopenharmony_ci struct n2_ahash_alg derived; 27562306a36Sopenharmony_ci}; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic inline struct n2_hmac_alg *n2_hmac_alg(struct crypto_tfm *tfm) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci struct crypto_alg *alg = tfm->__crt_alg; 28062306a36Sopenharmony_ci struct ahash_alg *ahash_alg; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci ahash_alg = container_of(alg, struct ahash_alg, halg.base); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci return container_of(ahash_alg, struct n2_hmac_alg, derived.alg); 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistruct n2_hash_ctx { 28862306a36Sopenharmony_ci struct crypto_ahash *fallback_tfm; 28962306a36Sopenharmony_ci}; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci#define N2_HASH_KEY_MAX 32 /* HW limit for all HMAC requests */ 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistruct n2_hmac_ctx { 29462306a36Sopenharmony_ci struct n2_hash_ctx base; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci struct crypto_shash *child_shash; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci int hash_key_len; 29962306a36Sopenharmony_ci unsigned char hash_key[N2_HASH_KEY_MAX]; 30062306a36Sopenharmony_ci}; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistruct n2_hash_req_ctx { 30362306a36Sopenharmony_ci union { 30462306a36Sopenharmony_ci struct md5_state md5; 30562306a36Sopenharmony_ci struct sha1_state sha1; 30662306a36Sopenharmony_ci struct sha256_state sha256; 30762306a36Sopenharmony_ci } u; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci struct ahash_request fallback_req; 31062306a36Sopenharmony_ci}; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic int n2_hash_async_init(struct ahash_request *req) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); 31562306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 31662306a36Sopenharmony_ci struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); 31962306a36Sopenharmony_ci rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci return crypto_ahash_init(&rctx->fallback_req); 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic int n2_hash_async_update(struct ahash_request *req) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); 32762306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 32862306a36Sopenharmony_ci struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); 33162306a36Sopenharmony_ci rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; 33262306a36Sopenharmony_ci rctx->fallback_req.nbytes = req->nbytes; 33362306a36Sopenharmony_ci rctx->fallback_req.src = req->src; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci return crypto_ahash_update(&rctx->fallback_req); 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic int n2_hash_async_final(struct ahash_request *req) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); 34162306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 34262306a36Sopenharmony_ci struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); 34562306a36Sopenharmony_ci rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; 34662306a36Sopenharmony_ci rctx->fallback_req.result = req->result; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci return crypto_ahash_final(&rctx->fallback_req); 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic int n2_hash_async_finup(struct ahash_request *req) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); 35462306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 35562306a36Sopenharmony_ci struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); 35862306a36Sopenharmony_ci rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; 35962306a36Sopenharmony_ci rctx->fallback_req.nbytes = req->nbytes; 36062306a36Sopenharmony_ci rctx->fallback_req.src = req->src; 36162306a36Sopenharmony_ci rctx->fallback_req.result = req->result; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci return crypto_ahash_finup(&rctx->fallback_req); 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic int n2_hash_async_noimport(struct ahash_request *req, const void *in) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci return -ENOSYS; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic int n2_hash_async_noexport(struct ahash_request *req, void *out) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci return -ENOSYS; 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic int n2_hash_cra_init(struct crypto_tfm *tfm) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci const char *fallback_driver_name = crypto_tfm_alg_name(tfm); 37962306a36Sopenharmony_ci struct crypto_ahash *ahash = __crypto_ahash_cast(tfm); 38062306a36Sopenharmony_ci struct n2_hash_ctx *ctx = crypto_ahash_ctx(ahash); 38162306a36Sopenharmony_ci struct crypto_ahash *fallback_tfm; 38262306a36Sopenharmony_ci int err; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci fallback_tfm = crypto_alloc_ahash(fallback_driver_name, 0, 38562306a36Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK); 38662306a36Sopenharmony_ci if (IS_ERR(fallback_tfm)) { 38762306a36Sopenharmony_ci pr_warn("Fallback driver '%s' could not be loaded!\n", 38862306a36Sopenharmony_ci fallback_driver_name); 38962306a36Sopenharmony_ci err = PTR_ERR(fallback_tfm); 39062306a36Sopenharmony_ci goto out; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci crypto_ahash_set_reqsize(ahash, (sizeof(struct n2_hash_req_ctx) + 39462306a36Sopenharmony_ci crypto_ahash_reqsize(fallback_tfm))); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci ctx->fallback_tfm = fallback_tfm; 39762306a36Sopenharmony_ci return 0; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ciout: 40062306a36Sopenharmony_ci return err; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic void n2_hash_cra_exit(struct crypto_tfm *tfm) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct crypto_ahash *ahash = __crypto_ahash_cast(tfm); 40662306a36Sopenharmony_ci struct n2_hash_ctx *ctx = crypto_ahash_ctx(ahash); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci crypto_free_ahash(ctx->fallback_tfm); 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic int n2_hmac_cra_init(struct crypto_tfm *tfm) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci const char *fallback_driver_name = crypto_tfm_alg_name(tfm); 41462306a36Sopenharmony_ci struct crypto_ahash *ahash = __crypto_ahash_cast(tfm); 41562306a36Sopenharmony_ci struct n2_hmac_ctx *ctx = crypto_ahash_ctx(ahash); 41662306a36Sopenharmony_ci struct n2_hmac_alg *n2alg = n2_hmac_alg(tfm); 41762306a36Sopenharmony_ci struct crypto_ahash *fallback_tfm; 41862306a36Sopenharmony_ci struct crypto_shash *child_shash; 41962306a36Sopenharmony_ci int err; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci fallback_tfm = crypto_alloc_ahash(fallback_driver_name, 0, 42262306a36Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK); 42362306a36Sopenharmony_ci if (IS_ERR(fallback_tfm)) { 42462306a36Sopenharmony_ci pr_warn("Fallback driver '%s' could not be loaded!\n", 42562306a36Sopenharmony_ci fallback_driver_name); 42662306a36Sopenharmony_ci err = PTR_ERR(fallback_tfm); 42762306a36Sopenharmony_ci goto out; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci child_shash = crypto_alloc_shash(n2alg->child_alg, 0, 0); 43162306a36Sopenharmony_ci if (IS_ERR(child_shash)) { 43262306a36Sopenharmony_ci pr_warn("Child shash '%s' could not be loaded!\n", 43362306a36Sopenharmony_ci n2alg->child_alg); 43462306a36Sopenharmony_ci err = PTR_ERR(child_shash); 43562306a36Sopenharmony_ci goto out_free_fallback; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci crypto_ahash_set_reqsize(ahash, (sizeof(struct n2_hash_req_ctx) + 43962306a36Sopenharmony_ci crypto_ahash_reqsize(fallback_tfm))); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci ctx->child_shash = child_shash; 44262306a36Sopenharmony_ci ctx->base.fallback_tfm = fallback_tfm; 44362306a36Sopenharmony_ci return 0; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ciout_free_fallback: 44662306a36Sopenharmony_ci crypto_free_ahash(fallback_tfm); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ciout: 44962306a36Sopenharmony_ci return err; 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic void n2_hmac_cra_exit(struct crypto_tfm *tfm) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct crypto_ahash *ahash = __crypto_ahash_cast(tfm); 45562306a36Sopenharmony_ci struct n2_hmac_ctx *ctx = crypto_ahash_ctx(ahash); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci crypto_free_ahash(ctx->base.fallback_tfm); 45862306a36Sopenharmony_ci crypto_free_shash(ctx->child_shash); 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic int n2_hmac_async_setkey(struct crypto_ahash *tfm, const u8 *key, 46262306a36Sopenharmony_ci unsigned int keylen) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci struct n2_hmac_ctx *ctx = crypto_ahash_ctx(tfm); 46562306a36Sopenharmony_ci struct crypto_shash *child_shash = ctx->child_shash; 46662306a36Sopenharmony_ci struct crypto_ahash *fallback_tfm; 46762306a36Sopenharmony_ci int err, bs, ds; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci fallback_tfm = ctx->base.fallback_tfm; 47062306a36Sopenharmony_ci err = crypto_ahash_setkey(fallback_tfm, key, keylen); 47162306a36Sopenharmony_ci if (err) 47262306a36Sopenharmony_ci return err; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci bs = crypto_shash_blocksize(child_shash); 47562306a36Sopenharmony_ci ds = crypto_shash_digestsize(child_shash); 47662306a36Sopenharmony_ci BUG_ON(ds > N2_HASH_KEY_MAX); 47762306a36Sopenharmony_ci if (keylen > bs) { 47862306a36Sopenharmony_ci err = crypto_shash_tfm_digest(child_shash, key, keylen, 47962306a36Sopenharmony_ci ctx->hash_key); 48062306a36Sopenharmony_ci if (err) 48162306a36Sopenharmony_ci return err; 48262306a36Sopenharmony_ci keylen = ds; 48362306a36Sopenharmony_ci } else if (keylen <= N2_HASH_KEY_MAX) 48462306a36Sopenharmony_ci memcpy(ctx->hash_key, key, keylen); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci ctx->hash_key_len = keylen; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci return err; 48962306a36Sopenharmony_ci} 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_cistatic unsigned long wait_for_tail(struct spu_queue *qp) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci unsigned long head, hv_ret; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci do { 49662306a36Sopenharmony_ci hv_ret = sun4v_ncs_gethead(qp->qhandle, &head); 49762306a36Sopenharmony_ci if (hv_ret != HV_EOK) { 49862306a36Sopenharmony_ci pr_err("Hypervisor error on gethead\n"); 49962306a36Sopenharmony_ci break; 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci if (head == qp->tail) { 50262306a36Sopenharmony_ci qp->head = head; 50362306a36Sopenharmony_ci break; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci } while (1); 50662306a36Sopenharmony_ci return hv_ret; 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic unsigned long submit_and_wait_for_tail(struct spu_queue *qp, 51062306a36Sopenharmony_ci struct cwq_initial_entry *ent) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci unsigned long hv_ret = spu_queue_submit(qp, ent); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (hv_ret == HV_EOK) 51562306a36Sopenharmony_ci hv_ret = wait_for_tail(qp); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci return hv_ret; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic int n2_do_async_digest(struct ahash_request *req, 52162306a36Sopenharmony_ci unsigned int auth_type, unsigned int digest_size, 52262306a36Sopenharmony_ci unsigned int result_size, void *hash_loc, 52362306a36Sopenharmony_ci unsigned long auth_key, unsigned int auth_key_len) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 52662306a36Sopenharmony_ci struct cwq_initial_entry *ent; 52762306a36Sopenharmony_ci struct crypto_hash_walk walk; 52862306a36Sopenharmony_ci struct spu_queue *qp; 52962306a36Sopenharmony_ci unsigned long flags; 53062306a36Sopenharmony_ci int err = -ENODEV; 53162306a36Sopenharmony_ci int nbytes, cpu; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci /* The total effective length of the operation may not 53462306a36Sopenharmony_ci * exceed 2^16. 53562306a36Sopenharmony_ci */ 53662306a36Sopenharmony_ci if (unlikely(req->nbytes > (1 << 16))) { 53762306a36Sopenharmony_ci struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); 53862306a36Sopenharmony_ci struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); 54162306a36Sopenharmony_ci rctx->fallback_req.base.flags = 54262306a36Sopenharmony_ci req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; 54362306a36Sopenharmony_ci rctx->fallback_req.nbytes = req->nbytes; 54462306a36Sopenharmony_ci rctx->fallback_req.src = req->src; 54562306a36Sopenharmony_ci rctx->fallback_req.result = req->result; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci return crypto_ahash_digest(&rctx->fallback_req); 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci nbytes = crypto_hash_walk_first(req, &walk); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci cpu = get_cpu(); 55362306a36Sopenharmony_ci qp = cpu_to_cwq[cpu]; 55462306a36Sopenharmony_ci if (!qp) 55562306a36Sopenharmony_ci goto out; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci spin_lock_irqsave(&qp->lock, flags); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* XXX can do better, improve this later by doing a by-hand scatterlist 56062306a36Sopenharmony_ci * XXX walk, etc. 56162306a36Sopenharmony_ci */ 56262306a36Sopenharmony_ci ent = qp->q + qp->tail; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci ent->control = control_word_base(nbytes, auth_key_len, 0, 56562306a36Sopenharmony_ci auth_type, digest_size, 56662306a36Sopenharmony_ci false, true, false, false, 56762306a36Sopenharmony_ci OPCODE_INPLACE_BIT | 56862306a36Sopenharmony_ci OPCODE_AUTH_MAC); 56962306a36Sopenharmony_ci ent->src_addr = __pa(walk.data); 57062306a36Sopenharmony_ci ent->auth_key_addr = auth_key; 57162306a36Sopenharmony_ci ent->auth_iv_addr = __pa(hash_loc); 57262306a36Sopenharmony_ci ent->final_auth_state_addr = 0UL; 57362306a36Sopenharmony_ci ent->enc_key_addr = 0UL; 57462306a36Sopenharmony_ci ent->enc_iv_addr = 0UL; 57562306a36Sopenharmony_ci ent->dest_addr = __pa(hash_loc); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci nbytes = crypto_hash_walk_done(&walk, 0); 57862306a36Sopenharmony_ci while (nbytes > 0) { 57962306a36Sopenharmony_ci ent = spu_queue_next(qp, ent); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci ent->control = (nbytes - 1); 58262306a36Sopenharmony_ci ent->src_addr = __pa(walk.data); 58362306a36Sopenharmony_ci ent->auth_key_addr = 0UL; 58462306a36Sopenharmony_ci ent->auth_iv_addr = 0UL; 58562306a36Sopenharmony_ci ent->final_auth_state_addr = 0UL; 58662306a36Sopenharmony_ci ent->enc_key_addr = 0UL; 58762306a36Sopenharmony_ci ent->enc_iv_addr = 0UL; 58862306a36Sopenharmony_ci ent->dest_addr = 0UL; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci nbytes = crypto_hash_walk_done(&walk, 0); 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci ent->control |= CONTROL_END_OF_BLOCK; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (submit_and_wait_for_tail(qp, ent) != HV_EOK) 59562306a36Sopenharmony_ci err = -EINVAL; 59662306a36Sopenharmony_ci else 59762306a36Sopenharmony_ci err = 0; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->lock, flags); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (!err) 60262306a36Sopenharmony_ci memcpy(req->result, hash_loc, result_size); 60362306a36Sopenharmony_ciout: 60462306a36Sopenharmony_ci put_cpu(); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci return err; 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic int n2_hash_async_digest(struct ahash_request *req) 61062306a36Sopenharmony_ci{ 61162306a36Sopenharmony_ci struct n2_ahash_alg *n2alg = n2_ahash_alg(req->base.tfm); 61262306a36Sopenharmony_ci struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); 61362306a36Sopenharmony_ci int ds; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci ds = n2alg->digest_size; 61662306a36Sopenharmony_ci if (unlikely(req->nbytes == 0)) { 61762306a36Sopenharmony_ci memcpy(req->result, n2alg->hash_zero, ds); 61862306a36Sopenharmony_ci return 0; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci memcpy(&rctx->u, n2alg->hash_init, n2alg->hw_op_hashsz); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci return n2_do_async_digest(req, n2alg->auth_type, 62362306a36Sopenharmony_ci n2alg->hw_op_hashsz, ds, 62462306a36Sopenharmony_ci &rctx->u, 0UL, 0); 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic int n2_hmac_async_digest(struct ahash_request *req) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci struct n2_hmac_alg *n2alg = n2_hmac_alg(req->base.tfm); 63062306a36Sopenharmony_ci struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); 63162306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 63262306a36Sopenharmony_ci struct n2_hmac_ctx *ctx = crypto_ahash_ctx(tfm); 63362306a36Sopenharmony_ci int ds; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci ds = n2alg->derived.digest_size; 63662306a36Sopenharmony_ci if (unlikely(req->nbytes == 0) || 63762306a36Sopenharmony_ci unlikely(ctx->hash_key_len > N2_HASH_KEY_MAX)) { 63862306a36Sopenharmony_ci struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); 63962306a36Sopenharmony_ci struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); 64262306a36Sopenharmony_ci rctx->fallback_req.base.flags = 64362306a36Sopenharmony_ci req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; 64462306a36Sopenharmony_ci rctx->fallback_req.nbytes = req->nbytes; 64562306a36Sopenharmony_ci rctx->fallback_req.src = req->src; 64662306a36Sopenharmony_ci rctx->fallback_req.result = req->result; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci return crypto_ahash_digest(&rctx->fallback_req); 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci memcpy(&rctx->u, n2alg->derived.hash_init, 65162306a36Sopenharmony_ci n2alg->derived.hw_op_hashsz); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci return n2_do_async_digest(req, n2alg->derived.hmac_type, 65462306a36Sopenharmony_ci n2alg->derived.hw_op_hashsz, ds, 65562306a36Sopenharmony_ci &rctx->u, 65662306a36Sopenharmony_ci __pa(&ctx->hash_key), 65762306a36Sopenharmony_ci ctx->hash_key_len); 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistruct n2_skcipher_context { 66162306a36Sopenharmony_ci int key_len; 66262306a36Sopenharmony_ci int enc_type; 66362306a36Sopenharmony_ci union { 66462306a36Sopenharmony_ci u8 aes[AES_MAX_KEY_SIZE]; 66562306a36Sopenharmony_ci u8 des[DES_KEY_SIZE]; 66662306a36Sopenharmony_ci u8 des3[3 * DES_KEY_SIZE]; 66762306a36Sopenharmony_ci } key; 66862306a36Sopenharmony_ci}; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci#define N2_CHUNK_ARR_LEN 16 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_cistruct n2_crypto_chunk { 67362306a36Sopenharmony_ci struct list_head entry; 67462306a36Sopenharmony_ci unsigned long iv_paddr : 44; 67562306a36Sopenharmony_ci unsigned long arr_len : 20; 67662306a36Sopenharmony_ci unsigned long dest_paddr; 67762306a36Sopenharmony_ci unsigned long dest_final; 67862306a36Sopenharmony_ci struct { 67962306a36Sopenharmony_ci unsigned long src_paddr : 44; 68062306a36Sopenharmony_ci unsigned long src_len : 20; 68162306a36Sopenharmony_ci } arr[N2_CHUNK_ARR_LEN]; 68262306a36Sopenharmony_ci}; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_cistruct n2_request_context { 68562306a36Sopenharmony_ci struct skcipher_walk walk; 68662306a36Sopenharmony_ci struct list_head chunk_list; 68762306a36Sopenharmony_ci struct n2_crypto_chunk chunk; 68862306a36Sopenharmony_ci u8 temp_iv[16]; 68962306a36Sopenharmony_ci}; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci/* The SPU allows some level of flexibility for partial cipher blocks 69262306a36Sopenharmony_ci * being specified in a descriptor. 69362306a36Sopenharmony_ci * 69462306a36Sopenharmony_ci * It merely requires that every descriptor's length field is at least 69562306a36Sopenharmony_ci * as large as the cipher block size. This means that a cipher block 69662306a36Sopenharmony_ci * can span at most 2 descriptors. However, this does not allow a 69762306a36Sopenharmony_ci * partial block to span into the final descriptor as that would 69862306a36Sopenharmony_ci * violate the rule (since every descriptor's length must be at lest 69962306a36Sopenharmony_ci * the block size). So, for example, assuming an 8 byte block size: 70062306a36Sopenharmony_ci * 70162306a36Sopenharmony_ci * 0xe --> 0xa --> 0x8 70262306a36Sopenharmony_ci * 70362306a36Sopenharmony_ci * is a valid length sequence, whereas: 70462306a36Sopenharmony_ci * 70562306a36Sopenharmony_ci * 0xe --> 0xb --> 0x7 70662306a36Sopenharmony_ci * 70762306a36Sopenharmony_ci * is not a valid sequence. 70862306a36Sopenharmony_ci */ 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistruct n2_skcipher_alg { 71162306a36Sopenharmony_ci struct list_head entry; 71262306a36Sopenharmony_ci u8 enc_type; 71362306a36Sopenharmony_ci struct skcipher_alg skcipher; 71462306a36Sopenharmony_ci}; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic inline struct n2_skcipher_alg *n2_skcipher_alg(struct crypto_skcipher *tfm) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci struct skcipher_alg *alg = crypto_skcipher_alg(tfm); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci return container_of(alg, struct n2_skcipher_alg, skcipher); 72162306a36Sopenharmony_ci} 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_cistruct n2_skcipher_request_context { 72462306a36Sopenharmony_ci struct skcipher_walk walk; 72562306a36Sopenharmony_ci}; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_cistatic int n2_aes_setkey(struct crypto_skcipher *skcipher, const u8 *key, 72862306a36Sopenharmony_ci unsigned int keylen) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci struct crypto_tfm *tfm = crypto_skcipher_tfm(skcipher); 73162306a36Sopenharmony_ci struct n2_skcipher_context *ctx = crypto_tfm_ctx(tfm); 73262306a36Sopenharmony_ci struct n2_skcipher_alg *n2alg = n2_skcipher_alg(skcipher); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci ctx->enc_type = (n2alg->enc_type & ENC_TYPE_CHAINING_MASK); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci switch (keylen) { 73762306a36Sopenharmony_ci case AES_KEYSIZE_128: 73862306a36Sopenharmony_ci ctx->enc_type |= ENC_TYPE_ALG_AES128; 73962306a36Sopenharmony_ci break; 74062306a36Sopenharmony_ci case AES_KEYSIZE_192: 74162306a36Sopenharmony_ci ctx->enc_type |= ENC_TYPE_ALG_AES192; 74262306a36Sopenharmony_ci break; 74362306a36Sopenharmony_ci case AES_KEYSIZE_256: 74462306a36Sopenharmony_ci ctx->enc_type |= ENC_TYPE_ALG_AES256; 74562306a36Sopenharmony_ci break; 74662306a36Sopenharmony_ci default: 74762306a36Sopenharmony_ci return -EINVAL; 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci ctx->key_len = keylen; 75162306a36Sopenharmony_ci memcpy(ctx->key.aes, key, keylen); 75262306a36Sopenharmony_ci return 0; 75362306a36Sopenharmony_ci} 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_cistatic int n2_des_setkey(struct crypto_skcipher *skcipher, const u8 *key, 75662306a36Sopenharmony_ci unsigned int keylen) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci struct crypto_tfm *tfm = crypto_skcipher_tfm(skcipher); 75962306a36Sopenharmony_ci struct n2_skcipher_context *ctx = crypto_tfm_ctx(tfm); 76062306a36Sopenharmony_ci struct n2_skcipher_alg *n2alg = n2_skcipher_alg(skcipher); 76162306a36Sopenharmony_ci int err; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci err = verify_skcipher_des_key(skcipher, key); 76462306a36Sopenharmony_ci if (err) 76562306a36Sopenharmony_ci return err; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci ctx->enc_type = n2alg->enc_type; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci ctx->key_len = keylen; 77062306a36Sopenharmony_ci memcpy(ctx->key.des, key, keylen); 77162306a36Sopenharmony_ci return 0; 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic int n2_3des_setkey(struct crypto_skcipher *skcipher, const u8 *key, 77562306a36Sopenharmony_ci unsigned int keylen) 77662306a36Sopenharmony_ci{ 77762306a36Sopenharmony_ci struct crypto_tfm *tfm = crypto_skcipher_tfm(skcipher); 77862306a36Sopenharmony_ci struct n2_skcipher_context *ctx = crypto_tfm_ctx(tfm); 77962306a36Sopenharmony_ci struct n2_skcipher_alg *n2alg = n2_skcipher_alg(skcipher); 78062306a36Sopenharmony_ci int err; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci err = verify_skcipher_des3_key(skcipher, key); 78362306a36Sopenharmony_ci if (err) 78462306a36Sopenharmony_ci return err; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci ctx->enc_type = n2alg->enc_type; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci ctx->key_len = keylen; 78962306a36Sopenharmony_ci memcpy(ctx->key.des3, key, keylen); 79062306a36Sopenharmony_ci return 0; 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistatic inline int skcipher_descriptor_len(int nbytes, unsigned int block_size) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci int this_len = nbytes; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci this_len -= (nbytes & (block_size - 1)); 79862306a36Sopenharmony_ci return this_len > (1 << 16) ? (1 << 16) : this_len; 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_cistatic int __n2_crypt_chunk(struct crypto_skcipher *skcipher, 80262306a36Sopenharmony_ci struct n2_crypto_chunk *cp, 80362306a36Sopenharmony_ci struct spu_queue *qp, bool encrypt) 80462306a36Sopenharmony_ci{ 80562306a36Sopenharmony_ci struct n2_skcipher_context *ctx = crypto_skcipher_ctx(skcipher); 80662306a36Sopenharmony_ci struct cwq_initial_entry *ent; 80762306a36Sopenharmony_ci bool in_place; 80862306a36Sopenharmony_ci int i; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci ent = spu_queue_alloc(qp, cp->arr_len); 81162306a36Sopenharmony_ci if (!ent) { 81262306a36Sopenharmony_ci pr_info("queue_alloc() of %d fails\n", 81362306a36Sopenharmony_ci cp->arr_len); 81462306a36Sopenharmony_ci return -EBUSY; 81562306a36Sopenharmony_ci } 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci in_place = (cp->dest_paddr == cp->arr[0].src_paddr); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci ent->control = control_word_base(cp->arr[0].src_len, 82062306a36Sopenharmony_ci 0, ctx->enc_type, 0, 0, 82162306a36Sopenharmony_ci false, true, false, encrypt, 82262306a36Sopenharmony_ci OPCODE_ENCRYPT | 82362306a36Sopenharmony_ci (in_place ? OPCODE_INPLACE_BIT : 0)); 82462306a36Sopenharmony_ci ent->src_addr = cp->arr[0].src_paddr; 82562306a36Sopenharmony_ci ent->auth_key_addr = 0UL; 82662306a36Sopenharmony_ci ent->auth_iv_addr = 0UL; 82762306a36Sopenharmony_ci ent->final_auth_state_addr = 0UL; 82862306a36Sopenharmony_ci ent->enc_key_addr = __pa(&ctx->key); 82962306a36Sopenharmony_ci ent->enc_iv_addr = cp->iv_paddr; 83062306a36Sopenharmony_ci ent->dest_addr = (in_place ? 0UL : cp->dest_paddr); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci for (i = 1; i < cp->arr_len; i++) { 83362306a36Sopenharmony_ci ent = spu_queue_next(qp, ent); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci ent->control = cp->arr[i].src_len - 1; 83662306a36Sopenharmony_ci ent->src_addr = cp->arr[i].src_paddr; 83762306a36Sopenharmony_ci ent->auth_key_addr = 0UL; 83862306a36Sopenharmony_ci ent->auth_iv_addr = 0UL; 83962306a36Sopenharmony_ci ent->final_auth_state_addr = 0UL; 84062306a36Sopenharmony_ci ent->enc_key_addr = 0UL; 84162306a36Sopenharmony_ci ent->enc_iv_addr = 0UL; 84262306a36Sopenharmony_ci ent->dest_addr = 0UL; 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci ent->control |= CONTROL_END_OF_BLOCK; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci return (spu_queue_submit(qp, ent) != HV_EOK) ? -EINVAL : 0; 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_cistatic int n2_compute_chunks(struct skcipher_request *req) 85062306a36Sopenharmony_ci{ 85162306a36Sopenharmony_ci struct n2_request_context *rctx = skcipher_request_ctx(req); 85262306a36Sopenharmony_ci struct skcipher_walk *walk = &rctx->walk; 85362306a36Sopenharmony_ci struct n2_crypto_chunk *chunk; 85462306a36Sopenharmony_ci unsigned long dest_prev; 85562306a36Sopenharmony_ci unsigned int tot_len; 85662306a36Sopenharmony_ci bool prev_in_place; 85762306a36Sopenharmony_ci int err, nbytes; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci err = skcipher_walk_async(walk, req); 86062306a36Sopenharmony_ci if (err) 86162306a36Sopenharmony_ci return err; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci INIT_LIST_HEAD(&rctx->chunk_list); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci chunk = &rctx->chunk; 86662306a36Sopenharmony_ci INIT_LIST_HEAD(&chunk->entry); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci chunk->iv_paddr = 0UL; 86962306a36Sopenharmony_ci chunk->arr_len = 0; 87062306a36Sopenharmony_ci chunk->dest_paddr = 0UL; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci prev_in_place = false; 87362306a36Sopenharmony_ci dest_prev = ~0UL; 87462306a36Sopenharmony_ci tot_len = 0; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci while ((nbytes = walk->nbytes) != 0) { 87762306a36Sopenharmony_ci unsigned long dest_paddr, src_paddr; 87862306a36Sopenharmony_ci bool in_place; 87962306a36Sopenharmony_ci int this_len; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci src_paddr = (page_to_phys(walk->src.phys.page) + 88262306a36Sopenharmony_ci walk->src.phys.offset); 88362306a36Sopenharmony_ci dest_paddr = (page_to_phys(walk->dst.phys.page) + 88462306a36Sopenharmony_ci walk->dst.phys.offset); 88562306a36Sopenharmony_ci in_place = (src_paddr == dest_paddr); 88662306a36Sopenharmony_ci this_len = skcipher_descriptor_len(nbytes, walk->blocksize); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci if (chunk->arr_len != 0) { 88962306a36Sopenharmony_ci if (in_place != prev_in_place || 89062306a36Sopenharmony_ci (!prev_in_place && 89162306a36Sopenharmony_ci dest_paddr != dest_prev) || 89262306a36Sopenharmony_ci chunk->arr_len == N2_CHUNK_ARR_LEN || 89362306a36Sopenharmony_ci tot_len + this_len > (1 << 16)) { 89462306a36Sopenharmony_ci chunk->dest_final = dest_prev; 89562306a36Sopenharmony_ci list_add_tail(&chunk->entry, 89662306a36Sopenharmony_ci &rctx->chunk_list); 89762306a36Sopenharmony_ci chunk = kzalloc(sizeof(*chunk), GFP_ATOMIC); 89862306a36Sopenharmony_ci if (!chunk) { 89962306a36Sopenharmony_ci err = -ENOMEM; 90062306a36Sopenharmony_ci break; 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci INIT_LIST_HEAD(&chunk->entry); 90362306a36Sopenharmony_ci } 90462306a36Sopenharmony_ci } 90562306a36Sopenharmony_ci if (chunk->arr_len == 0) { 90662306a36Sopenharmony_ci chunk->dest_paddr = dest_paddr; 90762306a36Sopenharmony_ci tot_len = 0; 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci chunk->arr[chunk->arr_len].src_paddr = src_paddr; 91062306a36Sopenharmony_ci chunk->arr[chunk->arr_len].src_len = this_len; 91162306a36Sopenharmony_ci chunk->arr_len++; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci dest_prev = dest_paddr + this_len; 91462306a36Sopenharmony_ci prev_in_place = in_place; 91562306a36Sopenharmony_ci tot_len += this_len; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci err = skcipher_walk_done(walk, nbytes - this_len); 91862306a36Sopenharmony_ci if (err) 91962306a36Sopenharmony_ci break; 92062306a36Sopenharmony_ci } 92162306a36Sopenharmony_ci if (!err && chunk->arr_len != 0) { 92262306a36Sopenharmony_ci chunk->dest_final = dest_prev; 92362306a36Sopenharmony_ci list_add_tail(&chunk->entry, &rctx->chunk_list); 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci return err; 92762306a36Sopenharmony_ci} 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_cistatic void n2_chunk_complete(struct skcipher_request *req, void *final_iv) 93062306a36Sopenharmony_ci{ 93162306a36Sopenharmony_ci struct n2_request_context *rctx = skcipher_request_ctx(req); 93262306a36Sopenharmony_ci struct n2_crypto_chunk *c, *tmp; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci if (final_iv) 93562306a36Sopenharmony_ci memcpy(rctx->walk.iv, final_iv, rctx->walk.blocksize); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci list_for_each_entry_safe(c, tmp, &rctx->chunk_list, entry) { 93862306a36Sopenharmony_ci list_del(&c->entry); 93962306a36Sopenharmony_ci if (unlikely(c != &rctx->chunk)) 94062306a36Sopenharmony_ci kfree(c); 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci} 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_cistatic int n2_do_ecb(struct skcipher_request *req, bool encrypt) 94662306a36Sopenharmony_ci{ 94762306a36Sopenharmony_ci struct n2_request_context *rctx = skcipher_request_ctx(req); 94862306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 94962306a36Sopenharmony_ci int err = n2_compute_chunks(req); 95062306a36Sopenharmony_ci struct n2_crypto_chunk *c, *tmp; 95162306a36Sopenharmony_ci unsigned long flags, hv_ret; 95262306a36Sopenharmony_ci struct spu_queue *qp; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci if (err) 95562306a36Sopenharmony_ci return err; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci qp = cpu_to_cwq[get_cpu()]; 95862306a36Sopenharmony_ci err = -ENODEV; 95962306a36Sopenharmony_ci if (!qp) 96062306a36Sopenharmony_ci goto out; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci spin_lock_irqsave(&qp->lock, flags); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci list_for_each_entry_safe(c, tmp, &rctx->chunk_list, entry) { 96562306a36Sopenharmony_ci err = __n2_crypt_chunk(tfm, c, qp, encrypt); 96662306a36Sopenharmony_ci if (err) 96762306a36Sopenharmony_ci break; 96862306a36Sopenharmony_ci list_del(&c->entry); 96962306a36Sopenharmony_ci if (unlikely(c != &rctx->chunk)) 97062306a36Sopenharmony_ci kfree(c); 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci if (!err) { 97362306a36Sopenharmony_ci hv_ret = wait_for_tail(qp); 97462306a36Sopenharmony_ci if (hv_ret != HV_EOK) 97562306a36Sopenharmony_ci err = -EINVAL; 97662306a36Sopenharmony_ci } 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->lock, flags); 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ciout: 98162306a36Sopenharmony_ci put_cpu(); 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci n2_chunk_complete(req, NULL); 98462306a36Sopenharmony_ci return err; 98562306a36Sopenharmony_ci} 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_cistatic int n2_encrypt_ecb(struct skcipher_request *req) 98862306a36Sopenharmony_ci{ 98962306a36Sopenharmony_ci return n2_do_ecb(req, true); 99062306a36Sopenharmony_ci} 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_cistatic int n2_decrypt_ecb(struct skcipher_request *req) 99362306a36Sopenharmony_ci{ 99462306a36Sopenharmony_ci return n2_do_ecb(req, false); 99562306a36Sopenharmony_ci} 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_cistatic int n2_do_chaining(struct skcipher_request *req, bool encrypt) 99862306a36Sopenharmony_ci{ 99962306a36Sopenharmony_ci struct n2_request_context *rctx = skcipher_request_ctx(req); 100062306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 100162306a36Sopenharmony_ci unsigned long flags, hv_ret, iv_paddr; 100262306a36Sopenharmony_ci int err = n2_compute_chunks(req); 100362306a36Sopenharmony_ci struct n2_crypto_chunk *c, *tmp; 100462306a36Sopenharmony_ci struct spu_queue *qp; 100562306a36Sopenharmony_ci void *final_iv_addr; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci final_iv_addr = NULL; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci if (err) 101062306a36Sopenharmony_ci return err; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci qp = cpu_to_cwq[get_cpu()]; 101362306a36Sopenharmony_ci err = -ENODEV; 101462306a36Sopenharmony_ci if (!qp) 101562306a36Sopenharmony_ci goto out; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci spin_lock_irqsave(&qp->lock, flags); 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci if (encrypt) { 102062306a36Sopenharmony_ci iv_paddr = __pa(rctx->walk.iv); 102162306a36Sopenharmony_ci list_for_each_entry_safe(c, tmp, &rctx->chunk_list, 102262306a36Sopenharmony_ci entry) { 102362306a36Sopenharmony_ci c->iv_paddr = iv_paddr; 102462306a36Sopenharmony_ci err = __n2_crypt_chunk(tfm, c, qp, true); 102562306a36Sopenharmony_ci if (err) 102662306a36Sopenharmony_ci break; 102762306a36Sopenharmony_ci iv_paddr = c->dest_final - rctx->walk.blocksize; 102862306a36Sopenharmony_ci list_del(&c->entry); 102962306a36Sopenharmony_ci if (unlikely(c != &rctx->chunk)) 103062306a36Sopenharmony_ci kfree(c); 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci final_iv_addr = __va(iv_paddr); 103362306a36Sopenharmony_ci } else { 103462306a36Sopenharmony_ci list_for_each_entry_safe_reverse(c, tmp, &rctx->chunk_list, 103562306a36Sopenharmony_ci entry) { 103662306a36Sopenharmony_ci if (c == &rctx->chunk) { 103762306a36Sopenharmony_ci iv_paddr = __pa(rctx->walk.iv); 103862306a36Sopenharmony_ci } else { 103962306a36Sopenharmony_ci iv_paddr = (tmp->arr[tmp->arr_len-1].src_paddr + 104062306a36Sopenharmony_ci tmp->arr[tmp->arr_len-1].src_len - 104162306a36Sopenharmony_ci rctx->walk.blocksize); 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci if (!final_iv_addr) { 104462306a36Sopenharmony_ci unsigned long pa; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci pa = (c->arr[c->arr_len-1].src_paddr + 104762306a36Sopenharmony_ci c->arr[c->arr_len-1].src_len - 104862306a36Sopenharmony_ci rctx->walk.blocksize); 104962306a36Sopenharmony_ci final_iv_addr = rctx->temp_iv; 105062306a36Sopenharmony_ci memcpy(rctx->temp_iv, __va(pa), 105162306a36Sopenharmony_ci rctx->walk.blocksize); 105262306a36Sopenharmony_ci } 105362306a36Sopenharmony_ci c->iv_paddr = iv_paddr; 105462306a36Sopenharmony_ci err = __n2_crypt_chunk(tfm, c, qp, false); 105562306a36Sopenharmony_ci if (err) 105662306a36Sopenharmony_ci break; 105762306a36Sopenharmony_ci list_del(&c->entry); 105862306a36Sopenharmony_ci if (unlikely(c != &rctx->chunk)) 105962306a36Sopenharmony_ci kfree(c); 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci } 106262306a36Sopenharmony_ci if (!err) { 106362306a36Sopenharmony_ci hv_ret = wait_for_tail(qp); 106462306a36Sopenharmony_ci if (hv_ret != HV_EOK) 106562306a36Sopenharmony_ci err = -EINVAL; 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci spin_unlock_irqrestore(&qp->lock, flags); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ciout: 107162306a36Sopenharmony_ci put_cpu(); 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci n2_chunk_complete(req, err ? NULL : final_iv_addr); 107462306a36Sopenharmony_ci return err; 107562306a36Sopenharmony_ci} 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_cistatic int n2_encrypt_chaining(struct skcipher_request *req) 107862306a36Sopenharmony_ci{ 107962306a36Sopenharmony_ci return n2_do_chaining(req, true); 108062306a36Sopenharmony_ci} 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_cistatic int n2_decrypt_chaining(struct skcipher_request *req) 108362306a36Sopenharmony_ci{ 108462306a36Sopenharmony_ci return n2_do_chaining(req, false); 108562306a36Sopenharmony_ci} 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_cistruct n2_skcipher_tmpl { 108862306a36Sopenharmony_ci const char *name; 108962306a36Sopenharmony_ci const char *drv_name; 109062306a36Sopenharmony_ci u8 block_size; 109162306a36Sopenharmony_ci u8 enc_type; 109262306a36Sopenharmony_ci struct skcipher_alg skcipher; 109362306a36Sopenharmony_ci}; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_cistatic const struct n2_skcipher_tmpl skcipher_tmpls[] = { 109662306a36Sopenharmony_ci /* DES: ECB CBC and CFB are supported */ 109762306a36Sopenharmony_ci { .name = "ecb(des)", 109862306a36Sopenharmony_ci .drv_name = "ecb-des", 109962306a36Sopenharmony_ci .block_size = DES_BLOCK_SIZE, 110062306a36Sopenharmony_ci .enc_type = (ENC_TYPE_ALG_DES | 110162306a36Sopenharmony_ci ENC_TYPE_CHAINING_ECB), 110262306a36Sopenharmony_ci .skcipher = { 110362306a36Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 110462306a36Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 110562306a36Sopenharmony_ci .setkey = n2_des_setkey, 110662306a36Sopenharmony_ci .encrypt = n2_encrypt_ecb, 110762306a36Sopenharmony_ci .decrypt = n2_decrypt_ecb, 110862306a36Sopenharmony_ci }, 110962306a36Sopenharmony_ci }, 111062306a36Sopenharmony_ci { .name = "cbc(des)", 111162306a36Sopenharmony_ci .drv_name = "cbc-des", 111262306a36Sopenharmony_ci .block_size = DES_BLOCK_SIZE, 111362306a36Sopenharmony_ci .enc_type = (ENC_TYPE_ALG_DES | 111462306a36Sopenharmony_ci ENC_TYPE_CHAINING_CBC), 111562306a36Sopenharmony_ci .skcipher = { 111662306a36Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 111762306a36Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 111862306a36Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 111962306a36Sopenharmony_ci .setkey = n2_des_setkey, 112062306a36Sopenharmony_ci .encrypt = n2_encrypt_chaining, 112162306a36Sopenharmony_ci .decrypt = n2_decrypt_chaining, 112262306a36Sopenharmony_ci }, 112362306a36Sopenharmony_ci }, 112462306a36Sopenharmony_ci { .name = "cfb(des)", 112562306a36Sopenharmony_ci .drv_name = "cfb-des", 112662306a36Sopenharmony_ci .block_size = DES_BLOCK_SIZE, 112762306a36Sopenharmony_ci .enc_type = (ENC_TYPE_ALG_DES | 112862306a36Sopenharmony_ci ENC_TYPE_CHAINING_CFB), 112962306a36Sopenharmony_ci .skcipher = { 113062306a36Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 113162306a36Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 113262306a36Sopenharmony_ci .setkey = n2_des_setkey, 113362306a36Sopenharmony_ci .encrypt = n2_encrypt_chaining, 113462306a36Sopenharmony_ci .decrypt = n2_decrypt_chaining, 113562306a36Sopenharmony_ci }, 113662306a36Sopenharmony_ci }, 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci /* 3DES: ECB CBC and CFB are supported */ 113962306a36Sopenharmony_ci { .name = "ecb(des3_ede)", 114062306a36Sopenharmony_ci .drv_name = "ecb-3des", 114162306a36Sopenharmony_ci .block_size = DES_BLOCK_SIZE, 114262306a36Sopenharmony_ci .enc_type = (ENC_TYPE_ALG_3DES | 114362306a36Sopenharmony_ci ENC_TYPE_CHAINING_ECB), 114462306a36Sopenharmony_ci .skcipher = { 114562306a36Sopenharmony_ci .min_keysize = 3 * DES_KEY_SIZE, 114662306a36Sopenharmony_ci .max_keysize = 3 * DES_KEY_SIZE, 114762306a36Sopenharmony_ci .setkey = n2_3des_setkey, 114862306a36Sopenharmony_ci .encrypt = n2_encrypt_ecb, 114962306a36Sopenharmony_ci .decrypt = n2_decrypt_ecb, 115062306a36Sopenharmony_ci }, 115162306a36Sopenharmony_ci }, 115262306a36Sopenharmony_ci { .name = "cbc(des3_ede)", 115362306a36Sopenharmony_ci .drv_name = "cbc-3des", 115462306a36Sopenharmony_ci .block_size = DES_BLOCK_SIZE, 115562306a36Sopenharmony_ci .enc_type = (ENC_TYPE_ALG_3DES | 115662306a36Sopenharmony_ci ENC_TYPE_CHAINING_CBC), 115762306a36Sopenharmony_ci .skcipher = { 115862306a36Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 115962306a36Sopenharmony_ci .min_keysize = 3 * DES_KEY_SIZE, 116062306a36Sopenharmony_ci .max_keysize = 3 * DES_KEY_SIZE, 116162306a36Sopenharmony_ci .setkey = n2_3des_setkey, 116262306a36Sopenharmony_ci .encrypt = n2_encrypt_chaining, 116362306a36Sopenharmony_ci .decrypt = n2_decrypt_chaining, 116462306a36Sopenharmony_ci }, 116562306a36Sopenharmony_ci }, 116662306a36Sopenharmony_ci { .name = "cfb(des3_ede)", 116762306a36Sopenharmony_ci .drv_name = "cfb-3des", 116862306a36Sopenharmony_ci .block_size = DES_BLOCK_SIZE, 116962306a36Sopenharmony_ci .enc_type = (ENC_TYPE_ALG_3DES | 117062306a36Sopenharmony_ci ENC_TYPE_CHAINING_CFB), 117162306a36Sopenharmony_ci .skcipher = { 117262306a36Sopenharmony_ci .min_keysize = 3 * DES_KEY_SIZE, 117362306a36Sopenharmony_ci .max_keysize = 3 * DES_KEY_SIZE, 117462306a36Sopenharmony_ci .setkey = n2_3des_setkey, 117562306a36Sopenharmony_ci .encrypt = n2_encrypt_chaining, 117662306a36Sopenharmony_ci .decrypt = n2_decrypt_chaining, 117762306a36Sopenharmony_ci }, 117862306a36Sopenharmony_ci }, 117962306a36Sopenharmony_ci /* AES: ECB CBC and CTR are supported */ 118062306a36Sopenharmony_ci { .name = "ecb(aes)", 118162306a36Sopenharmony_ci .drv_name = "ecb-aes", 118262306a36Sopenharmony_ci .block_size = AES_BLOCK_SIZE, 118362306a36Sopenharmony_ci .enc_type = (ENC_TYPE_ALG_AES128 | 118462306a36Sopenharmony_ci ENC_TYPE_CHAINING_ECB), 118562306a36Sopenharmony_ci .skcipher = { 118662306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 118762306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 118862306a36Sopenharmony_ci .setkey = n2_aes_setkey, 118962306a36Sopenharmony_ci .encrypt = n2_encrypt_ecb, 119062306a36Sopenharmony_ci .decrypt = n2_decrypt_ecb, 119162306a36Sopenharmony_ci }, 119262306a36Sopenharmony_ci }, 119362306a36Sopenharmony_ci { .name = "cbc(aes)", 119462306a36Sopenharmony_ci .drv_name = "cbc-aes", 119562306a36Sopenharmony_ci .block_size = AES_BLOCK_SIZE, 119662306a36Sopenharmony_ci .enc_type = (ENC_TYPE_ALG_AES128 | 119762306a36Sopenharmony_ci ENC_TYPE_CHAINING_CBC), 119862306a36Sopenharmony_ci .skcipher = { 119962306a36Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 120062306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 120162306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 120262306a36Sopenharmony_ci .setkey = n2_aes_setkey, 120362306a36Sopenharmony_ci .encrypt = n2_encrypt_chaining, 120462306a36Sopenharmony_ci .decrypt = n2_decrypt_chaining, 120562306a36Sopenharmony_ci }, 120662306a36Sopenharmony_ci }, 120762306a36Sopenharmony_ci { .name = "ctr(aes)", 120862306a36Sopenharmony_ci .drv_name = "ctr-aes", 120962306a36Sopenharmony_ci .block_size = AES_BLOCK_SIZE, 121062306a36Sopenharmony_ci .enc_type = (ENC_TYPE_ALG_AES128 | 121162306a36Sopenharmony_ci ENC_TYPE_CHAINING_COUNTER), 121262306a36Sopenharmony_ci .skcipher = { 121362306a36Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 121462306a36Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 121562306a36Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 121662306a36Sopenharmony_ci .setkey = n2_aes_setkey, 121762306a36Sopenharmony_ci .encrypt = n2_encrypt_chaining, 121862306a36Sopenharmony_ci .decrypt = n2_encrypt_chaining, 121962306a36Sopenharmony_ci }, 122062306a36Sopenharmony_ci }, 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci}; 122362306a36Sopenharmony_ci#define NUM_CIPHER_TMPLS ARRAY_SIZE(skcipher_tmpls) 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_cistatic LIST_HEAD(skcipher_algs); 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_cistruct n2_hash_tmpl { 122862306a36Sopenharmony_ci const char *name; 122962306a36Sopenharmony_ci const u8 *hash_zero; 123062306a36Sopenharmony_ci const u8 *hash_init; 123162306a36Sopenharmony_ci u8 hw_op_hashsz; 123262306a36Sopenharmony_ci u8 digest_size; 123362306a36Sopenharmony_ci u8 statesize; 123462306a36Sopenharmony_ci u8 block_size; 123562306a36Sopenharmony_ci u8 auth_type; 123662306a36Sopenharmony_ci u8 hmac_type; 123762306a36Sopenharmony_ci}; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_cistatic const __le32 n2_md5_init[MD5_HASH_WORDS] = { 124062306a36Sopenharmony_ci cpu_to_le32(MD5_H0), 124162306a36Sopenharmony_ci cpu_to_le32(MD5_H1), 124262306a36Sopenharmony_ci cpu_to_le32(MD5_H2), 124362306a36Sopenharmony_ci cpu_to_le32(MD5_H3), 124462306a36Sopenharmony_ci}; 124562306a36Sopenharmony_cistatic const u32 n2_sha1_init[SHA1_DIGEST_SIZE / 4] = { 124662306a36Sopenharmony_ci SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4, 124762306a36Sopenharmony_ci}; 124862306a36Sopenharmony_cistatic const u32 n2_sha256_init[SHA256_DIGEST_SIZE / 4] = { 124962306a36Sopenharmony_ci SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3, 125062306a36Sopenharmony_ci SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7, 125162306a36Sopenharmony_ci}; 125262306a36Sopenharmony_cistatic const u32 n2_sha224_init[SHA256_DIGEST_SIZE / 4] = { 125362306a36Sopenharmony_ci SHA224_H0, SHA224_H1, SHA224_H2, SHA224_H3, 125462306a36Sopenharmony_ci SHA224_H4, SHA224_H5, SHA224_H6, SHA224_H7, 125562306a36Sopenharmony_ci}; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_cistatic const struct n2_hash_tmpl hash_tmpls[] = { 125862306a36Sopenharmony_ci { .name = "md5", 125962306a36Sopenharmony_ci .hash_zero = md5_zero_message_hash, 126062306a36Sopenharmony_ci .hash_init = (u8 *)n2_md5_init, 126162306a36Sopenharmony_ci .auth_type = AUTH_TYPE_MD5, 126262306a36Sopenharmony_ci .hmac_type = AUTH_TYPE_HMAC_MD5, 126362306a36Sopenharmony_ci .hw_op_hashsz = MD5_DIGEST_SIZE, 126462306a36Sopenharmony_ci .digest_size = MD5_DIGEST_SIZE, 126562306a36Sopenharmony_ci .statesize = sizeof(struct md5_state), 126662306a36Sopenharmony_ci .block_size = MD5_HMAC_BLOCK_SIZE }, 126762306a36Sopenharmony_ci { .name = "sha1", 126862306a36Sopenharmony_ci .hash_zero = sha1_zero_message_hash, 126962306a36Sopenharmony_ci .hash_init = (u8 *)n2_sha1_init, 127062306a36Sopenharmony_ci .auth_type = AUTH_TYPE_SHA1, 127162306a36Sopenharmony_ci .hmac_type = AUTH_TYPE_HMAC_SHA1, 127262306a36Sopenharmony_ci .hw_op_hashsz = SHA1_DIGEST_SIZE, 127362306a36Sopenharmony_ci .digest_size = SHA1_DIGEST_SIZE, 127462306a36Sopenharmony_ci .statesize = sizeof(struct sha1_state), 127562306a36Sopenharmony_ci .block_size = SHA1_BLOCK_SIZE }, 127662306a36Sopenharmony_ci { .name = "sha256", 127762306a36Sopenharmony_ci .hash_zero = sha256_zero_message_hash, 127862306a36Sopenharmony_ci .hash_init = (u8 *)n2_sha256_init, 127962306a36Sopenharmony_ci .auth_type = AUTH_TYPE_SHA256, 128062306a36Sopenharmony_ci .hmac_type = AUTH_TYPE_HMAC_SHA256, 128162306a36Sopenharmony_ci .hw_op_hashsz = SHA256_DIGEST_SIZE, 128262306a36Sopenharmony_ci .digest_size = SHA256_DIGEST_SIZE, 128362306a36Sopenharmony_ci .statesize = sizeof(struct sha256_state), 128462306a36Sopenharmony_ci .block_size = SHA256_BLOCK_SIZE }, 128562306a36Sopenharmony_ci { .name = "sha224", 128662306a36Sopenharmony_ci .hash_zero = sha224_zero_message_hash, 128762306a36Sopenharmony_ci .hash_init = (u8 *)n2_sha224_init, 128862306a36Sopenharmony_ci .auth_type = AUTH_TYPE_SHA256, 128962306a36Sopenharmony_ci .hmac_type = AUTH_TYPE_RESERVED, 129062306a36Sopenharmony_ci .hw_op_hashsz = SHA256_DIGEST_SIZE, 129162306a36Sopenharmony_ci .digest_size = SHA224_DIGEST_SIZE, 129262306a36Sopenharmony_ci .statesize = sizeof(struct sha256_state), 129362306a36Sopenharmony_ci .block_size = SHA224_BLOCK_SIZE }, 129462306a36Sopenharmony_ci}; 129562306a36Sopenharmony_ci#define NUM_HASH_TMPLS ARRAY_SIZE(hash_tmpls) 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_cistatic LIST_HEAD(ahash_algs); 129862306a36Sopenharmony_cistatic LIST_HEAD(hmac_algs); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_cistatic int algs_registered; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_cistatic void __n2_unregister_algs(void) 130362306a36Sopenharmony_ci{ 130462306a36Sopenharmony_ci struct n2_skcipher_alg *skcipher, *skcipher_tmp; 130562306a36Sopenharmony_ci struct n2_ahash_alg *alg, *alg_tmp; 130662306a36Sopenharmony_ci struct n2_hmac_alg *hmac, *hmac_tmp; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci list_for_each_entry_safe(skcipher, skcipher_tmp, &skcipher_algs, entry) { 130962306a36Sopenharmony_ci crypto_unregister_skcipher(&skcipher->skcipher); 131062306a36Sopenharmony_ci list_del(&skcipher->entry); 131162306a36Sopenharmony_ci kfree(skcipher); 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci list_for_each_entry_safe(hmac, hmac_tmp, &hmac_algs, derived.entry) { 131462306a36Sopenharmony_ci crypto_unregister_ahash(&hmac->derived.alg); 131562306a36Sopenharmony_ci list_del(&hmac->derived.entry); 131662306a36Sopenharmony_ci kfree(hmac); 131762306a36Sopenharmony_ci } 131862306a36Sopenharmony_ci list_for_each_entry_safe(alg, alg_tmp, &ahash_algs, entry) { 131962306a36Sopenharmony_ci crypto_unregister_ahash(&alg->alg); 132062306a36Sopenharmony_ci list_del(&alg->entry); 132162306a36Sopenharmony_ci kfree(alg); 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci} 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_cistatic int n2_skcipher_init_tfm(struct crypto_skcipher *tfm) 132662306a36Sopenharmony_ci{ 132762306a36Sopenharmony_ci crypto_skcipher_set_reqsize(tfm, sizeof(struct n2_request_context)); 132862306a36Sopenharmony_ci return 0; 132962306a36Sopenharmony_ci} 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_cistatic int __n2_register_one_skcipher(const struct n2_skcipher_tmpl *tmpl) 133262306a36Sopenharmony_ci{ 133362306a36Sopenharmony_ci struct n2_skcipher_alg *p = kzalloc(sizeof(*p), GFP_KERNEL); 133462306a36Sopenharmony_ci struct skcipher_alg *alg; 133562306a36Sopenharmony_ci int err; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci if (!p) 133862306a36Sopenharmony_ci return -ENOMEM; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci alg = &p->skcipher; 134162306a36Sopenharmony_ci *alg = tmpl->skcipher; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", tmpl->name); 134462306a36Sopenharmony_ci snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s-n2", tmpl->drv_name); 134562306a36Sopenharmony_ci alg->base.cra_priority = N2_CRA_PRIORITY; 134662306a36Sopenharmony_ci alg->base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC | 134762306a36Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY; 134862306a36Sopenharmony_ci alg->base.cra_blocksize = tmpl->block_size; 134962306a36Sopenharmony_ci p->enc_type = tmpl->enc_type; 135062306a36Sopenharmony_ci alg->base.cra_ctxsize = sizeof(struct n2_skcipher_context); 135162306a36Sopenharmony_ci alg->base.cra_module = THIS_MODULE; 135262306a36Sopenharmony_ci alg->init = n2_skcipher_init_tfm; 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci list_add(&p->entry, &skcipher_algs); 135562306a36Sopenharmony_ci err = crypto_register_skcipher(alg); 135662306a36Sopenharmony_ci if (err) { 135762306a36Sopenharmony_ci pr_err("%s alg registration failed\n", alg->base.cra_name); 135862306a36Sopenharmony_ci list_del(&p->entry); 135962306a36Sopenharmony_ci kfree(p); 136062306a36Sopenharmony_ci } else { 136162306a36Sopenharmony_ci pr_info("%s alg registered\n", alg->base.cra_name); 136262306a36Sopenharmony_ci } 136362306a36Sopenharmony_ci return err; 136462306a36Sopenharmony_ci} 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_cistatic int __n2_register_one_hmac(struct n2_ahash_alg *n2ahash) 136762306a36Sopenharmony_ci{ 136862306a36Sopenharmony_ci struct n2_hmac_alg *p = kzalloc(sizeof(*p), GFP_KERNEL); 136962306a36Sopenharmony_ci struct ahash_alg *ahash; 137062306a36Sopenharmony_ci struct crypto_alg *base; 137162306a36Sopenharmony_ci int err; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci if (!p) 137462306a36Sopenharmony_ci return -ENOMEM; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci p->child_alg = n2ahash->alg.halg.base.cra_name; 137762306a36Sopenharmony_ci memcpy(&p->derived, n2ahash, sizeof(struct n2_ahash_alg)); 137862306a36Sopenharmony_ci INIT_LIST_HEAD(&p->derived.entry); 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci ahash = &p->derived.alg; 138162306a36Sopenharmony_ci ahash->digest = n2_hmac_async_digest; 138262306a36Sopenharmony_ci ahash->setkey = n2_hmac_async_setkey; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci base = &ahash->halg.base; 138562306a36Sopenharmony_ci snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)", p->child_alg); 138662306a36Sopenharmony_ci snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "hmac-%s-n2", p->child_alg); 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci base->cra_ctxsize = sizeof(struct n2_hmac_ctx); 138962306a36Sopenharmony_ci base->cra_init = n2_hmac_cra_init; 139062306a36Sopenharmony_ci base->cra_exit = n2_hmac_cra_exit; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci list_add(&p->derived.entry, &hmac_algs); 139362306a36Sopenharmony_ci err = crypto_register_ahash(ahash); 139462306a36Sopenharmony_ci if (err) { 139562306a36Sopenharmony_ci pr_err("%s alg registration failed\n", base->cra_name); 139662306a36Sopenharmony_ci list_del(&p->derived.entry); 139762306a36Sopenharmony_ci kfree(p); 139862306a36Sopenharmony_ci } else { 139962306a36Sopenharmony_ci pr_info("%s alg registered\n", base->cra_name); 140062306a36Sopenharmony_ci } 140162306a36Sopenharmony_ci return err; 140262306a36Sopenharmony_ci} 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_cistatic int __n2_register_one_ahash(const struct n2_hash_tmpl *tmpl) 140562306a36Sopenharmony_ci{ 140662306a36Sopenharmony_ci struct n2_ahash_alg *p = kzalloc(sizeof(*p), GFP_KERNEL); 140762306a36Sopenharmony_ci struct hash_alg_common *halg; 140862306a36Sopenharmony_ci struct crypto_alg *base; 140962306a36Sopenharmony_ci struct ahash_alg *ahash; 141062306a36Sopenharmony_ci int err; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci if (!p) 141362306a36Sopenharmony_ci return -ENOMEM; 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci p->hash_zero = tmpl->hash_zero; 141662306a36Sopenharmony_ci p->hash_init = tmpl->hash_init; 141762306a36Sopenharmony_ci p->auth_type = tmpl->auth_type; 141862306a36Sopenharmony_ci p->hmac_type = tmpl->hmac_type; 141962306a36Sopenharmony_ci p->hw_op_hashsz = tmpl->hw_op_hashsz; 142062306a36Sopenharmony_ci p->digest_size = tmpl->digest_size; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci ahash = &p->alg; 142362306a36Sopenharmony_ci ahash->init = n2_hash_async_init; 142462306a36Sopenharmony_ci ahash->update = n2_hash_async_update; 142562306a36Sopenharmony_ci ahash->final = n2_hash_async_final; 142662306a36Sopenharmony_ci ahash->finup = n2_hash_async_finup; 142762306a36Sopenharmony_ci ahash->digest = n2_hash_async_digest; 142862306a36Sopenharmony_ci ahash->export = n2_hash_async_noexport; 142962306a36Sopenharmony_ci ahash->import = n2_hash_async_noimport; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci halg = &ahash->halg; 143262306a36Sopenharmony_ci halg->digestsize = tmpl->digest_size; 143362306a36Sopenharmony_ci halg->statesize = tmpl->statesize; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci base = &halg->base; 143662306a36Sopenharmony_ci snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "%s", tmpl->name); 143762306a36Sopenharmony_ci snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s-n2", tmpl->name); 143862306a36Sopenharmony_ci base->cra_priority = N2_CRA_PRIORITY; 143962306a36Sopenharmony_ci base->cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 144062306a36Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK; 144162306a36Sopenharmony_ci base->cra_blocksize = tmpl->block_size; 144262306a36Sopenharmony_ci base->cra_ctxsize = sizeof(struct n2_hash_ctx); 144362306a36Sopenharmony_ci base->cra_module = THIS_MODULE; 144462306a36Sopenharmony_ci base->cra_init = n2_hash_cra_init; 144562306a36Sopenharmony_ci base->cra_exit = n2_hash_cra_exit; 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci list_add(&p->entry, &ahash_algs); 144862306a36Sopenharmony_ci err = crypto_register_ahash(ahash); 144962306a36Sopenharmony_ci if (err) { 145062306a36Sopenharmony_ci pr_err("%s alg registration failed\n", base->cra_name); 145162306a36Sopenharmony_ci list_del(&p->entry); 145262306a36Sopenharmony_ci kfree(p); 145362306a36Sopenharmony_ci } else { 145462306a36Sopenharmony_ci pr_info("%s alg registered\n", base->cra_name); 145562306a36Sopenharmony_ci } 145662306a36Sopenharmony_ci if (!err && p->hmac_type != AUTH_TYPE_RESERVED) 145762306a36Sopenharmony_ci err = __n2_register_one_hmac(p); 145862306a36Sopenharmony_ci return err; 145962306a36Sopenharmony_ci} 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_cistatic int n2_register_algs(void) 146262306a36Sopenharmony_ci{ 146362306a36Sopenharmony_ci int i, err = 0; 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci mutex_lock(&spu_lock); 146662306a36Sopenharmony_ci if (algs_registered++) 146762306a36Sopenharmony_ci goto out; 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci for (i = 0; i < NUM_HASH_TMPLS; i++) { 147062306a36Sopenharmony_ci err = __n2_register_one_ahash(&hash_tmpls[i]); 147162306a36Sopenharmony_ci if (err) { 147262306a36Sopenharmony_ci __n2_unregister_algs(); 147362306a36Sopenharmony_ci goto out; 147462306a36Sopenharmony_ci } 147562306a36Sopenharmony_ci } 147662306a36Sopenharmony_ci for (i = 0; i < NUM_CIPHER_TMPLS; i++) { 147762306a36Sopenharmony_ci err = __n2_register_one_skcipher(&skcipher_tmpls[i]); 147862306a36Sopenharmony_ci if (err) { 147962306a36Sopenharmony_ci __n2_unregister_algs(); 148062306a36Sopenharmony_ci goto out; 148162306a36Sopenharmony_ci } 148262306a36Sopenharmony_ci } 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ciout: 148562306a36Sopenharmony_ci mutex_unlock(&spu_lock); 148662306a36Sopenharmony_ci return err; 148762306a36Sopenharmony_ci} 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_cistatic void n2_unregister_algs(void) 149062306a36Sopenharmony_ci{ 149162306a36Sopenharmony_ci mutex_lock(&spu_lock); 149262306a36Sopenharmony_ci if (!--algs_registered) 149362306a36Sopenharmony_ci __n2_unregister_algs(); 149462306a36Sopenharmony_ci mutex_unlock(&spu_lock); 149562306a36Sopenharmony_ci} 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci/* To map CWQ queues to interrupt sources, the hypervisor API provides 149862306a36Sopenharmony_ci * a devino. This isn't very useful to us because all of the 149962306a36Sopenharmony_ci * interrupts listed in the device_node have been translated to 150062306a36Sopenharmony_ci * Linux virtual IRQ cookie numbers. 150162306a36Sopenharmony_ci * 150262306a36Sopenharmony_ci * So we have to back-translate, going through the 'intr' and 'ino' 150362306a36Sopenharmony_ci * property tables of the n2cp MDESC node, matching it with the OF 150462306a36Sopenharmony_ci * 'interrupts' property entries, in order to figure out which 150562306a36Sopenharmony_ci * devino goes to which already-translated IRQ. 150662306a36Sopenharmony_ci */ 150762306a36Sopenharmony_cistatic int find_devino_index(struct platform_device *dev, struct spu_mdesc_info *ip, 150862306a36Sopenharmony_ci unsigned long dev_ino) 150962306a36Sopenharmony_ci{ 151062306a36Sopenharmony_ci const unsigned int *dev_intrs; 151162306a36Sopenharmony_ci unsigned int intr; 151262306a36Sopenharmony_ci int i; 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci for (i = 0; i < ip->num_intrs; i++) { 151562306a36Sopenharmony_ci if (ip->ino_table[i].ino == dev_ino) 151662306a36Sopenharmony_ci break; 151762306a36Sopenharmony_ci } 151862306a36Sopenharmony_ci if (i == ip->num_intrs) 151962306a36Sopenharmony_ci return -ENODEV; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci intr = ip->ino_table[i].intr; 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci dev_intrs = of_get_property(dev->dev.of_node, "interrupts", NULL); 152462306a36Sopenharmony_ci if (!dev_intrs) 152562306a36Sopenharmony_ci return -ENODEV; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci for (i = 0; i < dev->archdata.num_irqs; i++) { 152862306a36Sopenharmony_ci if (dev_intrs[i] == intr) 152962306a36Sopenharmony_ci return i; 153062306a36Sopenharmony_ci } 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci return -ENODEV; 153362306a36Sopenharmony_ci} 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_cistatic int spu_map_ino(struct platform_device *dev, struct spu_mdesc_info *ip, 153662306a36Sopenharmony_ci const char *irq_name, struct spu_queue *p, 153762306a36Sopenharmony_ci irq_handler_t handler) 153862306a36Sopenharmony_ci{ 153962306a36Sopenharmony_ci unsigned long herr; 154062306a36Sopenharmony_ci int index; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci herr = sun4v_ncs_qhandle_to_devino(p->qhandle, &p->devino); 154362306a36Sopenharmony_ci if (herr) 154462306a36Sopenharmony_ci return -EINVAL; 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci index = find_devino_index(dev, ip, p->devino); 154762306a36Sopenharmony_ci if (index < 0) 154862306a36Sopenharmony_ci return index; 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci p->irq = dev->archdata.irqs[index]; 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_ci sprintf(p->irq_name, "%s-%d", irq_name, index); 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci return request_irq(p->irq, handler, 0, p->irq_name, p); 155562306a36Sopenharmony_ci} 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_cistatic struct kmem_cache *queue_cache[2]; 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_cistatic void *new_queue(unsigned long q_type) 156062306a36Sopenharmony_ci{ 156162306a36Sopenharmony_ci return kmem_cache_zalloc(queue_cache[q_type - 1], GFP_KERNEL); 156262306a36Sopenharmony_ci} 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_cistatic void free_queue(void *p, unsigned long q_type) 156562306a36Sopenharmony_ci{ 156662306a36Sopenharmony_ci kmem_cache_free(queue_cache[q_type - 1], p); 156762306a36Sopenharmony_ci} 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_cistatic int queue_cache_init(void) 157062306a36Sopenharmony_ci{ 157162306a36Sopenharmony_ci if (!queue_cache[HV_NCS_QTYPE_MAU - 1]) 157262306a36Sopenharmony_ci queue_cache[HV_NCS_QTYPE_MAU - 1] = 157362306a36Sopenharmony_ci kmem_cache_create("mau_queue", 157462306a36Sopenharmony_ci (MAU_NUM_ENTRIES * 157562306a36Sopenharmony_ci MAU_ENTRY_SIZE), 157662306a36Sopenharmony_ci MAU_ENTRY_SIZE, 0, NULL); 157762306a36Sopenharmony_ci if (!queue_cache[HV_NCS_QTYPE_MAU - 1]) 157862306a36Sopenharmony_ci return -ENOMEM; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci if (!queue_cache[HV_NCS_QTYPE_CWQ - 1]) 158162306a36Sopenharmony_ci queue_cache[HV_NCS_QTYPE_CWQ - 1] = 158262306a36Sopenharmony_ci kmem_cache_create("cwq_queue", 158362306a36Sopenharmony_ci (CWQ_NUM_ENTRIES * 158462306a36Sopenharmony_ci CWQ_ENTRY_SIZE), 158562306a36Sopenharmony_ci CWQ_ENTRY_SIZE, 0, NULL); 158662306a36Sopenharmony_ci if (!queue_cache[HV_NCS_QTYPE_CWQ - 1]) { 158762306a36Sopenharmony_ci kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_MAU - 1]); 158862306a36Sopenharmony_ci queue_cache[HV_NCS_QTYPE_MAU - 1] = NULL; 158962306a36Sopenharmony_ci return -ENOMEM; 159062306a36Sopenharmony_ci } 159162306a36Sopenharmony_ci return 0; 159262306a36Sopenharmony_ci} 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_cistatic void queue_cache_destroy(void) 159562306a36Sopenharmony_ci{ 159662306a36Sopenharmony_ci kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_MAU - 1]); 159762306a36Sopenharmony_ci kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_CWQ - 1]); 159862306a36Sopenharmony_ci queue_cache[HV_NCS_QTYPE_MAU - 1] = NULL; 159962306a36Sopenharmony_ci queue_cache[HV_NCS_QTYPE_CWQ - 1] = NULL; 160062306a36Sopenharmony_ci} 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_cistatic long spu_queue_register_workfn(void *arg) 160362306a36Sopenharmony_ci{ 160462306a36Sopenharmony_ci struct spu_qreg *qr = arg; 160562306a36Sopenharmony_ci struct spu_queue *p = qr->queue; 160662306a36Sopenharmony_ci unsigned long q_type = qr->type; 160762306a36Sopenharmony_ci unsigned long hv_ret; 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci hv_ret = sun4v_ncs_qconf(q_type, __pa(p->q), 161062306a36Sopenharmony_ci CWQ_NUM_ENTRIES, &p->qhandle); 161162306a36Sopenharmony_ci if (!hv_ret) 161262306a36Sopenharmony_ci sun4v_ncs_sethead_marker(p->qhandle, 0); 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci return hv_ret ? -EINVAL : 0; 161562306a36Sopenharmony_ci} 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_cistatic int spu_queue_register(struct spu_queue *p, unsigned long q_type) 161862306a36Sopenharmony_ci{ 161962306a36Sopenharmony_ci int cpu = cpumask_any_and(&p->sharing, cpu_online_mask); 162062306a36Sopenharmony_ci struct spu_qreg qr = { .queue = p, .type = q_type }; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci return work_on_cpu_safe(cpu, spu_queue_register_workfn, &qr); 162362306a36Sopenharmony_ci} 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_cistatic int spu_queue_setup(struct spu_queue *p) 162662306a36Sopenharmony_ci{ 162762306a36Sopenharmony_ci int err; 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci p->q = new_queue(p->q_type); 163062306a36Sopenharmony_ci if (!p->q) 163162306a36Sopenharmony_ci return -ENOMEM; 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci err = spu_queue_register(p, p->q_type); 163462306a36Sopenharmony_ci if (err) { 163562306a36Sopenharmony_ci free_queue(p->q, p->q_type); 163662306a36Sopenharmony_ci p->q = NULL; 163762306a36Sopenharmony_ci } 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci return err; 164062306a36Sopenharmony_ci} 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_cistatic void spu_queue_destroy(struct spu_queue *p) 164362306a36Sopenharmony_ci{ 164462306a36Sopenharmony_ci unsigned long hv_ret; 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci if (!p->q) 164762306a36Sopenharmony_ci return; 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci hv_ret = sun4v_ncs_qconf(p->q_type, p->qhandle, 0, &p->qhandle); 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci if (!hv_ret) 165262306a36Sopenharmony_ci free_queue(p->q, p->q_type); 165362306a36Sopenharmony_ci} 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_cistatic void spu_list_destroy(struct list_head *list) 165662306a36Sopenharmony_ci{ 165762306a36Sopenharmony_ci struct spu_queue *p, *n; 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci list_for_each_entry_safe(p, n, list, list) { 166062306a36Sopenharmony_ci int i; 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_ci for (i = 0; i < NR_CPUS; i++) { 166362306a36Sopenharmony_ci if (cpu_to_cwq[i] == p) 166462306a36Sopenharmony_ci cpu_to_cwq[i] = NULL; 166562306a36Sopenharmony_ci } 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci if (p->irq) { 166862306a36Sopenharmony_ci free_irq(p->irq, p); 166962306a36Sopenharmony_ci p->irq = 0; 167062306a36Sopenharmony_ci } 167162306a36Sopenharmony_ci spu_queue_destroy(p); 167262306a36Sopenharmony_ci list_del(&p->list); 167362306a36Sopenharmony_ci kfree(p); 167462306a36Sopenharmony_ci } 167562306a36Sopenharmony_ci} 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci/* Walk the backward arcs of a CWQ 'exec-unit' node, 167862306a36Sopenharmony_ci * gathering cpu membership information. 167962306a36Sopenharmony_ci */ 168062306a36Sopenharmony_cistatic int spu_mdesc_walk_arcs(struct mdesc_handle *mdesc, 168162306a36Sopenharmony_ci struct platform_device *dev, 168262306a36Sopenharmony_ci u64 node, struct spu_queue *p, 168362306a36Sopenharmony_ci struct spu_queue **table) 168462306a36Sopenharmony_ci{ 168562306a36Sopenharmony_ci u64 arc; 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci mdesc_for_each_arc(arc, mdesc, node, MDESC_ARC_TYPE_BACK) { 168862306a36Sopenharmony_ci u64 tgt = mdesc_arc_target(mdesc, arc); 168962306a36Sopenharmony_ci const char *name = mdesc_node_name(mdesc, tgt); 169062306a36Sopenharmony_ci const u64 *id; 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci if (strcmp(name, "cpu")) 169362306a36Sopenharmony_ci continue; 169462306a36Sopenharmony_ci id = mdesc_get_property(mdesc, tgt, "id", NULL); 169562306a36Sopenharmony_ci if (table[*id] != NULL) { 169662306a36Sopenharmony_ci dev_err(&dev->dev, "%pOF: SPU cpu slot already set.\n", 169762306a36Sopenharmony_ci dev->dev.of_node); 169862306a36Sopenharmony_ci return -EINVAL; 169962306a36Sopenharmony_ci } 170062306a36Sopenharmony_ci cpumask_set_cpu(*id, &p->sharing); 170162306a36Sopenharmony_ci table[*id] = p; 170262306a36Sopenharmony_ci } 170362306a36Sopenharmony_ci return 0; 170462306a36Sopenharmony_ci} 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci/* Process an 'exec-unit' MDESC node of type 'cwq'. */ 170762306a36Sopenharmony_cistatic int handle_exec_unit(struct spu_mdesc_info *ip, struct list_head *list, 170862306a36Sopenharmony_ci struct platform_device *dev, struct mdesc_handle *mdesc, 170962306a36Sopenharmony_ci u64 node, const char *iname, unsigned long q_type, 171062306a36Sopenharmony_ci irq_handler_t handler, struct spu_queue **table) 171162306a36Sopenharmony_ci{ 171262306a36Sopenharmony_ci struct spu_queue *p; 171362306a36Sopenharmony_ci int err; 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci p = kzalloc(sizeof(struct spu_queue), GFP_KERNEL); 171662306a36Sopenharmony_ci if (!p) { 171762306a36Sopenharmony_ci dev_err(&dev->dev, "%pOF: Could not allocate SPU queue.\n", 171862306a36Sopenharmony_ci dev->dev.of_node); 171962306a36Sopenharmony_ci return -ENOMEM; 172062306a36Sopenharmony_ci } 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci cpumask_clear(&p->sharing); 172362306a36Sopenharmony_ci spin_lock_init(&p->lock); 172462306a36Sopenharmony_ci p->q_type = q_type; 172562306a36Sopenharmony_ci INIT_LIST_HEAD(&p->jobs); 172662306a36Sopenharmony_ci list_add(&p->list, list); 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci err = spu_mdesc_walk_arcs(mdesc, dev, node, p, table); 172962306a36Sopenharmony_ci if (err) 173062306a36Sopenharmony_ci return err; 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci err = spu_queue_setup(p); 173362306a36Sopenharmony_ci if (err) 173462306a36Sopenharmony_ci return err; 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci return spu_map_ino(dev, ip, iname, p, handler); 173762306a36Sopenharmony_ci} 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_cistatic int spu_mdesc_scan(struct mdesc_handle *mdesc, struct platform_device *dev, 174062306a36Sopenharmony_ci struct spu_mdesc_info *ip, struct list_head *list, 174162306a36Sopenharmony_ci const char *exec_name, unsigned long q_type, 174262306a36Sopenharmony_ci irq_handler_t handler, struct spu_queue **table) 174362306a36Sopenharmony_ci{ 174462306a36Sopenharmony_ci int err = 0; 174562306a36Sopenharmony_ci u64 node; 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci mdesc_for_each_node_by_name(mdesc, node, "exec-unit") { 174862306a36Sopenharmony_ci const char *type; 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci type = mdesc_get_property(mdesc, node, "type", NULL); 175162306a36Sopenharmony_ci if (!type || strcmp(type, exec_name)) 175262306a36Sopenharmony_ci continue; 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci err = handle_exec_unit(ip, list, dev, mdesc, node, 175562306a36Sopenharmony_ci exec_name, q_type, handler, table); 175662306a36Sopenharmony_ci if (err) { 175762306a36Sopenharmony_ci spu_list_destroy(list); 175862306a36Sopenharmony_ci break; 175962306a36Sopenharmony_ci } 176062306a36Sopenharmony_ci } 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci return err; 176362306a36Sopenharmony_ci} 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_cistatic int get_irq_props(struct mdesc_handle *mdesc, u64 node, 176662306a36Sopenharmony_ci struct spu_mdesc_info *ip) 176762306a36Sopenharmony_ci{ 176862306a36Sopenharmony_ci const u64 *ino; 176962306a36Sopenharmony_ci int ino_len; 177062306a36Sopenharmony_ci int i; 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci ino = mdesc_get_property(mdesc, node, "ino", &ino_len); 177362306a36Sopenharmony_ci if (!ino) { 177462306a36Sopenharmony_ci printk("NO 'ino'\n"); 177562306a36Sopenharmony_ci return -ENODEV; 177662306a36Sopenharmony_ci } 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci ip->num_intrs = ino_len / sizeof(u64); 177962306a36Sopenharmony_ci ip->ino_table = kzalloc((sizeof(struct ino_blob) * 178062306a36Sopenharmony_ci ip->num_intrs), 178162306a36Sopenharmony_ci GFP_KERNEL); 178262306a36Sopenharmony_ci if (!ip->ino_table) 178362306a36Sopenharmony_ci return -ENOMEM; 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci for (i = 0; i < ip->num_intrs; i++) { 178662306a36Sopenharmony_ci struct ino_blob *b = &ip->ino_table[i]; 178762306a36Sopenharmony_ci b->intr = i + 1; 178862306a36Sopenharmony_ci b->ino = ino[i]; 178962306a36Sopenharmony_ci } 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci return 0; 179262306a36Sopenharmony_ci} 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_cistatic int grab_mdesc_irq_props(struct mdesc_handle *mdesc, 179562306a36Sopenharmony_ci struct platform_device *dev, 179662306a36Sopenharmony_ci struct spu_mdesc_info *ip, 179762306a36Sopenharmony_ci const char *node_name) 179862306a36Sopenharmony_ci{ 179962306a36Sopenharmony_ci u64 node, reg; 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci if (of_property_read_reg(dev->dev.of_node, 0, ®, NULL) < 0) 180262306a36Sopenharmony_ci return -ENODEV; 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci mdesc_for_each_node_by_name(mdesc, node, "virtual-device") { 180562306a36Sopenharmony_ci const char *name; 180662306a36Sopenharmony_ci const u64 *chdl; 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci name = mdesc_get_property(mdesc, node, "name", NULL); 180962306a36Sopenharmony_ci if (!name || strcmp(name, node_name)) 181062306a36Sopenharmony_ci continue; 181162306a36Sopenharmony_ci chdl = mdesc_get_property(mdesc, node, "cfg-handle", NULL); 181262306a36Sopenharmony_ci if (!chdl || (*chdl != reg)) 181362306a36Sopenharmony_ci continue; 181462306a36Sopenharmony_ci ip->cfg_handle = *chdl; 181562306a36Sopenharmony_ci return get_irq_props(mdesc, node, ip); 181662306a36Sopenharmony_ci } 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci return -ENODEV; 181962306a36Sopenharmony_ci} 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_cistatic unsigned long n2_spu_hvapi_major; 182262306a36Sopenharmony_cistatic unsigned long n2_spu_hvapi_minor; 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_cistatic int n2_spu_hvapi_register(void) 182562306a36Sopenharmony_ci{ 182662306a36Sopenharmony_ci int err; 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci n2_spu_hvapi_major = 2; 182962306a36Sopenharmony_ci n2_spu_hvapi_minor = 0; 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci err = sun4v_hvapi_register(HV_GRP_NCS, 183262306a36Sopenharmony_ci n2_spu_hvapi_major, 183362306a36Sopenharmony_ci &n2_spu_hvapi_minor); 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci if (!err) 183662306a36Sopenharmony_ci pr_info("Registered NCS HVAPI version %lu.%lu\n", 183762306a36Sopenharmony_ci n2_spu_hvapi_major, 183862306a36Sopenharmony_ci n2_spu_hvapi_minor); 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci return err; 184162306a36Sopenharmony_ci} 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_cistatic void n2_spu_hvapi_unregister(void) 184462306a36Sopenharmony_ci{ 184562306a36Sopenharmony_ci sun4v_hvapi_unregister(HV_GRP_NCS); 184662306a36Sopenharmony_ci} 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_cistatic int global_ref; 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_cistatic int grab_global_resources(void) 185162306a36Sopenharmony_ci{ 185262306a36Sopenharmony_ci int err = 0; 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci mutex_lock(&spu_lock); 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci if (global_ref++) 185762306a36Sopenharmony_ci goto out; 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci err = n2_spu_hvapi_register(); 186062306a36Sopenharmony_ci if (err) 186162306a36Sopenharmony_ci goto out; 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci err = queue_cache_init(); 186462306a36Sopenharmony_ci if (err) 186562306a36Sopenharmony_ci goto out_hvapi_release; 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci err = -ENOMEM; 186862306a36Sopenharmony_ci cpu_to_cwq = kcalloc(NR_CPUS, sizeof(struct spu_queue *), 186962306a36Sopenharmony_ci GFP_KERNEL); 187062306a36Sopenharmony_ci if (!cpu_to_cwq) 187162306a36Sopenharmony_ci goto out_queue_cache_destroy; 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci cpu_to_mau = kcalloc(NR_CPUS, sizeof(struct spu_queue *), 187462306a36Sopenharmony_ci GFP_KERNEL); 187562306a36Sopenharmony_ci if (!cpu_to_mau) 187662306a36Sopenharmony_ci goto out_free_cwq_table; 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci err = 0; 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ciout: 188162306a36Sopenharmony_ci if (err) 188262306a36Sopenharmony_ci global_ref--; 188362306a36Sopenharmony_ci mutex_unlock(&spu_lock); 188462306a36Sopenharmony_ci return err; 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ciout_free_cwq_table: 188762306a36Sopenharmony_ci kfree(cpu_to_cwq); 188862306a36Sopenharmony_ci cpu_to_cwq = NULL; 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ciout_queue_cache_destroy: 189162306a36Sopenharmony_ci queue_cache_destroy(); 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ciout_hvapi_release: 189462306a36Sopenharmony_ci n2_spu_hvapi_unregister(); 189562306a36Sopenharmony_ci goto out; 189662306a36Sopenharmony_ci} 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_cistatic void release_global_resources(void) 189962306a36Sopenharmony_ci{ 190062306a36Sopenharmony_ci mutex_lock(&spu_lock); 190162306a36Sopenharmony_ci if (!--global_ref) { 190262306a36Sopenharmony_ci kfree(cpu_to_cwq); 190362306a36Sopenharmony_ci cpu_to_cwq = NULL; 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci kfree(cpu_to_mau); 190662306a36Sopenharmony_ci cpu_to_mau = NULL; 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci queue_cache_destroy(); 190962306a36Sopenharmony_ci n2_spu_hvapi_unregister(); 191062306a36Sopenharmony_ci } 191162306a36Sopenharmony_ci mutex_unlock(&spu_lock); 191262306a36Sopenharmony_ci} 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_cistatic struct n2_crypto *alloc_n2cp(void) 191562306a36Sopenharmony_ci{ 191662306a36Sopenharmony_ci struct n2_crypto *np = kzalloc(sizeof(struct n2_crypto), GFP_KERNEL); 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci if (np) 191962306a36Sopenharmony_ci INIT_LIST_HEAD(&np->cwq_list); 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci return np; 192262306a36Sopenharmony_ci} 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_cistatic void free_n2cp(struct n2_crypto *np) 192562306a36Sopenharmony_ci{ 192662306a36Sopenharmony_ci kfree(np->cwq_info.ino_table); 192762306a36Sopenharmony_ci np->cwq_info.ino_table = NULL; 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci kfree(np); 193062306a36Sopenharmony_ci} 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_cistatic void n2_spu_driver_version(void) 193362306a36Sopenharmony_ci{ 193462306a36Sopenharmony_ci static int n2_spu_version_printed; 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci if (n2_spu_version_printed++ == 0) 193762306a36Sopenharmony_ci pr_info("%s", version); 193862306a36Sopenharmony_ci} 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_cistatic int n2_crypto_probe(struct platform_device *dev) 194162306a36Sopenharmony_ci{ 194262306a36Sopenharmony_ci struct mdesc_handle *mdesc; 194362306a36Sopenharmony_ci struct n2_crypto *np; 194462306a36Sopenharmony_ci int err; 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci n2_spu_driver_version(); 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ci pr_info("Found N2CP at %pOF\n", dev->dev.of_node); 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci np = alloc_n2cp(); 195162306a36Sopenharmony_ci if (!np) { 195262306a36Sopenharmony_ci dev_err(&dev->dev, "%pOF: Unable to allocate n2cp.\n", 195362306a36Sopenharmony_ci dev->dev.of_node); 195462306a36Sopenharmony_ci return -ENOMEM; 195562306a36Sopenharmony_ci } 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci err = grab_global_resources(); 195862306a36Sopenharmony_ci if (err) { 195962306a36Sopenharmony_ci dev_err(&dev->dev, "%pOF: Unable to grab global resources.\n", 196062306a36Sopenharmony_ci dev->dev.of_node); 196162306a36Sopenharmony_ci goto out_free_n2cp; 196262306a36Sopenharmony_ci } 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci mdesc = mdesc_grab(); 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci if (!mdesc) { 196762306a36Sopenharmony_ci dev_err(&dev->dev, "%pOF: Unable to grab MDESC.\n", 196862306a36Sopenharmony_ci dev->dev.of_node); 196962306a36Sopenharmony_ci err = -ENODEV; 197062306a36Sopenharmony_ci goto out_free_global; 197162306a36Sopenharmony_ci } 197262306a36Sopenharmony_ci err = grab_mdesc_irq_props(mdesc, dev, &np->cwq_info, "n2cp"); 197362306a36Sopenharmony_ci if (err) { 197462306a36Sopenharmony_ci dev_err(&dev->dev, "%pOF: Unable to grab IRQ props.\n", 197562306a36Sopenharmony_ci dev->dev.of_node); 197662306a36Sopenharmony_ci mdesc_release(mdesc); 197762306a36Sopenharmony_ci goto out_free_global; 197862306a36Sopenharmony_ci } 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci err = spu_mdesc_scan(mdesc, dev, &np->cwq_info, &np->cwq_list, 198162306a36Sopenharmony_ci "cwq", HV_NCS_QTYPE_CWQ, cwq_intr, 198262306a36Sopenharmony_ci cpu_to_cwq); 198362306a36Sopenharmony_ci mdesc_release(mdesc); 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci if (err) { 198662306a36Sopenharmony_ci dev_err(&dev->dev, "%pOF: CWQ MDESC scan failed.\n", 198762306a36Sopenharmony_ci dev->dev.of_node); 198862306a36Sopenharmony_ci goto out_free_global; 198962306a36Sopenharmony_ci } 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci err = n2_register_algs(); 199262306a36Sopenharmony_ci if (err) { 199362306a36Sopenharmony_ci dev_err(&dev->dev, "%pOF: Unable to register algorithms.\n", 199462306a36Sopenharmony_ci dev->dev.of_node); 199562306a36Sopenharmony_ci goto out_free_spu_list; 199662306a36Sopenharmony_ci } 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci dev_set_drvdata(&dev->dev, np); 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci return 0; 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ciout_free_spu_list: 200362306a36Sopenharmony_ci spu_list_destroy(&np->cwq_list); 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ciout_free_global: 200662306a36Sopenharmony_ci release_global_resources(); 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ciout_free_n2cp: 200962306a36Sopenharmony_ci free_n2cp(np); 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci return err; 201262306a36Sopenharmony_ci} 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_cistatic int n2_crypto_remove(struct platform_device *dev) 201562306a36Sopenharmony_ci{ 201662306a36Sopenharmony_ci struct n2_crypto *np = dev_get_drvdata(&dev->dev); 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_ci n2_unregister_algs(); 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci spu_list_destroy(&np->cwq_list); 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci release_global_resources(); 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci free_n2cp(np); 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci return 0; 202762306a36Sopenharmony_ci} 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_cistatic struct n2_mau *alloc_ncp(void) 203062306a36Sopenharmony_ci{ 203162306a36Sopenharmony_ci struct n2_mau *mp = kzalloc(sizeof(struct n2_mau), GFP_KERNEL); 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci if (mp) 203462306a36Sopenharmony_ci INIT_LIST_HEAD(&mp->mau_list); 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci return mp; 203762306a36Sopenharmony_ci} 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_cistatic void free_ncp(struct n2_mau *mp) 204062306a36Sopenharmony_ci{ 204162306a36Sopenharmony_ci kfree(mp->mau_info.ino_table); 204262306a36Sopenharmony_ci mp->mau_info.ino_table = NULL; 204362306a36Sopenharmony_ci 204462306a36Sopenharmony_ci kfree(mp); 204562306a36Sopenharmony_ci} 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_cistatic int n2_mau_probe(struct platform_device *dev) 204862306a36Sopenharmony_ci{ 204962306a36Sopenharmony_ci struct mdesc_handle *mdesc; 205062306a36Sopenharmony_ci struct n2_mau *mp; 205162306a36Sopenharmony_ci int err; 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci n2_spu_driver_version(); 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ci pr_info("Found NCP at %pOF\n", dev->dev.of_node); 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci mp = alloc_ncp(); 205862306a36Sopenharmony_ci if (!mp) { 205962306a36Sopenharmony_ci dev_err(&dev->dev, "%pOF: Unable to allocate ncp.\n", 206062306a36Sopenharmony_ci dev->dev.of_node); 206162306a36Sopenharmony_ci return -ENOMEM; 206262306a36Sopenharmony_ci } 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci err = grab_global_resources(); 206562306a36Sopenharmony_ci if (err) { 206662306a36Sopenharmony_ci dev_err(&dev->dev, "%pOF: Unable to grab global resources.\n", 206762306a36Sopenharmony_ci dev->dev.of_node); 206862306a36Sopenharmony_ci goto out_free_ncp; 206962306a36Sopenharmony_ci } 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci mdesc = mdesc_grab(); 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci if (!mdesc) { 207462306a36Sopenharmony_ci dev_err(&dev->dev, "%pOF: Unable to grab MDESC.\n", 207562306a36Sopenharmony_ci dev->dev.of_node); 207662306a36Sopenharmony_ci err = -ENODEV; 207762306a36Sopenharmony_ci goto out_free_global; 207862306a36Sopenharmony_ci } 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci err = grab_mdesc_irq_props(mdesc, dev, &mp->mau_info, "ncp"); 208162306a36Sopenharmony_ci if (err) { 208262306a36Sopenharmony_ci dev_err(&dev->dev, "%pOF: Unable to grab IRQ props.\n", 208362306a36Sopenharmony_ci dev->dev.of_node); 208462306a36Sopenharmony_ci mdesc_release(mdesc); 208562306a36Sopenharmony_ci goto out_free_global; 208662306a36Sopenharmony_ci } 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_ci err = spu_mdesc_scan(mdesc, dev, &mp->mau_info, &mp->mau_list, 208962306a36Sopenharmony_ci "mau", HV_NCS_QTYPE_MAU, mau_intr, 209062306a36Sopenharmony_ci cpu_to_mau); 209162306a36Sopenharmony_ci mdesc_release(mdesc); 209262306a36Sopenharmony_ci 209362306a36Sopenharmony_ci if (err) { 209462306a36Sopenharmony_ci dev_err(&dev->dev, "%pOF: MAU MDESC scan failed.\n", 209562306a36Sopenharmony_ci dev->dev.of_node); 209662306a36Sopenharmony_ci goto out_free_global; 209762306a36Sopenharmony_ci } 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci dev_set_drvdata(&dev->dev, mp); 210062306a36Sopenharmony_ci 210162306a36Sopenharmony_ci return 0; 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ciout_free_global: 210462306a36Sopenharmony_ci release_global_resources(); 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ciout_free_ncp: 210762306a36Sopenharmony_ci free_ncp(mp); 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_ci return err; 211062306a36Sopenharmony_ci} 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_cistatic int n2_mau_remove(struct platform_device *dev) 211362306a36Sopenharmony_ci{ 211462306a36Sopenharmony_ci struct n2_mau *mp = dev_get_drvdata(&dev->dev); 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci spu_list_destroy(&mp->mau_list); 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci release_global_resources(); 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci free_ncp(mp); 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci return 0; 212362306a36Sopenharmony_ci} 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_cistatic const struct of_device_id n2_crypto_match[] = { 212662306a36Sopenharmony_ci { 212762306a36Sopenharmony_ci .name = "n2cp", 212862306a36Sopenharmony_ci .compatible = "SUNW,n2-cwq", 212962306a36Sopenharmony_ci }, 213062306a36Sopenharmony_ci { 213162306a36Sopenharmony_ci .name = "n2cp", 213262306a36Sopenharmony_ci .compatible = "SUNW,vf-cwq", 213362306a36Sopenharmony_ci }, 213462306a36Sopenharmony_ci { 213562306a36Sopenharmony_ci .name = "n2cp", 213662306a36Sopenharmony_ci .compatible = "SUNW,kt-cwq", 213762306a36Sopenharmony_ci }, 213862306a36Sopenharmony_ci {}, 213962306a36Sopenharmony_ci}; 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, n2_crypto_match); 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_cistatic struct platform_driver n2_crypto_driver = { 214462306a36Sopenharmony_ci .driver = { 214562306a36Sopenharmony_ci .name = "n2cp", 214662306a36Sopenharmony_ci .of_match_table = n2_crypto_match, 214762306a36Sopenharmony_ci }, 214862306a36Sopenharmony_ci .probe = n2_crypto_probe, 214962306a36Sopenharmony_ci .remove = n2_crypto_remove, 215062306a36Sopenharmony_ci}; 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_cistatic const struct of_device_id n2_mau_match[] = { 215362306a36Sopenharmony_ci { 215462306a36Sopenharmony_ci .name = "ncp", 215562306a36Sopenharmony_ci .compatible = "SUNW,n2-mau", 215662306a36Sopenharmony_ci }, 215762306a36Sopenharmony_ci { 215862306a36Sopenharmony_ci .name = "ncp", 215962306a36Sopenharmony_ci .compatible = "SUNW,vf-mau", 216062306a36Sopenharmony_ci }, 216162306a36Sopenharmony_ci { 216262306a36Sopenharmony_ci .name = "ncp", 216362306a36Sopenharmony_ci .compatible = "SUNW,kt-mau", 216462306a36Sopenharmony_ci }, 216562306a36Sopenharmony_ci {}, 216662306a36Sopenharmony_ci}; 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, n2_mau_match); 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_cistatic struct platform_driver n2_mau_driver = { 217162306a36Sopenharmony_ci .driver = { 217262306a36Sopenharmony_ci .name = "ncp", 217362306a36Sopenharmony_ci .of_match_table = n2_mau_match, 217462306a36Sopenharmony_ci }, 217562306a36Sopenharmony_ci .probe = n2_mau_probe, 217662306a36Sopenharmony_ci .remove = n2_mau_remove, 217762306a36Sopenharmony_ci}; 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_cistatic struct platform_driver * const drivers[] = { 218062306a36Sopenharmony_ci &n2_crypto_driver, 218162306a36Sopenharmony_ci &n2_mau_driver, 218262306a36Sopenharmony_ci}; 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_cistatic int __init n2_init(void) 218562306a36Sopenharmony_ci{ 218662306a36Sopenharmony_ci return platform_register_drivers(drivers, ARRAY_SIZE(drivers)); 218762306a36Sopenharmony_ci} 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_cistatic void __exit n2_exit(void) 219062306a36Sopenharmony_ci{ 219162306a36Sopenharmony_ci platform_unregister_drivers(drivers, ARRAY_SIZE(drivers)); 219262306a36Sopenharmony_ci} 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_cimodule_init(n2_init); 219562306a36Sopenharmony_cimodule_exit(n2_exit); 2196