18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/** 38c2ecf20Sopenharmony_ci * Routines supporting the Power 7+ Nest Accelerators driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2011-2012 International Business Machines Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Kent Yoder <yoder1@us.ibm.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <crypto/internal/aead.h> 118c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h> 128c2ecf20Sopenharmony_ci#include <crypto/aes.h> 138c2ecf20Sopenharmony_ci#include <crypto/sha.h> 148c2ecf20Sopenharmony_ci#include <crypto/algapi.h> 158c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 188c2ecf20Sopenharmony_ci#include <linux/types.h> 198c2ecf20Sopenharmony_ci#include <linux/mm.h> 208c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 218c2ecf20Sopenharmony_ci#include <linux/device.h> 228c2ecf20Sopenharmony_ci#include <linux/of.h> 238c2ecf20Sopenharmony_ci#include <asm/hvcall.h> 248c2ecf20Sopenharmony_ci#include <asm/vio.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include "nx_csbcpb.h" 278c2ecf20Sopenharmony_ci#include "nx.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/** 318c2ecf20Sopenharmony_ci * nx_hcall_sync - make an H_COP_OP hcall for the passed in op structure 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * @nx_ctx: the crypto context handle 348c2ecf20Sopenharmony_ci * @op: PFO operation struct to pass in 358c2ecf20Sopenharmony_ci * @may_sleep: flag indicating the request can sleep 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * Make the hcall, retrying while the hardware is busy. If we cannot yield 388c2ecf20Sopenharmony_ci * the thread, limit the number of retries to 10 here. 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ciint nx_hcall_sync(struct nx_crypto_ctx *nx_ctx, 418c2ecf20Sopenharmony_ci struct vio_pfo_op *op, 428c2ecf20Sopenharmony_ci u32 may_sleep) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci int rc, retries = 10; 458c2ecf20Sopenharmony_ci struct vio_dev *viodev = nx_driver.viodev; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci atomic_inc(&(nx_ctx->stats->sync_ops)); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci do { 508c2ecf20Sopenharmony_ci rc = vio_h_cop_sync(viodev, op); 518c2ecf20Sopenharmony_ci } while (rc == -EBUSY && !may_sleep && retries--); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci if (rc) { 548c2ecf20Sopenharmony_ci dev_dbg(&viodev->dev, "vio_h_cop_sync failed: rc: %d " 558c2ecf20Sopenharmony_ci "hcall rc: %ld\n", rc, op->hcall_err); 568c2ecf20Sopenharmony_ci atomic_inc(&(nx_ctx->stats->errors)); 578c2ecf20Sopenharmony_ci atomic_set(&(nx_ctx->stats->last_error), op->hcall_err); 588c2ecf20Sopenharmony_ci atomic_set(&(nx_ctx->stats->last_error_pid), current->pid); 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci return rc; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/** 658c2ecf20Sopenharmony_ci * nx_build_sg_list - build an NX scatter list describing a single buffer 668c2ecf20Sopenharmony_ci * 678c2ecf20Sopenharmony_ci * @sg_head: pointer to the first scatter list element to build 688c2ecf20Sopenharmony_ci * @start_addr: pointer to the linear buffer 698c2ecf20Sopenharmony_ci * @len: length of the data at @start_addr 708c2ecf20Sopenharmony_ci * @sgmax: the largest number of scatter list elements we're allowed to create 718c2ecf20Sopenharmony_ci * 728c2ecf20Sopenharmony_ci * This function will start writing nx_sg elements at @sg_head and keep 738c2ecf20Sopenharmony_ci * writing them until all of the data from @start_addr is described or 748c2ecf20Sopenharmony_ci * until sgmax elements have been written. Scatter list elements will be 758c2ecf20Sopenharmony_ci * created such that none of the elements describes a buffer that crosses a 4K 768c2ecf20Sopenharmony_ci * boundary. 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_cistruct nx_sg *nx_build_sg_list(struct nx_sg *sg_head, 798c2ecf20Sopenharmony_ci u8 *start_addr, 808c2ecf20Sopenharmony_ci unsigned int *len, 818c2ecf20Sopenharmony_ci u32 sgmax) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci unsigned int sg_len = 0; 848c2ecf20Sopenharmony_ci struct nx_sg *sg; 858c2ecf20Sopenharmony_ci u64 sg_addr = (u64)start_addr; 868c2ecf20Sopenharmony_ci u64 end_addr; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* determine the start and end for this address range - slightly 898c2ecf20Sopenharmony_ci * different if this is in VMALLOC_REGION */ 908c2ecf20Sopenharmony_ci if (is_vmalloc_addr(start_addr)) 918c2ecf20Sopenharmony_ci sg_addr = page_to_phys(vmalloc_to_page(start_addr)) 928c2ecf20Sopenharmony_ci + offset_in_page(sg_addr); 938c2ecf20Sopenharmony_ci else 948c2ecf20Sopenharmony_ci sg_addr = __pa(sg_addr); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci end_addr = sg_addr + *len; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci /* each iteration will write one struct nx_sg element and add the 998c2ecf20Sopenharmony_ci * length of data described by that element to sg_len. Once @len bytes 1008c2ecf20Sopenharmony_ci * have been described (or @sgmax elements have been written), the 1018c2ecf20Sopenharmony_ci * loop ends. min_t is used to ensure @end_addr falls on the same page 1028c2ecf20Sopenharmony_ci * as sg_addr, if not, we need to create another nx_sg element for the 1038c2ecf20Sopenharmony_ci * data on the next page. 1048c2ecf20Sopenharmony_ci * 1058c2ecf20Sopenharmony_ci * Also when using vmalloc'ed data, every time that a system page 1068c2ecf20Sopenharmony_ci * boundary is crossed the physical address needs to be re-calculated. 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ci for (sg = sg_head; sg_len < *len; sg++) { 1098c2ecf20Sopenharmony_ci u64 next_page; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci sg->addr = sg_addr; 1128c2ecf20Sopenharmony_ci sg_addr = min_t(u64, NX_PAGE_NUM(sg_addr + NX_PAGE_SIZE), 1138c2ecf20Sopenharmony_ci end_addr); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci next_page = (sg->addr & PAGE_MASK) + PAGE_SIZE; 1168c2ecf20Sopenharmony_ci sg->len = min_t(u64, sg_addr, next_page) - sg->addr; 1178c2ecf20Sopenharmony_ci sg_len += sg->len; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (sg_addr >= next_page && 1208c2ecf20Sopenharmony_ci is_vmalloc_addr(start_addr + sg_len)) { 1218c2ecf20Sopenharmony_ci sg_addr = page_to_phys(vmalloc_to_page( 1228c2ecf20Sopenharmony_ci start_addr + sg_len)); 1238c2ecf20Sopenharmony_ci end_addr = sg_addr + *len - sg_len; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if ((sg - sg_head) == sgmax) { 1278c2ecf20Sopenharmony_ci pr_err("nx: scatter/gather list overflow, pid: %d\n", 1288c2ecf20Sopenharmony_ci current->pid); 1298c2ecf20Sopenharmony_ci sg++; 1308c2ecf20Sopenharmony_ci break; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci *len = sg_len; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* return the moved sg_head pointer */ 1368c2ecf20Sopenharmony_ci return sg; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/** 1408c2ecf20Sopenharmony_ci * nx_walk_and_build - walk a linux scatterlist and build an nx scatterlist 1418c2ecf20Sopenharmony_ci * 1428c2ecf20Sopenharmony_ci * @nx_dst: pointer to the first nx_sg element to write 1438c2ecf20Sopenharmony_ci * @sglen: max number of nx_sg entries we're allowed to write 1448c2ecf20Sopenharmony_ci * @sg_src: pointer to the source linux scatterlist to walk 1458c2ecf20Sopenharmony_ci * @start: number of bytes to fast-forward past at the beginning of @sg_src 1468c2ecf20Sopenharmony_ci * @src_len: number of bytes to walk in @sg_src 1478c2ecf20Sopenharmony_ci */ 1488c2ecf20Sopenharmony_cistruct nx_sg *nx_walk_and_build(struct nx_sg *nx_dst, 1498c2ecf20Sopenharmony_ci unsigned int sglen, 1508c2ecf20Sopenharmony_ci struct scatterlist *sg_src, 1518c2ecf20Sopenharmony_ci unsigned int start, 1528c2ecf20Sopenharmony_ci unsigned int *src_len) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci struct scatter_walk walk; 1558c2ecf20Sopenharmony_ci struct nx_sg *nx_sg = nx_dst; 1568c2ecf20Sopenharmony_ci unsigned int n, offset = 0, len = *src_len; 1578c2ecf20Sopenharmony_ci char *dst; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* we need to fast forward through @start bytes first */ 1608c2ecf20Sopenharmony_ci for (;;) { 1618c2ecf20Sopenharmony_ci scatterwalk_start(&walk, sg_src); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (start < offset + sg_src->length) 1648c2ecf20Sopenharmony_ci break; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci offset += sg_src->length; 1678c2ecf20Sopenharmony_ci sg_src = sg_next(sg_src); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* start - offset is the number of bytes to advance in the scatterlist 1718c2ecf20Sopenharmony_ci * element we're currently looking at */ 1728c2ecf20Sopenharmony_ci scatterwalk_advance(&walk, start - offset); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci while (len && (nx_sg - nx_dst) < sglen) { 1758c2ecf20Sopenharmony_ci n = scatterwalk_clamp(&walk, len); 1768c2ecf20Sopenharmony_ci if (!n) { 1778c2ecf20Sopenharmony_ci /* In cases where we have scatterlist chain sg_next 1788c2ecf20Sopenharmony_ci * handles with it properly */ 1798c2ecf20Sopenharmony_ci scatterwalk_start(&walk, sg_next(walk.sg)); 1808c2ecf20Sopenharmony_ci n = scatterwalk_clamp(&walk, len); 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci dst = scatterwalk_map(&walk); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci nx_sg = nx_build_sg_list(nx_sg, dst, &n, sglen - (nx_sg - nx_dst)); 1858c2ecf20Sopenharmony_ci len -= n; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci scatterwalk_unmap(dst); 1888c2ecf20Sopenharmony_ci scatterwalk_advance(&walk, n); 1898c2ecf20Sopenharmony_ci scatterwalk_done(&walk, SCATTERWALK_FROM_SG, len); 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci /* update to_process */ 1928c2ecf20Sopenharmony_ci *src_len -= len; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* return the moved destination pointer */ 1958c2ecf20Sopenharmony_ci return nx_sg; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/** 1998c2ecf20Sopenharmony_ci * trim_sg_list - ensures the bound in sg list. 2008c2ecf20Sopenharmony_ci * @sg: sg list head 2018c2ecf20Sopenharmony_ci * @end: sg lisg end 2028c2ecf20Sopenharmony_ci * @delta: is the amount we need to crop in order to bound the list. 2038c2ecf20Sopenharmony_ci * 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_cistatic long int trim_sg_list(struct nx_sg *sg, 2068c2ecf20Sopenharmony_ci struct nx_sg *end, 2078c2ecf20Sopenharmony_ci unsigned int delta, 2088c2ecf20Sopenharmony_ci unsigned int *nbytes) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci long int oplen; 2118c2ecf20Sopenharmony_ci long int data_back; 2128c2ecf20Sopenharmony_ci unsigned int is_delta = delta; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci while (delta && end > sg) { 2158c2ecf20Sopenharmony_ci struct nx_sg *last = end - 1; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (last->len > delta) { 2188c2ecf20Sopenharmony_ci last->len -= delta; 2198c2ecf20Sopenharmony_ci delta = 0; 2208c2ecf20Sopenharmony_ci } else { 2218c2ecf20Sopenharmony_ci end--; 2228c2ecf20Sopenharmony_ci delta -= last->len; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* There are cases where we need to crop list in order to make it 2278c2ecf20Sopenharmony_ci * a block size multiple, but we also need to align data. In order to 2288c2ecf20Sopenharmony_ci * that we need to calculate how much we need to put back to be 2298c2ecf20Sopenharmony_ci * processed 2308c2ecf20Sopenharmony_ci */ 2318c2ecf20Sopenharmony_ci oplen = (sg - end) * sizeof(struct nx_sg); 2328c2ecf20Sopenharmony_ci if (is_delta) { 2338c2ecf20Sopenharmony_ci data_back = (abs(oplen) / AES_BLOCK_SIZE) * sg->len; 2348c2ecf20Sopenharmony_ci data_back = *nbytes - (data_back & ~(AES_BLOCK_SIZE - 1)); 2358c2ecf20Sopenharmony_ci *nbytes -= data_back; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return oplen; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci/** 2428c2ecf20Sopenharmony_ci * nx_build_sg_lists - walk the input scatterlists and build arrays of NX 2438c2ecf20Sopenharmony_ci * scatterlists based on them. 2448c2ecf20Sopenharmony_ci * 2458c2ecf20Sopenharmony_ci * @nx_ctx: NX crypto context for the lists we're building 2468c2ecf20Sopenharmony_ci * @iv: iv data, if the algorithm requires it 2478c2ecf20Sopenharmony_ci * @dst: destination scatterlist 2488c2ecf20Sopenharmony_ci * @src: source scatterlist 2498c2ecf20Sopenharmony_ci * @nbytes: length of data described in the scatterlists 2508c2ecf20Sopenharmony_ci * @offset: number of bytes to fast-forward past at the beginning of 2518c2ecf20Sopenharmony_ci * scatterlists. 2528c2ecf20Sopenharmony_ci * @oiv: destination for the iv data, if the algorithm requires it 2538c2ecf20Sopenharmony_ci * 2548c2ecf20Sopenharmony_ci * This is common code shared by all the AES algorithms. It uses the crypto 2558c2ecf20Sopenharmony_ci * scatterlist walk routines to traverse input and output scatterlists, building 2568c2ecf20Sopenharmony_ci * corresponding NX scatterlists 2578c2ecf20Sopenharmony_ci */ 2588c2ecf20Sopenharmony_ciint nx_build_sg_lists(struct nx_crypto_ctx *nx_ctx, 2598c2ecf20Sopenharmony_ci const u8 *iv, 2608c2ecf20Sopenharmony_ci struct scatterlist *dst, 2618c2ecf20Sopenharmony_ci struct scatterlist *src, 2628c2ecf20Sopenharmony_ci unsigned int *nbytes, 2638c2ecf20Sopenharmony_ci unsigned int offset, 2648c2ecf20Sopenharmony_ci u8 *oiv) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci unsigned int delta = 0; 2678c2ecf20Sopenharmony_ci unsigned int total = *nbytes; 2688c2ecf20Sopenharmony_ci struct nx_sg *nx_insg = nx_ctx->in_sg; 2698c2ecf20Sopenharmony_ci struct nx_sg *nx_outsg = nx_ctx->out_sg; 2708c2ecf20Sopenharmony_ci unsigned int max_sg_len; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci max_sg_len = min_t(u64, nx_ctx->ap->sglen, 2738c2ecf20Sopenharmony_ci nx_driver.of.max_sg_len/sizeof(struct nx_sg)); 2748c2ecf20Sopenharmony_ci max_sg_len = min_t(u64, max_sg_len, 2758c2ecf20Sopenharmony_ci nx_ctx->ap->databytelen/NX_PAGE_SIZE); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (oiv) 2788c2ecf20Sopenharmony_ci memcpy(oiv, iv, AES_BLOCK_SIZE); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci *nbytes = min_t(u64, *nbytes, nx_ctx->ap->databytelen); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci nx_outsg = nx_walk_and_build(nx_outsg, max_sg_len, dst, 2838c2ecf20Sopenharmony_ci offset, nbytes); 2848c2ecf20Sopenharmony_ci nx_insg = nx_walk_and_build(nx_insg, max_sg_len, src, 2858c2ecf20Sopenharmony_ci offset, nbytes); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (*nbytes < total) 2888c2ecf20Sopenharmony_ci delta = *nbytes - (*nbytes & ~(AES_BLOCK_SIZE - 1)); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* these lengths should be negative, which will indicate to phyp that 2918c2ecf20Sopenharmony_ci * the input and output parameters are scatterlists, not linear 2928c2ecf20Sopenharmony_ci * buffers */ 2938c2ecf20Sopenharmony_ci nx_ctx->op.inlen = trim_sg_list(nx_ctx->in_sg, nx_insg, delta, nbytes); 2948c2ecf20Sopenharmony_ci nx_ctx->op.outlen = trim_sg_list(nx_ctx->out_sg, nx_outsg, delta, nbytes); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return 0; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci/** 3008c2ecf20Sopenharmony_ci * nx_ctx_init - initialize an nx_ctx's vio_pfo_op struct 3018c2ecf20Sopenharmony_ci * 3028c2ecf20Sopenharmony_ci * @nx_ctx: the nx context to initialize 3038c2ecf20Sopenharmony_ci * @function: the function code for the op 3048c2ecf20Sopenharmony_ci */ 3058c2ecf20Sopenharmony_civoid nx_ctx_init(struct nx_crypto_ctx *nx_ctx, unsigned int function) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci spin_lock_init(&nx_ctx->lock); 3088c2ecf20Sopenharmony_ci memset(nx_ctx->kmem, 0, nx_ctx->kmem_len); 3098c2ecf20Sopenharmony_ci nx_ctx->csbcpb->csb.valid |= NX_CSB_VALID_BIT; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci nx_ctx->op.flags = function; 3128c2ecf20Sopenharmony_ci nx_ctx->op.csbcpb = __pa(nx_ctx->csbcpb); 3138c2ecf20Sopenharmony_ci nx_ctx->op.in = __pa(nx_ctx->in_sg); 3148c2ecf20Sopenharmony_ci nx_ctx->op.out = __pa(nx_ctx->out_sg); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (nx_ctx->csbcpb_aead) { 3178c2ecf20Sopenharmony_ci nx_ctx->csbcpb_aead->csb.valid |= NX_CSB_VALID_BIT; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci nx_ctx->op_aead.flags = function; 3208c2ecf20Sopenharmony_ci nx_ctx->op_aead.csbcpb = __pa(nx_ctx->csbcpb_aead); 3218c2ecf20Sopenharmony_ci nx_ctx->op_aead.in = __pa(nx_ctx->in_sg); 3228c2ecf20Sopenharmony_ci nx_ctx->op_aead.out = __pa(nx_ctx->out_sg); 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci} 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic void nx_of_update_status(struct device *dev, 3278c2ecf20Sopenharmony_ci struct property *p, 3288c2ecf20Sopenharmony_ci struct nx_of *props) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci if (!strncmp(p->value, "okay", p->length)) { 3318c2ecf20Sopenharmony_ci props->status = NX_WAITING; 3328c2ecf20Sopenharmony_ci props->flags |= NX_OF_FLAG_STATUS_SET; 3338c2ecf20Sopenharmony_ci } else { 3348c2ecf20Sopenharmony_ci dev_info(dev, "%s: status '%s' is not 'okay'\n", __func__, 3358c2ecf20Sopenharmony_ci (char *)p->value); 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic void nx_of_update_sglen(struct device *dev, 3408c2ecf20Sopenharmony_ci struct property *p, 3418c2ecf20Sopenharmony_ci struct nx_of *props) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci if (p->length != sizeof(props->max_sg_len)) { 3448c2ecf20Sopenharmony_ci dev_err(dev, "%s: unexpected format for " 3458c2ecf20Sopenharmony_ci "ibm,max-sg-len property\n", __func__); 3468c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: ibm,max-sg-len is %d bytes " 3478c2ecf20Sopenharmony_ci "long, expected %zd bytes\n", __func__, 3488c2ecf20Sopenharmony_ci p->length, sizeof(props->max_sg_len)); 3498c2ecf20Sopenharmony_ci return; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci props->max_sg_len = *(u32 *)p->value; 3538c2ecf20Sopenharmony_ci props->flags |= NX_OF_FLAG_MAXSGLEN_SET; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic void nx_of_update_msc(struct device *dev, 3578c2ecf20Sopenharmony_ci struct property *p, 3588c2ecf20Sopenharmony_ci struct nx_of *props) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct msc_triplet *trip; 3618c2ecf20Sopenharmony_ci struct max_sync_cop *msc; 3628c2ecf20Sopenharmony_ci unsigned int bytes_so_far, i, lenp; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci msc = (struct max_sync_cop *)p->value; 3658c2ecf20Sopenharmony_ci lenp = p->length; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci /* You can't tell if the data read in for this property is sane by its 3688c2ecf20Sopenharmony_ci * size alone. This is because there are sizes embedded in the data 3698c2ecf20Sopenharmony_ci * structure. The best we can do is check lengths as we parse and bail 3708c2ecf20Sopenharmony_ci * as soon as a length error is detected. */ 3718c2ecf20Sopenharmony_ci bytes_so_far = 0; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci while ((bytes_so_far + sizeof(struct max_sync_cop)) <= lenp) { 3748c2ecf20Sopenharmony_ci bytes_so_far += sizeof(struct max_sync_cop); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci trip = msc->trip; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci for (i = 0; 3798c2ecf20Sopenharmony_ci ((bytes_so_far + sizeof(struct msc_triplet)) <= lenp) && 3808c2ecf20Sopenharmony_ci i < msc->triplets; 3818c2ecf20Sopenharmony_ci i++) { 3828c2ecf20Sopenharmony_ci if (msc->fc >= NX_MAX_FC || msc->mode >= NX_MAX_MODE) { 3838c2ecf20Sopenharmony_ci dev_err(dev, "unknown function code/mode " 3848c2ecf20Sopenharmony_ci "combo: %d/%d (ignored)\n", msc->fc, 3858c2ecf20Sopenharmony_ci msc->mode); 3868c2ecf20Sopenharmony_ci goto next_loop; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci if (!trip->sglen || trip->databytelen < NX_PAGE_SIZE) { 3908c2ecf20Sopenharmony_ci dev_warn(dev, "bogus sglen/databytelen: " 3918c2ecf20Sopenharmony_ci "%u/%u (ignored)\n", trip->sglen, 3928c2ecf20Sopenharmony_ci trip->databytelen); 3938c2ecf20Sopenharmony_ci goto next_loop; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci switch (trip->keybitlen) { 3978c2ecf20Sopenharmony_ci case 128: 3988c2ecf20Sopenharmony_ci case 160: 3998c2ecf20Sopenharmony_ci props->ap[msc->fc][msc->mode][0].databytelen = 4008c2ecf20Sopenharmony_ci trip->databytelen; 4018c2ecf20Sopenharmony_ci props->ap[msc->fc][msc->mode][0].sglen = 4028c2ecf20Sopenharmony_ci trip->sglen; 4038c2ecf20Sopenharmony_ci break; 4048c2ecf20Sopenharmony_ci case 192: 4058c2ecf20Sopenharmony_ci props->ap[msc->fc][msc->mode][1].databytelen = 4068c2ecf20Sopenharmony_ci trip->databytelen; 4078c2ecf20Sopenharmony_ci props->ap[msc->fc][msc->mode][1].sglen = 4088c2ecf20Sopenharmony_ci trip->sglen; 4098c2ecf20Sopenharmony_ci break; 4108c2ecf20Sopenharmony_ci case 256: 4118c2ecf20Sopenharmony_ci if (msc->fc == NX_FC_AES) { 4128c2ecf20Sopenharmony_ci props->ap[msc->fc][msc->mode][2]. 4138c2ecf20Sopenharmony_ci databytelen = trip->databytelen; 4148c2ecf20Sopenharmony_ci props->ap[msc->fc][msc->mode][2].sglen = 4158c2ecf20Sopenharmony_ci trip->sglen; 4168c2ecf20Sopenharmony_ci } else if (msc->fc == NX_FC_AES_HMAC || 4178c2ecf20Sopenharmony_ci msc->fc == NX_FC_SHA) { 4188c2ecf20Sopenharmony_ci props->ap[msc->fc][msc->mode][1]. 4198c2ecf20Sopenharmony_ci databytelen = trip->databytelen; 4208c2ecf20Sopenharmony_ci props->ap[msc->fc][msc->mode][1].sglen = 4218c2ecf20Sopenharmony_ci trip->sglen; 4228c2ecf20Sopenharmony_ci } else { 4238c2ecf20Sopenharmony_ci dev_warn(dev, "unknown function " 4248c2ecf20Sopenharmony_ci "code/key bit len combo" 4258c2ecf20Sopenharmony_ci ": (%u/256)\n", msc->fc); 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci break; 4288c2ecf20Sopenharmony_ci case 512: 4298c2ecf20Sopenharmony_ci props->ap[msc->fc][msc->mode][2].databytelen = 4308c2ecf20Sopenharmony_ci trip->databytelen; 4318c2ecf20Sopenharmony_ci props->ap[msc->fc][msc->mode][2].sglen = 4328c2ecf20Sopenharmony_ci trip->sglen; 4338c2ecf20Sopenharmony_ci break; 4348c2ecf20Sopenharmony_ci default: 4358c2ecf20Sopenharmony_ci dev_warn(dev, "unknown function code/key bit " 4368c2ecf20Sopenharmony_ci "len combo: (%u/%u)\n", msc->fc, 4378c2ecf20Sopenharmony_ci trip->keybitlen); 4388c2ecf20Sopenharmony_ci break; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_cinext_loop: 4418c2ecf20Sopenharmony_ci bytes_so_far += sizeof(struct msc_triplet); 4428c2ecf20Sopenharmony_ci trip++; 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci msc = (struct max_sync_cop *)trip; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci props->flags |= NX_OF_FLAG_MAXSYNCCOP_SET; 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci/** 4528c2ecf20Sopenharmony_ci * nx_of_init - read openFirmware values from the device tree 4538c2ecf20Sopenharmony_ci * 4548c2ecf20Sopenharmony_ci * @dev: device handle 4558c2ecf20Sopenharmony_ci * @props: pointer to struct to hold the properties values 4568c2ecf20Sopenharmony_ci * 4578c2ecf20Sopenharmony_ci * Called once at driver probe time, this function will read out the 4588c2ecf20Sopenharmony_ci * openFirmware properties we use at runtime. If all the OF properties are 4598c2ecf20Sopenharmony_ci * acceptable, when we exit this function props->flags will indicate that 4608c2ecf20Sopenharmony_ci * we're ready to register our crypto algorithms. 4618c2ecf20Sopenharmony_ci */ 4628c2ecf20Sopenharmony_cistatic void nx_of_init(struct device *dev, struct nx_of *props) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci struct device_node *base_node = dev->of_node; 4658c2ecf20Sopenharmony_ci struct property *p; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci p = of_find_property(base_node, "status", NULL); 4688c2ecf20Sopenharmony_ci if (!p) 4698c2ecf20Sopenharmony_ci dev_info(dev, "%s: property 'status' not found\n", __func__); 4708c2ecf20Sopenharmony_ci else 4718c2ecf20Sopenharmony_ci nx_of_update_status(dev, p, props); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci p = of_find_property(base_node, "ibm,max-sg-len", NULL); 4748c2ecf20Sopenharmony_ci if (!p) 4758c2ecf20Sopenharmony_ci dev_info(dev, "%s: property 'ibm,max-sg-len' not found\n", 4768c2ecf20Sopenharmony_ci __func__); 4778c2ecf20Sopenharmony_ci else 4788c2ecf20Sopenharmony_ci nx_of_update_sglen(dev, p, props); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci p = of_find_property(base_node, "ibm,max-sync-cop", NULL); 4818c2ecf20Sopenharmony_ci if (!p) 4828c2ecf20Sopenharmony_ci dev_info(dev, "%s: property 'ibm,max-sync-cop' not found\n", 4838c2ecf20Sopenharmony_ci __func__); 4848c2ecf20Sopenharmony_ci else 4858c2ecf20Sopenharmony_ci nx_of_update_msc(dev, p, props); 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic bool nx_check_prop(struct device *dev, u32 fc, u32 mode, int slot) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci struct alg_props *props = &nx_driver.of.ap[fc][mode][slot]; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci if (!props->sglen || props->databytelen < NX_PAGE_SIZE) { 4938c2ecf20Sopenharmony_ci if (dev) 4948c2ecf20Sopenharmony_ci dev_warn(dev, "bogus sglen/databytelen for %u/%u/%u: " 4958c2ecf20Sopenharmony_ci "%u/%u (ignored)\n", fc, mode, slot, 4968c2ecf20Sopenharmony_ci props->sglen, props->databytelen); 4978c2ecf20Sopenharmony_ci return false; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci return true; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic bool nx_check_props(struct device *dev, u32 fc, u32 mode) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci int i; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) 5088c2ecf20Sopenharmony_ci if (!nx_check_prop(dev, fc, mode, i)) 5098c2ecf20Sopenharmony_ci return false; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci return true; 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic int nx_register_skcipher(struct skcipher_alg *alg, u32 fc, u32 mode) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci return nx_check_props(&nx_driver.viodev->dev, fc, mode) ? 5178c2ecf20Sopenharmony_ci crypto_register_skcipher(alg) : 0; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic int nx_register_aead(struct aead_alg *alg, u32 fc, u32 mode) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci return nx_check_props(&nx_driver.viodev->dev, fc, mode) ? 5238c2ecf20Sopenharmony_ci crypto_register_aead(alg) : 0; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic int nx_register_shash(struct shash_alg *alg, u32 fc, u32 mode, int slot) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci return (slot >= 0 ? nx_check_prop(&nx_driver.viodev->dev, 5298c2ecf20Sopenharmony_ci fc, mode, slot) : 5308c2ecf20Sopenharmony_ci nx_check_props(&nx_driver.viodev->dev, fc, mode)) ? 5318c2ecf20Sopenharmony_ci crypto_register_shash(alg) : 0; 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistatic void nx_unregister_skcipher(struct skcipher_alg *alg, u32 fc, u32 mode) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci if (nx_check_props(NULL, fc, mode)) 5378c2ecf20Sopenharmony_ci crypto_unregister_skcipher(alg); 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic void nx_unregister_aead(struct aead_alg *alg, u32 fc, u32 mode) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci if (nx_check_props(NULL, fc, mode)) 5438c2ecf20Sopenharmony_ci crypto_unregister_aead(alg); 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic void nx_unregister_shash(struct shash_alg *alg, u32 fc, u32 mode, 5478c2ecf20Sopenharmony_ci int slot) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci if (slot >= 0 ? nx_check_prop(NULL, fc, mode, slot) : 5508c2ecf20Sopenharmony_ci nx_check_props(NULL, fc, mode)) 5518c2ecf20Sopenharmony_ci crypto_unregister_shash(alg); 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci/** 5558c2ecf20Sopenharmony_ci * nx_register_algs - register algorithms with the crypto API 5568c2ecf20Sopenharmony_ci * 5578c2ecf20Sopenharmony_ci * Called from nx_probe() 5588c2ecf20Sopenharmony_ci * 5598c2ecf20Sopenharmony_ci * If all OF properties are in an acceptable state, the driver flags will 5608c2ecf20Sopenharmony_ci * indicate that we're ready and we'll create our debugfs files and register 5618c2ecf20Sopenharmony_ci * out crypto algorithms. 5628c2ecf20Sopenharmony_ci */ 5638c2ecf20Sopenharmony_cistatic int nx_register_algs(void) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci int rc = -1; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci if (nx_driver.of.flags != NX_OF_FLAG_MASK_READY) 5688c2ecf20Sopenharmony_ci goto out; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci memset(&nx_driver.stats, 0, sizeof(struct nx_stats)); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci NX_DEBUGFS_INIT(&nx_driver); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci nx_driver.of.status = NX_OKAY; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci rc = nx_register_skcipher(&nx_ecb_aes_alg, NX_FC_AES, NX_MODE_AES_ECB); 5778c2ecf20Sopenharmony_ci if (rc) 5788c2ecf20Sopenharmony_ci goto out; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci rc = nx_register_skcipher(&nx_cbc_aes_alg, NX_FC_AES, NX_MODE_AES_CBC); 5818c2ecf20Sopenharmony_ci if (rc) 5828c2ecf20Sopenharmony_ci goto out_unreg_ecb; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci rc = nx_register_skcipher(&nx_ctr3686_aes_alg, NX_FC_AES, 5858c2ecf20Sopenharmony_ci NX_MODE_AES_CTR); 5868c2ecf20Sopenharmony_ci if (rc) 5878c2ecf20Sopenharmony_ci goto out_unreg_cbc; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci rc = nx_register_aead(&nx_gcm_aes_alg, NX_FC_AES, NX_MODE_AES_GCM); 5908c2ecf20Sopenharmony_ci if (rc) 5918c2ecf20Sopenharmony_ci goto out_unreg_ctr3686; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci rc = nx_register_aead(&nx_gcm4106_aes_alg, NX_FC_AES, NX_MODE_AES_GCM); 5948c2ecf20Sopenharmony_ci if (rc) 5958c2ecf20Sopenharmony_ci goto out_unreg_gcm; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci rc = nx_register_aead(&nx_ccm_aes_alg, NX_FC_AES, NX_MODE_AES_CCM); 5988c2ecf20Sopenharmony_ci if (rc) 5998c2ecf20Sopenharmony_ci goto out_unreg_gcm4106; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci rc = nx_register_aead(&nx_ccm4309_aes_alg, NX_FC_AES, NX_MODE_AES_CCM); 6028c2ecf20Sopenharmony_ci if (rc) 6038c2ecf20Sopenharmony_ci goto out_unreg_ccm; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci rc = nx_register_shash(&nx_shash_sha256_alg, NX_FC_SHA, NX_MODE_SHA, 6068c2ecf20Sopenharmony_ci NX_PROPS_SHA256); 6078c2ecf20Sopenharmony_ci if (rc) 6088c2ecf20Sopenharmony_ci goto out_unreg_ccm4309; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci rc = nx_register_shash(&nx_shash_sha512_alg, NX_FC_SHA, NX_MODE_SHA, 6118c2ecf20Sopenharmony_ci NX_PROPS_SHA512); 6128c2ecf20Sopenharmony_ci if (rc) 6138c2ecf20Sopenharmony_ci goto out_unreg_s256; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci rc = nx_register_shash(&nx_shash_aes_xcbc_alg, 6168c2ecf20Sopenharmony_ci NX_FC_AES, NX_MODE_AES_XCBC_MAC, -1); 6178c2ecf20Sopenharmony_ci if (rc) 6188c2ecf20Sopenharmony_ci goto out_unreg_s512; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci goto out; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ciout_unreg_s512: 6238c2ecf20Sopenharmony_ci nx_unregister_shash(&nx_shash_sha512_alg, NX_FC_SHA, NX_MODE_SHA, 6248c2ecf20Sopenharmony_ci NX_PROPS_SHA512); 6258c2ecf20Sopenharmony_ciout_unreg_s256: 6268c2ecf20Sopenharmony_ci nx_unregister_shash(&nx_shash_sha256_alg, NX_FC_SHA, NX_MODE_SHA, 6278c2ecf20Sopenharmony_ci NX_PROPS_SHA256); 6288c2ecf20Sopenharmony_ciout_unreg_ccm4309: 6298c2ecf20Sopenharmony_ci nx_unregister_aead(&nx_ccm4309_aes_alg, NX_FC_AES, NX_MODE_AES_CCM); 6308c2ecf20Sopenharmony_ciout_unreg_ccm: 6318c2ecf20Sopenharmony_ci nx_unregister_aead(&nx_ccm_aes_alg, NX_FC_AES, NX_MODE_AES_CCM); 6328c2ecf20Sopenharmony_ciout_unreg_gcm4106: 6338c2ecf20Sopenharmony_ci nx_unregister_aead(&nx_gcm4106_aes_alg, NX_FC_AES, NX_MODE_AES_GCM); 6348c2ecf20Sopenharmony_ciout_unreg_gcm: 6358c2ecf20Sopenharmony_ci nx_unregister_aead(&nx_gcm_aes_alg, NX_FC_AES, NX_MODE_AES_GCM); 6368c2ecf20Sopenharmony_ciout_unreg_ctr3686: 6378c2ecf20Sopenharmony_ci nx_unregister_skcipher(&nx_ctr3686_aes_alg, NX_FC_AES, NX_MODE_AES_CTR); 6388c2ecf20Sopenharmony_ciout_unreg_cbc: 6398c2ecf20Sopenharmony_ci nx_unregister_skcipher(&nx_cbc_aes_alg, NX_FC_AES, NX_MODE_AES_CBC); 6408c2ecf20Sopenharmony_ciout_unreg_ecb: 6418c2ecf20Sopenharmony_ci nx_unregister_skcipher(&nx_ecb_aes_alg, NX_FC_AES, NX_MODE_AES_ECB); 6428c2ecf20Sopenharmony_ciout: 6438c2ecf20Sopenharmony_ci return rc; 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci/** 6478c2ecf20Sopenharmony_ci * nx_crypto_ctx_init - create and initialize a crypto api context 6488c2ecf20Sopenharmony_ci * 6498c2ecf20Sopenharmony_ci * @nx_ctx: the crypto api context 6508c2ecf20Sopenharmony_ci * @fc: function code for the context 6518c2ecf20Sopenharmony_ci * @mode: the function code specific mode for this context 6528c2ecf20Sopenharmony_ci */ 6538c2ecf20Sopenharmony_cistatic int nx_crypto_ctx_init(struct nx_crypto_ctx *nx_ctx, u32 fc, u32 mode) 6548c2ecf20Sopenharmony_ci{ 6558c2ecf20Sopenharmony_ci if (nx_driver.of.status != NX_OKAY) { 6568c2ecf20Sopenharmony_ci pr_err("Attempt to initialize NX crypto context while device " 6578c2ecf20Sopenharmony_ci "is not available!\n"); 6588c2ecf20Sopenharmony_ci return -ENODEV; 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci /* we need an extra page for csbcpb_aead for these modes */ 6628c2ecf20Sopenharmony_ci if (mode == NX_MODE_AES_GCM || mode == NX_MODE_AES_CCM) 6638c2ecf20Sopenharmony_ci nx_ctx->kmem_len = (5 * NX_PAGE_SIZE) + 6648c2ecf20Sopenharmony_ci sizeof(struct nx_csbcpb); 6658c2ecf20Sopenharmony_ci else 6668c2ecf20Sopenharmony_ci nx_ctx->kmem_len = (4 * NX_PAGE_SIZE) + 6678c2ecf20Sopenharmony_ci sizeof(struct nx_csbcpb); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci nx_ctx->kmem = kmalloc(nx_ctx->kmem_len, GFP_KERNEL); 6708c2ecf20Sopenharmony_ci if (!nx_ctx->kmem) 6718c2ecf20Sopenharmony_ci return -ENOMEM; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci /* the csbcpb and scatterlists must be 4K aligned pages */ 6748c2ecf20Sopenharmony_ci nx_ctx->csbcpb = (struct nx_csbcpb *)(round_up((u64)nx_ctx->kmem, 6758c2ecf20Sopenharmony_ci (u64)NX_PAGE_SIZE)); 6768c2ecf20Sopenharmony_ci nx_ctx->in_sg = (struct nx_sg *)((u8 *)nx_ctx->csbcpb + NX_PAGE_SIZE); 6778c2ecf20Sopenharmony_ci nx_ctx->out_sg = (struct nx_sg *)((u8 *)nx_ctx->in_sg + NX_PAGE_SIZE); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (mode == NX_MODE_AES_GCM || mode == NX_MODE_AES_CCM) 6808c2ecf20Sopenharmony_ci nx_ctx->csbcpb_aead = 6818c2ecf20Sopenharmony_ci (struct nx_csbcpb *)((u8 *)nx_ctx->out_sg + 6828c2ecf20Sopenharmony_ci NX_PAGE_SIZE); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci /* give each context a pointer to global stats and their OF 6858c2ecf20Sopenharmony_ci * properties */ 6868c2ecf20Sopenharmony_ci nx_ctx->stats = &nx_driver.stats; 6878c2ecf20Sopenharmony_ci memcpy(nx_ctx->props, nx_driver.of.ap[fc][mode], 6888c2ecf20Sopenharmony_ci sizeof(struct alg_props) * 3); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci return 0; 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci/* entry points from the crypto tfm initializers */ 6948c2ecf20Sopenharmony_ciint nx_crypto_ctx_aes_ccm_init(struct crypto_aead *tfm) 6958c2ecf20Sopenharmony_ci{ 6968c2ecf20Sopenharmony_ci crypto_aead_set_reqsize(tfm, sizeof(struct nx_ccm_rctx)); 6978c2ecf20Sopenharmony_ci return nx_crypto_ctx_init(crypto_aead_ctx(tfm), NX_FC_AES, 6988c2ecf20Sopenharmony_ci NX_MODE_AES_CCM); 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ciint nx_crypto_ctx_aes_gcm_init(struct crypto_aead *tfm) 7028c2ecf20Sopenharmony_ci{ 7038c2ecf20Sopenharmony_ci crypto_aead_set_reqsize(tfm, sizeof(struct nx_gcm_rctx)); 7048c2ecf20Sopenharmony_ci return nx_crypto_ctx_init(crypto_aead_ctx(tfm), NX_FC_AES, 7058c2ecf20Sopenharmony_ci NX_MODE_AES_GCM); 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ciint nx_crypto_ctx_aes_ctr_init(struct crypto_skcipher *tfm) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci return nx_crypto_ctx_init(crypto_skcipher_ctx(tfm), NX_FC_AES, 7118c2ecf20Sopenharmony_ci NX_MODE_AES_CTR); 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ciint nx_crypto_ctx_aes_cbc_init(struct crypto_skcipher *tfm) 7158c2ecf20Sopenharmony_ci{ 7168c2ecf20Sopenharmony_ci return nx_crypto_ctx_init(crypto_skcipher_ctx(tfm), NX_FC_AES, 7178c2ecf20Sopenharmony_ci NX_MODE_AES_CBC); 7188c2ecf20Sopenharmony_ci} 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ciint nx_crypto_ctx_aes_ecb_init(struct crypto_skcipher *tfm) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci return nx_crypto_ctx_init(crypto_skcipher_ctx(tfm), NX_FC_AES, 7238c2ecf20Sopenharmony_ci NX_MODE_AES_ECB); 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ciint nx_crypto_ctx_sha_init(struct crypto_tfm *tfm) 7278c2ecf20Sopenharmony_ci{ 7288c2ecf20Sopenharmony_ci return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_SHA, NX_MODE_SHA); 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ciint nx_crypto_ctx_aes_xcbc_init(struct crypto_tfm *tfm) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES, 7348c2ecf20Sopenharmony_ci NX_MODE_AES_XCBC_MAC); 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci/** 7388c2ecf20Sopenharmony_ci * nx_crypto_ctx_exit - destroy a crypto api context 7398c2ecf20Sopenharmony_ci * 7408c2ecf20Sopenharmony_ci * @tfm: the crypto transform pointer for the context 7418c2ecf20Sopenharmony_ci * 7428c2ecf20Sopenharmony_ci * As crypto API contexts are destroyed, this exit hook is called to free the 7438c2ecf20Sopenharmony_ci * memory associated with it. 7448c2ecf20Sopenharmony_ci */ 7458c2ecf20Sopenharmony_civoid nx_crypto_ctx_exit(struct crypto_tfm *tfm) 7468c2ecf20Sopenharmony_ci{ 7478c2ecf20Sopenharmony_ci struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci kfree_sensitive(nx_ctx->kmem); 7508c2ecf20Sopenharmony_ci nx_ctx->csbcpb = NULL; 7518c2ecf20Sopenharmony_ci nx_ctx->csbcpb_aead = NULL; 7528c2ecf20Sopenharmony_ci nx_ctx->in_sg = NULL; 7538c2ecf20Sopenharmony_ci nx_ctx->out_sg = NULL; 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_civoid nx_crypto_ctx_skcipher_exit(struct crypto_skcipher *tfm) 7578c2ecf20Sopenharmony_ci{ 7588c2ecf20Sopenharmony_ci nx_crypto_ctx_exit(crypto_skcipher_ctx(tfm)); 7598c2ecf20Sopenharmony_ci} 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_civoid nx_crypto_ctx_aead_exit(struct crypto_aead *tfm) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci struct nx_crypto_ctx *nx_ctx = crypto_aead_ctx(tfm); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci kfree_sensitive(nx_ctx->kmem); 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_cistatic int nx_probe(struct vio_dev *viodev, const struct vio_device_id *id) 7698c2ecf20Sopenharmony_ci{ 7708c2ecf20Sopenharmony_ci dev_dbg(&viodev->dev, "driver probed: %s resource id: 0x%x\n", 7718c2ecf20Sopenharmony_ci viodev->name, viodev->resource_id); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci if (nx_driver.viodev) { 7748c2ecf20Sopenharmony_ci dev_err(&viodev->dev, "%s: Attempt to register more than one " 7758c2ecf20Sopenharmony_ci "instance of the hardware\n", __func__); 7768c2ecf20Sopenharmony_ci return -EINVAL; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci nx_driver.viodev = viodev; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci nx_of_init(&viodev->dev, &nx_driver.of); 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci return nx_register_algs(); 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_cistatic int nx_remove(struct vio_dev *viodev) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci dev_dbg(&viodev->dev, "entering nx_remove for UA 0x%x\n", 7898c2ecf20Sopenharmony_ci viodev->unit_address); 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci if (nx_driver.of.status == NX_OKAY) { 7928c2ecf20Sopenharmony_ci NX_DEBUGFS_FINI(&nx_driver); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci nx_unregister_shash(&nx_shash_aes_xcbc_alg, 7958c2ecf20Sopenharmony_ci NX_FC_AES, NX_MODE_AES_XCBC_MAC, -1); 7968c2ecf20Sopenharmony_ci nx_unregister_shash(&nx_shash_sha512_alg, 7978c2ecf20Sopenharmony_ci NX_FC_SHA, NX_MODE_SHA, NX_PROPS_SHA256); 7988c2ecf20Sopenharmony_ci nx_unregister_shash(&nx_shash_sha256_alg, 7998c2ecf20Sopenharmony_ci NX_FC_SHA, NX_MODE_SHA, NX_PROPS_SHA512); 8008c2ecf20Sopenharmony_ci nx_unregister_aead(&nx_ccm4309_aes_alg, 8018c2ecf20Sopenharmony_ci NX_FC_AES, NX_MODE_AES_CCM); 8028c2ecf20Sopenharmony_ci nx_unregister_aead(&nx_ccm_aes_alg, NX_FC_AES, NX_MODE_AES_CCM); 8038c2ecf20Sopenharmony_ci nx_unregister_aead(&nx_gcm4106_aes_alg, 8048c2ecf20Sopenharmony_ci NX_FC_AES, NX_MODE_AES_GCM); 8058c2ecf20Sopenharmony_ci nx_unregister_aead(&nx_gcm_aes_alg, 8068c2ecf20Sopenharmony_ci NX_FC_AES, NX_MODE_AES_GCM); 8078c2ecf20Sopenharmony_ci nx_unregister_skcipher(&nx_ctr3686_aes_alg, 8088c2ecf20Sopenharmony_ci NX_FC_AES, NX_MODE_AES_CTR); 8098c2ecf20Sopenharmony_ci nx_unregister_skcipher(&nx_cbc_aes_alg, NX_FC_AES, 8108c2ecf20Sopenharmony_ci NX_MODE_AES_CBC); 8118c2ecf20Sopenharmony_ci nx_unregister_skcipher(&nx_ecb_aes_alg, NX_FC_AES, 8128c2ecf20Sopenharmony_ci NX_MODE_AES_ECB); 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci return 0; 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci/* module wide initialization/cleanup */ 8208c2ecf20Sopenharmony_cistatic int __init nx_init(void) 8218c2ecf20Sopenharmony_ci{ 8228c2ecf20Sopenharmony_ci return vio_register_driver(&nx_driver.viodriver); 8238c2ecf20Sopenharmony_ci} 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_cistatic void __exit nx_fini(void) 8268c2ecf20Sopenharmony_ci{ 8278c2ecf20Sopenharmony_ci vio_unregister_driver(&nx_driver.viodriver); 8288c2ecf20Sopenharmony_ci} 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_cistatic const struct vio_device_id nx_crypto_driver_ids[] = { 8318c2ecf20Sopenharmony_ci { "ibm,sym-encryption-v1", "ibm,sym-encryption" }, 8328c2ecf20Sopenharmony_ci { "", "" } 8338c2ecf20Sopenharmony_ci}; 8348c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(vio, nx_crypto_driver_ids); 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci/* driver state structure */ 8378c2ecf20Sopenharmony_cistruct nx_crypto_driver nx_driver = { 8388c2ecf20Sopenharmony_ci .viodriver = { 8398c2ecf20Sopenharmony_ci .id_table = nx_crypto_driver_ids, 8408c2ecf20Sopenharmony_ci .probe = nx_probe, 8418c2ecf20Sopenharmony_ci .remove = nx_remove, 8428c2ecf20Sopenharmony_ci .name = NX_NAME, 8438c2ecf20Sopenharmony_ci }, 8448c2ecf20Sopenharmony_ci}; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_cimodule_init(nx_init); 8478c2ecf20Sopenharmony_cimodule_exit(nx_fini); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ciMODULE_AUTHOR("Kent Yoder <yoder1@us.ibm.com>"); 8508c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(NX_STRING); 8518c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 8528c2ecf20Sopenharmony_ciMODULE_VERSION(NX_VERSION); 853