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