162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Routines supporting the Power 7+ Nest Accelerators driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2011-2012 International Business Machines Inc. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Kent Yoder <yoder1@us.ibm.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <crypto/internal/aead.h> 1162306a36Sopenharmony_ci#include <crypto/internal/hash.h> 1262306a36Sopenharmony_ci#include <crypto/aes.h> 1362306a36Sopenharmony_ci#include <crypto/sha2.h> 1462306a36Sopenharmony_ci#include <crypto/algapi.h> 1562306a36Sopenharmony_ci#include <crypto/scatterwalk.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/moduleparam.h> 1862306a36Sopenharmony_ci#include <linux/types.h> 1962306a36Sopenharmony_ci#include <linux/mm.h> 2062306a36Sopenharmony_ci#include <linux/scatterlist.h> 2162306a36Sopenharmony_ci#include <linux/device.h> 2262306a36Sopenharmony_ci#include <linux/of.h> 2362306a36Sopenharmony_ci#include <asm/hvcall.h> 2462306a36Sopenharmony_ci#include <asm/vio.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include "nx_csbcpb.h" 2762306a36Sopenharmony_ci#include "nx.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/** 3162306a36Sopenharmony_ci * nx_hcall_sync - make an H_COP_OP hcall for the passed in op structure 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * @nx_ctx: the crypto context handle 3462306a36Sopenharmony_ci * @op: PFO operation struct to pass in 3562306a36Sopenharmony_ci * @may_sleep: flag indicating the request can sleep 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * Make the hcall, retrying while the hardware is busy. If we cannot yield 3862306a36Sopenharmony_ci * the thread, limit the number of retries to 10 here. 3962306a36Sopenharmony_ci */ 4062306a36Sopenharmony_ciint nx_hcall_sync(struct nx_crypto_ctx *nx_ctx, 4162306a36Sopenharmony_ci struct vio_pfo_op *op, 4262306a36Sopenharmony_ci u32 may_sleep) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci int rc, retries = 10; 4562306a36Sopenharmony_ci struct vio_dev *viodev = nx_driver.viodev; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci atomic_inc(&(nx_ctx->stats->sync_ops)); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci do { 5062306a36Sopenharmony_ci rc = vio_h_cop_sync(viodev, op); 5162306a36Sopenharmony_ci } while (rc == -EBUSY && !may_sleep && retries--); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci if (rc) { 5462306a36Sopenharmony_ci dev_dbg(&viodev->dev, "vio_h_cop_sync failed: rc: %d " 5562306a36Sopenharmony_ci "hcall rc: %ld\n", rc, op->hcall_err); 5662306a36Sopenharmony_ci atomic_inc(&(nx_ctx->stats->errors)); 5762306a36Sopenharmony_ci atomic_set(&(nx_ctx->stats->last_error), op->hcall_err); 5862306a36Sopenharmony_ci atomic_set(&(nx_ctx->stats->last_error_pid), current->pid); 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci return rc; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/** 6562306a36Sopenharmony_ci * nx_build_sg_list - build an NX scatter list describing a single buffer 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci * @sg_head: pointer to the first scatter list element to build 6862306a36Sopenharmony_ci * @start_addr: pointer to the linear buffer 6962306a36Sopenharmony_ci * @len: length of the data at @start_addr 7062306a36Sopenharmony_ci * @sgmax: the largest number of scatter list elements we're allowed to create 7162306a36Sopenharmony_ci * 7262306a36Sopenharmony_ci * This function will start writing nx_sg elements at @sg_head and keep 7362306a36Sopenharmony_ci * writing them until all of the data from @start_addr is described or 7462306a36Sopenharmony_ci * until sgmax elements have been written. Scatter list elements will be 7562306a36Sopenharmony_ci * created such that none of the elements describes a buffer that crosses a 4K 7662306a36Sopenharmony_ci * boundary. 7762306a36Sopenharmony_ci */ 7862306a36Sopenharmony_cistruct nx_sg *nx_build_sg_list(struct nx_sg *sg_head, 7962306a36Sopenharmony_ci u8 *start_addr, 8062306a36Sopenharmony_ci unsigned int *len, 8162306a36Sopenharmony_ci u32 sgmax) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci unsigned int sg_len = 0; 8462306a36Sopenharmony_ci struct nx_sg *sg; 8562306a36Sopenharmony_ci u64 sg_addr = (u64)start_addr; 8662306a36Sopenharmony_ci u64 end_addr; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* determine the start and end for this address range - slightly 8962306a36Sopenharmony_ci * different if this is in VMALLOC_REGION */ 9062306a36Sopenharmony_ci if (is_vmalloc_addr(start_addr)) 9162306a36Sopenharmony_ci sg_addr = page_to_phys(vmalloc_to_page(start_addr)) 9262306a36Sopenharmony_ci + offset_in_page(sg_addr); 9362306a36Sopenharmony_ci else 9462306a36Sopenharmony_ci sg_addr = __pa(sg_addr); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci end_addr = sg_addr + *len; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* each iteration will write one struct nx_sg element and add the 9962306a36Sopenharmony_ci * length of data described by that element to sg_len. Once @len bytes 10062306a36Sopenharmony_ci * have been described (or @sgmax elements have been written), the 10162306a36Sopenharmony_ci * loop ends. min_t is used to ensure @end_addr falls on the same page 10262306a36Sopenharmony_ci * as sg_addr, if not, we need to create another nx_sg element for the 10362306a36Sopenharmony_ci * data on the next page. 10462306a36Sopenharmony_ci * 10562306a36Sopenharmony_ci * Also when using vmalloc'ed data, every time that a system page 10662306a36Sopenharmony_ci * boundary is crossed the physical address needs to be re-calculated. 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_ci for (sg = sg_head; sg_len < *len; sg++) { 10962306a36Sopenharmony_ci u64 next_page; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci sg->addr = sg_addr; 11262306a36Sopenharmony_ci sg_addr = min_t(u64, NX_PAGE_NUM(sg_addr + NX_PAGE_SIZE), 11362306a36Sopenharmony_ci end_addr); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci next_page = (sg->addr & PAGE_MASK) + PAGE_SIZE; 11662306a36Sopenharmony_ci sg->len = min_t(u64, sg_addr, next_page) - sg->addr; 11762306a36Sopenharmony_ci sg_len += sg->len; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci if (sg_addr >= next_page && 12062306a36Sopenharmony_ci is_vmalloc_addr(start_addr + sg_len)) { 12162306a36Sopenharmony_ci sg_addr = page_to_phys(vmalloc_to_page( 12262306a36Sopenharmony_ci start_addr + sg_len)); 12362306a36Sopenharmony_ci end_addr = sg_addr + *len - sg_len; 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if ((sg - sg_head) == sgmax) { 12762306a36Sopenharmony_ci pr_err("nx: scatter/gather list overflow, pid: %d\n", 12862306a36Sopenharmony_ci current->pid); 12962306a36Sopenharmony_ci sg++; 13062306a36Sopenharmony_ci break; 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci *len = sg_len; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /* return the moved sg_head pointer */ 13662306a36Sopenharmony_ci return sg; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/** 14062306a36Sopenharmony_ci * nx_walk_and_build - walk a linux scatterlist and build an nx scatterlist 14162306a36Sopenharmony_ci * 14262306a36Sopenharmony_ci * @nx_dst: pointer to the first nx_sg element to write 14362306a36Sopenharmony_ci * @sglen: max number of nx_sg entries we're allowed to write 14462306a36Sopenharmony_ci * @sg_src: pointer to the source linux scatterlist to walk 14562306a36Sopenharmony_ci * @start: number of bytes to fast-forward past at the beginning of @sg_src 14662306a36Sopenharmony_ci * @src_len: number of bytes to walk in @sg_src 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_cistruct nx_sg *nx_walk_and_build(struct nx_sg *nx_dst, 14962306a36Sopenharmony_ci unsigned int sglen, 15062306a36Sopenharmony_ci struct scatterlist *sg_src, 15162306a36Sopenharmony_ci unsigned int start, 15262306a36Sopenharmony_ci unsigned int *src_len) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct scatter_walk walk; 15562306a36Sopenharmony_ci struct nx_sg *nx_sg = nx_dst; 15662306a36Sopenharmony_ci unsigned int n, offset = 0, len = *src_len; 15762306a36Sopenharmony_ci char *dst; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* we need to fast forward through @start bytes first */ 16062306a36Sopenharmony_ci for (;;) { 16162306a36Sopenharmony_ci scatterwalk_start(&walk, sg_src); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (start < offset + sg_src->length) 16462306a36Sopenharmony_ci break; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci offset += sg_src->length; 16762306a36Sopenharmony_ci sg_src = sg_next(sg_src); 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* start - offset is the number of bytes to advance in the scatterlist 17162306a36Sopenharmony_ci * element we're currently looking at */ 17262306a36Sopenharmony_ci scatterwalk_advance(&walk, start - offset); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci while (len && (nx_sg - nx_dst) < sglen) { 17562306a36Sopenharmony_ci n = scatterwalk_clamp(&walk, len); 17662306a36Sopenharmony_ci if (!n) { 17762306a36Sopenharmony_ci /* In cases where we have scatterlist chain sg_next 17862306a36Sopenharmony_ci * handles with it properly */ 17962306a36Sopenharmony_ci scatterwalk_start(&walk, sg_next(walk.sg)); 18062306a36Sopenharmony_ci n = scatterwalk_clamp(&walk, len); 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci dst = scatterwalk_map(&walk); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci nx_sg = nx_build_sg_list(nx_sg, dst, &n, sglen - (nx_sg - nx_dst)); 18562306a36Sopenharmony_ci len -= n; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci scatterwalk_unmap(dst); 18862306a36Sopenharmony_ci scatterwalk_advance(&walk, n); 18962306a36Sopenharmony_ci scatterwalk_done(&walk, SCATTERWALK_FROM_SG, len); 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci /* update to_process */ 19262306a36Sopenharmony_ci *src_len -= len; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci /* return the moved destination pointer */ 19562306a36Sopenharmony_ci return nx_sg; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci/** 19962306a36Sopenharmony_ci * trim_sg_list - ensures the bound in sg list. 20062306a36Sopenharmony_ci * @sg: sg list head 20162306a36Sopenharmony_ci * @end: sg lisg end 20262306a36Sopenharmony_ci * @delta: is the amount we need to crop in order to bound the list. 20362306a36Sopenharmony_ci * @nbytes: length of data in the scatterlists or data length - whichever 20462306a36Sopenharmony_ci * is greater. 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_cistatic long int trim_sg_list(struct nx_sg *sg, 20762306a36Sopenharmony_ci struct nx_sg *end, 20862306a36Sopenharmony_ci unsigned int delta, 20962306a36Sopenharmony_ci unsigned int *nbytes) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci long int oplen; 21262306a36Sopenharmony_ci long int data_back; 21362306a36Sopenharmony_ci unsigned int is_delta = delta; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci while (delta && end > sg) { 21662306a36Sopenharmony_ci struct nx_sg *last = end - 1; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if (last->len > delta) { 21962306a36Sopenharmony_ci last->len -= delta; 22062306a36Sopenharmony_ci delta = 0; 22162306a36Sopenharmony_ci } else { 22262306a36Sopenharmony_ci end--; 22362306a36Sopenharmony_ci delta -= last->len; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* There are cases where we need to crop list in order to make it 22862306a36Sopenharmony_ci * a block size multiple, but we also need to align data. In order to 22962306a36Sopenharmony_ci * that we need to calculate how much we need to put back to be 23062306a36Sopenharmony_ci * processed 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_ci oplen = (sg - end) * sizeof(struct nx_sg); 23362306a36Sopenharmony_ci if (is_delta) { 23462306a36Sopenharmony_ci data_back = (abs(oplen) / AES_BLOCK_SIZE) * sg->len; 23562306a36Sopenharmony_ci data_back = *nbytes - (data_back & ~(AES_BLOCK_SIZE - 1)); 23662306a36Sopenharmony_ci *nbytes -= data_back; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci return oplen; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/** 24362306a36Sopenharmony_ci * nx_build_sg_lists - walk the input scatterlists and build arrays of NX 24462306a36Sopenharmony_ci * scatterlists based on them. 24562306a36Sopenharmony_ci * 24662306a36Sopenharmony_ci * @nx_ctx: NX crypto context for the lists we're building 24762306a36Sopenharmony_ci * @iv: iv data, if the algorithm requires it 24862306a36Sopenharmony_ci * @dst: destination scatterlist 24962306a36Sopenharmony_ci * @src: source scatterlist 25062306a36Sopenharmony_ci * @nbytes: length of data described in the scatterlists 25162306a36Sopenharmony_ci * @offset: number of bytes to fast-forward past at the beginning of 25262306a36Sopenharmony_ci * scatterlists. 25362306a36Sopenharmony_ci * @oiv: destination for the iv data, if the algorithm requires it 25462306a36Sopenharmony_ci * 25562306a36Sopenharmony_ci * This is common code shared by all the AES algorithms. It uses the crypto 25662306a36Sopenharmony_ci * scatterlist walk routines to traverse input and output scatterlists, building 25762306a36Sopenharmony_ci * corresponding NX scatterlists 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_ciint nx_build_sg_lists(struct nx_crypto_ctx *nx_ctx, 26062306a36Sopenharmony_ci const u8 *iv, 26162306a36Sopenharmony_ci struct scatterlist *dst, 26262306a36Sopenharmony_ci struct scatterlist *src, 26362306a36Sopenharmony_ci unsigned int *nbytes, 26462306a36Sopenharmony_ci unsigned int offset, 26562306a36Sopenharmony_ci u8 *oiv) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci unsigned int delta = 0; 26862306a36Sopenharmony_ci unsigned int total = *nbytes; 26962306a36Sopenharmony_ci struct nx_sg *nx_insg = nx_ctx->in_sg; 27062306a36Sopenharmony_ci struct nx_sg *nx_outsg = nx_ctx->out_sg; 27162306a36Sopenharmony_ci unsigned int max_sg_len; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci max_sg_len = min_t(u64, nx_ctx->ap->sglen, 27462306a36Sopenharmony_ci nx_driver.of.max_sg_len/sizeof(struct nx_sg)); 27562306a36Sopenharmony_ci max_sg_len = min_t(u64, max_sg_len, 27662306a36Sopenharmony_ci nx_ctx->ap->databytelen/NX_PAGE_SIZE); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (oiv) 27962306a36Sopenharmony_ci memcpy(oiv, iv, AES_BLOCK_SIZE); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci *nbytes = min_t(u64, *nbytes, nx_ctx->ap->databytelen); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci nx_outsg = nx_walk_and_build(nx_outsg, max_sg_len, dst, 28462306a36Sopenharmony_ci offset, nbytes); 28562306a36Sopenharmony_ci nx_insg = nx_walk_and_build(nx_insg, max_sg_len, src, 28662306a36Sopenharmony_ci offset, nbytes); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (*nbytes < total) 28962306a36Sopenharmony_ci delta = *nbytes - (*nbytes & ~(AES_BLOCK_SIZE - 1)); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* these lengths should be negative, which will indicate to phyp that 29262306a36Sopenharmony_ci * the input and output parameters are scatterlists, not linear 29362306a36Sopenharmony_ci * buffers */ 29462306a36Sopenharmony_ci nx_ctx->op.inlen = trim_sg_list(nx_ctx->in_sg, nx_insg, delta, nbytes); 29562306a36Sopenharmony_ci nx_ctx->op.outlen = trim_sg_list(nx_ctx->out_sg, nx_outsg, delta, nbytes); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci return 0; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci/** 30162306a36Sopenharmony_ci * nx_ctx_init - initialize an nx_ctx's vio_pfo_op struct 30262306a36Sopenharmony_ci * 30362306a36Sopenharmony_ci * @nx_ctx: the nx context to initialize 30462306a36Sopenharmony_ci * @function: the function code for the op 30562306a36Sopenharmony_ci */ 30662306a36Sopenharmony_civoid nx_ctx_init(struct nx_crypto_ctx *nx_ctx, unsigned int function) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci spin_lock_init(&nx_ctx->lock); 30962306a36Sopenharmony_ci memset(nx_ctx->kmem, 0, nx_ctx->kmem_len); 31062306a36Sopenharmony_ci nx_ctx->csbcpb->csb.valid |= NX_CSB_VALID_BIT; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci nx_ctx->op.flags = function; 31362306a36Sopenharmony_ci nx_ctx->op.csbcpb = __pa(nx_ctx->csbcpb); 31462306a36Sopenharmony_ci nx_ctx->op.in = __pa(nx_ctx->in_sg); 31562306a36Sopenharmony_ci nx_ctx->op.out = __pa(nx_ctx->out_sg); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (nx_ctx->csbcpb_aead) { 31862306a36Sopenharmony_ci nx_ctx->csbcpb_aead->csb.valid |= NX_CSB_VALID_BIT; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci nx_ctx->op_aead.flags = function; 32162306a36Sopenharmony_ci nx_ctx->op_aead.csbcpb = __pa(nx_ctx->csbcpb_aead); 32262306a36Sopenharmony_ci nx_ctx->op_aead.in = __pa(nx_ctx->in_sg); 32362306a36Sopenharmony_ci nx_ctx->op_aead.out = __pa(nx_ctx->out_sg); 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic void nx_of_update_status(struct device *dev, 32862306a36Sopenharmony_ci struct property *p, 32962306a36Sopenharmony_ci struct nx_of *props) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci if (!strncmp(p->value, "okay", p->length)) { 33262306a36Sopenharmony_ci props->status = NX_WAITING; 33362306a36Sopenharmony_ci props->flags |= NX_OF_FLAG_STATUS_SET; 33462306a36Sopenharmony_ci } else { 33562306a36Sopenharmony_ci dev_info(dev, "%s: status '%s' is not 'okay'\n", __func__, 33662306a36Sopenharmony_ci (char *)p->value); 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic void nx_of_update_sglen(struct device *dev, 34162306a36Sopenharmony_ci struct property *p, 34262306a36Sopenharmony_ci struct nx_of *props) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci if (p->length != sizeof(props->max_sg_len)) { 34562306a36Sopenharmony_ci dev_err(dev, "%s: unexpected format for " 34662306a36Sopenharmony_ci "ibm,max-sg-len property\n", __func__); 34762306a36Sopenharmony_ci dev_dbg(dev, "%s: ibm,max-sg-len is %d bytes " 34862306a36Sopenharmony_ci "long, expected %zd bytes\n", __func__, 34962306a36Sopenharmony_ci p->length, sizeof(props->max_sg_len)); 35062306a36Sopenharmony_ci return; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci props->max_sg_len = *(u32 *)p->value; 35462306a36Sopenharmony_ci props->flags |= NX_OF_FLAG_MAXSGLEN_SET; 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic void nx_of_update_msc(struct device *dev, 35862306a36Sopenharmony_ci struct property *p, 35962306a36Sopenharmony_ci struct nx_of *props) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci struct msc_triplet *trip; 36262306a36Sopenharmony_ci struct max_sync_cop *msc; 36362306a36Sopenharmony_ci unsigned int bytes_so_far, i, lenp; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci msc = (struct max_sync_cop *)p->value; 36662306a36Sopenharmony_ci lenp = p->length; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* You can't tell if the data read in for this property is sane by its 36962306a36Sopenharmony_ci * size alone. This is because there are sizes embedded in the data 37062306a36Sopenharmony_ci * structure. The best we can do is check lengths as we parse and bail 37162306a36Sopenharmony_ci * as soon as a length error is detected. */ 37262306a36Sopenharmony_ci bytes_so_far = 0; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci while ((bytes_so_far + sizeof(struct max_sync_cop)) <= lenp) { 37562306a36Sopenharmony_ci bytes_so_far += sizeof(struct max_sync_cop); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci trip = msc->trip; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci for (i = 0; 38062306a36Sopenharmony_ci ((bytes_so_far + sizeof(struct msc_triplet)) <= lenp) && 38162306a36Sopenharmony_ci i < msc->triplets; 38262306a36Sopenharmony_ci i++) { 38362306a36Sopenharmony_ci if (msc->fc >= NX_MAX_FC || msc->mode >= NX_MAX_MODE) { 38462306a36Sopenharmony_ci dev_err(dev, "unknown function code/mode " 38562306a36Sopenharmony_ci "combo: %d/%d (ignored)\n", msc->fc, 38662306a36Sopenharmony_ci msc->mode); 38762306a36Sopenharmony_ci goto next_loop; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (!trip->sglen || trip->databytelen < NX_PAGE_SIZE) { 39162306a36Sopenharmony_ci dev_warn(dev, "bogus sglen/databytelen: " 39262306a36Sopenharmony_ci "%u/%u (ignored)\n", trip->sglen, 39362306a36Sopenharmony_ci trip->databytelen); 39462306a36Sopenharmony_ci goto next_loop; 39562306a36Sopenharmony_ci } 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci switch (trip->keybitlen) { 39862306a36Sopenharmony_ci case 128: 39962306a36Sopenharmony_ci case 160: 40062306a36Sopenharmony_ci props->ap[msc->fc][msc->mode][0].databytelen = 40162306a36Sopenharmony_ci trip->databytelen; 40262306a36Sopenharmony_ci props->ap[msc->fc][msc->mode][0].sglen = 40362306a36Sopenharmony_ci trip->sglen; 40462306a36Sopenharmony_ci break; 40562306a36Sopenharmony_ci case 192: 40662306a36Sopenharmony_ci props->ap[msc->fc][msc->mode][1].databytelen = 40762306a36Sopenharmony_ci trip->databytelen; 40862306a36Sopenharmony_ci props->ap[msc->fc][msc->mode][1].sglen = 40962306a36Sopenharmony_ci trip->sglen; 41062306a36Sopenharmony_ci break; 41162306a36Sopenharmony_ci case 256: 41262306a36Sopenharmony_ci if (msc->fc == NX_FC_AES) { 41362306a36Sopenharmony_ci props->ap[msc->fc][msc->mode][2]. 41462306a36Sopenharmony_ci databytelen = trip->databytelen; 41562306a36Sopenharmony_ci props->ap[msc->fc][msc->mode][2].sglen = 41662306a36Sopenharmony_ci trip->sglen; 41762306a36Sopenharmony_ci } else if (msc->fc == NX_FC_AES_HMAC || 41862306a36Sopenharmony_ci msc->fc == NX_FC_SHA) { 41962306a36Sopenharmony_ci props->ap[msc->fc][msc->mode][1]. 42062306a36Sopenharmony_ci databytelen = trip->databytelen; 42162306a36Sopenharmony_ci props->ap[msc->fc][msc->mode][1].sglen = 42262306a36Sopenharmony_ci trip->sglen; 42362306a36Sopenharmony_ci } else { 42462306a36Sopenharmony_ci dev_warn(dev, "unknown function " 42562306a36Sopenharmony_ci "code/key bit len combo" 42662306a36Sopenharmony_ci ": (%u/256)\n", msc->fc); 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci break; 42962306a36Sopenharmony_ci case 512: 43062306a36Sopenharmony_ci props->ap[msc->fc][msc->mode][2].databytelen = 43162306a36Sopenharmony_ci trip->databytelen; 43262306a36Sopenharmony_ci props->ap[msc->fc][msc->mode][2].sglen = 43362306a36Sopenharmony_ci trip->sglen; 43462306a36Sopenharmony_ci break; 43562306a36Sopenharmony_ci default: 43662306a36Sopenharmony_ci dev_warn(dev, "unknown function code/key bit " 43762306a36Sopenharmony_ci "len combo: (%u/%u)\n", msc->fc, 43862306a36Sopenharmony_ci trip->keybitlen); 43962306a36Sopenharmony_ci break; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_cinext_loop: 44262306a36Sopenharmony_ci bytes_so_far += sizeof(struct msc_triplet); 44362306a36Sopenharmony_ci trip++; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci msc = (struct max_sync_cop *)trip; 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci props->flags |= NX_OF_FLAG_MAXSYNCCOP_SET; 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci/** 45362306a36Sopenharmony_ci * nx_of_init - read openFirmware values from the device tree 45462306a36Sopenharmony_ci * 45562306a36Sopenharmony_ci * @dev: device handle 45662306a36Sopenharmony_ci * @props: pointer to struct to hold the properties values 45762306a36Sopenharmony_ci * 45862306a36Sopenharmony_ci * Called once at driver probe time, this function will read out the 45962306a36Sopenharmony_ci * openFirmware properties we use at runtime. If all the OF properties are 46062306a36Sopenharmony_ci * acceptable, when we exit this function props->flags will indicate that 46162306a36Sopenharmony_ci * we're ready to register our crypto algorithms. 46262306a36Sopenharmony_ci */ 46362306a36Sopenharmony_cistatic void nx_of_init(struct device *dev, struct nx_of *props) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct device_node *base_node = dev->of_node; 46662306a36Sopenharmony_ci struct property *p; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci p = of_find_property(base_node, "status", NULL); 46962306a36Sopenharmony_ci if (!p) 47062306a36Sopenharmony_ci dev_info(dev, "%s: property 'status' not found\n", __func__); 47162306a36Sopenharmony_ci else 47262306a36Sopenharmony_ci nx_of_update_status(dev, p, props); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci p = of_find_property(base_node, "ibm,max-sg-len", NULL); 47562306a36Sopenharmony_ci if (!p) 47662306a36Sopenharmony_ci dev_info(dev, "%s: property 'ibm,max-sg-len' not found\n", 47762306a36Sopenharmony_ci __func__); 47862306a36Sopenharmony_ci else 47962306a36Sopenharmony_ci nx_of_update_sglen(dev, p, props); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci p = of_find_property(base_node, "ibm,max-sync-cop", NULL); 48262306a36Sopenharmony_ci if (!p) 48362306a36Sopenharmony_ci dev_info(dev, "%s: property 'ibm,max-sync-cop' not found\n", 48462306a36Sopenharmony_ci __func__); 48562306a36Sopenharmony_ci else 48662306a36Sopenharmony_ci nx_of_update_msc(dev, p, props); 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic bool nx_check_prop(struct device *dev, u32 fc, u32 mode, int slot) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci struct alg_props *props = &nx_driver.of.ap[fc][mode][slot]; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (!props->sglen || props->databytelen < NX_PAGE_SIZE) { 49462306a36Sopenharmony_ci if (dev) 49562306a36Sopenharmony_ci dev_warn(dev, "bogus sglen/databytelen for %u/%u/%u: " 49662306a36Sopenharmony_ci "%u/%u (ignored)\n", fc, mode, slot, 49762306a36Sopenharmony_ci props->sglen, props->databytelen); 49862306a36Sopenharmony_ci return false; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci return true; 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic bool nx_check_props(struct device *dev, u32 fc, u32 mode) 50562306a36Sopenharmony_ci{ 50662306a36Sopenharmony_ci int i; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci for (i = 0; i < 3; i++) 50962306a36Sopenharmony_ci if (!nx_check_prop(dev, fc, mode, i)) 51062306a36Sopenharmony_ci return false; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci return true; 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_cistatic int nx_register_skcipher(struct skcipher_alg *alg, u32 fc, u32 mode) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci return nx_check_props(&nx_driver.viodev->dev, fc, mode) ? 51862306a36Sopenharmony_ci crypto_register_skcipher(alg) : 0; 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic int nx_register_aead(struct aead_alg *alg, u32 fc, u32 mode) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci return nx_check_props(&nx_driver.viodev->dev, fc, mode) ? 52462306a36Sopenharmony_ci crypto_register_aead(alg) : 0; 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic int nx_register_shash(struct shash_alg *alg, u32 fc, u32 mode, int slot) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci return (slot >= 0 ? nx_check_prop(&nx_driver.viodev->dev, 53062306a36Sopenharmony_ci fc, mode, slot) : 53162306a36Sopenharmony_ci nx_check_props(&nx_driver.viodev->dev, fc, mode)) ? 53262306a36Sopenharmony_ci crypto_register_shash(alg) : 0; 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic void nx_unregister_skcipher(struct skcipher_alg *alg, u32 fc, u32 mode) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci if (nx_check_props(NULL, fc, mode)) 53862306a36Sopenharmony_ci crypto_unregister_skcipher(alg); 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic void nx_unregister_aead(struct aead_alg *alg, u32 fc, u32 mode) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci if (nx_check_props(NULL, fc, mode)) 54462306a36Sopenharmony_ci crypto_unregister_aead(alg); 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic void nx_unregister_shash(struct shash_alg *alg, u32 fc, u32 mode, 54862306a36Sopenharmony_ci int slot) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci if (slot >= 0 ? nx_check_prop(NULL, fc, mode, slot) : 55162306a36Sopenharmony_ci nx_check_props(NULL, fc, mode)) 55262306a36Sopenharmony_ci crypto_unregister_shash(alg); 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci/** 55662306a36Sopenharmony_ci * nx_register_algs - register algorithms with the crypto API 55762306a36Sopenharmony_ci * 55862306a36Sopenharmony_ci * Called from nx_probe() 55962306a36Sopenharmony_ci * 56062306a36Sopenharmony_ci * If all OF properties are in an acceptable state, the driver flags will 56162306a36Sopenharmony_ci * indicate that we're ready and we'll create our debugfs files and register 56262306a36Sopenharmony_ci * out crypto algorithms. 56362306a36Sopenharmony_ci */ 56462306a36Sopenharmony_cistatic int nx_register_algs(void) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci int rc = -1; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if (nx_driver.of.flags != NX_OF_FLAG_MASK_READY) 56962306a36Sopenharmony_ci goto out; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci memset(&nx_driver.stats, 0, sizeof(struct nx_stats)); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci NX_DEBUGFS_INIT(&nx_driver); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci nx_driver.of.status = NX_OKAY; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci rc = nx_register_skcipher(&nx_ecb_aes_alg, NX_FC_AES, NX_MODE_AES_ECB); 57862306a36Sopenharmony_ci if (rc) 57962306a36Sopenharmony_ci goto out; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci rc = nx_register_skcipher(&nx_cbc_aes_alg, NX_FC_AES, NX_MODE_AES_CBC); 58262306a36Sopenharmony_ci if (rc) 58362306a36Sopenharmony_ci goto out_unreg_ecb; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci rc = nx_register_skcipher(&nx_ctr3686_aes_alg, NX_FC_AES, 58662306a36Sopenharmony_ci NX_MODE_AES_CTR); 58762306a36Sopenharmony_ci if (rc) 58862306a36Sopenharmony_ci goto out_unreg_cbc; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci rc = nx_register_aead(&nx_gcm_aes_alg, NX_FC_AES, NX_MODE_AES_GCM); 59162306a36Sopenharmony_ci if (rc) 59262306a36Sopenharmony_ci goto out_unreg_ctr3686; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci rc = nx_register_aead(&nx_gcm4106_aes_alg, NX_FC_AES, NX_MODE_AES_GCM); 59562306a36Sopenharmony_ci if (rc) 59662306a36Sopenharmony_ci goto out_unreg_gcm; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci rc = nx_register_aead(&nx_ccm_aes_alg, NX_FC_AES, NX_MODE_AES_CCM); 59962306a36Sopenharmony_ci if (rc) 60062306a36Sopenharmony_ci goto out_unreg_gcm4106; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci rc = nx_register_aead(&nx_ccm4309_aes_alg, NX_FC_AES, NX_MODE_AES_CCM); 60362306a36Sopenharmony_ci if (rc) 60462306a36Sopenharmony_ci goto out_unreg_ccm; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci rc = nx_register_shash(&nx_shash_sha256_alg, NX_FC_SHA, NX_MODE_SHA, 60762306a36Sopenharmony_ci NX_PROPS_SHA256); 60862306a36Sopenharmony_ci if (rc) 60962306a36Sopenharmony_ci goto out_unreg_ccm4309; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci rc = nx_register_shash(&nx_shash_sha512_alg, NX_FC_SHA, NX_MODE_SHA, 61262306a36Sopenharmony_ci NX_PROPS_SHA512); 61362306a36Sopenharmony_ci if (rc) 61462306a36Sopenharmony_ci goto out_unreg_s256; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci rc = nx_register_shash(&nx_shash_aes_xcbc_alg, 61762306a36Sopenharmony_ci NX_FC_AES, NX_MODE_AES_XCBC_MAC, -1); 61862306a36Sopenharmony_ci if (rc) 61962306a36Sopenharmony_ci goto out_unreg_s512; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci goto out; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ciout_unreg_s512: 62462306a36Sopenharmony_ci nx_unregister_shash(&nx_shash_sha512_alg, NX_FC_SHA, NX_MODE_SHA, 62562306a36Sopenharmony_ci NX_PROPS_SHA512); 62662306a36Sopenharmony_ciout_unreg_s256: 62762306a36Sopenharmony_ci nx_unregister_shash(&nx_shash_sha256_alg, NX_FC_SHA, NX_MODE_SHA, 62862306a36Sopenharmony_ci NX_PROPS_SHA256); 62962306a36Sopenharmony_ciout_unreg_ccm4309: 63062306a36Sopenharmony_ci nx_unregister_aead(&nx_ccm4309_aes_alg, NX_FC_AES, NX_MODE_AES_CCM); 63162306a36Sopenharmony_ciout_unreg_ccm: 63262306a36Sopenharmony_ci nx_unregister_aead(&nx_ccm_aes_alg, NX_FC_AES, NX_MODE_AES_CCM); 63362306a36Sopenharmony_ciout_unreg_gcm4106: 63462306a36Sopenharmony_ci nx_unregister_aead(&nx_gcm4106_aes_alg, NX_FC_AES, NX_MODE_AES_GCM); 63562306a36Sopenharmony_ciout_unreg_gcm: 63662306a36Sopenharmony_ci nx_unregister_aead(&nx_gcm_aes_alg, NX_FC_AES, NX_MODE_AES_GCM); 63762306a36Sopenharmony_ciout_unreg_ctr3686: 63862306a36Sopenharmony_ci nx_unregister_skcipher(&nx_ctr3686_aes_alg, NX_FC_AES, NX_MODE_AES_CTR); 63962306a36Sopenharmony_ciout_unreg_cbc: 64062306a36Sopenharmony_ci nx_unregister_skcipher(&nx_cbc_aes_alg, NX_FC_AES, NX_MODE_AES_CBC); 64162306a36Sopenharmony_ciout_unreg_ecb: 64262306a36Sopenharmony_ci nx_unregister_skcipher(&nx_ecb_aes_alg, NX_FC_AES, NX_MODE_AES_ECB); 64362306a36Sopenharmony_ciout: 64462306a36Sopenharmony_ci return rc; 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci/** 64862306a36Sopenharmony_ci * nx_crypto_ctx_init - create and initialize a crypto api context 64962306a36Sopenharmony_ci * 65062306a36Sopenharmony_ci * @nx_ctx: the crypto api context 65162306a36Sopenharmony_ci * @fc: function code for the context 65262306a36Sopenharmony_ci * @mode: the function code specific mode for this context 65362306a36Sopenharmony_ci */ 65462306a36Sopenharmony_cistatic int nx_crypto_ctx_init(struct nx_crypto_ctx *nx_ctx, u32 fc, u32 mode) 65562306a36Sopenharmony_ci{ 65662306a36Sopenharmony_ci if (nx_driver.of.status != NX_OKAY) { 65762306a36Sopenharmony_ci pr_err("Attempt to initialize NX crypto context while device " 65862306a36Sopenharmony_ci "is not available!\n"); 65962306a36Sopenharmony_ci return -ENODEV; 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci /* we need an extra page for csbcpb_aead for these modes */ 66362306a36Sopenharmony_ci if (mode == NX_MODE_AES_GCM || mode == NX_MODE_AES_CCM) 66462306a36Sopenharmony_ci nx_ctx->kmem_len = (5 * NX_PAGE_SIZE) + 66562306a36Sopenharmony_ci sizeof(struct nx_csbcpb); 66662306a36Sopenharmony_ci else 66762306a36Sopenharmony_ci nx_ctx->kmem_len = (4 * NX_PAGE_SIZE) + 66862306a36Sopenharmony_ci sizeof(struct nx_csbcpb); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci nx_ctx->kmem = kmalloc(nx_ctx->kmem_len, GFP_KERNEL); 67162306a36Sopenharmony_ci if (!nx_ctx->kmem) 67262306a36Sopenharmony_ci return -ENOMEM; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci /* the csbcpb and scatterlists must be 4K aligned pages */ 67562306a36Sopenharmony_ci nx_ctx->csbcpb = (struct nx_csbcpb *)(round_up((u64)nx_ctx->kmem, 67662306a36Sopenharmony_ci (u64)NX_PAGE_SIZE)); 67762306a36Sopenharmony_ci nx_ctx->in_sg = (struct nx_sg *)((u8 *)nx_ctx->csbcpb + NX_PAGE_SIZE); 67862306a36Sopenharmony_ci nx_ctx->out_sg = (struct nx_sg *)((u8 *)nx_ctx->in_sg + NX_PAGE_SIZE); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (mode == NX_MODE_AES_GCM || mode == NX_MODE_AES_CCM) 68162306a36Sopenharmony_ci nx_ctx->csbcpb_aead = 68262306a36Sopenharmony_ci (struct nx_csbcpb *)((u8 *)nx_ctx->out_sg + 68362306a36Sopenharmony_ci NX_PAGE_SIZE); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci /* give each context a pointer to global stats and their OF 68662306a36Sopenharmony_ci * properties */ 68762306a36Sopenharmony_ci nx_ctx->stats = &nx_driver.stats; 68862306a36Sopenharmony_ci memcpy(nx_ctx->props, nx_driver.of.ap[fc][mode], 68962306a36Sopenharmony_ci sizeof(struct alg_props) * 3); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return 0; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci/* entry points from the crypto tfm initializers */ 69562306a36Sopenharmony_ciint nx_crypto_ctx_aes_ccm_init(struct crypto_aead *tfm) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci crypto_aead_set_reqsize(tfm, sizeof(struct nx_ccm_rctx)); 69862306a36Sopenharmony_ci return nx_crypto_ctx_init(crypto_aead_ctx(tfm), NX_FC_AES, 69962306a36Sopenharmony_ci NX_MODE_AES_CCM); 70062306a36Sopenharmony_ci} 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ciint nx_crypto_ctx_aes_gcm_init(struct crypto_aead *tfm) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci crypto_aead_set_reqsize(tfm, sizeof(struct nx_gcm_rctx)); 70562306a36Sopenharmony_ci return nx_crypto_ctx_init(crypto_aead_ctx(tfm), NX_FC_AES, 70662306a36Sopenharmony_ci NX_MODE_AES_GCM); 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ciint nx_crypto_ctx_aes_ctr_init(struct crypto_skcipher *tfm) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci return nx_crypto_ctx_init(crypto_skcipher_ctx(tfm), NX_FC_AES, 71262306a36Sopenharmony_ci NX_MODE_AES_CTR); 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ciint nx_crypto_ctx_aes_cbc_init(struct crypto_skcipher *tfm) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci return nx_crypto_ctx_init(crypto_skcipher_ctx(tfm), NX_FC_AES, 71862306a36Sopenharmony_ci NX_MODE_AES_CBC); 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ciint nx_crypto_ctx_aes_ecb_init(struct crypto_skcipher *tfm) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci return nx_crypto_ctx_init(crypto_skcipher_ctx(tfm), NX_FC_AES, 72462306a36Sopenharmony_ci NX_MODE_AES_ECB); 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ciint nx_crypto_ctx_sha_init(struct crypto_tfm *tfm) 72862306a36Sopenharmony_ci{ 72962306a36Sopenharmony_ci return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_SHA, NX_MODE_SHA); 73062306a36Sopenharmony_ci} 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ciint nx_crypto_ctx_aes_xcbc_init(struct crypto_tfm *tfm) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES, 73562306a36Sopenharmony_ci NX_MODE_AES_XCBC_MAC); 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci/** 73962306a36Sopenharmony_ci * nx_crypto_ctx_exit - destroy a crypto api context 74062306a36Sopenharmony_ci * 74162306a36Sopenharmony_ci * @tfm: the crypto transform pointer for the context 74262306a36Sopenharmony_ci * 74362306a36Sopenharmony_ci * As crypto API contexts are destroyed, this exit hook is called to free the 74462306a36Sopenharmony_ci * memory associated with it. 74562306a36Sopenharmony_ci */ 74662306a36Sopenharmony_civoid nx_crypto_ctx_exit(struct crypto_tfm *tfm) 74762306a36Sopenharmony_ci{ 74862306a36Sopenharmony_ci struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci kfree_sensitive(nx_ctx->kmem); 75162306a36Sopenharmony_ci nx_ctx->csbcpb = NULL; 75262306a36Sopenharmony_ci nx_ctx->csbcpb_aead = NULL; 75362306a36Sopenharmony_ci nx_ctx->in_sg = NULL; 75462306a36Sopenharmony_ci nx_ctx->out_sg = NULL; 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_civoid nx_crypto_ctx_skcipher_exit(struct crypto_skcipher *tfm) 75862306a36Sopenharmony_ci{ 75962306a36Sopenharmony_ci nx_crypto_ctx_exit(crypto_skcipher_ctx(tfm)); 76062306a36Sopenharmony_ci} 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_civoid nx_crypto_ctx_aead_exit(struct crypto_aead *tfm) 76362306a36Sopenharmony_ci{ 76462306a36Sopenharmony_ci struct nx_crypto_ctx *nx_ctx = crypto_aead_ctx(tfm); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci kfree_sensitive(nx_ctx->kmem); 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_cistatic int nx_probe(struct vio_dev *viodev, const struct vio_device_id *id) 77062306a36Sopenharmony_ci{ 77162306a36Sopenharmony_ci dev_dbg(&viodev->dev, "driver probed: %s resource id: 0x%x\n", 77262306a36Sopenharmony_ci viodev->name, viodev->resource_id); 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci if (nx_driver.viodev) { 77562306a36Sopenharmony_ci dev_err(&viodev->dev, "%s: Attempt to register more than one " 77662306a36Sopenharmony_ci "instance of the hardware\n", __func__); 77762306a36Sopenharmony_ci return -EINVAL; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci nx_driver.viodev = viodev; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci nx_of_init(&viodev->dev, &nx_driver.of); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci return nx_register_algs(); 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_cistatic void nx_remove(struct vio_dev *viodev) 78862306a36Sopenharmony_ci{ 78962306a36Sopenharmony_ci dev_dbg(&viodev->dev, "entering nx_remove for UA 0x%x\n", 79062306a36Sopenharmony_ci viodev->unit_address); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci if (nx_driver.of.status == NX_OKAY) { 79362306a36Sopenharmony_ci NX_DEBUGFS_FINI(&nx_driver); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci nx_unregister_shash(&nx_shash_aes_xcbc_alg, 79662306a36Sopenharmony_ci NX_FC_AES, NX_MODE_AES_XCBC_MAC, -1); 79762306a36Sopenharmony_ci nx_unregister_shash(&nx_shash_sha512_alg, 79862306a36Sopenharmony_ci NX_FC_SHA, NX_MODE_SHA, NX_PROPS_SHA256); 79962306a36Sopenharmony_ci nx_unregister_shash(&nx_shash_sha256_alg, 80062306a36Sopenharmony_ci NX_FC_SHA, NX_MODE_SHA, NX_PROPS_SHA512); 80162306a36Sopenharmony_ci nx_unregister_aead(&nx_ccm4309_aes_alg, 80262306a36Sopenharmony_ci NX_FC_AES, NX_MODE_AES_CCM); 80362306a36Sopenharmony_ci nx_unregister_aead(&nx_ccm_aes_alg, NX_FC_AES, NX_MODE_AES_CCM); 80462306a36Sopenharmony_ci nx_unregister_aead(&nx_gcm4106_aes_alg, 80562306a36Sopenharmony_ci NX_FC_AES, NX_MODE_AES_GCM); 80662306a36Sopenharmony_ci nx_unregister_aead(&nx_gcm_aes_alg, 80762306a36Sopenharmony_ci NX_FC_AES, NX_MODE_AES_GCM); 80862306a36Sopenharmony_ci nx_unregister_skcipher(&nx_ctr3686_aes_alg, 80962306a36Sopenharmony_ci NX_FC_AES, NX_MODE_AES_CTR); 81062306a36Sopenharmony_ci nx_unregister_skcipher(&nx_cbc_aes_alg, NX_FC_AES, 81162306a36Sopenharmony_ci NX_MODE_AES_CBC); 81262306a36Sopenharmony_ci nx_unregister_skcipher(&nx_ecb_aes_alg, NX_FC_AES, 81362306a36Sopenharmony_ci NX_MODE_AES_ECB); 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci} 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci/* module wide initialization/cleanup */ 81962306a36Sopenharmony_cistatic int __init nx_init(void) 82062306a36Sopenharmony_ci{ 82162306a36Sopenharmony_ci return vio_register_driver(&nx_driver.viodriver); 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_cistatic void __exit nx_fini(void) 82562306a36Sopenharmony_ci{ 82662306a36Sopenharmony_ci vio_unregister_driver(&nx_driver.viodriver); 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_cistatic const struct vio_device_id nx_crypto_driver_ids[] = { 83062306a36Sopenharmony_ci { "ibm,sym-encryption-v1", "ibm,sym-encryption" }, 83162306a36Sopenharmony_ci { "", "" } 83262306a36Sopenharmony_ci}; 83362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(vio, nx_crypto_driver_ids); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci/* driver state structure */ 83662306a36Sopenharmony_cistruct nx_crypto_driver nx_driver = { 83762306a36Sopenharmony_ci .viodriver = { 83862306a36Sopenharmony_ci .id_table = nx_crypto_driver_ids, 83962306a36Sopenharmony_ci .probe = nx_probe, 84062306a36Sopenharmony_ci .remove = nx_remove, 84162306a36Sopenharmony_ci .name = NX_NAME, 84262306a36Sopenharmony_ci }, 84362306a36Sopenharmony_ci}; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_cimodule_init(nx_init); 84662306a36Sopenharmony_cimodule_exit(nx_fini); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ciMODULE_AUTHOR("Kent Yoder <yoder1@us.ibm.com>"); 84962306a36Sopenharmony_ciMODULE_DESCRIPTION(NX_STRING); 85062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 85162306a36Sopenharmony_ciMODULE_VERSION(NX_VERSION); 852