1fbf31dd5STom Zanussi // SPDX-License-Identifier: GPL-2.0-only
2fbf31dd5STom Zanussi /*
3fbf31dd5STom Zanussi  * Intel Keem Bay OCS ECC Crypto Driver.
4fbf31dd5STom Zanussi  *
5fbf31dd5STom Zanussi  * Copyright (C) 2019-2021 Intel Corporation
6fbf31dd5STom Zanussi  */
7fbf31dd5STom Zanussi 
8fbf31dd5STom Zanussi #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9fbf31dd5STom Zanussi 
10530d7b00SHerbert Xu #include <crypto/ecc_curve.h>
11530d7b00SHerbert Xu #include <crypto/ecdh.h>
12530d7b00SHerbert Xu #include <crypto/engine.h>
13530d7b00SHerbert Xu #include <crypto/internal/ecc.h>
14530d7b00SHerbert Xu #include <crypto/internal/kpp.h>
15530d7b00SHerbert Xu #include <crypto/kpp.h>
16530d7b00SHerbert Xu #include <crypto/rng.h>
17fbf31dd5STom Zanussi #include <linux/clk.h>
18fbf31dd5STom Zanussi #include <linux/completion.h>
19530d7b00SHerbert Xu #include <linux/err.h>
20fbf31dd5STom Zanussi #include <linux/fips.h>
21fbf31dd5STom Zanussi #include <linux/interrupt.h>
22fbf31dd5STom Zanussi #include <linux/io.h>
23fbf31dd5STom Zanussi #include <linux/iopoll.h>
24fbf31dd5STom Zanussi #include <linux/irq.h>
25530d7b00SHerbert Xu #include <linux/kernel.h>
26fbf31dd5STom Zanussi #include <linux/module.h>
27fbf31dd5STom Zanussi #include <linux/of.h>
28fbf31dd5STom Zanussi #include <linux/platform_device.h>
29fbf31dd5STom Zanussi #include <linux/scatterlist.h>
30530d7b00SHerbert Xu #include <linux/string.h>
31fbf31dd5STom Zanussi 
32fbf31dd5STom Zanussi #define DRV_NAME			"keembay-ocs-ecc"
33fbf31dd5STom Zanussi 
34fbf31dd5STom Zanussi #define KMB_OCS_ECC_PRIORITY		350
35fbf31dd5STom Zanussi 
36fbf31dd5STom Zanussi #define HW_OFFS_OCS_ECC_COMMAND		0x00000000
37fbf31dd5STom Zanussi #define HW_OFFS_OCS_ECC_STATUS		0x00000004
38fbf31dd5STom Zanussi #define HW_OFFS_OCS_ECC_DATA_IN		0x00000080
39fbf31dd5STom Zanussi #define HW_OFFS_OCS_ECC_CX_DATA_OUT	0x00000100
40fbf31dd5STom Zanussi #define HW_OFFS_OCS_ECC_CY_DATA_OUT	0x00000180
41fbf31dd5STom Zanussi #define HW_OFFS_OCS_ECC_ISR		0x00000400
42fbf31dd5STom Zanussi #define HW_OFFS_OCS_ECC_IER		0x00000404
43fbf31dd5STom Zanussi 
44fbf31dd5STom Zanussi #define HW_OCS_ECC_ISR_INT_STATUS_DONE	BIT(0)
45fbf31dd5STom Zanussi #define HW_OCS_ECC_COMMAND_INS_BP	BIT(0)
46fbf31dd5STom Zanussi 
47fbf31dd5STom Zanussi #define HW_OCS_ECC_COMMAND_START_VAL	BIT(0)
48fbf31dd5STom Zanussi 
49fbf31dd5STom Zanussi #define OCS_ECC_OP_SIZE_384		BIT(8)
50fbf31dd5STom Zanussi #define OCS_ECC_OP_SIZE_256		0
51fbf31dd5STom Zanussi 
52fbf31dd5STom Zanussi /* ECC Instruction : for ECC_COMMAND */
53fbf31dd5STom Zanussi #define OCS_ECC_INST_WRITE_AX		(0x1 << HW_OCS_ECC_COMMAND_INS_BP)
54fbf31dd5STom Zanussi #define OCS_ECC_INST_WRITE_AY		(0x2 << HW_OCS_ECC_COMMAND_INS_BP)
55fbf31dd5STom Zanussi #define OCS_ECC_INST_WRITE_BX_D		(0x3 << HW_OCS_ECC_COMMAND_INS_BP)
56fbf31dd5STom Zanussi #define OCS_ECC_INST_WRITE_BY_L		(0x4 << HW_OCS_ECC_COMMAND_INS_BP)
57fbf31dd5STom Zanussi #define OCS_ECC_INST_WRITE_P		(0x5 << HW_OCS_ECC_COMMAND_INS_BP)
58fbf31dd5STom Zanussi #define OCS_ECC_INST_WRITE_A		(0x6 << HW_OCS_ECC_COMMAND_INS_BP)
59fbf31dd5STom Zanussi #define OCS_ECC_INST_CALC_D_IDX_A	(0x8 << HW_OCS_ECC_COMMAND_INS_BP)
60fbf31dd5STom Zanussi #define OCS_ECC_INST_CALC_A_POW_B_MODP	(0xB << HW_OCS_ECC_COMMAND_INS_BP)
61fbf31dd5STom Zanussi #define OCS_ECC_INST_CALC_A_MUL_B_MODP	(0xC  << HW_OCS_ECC_COMMAND_INS_BP)
62fbf31dd5STom Zanussi #define OCS_ECC_INST_CALC_A_ADD_B_MODP	(0xD << HW_OCS_ECC_COMMAND_INS_BP)
63fbf31dd5STom Zanussi 
64fbf31dd5STom Zanussi #define ECC_ENABLE_INTR			1
65fbf31dd5STom Zanussi 
66fbf31dd5STom Zanussi #define POLL_USEC			100
67fbf31dd5STom Zanussi #define TIMEOUT_USEC			10000
68fbf31dd5STom Zanussi 
69fbf31dd5STom Zanussi #define KMB_ECC_VLI_MAX_DIGITS		ECC_CURVE_NIST_P384_DIGITS
70fbf31dd5STom Zanussi #define KMB_ECC_VLI_MAX_BYTES		(KMB_ECC_VLI_MAX_DIGITS \
71fbf31dd5STom Zanussi 					 << ECC_DIGITS_TO_BYTES_SHIFT)
72fbf31dd5STom Zanussi 
73fbf31dd5STom Zanussi #define POW_CUBE			3
74fbf31dd5STom Zanussi 
75fbf31dd5STom Zanussi /**
76fbf31dd5STom Zanussi  * struct ocs_ecc_dev - ECC device context
77fbf31dd5STom Zanussi  * @list: List of device contexts
78fbf31dd5STom Zanussi  * @dev: OCS ECC device
79fbf31dd5STom Zanussi  * @base_reg: IO base address of OCS ECC
80fbf31dd5STom Zanussi  * @engine: Crypto engine for the device
81fbf31dd5STom Zanussi  * @irq_done: IRQ done completion.
82fbf31dd5STom Zanussi  * @irq: IRQ number
83fbf31dd5STom Zanussi  */
84fbf31dd5STom Zanussi struct ocs_ecc_dev {
85fbf31dd5STom Zanussi 	struct list_head list;
86fbf31dd5STom Zanussi 	struct device *dev;
87fbf31dd5STom Zanussi 	void __iomem *base_reg;
88fbf31dd5STom Zanussi 	struct crypto_engine *engine;
89fbf31dd5STom Zanussi 	struct completion irq_done;
90fbf31dd5STom Zanussi 	int irq;
91fbf31dd5STom Zanussi };
92fbf31dd5STom Zanussi 
93fbf31dd5STom Zanussi /**
94fbf31dd5STom Zanussi  * struct ocs_ecc_ctx - Transformation context.
95fbf31dd5STom Zanussi  * @ecc_dev:	 The ECC driver associated with this context.
96fbf31dd5STom Zanussi  * @curve:	 The elliptic curve used by this transformation.
97fbf31dd5STom Zanussi  * @private_key: The private key.
98fbf31dd5STom Zanussi  */
99fbf31dd5STom Zanussi struct ocs_ecc_ctx {
100fbf31dd5STom Zanussi 	struct ocs_ecc_dev *ecc_dev;
101fbf31dd5STom Zanussi 	const struct ecc_curve *curve;
102fbf31dd5STom Zanussi 	u64 private_key[KMB_ECC_VLI_MAX_DIGITS];
103fbf31dd5STom Zanussi };
104fbf31dd5STom Zanussi 
105fbf31dd5STom Zanussi /* Driver data. */
106fbf31dd5STom Zanussi struct ocs_ecc_drv {
107fbf31dd5STom Zanussi 	struct list_head dev_list;
108fbf31dd5STom Zanussi 	spinlock_t lock;	/* Protects dev_list. */
109fbf31dd5STom Zanussi };
110fbf31dd5STom Zanussi 
111fbf31dd5STom Zanussi /* Global variable holding the list of OCS ECC devices (only one expected). */
112fbf31dd5STom Zanussi static struct ocs_ecc_drv ocs_ecc = {
113fbf31dd5STom Zanussi 	.dev_list = LIST_HEAD_INIT(ocs_ecc.dev_list),
114fbf31dd5STom Zanussi 	.lock = __SPIN_LOCK_UNLOCKED(ocs_ecc.lock),
115fbf31dd5STom Zanussi };
116fbf31dd5STom Zanussi 
117fbf31dd5STom Zanussi /* Get OCS ECC tfm context from kpp_request. */
kmb_ocs_ecc_tctx(struct kpp_request * req)118fbf31dd5STom Zanussi static inline struct ocs_ecc_ctx *kmb_ocs_ecc_tctx(struct kpp_request *req)
119fbf31dd5STom Zanussi {
120fbf31dd5STom Zanussi 	return kpp_tfm_ctx(crypto_kpp_reqtfm(req));
121fbf31dd5STom Zanussi }
122fbf31dd5STom Zanussi 
123fbf31dd5STom Zanussi /* Converts number of digits to number of bytes. */
digits_to_bytes(unsigned int n)124fbf31dd5STom Zanussi static inline unsigned int digits_to_bytes(unsigned int n)
125fbf31dd5STom Zanussi {
126fbf31dd5STom Zanussi 	return n << ECC_DIGITS_TO_BYTES_SHIFT;
127fbf31dd5STom Zanussi }
128fbf31dd5STom Zanussi 
129fbf31dd5STom Zanussi /*
130fbf31dd5STom Zanussi  * Wait for ECC idle i.e when an operation (other than write operations)
131fbf31dd5STom Zanussi  * is done.
132fbf31dd5STom Zanussi  */
ocs_ecc_wait_idle(struct ocs_ecc_dev * dev)133fbf31dd5STom Zanussi static inline int ocs_ecc_wait_idle(struct ocs_ecc_dev *dev)
134fbf31dd5STom Zanussi {
135fbf31dd5STom Zanussi 	u32 value;
136fbf31dd5STom Zanussi 
137fbf31dd5STom Zanussi 	return readl_poll_timeout((dev->base_reg + HW_OFFS_OCS_ECC_STATUS),
138fbf31dd5STom Zanussi 				  value,
139fbf31dd5STom Zanussi 				  !(value & HW_OCS_ECC_ISR_INT_STATUS_DONE),
140fbf31dd5STom Zanussi 				  POLL_USEC, TIMEOUT_USEC);
141fbf31dd5STom Zanussi }
142fbf31dd5STom Zanussi 
ocs_ecc_cmd_start(struct ocs_ecc_dev * ecc_dev,u32 op_size)143fbf31dd5STom Zanussi static void ocs_ecc_cmd_start(struct ocs_ecc_dev *ecc_dev, u32 op_size)
144fbf31dd5STom Zanussi {
145fbf31dd5STom Zanussi 	iowrite32(op_size | HW_OCS_ECC_COMMAND_START_VAL,
146fbf31dd5STom Zanussi 		  ecc_dev->base_reg + HW_OFFS_OCS_ECC_COMMAND);
147fbf31dd5STom Zanussi }
148fbf31dd5STom Zanussi 
149fbf31dd5STom Zanussi /* Direct write of u32 buffer to ECC engine with associated instruction. */
ocs_ecc_write_cmd_and_data(struct ocs_ecc_dev * dev,u32 op_size,u32 inst,const void * data_in,size_t data_size)150fbf31dd5STom Zanussi static void ocs_ecc_write_cmd_and_data(struct ocs_ecc_dev *dev,
151fbf31dd5STom Zanussi 				       u32 op_size,
152fbf31dd5STom Zanussi 				       u32 inst,
153fbf31dd5STom Zanussi 				       const void *data_in,
154fbf31dd5STom Zanussi 				       size_t data_size)
155fbf31dd5STom Zanussi {
156fbf31dd5STom Zanussi 	iowrite32(op_size | inst, dev->base_reg + HW_OFFS_OCS_ECC_COMMAND);
157fbf31dd5STom Zanussi 
158fbf31dd5STom Zanussi 	/* MMIO Write src uint32 to dst. */
159fbf31dd5STom Zanussi 	memcpy_toio(dev->base_reg + HW_OFFS_OCS_ECC_DATA_IN, data_in,
160fbf31dd5STom Zanussi 		    data_size);
161fbf31dd5STom Zanussi }
162fbf31dd5STom Zanussi 
163fbf31dd5STom Zanussi /* Start OCS ECC operation and wait for its completion. */
ocs_ecc_trigger_op(struct ocs_ecc_dev * ecc_dev,u32 op_size,u32 inst)164fbf31dd5STom Zanussi static int ocs_ecc_trigger_op(struct ocs_ecc_dev *ecc_dev, u32 op_size,
165fbf31dd5STom Zanussi 			      u32 inst)
166fbf31dd5STom Zanussi {
167fbf31dd5STom Zanussi 	reinit_completion(&ecc_dev->irq_done);
168fbf31dd5STom Zanussi 
169fbf31dd5STom Zanussi 	iowrite32(ECC_ENABLE_INTR, ecc_dev->base_reg + HW_OFFS_OCS_ECC_IER);
170fbf31dd5STom Zanussi 	iowrite32(op_size | inst, ecc_dev->base_reg + HW_OFFS_OCS_ECC_COMMAND);
171fbf31dd5STom Zanussi 
172fbf31dd5STom Zanussi 	return wait_for_completion_interruptible(&ecc_dev->irq_done);
173fbf31dd5STom Zanussi }
174fbf31dd5STom Zanussi 
175fbf31dd5STom Zanussi /**
176fbf31dd5STom Zanussi  * ocs_ecc_read_cx_out() - Read the CX data output buffer.
177fbf31dd5STom Zanussi  * @dev:	The OCS ECC device to read from.
178fbf31dd5STom Zanussi  * @cx_out:	The buffer where to store the CX value. Must be at least
179fbf31dd5STom Zanussi  *		@byte_count byte long.
180fbf31dd5STom Zanussi  * @byte_count:	The amount of data to read.
181fbf31dd5STom Zanussi  */
ocs_ecc_read_cx_out(struct ocs_ecc_dev * dev,void * cx_out,size_t byte_count)182fbf31dd5STom Zanussi static inline void ocs_ecc_read_cx_out(struct ocs_ecc_dev *dev, void *cx_out,
183fbf31dd5STom Zanussi 				       size_t byte_count)
184fbf31dd5STom Zanussi {
185fbf31dd5STom Zanussi 	memcpy_fromio(cx_out, dev->base_reg + HW_OFFS_OCS_ECC_CX_DATA_OUT,
186fbf31dd5STom Zanussi 		      byte_count);
187fbf31dd5STom Zanussi }
188fbf31dd5STom Zanussi 
189fbf31dd5STom Zanussi /**
190fbf31dd5STom Zanussi  * ocs_ecc_read_cy_out() - Read the CX data output buffer.
191fbf31dd5STom Zanussi  * @dev:	The OCS ECC device to read from.
192fbf31dd5STom Zanussi  * @cy_out:	The buffer where to store the CY value. Must be at least
193fbf31dd5STom Zanussi  *		@byte_count byte long.
194fbf31dd5STom Zanussi  * @byte_count:	The amount of data to read.
195fbf31dd5STom Zanussi  */
ocs_ecc_read_cy_out(struct ocs_ecc_dev * dev,void * cy_out,size_t byte_count)196fbf31dd5STom Zanussi static inline void ocs_ecc_read_cy_out(struct ocs_ecc_dev *dev, void *cy_out,
197fbf31dd5STom Zanussi 				       size_t byte_count)
198fbf31dd5STom Zanussi {
199fbf31dd5STom Zanussi 	memcpy_fromio(cy_out, dev->base_reg + HW_OFFS_OCS_ECC_CY_DATA_OUT,
200fbf31dd5STom Zanussi 		      byte_count);
201fbf31dd5STom Zanussi }
202fbf31dd5STom Zanussi 
kmb_ocs_ecc_find_dev(struct ocs_ecc_ctx * tctx)203fbf31dd5STom Zanussi static struct ocs_ecc_dev *kmb_ocs_ecc_find_dev(struct ocs_ecc_ctx *tctx)
204fbf31dd5STom Zanussi {
205fbf31dd5STom Zanussi 	if (tctx->ecc_dev)
206fbf31dd5STom Zanussi 		return tctx->ecc_dev;
207fbf31dd5STom Zanussi 
208fbf31dd5STom Zanussi 	spin_lock(&ocs_ecc.lock);
209fbf31dd5STom Zanussi 
210fbf31dd5STom Zanussi 	/* Only a single OCS device available. */
211fbf31dd5STom Zanussi 	tctx->ecc_dev = list_first_entry(&ocs_ecc.dev_list, struct ocs_ecc_dev,
212fbf31dd5STom Zanussi 					 list);
213fbf31dd5STom Zanussi 
214fbf31dd5STom Zanussi 	spin_unlock(&ocs_ecc.lock);
215fbf31dd5STom Zanussi 
216fbf31dd5STom Zanussi 	return tctx->ecc_dev;
217fbf31dd5STom Zanussi }
218fbf31dd5STom Zanussi 
219fbf31dd5STom Zanussi /* Do point multiplication using OCS ECC HW. */
kmb_ecc_point_mult(struct ocs_ecc_dev * ecc_dev,struct ecc_point * result,const struct ecc_point * point,u64 * scalar,const struct ecc_curve * curve)220fbf31dd5STom Zanussi static int kmb_ecc_point_mult(struct ocs_ecc_dev *ecc_dev,
221fbf31dd5STom Zanussi 			      struct ecc_point *result,
222fbf31dd5STom Zanussi 			      const struct ecc_point *point,
223fbf31dd5STom Zanussi 			      u64 *scalar,
224fbf31dd5STom Zanussi 			      const struct ecc_curve *curve)
225fbf31dd5STom Zanussi {
226fbf31dd5STom Zanussi 	u8 sca[KMB_ECC_VLI_MAX_BYTES]; /* Use the maximum data size. */
227fbf31dd5STom Zanussi 	u32 op_size = (curve->g.ndigits > ECC_CURVE_NIST_P256_DIGITS) ?
228fbf31dd5STom Zanussi 		      OCS_ECC_OP_SIZE_384 : OCS_ECC_OP_SIZE_256;
229fbf31dd5STom Zanussi 	size_t nbytes = digits_to_bytes(curve->g.ndigits);
230fbf31dd5STom Zanussi 	int rc = 0;
231fbf31dd5STom Zanussi 
232fbf31dd5STom Zanussi 	/* Generate random nbytes for Simple and Differential SCA protection. */
233fbf31dd5STom Zanussi 	rc = crypto_get_default_rng();
234fbf31dd5STom Zanussi 	if (rc)
235fbf31dd5STom Zanussi 		return rc;
236fbf31dd5STom Zanussi 
237fbf31dd5STom Zanussi 	rc = crypto_rng_get_bytes(crypto_default_rng, sca, nbytes);
238fbf31dd5STom Zanussi 	crypto_put_default_rng();
239fbf31dd5STom Zanussi 	if (rc)
240fbf31dd5STom Zanussi 		return rc;
241fbf31dd5STom Zanussi 
242fbf31dd5STom Zanussi 	/* Wait engine to be idle before starting new operation. */
243fbf31dd5STom Zanussi 	rc = ocs_ecc_wait_idle(ecc_dev);
244fbf31dd5STom Zanussi 	if (rc)
245fbf31dd5STom Zanussi 		return rc;
246fbf31dd5STom Zanussi 
247fbf31dd5STom Zanussi 	/* Send ecc_start pulse as well as indicating operation size. */
248fbf31dd5STom Zanussi 	ocs_ecc_cmd_start(ecc_dev, op_size);
249fbf31dd5STom Zanussi 
250fbf31dd5STom Zanussi 	/* Write ax param; Base point (Gx). */
251fbf31dd5STom Zanussi 	ocs_ecc_write_cmd_and_data(ecc_dev, op_size, OCS_ECC_INST_WRITE_AX,
252fbf31dd5STom Zanussi 				   point->x, nbytes);
253fbf31dd5STom Zanussi 
254fbf31dd5STom Zanussi 	/* Write ay param; Base point (Gy). */
255fbf31dd5STom Zanussi 	ocs_ecc_write_cmd_and_data(ecc_dev, op_size, OCS_ECC_INST_WRITE_AY,
256fbf31dd5STom Zanussi 				   point->y, nbytes);
257fbf31dd5STom Zanussi 
258fbf31dd5STom Zanussi 	/*
259fbf31dd5STom Zanussi 	 * Write the private key into DATA_IN reg.
260fbf31dd5STom Zanussi 	 *
261fbf31dd5STom Zanussi 	 * Since DATA_IN register is used to write different values during the
262fbf31dd5STom Zanussi 	 * computation private Key value is overwritten with
263fbf31dd5STom Zanussi 	 * side-channel-resistance value.
264fbf31dd5STom Zanussi 	 */
265fbf31dd5STom Zanussi 	ocs_ecc_write_cmd_and_data(ecc_dev, op_size, OCS_ECC_INST_WRITE_BX_D,
266fbf31dd5STom Zanussi 				   scalar, nbytes);
267fbf31dd5STom Zanussi 
268fbf31dd5STom Zanussi 	/* Write operand by/l. */
269fbf31dd5STom Zanussi 	ocs_ecc_write_cmd_and_data(ecc_dev, op_size, OCS_ECC_INST_WRITE_BY_L,
270fbf31dd5STom Zanussi 				   sca, nbytes);
271fbf31dd5STom Zanussi 	memzero_explicit(sca, sizeof(sca));
272fbf31dd5STom Zanussi 
273fbf31dd5STom Zanussi 	/* Write p = curve prime(GF modulus). */
274fbf31dd5STom Zanussi 	ocs_ecc_write_cmd_and_data(ecc_dev, op_size, OCS_ECC_INST_WRITE_P,
275fbf31dd5STom Zanussi 				   curve->p, nbytes);
276fbf31dd5STom Zanussi 
277fbf31dd5STom Zanussi 	/* Write a = curve coefficient. */
278fbf31dd5STom Zanussi 	ocs_ecc_write_cmd_and_data(ecc_dev, op_size, OCS_ECC_INST_WRITE_A,
279fbf31dd5STom Zanussi 				   curve->a, nbytes);
280fbf31dd5STom Zanussi 
281fbf31dd5STom Zanussi 	/* Make hardware perform the multiplication. */
282fbf31dd5STom Zanussi 	rc = ocs_ecc_trigger_op(ecc_dev, op_size, OCS_ECC_INST_CALC_D_IDX_A);
283fbf31dd5STom Zanussi 	if (rc)
284fbf31dd5STom Zanussi 		return rc;
285fbf31dd5STom Zanussi 
286fbf31dd5STom Zanussi 	/* Read result. */
287fbf31dd5STom Zanussi 	ocs_ecc_read_cx_out(ecc_dev, result->x, nbytes);
288fbf31dd5STom Zanussi 	ocs_ecc_read_cy_out(ecc_dev, result->y, nbytes);
289fbf31dd5STom Zanussi 
290fbf31dd5STom Zanussi 	return 0;
291fbf31dd5STom Zanussi }
292fbf31dd5STom Zanussi 
293fbf31dd5STom Zanussi /**
294fbf31dd5STom Zanussi  * kmb_ecc_do_scalar_op() - Perform Scalar operation using OCS ECC HW.
295fbf31dd5STom Zanussi  * @ecc_dev:	The OCS ECC device to use.
296fbf31dd5STom Zanussi  * @scalar_out:	Where to store the output scalar.
297fbf31dd5STom Zanussi  * @scalar_a:	Input scalar operand 'a'.
298fbf31dd5STom Zanussi  * @scalar_b:	Input scalar operand 'b'
299fbf31dd5STom Zanussi  * @curve:	The curve on which the operation is performed.
300fbf31dd5STom Zanussi  * @ndigits:	The size of the operands (in digits).
301fbf31dd5STom Zanussi  * @inst:	The operation to perform (as an OCS ECC instruction).
302fbf31dd5STom Zanussi  *
303fbf31dd5STom Zanussi  * Return:	0 on success, negative error code otherwise.
304fbf31dd5STom Zanussi  */
kmb_ecc_do_scalar_op(struct ocs_ecc_dev * ecc_dev,u64 * scalar_out,const u64 * scalar_a,const u64 * scalar_b,const struct ecc_curve * curve,unsigned int ndigits,const u32 inst)305fbf31dd5STom Zanussi static int kmb_ecc_do_scalar_op(struct ocs_ecc_dev *ecc_dev, u64 *scalar_out,
306fbf31dd5STom Zanussi 				const u64 *scalar_a, const u64 *scalar_b,
307fbf31dd5STom Zanussi 				const struct ecc_curve *curve,
308fbf31dd5STom Zanussi 				unsigned int ndigits, const u32 inst)
309fbf31dd5STom Zanussi {
310fbf31dd5STom Zanussi 	u32 op_size = (ndigits > ECC_CURVE_NIST_P256_DIGITS) ?
311fbf31dd5STom Zanussi 		      OCS_ECC_OP_SIZE_384 : OCS_ECC_OP_SIZE_256;
312fbf31dd5STom Zanussi 	size_t nbytes = digits_to_bytes(ndigits);
313fbf31dd5STom Zanussi 	int rc;
314fbf31dd5STom Zanussi 
315fbf31dd5STom Zanussi 	/* Wait engine to be idle before starting new operation. */
316fbf31dd5STom Zanussi 	rc = ocs_ecc_wait_idle(ecc_dev);
317fbf31dd5STom Zanussi 	if (rc)
318fbf31dd5STom Zanussi 		return rc;
319fbf31dd5STom Zanussi 
320fbf31dd5STom Zanussi 	/* Send ecc_start pulse as well as indicating operation size. */
321fbf31dd5STom Zanussi 	ocs_ecc_cmd_start(ecc_dev, op_size);
322fbf31dd5STom Zanussi 
323fbf31dd5STom Zanussi 	/* Write ax param (Base point (Gx).*/
324fbf31dd5STom Zanussi 	ocs_ecc_write_cmd_and_data(ecc_dev, op_size, OCS_ECC_INST_WRITE_AX,
325fbf31dd5STom Zanussi 				   scalar_a, nbytes);
326fbf31dd5STom Zanussi 
327fbf31dd5STom Zanussi 	/* Write ay param Base point (Gy).*/
328fbf31dd5STom Zanussi 	ocs_ecc_write_cmd_and_data(ecc_dev, op_size, OCS_ECC_INST_WRITE_AY,
329fbf31dd5STom Zanussi 				   scalar_b, nbytes);
330fbf31dd5STom Zanussi 
331fbf31dd5STom Zanussi 	/* Write p = curve prime(GF modulus).*/
332fbf31dd5STom Zanussi 	ocs_ecc_write_cmd_and_data(ecc_dev, op_size, OCS_ECC_INST_WRITE_P,
333fbf31dd5STom Zanussi 				   curve->p, nbytes);
334fbf31dd5STom Zanussi 
335fbf31dd5STom Zanussi 	/* Give instruction A.B or A+B to ECC engine. */
336fbf31dd5STom Zanussi 	rc = ocs_ecc_trigger_op(ecc_dev, op_size, inst);
337fbf31dd5STom Zanussi 	if (rc)
338fbf31dd5STom Zanussi 		return rc;
339fbf31dd5STom Zanussi 
340fbf31dd5STom Zanussi 	ocs_ecc_read_cx_out(ecc_dev, scalar_out, nbytes);
341fbf31dd5STom Zanussi 
342fbf31dd5STom Zanussi 	if (vli_is_zero(scalar_out, ndigits))
343fbf31dd5STom Zanussi 		return -EINVAL;
344fbf31dd5STom Zanussi 
345fbf31dd5STom Zanussi 	return 0;
346fbf31dd5STom Zanussi }
347fbf31dd5STom Zanussi 
348fbf31dd5STom Zanussi /* SP800-56A section 5.6.2.3.4 partial verification: ephemeral keys only */
kmb_ocs_ecc_is_pubkey_valid_partial(struct ocs_ecc_dev * ecc_dev,const struct ecc_curve * curve,struct ecc_point * pk)349fbf31dd5STom Zanussi static int kmb_ocs_ecc_is_pubkey_valid_partial(struct ocs_ecc_dev *ecc_dev,
350fbf31dd5STom Zanussi 					       const struct ecc_curve *curve,
351fbf31dd5STom Zanussi 					       struct ecc_point *pk)
352fbf31dd5STom Zanussi {
353fbf31dd5STom Zanussi 	u64 xxx[KMB_ECC_VLI_MAX_DIGITS] = { 0 };
354fbf31dd5STom Zanussi 	u64 yy[KMB_ECC_VLI_MAX_DIGITS] = { 0 };
355fbf31dd5STom Zanussi 	u64 w[KMB_ECC_VLI_MAX_DIGITS] = { 0 };
356fbf31dd5STom Zanussi 	int rc;
357fbf31dd5STom Zanussi 
358fbf31dd5STom Zanussi 	if (WARN_ON(pk->ndigits != curve->g.ndigits))
359fbf31dd5STom Zanussi 		return -EINVAL;
360fbf31dd5STom Zanussi 
361fbf31dd5STom Zanussi 	/* Check 1: Verify key is not the zero point. */
362fbf31dd5STom Zanussi 	if (ecc_point_is_zero(pk))
363fbf31dd5STom Zanussi 		return -EINVAL;
364fbf31dd5STom Zanussi 
365fbf31dd5STom Zanussi 	/* Check 2: Verify key is in the range [0, p-1]. */
366fbf31dd5STom Zanussi 	if (vli_cmp(curve->p, pk->x, pk->ndigits) != 1)
367fbf31dd5STom Zanussi 		return -EINVAL;
368fbf31dd5STom Zanussi 
369fbf31dd5STom Zanussi 	if (vli_cmp(curve->p, pk->y, pk->ndigits) != 1)
370fbf31dd5STom Zanussi 		return -EINVAL;
371fbf31dd5STom Zanussi 
372fbf31dd5STom Zanussi 	/* Check 3: Verify that y^2 == (x^3 + a·x + b) mod p */
373fbf31dd5STom Zanussi 
374fbf31dd5STom Zanussi 	 /* y^2 */
375fbf31dd5STom Zanussi 	/* Compute y^2 -> store in yy */
376fbf31dd5STom Zanussi 	rc = kmb_ecc_do_scalar_op(ecc_dev, yy, pk->y, pk->y, curve, pk->ndigits,
377fbf31dd5STom Zanussi 				  OCS_ECC_INST_CALC_A_MUL_B_MODP);
378fbf31dd5STom Zanussi 	if (rc)
379fbf31dd5STom Zanussi 		goto exit;
380fbf31dd5STom Zanussi 
381fbf31dd5STom Zanussi 	/* x^3 */
382fbf31dd5STom Zanussi 	/* Assigning w = 3, used for calculating x^3. */
383fbf31dd5STom Zanussi 	w[0] = POW_CUBE;
384fbf31dd5STom Zanussi 	/* Load the next stage.*/
385fbf31dd5STom Zanussi 	rc = kmb_ecc_do_scalar_op(ecc_dev, xxx, pk->x, w, curve, pk->ndigits,
386fbf31dd5STom Zanussi 				  OCS_ECC_INST_CALC_A_POW_B_MODP);
387fbf31dd5STom Zanussi 	if (rc)
388fbf31dd5STom Zanussi 		goto exit;
389fbf31dd5STom Zanussi 
390fbf31dd5STom Zanussi 	/* Do a*x -> store in w. */
391fbf31dd5STom Zanussi 	rc = kmb_ecc_do_scalar_op(ecc_dev, w, curve->a, pk->x, curve,
392fbf31dd5STom Zanussi 				  pk->ndigits,
393fbf31dd5STom Zanussi 				  OCS_ECC_INST_CALC_A_MUL_B_MODP);
394fbf31dd5STom Zanussi 	if (rc)
395fbf31dd5STom Zanussi 		goto exit;
396fbf31dd5STom Zanussi 
397fbf31dd5STom Zanussi 	/* Do ax + b == w + b; store in w. */
398fbf31dd5STom Zanussi 	rc = kmb_ecc_do_scalar_op(ecc_dev, w, w, curve->b, curve,
399fbf31dd5STom Zanussi 				  pk->ndigits,
400fbf31dd5STom Zanussi 				  OCS_ECC_INST_CALC_A_ADD_B_MODP);
401fbf31dd5STom Zanussi 	if (rc)
402fbf31dd5STom Zanussi 		goto exit;
403fbf31dd5STom Zanussi 
404fbf31dd5STom Zanussi 	/* x^3 + ax + b == x^3 + w -> store in w. */
405fbf31dd5STom Zanussi 	rc = kmb_ecc_do_scalar_op(ecc_dev, w, xxx, w, curve, pk->ndigits,
406fbf31dd5STom Zanussi 				  OCS_ECC_INST_CALC_A_ADD_B_MODP);
407fbf31dd5STom Zanussi 	if (rc)
408fbf31dd5STom Zanussi 		goto exit;
409fbf31dd5STom Zanussi 
410fbf31dd5STom Zanussi 	/* Compare y^2 == x^3 + a·x + b. */
411fbf31dd5STom Zanussi 	rc = vli_cmp(yy, w, pk->ndigits);
412fbf31dd5STom Zanussi 	if (rc)
413fbf31dd5STom Zanussi 		rc = -EINVAL;
414fbf31dd5STom Zanussi 
415fbf31dd5STom Zanussi exit:
416fbf31dd5STom Zanussi 	memzero_explicit(xxx, sizeof(xxx));
417fbf31dd5STom Zanussi 	memzero_explicit(yy, sizeof(yy));
418fbf31dd5STom Zanussi 	memzero_explicit(w, sizeof(w));
419fbf31dd5STom Zanussi 
420fbf31dd5STom Zanussi 	return rc;
421fbf31dd5STom Zanussi }
422fbf31dd5STom Zanussi 
423fbf31dd5STom Zanussi /* SP800-56A section 5.6.2.3.3 full verification */
kmb_ocs_ecc_is_pubkey_valid_full(struct ocs_ecc_dev * ecc_dev,const struct ecc_curve * curve,struct ecc_point * pk)424fbf31dd5STom Zanussi static int kmb_ocs_ecc_is_pubkey_valid_full(struct ocs_ecc_dev *ecc_dev,
425fbf31dd5STom Zanussi 					    const struct ecc_curve *curve,
426fbf31dd5STom Zanussi 					    struct ecc_point *pk)
427fbf31dd5STom Zanussi {
428fbf31dd5STom Zanussi 	struct ecc_point *nQ;
429fbf31dd5STom Zanussi 	int rc;
430fbf31dd5STom Zanussi 
431fbf31dd5STom Zanussi 	/* Checks 1 through 3 */
432fbf31dd5STom Zanussi 	rc = kmb_ocs_ecc_is_pubkey_valid_partial(ecc_dev, curve, pk);
433fbf31dd5STom Zanussi 	if (rc)
434fbf31dd5STom Zanussi 		return rc;
435fbf31dd5STom Zanussi 
436fbf31dd5STom Zanussi 	/* Check 4: Verify that nQ is the zero point. */
437fbf31dd5STom Zanussi 	nQ = ecc_alloc_point(pk->ndigits);
438fbf31dd5STom Zanussi 	if (!nQ)
439fbf31dd5STom Zanussi 		return -ENOMEM;
440fbf31dd5STom Zanussi 
441fbf31dd5STom Zanussi 	rc = kmb_ecc_point_mult(ecc_dev, nQ, pk, curve->n, curve);
442fbf31dd5STom Zanussi 	if (rc)
443fbf31dd5STom Zanussi 		goto exit;
444fbf31dd5STom Zanussi 
445fbf31dd5STom Zanussi 	if (!ecc_point_is_zero(nQ))
446fbf31dd5STom Zanussi 		rc = -EINVAL;
447fbf31dd5STom Zanussi 
448fbf31dd5STom Zanussi exit:
449fbf31dd5STom Zanussi 	ecc_free_point(nQ);
450fbf31dd5STom Zanussi 
451fbf31dd5STom Zanussi 	return rc;
452fbf31dd5STom Zanussi }
453fbf31dd5STom Zanussi 
kmb_ecc_is_key_valid(const struct ecc_curve * curve,const u64 * private_key,size_t private_key_len)454fbf31dd5STom Zanussi static int kmb_ecc_is_key_valid(const struct ecc_curve *curve,
455fbf31dd5STom Zanussi 				const u64 *private_key, size_t private_key_len)
456fbf31dd5STom Zanussi {
457fbf31dd5STom Zanussi 	size_t ndigits = curve->g.ndigits;
458fbf31dd5STom Zanussi 	u64 one[KMB_ECC_VLI_MAX_DIGITS] = {1};
459fbf31dd5STom Zanussi 	u64 res[KMB_ECC_VLI_MAX_DIGITS];
460fbf31dd5STom Zanussi 
461fbf31dd5STom Zanussi 	if (private_key_len != digits_to_bytes(ndigits))
462fbf31dd5STom Zanussi 		return -EINVAL;
463fbf31dd5STom Zanussi 
464fbf31dd5STom Zanussi 	if (!private_key)
465fbf31dd5STom Zanussi 		return -EINVAL;
466fbf31dd5STom Zanussi 
467fbf31dd5STom Zanussi 	/* Make sure the private key is in the range [2, n-3]. */
468fbf31dd5STom Zanussi 	if (vli_cmp(one, private_key, ndigits) != -1)
469fbf31dd5STom Zanussi 		return -EINVAL;
470fbf31dd5STom Zanussi 
471fbf31dd5STom Zanussi 	vli_sub(res, curve->n, one, ndigits);
472fbf31dd5STom Zanussi 	vli_sub(res, res, one, ndigits);
473fbf31dd5STom Zanussi 	if (vli_cmp(res, private_key, ndigits) != 1)
474fbf31dd5STom Zanussi 		return -EINVAL;
475fbf31dd5STom Zanussi 
476fbf31dd5STom Zanussi 	return 0;
477fbf31dd5STom Zanussi }
478fbf31dd5STom Zanussi 
479fbf31dd5STom Zanussi /*
480fbf31dd5STom Zanussi  * ECC private keys are generated using the method of extra random bits,
481fbf31dd5STom Zanussi  * equivalent to that described in FIPS 186-4, Appendix B.4.1.
482fbf31dd5STom Zanussi  *
483fbf31dd5STom Zanussi  * d = (c mod(n–1)) + 1    where c is a string of random bits, 64 bits longer
484fbf31dd5STom Zanussi  *                         than requested
485fbf31dd5STom Zanussi  * 0 <= c mod(n-1) <= n-2  and implies that
486fbf31dd5STom Zanussi  * 1 <= d <= n-1
487fbf31dd5STom Zanussi  *
488fbf31dd5STom Zanussi  * This method generates a private key uniformly distributed in the range
489fbf31dd5STom Zanussi  * [1, n-1].
490fbf31dd5STom Zanussi  */
kmb_ecc_gen_privkey(const struct ecc_curve * curve,u64 * privkey)491fbf31dd5STom Zanussi static int kmb_ecc_gen_privkey(const struct ecc_curve *curve, u64 *privkey)
492fbf31dd5STom Zanussi {
493fbf31dd5STom Zanussi 	size_t nbytes = digits_to_bytes(curve->g.ndigits);
494fbf31dd5STom Zanussi 	u64 priv[KMB_ECC_VLI_MAX_DIGITS];
495fbf31dd5STom Zanussi 	size_t nbits;
496fbf31dd5STom Zanussi 	int rc;
497fbf31dd5STom Zanussi 
498fbf31dd5STom Zanussi 	nbits = vli_num_bits(curve->n, curve->g.ndigits);
499fbf31dd5STom Zanussi 
500fbf31dd5STom Zanussi 	/* Check that N is included in Table 1 of FIPS 186-4, section 6.1.1 */
501fbf31dd5STom Zanussi 	if (nbits < 160 || curve->g.ndigits > ARRAY_SIZE(priv))
502fbf31dd5STom Zanussi 		return -EINVAL;
503fbf31dd5STom Zanussi 
504fbf31dd5STom Zanussi 	/*
505fbf31dd5STom Zanussi 	 * FIPS 186-4 recommends that the private key should be obtained from a
506fbf31dd5STom Zanussi 	 * RBG with a security strength equal to or greater than the security
507fbf31dd5STom Zanussi 	 * strength associated with N.
508fbf31dd5STom Zanussi 	 *
509fbf31dd5STom Zanussi 	 * The maximum security strength identified by NIST SP800-57pt1r4 for
510fbf31dd5STom Zanussi 	 * ECC is 256 (N >= 512).
511fbf31dd5STom Zanussi 	 *
512fbf31dd5STom Zanussi 	 * This condition is met by the default RNG because it selects a favored
513fbf31dd5STom Zanussi 	 * DRBG with a security strength of 256.
514fbf31dd5STom Zanussi 	 */
515fbf31dd5STom Zanussi 	if (crypto_get_default_rng())
516fbf31dd5STom Zanussi 		return -EFAULT;
517fbf31dd5STom Zanussi 
518fbf31dd5STom Zanussi 	rc = crypto_rng_get_bytes(crypto_default_rng, (u8 *)priv, nbytes);
519fbf31dd5STom Zanussi 	crypto_put_default_rng();
520fbf31dd5STom Zanussi 	if (rc)
521fbf31dd5STom Zanussi 		goto cleanup;
522fbf31dd5STom Zanussi 
523fbf31dd5STom Zanussi 	rc = kmb_ecc_is_key_valid(curve, priv, nbytes);
524fbf31dd5STom Zanussi 	if (rc)
525fbf31dd5STom Zanussi 		goto cleanup;
526fbf31dd5STom Zanussi 
527fbf31dd5STom Zanussi 	ecc_swap_digits(priv, privkey, curve->g.ndigits);
528fbf31dd5STom Zanussi 
529fbf31dd5STom Zanussi cleanup:
530fbf31dd5STom Zanussi 	memzero_explicit(&priv, sizeof(priv));
531fbf31dd5STom Zanussi 
532fbf31dd5STom Zanussi 	return rc;
533fbf31dd5STom Zanussi }
534fbf31dd5STom Zanussi 
kmb_ocs_ecdh_set_secret(struct crypto_kpp * tfm,const void * buf,unsigned int len)535fbf31dd5STom Zanussi static int kmb_ocs_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
536fbf31dd5STom Zanussi 				   unsigned int len)
537fbf31dd5STom Zanussi {
538fbf31dd5STom Zanussi 	struct ocs_ecc_ctx *tctx = kpp_tfm_ctx(tfm);
539fbf31dd5STom Zanussi 	struct ecdh params;
540fbf31dd5STom Zanussi 	int rc = 0;
541fbf31dd5STom Zanussi 
542fbf31dd5STom Zanussi 	rc = crypto_ecdh_decode_key(buf, len, &params);
543fbf31dd5STom Zanussi 	if (rc)
544fbf31dd5STom Zanussi 		goto cleanup;
545fbf31dd5STom Zanussi 
546fbf31dd5STom Zanussi 	/* Ensure key size is not bigger then expected. */
547fbf31dd5STom Zanussi 	if (params.key_size > digits_to_bytes(tctx->curve->g.ndigits)) {
548fbf31dd5STom Zanussi 		rc = -EINVAL;
549fbf31dd5STom Zanussi 		goto cleanup;
550fbf31dd5STom Zanussi 	}
551fbf31dd5STom Zanussi 
552fbf31dd5STom Zanussi 	/* Auto-generate private key is not provided. */
553fbf31dd5STom Zanussi 	if (!params.key || !params.key_size) {
554fbf31dd5STom Zanussi 		rc = kmb_ecc_gen_privkey(tctx->curve, tctx->private_key);
555fbf31dd5STom Zanussi 		goto cleanup;
556fbf31dd5STom Zanussi 	}
557fbf31dd5STom Zanussi 
558fbf31dd5STom Zanussi 	rc = kmb_ecc_is_key_valid(tctx->curve, (const u64 *)params.key,
559fbf31dd5STom Zanussi 				  params.key_size);
560fbf31dd5STom Zanussi 	if (rc)
561fbf31dd5STom Zanussi 		goto cleanup;
562fbf31dd5STom Zanussi 
563fbf31dd5STom Zanussi 	ecc_swap_digits((const u64 *)params.key, tctx->private_key,
564fbf31dd5STom Zanussi 			tctx->curve->g.ndigits);
565fbf31dd5STom Zanussi cleanup:
566fbf31dd5STom Zanussi 	memzero_explicit(&params, sizeof(params));
567fbf31dd5STom Zanussi 
568fbf31dd5STom Zanussi 	if (rc)
569fbf31dd5STom Zanussi 		tctx->curve = NULL;
570fbf31dd5STom Zanussi 
571fbf31dd5STom Zanussi 	return rc;
572fbf31dd5STom Zanussi }
573fbf31dd5STom Zanussi 
574fbf31dd5STom Zanussi /* Compute shared secret. */
kmb_ecc_do_shared_secret(struct ocs_ecc_ctx * tctx,struct kpp_request * req)575fbf31dd5STom Zanussi static int kmb_ecc_do_shared_secret(struct ocs_ecc_ctx *tctx,
576fbf31dd5STom Zanussi 				    struct kpp_request *req)
577fbf31dd5STom Zanussi {
578fbf31dd5STom Zanussi 	struct ocs_ecc_dev *ecc_dev = tctx->ecc_dev;
579fbf31dd5STom Zanussi 	const struct ecc_curve *curve = tctx->curve;
580fbf31dd5STom Zanussi 	u64 shared_secret[KMB_ECC_VLI_MAX_DIGITS];
581fbf31dd5STom Zanussi 	u64 pubk_buf[KMB_ECC_VLI_MAX_DIGITS * 2];
582fbf31dd5STom Zanussi 	size_t copied, nbytes, pubk_len;
583fbf31dd5STom Zanussi 	struct ecc_point *pk, *result;
584fbf31dd5STom Zanussi 	int rc;
585fbf31dd5STom Zanussi 
586fbf31dd5STom Zanussi 	nbytes = digits_to_bytes(curve->g.ndigits);
587fbf31dd5STom Zanussi 
588fbf31dd5STom Zanussi 	/* Public key is a point, thus it has two coordinates */
589fbf31dd5STom Zanussi 	pubk_len = 2 * nbytes;
590fbf31dd5STom Zanussi 
591fbf31dd5STom Zanussi 	/* Copy public key from SG list to pubk_buf. */
592fbf31dd5STom Zanussi 	copied = sg_copy_to_buffer(req->src,
593fbf31dd5STom Zanussi 				   sg_nents_for_len(req->src, pubk_len),
594fbf31dd5STom Zanussi 				   pubk_buf, pubk_len);
595fbf31dd5STom Zanussi 	if (copied != pubk_len)
596fbf31dd5STom Zanussi 		return -EINVAL;
597fbf31dd5STom Zanussi 
598fbf31dd5STom Zanussi 	/* Allocate and initialize public key point. */
599fbf31dd5STom Zanussi 	pk = ecc_alloc_point(curve->g.ndigits);
600fbf31dd5STom Zanussi 	if (!pk)
601fbf31dd5STom Zanussi 		return -ENOMEM;
602fbf31dd5STom Zanussi 
603fbf31dd5STom Zanussi 	ecc_swap_digits(pubk_buf, pk->x, curve->g.ndigits);
604fbf31dd5STom Zanussi 	ecc_swap_digits(&pubk_buf[curve->g.ndigits], pk->y, curve->g.ndigits);
605fbf31dd5STom Zanussi 
606fbf31dd5STom Zanussi 	/*
607fbf31dd5STom Zanussi 	 * Check the public key for following
608fbf31dd5STom Zanussi 	 * Check 1: Verify key is not the zero point.
609fbf31dd5STom Zanussi 	 * Check 2: Verify key is in the range [1, p-1].
610fbf31dd5STom Zanussi 	 * Check 3: Verify that y^2 == (x^3 + a·x + b) mod p
611fbf31dd5STom Zanussi 	 */
612fbf31dd5STom Zanussi 	rc = kmb_ocs_ecc_is_pubkey_valid_partial(ecc_dev, curve, pk);
613fbf31dd5STom Zanussi 	if (rc)
614fbf31dd5STom Zanussi 		goto exit_free_pk;
615fbf31dd5STom Zanussi 
616fbf31dd5STom Zanussi 	/* Allocate point for storing computed shared secret. */
617fbf31dd5STom Zanussi 	result = ecc_alloc_point(pk->ndigits);
618fbf31dd5STom Zanussi 	if (!result) {
619fbf31dd5STom Zanussi 		rc = -ENOMEM;
620fbf31dd5STom Zanussi 		goto exit_free_pk;
621fbf31dd5STom Zanussi 	}
622fbf31dd5STom Zanussi 
623fbf31dd5STom Zanussi 	/* Calculate the shared secret.*/
624fbf31dd5STom Zanussi 	rc = kmb_ecc_point_mult(ecc_dev, result, pk, tctx->private_key, curve);
625fbf31dd5STom Zanussi 	if (rc)
626fbf31dd5STom Zanussi 		goto exit_free_result;
627fbf31dd5STom Zanussi 
628fbf31dd5STom Zanussi 	if (ecc_point_is_zero(result)) {
629fbf31dd5STom Zanussi 		rc = -EFAULT;
630fbf31dd5STom Zanussi 		goto exit_free_result;
631fbf31dd5STom Zanussi 	}
632fbf31dd5STom Zanussi 
633fbf31dd5STom Zanussi 	/* Copy shared secret from point to buffer. */
634fbf31dd5STom Zanussi 	ecc_swap_digits(result->x, shared_secret, result->ndigits);
635fbf31dd5STom Zanussi 
636fbf31dd5STom Zanussi 	/* Request might ask for less bytes than what we have. */
637fbf31dd5STom Zanussi 	nbytes = min_t(size_t, nbytes, req->dst_len);
638fbf31dd5STom Zanussi 
639fbf31dd5STom Zanussi 	copied = sg_copy_from_buffer(req->dst,
640fbf31dd5STom Zanussi 				     sg_nents_for_len(req->dst, nbytes),
641fbf31dd5STom Zanussi 				     shared_secret, nbytes);
642fbf31dd5STom Zanussi 
643fbf31dd5STom Zanussi 	if (copied != nbytes)
644fbf31dd5STom Zanussi 		rc = -EINVAL;
645fbf31dd5STom Zanussi 
646fbf31dd5STom Zanussi 	memzero_explicit(shared_secret, sizeof(shared_secret));
647fbf31dd5STom Zanussi 
648fbf31dd5STom Zanussi exit_free_result:
649fbf31dd5STom Zanussi 	ecc_free_point(result);
650fbf31dd5STom Zanussi 
651fbf31dd5STom Zanussi exit_free_pk:
652fbf31dd5STom Zanussi 	ecc_free_point(pk);
653fbf31dd5STom Zanussi 
654fbf31dd5STom Zanussi 	return rc;
655fbf31dd5STom Zanussi }
656fbf31dd5STom Zanussi 
657fbf31dd5STom Zanussi /* Compute public key. */
kmb_ecc_do_public_key(struct ocs_ecc_ctx * tctx,struct kpp_request * req)658fbf31dd5STom Zanussi static int kmb_ecc_do_public_key(struct ocs_ecc_ctx *tctx,
659fbf31dd5STom Zanussi 				 struct kpp_request *req)
660fbf31dd5STom Zanussi {
661fbf31dd5STom Zanussi 	const struct ecc_curve *curve = tctx->curve;
662fbf31dd5STom Zanussi 	u64 pubk_buf[KMB_ECC_VLI_MAX_DIGITS * 2];
663fbf31dd5STom Zanussi 	struct ecc_point *pk;
664fbf31dd5STom Zanussi 	size_t pubk_len;
665fbf31dd5STom Zanussi 	size_t copied;
666fbf31dd5STom Zanussi 	int rc;
667fbf31dd5STom Zanussi 
668fbf31dd5STom Zanussi 	/* Public key is a point, so it has double the digits. */
669fbf31dd5STom Zanussi 	pubk_len = 2 * digits_to_bytes(curve->g.ndigits);
670fbf31dd5STom Zanussi 
671fbf31dd5STom Zanussi 	pk = ecc_alloc_point(curve->g.ndigits);
672fbf31dd5STom Zanussi 	if (!pk)
673fbf31dd5STom Zanussi 		return -ENOMEM;
674fbf31dd5STom Zanussi 
675fbf31dd5STom Zanussi 	/* Public Key(pk) = priv * G. */
676fbf31dd5STom Zanussi 	rc = kmb_ecc_point_mult(tctx->ecc_dev, pk, &curve->g, tctx->private_key,
677fbf31dd5STom Zanussi 				curve);
678fbf31dd5STom Zanussi 	if (rc)
679fbf31dd5STom Zanussi 		goto exit;
680fbf31dd5STom Zanussi 
681fbf31dd5STom Zanussi 	/* SP800-56A rev 3 5.6.2.1.3 key check */
682fbf31dd5STom Zanussi 	if (kmb_ocs_ecc_is_pubkey_valid_full(tctx->ecc_dev, curve, pk)) {
683fbf31dd5STom Zanussi 		rc = -EAGAIN;
684fbf31dd5STom Zanussi 		goto exit;
685fbf31dd5STom Zanussi 	}
686fbf31dd5STom Zanussi 
687fbf31dd5STom Zanussi 	/* Copy public key from point to buffer. */
688fbf31dd5STom Zanussi 	ecc_swap_digits(pk->x, pubk_buf, pk->ndigits);
689fbf31dd5STom Zanussi 	ecc_swap_digits(pk->y, &pubk_buf[pk->ndigits], pk->ndigits);
690fbf31dd5STom Zanussi 
691fbf31dd5STom Zanussi 	/* Copy public key to req->dst. */
692fbf31dd5STom Zanussi 	copied = sg_copy_from_buffer(req->dst,
693fbf31dd5STom Zanussi 				     sg_nents_for_len(req->dst, pubk_len),
694fbf31dd5STom Zanussi 				     pubk_buf, pubk_len);
695fbf31dd5STom Zanussi 
696fbf31dd5STom Zanussi 	if (copied != pubk_len)
697fbf31dd5STom Zanussi 		rc = -EINVAL;
698fbf31dd5STom Zanussi 
699fbf31dd5STom Zanussi exit:
700fbf31dd5STom Zanussi 	ecc_free_point(pk);
701fbf31dd5STom Zanussi 
702fbf31dd5STom Zanussi 	return rc;
703fbf31dd5STom Zanussi }
704fbf31dd5STom Zanussi 
kmb_ocs_ecc_do_one_request(struct crypto_engine * engine,void * areq)705fbf31dd5STom Zanussi static int kmb_ocs_ecc_do_one_request(struct crypto_engine *engine,
706fbf31dd5STom Zanussi 				      void *areq)
707fbf31dd5STom Zanussi {
708fbf31dd5STom Zanussi 	struct kpp_request *req = container_of(areq, struct kpp_request, base);
709fbf31dd5STom Zanussi 	struct ocs_ecc_ctx *tctx = kmb_ocs_ecc_tctx(req);
710fbf31dd5STom Zanussi 	struct ocs_ecc_dev *ecc_dev = tctx->ecc_dev;
711fbf31dd5STom Zanussi 	int rc;
712fbf31dd5STom Zanussi 
713fbf31dd5STom Zanussi 	if (req->src)
714fbf31dd5STom Zanussi 		rc = kmb_ecc_do_shared_secret(tctx, req);
715fbf31dd5STom Zanussi 	else
716fbf31dd5STom Zanussi 		rc = kmb_ecc_do_public_key(tctx, req);
717fbf31dd5STom Zanussi 
718fbf31dd5STom Zanussi 	crypto_finalize_kpp_request(ecc_dev->engine, req, rc);
719fbf31dd5STom Zanussi 
720fbf31dd5STom Zanussi 	return 0;
721fbf31dd5STom Zanussi }
722fbf31dd5STom Zanussi 
kmb_ocs_ecdh_generate_public_key(struct kpp_request * req)723fbf31dd5STom Zanussi static int kmb_ocs_ecdh_generate_public_key(struct kpp_request *req)
724fbf31dd5STom Zanussi {
725fbf31dd5STom Zanussi 	struct ocs_ecc_ctx *tctx = kmb_ocs_ecc_tctx(req);
726fbf31dd5STom Zanussi 	const struct ecc_curve *curve = tctx->curve;
727fbf31dd5STom Zanussi 
728fbf31dd5STom Zanussi 	/* Ensure kmb_ocs_ecdh_set_secret() has been successfully called. */
729fbf31dd5STom Zanussi 	if (!tctx->curve)
730fbf31dd5STom Zanussi 		return -EINVAL;
731fbf31dd5STom Zanussi 
732fbf31dd5STom Zanussi 	/* Ensure dst is present. */
733fbf31dd5STom Zanussi 	if (!req->dst)
734fbf31dd5STom Zanussi 		return -EINVAL;
735fbf31dd5STom Zanussi 
736fbf31dd5STom Zanussi 	/* Check the request dst is big enough to hold the public key. */
737fbf31dd5STom Zanussi 	if (req->dst_len < (2 * digits_to_bytes(curve->g.ndigits)))
738fbf31dd5STom Zanussi 		return -EINVAL;
739fbf31dd5STom Zanussi 
740fbf31dd5STom Zanussi 	/* 'src' is not supposed to be present when generate pubk is called. */
741fbf31dd5STom Zanussi 	if (req->src)
742fbf31dd5STom Zanussi 		return -EINVAL;
743fbf31dd5STom Zanussi 
744fbf31dd5STom Zanussi 	return crypto_transfer_kpp_request_to_engine(tctx->ecc_dev->engine,
745fbf31dd5STom Zanussi 						     req);
746fbf31dd5STom Zanussi }
747fbf31dd5STom Zanussi 
kmb_ocs_ecdh_compute_shared_secret(struct kpp_request * req)748fbf31dd5STom Zanussi static int kmb_ocs_ecdh_compute_shared_secret(struct kpp_request *req)
749fbf31dd5STom Zanussi {
750fbf31dd5STom Zanussi 	struct ocs_ecc_ctx *tctx = kmb_ocs_ecc_tctx(req);
751fbf31dd5STom Zanussi 	const struct ecc_curve *curve = tctx->curve;
752fbf31dd5STom Zanussi 
753fbf31dd5STom Zanussi 	/* Ensure kmb_ocs_ecdh_set_secret() has been successfully called. */
754fbf31dd5STom Zanussi 	if (!tctx->curve)
755fbf31dd5STom Zanussi 		return -EINVAL;
756fbf31dd5STom Zanussi 
757fbf31dd5STom Zanussi 	/* Ensure dst is present. */
758fbf31dd5STom Zanussi 	if (!req->dst)
759fbf31dd5STom Zanussi 		return -EINVAL;
760fbf31dd5STom Zanussi 
761fbf31dd5STom Zanussi 	/* Ensure src is present. */
762fbf31dd5STom Zanussi 	if (!req->src)
763fbf31dd5STom Zanussi 		return -EINVAL;
764fbf31dd5STom Zanussi 
765fbf31dd5STom Zanussi 	/*
766fbf31dd5STom Zanussi 	 * req->src is expected to the (other-side) public key, so its length
767fbf31dd5STom Zanussi 	 * must be 2 * coordinate size (in bytes).
768fbf31dd5STom Zanussi 	 */
769fbf31dd5STom Zanussi 	if (req->src_len != 2 * digits_to_bytes(curve->g.ndigits))
770fbf31dd5STom Zanussi 		return -EINVAL;
771fbf31dd5STom Zanussi 
772fbf31dd5STom Zanussi 	return crypto_transfer_kpp_request_to_engine(tctx->ecc_dev->engine,
773fbf31dd5STom Zanussi 						     req);
774fbf31dd5STom Zanussi }
775fbf31dd5STom Zanussi 
kmb_ecc_tctx_init(struct ocs_ecc_ctx * tctx,unsigned int curve_id)776fbf31dd5STom Zanussi static int kmb_ecc_tctx_init(struct ocs_ecc_ctx *tctx, unsigned int curve_id)
777fbf31dd5STom Zanussi {
778fbf31dd5STom Zanussi 	memset(tctx, 0, sizeof(*tctx));
779fbf31dd5STom Zanussi 
780fbf31dd5STom Zanussi 	tctx->ecc_dev = kmb_ocs_ecc_find_dev(tctx);
781fbf31dd5STom Zanussi 
782fbf31dd5STom Zanussi 	if (IS_ERR(tctx->ecc_dev)) {
783fbf31dd5STom Zanussi 		pr_err("Failed to find the device : %ld\n",
784fbf31dd5STom Zanussi 		       PTR_ERR(tctx->ecc_dev));
785fbf31dd5STom Zanussi 		return PTR_ERR(tctx->ecc_dev);
786fbf31dd5STom Zanussi 	}
787fbf31dd5STom Zanussi 
788fbf31dd5STom Zanussi 	tctx->curve = ecc_get_curve(curve_id);
789fbf31dd5STom Zanussi 	if (!tctx->curve)
790fbf31dd5STom Zanussi 		return -EOPNOTSUPP;
791fbf31dd5STom Zanussi 
792fbf31dd5STom Zanussi 	return 0;
793fbf31dd5STom Zanussi }
794fbf31dd5STom Zanussi 
kmb_ocs_ecdh_nist_p256_init_tfm(struct crypto_kpp * tfm)795fbf31dd5STom Zanussi static int kmb_ocs_ecdh_nist_p256_init_tfm(struct crypto_kpp *tfm)
796fbf31dd5STom Zanussi {
797fbf31dd5STom Zanussi 	struct ocs_ecc_ctx *tctx = kpp_tfm_ctx(tfm);
798fbf31dd5STom Zanussi 
799fbf31dd5STom Zanussi 	return kmb_ecc_tctx_init(tctx, ECC_CURVE_NIST_P256);
800fbf31dd5STom Zanussi }
801fbf31dd5STom Zanussi 
kmb_ocs_ecdh_nist_p384_init_tfm(struct crypto_kpp * tfm)802fbf31dd5STom Zanussi static int kmb_ocs_ecdh_nist_p384_init_tfm(struct crypto_kpp *tfm)
803fbf31dd5STom Zanussi {
804fbf31dd5STom Zanussi 	struct ocs_ecc_ctx *tctx = kpp_tfm_ctx(tfm);
805fbf31dd5STom Zanussi 
806fbf31dd5STom Zanussi 	return kmb_ecc_tctx_init(tctx, ECC_CURVE_NIST_P384);
807fbf31dd5STom Zanussi }
808fbf31dd5STom Zanussi 
kmb_ocs_ecdh_exit_tfm(struct crypto_kpp * tfm)809fbf31dd5STom Zanussi static void kmb_ocs_ecdh_exit_tfm(struct crypto_kpp *tfm)
810fbf31dd5STom Zanussi {
811fbf31dd5STom Zanussi 	struct ocs_ecc_ctx *tctx = kpp_tfm_ctx(tfm);
812fbf31dd5STom Zanussi 
813fbf31dd5STom Zanussi 	memzero_explicit(tctx->private_key, sizeof(*tctx->private_key));
814fbf31dd5STom Zanussi }
815fbf31dd5STom Zanussi 
kmb_ocs_ecdh_max_size(struct crypto_kpp * tfm)816fbf31dd5STom Zanussi static unsigned int kmb_ocs_ecdh_max_size(struct crypto_kpp *tfm)
817fbf31dd5STom Zanussi {
818fbf31dd5STom Zanussi 	struct ocs_ecc_ctx *tctx = kpp_tfm_ctx(tfm);
819fbf31dd5STom Zanussi 
820fbf31dd5STom Zanussi 	/* Public key is made of two coordinates, so double the digits. */
821fbf31dd5STom Zanussi 	return digits_to_bytes(tctx->curve->g.ndigits) * 2;
822fbf31dd5STom Zanussi }
823fbf31dd5STom Zanussi 
824530d7b00SHerbert Xu static struct kpp_engine_alg ocs_ecdh_p256 = {
825530d7b00SHerbert Xu 	.base.set_secret = kmb_ocs_ecdh_set_secret,
826530d7b00SHerbert Xu 	.base.generate_public_key = kmb_ocs_ecdh_generate_public_key,
827530d7b00SHerbert Xu 	.base.compute_shared_secret = kmb_ocs_ecdh_compute_shared_secret,
828530d7b00SHerbert Xu 	.base.init = kmb_ocs_ecdh_nist_p256_init_tfm,
829530d7b00SHerbert Xu 	.base.exit = kmb_ocs_ecdh_exit_tfm,
830530d7b00SHerbert Xu 	.base.max_size = kmb_ocs_ecdh_max_size,
831530d7b00SHerbert Xu 	.base.base = {
832fbf31dd5STom Zanussi 		.cra_name = "ecdh-nist-p256",
833fbf31dd5STom Zanussi 		.cra_driver_name = "ecdh-nist-p256-keembay-ocs",
834fbf31dd5STom Zanussi 		.cra_priority = KMB_OCS_ECC_PRIORITY,
835fbf31dd5STom Zanussi 		.cra_module = THIS_MODULE,
836fbf31dd5STom Zanussi 		.cra_ctxsize = sizeof(struct ocs_ecc_ctx),
837fbf31dd5STom Zanussi 	},
838530d7b00SHerbert Xu 	.op.do_one_request = kmb_ocs_ecc_do_one_request,
839fbf31dd5STom Zanussi };
840fbf31dd5STom Zanussi 
841530d7b00SHerbert Xu static struct kpp_engine_alg ocs_ecdh_p384 = {
842530d7b00SHerbert Xu 	.base.set_secret = kmb_ocs_ecdh_set_secret,
843530d7b00SHerbert Xu 	.base.generate_public_key = kmb_ocs_ecdh_generate_public_key,
844530d7b00SHerbert Xu 	.base.compute_shared_secret = kmb_ocs_ecdh_compute_shared_secret,
845530d7b00SHerbert Xu 	.base.init = kmb_ocs_ecdh_nist_p384_init_tfm,
846530d7b00SHerbert Xu 	.base.exit = kmb_ocs_ecdh_exit_tfm,
847530d7b00SHerbert Xu 	.base.max_size = kmb_ocs_ecdh_max_size,
848530d7b00SHerbert Xu 	.base.base = {
849fbf31dd5STom Zanussi 		.cra_name = "ecdh-nist-p384",
850fbf31dd5STom Zanussi 		.cra_driver_name = "ecdh-nist-p384-keembay-ocs",
851fbf31dd5STom Zanussi 		.cra_priority = KMB_OCS_ECC_PRIORITY,
852fbf31dd5STom Zanussi 		.cra_module = THIS_MODULE,
853fbf31dd5STom Zanussi 		.cra_ctxsize = sizeof(struct ocs_ecc_ctx),
854fbf31dd5STom Zanussi 	},
855530d7b00SHerbert Xu 	.op.do_one_request = kmb_ocs_ecc_do_one_request,
856fbf31dd5STom Zanussi };
857fbf31dd5STom Zanussi 
ocs_ecc_irq_handler(int irq,void * dev_id)858fbf31dd5STom Zanussi static irqreturn_t ocs_ecc_irq_handler(int irq, void *dev_id)
859fbf31dd5STom Zanussi {
860fbf31dd5STom Zanussi 	struct ocs_ecc_dev *ecc_dev = dev_id;
861fbf31dd5STom Zanussi 	u32 status;
862fbf31dd5STom Zanussi 
863fbf31dd5STom Zanussi 	/*
864fbf31dd5STom Zanussi 	 * Read the status register and write it back to clear the
865fbf31dd5STom Zanussi 	 * DONE_INT_STATUS bit.
866fbf31dd5STom Zanussi 	 */
867fbf31dd5STom Zanussi 	status = ioread32(ecc_dev->base_reg + HW_OFFS_OCS_ECC_ISR);
868fbf31dd5STom Zanussi 	iowrite32(status, ecc_dev->base_reg + HW_OFFS_OCS_ECC_ISR);
869fbf31dd5STom Zanussi 
870fbf31dd5STom Zanussi 	if (!(status & HW_OCS_ECC_ISR_INT_STATUS_DONE))
871fbf31dd5STom Zanussi 		return IRQ_NONE;
872fbf31dd5STom Zanussi 
873fbf31dd5STom Zanussi 	complete(&ecc_dev->irq_done);
874fbf31dd5STom Zanussi 
875fbf31dd5STom Zanussi 	return IRQ_HANDLED;
876fbf31dd5STom Zanussi }
877fbf31dd5STom Zanussi 
kmb_ocs_ecc_probe(struct platform_device * pdev)878fbf31dd5STom Zanussi static int kmb_ocs_ecc_probe(struct platform_device *pdev)
879fbf31dd5STom Zanussi {
880fbf31dd5STom Zanussi 	struct device *dev = &pdev->dev;
881fbf31dd5STom Zanussi 	struct ocs_ecc_dev *ecc_dev;
882fbf31dd5STom Zanussi 	int rc;
883fbf31dd5STom Zanussi 
884fbf31dd5STom Zanussi 	ecc_dev = devm_kzalloc(dev, sizeof(*ecc_dev), GFP_KERNEL);
885fbf31dd5STom Zanussi 	if (!ecc_dev)
886fbf31dd5STom Zanussi 		return -ENOMEM;
887fbf31dd5STom Zanussi 
888fbf31dd5STom Zanussi 	ecc_dev->dev = dev;
889fbf31dd5STom Zanussi 
890fbf31dd5STom Zanussi 	platform_set_drvdata(pdev, ecc_dev);
891fbf31dd5STom Zanussi 
892fbf31dd5STom Zanussi 	INIT_LIST_HEAD(&ecc_dev->list);
893fbf31dd5STom Zanussi 	init_completion(&ecc_dev->irq_done);
894fbf31dd5STom Zanussi 
895fbf31dd5STom Zanussi 	/* Get base register address. */
896fbf31dd5STom Zanussi 	ecc_dev->base_reg = devm_platform_ioremap_resource(pdev, 0);
897fbf31dd5STom Zanussi 	if (IS_ERR(ecc_dev->base_reg)) {
898fbf31dd5STom Zanussi 		dev_err(dev, "Failed to get base address\n");
899fbf31dd5STom Zanussi 		rc = PTR_ERR(ecc_dev->base_reg);
900fbf31dd5STom Zanussi 		goto list_del;
901fbf31dd5STom Zanussi 	}
902fbf31dd5STom Zanussi 
903fbf31dd5STom Zanussi 	/* Get and request IRQ */
904fbf31dd5STom Zanussi 	ecc_dev->irq = platform_get_irq(pdev, 0);
905fbf31dd5STom Zanussi 	if (ecc_dev->irq < 0) {
906fbf31dd5STom Zanussi 		rc = ecc_dev->irq;
907fbf31dd5STom Zanussi 		goto list_del;
908fbf31dd5STom Zanussi 	}
909fbf31dd5STom Zanussi 
910fbf31dd5STom Zanussi 	rc = devm_request_threaded_irq(dev, ecc_dev->irq, ocs_ecc_irq_handler,
911fbf31dd5STom Zanussi 				       NULL, 0, "keembay-ocs-ecc", ecc_dev);
912fbf31dd5STom Zanussi 	if (rc < 0) {
913fbf31dd5STom Zanussi 		dev_err(dev, "Could not request IRQ\n");
914fbf31dd5STom Zanussi 		goto list_del;
915fbf31dd5STom Zanussi 	}
916fbf31dd5STom Zanussi 
917fbf31dd5STom Zanussi 	/* Add device to the list of OCS ECC devices. */
918fbf31dd5STom Zanussi 	spin_lock(&ocs_ecc.lock);
919fbf31dd5STom Zanussi 	list_add_tail(&ecc_dev->list, &ocs_ecc.dev_list);
920fbf31dd5STom Zanussi 	spin_unlock(&ocs_ecc.lock);
921fbf31dd5STom Zanussi 
922fbf31dd5STom Zanussi 	/* Initialize crypto engine. */
923fbf31dd5STom Zanussi 	ecc_dev->engine = crypto_engine_alloc_init(dev, 1);
924fbf31dd5STom Zanussi 	if (!ecc_dev->engine) {
925fbf31dd5STom Zanussi 		dev_err(dev, "Could not allocate crypto engine\n");
926fbf31dd5STom Zanussi 		rc = -ENOMEM;
927fbf31dd5STom Zanussi 		goto list_del;
928fbf31dd5STom Zanussi 	}
929fbf31dd5STom Zanussi 
930fbf31dd5STom Zanussi 	rc = crypto_engine_start(ecc_dev->engine);
931fbf31dd5STom Zanussi 	if (rc) {
932fbf31dd5STom Zanussi 		dev_err(dev, "Could not start crypto engine\n");
933fbf31dd5STom Zanussi 		goto cleanup;
934fbf31dd5STom Zanussi 	}
935fbf31dd5STom Zanussi 
936fbf31dd5STom Zanussi 	/* Register the KPP algo. */
937530d7b00SHerbert Xu 	rc = crypto_engine_register_kpp(&ocs_ecdh_p256);
938fbf31dd5STom Zanussi 	if (rc) {
939fbf31dd5STom Zanussi 		dev_err(dev,
940fbf31dd5STom Zanussi 			"Could not register OCS algorithms with Crypto API\n");
941fbf31dd5STom Zanussi 		goto cleanup;
942fbf31dd5STom Zanussi 	}
943fbf31dd5STom Zanussi 
944530d7b00SHerbert Xu 	rc = crypto_engine_register_kpp(&ocs_ecdh_p384);
945fbf31dd5STom Zanussi 	if (rc) {
946fbf31dd5STom Zanussi 		dev_err(dev,
947fbf31dd5STom Zanussi 			"Could not register OCS algorithms with Crypto API\n");
948fbf31dd5STom Zanussi 		goto ocs_ecdh_p384_error;
949fbf31dd5STom Zanussi 	}
950fbf31dd5STom Zanussi 
951fbf31dd5STom Zanussi 	return 0;
952fbf31dd5STom Zanussi 
953fbf31dd5STom Zanussi ocs_ecdh_p384_error:
954530d7b00SHerbert Xu 	crypto_engine_unregister_kpp(&ocs_ecdh_p256);
955fbf31dd5STom Zanussi 
956fbf31dd5STom Zanussi cleanup:
957fbf31dd5STom Zanussi 	crypto_engine_exit(ecc_dev->engine);
958fbf31dd5STom Zanussi 
959fbf31dd5STom Zanussi list_del:
960fbf31dd5STom Zanussi 	spin_lock(&ocs_ecc.lock);
961fbf31dd5STom Zanussi 	list_del(&ecc_dev->list);
962fbf31dd5STom Zanussi 	spin_unlock(&ocs_ecc.lock);
963fbf31dd5STom Zanussi 
964fbf31dd5STom Zanussi 	return rc;
965fbf31dd5STom Zanussi }
966fbf31dd5STom Zanussi 
kmb_ocs_ecc_remove(struct platform_device * pdev)967*b6b73a24SUwe Kleine-König static void kmb_ocs_ecc_remove(struct platform_device *pdev)
968fbf31dd5STom Zanussi {
969fbf31dd5STom Zanussi 	struct ocs_ecc_dev *ecc_dev;
970fbf31dd5STom Zanussi 
971fbf31dd5STom Zanussi 	ecc_dev = platform_get_drvdata(pdev);
972fbf31dd5STom Zanussi 
973530d7b00SHerbert Xu 	crypto_engine_unregister_kpp(&ocs_ecdh_p384);
974530d7b00SHerbert Xu 	crypto_engine_unregister_kpp(&ocs_ecdh_p256);
975fbf31dd5STom Zanussi 
976fbf31dd5STom Zanussi 	spin_lock(&ocs_ecc.lock);
977fbf31dd5STom Zanussi 	list_del(&ecc_dev->list);
978fbf31dd5STom Zanussi 	spin_unlock(&ocs_ecc.lock);
979fbf31dd5STom Zanussi 
980fbf31dd5STom Zanussi 	crypto_engine_exit(ecc_dev->engine);
981fbf31dd5STom Zanussi }
982fbf31dd5STom Zanussi 
983fbf31dd5STom Zanussi /* Device tree driver match. */
984fbf31dd5STom Zanussi static const struct of_device_id kmb_ocs_ecc_of_match[] = {
985fbf31dd5STom Zanussi 	{
986fbf31dd5STom Zanussi 		.compatible = "intel,keembay-ocs-ecc",
987fbf31dd5STom Zanussi 	},
988fbf31dd5STom Zanussi 	{}
989fbf31dd5STom Zanussi };
990fbf31dd5STom Zanussi 
991fbf31dd5STom Zanussi /* The OCS driver is a platform device. */
992fbf31dd5STom Zanussi static struct platform_driver kmb_ocs_ecc_driver = {
993fbf31dd5STom Zanussi 	.probe = kmb_ocs_ecc_probe,
994*b6b73a24SUwe Kleine-König 	.remove_new = kmb_ocs_ecc_remove,
995fbf31dd5STom Zanussi 	.driver = {
996fbf31dd5STom Zanussi 			.name = DRV_NAME,
997fbf31dd5STom Zanussi 			.of_match_table = kmb_ocs_ecc_of_match,
998fbf31dd5STom Zanussi 		},
999fbf31dd5STom Zanussi };
1000fbf31dd5STom Zanussi module_platform_driver(kmb_ocs_ecc_driver);
1001fbf31dd5STom Zanussi 
1002fbf31dd5STom Zanussi MODULE_LICENSE("GPL");
1003fbf31dd5STom Zanussi MODULE_DESCRIPTION("Intel Keem Bay OCS ECC Driver");
1004fbf31dd5STom Zanussi MODULE_ALIAS_CRYPTO("ecdh-nist-p256");
1005fbf31dd5STom Zanussi MODULE_ALIAS_CRYPTO("ecdh-nist-p384");
1006fbf31dd5STom Zanussi MODULE_ALIAS_CRYPTO("ecdh-nist-p256-keembay-ocs");
1007fbf31dd5STom Zanussi MODULE_ALIAS_CRYPTO("ecdh-nist-p384-keembay-ocs");
1008