18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* n2_core.c: Niagara2 Stream Processing Unit (SPU) crypto support. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2010, 2011 David S. Miller <davem@davemloft.net> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/of.h> 128c2ecf20Sopenharmony_ci#include <linux/of_device.h> 138c2ecf20Sopenharmony_ci#include <linux/cpumask.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 168c2ecf20Sopenharmony_ci#include <linux/crypto.h> 178c2ecf20Sopenharmony_ci#include <crypto/md5.h> 188c2ecf20Sopenharmony_ci#include <crypto/sha.h> 198c2ecf20Sopenharmony_ci#include <crypto/aes.h> 208c2ecf20Sopenharmony_ci#include <crypto/internal/des.h> 218c2ecf20Sopenharmony_ci#include <linux/mutex.h> 228c2ecf20Sopenharmony_ci#include <linux/delay.h> 238c2ecf20Sopenharmony_ci#include <linux/sched.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h> 268c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h> 278c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h> 288c2ecf20Sopenharmony_ci#include <crypto/algapi.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <asm/hypervisor.h> 318c2ecf20Sopenharmony_ci#include <asm/mdesc.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include "n2_core.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define DRV_MODULE_NAME "n2_crypto" 368c2ecf20Sopenharmony_ci#define DRV_MODULE_VERSION "0.2" 378c2ecf20Sopenharmony_ci#define DRV_MODULE_RELDATE "July 28, 2011" 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic const char version[] = 408c2ecf20Sopenharmony_ci DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ciMODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); 438c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Niagara2 Crypto driver"); 448c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 458c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_MODULE_VERSION); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define N2_CRA_PRIORITY 200 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(spu_lock); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct spu_queue { 528c2ecf20Sopenharmony_ci cpumask_t sharing; 538c2ecf20Sopenharmony_ci unsigned long qhandle; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci spinlock_t lock; 568c2ecf20Sopenharmony_ci u8 q_type; 578c2ecf20Sopenharmony_ci void *q; 588c2ecf20Sopenharmony_ci unsigned long head; 598c2ecf20Sopenharmony_ci unsigned long tail; 608c2ecf20Sopenharmony_ci struct list_head jobs; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci unsigned long devino; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci char irq_name[32]; 658c2ecf20Sopenharmony_ci unsigned int irq; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci struct list_head list; 688c2ecf20Sopenharmony_ci}; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistruct spu_qreg { 718c2ecf20Sopenharmony_ci struct spu_queue *queue; 728c2ecf20Sopenharmony_ci unsigned long type; 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic struct spu_queue **cpu_to_cwq; 768c2ecf20Sopenharmony_cistatic struct spu_queue **cpu_to_mau; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic unsigned long spu_next_offset(struct spu_queue *q, unsigned long off) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci if (q->q_type == HV_NCS_QTYPE_MAU) { 818c2ecf20Sopenharmony_ci off += MAU_ENTRY_SIZE; 828c2ecf20Sopenharmony_ci if (off == (MAU_ENTRY_SIZE * MAU_NUM_ENTRIES)) 838c2ecf20Sopenharmony_ci off = 0; 848c2ecf20Sopenharmony_ci } else { 858c2ecf20Sopenharmony_ci off += CWQ_ENTRY_SIZE; 868c2ecf20Sopenharmony_ci if (off == (CWQ_ENTRY_SIZE * CWQ_NUM_ENTRIES)) 878c2ecf20Sopenharmony_ci off = 0; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci return off; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistruct n2_request_common { 938c2ecf20Sopenharmony_ci struct list_head entry; 948c2ecf20Sopenharmony_ci unsigned int offset; 958c2ecf20Sopenharmony_ci}; 968c2ecf20Sopenharmony_ci#define OFFSET_NOT_RUNNING (~(unsigned int)0) 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* An async job request records the final tail value it used in 998c2ecf20Sopenharmony_ci * n2_request_common->offset, test to see if that offset is in 1008c2ecf20Sopenharmony_ci * the range old_head, new_head, inclusive. 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_cistatic inline bool job_finished(struct spu_queue *q, unsigned int offset, 1038c2ecf20Sopenharmony_ci unsigned long old_head, unsigned long new_head) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci if (old_head <= new_head) { 1068c2ecf20Sopenharmony_ci if (offset > old_head && offset <= new_head) 1078c2ecf20Sopenharmony_ci return true; 1088c2ecf20Sopenharmony_ci } else { 1098c2ecf20Sopenharmony_ci if (offset > old_head || offset <= new_head) 1108c2ecf20Sopenharmony_ci return true; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci return false; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* When the HEAD marker is unequal to the actual HEAD, we get 1168c2ecf20Sopenharmony_ci * a virtual device INO interrupt. We should process the 1178c2ecf20Sopenharmony_ci * completed CWQ entries and adjust the HEAD marker to clear 1188c2ecf20Sopenharmony_ci * the IRQ. 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_cistatic irqreturn_t cwq_intr(int irq, void *dev_id) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci unsigned long off, new_head, hv_ret; 1238c2ecf20Sopenharmony_ci struct spu_queue *q = dev_id; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci pr_err("CPU[%d]: Got CWQ interrupt for qhdl[%lx]\n", 1268c2ecf20Sopenharmony_ci smp_processor_id(), q->qhandle); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci spin_lock(&q->lock); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci hv_ret = sun4v_ncs_gethead(q->qhandle, &new_head); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci pr_err("CPU[%d]: CWQ gethead[%lx] hv_ret[%lu]\n", 1338c2ecf20Sopenharmony_ci smp_processor_id(), new_head, hv_ret); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci for (off = q->head; off != new_head; off = spu_next_offset(q, off)) { 1368c2ecf20Sopenharmony_ci /* XXX ... XXX */ 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci hv_ret = sun4v_ncs_sethead_marker(q->qhandle, new_head); 1408c2ecf20Sopenharmony_ci if (hv_ret == HV_EOK) 1418c2ecf20Sopenharmony_ci q->head = new_head; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci spin_unlock(&q->lock); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic irqreturn_t mau_intr(int irq, void *dev_id) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct spu_queue *q = dev_id; 1518c2ecf20Sopenharmony_ci unsigned long head, hv_ret; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci spin_lock(&q->lock); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci pr_err("CPU[%d]: Got MAU interrupt for qhdl[%lx]\n", 1568c2ecf20Sopenharmony_ci smp_processor_id(), q->qhandle); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci hv_ret = sun4v_ncs_gethead(q->qhandle, &head); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci pr_err("CPU[%d]: MAU gethead[%lx] hv_ret[%lu]\n", 1618c2ecf20Sopenharmony_ci smp_processor_id(), head, hv_ret); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci sun4v_ncs_sethead_marker(q->qhandle, head); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci spin_unlock(&q->lock); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic void *spu_queue_next(struct spu_queue *q, void *cur) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci return q->q + spu_next_offset(q, cur - q->q); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic int spu_queue_num_free(struct spu_queue *q) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci unsigned long head = q->head; 1788c2ecf20Sopenharmony_ci unsigned long tail = q->tail; 1798c2ecf20Sopenharmony_ci unsigned long end = (CWQ_ENTRY_SIZE * CWQ_NUM_ENTRIES); 1808c2ecf20Sopenharmony_ci unsigned long diff; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (head > tail) 1838c2ecf20Sopenharmony_ci diff = head - tail; 1848c2ecf20Sopenharmony_ci else 1858c2ecf20Sopenharmony_ci diff = (end - tail) + head; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci return (diff / CWQ_ENTRY_SIZE) - 1; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic void *spu_queue_alloc(struct spu_queue *q, int num_entries) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci int avail = spu_queue_num_free(q); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (avail >= num_entries) 1958c2ecf20Sopenharmony_ci return q->q + q->tail; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return NULL; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic unsigned long spu_queue_submit(struct spu_queue *q, void *last) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci unsigned long hv_ret, new_tail; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci new_tail = spu_next_offset(q, last - q->q); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci hv_ret = sun4v_ncs_settail(q->qhandle, new_tail); 2078c2ecf20Sopenharmony_ci if (hv_ret == HV_EOK) 2088c2ecf20Sopenharmony_ci q->tail = new_tail; 2098c2ecf20Sopenharmony_ci return hv_ret; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic u64 control_word_base(unsigned int len, unsigned int hmac_key_len, 2138c2ecf20Sopenharmony_ci int enc_type, int auth_type, 2148c2ecf20Sopenharmony_ci unsigned int hash_len, 2158c2ecf20Sopenharmony_ci bool sfas, bool sob, bool eob, bool encrypt, 2168c2ecf20Sopenharmony_ci int opcode) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci u64 word = (len - 1) & CONTROL_LEN; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci word |= ((u64) opcode << CONTROL_OPCODE_SHIFT); 2218c2ecf20Sopenharmony_ci word |= ((u64) enc_type << CONTROL_ENC_TYPE_SHIFT); 2228c2ecf20Sopenharmony_ci word |= ((u64) auth_type << CONTROL_AUTH_TYPE_SHIFT); 2238c2ecf20Sopenharmony_ci if (sfas) 2248c2ecf20Sopenharmony_ci word |= CONTROL_STORE_FINAL_AUTH_STATE; 2258c2ecf20Sopenharmony_ci if (sob) 2268c2ecf20Sopenharmony_ci word |= CONTROL_START_OF_BLOCK; 2278c2ecf20Sopenharmony_ci if (eob) 2288c2ecf20Sopenharmony_ci word |= CONTROL_END_OF_BLOCK; 2298c2ecf20Sopenharmony_ci if (encrypt) 2308c2ecf20Sopenharmony_ci word |= CONTROL_ENCRYPT; 2318c2ecf20Sopenharmony_ci if (hmac_key_len) 2328c2ecf20Sopenharmony_ci word |= ((u64) (hmac_key_len - 1)) << CONTROL_HMAC_KEY_LEN_SHIFT; 2338c2ecf20Sopenharmony_ci if (hash_len) 2348c2ecf20Sopenharmony_ci word |= ((u64) (hash_len - 1)) << CONTROL_HASH_LEN_SHIFT; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci return word; 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci#if 0 2408c2ecf20Sopenharmony_cistatic inline bool n2_should_run_async(struct spu_queue *qp, int this_len) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci if (this_len >= 64 || 2438c2ecf20Sopenharmony_ci qp->head != qp->tail) 2448c2ecf20Sopenharmony_ci return true; 2458c2ecf20Sopenharmony_ci return false; 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci#endif 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistruct n2_ahash_alg { 2508c2ecf20Sopenharmony_ci struct list_head entry; 2518c2ecf20Sopenharmony_ci const u8 *hash_zero; 2528c2ecf20Sopenharmony_ci const u8 *hash_init; 2538c2ecf20Sopenharmony_ci u8 hw_op_hashsz; 2548c2ecf20Sopenharmony_ci u8 digest_size; 2558c2ecf20Sopenharmony_ci u8 auth_type; 2568c2ecf20Sopenharmony_ci u8 hmac_type; 2578c2ecf20Sopenharmony_ci struct ahash_alg alg; 2588c2ecf20Sopenharmony_ci}; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic inline struct n2_ahash_alg *n2_ahash_alg(struct crypto_tfm *tfm) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct crypto_alg *alg = tfm->__crt_alg; 2638c2ecf20Sopenharmony_ci struct ahash_alg *ahash_alg; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci ahash_alg = container_of(alg, struct ahash_alg, halg.base); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci return container_of(ahash_alg, struct n2_ahash_alg, alg); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistruct n2_hmac_alg { 2718c2ecf20Sopenharmony_ci const char *child_alg; 2728c2ecf20Sopenharmony_ci struct n2_ahash_alg derived; 2738c2ecf20Sopenharmony_ci}; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic inline struct n2_hmac_alg *n2_hmac_alg(struct crypto_tfm *tfm) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci struct crypto_alg *alg = tfm->__crt_alg; 2788c2ecf20Sopenharmony_ci struct ahash_alg *ahash_alg; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci ahash_alg = container_of(alg, struct ahash_alg, halg.base); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return container_of(ahash_alg, struct n2_hmac_alg, derived.alg); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistruct n2_hash_ctx { 2868c2ecf20Sopenharmony_ci struct crypto_ahash *fallback_tfm; 2878c2ecf20Sopenharmony_ci}; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci#define N2_HASH_KEY_MAX 32 /* HW limit for all HMAC requests */ 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistruct n2_hmac_ctx { 2928c2ecf20Sopenharmony_ci struct n2_hash_ctx base; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci struct crypto_shash *child_shash; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci int hash_key_len; 2978c2ecf20Sopenharmony_ci unsigned char hash_key[N2_HASH_KEY_MAX]; 2988c2ecf20Sopenharmony_ci}; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistruct n2_hash_req_ctx { 3018c2ecf20Sopenharmony_ci union { 3028c2ecf20Sopenharmony_ci struct md5_state md5; 3038c2ecf20Sopenharmony_ci struct sha1_state sha1; 3048c2ecf20Sopenharmony_ci struct sha256_state sha256; 3058c2ecf20Sopenharmony_ci } u; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci struct ahash_request fallback_req; 3088c2ecf20Sopenharmony_ci}; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic int n2_hash_async_init(struct ahash_request *req) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); 3138c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 3148c2ecf20Sopenharmony_ci struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); 3178c2ecf20Sopenharmony_ci rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci return crypto_ahash_init(&rctx->fallback_req); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic int n2_hash_async_update(struct ahash_request *req) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); 3258c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 3268c2ecf20Sopenharmony_ci struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); 3298c2ecf20Sopenharmony_ci rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; 3308c2ecf20Sopenharmony_ci rctx->fallback_req.nbytes = req->nbytes; 3318c2ecf20Sopenharmony_ci rctx->fallback_req.src = req->src; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci return crypto_ahash_update(&rctx->fallback_req); 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic int n2_hash_async_final(struct ahash_request *req) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); 3398c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 3408c2ecf20Sopenharmony_ci struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); 3438c2ecf20Sopenharmony_ci rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; 3448c2ecf20Sopenharmony_ci rctx->fallback_req.result = req->result; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci return crypto_ahash_final(&rctx->fallback_req); 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic int n2_hash_async_finup(struct ahash_request *req) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); 3528c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 3538c2ecf20Sopenharmony_ci struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); 3568c2ecf20Sopenharmony_ci rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; 3578c2ecf20Sopenharmony_ci rctx->fallback_req.nbytes = req->nbytes; 3588c2ecf20Sopenharmony_ci rctx->fallback_req.src = req->src; 3598c2ecf20Sopenharmony_ci rctx->fallback_req.result = req->result; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci return crypto_ahash_finup(&rctx->fallback_req); 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic int n2_hash_async_noimport(struct ahash_request *req, const void *in) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci return -ENOSYS; 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic int n2_hash_async_noexport(struct ahash_request *req, void *out) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci return -ENOSYS; 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic int n2_hash_cra_init(struct crypto_tfm *tfm) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci const char *fallback_driver_name = crypto_tfm_alg_name(tfm); 3778c2ecf20Sopenharmony_ci struct crypto_ahash *ahash = __crypto_ahash_cast(tfm); 3788c2ecf20Sopenharmony_ci struct n2_hash_ctx *ctx = crypto_ahash_ctx(ahash); 3798c2ecf20Sopenharmony_ci struct crypto_ahash *fallback_tfm; 3808c2ecf20Sopenharmony_ci int err; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci fallback_tfm = crypto_alloc_ahash(fallback_driver_name, 0, 3838c2ecf20Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK); 3848c2ecf20Sopenharmony_ci if (IS_ERR(fallback_tfm)) { 3858c2ecf20Sopenharmony_ci pr_warn("Fallback driver '%s' could not be loaded!\n", 3868c2ecf20Sopenharmony_ci fallback_driver_name); 3878c2ecf20Sopenharmony_ci err = PTR_ERR(fallback_tfm); 3888c2ecf20Sopenharmony_ci goto out; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci crypto_ahash_set_reqsize(ahash, (sizeof(struct n2_hash_req_ctx) + 3928c2ecf20Sopenharmony_ci crypto_ahash_reqsize(fallback_tfm))); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci ctx->fallback_tfm = fallback_tfm; 3958c2ecf20Sopenharmony_ci return 0; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ciout: 3988c2ecf20Sopenharmony_ci return err; 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic void n2_hash_cra_exit(struct crypto_tfm *tfm) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci struct crypto_ahash *ahash = __crypto_ahash_cast(tfm); 4048c2ecf20Sopenharmony_ci struct n2_hash_ctx *ctx = crypto_ahash_ctx(ahash); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci crypto_free_ahash(ctx->fallback_tfm); 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic int n2_hmac_cra_init(struct crypto_tfm *tfm) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci const char *fallback_driver_name = crypto_tfm_alg_name(tfm); 4128c2ecf20Sopenharmony_ci struct crypto_ahash *ahash = __crypto_ahash_cast(tfm); 4138c2ecf20Sopenharmony_ci struct n2_hmac_ctx *ctx = crypto_ahash_ctx(ahash); 4148c2ecf20Sopenharmony_ci struct n2_hmac_alg *n2alg = n2_hmac_alg(tfm); 4158c2ecf20Sopenharmony_ci struct crypto_ahash *fallback_tfm; 4168c2ecf20Sopenharmony_ci struct crypto_shash *child_shash; 4178c2ecf20Sopenharmony_ci int err; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci fallback_tfm = crypto_alloc_ahash(fallback_driver_name, 0, 4208c2ecf20Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK); 4218c2ecf20Sopenharmony_ci if (IS_ERR(fallback_tfm)) { 4228c2ecf20Sopenharmony_ci pr_warn("Fallback driver '%s' could not be loaded!\n", 4238c2ecf20Sopenharmony_ci fallback_driver_name); 4248c2ecf20Sopenharmony_ci err = PTR_ERR(fallback_tfm); 4258c2ecf20Sopenharmony_ci goto out; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci child_shash = crypto_alloc_shash(n2alg->child_alg, 0, 0); 4298c2ecf20Sopenharmony_ci if (IS_ERR(child_shash)) { 4308c2ecf20Sopenharmony_ci pr_warn("Child shash '%s' could not be loaded!\n", 4318c2ecf20Sopenharmony_ci n2alg->child_alg); 4328c2ecf20Sopenharmony_ci err = PTR_ERR(child_shash); 4338c2ecf20Sopenharmony_ci goto out_free_fallback; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci crypto_ahash_set_reqsize(ahash, (sizeof(struct n2_hash_req_ctx) + 4378c2ecf20Sopenharmony_ci crypto_ahash_reqsize(fallback_tfm))); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci ctx->child_shash = child_shash; 4408c2ecf20Sopenharmony_ci ctx->base.fallback_tfm = fallback_tfm; 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ciout_free_fallback: 4448c2ecf20Sopenharmony_ci crypto_free_ahash(fallback_tfm); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ciout: 4478c2ecf20Sopenharmony_ci return err; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic void n2_hmac_cra_exit(struct crypto_tfm *tfm) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci struct crypto_ahash *ahash = __crypto_ahash_cast(tfm); 4538c2ecf20Sopenharmony_ci struct n2_hmac_ctx *ctx = crypto_ahash_ctx(ahash); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci crypto_free_ahash(ctx->base.fallback_tfm); 4568c2ecf20Sopenharmony_ci crypto_free_shash(ctx->child_shash); 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic int n2_hmac_async_setkey(struct crypto_ahash *tfm, const u8 *key, 4608c2ecf20Sopenharmony_ci unsigned int keylen) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci struct n2_hmac_ctx *ctx = crypto_ahash_ctx(tfm); 4638c2ecf20Sopenharmony_ci struct crypto_shash *child_shash = ctx->child_shash; 4648c2ecf20Sopenharmony_ci struct crypto_ahash *fallback_tfm; 4658c2ecf20Sopenharmony_ci int err, bs, ds; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci fallback_tfm = ctx->base.fallback_tfm; 4688c2ecf20Sopenharmony_ci err = crypto_ahash_setkey(fallback_tfm, key, keylen); 4698c2ecf20Sopenharmony_ci if (err) 4708c2ecf20Sopenharmony_ci return err; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci bs = crypto_shash_blocksize(child_shash); 4738c2ecf20Sopenharmony_ci ds = crypto_shash_digestsize(child_shash); 4748c2ecf20Sopenharmony_ci BUG_ON(ds > N2_HASH_KEY_MAX); 4758c2ecf20Sopenharmony_ci if (keylen > bs) { 4768c2ecf20Sopenharmony_ci err = crypto_shash_tfm_digest(child_shash, key, keylen, 4778c2ecf20Sopenharmony_ci ctx->hash_key); 4788c2ecf20Sopenharmony_ci if (err) 4798c2ecf20Sopenharmony_ci return err; 4808c2ecf20Sopenharmony_ci keylen = ds; 4818c2ecf20Sopenharmony_ci } else if (keylen <= N2_HASH_KEY_MAX) 4828c2ecf20Sopenharmony_ci memcpy(ctx->hash_key, key, keylen); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci ctx->hash_key_len = keylen; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci return err; 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic unsigned long wait_for_tail(struct spu_queue *qp) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci unsigned long head, hv_ret; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci do { 4948c2ecf20Sopenharmony_ci hv_ret = sun4v_ncs_gethead(qp->qhandle, &head); 4958c2ecf20Sopenharmony_ci if (hv_ret != HV_EOK) { 4968c2ecf20Sopenharmony_ci pr_err("Hypervisor error on gethead\n"); 4978c2ecf20Sopenharmony_ci break; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci if (head == qp->tail) { 5008c2ecf20Sopenharmony_ci qp->head = head; 5018c2ecf20Sopenharmony_ci break; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci } while (1); 5048c2ecf20Sopenharmony_ci return hv_ret; 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic unsigned long submit_and_wait_for_tail(struct spu_queue *qp, 5088c2ecf20Sopenharmony_ci struct cwq_initial_entry *ent) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci unsigned long hv_ret = spu_queue_submit(qp, ent); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci if (hv_ret == HV_EOK) 5138c2ecf20Sopenharmony_ci hv_ret = wait_for_tail(qp); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci return hv_ret; 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic int n2_do_async_digest(struct ahash_request *req, 5198c2ecf20Sopenharmony_ci unsigned int auth_type, unsigned int digest_size, 5208c2ecf20Sopenharmony_ci unsigned int result_size, void *hash_loc, 5218c2ecf20Sopenharmony_ci unsigned long auth_key, unsigned int auth_key_len) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 5248c2ecf20Sopenharmony_ci struct cwq_initial_entry *ent; 5258c2ecf20Sopenharmony_ci struct crypto_hash_walk walk; 5268c2ecf20Sopenharmony_ci struct spu_queue *qp; 5278c2ecf20Sopenharmony_ci unsigned long flags; 5288c2ecf20Sopenharmony_ci int err = -ENODEV; 5298c2ecf20Sopenharmony_ci int nbytes, cpu; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci /* The total effective length of the operation may not 5328c2ecf20Sopenharmony_ci * exceed 2^16. 5338c2ecf20Sopenharmony_ci */ 5348c2ecf20Sopenharmony_ci if (unlikely(req->nbytes > (1 << 16))) { 5358c2ecf20Sopenharmony_ci struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); 5368c2ecf20Sopenharmony_ci struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); 5398c2ecf20Sopenharmony_ci rctx->fallback_req.base.flags = 5408c2ecf20Sopenharmony_ci req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; 5418c2ecf20Sopenharmony_ci rctx->fallback_req.nbytes = req->nbytes; 5428c2ecf20Sopenharmony_ci rctx->fallback_req.src = req->src; 5438c2ecf20Sopenharmony_ci rctx->fallback_req.result = req->result; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci return crypto_ahash_digest(&rctx->fallback_req); 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci nbytes = crypto_hash_walk_first(req, &walk); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci cpu = get_cpu(); 5518c2ecf20Sopenharmony_ci qp = cpu_to_cwq[cpu]; 5528c2ecf20Sopenharmony_ci if (!qp) 5538c2ecf20Sopenharmony_ci goto out; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci spin_lock_irqsave(&qp->lock, flags); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* XXX can do better, improve this later by doing a by-hand scatterlist 5588c2ecf20Sopenharmony_ci * XXX walk, etc. 5598c2ecf20Sopenharmony_ci */ 5608c2ecf20Sopenharmony_ci ent = qp->q + qp->tail; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci ent->control = control_word_base(nbytes, auth_key_len, 0, 5638c2ecf20Sopenharmony_ci auth_type, digest_size, 5648c2ecf20Sopenharmony_ci false, true, false, false, 5658c2ecf20Sopenharmony_ci OPCODE_INPLACE_BIT | 5668c2ecf20Sopenharmony_ci OPCODE_AUTH_MAC); 5678c2ecf20Sopenharmony_ci ent->src_addr = __pa(walk.data); 5688c2ecf20Sopenharmony_ci ent->auth_key_addr = auth_key; 5698c2ecf20Sopenharmony_ci ent->auth_iv_addr = __pa(hash_loc); 5708c2ecf20Sopenharmony_ci ent->final_auth_state_addr = 0UL; 5718c2ecf20Sopenharmony_ci ent->enc_key_addr = 0UL; 5728c2ecf20Sopenharmony_ci ent->enc_iv_addr = 0UL; 5738c2ecf20Sopenharmony_ci ent->dest_addr = __pa(hash_loc); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci nbytes = crypto_hash_walk_done(&walk, 0); 5768c2ecf20Sopenharmony_ci while (nbytes > 0) { 5778c2ecf20Sopenharmony_ci ent = spu_queue_next(qp, ent); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci ent->control = (nbytes - 1); 5808c2ecf20Sopenharmony_ci ent->src_addr = __pa(walk.data); 5818c2ecf20Sopenharmony_ci ent->auth_key_addr = 0UL; 5828c2ecf20Sopenharmony_ci ent->auth_iv_addr = 0UL; 5838c2ecf20Sopenharmony_ci ent->final_auth_state_addr = 0UL; 5848c2ecf20Sopenharmony_ci ent->enc_key_addr = 0UL; 5858c2ecf20Sopenharmony_ci ent->enc_iv_addr = 0UL; 5868c2ecf20Sopenharmony_ci ent->dest_addr = 0UL; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci nbytes = crypto_hash_walk_done(&walk, 0); 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci ent->control |= CONTROL_END_OF_BLOCK; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci if (submit_and_wait_for_tail(qp, ent) != HV_EOK) 5938c2ecf20Sopenharmony_ci err = -EINVAL; 5948c2ecf20Sopenharmony_ci else 5958c2ecf20Sopenharmony_ci err = 0; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->lock, flags); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci if (!err) 6008c2ecf20Sopenharmony_ci memcpy(req->result, hash_loc, result_size); 6018c2ecf20Sopenharmony_ciout: 6028c2ecf20Sopenharmony_ci put_cpu(); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci return err; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic int n2_hash_async_digest(struct ahash_request *req) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci struct n2_ahash_alg *n2alg = n2_ahash_alg(req->base.tfm); 6108c2ecf20Sopenharmony_ci struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); 6118c2ecf20Sopenharmony_ci int ds; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci ds = n2alg->digest_size; 6148c2ecf20Sopenharmony_ci if (unlikely(req->nbytes == 0)) { 6158c2ecf20Sopenharmony_ci memcpy(req->result, n2alg->hash_zero, ds); 6168c2ecf20Sopenharmony_ci return 0; 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci memcpy(&rctx->u, n2alg->hash_init, n2alg->hw_op_hashsz); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci return n2_do_async_digest(req, n2alg->auth_type, 6218c2ecf20Sopenharmony_ci n2alg->hw_op_hashsz, ds, 6228c2ecf20Sopenharmony_ci &rctx->u, 0UL, 0); 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic int n2_hmac_async_digest(struct ahash_request *req) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci struct n2_hmac_alg *n2alg = n2_hmac_alg(req->base.tfm); 6288c2ecf20Sopenharmony_ci struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); 6298c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 6308c2ecf20Sopenharmony_ci struct n2_hmac_ctx *ctx = crypto_ahash_ctx(tfm); 6318c2ecf20Sopenharmony_ci int ds; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci ds = n2alg->derived.digest_size; 6348c2ecf20Sopenharmony_ci if (unlikely(req->nbytes == 0) || 6358c2ecf20Sopenharmony_ci unlikely(ctx->hash_key_len > N2_HASH_KEY_MAX)) { 6368c2ecf20Sopenharmony_ci struct n2_hash_req_ctx *rctx = ahash_request_ctx(req); 6378c2ecf20Sopenharmony_ci struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); 6408c2ecf20Sopenharmony_ci rctx->fallback_req.base.flags = 6418c2ecf20Sopenharmony_ci req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; 6428c2ecf20Sopenharmony_ci rctx->fallback_req.nbytes = req->nbytes; 6438c2ecf20Sopenharmony_ci rctx->fallback_req.src = req->src; 6448c2ecf20Sopenharmony_ci rctx->fallback_req.result = req->result; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci return crypto_ahash_digest(&rctx->fallback_req); 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci memcpy(&rctx->u, n2alg->derived.hash_init, 6498c2ecf20Sopenharmony_ci n2alg->derived.hw_op_hashsz); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci return n2_do_async_digest(req, n2alg->derived.hmac_type, 6528c2ecf20Sopenharmony_ci n2alg->derived.hw_op_hashsz, ds, 6538c2ecf20Sopenharmony_ci &rctx->u, 6548c2ecf20Sopenharmony_ci __pa(&ctx->hash_key), 6558c2ecf20Sopenharmony_ci ctx->hash_key_len); 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistruct n2_skcipher_context { 6598c2ecf20Sopenharmony_ci int key_len; 6608c2ecf20Sopenharmony_ci int enc_type; 6618c2ecf20Sopenharmony_ci union { 6628c2ecf20Sopenharmony_ci u8 aes[AES_MAX_KEY_SIZE]; 6638c2ecf20Sopenharmony_ci u8 des[DES_KEY_SIZE]; 6648c2ecf20Sopenharmony_ci u8 des3[3 * DES_KEY_SIZE]; 6658c2ecf20Sopenharmony_ci } key; 6668c2ecf20Sopenharmony_ci}; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci#define N2_CHUNK_ARR_LEN 16 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_cistruct n2_crypto_chunk { 6718c2ecf20Sopenharmony_ci struct list_head entry; 6728c2ecf20Sopenharmony_ci unsigned long iv_paddr : 44; 6738c2ecf20Sopenharmony_ci unsigned long arr_len : 20; 6748c2ecf20Sopenharmony_ci unsigned long dest_paddr; 6758c2ecf20Sopenharmony_ci unsigned long dest_final; 6768c2ecf20Sopenharmony_ci struct { 6778c2ecf20Sopenharmony_ci unsigned long src_paddr : 44; 6788c2ecf20Sopenharmony_ci unsigned long src_len : 20; 6798c2ecf20Sopenharmony_ci } arr[N2_CHUNK_ARR_LEN]; 6808c2ecf20Sopenharmony_ci}; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistruct n2_request_context { 6838c2ecf20Sopenharmony_ci struct skcipher_walk walk; 6848c2ecf20Sopenharmony_ci struct list_head chunk_list; 6858c2ecf20Sopenharmony_ci struct n2_crypto_chunk chunk; 6868c2ecf20Sopenharmony_ci u8 temp_iv[16]; 6878c2ecf20Sopenharmony_ci}; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci/* The SPU allows some level of flexibility for partial cipher blocks 6908c2ecf20Sopenharmony_ci * being specified in a descriptor. 6918c2ecf20Sopenharmony_ci * 6928c2ecf20Sopenharmony_ci * It merely requires that every descriptor's length field is at least 6938c2ecf20Sopenharmony_ci * as large as the cipher block size. This means that a cipher block 6948c2ecf20Sopenharmony_ci * can span at most 2 descriptors. However, this does not allow a 6958c2ecf20Sopenharmony_ci * partial block to span into the final descriptor as that would 6968c2ecf20Sopenharmony_ci * violate the rule (since every descriptor's length must be at lest 6978c2ecf20Sopenharmony_ci * the block size). So, for example, assuming an 8 byte block size: 6988c2ecf20Sopenharmony_ci * 6998c2ecf20Sopenharmony_ci * 0xe --> 0xa --> 0x8 7008c2ecf20Sopenharmony_ci * 7018c2ecf20Sopenharmony_ci * is a valid length sequence, whereas: 7028c2ecf20Sopenharmony_ci * 7038c2ecf20Sopenharmony_ci * 0xe --> 0xb --> 0x7 7048c2ecf20Sopenharmony_ci * 7058c2ecf20Sopenharmony_ci * is not a valid sequence. 7068c2ecf20Sopenharmony_ci */ 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistruct n2_skcipher_alg { 7098c2ecf20Sopenharmony_ci struct list_head entry; 7108c2ecf20Sopenharmony_ci u8 enc_type; 7118c2ecf20Sopenharmony_ci struct skcipher_alg skcipher; 7128c2ecf20Sopenharmony_ci}; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cistatic inline struct n2_skcipher_alg *n2_skcipher_alg(struct crypto_skcipher *tfm) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci struct skcipher_alg *alg = crypto_skcipher_alg(tfm); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci return container_of(alg, struct n2_skcipher_alg, skcipher); 7198c2ecf20Sopenharmony_ci} 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_cistruct n2_skcipher_request_context { 7228c2ecf20Sopenharmony_ci struct skcipher_walk walk; 7238c2ecf20Sopenharmony_ci}; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_cistatic int n2_aes_setkey(struct crypto_skcipher *skcipher, const u8 *key, 7268c2ecf20Sopenharmony_ci unsigned int keylen) 7278c2ecf20Sopenharmony_ci{ 7288c2ecf20Sopenharmony_ci struct crypto_tfm *tfm = crypto_skcipher_tfm(skcipher); 7298c2ecf20Sopenharmony_ci struct n2_skcipher_context *ctx = crypto_tfm_ctx(tfm); 7308c2ecf20Sopenharmony_ci struct n2_skcipher_alg *n2alg = n2_skcipher_alg(skcipher); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci ctx->enc_type = (n2alg->enc_type & ENC_TYPE_CHAINING_MASK); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci switch (keylen) { 7358c2ecf20Sopenharmony_ci case AES_KEYSIZE_128: 7368c2ecf20Sopenharmony_ci ctx->enc_type |= ENC_TYPE_ALG_AES128; 7378c2ecf20Sopenharmony_ci break; 7388c2ecf20Sopenharmony_ci case AES_KEYSIZE_192: 7398c2ecf20Sopenharmony_ci ctx->enc_type |= ENC_TYPE_ALG_AES192; 7408c2ecf20Sopenharmony_ci break; 7418c2ecf20Sopenharmony_ci case AES_KEYSIZE_256: 7428c2ecf20Sopenharmony_ci ctx->enc_type |= ENC_TYPE_ALG_AES256; 7438c2ecf20Sopenharmony_ci break; 7448c2ecf20Sopenharmony_ci default: 7458c2ecf20Sopenharmony_ci return -EINVAL; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci ctx->key_len = keylen; 7498c2ecf20Sopenharmony_ci memcpy(ctx->key.aes, key, keylen); 7508c2ecf20Sopenharmony_ci return 0; 7518c2ecf20Sopenharmony_ci} 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_cistatic int n2_des_setkey(struct crypto_skcipher *skcipher, const u8 *key, 7548c2ecf20Sopenharmony_ci unsigned int keylen) 7558c2ecf20Sopenharmony_ci{ 7568c2ecf20Sopenharmony_ci struct crypto_tfm *tfm = crypto_skcipher_tfm(skcipher); 7578c2ecf20Sopenharmony_ci struct n2_skcipher_context *ctx = crypto_tfm_ctx(tfm); 7588c2ecf20Sopenharmony_ci struct n2_skcipher_alg *n2alg = n2_skcipher_alg(skcipher); 7598c2ecf20Sopenharmony_ci int err; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci err = verify_skcipher_des_key(skcipher, key); 7628c2ecf20Sopenharmony_ci if (err) 7638c2ecf20Sopenharmony_ci return err; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci ctx->enc_type = n2alg->enc_type; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci ctx->key_len = keylen; 7688c2ecf20Sopenharmony_ci memcpy(ctx->key.des, key, keylen); 7698c2ecf20Sopenharmony_ci return 0; 7708c2ecf20Sopenharmony_ci} 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_cistatic int n2_3des_setkey(struct crypto_skcipher *skcipher, const u8 *key, 7738c2ecf20Sopenharmony_ci unsigned int keylen) 7748c2ecf20Sopenharmony_ci{ 7758c2ecf20Sopenharmony_ci struct crypto_tfm *tfm = crypto_skcipher_tfm(skcipher); 7768c2ecf20Sopenharmony_ci struct n2_skcipher_context *ctx = crypto_tfm_ctx(tfm); 7778c2ecf20Sopenharmony_ci struct n2_skcipher_alg *n2alg = n2_skcipher_alg(skcipher); 7788c2ecf20Sopenharmony_ci int err; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci err = verify_skcipher_des3_key(skcipher, key); 7818c2ecf20Sopenharmony_ci if (err) 7828c2ecf20Sopenharmony_ci return err; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci ctx->enc_type = n2alg->enc_type; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci ctx->key_len = keylen; 7878c2ecf20Sopenharmony_ci memcpy(ctx->key.des3, key, keylen); 7888c2ecf20Sopenharmony_ci return 0; 7898c2ecf20Sopenharmony_ci} 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_cistatic inline int skcipher_descriptor_len(int nbytes, unsigned int block_size) 7928c2ecf20Sopenharmony_ci{ 7938c2ecf20Sopenharmony_ci int this_len = nbytes; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci this_len -= (nbytes & (block_size - 1)); 7968c2ecf20Sopenharmony_ci return this_len > (1 << 16) ? (1 << 16) : this_len; 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistatic int __n2_crypt_chunk(struct crypto_skcipher *skcipher, 8008c2ecf20Sopenharmony_ci struct n2_crypto_chunk *cp, 8018c2ecf20Sopenharmony_ci struct spu_queue *qp, bool encrypt) 8028c2ecf20Sopenharmony_ci{ 8038c2ecf20Sopenharmony_ci struct n2_skcipher_context *ctx = crypto_skcipher_ctx(skcipher); 8048c2ecf20Sopenharmony_ci struct cwq_initial_entry *ent; 8058c2ecf20Sopenharmony_ci bool in_place; 8068c2ecf20Sopenharmony_ci int i; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci ent = spu_queue_alloc(qp, cp->arr_len); 8098c2ecf20Sopenharmony_ci if (!ent) { 8108c2ecf20Sopenharmony_ci pr_info("queue_alloc() of %d fails\n", 8118c2ecf20Sopenharmony_ci cp->arr_len); 8128c2ecf20Sopenharmony_ci return -EBUSY; 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci in_place = (cp->dest_paddr == cp->arr[0].src_paddr); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci ent->control = control_word_base(cp->arr[0].src_len, 8188c2ecf20Sopenharmony_ci 0, ctx->enc_type, 0, 0, 8198c2ecf20Sopenharmony_ci false, true, false, encrypt, 8208c2ecf20Sopenharmony_ci OPCODE_ENCRYPT | 8218c2ecf20Sopenharmony_ci (in_place ? OPCODE_INPLACE_BIT : 0)); 8228c2ecf20Sopenharmony_ci ent->src_addr = cp->arr[0].src_paddr; 8238c2ecf20Sopenharmony_ci ent->auth_key_addr = 0UL; 8248c2ecf20Sopenharmony_ci ent->auth_iv_addr = 0UL; 8258c2ecf20Sopenharmony_ci ent->final_auth_state_addr = 0UL; 8268c2ecf20Sopenharmony_ci ent->enc_key_addr = __pa(&ctx->key); 8278c2ecf20Sopenharmony_ci ent->enc_iv_addr = cp->iv_paddr; 8288c2ecf20Sopenharmony_ci ent->dest_addr = (in_place ? 0UL : cp->dest_paddr); 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci for (i = 1; i < cp->arr_len; i++) { 8318c2ecf20Sopenharmony_ci ent = spu_queue_next(qp, ent); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci ent->control = cp->arr[i].src_len - 1; 8348c2ecf20Sopenharmony_ci ent->src_addr = cp->arr[i].src_paddr; 8358c2ecf20Sopenharmony_ci ent->auth_key_addr = 0UL; 8368c2ecf20Sopenharmony_ci ent->auth_iv_addr = 0UL; 8378c2ecf20Sopenharmony_ci ent->final_auth_state_addr = 0UL; 8388c2ecf20Sopenharmony_ci ent->enc_key_addr = 0UL; 8398c2ecf20Sopenharmony_ci ent->enc_iv_addr = 0UL; 8408c2ecf20Sopenharmony_ci ent->dest_addr = 0UL; 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci ent->control |= CONTROL_END_OF_BLOCK; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci return (spu_queue_submit(qp, ent) != HV_EOK) ? -EINVAL : 0; 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_cistatic int n2_compute_chunks(struct skcipher_request *req) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci struct n2_request_context *rctx = skcipher_request_ctx(req); 8508c2ecf20Sopenharmony_ci struct skcipher_walk *walk = &rctx->walk; 8518c2ecf20Sopenharmony_ci struct n2_crypto_chunk *chunk; 8528c2ecf20Sopenharmony_ci unsigned long dest_prev; 8538c2ecf20Sopenharmony_ci unsigned int tot_len; 8548c2ecf20Sopenharmony_ci bool prev_in_place; 8558c2ecf20Sopenharmony_ci int err, nbytes; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci err = skcipher_walk_async(walk, req); 8588c2ecf20Sopenharmony_ci if (err) 8598c2ecf20Sopenharmony_ci return err; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&rctx->chunk_list); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci chunk = &rctx->chunk; 8648c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&chunk->entry); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci chunk->iv_paddr = 0UL; 8678c2ecf20Sopenharmony_ci chunk->arr_len = 0; 8688c2ecf20Sopenharmony_ci chunk->dest_paddr = 0UL; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci prev_in_place = false; 8718c2ecf20Sopenharmony_ci dest_prev = ~0UL; 8728c2ecf20Sopenharmony_ci tot_len = 0; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci while ((nbytes = walk->nbytes) != 0) { 8758c2ecf20Sopenharmony_ci unsigned long dest_paddr, src_paddr; 8768c2ecf20Sopenharmony_ci bool in_place; 8778c2ecf20Sopenharmony_ci int this_len; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci src_paddr = (page_to_phys(walk->src.phys.page) + 8808c2ecf20Sopenharmony_ci walk->src.phys.offset); 8818c2ecf20Sopenharmony_ci dest_paddr = (page_to_phys(walk->dst.phys.page) + 8828c2ecf20Sopenharmony_ci walk->dst.phys.offset); 8838c2ecf20Sopenharmony_ci in_place = (src_paddr == dest_paddr); 8848c2ecf20Sopenharmony_ci this_len = skcipher_descriptor_len(nbytes, walk->blocksize); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci if (chunk->arr_len != 0) { 8878c2ecf20Sopenharmony_ci if (in_place != prev_in_place || 8888c2ecf20Sopenharmony_ci (!prev_in_place && 8898c2ecf20Sopenharmony_ci dest_paddr != dest_prev) || 8908c2ecf20Sopenharmony_ci chunk->arr_len == N2_CHUNK_ARR_LEN || 8918c2ecf20Sopenharmony_ci tot_len + this_len > (1 << 16)) { 8928c2ecf20Sopenharmony_ci chunk->dest_final = dest_prev; 8938c2ecf20Sopenharmony_ci list_add_tail(&chunk->entry, 8948c2ecf20Sopenharmony_ci &rctx->chunk_list); 8958c2ecf20Sopenharmony_ci chunk = kzalloc(sizeof(*chunk), GFP_ATOMIC); 8968c2ecf20Sopenharmony_ci if (!chunk) { 8978c2ecf20Sopenharmony_ci err = -ENOMEM; 8988c2ecf20Sopenharmony_ci break; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&chunk->entry); 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci } 9038c2ecf20Sopenharmony_ci if (chunk->arr_len == 0) { 9048c2ecf20Sopenharmony_ci chunk->dest_paddr = dest_paddr; 9058c2ecf20Sopenharmony_ci tot_len = 0; 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci chunk->arr[chunk->arr_len].src_paddr = src_paddr; 9088c2ecf20Sopenharmony_ci chunk->arr[chunk->arr_len].src_len = this_len; 9098c2ecf20Sopenharmony_ci chunk->arr_len++; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci dest_prev = dest_paddr + this_len; 9128c2ecf20Sopenharmony_ci prev_in_place = in_place; 9138c2ecf20Sopenharmony_ci tot_len += this_len; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci err = skcipher_walk_done(walk, nbytes - this_len); 9168c2ecf20Sopenharmony_ci if (err) 9178c2ecf20Sopenharmony_ci break; 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci if (!err && chunk->arr_len != 0) { 9208c2ecf20Sopenharmony_ci chunk->dest_final = dest_prev; 9218c2ecf20Sopenharmony_ci list_add_tail(&chunk->entry, &rctx->chunk_list); 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci return err; 9258c2ecf20Sopenharmony_ci} 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_cistatic void n2_chunk_complete(struct skcipher_request *req, void *final_iv) 9288c2ecf20Sopenharmony_ci{ 9298c2ecf20Sopenharmony_ci struct n2_request_context *rctx = skcipher_request_ctx(req); 9308c2ecf20Sopenharmony_ci struct n2_crypto_chunk *c, *tmp; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci if (final_iv) 9338c2ecf20Sopenharmony_ci memcpy(rctx->walk.iv, final_iv, rctx->walk.blocksize); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci list_for_each_entry_safe(c, tmp, &rctx->chunk_list, entry) { 9368c2ecf20Sopenharmony_ci list_del(&c->entry); 9378c2ecf20Sopenharmony_ci if (unlikely(c != &rctx->chunk)) 9388c2ecf20Sopenharmony_ci kfree(c); 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci} 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_cistatic int n2_do_ecb(struct skcipher_request *req, bool encrypt) 9448c2ecf20Sopenharmony_ci{ 9458c2ecf20Sopenharmony_ci struct n2_request_context *rctx = skcipher_request_ctx(req); 9468c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 9478c2ecf20Sopenharmony_ci int err = n2_compute_chunks(req); 9488c2ecf20Sopenharmony_ci struct n2_crypto_chunk *c, *tmp; 9498c2ecf20Sopenharmony_ci unsigned long flags, hv_ret; 9508c2ecf20Sopenharmony_ci struct spu_queue *qp; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci if (err) 9538c2ecf20Sopenharmony_ci return err; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci qp = cpu_to_cwq[get_cpu()]; 9568c2ecf20Sopenharmony_ci err = -ENODEV; 9578c2ecf20Sopenharmony_ci if (!qp) 9588c2ecf20Sopenharmony_ci goto out; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci spin_lock_irqsave(&qp->lock, flags); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci list_for_each_entry_safe(c, tmp, &rctx->chunk_list, entry) { 9638c2ecf20Sopenharmony_ci err = __n2_crypt_chunk(tfm, c, qp, encrypt); 9648c2ecf20Sopenharmony_ci if (err) 9658c2ecf20Sopenharmony_ci break; 9668c2ecf20Sopenharmony_ci list_del(&c->entry); 9678c2ecf20Sopenharmony_ci if (unlikely(c != &rctx->chunk)) 9688c2ecf20Sopenharmony_ci kfree(c); 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci if (!err) { 9718c2ecf20Sopenharmony_ci hv_ret = wait_for_tail(qp); 9728c2ecf20Sopenharmony_ci if (hv_ret != HV_EOK) 9738c2ecf20Sopenharmony_ci err = -EINVAL; 9748c2ecf20Sopenharmony_ci } 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->lock, flags); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ciout: 9798c2ecf20Sopenharmony_ci put_cpu(); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci n2_chunk_complete(req, NULL); 9828c2ecf20Sopenharmony_ci return err; 9838c2ecf20Sopenharmony_ci} 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_cistatic int n2_encrypt_ecb(struct skcipher_request *req) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci return n2_do_ecb(req, true); 9888c2ecf20Sopenharmony_ci} 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_cistatic int n2_decrypt_ecb(struct skcipher_request *req) 9918c2ecf20Sopenharmony_ci{ 9928c2ecf20Sopenharmony_ci return n2_do_ecb(req, false); 9938c2ecf20Sopenharmony_ci} 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_cistatic int n2_do_chaining(struct skcipher_request *req, bool encrypt) 9968c2ecf20Sopenharmony_ci{ 9978c2ecf20Sopenharmony_ci struct n2_request_context *rctx = skcipher_request_ctx(req); 9988c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 9998c2ecf20Sopenharmony_ci unsigned long flags, hv_ret, iv_paddr; 10008c2ecf20Sopenharmony_ci int err = n2_compute_chunks(req); 10018c2ecf20Sopenharmony_ci struct n2_crypto_chunk *c, *tmp; 10028c2ecf20Sopenharmony_ci struct spu_queue *qp; 10038c2ecf20Sopenharmony_ci void *final_iv_addr; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci final_iv_addr = NULL; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci if (err) 10088c2ecf20Sopenharmony_ci return err; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci qp = cpu_to_cwq[get_cpu()]; 10118c2ecf20Sopenharmony_ci err = -ENODEV; 10128c2ecf20Sopenharmony_ci if (!qp) 10138c2ecf20Sopenharmony_ci goto out; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci spin_lock_irqsave(&qp->lock, flags); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci if (encrypt) { 10188c2ecf20Sopenharmony_ci iv_paddr = __pa(rctx->walk.iv); 10198c2ecf20Sopenharmony_ci list_for_each_entry_safe(c, tmp, &rctx->chunk_list, 10208c2ecf20Sopenharmony_ci entry) { 10218c2ecf20Sopenharmony_ci c->iv_paddr = iv_paddr; 10228c2ecf20Sopenharmony_ci err = __n2_crypt_chunk(tfm, c, qp, true); 10238c2ecf20Sopenharmony_ci if (err) 10248c2ecf20Sopenharmony_ci break; 10258c2ecf20Sopenharmony_ci iv_paddr = c->dest_final - rctx->walk.blocksize; 10268c2ecf20Sopenharmony_ci list_del(&c->entry); 10278c2ecf20Sopenharmony_ci if (unlikely(c != &rctx->chunk)) 10288c2ecf20Sopenharmony_ci kfree(c); 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci final_iv_addr = __va(iv_paddr); 10318c2ecf20Sopenharmony_ci } else { 10328c2ecf20Sopenharmony_ci list_for_each_entry_safe_reverse(c, tmp, &rctx->chunk_list, 10338c2ecf20Sopenharmony_ci entry) { 10348c2ecf20Sopenharmony_ci if (c == &rctx->chunk) { 10358c2ecf20Sopenharmony_ci iv_paddr = __pa(rctx->walk.iv); 10368c2ecf20Sopenharmony_ci } else { 10378c2ecf20Sopenharmony_ci iv_paddr = (tmp->arr[tmp->arr_len-1].src_paddr + 10388c2ecf20Sopenharmony_ci tmp->arr[tmp->arr_len-1].src_len - 10398c2ecf20Sopenharmony_ci rctx->walk.blocksize); 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci if (!final_iv_addr) { 10428c2ecf20Sopenharmony_ci unsigned long pa; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci pa = (c->arr[c->arr_len-1].src_paddr + 10458c2ecf20Sopenharmony_ci c->arr[c->arr_len-1].src_len - 10468c2ecf20Sopenharmony_ci rctx->walk.blocksize); 10478c2ecf20Sopenharmony_ci final_iv_addr = rctx->temp_iv; 10488c2ecf20Sopenharmony_ci memcpy(rctx->temp_iv, __va(pa), 10498c2ecf20Sopenharmony_ci rctx->walk.blocksize); 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci c->iv_paddr = iv_paddr; 10528c2ecf20Sopenharmony_ci err = __n2_crypt_chunk(tfm, c, qp, false); 10538c2ecf20Sopenharmony_ci if (err) 10548c2ecf20Sopenharmony_ci break; 10558c2ecf20Sopenharmony_ci list_del(&c->entry); 10568c2ecf20Sopenharmony_ci if (unlikely(c != &rctx->chunk)) 10578c2ecf20Sopenharmony_ci kfree(c); 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci } 10608c2ecf20Sopenharmony_ci if (!err) { 10618c2ecf20Sopenharmony_ci hv_ret = wait_for_tail(qp); 10628c2ecf20Sopenharmony_ci if (hv_ret != HV_EOK) 10638c2ecf20Sopenharmony_ci err = -EINVAL; 10648c2ecf20Sopenharmony_ci } 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&qp->lock, flags); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ciout: 10698c2ecf20Sopenharmony_ci put_cpu(); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci n2_chunk_complete(req, err ? NULL : final_iv_addr); 10728c2ecf20Sopenharmony_ci return err; 10738c2ecf20Sopenharmony_ci} 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_cistatic int n2_encrypt_chaining(struct skcipher_request *req) 10768c2ecf20Sopenharmony_ci{ 10778c2ecf20Sopenharmony_ci return n2_do_chaining(req, true); 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_cistatic int n2_decrypt_chaining(struct skcipher_request *req) 10818c2ecf20Sopenharmony_ci{ 10828c2ecf20Sopenharmony_ci return n2_do_chaining(req, false); 10838c2ecf20Sopenharmony_ci} 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_cistruct n2_skcipher_tmpl { 10868c2ecf20Sopenharmony_ci const char *name; 10878c2ecf20Sopenharmony_ci const char *drv_name; 10888c2ecf20Sopenharmony_ci u8 block_size; 10898c2ecf20Sopenharmony_ci u8 enc_type; 10908c2ecf20Sopenharmony_ci struct skcipher_alg skcipher; 10918c2ecf20Sopenharmony_ci}; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_cistatic const struct n2_skcipher_tmpl skcipher_tmpls[] = { 10948c2ecf20Sopenharmony_ci /* DES: ECB CBC and CFB are supported */ 10958c2ecf20Sopenharmony_ci { .name = "ecb(des)", 10968c2ecf20Sopenharmony_ci .drv_name = "ecb-des", 10978c2ecf20Sopenharmony_ci .block_size = DES_BLOCK_SIZE, 10988c2ecf20Sopenharmony_ci .enc_type = (ENC_TYPE_ALG_DES | 10998c2ecf20Sopenharmony_ci ENC_TYPE_CHAINING_ECB), 11008c2ecf20Sopenharmony_ci .skcipher = { 11018c2ecf20Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 11028c2ecf20Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 11038c2ecf20Sopenharmony_ci .setkey = n2_des_setkey, 11048c2ecf20Sopenharmony_ci .encrypt = n2_encrypt_ecb, 11058c2ecf20Sopenharmony_ci .decrypt = n2_decrypt_ecb, 11068c2ecf20Sopenharmony_ci }, 11078c2ecf20Sopenharmony_ci }, 11088c2ecf20Sopenharmony_ci { .name = "cbc(des)", 11098c2ecf20Sopenharmony_ci .drv_name = "cbc-des", 11108c2ecf20Sopenharmony_ci .block_size = DES_BLOCK_SIZE, 11118c2ecf20Sopenharmony_ci .enc_type = (ENC_TYPE_ALG_DES | 11128c2ecf20Sopenharmony_ci ENC_TYPE_CHAINING_CBC), 11138c2ecf20Sopenharmony_ci .skcipher = { 11148c2ecf20Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 11158c2ecf20Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 11168c2ecf20Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 11178c2ecf20Sopenharmony_ci .setkey = n2_des_setkey, 11188c2ecf20Sopenharmony_ci .encrypt = n2_encrypt_chaining, 11198c2ecf20Sopenharmony_ci .decrypt = n2_decrypt_chaining, 11208c2ecf20Sopenharmony_ci }, 11218c2ecf20Sopenharmony_ci }, 11228c2ecf20Sopenharmony_ci { .name = "cfb(des)", 11238c2ecf20Sopenharmony_ci .drv_name = "cfb-des", 11248c2ecf20Sopenharmony_ci .block_size = DES_BLOCK_SIZE, 11258c2ecf20Sopenharmony_ci .enc_type = (ENC_TYPE_ALG_DES | 11268c2ecf20Sopenharmony_ci ENC_TYPE_CHAINING_CFB), 11278c2ecf20Sopenharmony_ci .skcipher = { 11288c2ecf20Sopenharmony_ci .min_keysize = DES_KEY_SIZE, 11298c2ecf20Sopenharmony_ci .max_keysize = DES_KEY_SIZE, 11308c2ecf20Sopenharmony_ci .setkey = n2_des_setkey, 11318c2ecf20Sopenharmony_ci .encrypt = n2_encrypt_chaining, 11328c2ecf20Sopenharmony_ci .decrypt = n2_decrypt_chaining, 11338c2ecf20Sopenharmony_ci }, 11348c2ecf20Sopenharmony_ci }, 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci /* 3DES: ECB CBC and CFB are supported */ 11378c2ecf20Sopenharmony_ci { .name = "ecb(des3_ede)", 11388c2ecf20Sopenharmony_ci .drv_name = "ecb-3des", 11398c2ecf20Sopenharmony_ci .block_size = DES_BLOCK_SIZE, 11408c2ecf20Sopenharmony_ci .enc_type = (ENC_TYPE_ALG_3DES | 11418c2ecf20Sopenharmony_ci ENC_TYPE_CHAINING_ECB), 11428c2ecf20Sopenharmony_ci .skcipher = { 11438c2ecf20Sopenharmony_ci .min_keysize = 3 * DES_KEY_SIZE, 11448c2ecf20Sopenharmony_ci .max_keysize = 3 * DES_KEY_SIZE, 11458c2ecf20Sopenharmony_ci .setkey = n2_3des_setkey, 11468c2ecf20Sopenharmony_ci .encrypt = n2_encrypt_ecb, 11478c2ecf20Sopenharmony_ci .decrypt = n2_decrypt_ecb, 11488c2ecf20Sopenharmony_ci }, 11498c2ecf20Sopenharmony_ci }, 11508c2ecf20Sopenharmony_ci { .name = "cbc(des3_ede)", 11518c2ecf20Sopenharmony_ci .drv_name = "cbc-3des", 11528c2ecf20Sopenharmony_ci .block_size = DES_BLOCK_SIZE, 11538c2ecf20Sopenharmony_ci .enc_type = (ENC_TYPE_ALG_3DES | 11548c2ecf20Sopenharmony_ci ENC_TYPE_CHAINING_CBC), 11558c2ecf20Sopenharmony_ci .skcipher = { 11568c2ecf20Sopenharmony_ci .ivsize = DES_BLOCK_SIZE, 11578c2ecf20Sopenharmony_ci .min_keysize = 3 * DES_KEY_SIZE, 11588c2ecf20Sopenharmony_ci .max_keysize = 3 * DES_KEY_SIZE, 11598c2ecf20Sopenharmony_ci .setkey = n2_3des_setkey, 11608c2ecf20Sopenharmony_ci .encrypt = n2_encrypt_chaining, 11618c2ecf20Sopenharmony_ci .decrypt = n2_decrypt_chaining, 11628c2ecf20Sopenharmony_ci }, 11638c2ecf20Sopenharmony_ci }, 11648c2ecf20Sopenharmony_ci { .name = "cfb(des3_ede)", 11658c2ecf20Sopenharmony_ci .drv_name = "cfb-3des", 11668c2ecf20Sopenharmony_ci .block_size = DES_BLOCK_SIZE, 11678c2ecf20Sopenharmony_ci .enc_type = (ENC_TYPE_ALG_3DES | 11688c2ecf20Sopenharmony_ci ENC_TYPE_CHAINING_CFB), 11698c2ecf20Sopenharmony_ci .skcipher = { 11708c2ecf20Sopenharmony_ci .min_keysize = 3 * DES_KEY_SIZE, 11718c2ecf20Sopenharmony_ci .max_keysize = 3 * DES_KEY_SIZE, 11728c2ecf20Sopenharmony_ci .setkey = n2_3des_setkey, 11738c2ecf20Sopenharmony_ci .encrypt = n2_encrypt_chaining, 11748c2ecf20Sopenharmony_ci .decrypt = n2_decrypt_chaining, 11758c2ecf20Sopenharmony_ci }, 11768c2ecf20Sopenharmony_ci }, 11778c2ecf20Sopenharmony_ci /* AES: ECB CBC and CTR are supported */ 11788c2ecf20Sopenharmony_ci { .name = "ecb(aes)", 11798c2ecf20Sopenharmony_ci .drv_name = "ecb-aes", 11808c2ecf20Sopenharmony_ci .block_size = AES_BLOCK_SIZE, 11818c2ecf20Sopenharmony_ci .enc_type = (ENC_TYPE_ALG_AES128 | 11828c2ecf20Sopenharmony_ci ENC_TYPE_CHAINING_ECB), 11838c2ecf20Sopenharmony_ci .skcipher = { 11848c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 11858c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 11868c2ecf20Sopenharmony_ci .setkey = n2_aes_setkey, 11878c2ecf20Sopenharmony_ci .encrypt = n2_encrypt_ecb, 11888c2ecf20Sopenharmony_ci .decrypt = n2_decrypt_ecb, 11898c2ecf20Sopenharmony_ci }, 11908c2ecf20Sopenharmony_ci }, 11918c2ecf20Sopenharmony_ci { .name = "cbc(aes)", 11928c2ecf20Sopenharmony_ci .drv_name = "cbc-aes", 11938c2ecf20Sopenharmony_ci .block_size = AES_BLOCK_SIZE, 11948c2ecf20Sopenharmony_ci .enc_type = (ENC_TYPE_ALG_AES128 | 11958c2ecf20Sopenharmony_ci ENC_TYPE_CHAINING_CBC), 11968c2ecf20Sopenharmony_ci .skcipher = { 11978c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 11988c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 11998c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 12008c2ecf20Sopenharmony_ci .setkey = n2_aes_setkey, 12018c2ecf20Sopenharmony_ci .encrypt = n2_encrypt_chaining, 12028c2ecf20Sopenharmony_ci .decrypt = n2_decrypt_chaining, 12038c2ecf20Sopenharmony_ci }, 12048c2ecf20Sopenharmony_ci }, 12058c2ecf20Sopenharmony_ci { .name = "ctr(aes)", 12068c2ecf20Sopenharmony_ci .drv_name = "ctr-aes", 12078c2ecf20Sopenharmony_ci .block_size = AES_BLOCK_SIZE, 12088c2ecf20Sopenharmony_ci .enc_type = (ENC_TYPE_ALG_AES128 | 12098c2ecf20Sopenharmony_ci ENC_TYPE_CHAINING_COUNTER), 12108c2ecf20Sopenharmony_ci .skcipher = { 12118c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 12128c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 12138c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 12148c2ecf20Sopenharmony_ci .setkey = n2_aes_setkey, 12158c2ecf20Sopenharmony_ci .encrypt = n2_encrypt_chaining, 12168c2ecf20Sopenharmony_ci .decrypt = n2_encrypt_chaining, 12178c2ecf20Sopenharmony_ci }, 12188c2ecf20Sopenharmony_ci }, 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci}; 12218c2ecf20Sopenharmony_ci#define NUM_CIPHER_TMPLS ARRAY_SIZE(skcipher_tmpls) 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_cistatic LIST_HEAD(skcipher_algs); 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_cistruct n2_hash_tmpl { 12268c2ecf20Sopenharmony_ci const char *name; 12278c2ecf20Sopenharmony_ci const u8 *hash_zero; 12288c2ecf20Sopenharmony_ci const u8 *hash_init; 12298c2ecf20Sopenharmony_ci u8 hw_op_hashsz; 12308c2ecf20Sopenharmony_ci u8 digest_size; 12318c2ecf20Sopenharmony_ci u8 statesize; 12328c2ecf20Sopenharmony_ci u8 block_size; 12338c2ecf20Sopenharmony_ci u8 auth_type; 12348c2ecf20Sopenharmony_ci u8 hmac_type; 12358c2ecf20Sopenharmony_ci}; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_cistatic const __le32 n2_md5_init[MD5_HASH_WORDS] = { 12388c2ecf20Sopenharmony_ci cpu_to_le32(MD5_H0), 12398c2ecf20Sopenharmony_ci cpu_to_le32(MD5_H1), 12408c2ecf20Sopenharmony_ci cpu_to_le32(MD5_H2), 12418c2ecf20Sopenharmony_ci cpu_to_le32(MD5_H3), 12428c2ecf20Sopenharmony_ci}; 12438c2ecf20Sopenharmony_cistatic const u32 n2_sha1_init[SHA1_DIGEST_SIZE / 4] = { 12448c2ecf20Sopenharmony_ci SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4, 12458c2ecf20Sopenharmony_ci}; 12468c2ecf20Sopenharmony_cistatic const u32 n2_sha256_init[SHA256_DIGEST_SIZE / 4] = { 12478c2ecf20Sopenharmony_ci SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3, 12488c2ecf20Sopenharmony_ci SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7, 12498c2ecf20Sopenharmony_ci}; 12508c2ecf20Sopenharmony_cistatic const u32 n2_sha224_init[SHA256_DIGEST_SIZE / 4] = { 12518c2ecf20Sopenharmony_ci SHA224_H0, SHA224_H1, SHA224_H2, SHA224_H3, 12528c2ecf20Sopenharmony_ci SHA224_H4, SHA224_H5, SHA224_H6, SHA224_H7, 12538c2ecf20Sopenharmony_ci}; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_cistatic const struct n2_hash_tmpl hash_tmpls[] = { 12568c2ecf20Sopenharmony_ci { .name = "md5", 12578c2ecf20Sopenharmony_ci .hash_zero = md5_zero_message_hash, 12588c2ecf20Sopenharmony_ci .hash_init = (u8 *)n2_md5_init, 12598c2ecf20Sopenharmony_ci .auth_type = AUTH_TYPE_MD5, 12608c2ecf20Sopenharmony_ci .hmac_type = AUTH_TYPE_HMAC_MD5, 12618c2ecf20Sopenharmony_ci .hw_op_hashsz = MD5_DIGEST_SIZE, 12628c2ecf20Sopenharmony_ci .digest_size = MD5_DIGEST_SIZE, 12638c2ecf20Sopenharmony_ci .statesize = sizeof(struct md5_state), 12648c2ecf20Sopenharmony_ci .block_size = MD5_HMAC_BLOCK_SIZE }, 12658c2ecf20Sopenharmony_ci { .name = "sha1", 12668c2ecf20Sopenharmony_ci .hash_zero = sha1_zero_message_hash, 12678c2ecf20Sopenharmony_ci .hash_init = (u8 *)n2_sha1_init, 12688c2ecf20Sopenharmony_ci .auth_type = AUTH_TYPE_SHA1, 12698c2ecf20Sopenharmony_ci .hmac_type = AUTH_TYPE_HMAC_SHA1, 12708c2ecf20Sopenharmony_ci .hw_op_hashsz = SHA1_DIGEST_SIZE, 12718c2ecf20Sopenharmony_ci .digest_size = SHA1_DIGEST_SIZE, 12728c2ecf20Sopenharmony_ci .statesize = sizeof(struct sha1_state), 12738c2ecf20Sopenharmony_ci .block_size = SHA1_BLOCK_SIZE }, 12748c2ecf20Sopenharmony_ci { .name = "sha256", 12758c2ecf20Sopenharmony_ci .hash_zero = sha256_zero_message_hash, 12768c2ecf20Sopenharmony_ci .hash_init = (u8 *)n2_sha256_init, 12778c2ecf20Sopenharmony_ci .auth_type = AUTH_TYPE_SHA256, 12788c2ecf20Sopenharmony_ci .hmac_type = AUTH_TYPE_HMAC_SHA256, 12798c2ecf20Sopenharmony_ci .hw_op_hashsz = SHA256_DIGEST_SIZE, 12808c2ecf20Sopenharmony_ci .digest_size = SHA256_DIGEST_SIZE, 12818c2ecf20Sopenharmony_ci .statesize = sizeof(struct sha256_state), 12828c2ecf20Sopenharmony_ci .block_size = SHA256_BLOCK_SIZE }, 12838c2ecf20Sopenharmony_ci { .name = "sha224", 12848c2ecf20Sopenharmony_ci .hash_zero = sha224_zero_message_hash, 12858c2ecf20Sopenharmony_ci .hash_init = (u8 *)n2_sha224_init, 12868c2ecf20Sopenharmony_ci .auth_type = AUTH_TYPE_SHA256, 12878c2ecf20Sopenharmony_ci .hmac_type = AUTH_TYPE_RESERVED, 12888c2ecf20Sopenharmony_ci .hw_op_hashsz = SHA256_DIGEST_SIZE, 12898c2ecf20Sopenharmony_ci .digest_size = SHA224_DIGEST_SIZE, 12908c2ecf20Sopenharmony_ci .statesize = sizeof(struct sha256_state), 12918c2ecf20Sopenharmony_ci .block_size = SHA224_BLOCK_SIZE }, 12928c2ecf20Sopenharmony_ci}; 12938c2ecf20Sopenharmony_ci#define NUM_HASH_TMPLS ARRAY_SIZE(hash_tmpls) 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_cistatic LIST_HEAD(ahash_algs); 12968c2ecf20Sopenharmony_cistatic LIST_HEAD(hmac_algs); 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_cistatic int algs_registered; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_cistatic void __n2_unregister_algs(void) 13018c2ecf20Sopenharmony_ci{ 13028c2ecf20Sopenharmony_ci struct n2_skcipher_alg *skcipher, *skcipher_tmp; 13038c2ecf20Sopenharmony_ci struct n2_ahash_alg *alg, *alg_tmp; 13048c2ecf20Sopenharmony_ci struct n2_hmac_alg *hmac, *hmac_tmp; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci list_for_each_entry_safe(skcipher, skcipher_tmp, &skcipher_algs, entry) { 13078c2ecf20Sopenharmony_ci crypto_unregister_skcipher(&skcipher->skcipher); 13088c2ecf20Sopenharmony_ci list_del(&skcipher->entry); 13098c2ecf20Sopenharmony_ci kfree(skcipher); 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci list_for_each_entry_safe(hmac, hmac_tmp, &hmac_algs, derived.entry) { 13128c2ecf20Sopenharmony_ci crypto_unregister_ahash(&hmac->derived.alg); 13138c2ecf20Sopenharmony_ci list_del(&hmac->derived.entry); 13148c2ecf20Sopenharmony_ci kfree(hmac); 13158c2ecf20Sopenharmony_ci } 13168c2ecf20Sopenharmony_ci list_for_each_entry_safe(alg, alg_tmp, &ahash_algs, entry) { 13178c2ecf20Sopenharmony_ci crypto_unregister_ahash(&alg->alg); 13188c2ecf20Sopenharmony_ci list_del(&alg->entry); 13198c2ecf20Sopenharmony_ci kfree(alg); 13208c2ecf20Sopenharmony_ci } 13218c2ecf20Sopenharmony_ci} 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_cistatic int n2_skcipher_init_tfm(struct crypto_skcipher *tfm) 13248c2ecf20Sopenharmony_ci{ 13258c2ecf20Sopenharmony_ci crypto_skcipher_set_reqsize(tfm, sizeof(struct n2_request_context)); 13268c2ecf20Sopenharmony_ci return 0; 13278c2ecf20Sopenharmony_ci} 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_cistatic int __n2_register_one_skcipher(const struct n2_skcipher_tmpl *tmpl) 13308c2ecf20Sopenharmony_ci{ 13318c2ecf20Sopenharmony_ci struct n2_skcipher_alg *p = kzalloc(sizeof(*p), GFP_KERNEL); 13328c2ecf20Sopenharmony_ci struct skcipher_alg *alg; 13338c2ecf20Sopenharmony_ci int err; 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci if (!p) 13368c2ecf20Sopenharmony_ci return -ENOMEM; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci alg = &p->skcipher; 13398c2ecf20Sopenharmony_ci *alg = tmpl->skcipher; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", tmpl->name); 13428c2ecf20Sopenharmony_ci snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s-n2", tmpl->drv_name); 13438c2ecf20Sopenharmony_ci alg->base.cra_priority = N2_CRA_PRIORITY; 13448c2ecf20Sopenharmony_ci alg->base.cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC | 13458c2ecf20Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY; 13468c2ecf20Sopenharmony_ci alg->base.cra_blocksize = tmpl->block_size; 13478c2ecf20Sopenharmony_ci p->enc_type = tmpl->enc_type; 13488c2ecf20Sopenharmony_ci alg->base.cra_ctxsize = sizeof(struct n2_skcipher_context); 13498c2ecf20Sopenharmony_ci alg->base.cra_module = THIS_MODULE; 13508c2ecf20Sopenharmony_ci alg->init = n2_skcipher_init_tfm; 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci list_add(&p->entry, &skcipher_algs); 13538c2ecf20Sopenharmony_ci err = crypto_register_skcipher(alg); 13548c2ecf20Sopenharmony_ci if (err) { 13558c2ecf20Sopenharmony_ci pr_err("%s alg registration failed\n", alg->base.cra_name); 13568c2ecf20Sopenharmony_ci list_del(&p->entry); 13578c2ecf20Sopenharmony_ci kfree(p); 13588c2ecf20Sopenharmony_ci } else { 13598c2ecf20Sopenharmony_ci pr_info("%s alg registered\n", alg->base.cra_name); 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci return err; 13628c2ecf20Sopenharmony_ci} 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_cistatic int __n2_register_one_hmac(struct n2_ahash_alg *n2ahash) 13658c2ecf20Sopenharmony_ci{ 13668c2ecf20Sopenharmony_ci struct n2_hmac_alg *p = kzalloc(sizeof(*p), GFP_KERNEL); 13678c2ecf20Sopenharmony_ci struct ahash_alg *ahash; 13688c2ecf20Sopenharmony_ci struct crypto_alg *base; 13698c2ecf20Sopenharmony_ci int err; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci if (!p) 13728c2ecf20Sopenharmony_ci return -ENOMEM; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci p->child_alg = n2ahash->alg.halg.base.cra_name; 13758c2ecf20Sopenharmony_ci memcpy(&p->derived, n2ahash, sizeof(struct n2_ahash_alg)); 13768c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&p->derived.entry); 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci ahash = &p->derived.alg; 13798c2ecf20Sopenharmony_ci ahash->digest = n2_hmac_async_digest; 13808c2ecf20Sopenharmony_ci ahash->setkey = n2_hmac_async_setkey; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci base = &ahash->halg.base; 13838c2ecf20Sopenharmony_ci snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)", p->child_alg); 13848c2ecf20Sopenharmony_ci snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "hmac-%s-n2", p->child_alg); 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci base->cra_ctxsize = sizeof(struct n2_hmac_ctx); 13878c2ecf20Sopenharmony_ci base->cra_init = n2_hmac_cra_init; 13888c2ecf20Sopenharmony_ci base->cra_exit = n2_hmac_cra_exit; 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci list_add(&p->derived.entry, &hmac_algs); 13918c2ecf20Sopenharmony_ci err = crypto_register_ahash(ahash); 13928c2ecf20Sopenharmony_ci if (err) { 13938c2ecf20Sopenharmony_ci pr_err("%s alg registration failed\n", base->cra_name); 13948c2ecf20Sopenharmony_ci list_del(&p->derived.entry); 13958c2ecf20Sopenharmony_ci kfree(p); 13968c2ecf20Sopenharmony_ci } else { 13978c2ecf20Sopenharmony_ci pr_info("%s alg registered\n", base->cra_name); 13988c2ecf20Sopenharmony_ci } 13998c2ecf20Sopenharmony_ci return err; 14008c2ecf20Sopenharmony_ci} 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_cistatic int __n2_register_one_ahash(const struct n2_hash_tmpl *tmpl) 14038c2ecf20Sopenharmony_ci{ 14048c2ecf20Sopenharmony_ci struct n2_ahash_alg *p = kzalloc(sizeof(*p), GFP_KERNEL); 14058c2ecf20Sopenharmony_ci struct hash_alg_common *halg; 14068c2ecf20Sopenharmony_ci struct crypto_alg *base; 14078c2ecf20Sopenharmony_ci struct ahash_alg *ahash; 14088c2ecf20Sopenharmony_ci int err; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci if (!p) 14118c2ecf20Sopenharmony_ci return -ENOMEM; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci p->hash_zero = tmpl->hash_zero; 14148c2ecf20Sopenharmony_ci p->hash_init = tmpl->hash_init; 14158c2ecf20Sopenharmony_ci p->auth_type = tmpl->auth_type; 14168c2ecf20Sopenharmony_ci p->hmac_type = tmpl->hmac_type; 14178c2ecf20Sopenharmony_ci p->hw_op_hashsz = tmpl->hw_op_hashsz; 14188c2ecf20Sopenharmony_ci p->digest_size = tmpl->digest_size; 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci ahash = &p->alg; 14218c2ecf20Sopenharmony_ci ahash->init = n2_hash_async_init; 14228c2ecf20Sopenharmony_ci ahash->update = n2_hash_async_update; 14238c2ecf20Sopenharmony_ci ahash->final = n2_hash_async_final; 14248c2ecf20Sopenharmony_ci ahash->finup = n2_hash_async_finup; 14258c2ecf20Sopenharmony_ci ahash->digest = n2_hash_async_digest; 14268c2ecf20Sopenharmony_ci ahash->export = n2_hash_async_noexport; 14278c2ecf20Sopenharmony_ci ahash->import = n2_hash_async_noimport; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci halg = &ahash->halg; 14308c2ecf20Sopenharmony_ci halg->digestsize = tmpl->digest_size; 14318c2ecf20Sopenharmony_ci halg->statesize = tmpl->statesize; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci base = &halg->base; 14348c2ecf20Sopenharmony_ci snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "%s", tmpl->name); 14358c2ecf20Sopenharmony_ci snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s-n2", tmpl->name); 14368c2ecf20Sopenharmony_ci base->cra_priority = N2_CRA_PRIORITY; 14378c2ecf20Sopenharmony_ci base->cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 14388c2ecf20Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK; 14398c2ecf20Sopenharmony_ci base->cra_blocksize = tmpl->block_size; 14408c2ecf20Sopenharmony_ci base->cra_ctxsize = sizeof(struct n2_hash_ctx); 14418c2ecf20Sopenharmony_ci base->cra_module = THIS_MODULE; 14428c2ecf20Sopenharmony_ci base->cra_init = n2_hash_cra_init; 14438c2ecf20Sopenharmony_ci base->cra_exit = n2_hash_cra_exit; 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci list_add(&p->entry, &ahash_algs); 14468c2ecf20Sopenharmony_ci err = crypto_register_ahash(ahash); 14478c2ecf20Sopenharmony_ci if (err) { 14488c2ecf20Sopenharmony_ci pr_err("%s alg registration failed\n", base->cra_name); 14498c2ecf20Sopenharmony_ci list_del(&p->entry); 14508c2ecf20Sopenharmony_ci kfree(p); 14518c2ecf20Sopenharmony_ci } else { 14528c2ecf20Sopenharmony_ci pr_info("%s alg registered\n", base->cra_name); 14538c2ecf20Sopenharmony_ci } 14548c2ecf20Sopenharmony_ci if (!err && p->hmac_type != AUTH_TYPE_RESERVED) 14558c2ecf20Sopenharmony_ci err = __n2_register_one_hmac(p); 14568c2ecf20Sopenharmony_ci return err; 14578c2ecf20Sopenharmony_ci} 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_cistatic int n2_register_algs(void) 14608c2ecf20Sopenharmony_ci{ 14618c2ecf20Sopenharmony_ci int i, err = 0; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci mutex_lock(&spu_lock); 14648c2ecf20Sopenharmony_ci if (algs_registered++) 14658c2ecf20Sopenharmony_ci goto out; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci for (i = 0; i < NUM_HASH_TMPLS; i++) { 14688c2ecf20Sopenharmony_ci err = __n2_register_one_ahash(&hash_tmpls[i]); 14698c2ecf20Sopenharmony_ci if (err) { 14708c2ecf20Sopenharmony_ci __n2_unregister_algs(); 14718c2ecf20Sopenharmony_ci goto out; 14728c2ecf20Sopenharmony_ci } 14738c2ecf20Sopenharmony_ci } 14748c2ecf20Sopenharmony_ci for (i = 0; i < NUM_CIPHER_TMPLS; i++) { 14758c2ecf20Sopenharmony_ci err = __n2_register_one_skcipher(&skcipher_tmpls[i]); 14768c2ecf20Sopenharmony_ci if (err) { 14778c2ecf20Sopenharmony_ci __n2_unregister_algs(); 14788c2ecf20Sopenharmony_ci goto out; 14798c2ecf20Sopenharmony_ci } 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ciout: 14838c2ecf20Sopenharmony_ci mutex_unlock(&spu_lock); 14848c2ecf20Sopenharmony_ci return err; 14858c2ecf20Sopenharmony_ci} 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_cistatic void n2_unregister_algs(void) 14888c2ecf20Sopenharmony_ci{ 14898c2ecf20Sopenharmony_ci mutex_lock(&spu_lock); 14908c2ecf20Sopenharmony_ci if (!--algs_registered) 14918c2ecf20Sopenharmony_ci __n2_unregister_algs(); 14928c2ecf20Sopenharmony_ci mutex_unlock(&spu_lock); 14938c2ecf20Sopenharmony_ci} 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci/* To map CWQ queues to interrupt sources, the hypervisor API provides 14968c2ecf20Sopenharmony_ci * a devino. This isn't very useful to us because all of the 14978c2ecf20Sopenharmony_ci * interrupts listed in the device_node have been translated to 14988c2ecf20Sopenharmony_ci * Linux virtual IRQ cookie numbers. 14998c2ecf20Sopenharmony_ci * 15008c2ecf20Sopenharmony_ci * So we have to back-translate, going through the 'intr' and 'ino' 15018c2ecf20Sopenharmony_ci * property tables of the n2cp MDESC node, matching it with the OF 15028c2ecf20Sopenharmony_ci * 'interrupts' property entries, in order to to figure out which 15038c2ecf20Sopenharmony_ci * devino goes to which already-translated IRQ. 15048c2ecf20Sopenharmony_ci */ 15058c2ecf20Sopenharmony_cistatic int find_devino_index(struct platform_device *dev, struct spu_mdesc_info *ip, 15068c2ecf20Sopenharmony_ci unsigned long dev_ino) 15078c2ecf20Sopenharmony_ci{ 15088c2ecf20Sopenharmony_ci const unsigned int *dev_intrs; 15098c2ecf20Sopenharmony_ci unsigned int intr; 15108c2ecf20Sopenharmony_ci int i; 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci for (i = 0; i < ip->num_intrs; i++) { 15138c2ecf20Sopenharmony_ci if (ip->ino_table[i].ino == dev_ino) 15148c2ecf20Sopenharmony_ci break; 15158c2ecf20Sopenharmony_ci } 15168c2ecf20Sopenharmony_ci if (i == ip->num_intrs) 15178c2ecf20Sopenharmony_ci return -ENODEV; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci intr = ip->ino_table[i].intr; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci dev_intrs = of_get_property(dev->dev.of_node, "interrupts", NULL); 15228c2ecf20Sopenharmony_ci if (!dev_intrs) 15238c2ecf20Sopenharmony_ci return -ENODEV; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci for (i = 0; i < dev->archdata.num_irqs; i++) { 15268c2ecf20Sopenharmony_ci if (dev_intrs[i] == intr) 15278c2ecf20Sopenharmony_ci return i; 15288c2ecf20Sopenharmony_ci } 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci return -ENODEV; 15318c2ecf20Sopenharmony_ci} 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_cistatic int spu_map_ino(struct platform_device *dev, struct spu_mdesc_info *ip, 15348c2ecf20Sopenharmony_ci const char *irq_name, struct spu_queue *p, 15358c2ecf20Sopenharmony_ci irq_handler_t handler) 15368c2ecf20Sopenharmony_ci{ 15378c2ecf20Sopenharmony_ci unsigned long herr; 15388c2ecf20Sopenharmony_ci int index; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci herr = sun4v_ncs_qhandle_to_devino(p->qhandle, &p->devino); 15418c2ecf20Sopenharmony_ci if (herr) 15428c2ecf20Sopenharmony_ci return -EINVAL; 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci index = find_devino_index(dev, ip, p->devino); 15458c2ecf20Sopenharmony_ci if (index < 0) 15468c2ecf20Sopenharmony_ci return index; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci p->irq = dev->archdata.irqs[index]; 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci sprintf(p->irq_name, "%s-%d", irq_name, index); 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci return request_irq(p->irq, handler, 0, p->irq_name, p); 15538c2ecf20Sopenharmony_ci} 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_cistatic struct kmem_cache *queue_cache[2]; 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_cistatic void *new_queue(unsigned long q_type) 15588c2ecf20Sopenharmony_ci{ 15598c2ecf20Sopenharmony_ci return kmem_cache_zalloc(queue_cache[q_type - 1], GFP_KERNEL); 15608c2ecf20Sopenharmony_ci} 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_cistatic void free_queue(void *p, unsigned long q_type) 15638c2ecf20Sopenharmony_ci{ 15648c2ecf20Sopenharmony_ci kmem_cache_free(queue_cache[q_type - 1], p); 15658c2ecf20Sopenharmony_ci} 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_cistatic int queue_cache_init(void) 15688c2ecf20Sopenharmony_ci{ 15698c2ecf20Sopenharmony_ci if (!queue_cache[HV_NCS_QTYPE_MAU - 1]) 15708c2ecf20Sopenharmony_ci queue_cache[HV_NCS_QTYPE_MAU - 1] = 15718c2ecf20Sopenharmony_ci kmem_cache_create("mau_queue", 15728c2ecf20Sopenharmony_ci (MAU_NUM_ENTRIES * 15738c2ecf20Sopenharmony_ci MAU_ENTRY_SIZE), 15748c2ecf20Sopenharmony_ci MAU_ENTRY_SIZE, 0, NULL); 15758c2ecf20Sopenharmony_ci if (!queue_cache[HV_NCS_QTYPE_MAU - 1]) 15768c2ecf20Sopenharmony_ci return -ENOMEM; 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci if (!queue_cache[HV_NCS_QTYPE_CWQ - 1]) 15798c2ecf20Sopenharmony_ci queue_cache[HV_NCS_QTYPE_CWQ - 1] = 15808c2ecf20Sopenharmony_ci kmem_cache_create("cwq_queue", 15818c2ecf20Sopenharmony_ci (CWQ_NUM_ENTRIES * 15828c2ecf20Sopenharmony_ci CWQ_ENTRY_SIZE), 15838c2ecf20Sopenharmony_ci CWQ_ENTRY_SIZE, 0, NULL); 15848c2ecf20Sopenharmony_ci if (!queue_cache[HV_NCS_QTYPE_CWQ - 1]) { 15858c2ecf20Sopenharmony_ci kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_MAU - 1]); 15868c2ecf20Sopenharmony_ci queue_cache[HV_NCS_QTYPE_MAU - 1] = NULL; 15878c2ecf20Sopenharmony_ci return -ENOMEM; 15888c2ecf20Sopenharmony_ci } 15898c2ecf20Sopenharmony_ci return 0; 15908c2ecf20Sopenharmony_ci} 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_cistatic void queue_cache_destroy(void) 15938c2ecf20Sopenharmony_ci{ 15948c2ecf20Sopenharmony_ci kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_MAU - 1]); 15958c2ecf20Sopenharmony_ci kmem_cache_destroy(queue_cache[HV_NCS_QTYPE_CWQ - 1]); 15968c2ecf20Sopenharmony_ci queue_cache[HV_NCS_QTYPE_MAU - 1] = NULL; 15978c2ecf20Sopenharmony_ci queue_cache[HV_NCS_QTYPE_CWQ - 1] = NULL; 15988c2ecf20Sopenharmony_ci} 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_cistatic long spu_queue_register_workfn(void *arg) 16018c2ecf20Sopenharmony_ci{ 16028c2ecf20Sopenharmony_ci struct spu_qreg *qr = arg; 16038c2ecf20Sopenharmony_ci struct spu_queue *p = qr->queue; 16048c2ecf20Sopenharmony_ci unsigned long q_type = qr->type; 16058c2ecf20Sopenharmony_ci unsigned long hv_ret; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci hv_ret = sun4v_ncs_qconf(q_type, __pa(p->q), 16088c2ecf20Sopenharmony_ci CWQ_NUM_ENTRIES, &p->qhandle); 16098c2ecf20Sopenharmony_ci if (!hv_ret) 16108c2ecf20Sopenharmony_ci sun4v_ncs_sethead_marker(p->qhandle, 0); 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci return hv_ret ? -EINVAL : 0; 16138c2ecf20Sopenharmony_ci} 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_cistatic int spu_queue_register(struct spu_queue *p, unsigned long q_type) 16168c2ecf20Sopenharmony_ci{ 16178c2ecf20Sopenharmony_ci int cpu = cpumask_any_and(&p->sharing, cpu_online_mask); 16188c2ecf20Sopenharmony_ci struct spu_qreg qr = { .queue = p, .type = q_type }; 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci return work_on_cpu_safe(cpu, spu_queue_register_workfn, &qr); 16218c2ecf20Sopenharmony_ci} 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_cistatic int spu_queue_setup(struct spu_queue *p) 16248c2ecf20Sopenharmony_ci{ 16258c2ecf20Sopenharmony_ci int err; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci p->q = new_queue(p->q_type); 16288c2ecf20Sopenharmony_ci if (!p->q) 16298c2ecf20Sopenharmony_ci return -ENOMEM; 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci err = spu_queue_register(p, p->q_type); 16328c2ecf20Sopenharmony_ci if (err) { 16338c2ecf20Sopenharmony_ci free_queue(p->q, p->q_type); 16348c2ecf20Sopenharmony_ci p->q = NULL; 16358c2ecf20Sopenharmony_ci } 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci return err; 16388c2ecf20Sopenharmony_ci} 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_cistatic void spu_queue_destroy(struct spu_queue *p) 16418c2ecf20Sopenharmony_ci{ 16428c2ecf20Sopenharmony_ci unsigned long hv_ret; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci if (!p->q) 16458c2ecf20Sopenharmony_ci return; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci hv_ret = sun4v_ncs_qconf(p->q_type, p->qhandle, 0, &p->qhandle); 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci if (!hv_ret) 16508c2ecf20Sopenharmony_ci free_queue(p->q, p->q_type); 16518c2ecf20Sopenharmony_ci} 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_cistatic void spu_list_destroy(struct list_head *list) 16548c2ecf20Sopenharmony_ci{ 16558c2ecf20Sopenharmony_ci struct spu_queue *p, *n; 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci list_for_each_entry_safe(p, n, list, list) { 16588c2ecf20Sopenharmony_ci int i; 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci for (i = 0; i < NR_CPUS; i++) { 16618c2ecf20Sopenharmony_ci if (cpu_to_cwq[i] == p) 16628c2ecf20Sopenharmony_ci cpu_to_cwq[i] = NULL; 16638c2ecf20Sopenharmony_ci } 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci if (p->irq) { 16668c2ecf20Sopenharmony_ci free_irq(p->irq, p); 16678c2ecf20Sopenharmony_ci p->irq = 0; 16688c2ecf20Sopenharmony_ci } 16698c2ecf20Sopenharmony_ci spu_queue_destroy(p); 16708c2ecf20Sopenharmony_ci list_del(&p->list); 16718c2ecf20Sopenharmony_ci kfree(p); 16728c2ecf20Sopenharmony_ci } 16738c2ecf20Sopenharmony_ci} 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci/* Walk the backward arcs of a CWQ 'exec-unit' node, 16768c2ecf20Sopenharmony_ci * gathering cpu membership information. 16778c2ecf20Sopenharmony_ci */ 16788c2ecf20Sopenharmony_cistatic int spu_mdesc_walk_arcs(struct mdesc_handle *mdesc, 16798c2ecf20Sopenharmony_ci struct platform_device *dev, 16808c2ecf20Sopenharmony_ci u64 node, struct spu_queue *p, 16818c2ecf20Sopenharmony_ci struct spu_queue **table) 16828c2ecf20Sopenharmony_ci{ 16838c2ecf20Sopenharmony_ci u64 arc; 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci mdesc_for_each_arc(arc, mdesc, node, MDESC_ARC_TYPE_BACK) { 16868c2ecf20Sopenharmony_ci u64 tgt = mdesc_arc_target(mdesc, arc); 16878c2ecf20Sopenharmony_ci const char *name = mdesc_node_name(mdesc, tgt); 16888c2ecf20Sopenharmony_ci const u64 *id; 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci if (strcmp(name, "cpu")) 16918c2ecf20Sopenharmony_ci continue; 16928c2ecf20Sopenharmony_ci id = mdesc_get_property(mdesc, tgt, "id", NULL); 16938c2ecf20Sopenharmony_ci if (table[*id] != NULL) { 16948c2ecf20Sopenharmony_ci dev_err(&dev->dev, "%pOF: SPU cpu slot already set.\n", 16958c2ecf20Sopenharmony_ci dev->dev.of_node); 16968c2ecf20Sopenharmony_ci return -EINVAL; 16978c2ecf20Sopenharmony_ci } 16988c2ecf20Sopenharmony_ci cpumask_set_cpu(*id, &p->sharing); 16998c2ecf20Sopenharmony_ci table[*id] = p; 17008c2ecf20Sopenharmony_ci } 17018c2ecf20Sopenharmony_ci return 0; 17028c2ecf20Sopenharmony_ci} 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci/* Process an 'exec-unit' MDESC node of type 'cwq'. */ 17058c2ecf20Sopenharmony_cistatic int handle_exec_unit(struct spu_mdesc_info *ip, struct list_head *list, 17068c2ecf20Sopenharmony_ci struct platform_device *dev, struct mdesc_handle *mdesc, 17078c2ecf20Sopenharmony_ci u64 node, const char *iname, unsigned long q_type, 17088c2ecf20Sopenharmony_ci irq_handler_t handler, struct spu_queue **table) 17098c2ecf20Sopenharmony_ci{ 17108c2ecf20Sopenharmony_ci struct spu_queue *p; 17118c2ecf20Sopenharmony_ci int err; 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci p = kzalloc(sizeof(struct spu_queue), GFP_KERNEL); 17148c2ecf20Sopenharmony_ci if (!p) { 17158c2ecf20Sopenharmony_ci dev_err(&dev->dev, "%pOF: Could not allocate SPU queue.\n", 17168c2ecf20Sopenharmony_ci dev->dev.of_node); 17178c2ecf20Sopenharmony_ci return -ENOMEM; 17188c2ecf20Sopenharmony_ci } 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci cpumask_clear(&p->sharing); 17218c2ecf20Sopenharmony_ci spin_lock_init(&p->lock); 17228c2ecf20Sopenharmony_ci p->q_type = q_type; 17238c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&p->jobs); 17248c2ecf20Sopenharmony_ci list_add(&p->list, list); 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci err = spu_mdesc_walk_arcs(mdesc, dev, node, p, table); 17278c2ecf20Sopenharmony_ci if (err) 17288c2ecf20Sopenharmony_ci return err; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci err = spu_queue_setup(p); 17318c2ecf20Sopenharmony_ci if (err) 17328c2ecf20Sopenharmony_ci return err; 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci return spu_map_ino(dev, ip, iname, p, handler); 17358c2ecf20Sopenharmony_ci} 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_cistatic int spu_mdesc_scan(struct mdesc_handle *mdesc, struct platform_device *dev, 17388c2ecf20Sopenharmony_ci struct spu_mdesc_info *ip, struct list_head *list, 17398c2ecf20Sopenharmony_ci const char *exec_name, unsigned long q_type, 17408c2ecf20Sopenharmony_ci irq_handler_t handler, struct spu_queue **table) 17418c2ecf20Sopenharmony_ci{ 17428c2ecf20Sopenharmony_ci int err = 0; 17438c2ecf20Sopenharmony_ci u64 node; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci mdesc_for_each_node_by_name(mdesc, node, "exec-unit") { 17468c2ecf20Sopenharmony_ci const char *type; 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci type = mdesc_get_property(mdesc, node, "type", NULL); 17498c2ecf20Sopenharmony_ci if (!type || strcmp(type, exec_name)) 17508c2ecf20Sopenharmony_ci continue; 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci err = handle_exec_unit(ip, list, dev, mdesc, node, 17538c2ecf20Sopenharmony_ci exec_name, q_type, handler, table); 17548c2ecf20Sopenharmony_ci if (err) { 17558c2ecf20Sopenharmony_ci spu_list_destroy(list); 17568c2ecf20Sopenharmony_ci break; 17578c2ecf20Sopenharmony_ci } 17588c2ecf20Sopenharmony_ci } 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci return err; 17618c2ecf20Sopenharmony_ci} 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_cistatic int get_irq_props(struct mdesc_handle *mdesc, u64 node, 17648c2ecf20Sopenharmony_ci struct spu_mdesc_info *ip) 17658c2ecf20Sopenharmony_ci{ 17668c2ecf20Sopenharmony_ci const u64 *ino; 17678c2ecf20Sopenharmony_ci int ino_len; 17688c2ecf20Sopenharmony_ci int i; 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci ino = mdesc_get_property(mdesc, node, "ino", &ino_len); 17718c2ecf20Sopenharmony_ci if (!ino) { 17728c2ecf20Sopenharmony_ci printk("NO 'ino'\n"); 17738c2ecf20Sopenharmony_ci return -ENODEV; 17748c2ecf20Sopenharmony_ci } 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci ip->num_intrs = ino_len / sizeof(u64); 17778c2ecf20Sopenharmony_ci ip->ino_table = kzalloc((sizeof(struct ino_blob) * 17788c2ecf20Sopenharmony_ci ip->num_intrs), 17798c2ecf20Sopenharmony_ci GFP_KERNEL); 17808c2ecf20Sopenharmony_ci if (!ip->ino_table) 17818c2ecf20Sopenharmony_ci return -ENOMEM; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci for (i = 0; i < ip->num_intrs; i++) { 17848c2ecf20Sopenharmony_ci struct ino_blob *b = &ip->ino_table[i]; 17858c2ecf20Sopenharmony_ci b->intr = i + 1; 17868c2ecf20Sopenharmony_ci b->ino = ino[i]; 17878c2ecf20Sopenharmony_ci } 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci return 0; 17908c2ecf20Sopenharmony_ci} 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_cistatic int grab_mdesc_irq_props(struct mdesc_handle *mdesc, 17938c2ecf20Sopenharmony_ci struct platform_device *dev, 17948c2ecf20Sopenharmony_ci struct spu_mdesc_info *ip, 17958c2ecf20Sopenharmony_ci const char *node_name) 17968c2ecf20Sopenharmony_ci{ 17978c2ecf20Sopenharmony_ci const unsigned int *reg; 17988c2ecf20Sopenharmony_ci u64 node; 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci reg = of_get_property(dev->dev.of_node, "reg", NULL); 18018c2ecf20Sopenharmony_ci if (!reg) 18028c2ecf20Sopenharmony_ci return -ENODEV; 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci mdesc_for_each_node_by_name(mdesc, node, "virtual-device") { 18058c2ecf20Sopenharmony_ci const char *name; 18068c2ecf20Sopenharmony_ci const u64 *chdl; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci name = mdesc_get_property(mdesc, node, "name", NULL); 18098c2ecf20Sopenharmony_ci if (!name || strcmp(name, node_name)) 18108c2ecf20Sopenharmony_ci continue; 18118c2ecf20Sopenharmony_ci chdl = mdesc_get_property(mdesc, node, "cfg-handle", NULL); 18128c2ecf20Sopenharmony_ci if (!chdl || (*chdl != *reg)) 18138c2ecf20Sopenharmony_ci continue; 18148c2ecf20Sopenharmony_ci ip->cfg_handle = *chdl; 18158c2ecf20Sopenharmony_ci return get_irq_props(mdesc, node, ip); 18168c2ecf20Sopenharmony_ci } 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci return -ENODEV; 18198c2ecf20Sopenharmony_ci} 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_cistatic unsigned long n2_spu_hvapi_major; 18228c2ecf20Sopenharmony_cistatic unsigned long n2_spu_hvapi_minor; 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_cistatic int n2_spu_hvapi_register(void) 18258c2ecf20Sopenharmony_ci{ 18268c2ecf20Sopenharmony_ci int err; 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci n2_spu_hvapi_major = 2; 18298c2ecf20Sopenharmony_ci n2_spu_hvapi_minor = 0; 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci err = sun4v_hvapi_register(HV_GRP_NCS, 18328c2ecf20Sopenharmony_ci n2_spu_hvapi_major, 18338c2ecf20Sopenharmony_ci &n2_spu_hvapi_minor); 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci if (!err) 18368c2ecf20Sopenharmony_ci pr_info("Registered NCS HVAPI version %lu.%lu\n", 18378c2ecf20Sopenharmony_ci n2_spu_hvapi_major, 18388c2ecf20Sopenharmony_ci n2_spu_hvapi_minor); 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci return err; 18418c2ecf20Sopenharmony_ci} 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_cistatic void n2_spu_hvapi_unregister(void) 18448c2ecf20Sopenharmony_ci{ 18458c2ecf20Sopenharmony_ci sun4v_hvapi_unregister(HV_GRP_NCS); 18468c2ecf20Sopenharmony_ci} 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_cistatic int global_ref; 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_cistatic int grab_global_resources(void) 18518c2ecf20Sopenharmony_ci{ 18528c2ecf20Sopenharmony_ci int err = 0; 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci mutex_lock(&spu_lock); 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci if (global_ref++) 18578c2ecf20Sopenharmony_ci goto out; 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci err = n2_spu_hvapi_register(); 18608c2ecf20Sopenharmony_ci if (err) 18618c2ecf20Sopenharmony_ci goto out; 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci err = queue_cache_init(); 18648c2ecf20Sopenharmony_ci if (err) 18658c2ecf20Sopenharmony_ci goto out_hvapi_release; 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci err = -ENOMEM; 18688c2ecf20Sopenharmony_ci cpu_to_cwq = kcalloc(NR_CPUS, sizeof(struct spu_queue *), 18698c2ecf20Sopenharmony_ci GFP_KERNEL); 18708c2ecf20Sopenharmony_ci if (!cpu_to_cwq) 18718c2ecf20Sopenharmony_ci goto out_queue_cache_destroy; 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci cpu_to_mau = kcalloc(NR_CPUS, sizeof(struct spu_queue *), 18748c2ecf20Sopenharmony_ci GFP_KERNEL); 18758c2ecf20Sopenharmony_ci if (!cpu_to_mau) 18768c2ecf20Sopenharmony_ci goto out_free_cwq_table; 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci err = 0; 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ciout: 18818c2ecf20Sopenharmony_ci if (err) 18828c2ecf20Sopenharmony_ci global_ref--; 18838c2ecf20Sopenharmony_ci mutex_unlock(&spu_lock); 18848c2ecf20Sopenharmony_ci return err; 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ciout_free_cwq_table: 18878c2ecf20Sopenharmony_ci kfree(cpu_to_cwq); 18888c2ecf20Sopenharmony_ci cpu_to_cwq = NULL; 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ciout_queue_cache_destroy: 18918c2ecf20Sopenharmony_ci queue_cache_destroy(); 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ciout_hvapi_release: 18948c2ecf20Sopenharmony_ci n2_spu_hvapi_unregister(); 18958c2ecf20Sopenharmony_ci goto out; 18968c2ecf20Sopenharmony_ci} 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_cistatic void release_global_resources(void) 18998c2ecf20Sopenharmony_ci{ 19008c2ecf20Sopenharmony_ci mutex_lock(&spu_lock); 19018c2ecf20Sopenharmony_ci if (!--global_ref) { 19028c2ecf20Sopenharmony_ci kfree(cpu_to_cwq); 19038c2ecf20Sopenharmony_ci cpu_to_cwq = NULL; 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci kfree(cpu_to_mau); 19068c2ecf20Sopenharmony_ci cpu_to_mau = NULL; 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci queue_cache_destroy(); 19098c2ecf20Sopenharmony_ci n2_spu_hvapi_unregister(); 19108c2ecf20Sopenharmony_ci } 19118c2ecf20Sopenharmony_ci mutex_unlock(&spu_lock); 19128c2ecf20Sopenharmony_ci} 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_cistatic struct n2_crypto *alloc_n2cp(void) 19158c2ecf20Sopenharmony_ci{ 19168c2ecf20Sopenharmony_ci struct n2_crypto *np = kzalloc(sizeof(struct n2_crypto), GFP_KERNEL); 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_ci if (np) 19198c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&np->cwq_list); 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci return np; 19228c2ecf20Sopenharmony_ci} 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_cistatic void free_n2cp(struct n2_crypto *np) 19258c2ecf20Sopenharmony_ci{ 19268c2ecf20Sopenharmony_ci kfree(np->cwq_info.ino_table); 19278c2ecf20Sopenharmony_ci np->cwq_info.ino_table = NULL; 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci kfree(np); 19308c2ecf20Sopenharmony_ci} 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_cistatic void n2_spu_driver_version(void) 19338c2ecf20Sopenharmony_ci{ 19348c2ecf20Sopenharmony_ci static int n2_spu_version_printed; 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci if (n2_spu_version_printed++ == 0) 19378c2ecf20Sopenharmony_ci pr_info("%s", version); 19388c2ecf20Sopenharmony_ci} 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_cistatic int n2_crypto_probe(struct platform_device *dev) 19418c2ecf20Sopenharmony_ci{ 19428c2ecf20Sopenharmony_ci struct mdesc_handle *mdesc; 19438c2ecf20Sopenharmony_ci struct n2_crypto *np; 19448c2ecf20Sopenharmony_ci int err; 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci n2_spu_driver_version(); 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci pr_info("Found N2CP at %pOF\n", dev->dev.of_node); 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci np = alloc_n2cp(); 19518c2ecf20Sopenharmony_ci if (!np) { 19528c2ecf20Sopenharmony_ci dev_err(&dev->dev, "%pOF: Unable to allocate n2cp.\n", 19538c2ecf20Sopenharmony_ci dev->dev.of_node); 19548c2ecf20Sopenharmony_ci return -ENOMEM; 19558c2ecf20Sopenharmony_ci } 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci err = grab_global_resources(); 19588c2ecf20Sopenharmony_ci if (err) { 19598c2ecf20Sopenharmony_ci dev_err(&dev->dev, "%pOF: Unable to grab global resources.\n", 19608c2ecf20Sopenharmony_ci dev->dev.of_node); 19618c2ecf20Sopenharmony_ci goto out_free_n2cp; 19628c2ecf20Sopenharmony_ci } 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_ci mdesc = mdesc_grab(); 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci if (!mdesc) { 19678c2ecf20Sopenharmony_ci dev_err(&dev->dev, "%pOF: Unable to grab MDESC.\n", 19688c2ecf20Sopenharmony_ci dev->dev.of_node); 19698c2ecf20Sopenharmony_ci err = -ENODEV; 19708c2ecf20Sopenharmony_ci goto out_free_global; 19718c2ecf20Sopenharmony_ci } 19728c2ecf20Sopenharmony_ci err = grab_mdesc_irq_props(mdesc, dev, &np->cwq_info, "n2cp"); 19738c2ecf20Sopenharmony_ci if (err) { 19748c2ecf20Sopenharmony_ci dev_err(&dev->dev, "%pOF: Unable to grab IRQ props.\n", 19758c2ecf20Sopenharmony_ci dev->dev.of_node); 19768c2ecf20Sopenharmony_ci mdesc_release(mdesc); 19778c2ecf20Sopenharmony_ci goto out_free_global; 19788c2ecf20Sopenharmony_ci } 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci err = spu_mdesc_scan(mdesc, dev, &np->cwq_info, &np->cwq_list, 19818c2ecf20Sopenharmony_ci "cwq", HV_NCS_QTYPE_CWQ, cwq_intr, 19828c2ecf20Sopenharmony_ci cpu_to_cwq); 19838c2ecf20Sopenharmony_ci mdesc_release(mdesc); 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci if (err) { 19868c2ecf20Sopenharmony_ci dev_err(&dev->dev, "%pOF: CWQ MDESC scan failed.\n", 19878c2ecf20Sopenharmony_ci dev->dev.of_node); 19888c2ecf20Sopenharmony_ci goto out_free_global; 19898c2ecf20Sopenharmony_ci } 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci err = n2_register_algs(); 19928c2ecf20Sopenharmony_ci if (err) { 19938c2ecf20Sopenharmony_ci dev_err(&dev->dev, "%pOF: Unable to register algorithms.\n", 19948c2ecf20Sopenharmony_ci dev->dev.of_node); 19958c2ecf20Sopenharmony_ci goto out_free_spu_list; 19968c2ecf20Sopenharmony_ci } 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci dev_set_drvdata(&dev->dev, np); 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci return 0; 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ciout_free_spu_list: 20038c2ecf20Sopenharmony_ci spu_list_destroy(&np->cwq_list); 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ciout_free_global: 20068c2ecf20Sopenharmony_ci release_global_resources(); 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ciout_free_n2cp: 20098c2ecf20Sopenharmony_ci free_n2cp(np); 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci return err; 20128c2ecf20Sopenharmony_ci} 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_cistatic int n2_crypto_remove(struct platform_device *dev) 20158c2ecf20Sopenharmony_ci{ 20168c2ecf20Sopenharmony_ci struct n2_crypto *np = dev_get_drvdata(&dev->dev); 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci n2_unregister_algs(); 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci spu_list_destroy(&np->cwq_list); 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci release_global_resources(); 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci free_n2cp(np); 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci return 0; 20278c2ecf20Sopenharmony_ci} 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_cistatic struct n2_mau *alloc_ncp(void) 20308c2ecf20Sopenharmony_ci{ 20318c2ecf20Sopenharmony_ci struct n2_mau *mp = kzalloc(sizeof(struct n2_mau), GFP_KERNEL); 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci if (mp) 20348c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&mp->mau_list); 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci return mp; 20378c2ecf20Sopenharmony_ci} 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_cistatic void free_ncp(struct n2_mau *mp) 20408c2ecf20Sopenharmony_ci{ 20418c2ecf20Sopenharmony_ci kfree(mp->mau_info.ino_table); 20428c2ecf20Sopenharmony_ci mp->mau_info.ino_table = NULL; 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci kfree(mp); 20458c2ecf20Sopenharmony_ci} 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_cistatic int n2_mau_probe(struct platform_device *dev) 20488c2ecf20Sopenharmony_ci{ 20498c2ecf20Sopenharmony_ci struct mdesc_handle *mdesc; 20508c2ecf20Sopenharmony_ci struct n2_mau *mp; 20518c2ecf20Sopenharmony_ci int err; 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci n2_spu_driver_version(); 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci pr_info("Found NCP at %pOF\n", dev->dev.of_node); 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci mp = alloc_ncp(); 20588c2ecf20Sopenharmony_ci if (!mp) { 20598c2ecf20Sopenharmony_ci dev_err(&dev->dev, "%pOF: Unable to allocate ncp.\n", 20608c2ecf20Sopenharmony_ci dev->dev.of_node); 20618c2ecf20Sopenharmony_ci return -ENOMEM; 20628c2ecf20Sopenharmony_ci } 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci err = grab_global_resources(); 20658c2ecf20Sopenharmony_ci if (err) { 20668c2ecf20Sopenharmony_ci dev_err(&dev->dev, "%pOF: Unable to grab global resources.\n", 20678c2ecf20Sopenharmony_ci dev->dev.of_node); 20688c2ecf20Sopenharmony_ci goto out_free_ncp; 20698c2ecf20Sopenharmony_ci } 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci mdesc = mdesc_grab(); 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci if (!mdesc) { 20748c2ecf20Sopenharmony_ci dev_err(&dev->dev, "%pOF: Unable to grab MDESC.\n", 20758c2ecf20Sopenharmony_ci dev->dev.of_node); 20768c2ecf20Sopenharmony_ci err = -ENODEV; 20778c2ecf20Sopenharmony_ci goto out_free_global; 20788c2ecf20Sopenharmony_ci } 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci err = grab_mdesc_irq_props(mdesc, dev, &mp->mau_info, "ncp"); 20818c2ecf20Sopenharmony_ci if (err) { 20828c2ecf20Sopenharmony_ci dev_err(&dev->dev, "%pOF: Unable to grab IRQ props.\n", 20838c2ecf20Sopenharmony_ci dev->dev.of_node); 20848c2ecf20Sopenharmony_ci mdesc_release(mdesc); 20858c2ecf20Sopenharmony_ci goto out_free_global; 20868c2ecf20Sopenharmony_ci } 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci err = spu_mdesc_scan(mdesc, dev, &mp->mau_info, &mp->mau_list, 20898c2ecf20Sopenharmony_ci "mau", HV_NCS_QTYPE_MAU, mau_intr, 20908c2ecf20Sopenharmony_ci cpu_to_mau); 20918c2ecf20Sopenharmony_ci mdesc_release(mdesc); 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci if (err) { 20948c2ecf20Sopenharmony_ci dev_err(&dev->dev, "%pOF: MAU MDESC scan failed.\n", 20958c2ecf20Sopenharmony_ci dev->dev.of_node); 20968c2ecf20Sopenharmony_ci goto out_free_global; 20978c2ecf20Sopenharmony_ci } 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci dev_set_drvdata(&dev->dev, mp); 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci return 0; 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ciout_free_global: 21048c2ecf20Sopenharmony_ci release_global_resources(); 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ciout_free_ncp: 21078c2ecf20Sopenharmony_ci free_ncp(mp); 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci return err; 21108c2ecf20Sopenharmony_ci} 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_cistatic int n2_mau_remove(struct platform_device *dev) 21138c2ecf20Sopenharmony_ci{ 21148c2ecf20Sopenharmony_ci struct n2_mau *mp = dev_get_drvdata(&dev->dev); 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci spu_list_destroy(&mp->mau_list); 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci release_global_resources(); 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci free_ncp(mp); 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci return 0; 21238c2ecf20Sopenharmony_ci} 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_cistatic const struct of_device_id n2_crypto_match[] = { 21268c2ecf20Sopenharmony_ci { 21278c2ecf20Sopenharmony_ci .name = "n2cp", 21288c2ecf20Sopenharmony_ci .compatible = "SUNW,n2-cwq", 21298c2ecf20Sopenharmony_ci }, 21308c2ecf20Sopenharmony_ci { 21318c2ecf20Sopenharmony_ci .name = "n2cp", 21328c2ecf20Sopenharmony_ci .compatible = "SUNW,vf-cwq", 21338c2ecf20Sopenharmony_ci }, 21348c2ecf20Sopenharmony_ci { 21358c2ecf20Sopenharmony_ci .name = "n2cp", 21368c2ecf20Sopenharmony_ci .compatible = "SUNW,kt-cwq", 21378c2ecf20Sopenharmony_ci }, 21388c2ecf20Sopenharmony_ci {}, 21398c2ecf20Sopenharmony_ci}; 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, n2_crypto_match); 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_cistatic struct platform_driver n2_crypto_driver = { 21448c2ecf20Sopenharmony_ci .driver = { 21458c2ecf20Sopenharmony_ci .name = "n2cp", 21468c2ecf20Sopenharmony_ci .of_match_table = n2_crypto_match, 21478c2ecf20Sopenharmony_ci }, 21488c2ecf20Sopenharmony_ci .probe = n2_crypto_probe, 21498c2ecf20Sopenharmony_ci .remove = n2_crypto_remove, 21508c2ecf20Sopenharmony_ci}; 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_cistatic const struct of_device_id n2_mau_match[] = { 21538c2ecf20Sopenharmony_ci { 21548c2ecf20Sopenharmony_ci .name = "ncp", 21558c2ecf20Sopenharmony_ci .compatible = "SUNW,n2-mau", 21568c2ecf20Sopenharmony_ci }, 21578c2ecf20Sopenharmony_ci { 21588c2ecf20Sopenharmony_ci .name = "ncp", 21598c2ecf20Sopenharmony_ci .compatible = "SUNW,vf-mau", 21608c2ecf20Sopenharmony_ci }, 21618c2ecf20Sopenharmony_ci { 21628c2ecf20Sopenharmony_ci .name = "ncp", 21638c2ecf20Sopenharmony_ci .compatible = "SUNW,kt-mau", 21648c2ecf20Sopenharmony_ci }, 21658c2ecf20Sopenharmony_ci {}, 21668c2ecf20Sopenharmony_ci}; 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, n2_mau_match); 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_cistatic struct platform_driver n2_mau_driver = { 21718c2ecf20Sopenharmony_ci .driver = { 21728c2ecf20Sopenharmony_ci .name = "ncp", 21738c2ecf20Sopenharmony_ci .of_match_table = n2_mau_match, 21748c2ecf20Sopenharmony_ci }, 21758c2ecf20Sopenharmony_ci .probe = n2_mau_probe, 21768c2ecf20Sopenharmony_ci .remove = n2_mau_remove, 21778c2ecf20Sopenharmony_ci}; 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_cistatic struct platform_driver * const drivers[] = { 21808c2ecf20Sopenharmony_ci &n2_crypto_driver, 21818c2ecf20Sopenharmony_ci &n2_mau_driver, 21828c2ecf20Sopenharmony_ci}; 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_cistatic int __init n2_init(void) 21858c2ecf20Sopenharmony_ci{ 21868c2ecf20Sopenharmony_ci return platform_register_drivers(drivers, ARRAY_SIZE(drivers)); 21878c2ecf20Sopenharmony_ci} 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_cistatic void __exit n2_exit(void) 21908c2ecf20Sopenharmony_ci{ 21918c2ecf20Sopenharmony_ci platform_unregister_drivers(drivers, ARRAY_SIZE(drivers)); 21928c2ecf20Sopenharmony_ci} 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_cimodule_init(n2_init); 21958c2ecf20Sopenharmony_cimodule_exit(n2_exit); 2196