1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2020-2022 NXP
5 #ifndef __DESC_SDAP_H__
6 #define __DESC_SDAP_H__
12 /* The file defines all the functions to do PDCP without protocol support in
16 /* Enable SDAP support */
19 #define SDAP_BYTE_SIZE 1
20 #define SDAP_BITS_SIZE (SDAP_BYTE_SIZE * 8)
24 * rta_inline_pdcp_query() - Provide indications if a key can be passed as
25 * immediate data or shall be referenced in a
27 * Return: 0 if data can be inlined or 1 if referenced.
30 rta_inline_pdcp_sdap_query(enum auth_type_pdcp auth_alg,
31 enum cipher_type_pdcp cipher_alg,
32 __rte_unused enum pdcp_sn_size sn_size,
33 __rte_unused int8_t hfn_ovd)
35 if ((cipher_alg != PDCP_CIPHER_TYPE_NULL) &&
36 (auth_alg != PDCP_AUTH_TYPE_NULL))
42 static inline void key_loading_opti(struct program *p,
43 struct alginfo *cipherdata,
44 struct alginfo *authdata)
46 LABEL(lbl_skip_key_loading_jump);
47 REFERENCE(ref_skip_key_loading_jump);
49 /* Optimisation to bypass key loading (and decryption of the keys):
50 * Jump command testing:
51 * - SHRD: Descriptor is shared
52 * - SELF: The shared descriptor is in the same DECO
53 * - BOTH: The Class 1 and 2 CHA have finished
54 * -> If this is true, we jump and skip loading of the keys as they are
57 ref_skip_key_loading_jump =
58 JUMP(p, lbl_skip_key_loading_jump, LOCAL_JUMP, ALL_TRUE,
63 KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
64 cipherdata->keylen, INLINE_KEY(cipherdata));
68 KEY(p, KEY2, authdata->key_enc_flags, authdata->key,
69 authdata->keylen, INLINE_KEY(authdata));
72 /* Save the place where we want the jump to go */
73 SET_LABEL(p, lbl_skip_key_loading_jump);
74 /* Update the jump command with the position where to jump */
75 PATCH_JUMP(p, ref_skip_key_loading_jump, lbl_skip_key_loading_jump);
78 static inline int pdcp_sdap_get_sn_parameters(enum pdcp_sn_size sn_size,
79 bool swap, uint32_t *offset,
87 *sn_mask = (swap == false) ? PDCP_C_PLANE_SN_MASK :
88 PDCP_C_PLANE_SN_MASK_BE;
93 *sn_mask = (swap == false) ? PDCP_7BIT_SN_MASK :
99 *sn_mask = (swap == false) ? PDCP_12BIT_SN_MASK :
100 PDCP_12BIT_SN_MASK_BE;
102 case PDCP_SN_SIZE_15:
105 *sn_mask = (swap == false) ? PDCP_U_PLANE_15BIT_SN_MASK :
106 PDCP_U_PLANE_15BIT_SN_MASK_BE;
108 case PDCP_SN_SIZE_18:
111 *sn_mask = (swap == false) ? PDCP_U_PLANE_18BIT_SN_MASK :
112 PDCP_U_PLANE_18BIT_SN_MASK_BE;
115 pr_err("Invalid sn_size for %s\n", __func__);
120 *length += SDAP_BYTE_SIZE;
121 *offset -= SDAP_BYTE_SIZE;
127 static inline int pdcp_sdap_insert_no_int_op(struct program *p,
128 bool swap __maybe_unused,
129 struct alginfo *cipherdata,
131 enum pdcp_sn_size sn_size,
132 enum pdb_type_e pdb_type)
135 uint32_t sn_mask = 0;
138 int hfn_bearer_dir_offset_in_descbuf =
139 (pdb_type == PDCP_PDB_TYPE_FULL_PDB) ?
140 FULL_PDB_DESCBUF_HFN_BEARER_DIR_OFFSET :
141 REDUCED_PDB_DESCBUF_HFN_BEARER_DIR_OFFSET;
143 if (pdcp_sdap_get_sn_parameters(sn_size, swap, &offset, &length,
148 key_loading_opti(p, cipherdata, NULL);
150 SEQLOAD(p, MATH0, offset, length, 0);
151 JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
154 ((swap == true) ? MATH_FUN_RSHIFT : MATH_FUN_LSHIFT),
155 SDAP_BITS_SIZE, MATH1, 8, 0);
156 MATHB(p, MATH1, AND, sn_mask, MATH1, 8, IFB | IMMED2);
158 MATHB(p, MATH0, AND, sn_mask, MATH1, 8, IFB | IMMED2);
161 SEQSTORE(p, MATH0, offset, length, 0);
163 MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
164 MOVEB(p, DESCBUF, hfn_bearer_dir_offset_in_descbuf,
165 MATH2, 0, 8, WAITCOMP | IMMED);
166 MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
168 MATHB(p, SEQINSZ, SUB, MATH3, VSEQINSZ, 4, 0);
169 MATHB(p, SEQINSZ, SUB, MATH3, VSEQOUTSZ, 4, 0);
171 SEQFIFOSTORE(p, MSG, 0, 0, VLF);
173 op = dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC;
174 switch (cipherdata->algtype) {
175 case PDCP_CIPHER_TYPE_SNOW:
177 MOVEB(p, MATH2, 0, CONTEXT1, 0, 8, WAITCOMP | IMMED);
178 ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8, OP_ALG_AAI_F8,
179 OP_ALG_AS_INITFINAL, ICV_CHECK_DISABLE, op);
182 case PDCP_CIPHER_TYPE_AES:
183 /* The first 64 bits are 0 */
184 MOVEB(p, MATH2, 0, CONTEXT1, 16, 8, WAITCOMP | IMMED);
185 ALG_OPERATION(p, OP_ALG_ALGSEL_AES, OP_ALG_AAI_CTR,
186 OP_ALG_AS_INITFINAL, ICV_CHECK_DISABLE, op);
189 case PDCP_CIPHER_TYPE_ZUC:
190 /* The LSB and MSB is the same for ZUC context */
191 MOVEB(p, MATH2, 0, CONTEXT1, 0, 0x08, IMMED);
192 MOVEB(p, MATH2, 0, CONTEXT1, 0x08, 0x08, WAITCOMP | IMMED);
194 ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE, OP_ALG_AAI_F8,
195 OP_ALG_AS_INITFINAL, ICV_CHECK_DISABLE, op);
199 pr_err("%s: Invalid encrypt algorithm selected: %d\n",
200 "pdcp_sdap_insert_15bit_op", cipherdata->algtype);
204 SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
210 pdcp_sdap_insert_enc_only_op(struct program *p, bool swap __maybe_unused,
211 struct alginfo *cipherdata,
212 struct alginfo *authdata __maybe_unused,
213 unsigned int dir, enum pdcp_sn_size sn_size,
214 enum pdb_type_e pdb_type)
216 uint32_t offset = 0, length = 0, sn_mask = 0;
217 int hfn_bearer_dir_offset_in_descbuf =
218 (pdb_type == PDCP_PDB_TYPE_FULL_PDB) ?
219 FULL_PDB_DESCBUF_HFN_BEARER_DIR_OFFSET :
220 REDUCED_PDB_DESCBUF_HFN_BEARER_DIR_OFFSET;
222 if (pdcp_sdap_get_sn_parameters(sn_size, swap, &offset, &length,
227 key_loading_opti(p, cipherdata, NULL);
230 SEQLOAD(p, MATH0, offset, length, 0);
231 JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
235 ((swap == true) ? MATH_FUN_RSHIFT : MATH_FUN_LSHIFT),
236 SDAP_BITS_SIZE, MATH1, 8, 0);
237 MATHB(p, MATH1, AND, sn_mask, MATH1, 8, IFB | IMMED2);
239 MATHB(p, MATH0, AND, sn_mask, MATH1, 8, IFB | IMMED2);
242 /* Word (32 bit) swap */
243 MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
244 /* Load words from PDB: word 02 (HFN) + word 03 (bearer_dir)*/
245 MOVEB(p, DESCBUF, hfn_bearer_dir_offset_in_descbuf,
246 MATH2, 0, 8, WAITCOMP | IMMED);
247 /* Create basic IV */
248 MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
251 SEQSTORE(p, MATH0, offset, length, 0);
253 MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
255 if (dir == OP_TYPE_ENCAP_PROTOCOL)
256 MATHB(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
258 MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
260 switch (cipherdata->algtype) {
261 case PDCP_CIPHER_TYPE_SNOW:
262 MOVEB(p, MATH2, 0, CONTEXT1, 0, 8, WAITCOMP | IMMED);
263 SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
264 ALG_OPERATION(p, OP_ALG_ALGSEL_SNOW_F8, OP_ALG_AAI_F8,
265 OP_ALG_AS_INITFINAL, ICV_CHECK_DISABLE,
266 dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC :
270 case PDCP_CIPHER_TYPE_AES:
271 MOVEB(p, MATH2, 0, CONTEXT1, 16, 8, WAITCOMP | IMMED);
273 SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
274 ALG_OPERATION(p, OP_ALG_ALGSEL_AES, OP_ALG_AAI_CTR,
275 OP_ALG_AS_INITFINAL, ICV_CHECK_DISABLE,
276 dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC :
280 case PDCP_CIPHER_TYPE_ZUC:
281 MOVEB(p, MATH2, 0, CONTEXT1, 0, 0x08, IMMED);
282 MOVEB(p, MATH2, 0, CONTEXT1, 0x08, 0x08, WAITCOMP | IMMED);
284 SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
285 ALG_OPERATION(p, OP_ALG_ALGSEL_ZUCE, OP_ALG_AAI_F8,
286 OP_ALG_AS_INITFINAL, ICV_CHECK_DISABLE,
287 dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC :
292 pr_err("%s: Invalid encrypt algorithm selected: %d\n",
293 "pdcp_sdap_insert_enc_only_op", cipherdata->algtype);
297 if (dir == OP_TYPE_ENCAP_PROTOCOL) {
298 SEQFIFOLOAD(p, MSG1, 0, VLF);
299 FIFOLOAD(p, MSG1, PDCP_NULL_INT_MAC_I_VAL, 4,
300 LAST1 | FLUSH1 | IMMED);
302 SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
303 MOVE(p, OFIFO, 0, MATH1, 4, PDCP_MAC_I_LEN, WAITCOMP | IMMED);
304 MATHB(p, MATH1, XOR, PDCP_NULL_INT_MAC_I_VAL, NONE, 4, IMMED2);
305 JUMP(p, PDCP_NULL_INT_ICV_CHECK_FAILED_STATUS, HALT_STATUS,
313 * This function leverage the use of in/out snooping as SNOW and ZUC both
314 * have a class 1 and class 2 CHA. It also supports AES as cipher.
325 pdcp_sdap_insert_snoop_op(struct program *p, bool swap __maybe_unused,
326 struct alginfo *cipherdata, struct alginfo *authdata,
327 unsigned int dir, enum pdcp_sn_size sn_size,
328 enum pdb_type_e pdb_type)
330 uint32_t offset = 0, length = 0, sn_mask = 0;
331 uint32_t int_op_alg = 0;
332 uint32_t int_op_aai = 0;
333 uint32_t cipher_op_alg = 0;
334 uint32_t cipher_op_aai = 0;
335 int hfn_bearer_dir_offset_in_descbuf =
336 (pdb_type == PDCP_PDB_TYPE_FULL_PDB) ?
337 FULL_PDB_DESCBUF_HFN_BEARER_DIR_OFFSET :
338 REDUCED_PDB_DESCBUF_HFN_BEARER_DIR_OFFSET;
340 if (pdcp_sdap_get_sn_parameters(sn_size, swap, &offset, &length,
344 if (dir == OP_TYPE_ENCAP_PROTOCOL)
345 MATHB(p, SEQINSZ, SUB, length, VSEQINSZ, 4, IMMED2);
347 key_loading_opti(p, cipherdata, authdata);
349 /* Load the PDCP header from the input data
350 * Note: SEQINSZ is decremented by length
352 SEQLOAD(p, MATH0, offset, length, 0);
353 /* Wait the SN is loaded */
354 JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
356 /* Pass the PDCP header to integrity block */
357 MOVEB(p, MATH0, offset, IFIFOAB2, 0, length, IMMED);
360 /* If SDAP is enabled, the least significant byte is the SDAP header
361 * Remove it by shifting the register
364 ((swap == true) ? MATH_FUN_RSHIFT : MATH_FUN_LSHIFT),
365 SDAP_BITS_SIZE, MATH1, 8, 0);
366 /* Mask the PDCP header to keep only the SN */
367 MATHB(p, MATH1, AND, sn_mask, MATH1, 8, IFB | IMMED2);
369 /* Mask the PDCP header to keep only the SN */
370 MATHB(p, MATH0, AND, sn_mask, MATH1, 8, IFB | IMMED2);
373 /* Do a byte swap, it places the SN in upper part of the MATH reg */
374 MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
376 /* Load the HFN / Beare / Dir from the PDB
377 * CAAM word are 32bit hence loading 8 byte loads 2 words:
378 * - The HFN at offset hfn_bearer_dir_offset_in_descbuf
379 * - The Bearer / Dir at next word
381 MOVEB(p, DESCBUF, hfn_bearer_dir_offset_in_descbuf,
382 MATH2, 0, 8, WAITCOMP | IMMED);
384 /* Create the 4 first byte of the ICV by or-ing the math registers */
385 MATHB(p, MATH1, OR, MATH2, MATH1, 8, 0);
387 /* Set the IV of class 1 CHA */
388 if (cipherdata->algtype == PDCP_CIPHER_TYPE_AES) {
389 MOVEB(p, MATH1, 0, CONTEXT1, 16, 8, IMMED);
391 /* Set the IV for the confidentiality CHA */
392 MOVEB(p, MATH1, 0, CONTEXT1, 0, 8, IMMED);
395 /* Set the IV of class 2 CHA */
396 if (authdata->algtype == PDCP_AUTH_TYPE_ZUC) {
397 /* Set the IV for the integrity CHA */
398 MOVEB(p, MATH1, 0, CONTEXT2, 0, 8, WAITCOMP | IMMED);
399 } else if (authdata->algtype == PDCP_AUTH_TYPE_SNOW) {
400 MOVEB(p, MATH1, 0, CONTEXT2, 0, 4, WAITCOMP | IMMED);
402 /* Generate the bottom snow IV for integrity
403 * Note: MATH1 lowest 32bits is as follow:
404 * | bearer (5) | Dir (1) | zero (26) |
405 * the resulting math regs will be:
407 * | zero (5) | Dir (1) | zero (26) | | Bearer (5) | zero (27) |
410 MATHB(p, MATH1, AND, upper_32_bits(PDCP_BEARER_MASK),
412 MATHB(p, MATH1, AND, lower_32_bits(PDCP_DIR_MASK),
415 MATHB(p, MATH1, AND, lower_32_bits(PDCP_BEARER_MASK_BE),
417 MATHB(p, MATH1, AND, upper_32_bits(PDCP_DIR_MASK_BE),
420 /* Word swap MATH3 reg */
421 MATHB(p, MATH3, SHLD, MATH3, MATH3, 8, 0);
423 /* Don't understand, seems to be doing a move of 12 byte
424 * (read MATH2 and overread MATH3)
426 MOVEB(p, MATH2, 4, OFIFO, 0, 12, IMMED);
428 /* Add the rest of the snow IV to the context */
429 MOVE(p, OFIFO, 0, CONTEXT2, 4, 12, IMMED);
432 /* Set the variable size of data the register will write */
433 if (dir == OP_TYPE_ENCAP_PROTOCOL) {
434 /* We will add the integrity data so add its length */
435 MATHI(p, SEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
437 /* We will check the integrity data so remove its length */
438 MATHI(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
439 /* Do not take the ICV in the out-snooping configuration */
440 MATHI(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQINSZ, 4, IMMED2);
443 /* We write the PDCP header to output*/
444 SEQSTORE(p, MATH0, offset, length, 0);
446 /* Definition of the flow of output data */
447 if (dir == OP_TYPE_ENCAP_PROTOCOL) {
448 /* We write data according to VSEQOUTSZ */
449 SEQFIFOSTORE(p, MSG, 0, 0, VLF);
451 /* We write data according to VSEQOUTSZ */
452 SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
455 /* Get parameters for authentication */
456 if (authdata->algtype == PDCP_AUTH_TYPE_ZUC) {
457 int_op_alg = OP_ALG_ALGSEL_ZUCA;
458 int_op_aai = OP_ALG_AAI_F9;
459 } else if (authdata->algtype == PDCP_AUTH_TYPE_SNOW) {
460 int_op_alg = OP_ALG_ALGSEL_SNOW_F9;
461 int_op_aai = OP_ALG_AAI_F9;
463 pr_err("%s no support for auth alg: %d\n", __func__,
468 /* Get parameters for ciphering */
469 if (cipherdata->algtype == PDCP_CIPHER_TYPE_ZUC) {
470 cipher_op_alg = OP_ALG_ALGSEL_ZUCE;
471 cipher_op_aai = OP_ALG_AAI_F8;
472 } else if (cipherdata->algtype == PDCP_CIPHER_TYPE_SNOW) {
473 cipher_op_alg = OP_ALG_ALGSEL_SNOW_F8;
474 cipher_op_aai = OP_ALG_AAI_F8;
475 } else if (cipherdata->algtype == PDCP_CIPHER_TYPE_AES) {
476 cipher_op_alg = OP_ALG_ALGSEL_AES;
477 cipher_op_aai = OP_ALG_AAI_CTR;
479 pr_err("%s no support for cipher alg: %d\n", __func__,
484 /* Configure the CHA, the class 2 CHA must be configured first or an
485 * error will be generated
488 /* Configure the class 2 CHA (integrity )*/
489 ALG_OPERATION(p, int_op_alg, int_op_aai, OP_ALG_AS_INITFINAL,
490 dir == OP_TYPE_ENCAP_PROTOCOL ? ICV_CHECK_DISABLE :
494 /* Configure class 1 CHA (confidentiality)*/
495 ALG_OPERATION(p, cipher_op_alg, cipher_op_aai, OP_ALG_AS_INITFINAL,
497 dir == OP_TYPE_ENCAP_PROTOCOL ? DIR_ENC : DIR_DEC);
499 /* Definition of the flow of input data */
500 if (dir == OP_TYPE_ENCAP_PROTOCOL) {
501 /* We read data according to VSEQINSZ
502 * Note: we perform an in-snooping, eg the data will be read
503 * only once. they will be sent to both the integrity CHA and
504 * confidentiality CHA
506 SEQFIFOLOAD(p, MSGINSNOOP, 0, VLF | LAST2);
508 /* When the integrity CHA is finished, send the ICV stored in
509 * the context to the confidentiality CHA for encryption
511 MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
513 /* We read data according to VSEQINSZ
514 * Note: we perform an out-snooping, eg the data will be read
515 * only once. The will first be sent to the confidentiality
516 * CHA for decryption, then the CAAM will direct them to the
517 * integrity CHA to verify the ICV (which is at the end of the
520 SEQFIFOLOAD(p, MSGOUTSNOOP, 0, VLF | LAST2);
522 /* Process the ICV by class 1 CHA */
523 SEQFIFOLOAD(p, MSG1, 4, LAST1 | FLUSH1);
525 /* Wait for class 1 CHA to finish, the ICV data are stalling in
528 JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CLASS1 | NOP | NIFP);
530 LOAD(p, 0, DCTRL, 0, LDLEN_RST_CHA_OFIFO_PTR, IMMED);
532 /* Save the content left in the Output FIFO (the ICV) to MATH0
534 MOVE(p, OFIFO, 0, MATH0, 0, 4, WAITCOMP | IMMED);
536 /* Configure a NFIFO entry to take data from the altsource
537 * and send it to the class 2 CHA as an ICV
539 NFIFOADD(p, IFIFO, ICV2, 4, LAST2);
541 /* Move the content of MATH0 (OFIFO offset) to altsource
542 * Note: As configured by the altsource, this will send
545 MOVE(p, MATH0, 0, IFIFO, 0, 4, WAITCOMP | IMMED);
548 if (authdata->algtype == PDCP_CIPHER_TYPE_ZUC) {
549 /* Reset ZUCA mode and done interrupt
550 * Note: If it is not done, DECO generate an error: 200031ca
553 LOAD(p, CLRW_CLR_C2MODE, CLRW, 0, 4, IMMED);
554 LOAD(p, CIRQ_ZADI, ICTRL, 0, 4, IMMED);
560 /* Function used when the integrity algorithm is a class 1 CHA so outsnooping
570 static inline int pdcp_sdap_insert_no_snoop_op(
571 struct program *p, bool swap __maybe_unused, struct alginfo *cipherdata,
572 struct alginfo *authdata, unsigned int dir, enum pdcp_sn_size sn_size,
573 enum pdb_type_e pdb_type)
575 uint32_t offset = 0, length = 0, sn_mask = 0;
576 uint32_t cipher_alg_op = 0;
577 uint32_t cipher_alg_aai = 0;
578 int hfn_bearer_dir_offset_in_descbuf =
579 (pdb_type == PDCP_PDB_TYPE_FULL_PDB) ?
580 FULL_PDB_DESCBUF_HFN_BEARER_DIR_OFFSET :
581 REDUCED_PDB_DESCBUF_HFN_BEARER_DIR_OFFSET;
583 if (pdcp_sdap_get_sn_parameters(sn_size, swap, &offset, &length,
587 SEQLOAD(p, MATH0, offset, length, 0);
588 JUMP(p, 1, LOCAL_JUMP, ALL_TRUE, CALM);
592 ((swap == true) ? MATH_FUN_RSHIFT : MATH_FUN_LSHIFT),
593 SDAP_BITS_SIZE, MATH1, 8, 0);
594 MATHB(p, MATH1, AND, sn_mask, MATH1, 8, IFB | IMMED2);
596 MATHB(p, MATH0, AND, sn_mask, MATH1, 8, IFB | IMMED2);
599 MATHB(p, MATH1, SHLD, MATH1, MATH1, 8, 0);
600 MOVEB(p, DESCBUF, hfn_bearer_dir_offset_in_descbuf,
601 MATH2, 0, 0x08, WAITCOMP | IMMED);
602 MATHB(p, MATH1, OR, MATH2, MATH2, 8, 0);
604 SEQSTORE(p, MATH0, offset, length, 0);
606 if (dir == OP_TYPE_ENCAP_PROTOCOL) {
607 /* Load authentication key */
608 KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
609 authdata->keylen, INLINE_KEY(authdata));
611 /* Set the iv for AES authentication */
612 MOVEB(p, MATH2, 0, IFIFOAB1, 0, 8, IMMED);
614 /* Pass the header */
615 MOVEB(p, MATH0, offset, IFIFOAB1, 0, length, IMMED);
617 /* Configure variable size for I/O */
618 MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
619 MATHB(p, VSEQINSZ, ADD, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
621 /* Perform the authentication */
622 ALG_OPERATION(p, OP_ALG_ALGSEL_AES, OP_ALG_AAI_CMAC,
623 OP_ALG_AS_INITFINAL, ICV_CHECK_DISABLE, DIR_DEC);
625 /* Configure the read of data */
626 SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
628 /* Save the ICV generated */
629 MOVEB(p, CONTEXT1, 0, MATH3, 0, 4, WAITCOMP | IMMED);
631 /* The CHA will be reused so we need to clear it */
632 LOAD(p, CLRW_RESET_CLS1_CHA |
640 /* Load confidentiality key */
641 KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
642 cipherdata->keylen, INLINE_KEY(cipherdata));
644 /* Load the IV for ciphering */
645 if (cipherdata->algtype == PDCP_CIPHER_TYPE_AES) {
646 MOVEB(p, MATH2, 0, CONTEXT1, 16, 8, IMMED);
647 cipher_alg_op = OP_ALG_ALGSEL_AES;
648 cipher_alg_aai = OP_ALG_AAI_CTR;
649 } else if (cipherdata->algtype == PDCP_CIPHER_TYPE_ZUC) {
650 /* Set the IV for the confidentiality CHA */
651 MOVEB(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
652 cipher_alg_op = OP_ALG_ALGSEL_ZUCE;
653 cipher_alg_aai = OP_ALG_AAI_F8;
654 } else if (cipherdata->algtype == PDCP_CIPHER_TYPE_SNOW) {
655 /* Set the IV for the confidentiality CHA */
656 MOVEB(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
657 cipher_alg_op = OP_ALG_ALGSEL_SNOW_F8;
658 cipher_alg_aai = OP_ALG_AAI_F8;
661 /* Rewind the pointer on input data to reread it */
662 SEQINPTR(p, 0, PDCP_NULL_MAX_FRAME_LEN, RTO);
664 /* Define the ciphering operation */
665 ALG_OPERATION(p, cipher_alg_op, cipher_alg_aai,
666 OP_ALG_AS_INITFINAL, ICV_CHECK_DISABLE, DIR_ENC);
668 /* Define the data to write */
669 SEQFIFOSTORE(p, MSG, 0, 0, VLF);
671 /* Skip the header which does not need to be encrypted */
672 SEQFIFOLOAD(p, SKIP, length, 0);
674 /* Read the rest of the data */
675 SEQFIFOLOAD(p, MSG1, 0, VLF);
677 /* Send the ICV stored in MATH3 for encryption */
678 MOVEB(p, MATH3, 0, IFIFOAB1, 0, 4, LAST1 | FLUSH1 | IMMED);
680 /* Load the IV for ciphering */
681 if (cipherdata->algtype == PDCP_CIPHER_TYPE_AES) {
682 MOVEB(p, MATH2, 0, CONTEXT1, 16, 8, IMMED);
683 cipher_alg_op = OP_ALG_ALGSEL_AES;
684 cipher_alg_aai = OP_ALG_AAI_CTR;
685 } else if (cipherdata->algtype == PDCP_CIPHER_TYPE_ZUC) {
686 /* Set the IV for the confidentiality CHA */
687 MOVEB(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
688 cipher_alg_op = OP_ALG_ALGSEL_ZUCE;
689 cipher_alg_aai = OP_ALG_AAI_F8;
690 } else if (cipherdata->algtype == PDCP_CIPHER_TYPE_SNOW) {
691 /* Set the IV for the confidentiality CHA */
692 MOVEB(p, MATH2, 0, CONTEXT1, 0, 8, IMMED);
693 cipher_alg_op = OP_ALG_ALGSEL_SNOW_F8;
694 cipher_alg_aai = OP_ALG_AAI_F8;
696 MOVEB(p, MATH2, 0, CONTEXT2, 0, 8, IMMED);
698 /* Read all the data */
699 MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
701 /* Do not write back the ICV */
702 MATHB(p, SEQINSZ, SUB, PDCP_MAC_I_LEN, VSEQOUTSZ, 4, IMMED2);
704 /* Load the key for ciphering */
705 KEY(p, KEY1, cipherdata->key_enc_flags, cipherdata->key,
706 cipherdata->keylen, INLINE_KEY(cipherdata));
708 /* Write all the data */
709 SEQFIFOSTORE(p, MSG, 0, 0, VLF | CONT);
711 /* Define the ciphering algorithm */
712 ALG_OPERATION(p, cipher_alg_op, cipher_alg_aai,
713 OP_ALG_AS_INITFINAL, ICV_CHECK_DISABLE, DIR_DEC);
715 /* Read all the data */
716 SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
718 /* Save the ICV which is stalling in output FIFO to MATH3 */
719 MOVEB(p, OFIFO, 0, MATH3, 0, 4, IMMED);
721 /* Reset class 1 CHA */
722 LOAD(p, CLRW_RESET_CLS1_CHA |
730 /* Load the key for authentication */
731 KEY(p, KEY1, authdata->key_enc_flags, authdata->key,
732 authdata->keylen, INLINE_KEY(authdata));
734 /* Start a new sequence */
735 SEQINPTR(p, 0, 0, SOP);
737 /* Define the operation to verify the ICV */
738 ALG_OPERATION(p, OP_ALG_ALGSEL_AES, OP_ALG_AAI_CMAC,
739 OP_ALG_AS_INITFINAL, ICV_CHECK_ENABLE, DIR_DEC);
741 /* Set the variable size input */
742 MATHB(p, SEQINSZ, SUB, ZERO, VSEQINSZ, 4, 0);
744 MOVE(p, CONTEXT2, 0, IFIFOAB1, 0, 8, IMMED);
746 SEQFIFOLOAD(p, MSG1, 0, VLF | LAST1 | FLUSH1);
748 /* Define an NFIFO entry to load the ICV saved */
749 LOAD(p, NFIFOENTRY_STYPE_ALTSOURCE |
750 NFIFOENTRY_DEST_CLASS1 |
751 NFIFOENTRY_DTYPE_ICV |
753 NFIFOENTRY_FC1 | 4, NFIFO_SZL, 0, 4, IMMED);
756 MOVEB(p, MATH3, 0, ALTSOURCE, 0, 4, IMMED);
763 pdcp_sdap_insert_cplane_null_op(struct program *p,
764 bool swap __maybe_unused,
765 struct alginfo *cipherdata,
766 struct alginfo *authdata,
768 enum pdcp_sn_size sn_size,
769 enum pdb_type_e pdb_type __maybe_unused)
771 return pdcp_insert_cplane_null_op(p, swap, cipherdata, authdata, dir,
776 pdcp_sdap_insert_cplane_int_only_op(struct program *p,
777 bool swap __maybe_unused,
778 struct alginfo *cipherdata,
779 struct alginfo *authdata,
781 enum pdcp_sn_size sn_size,
782 enum pdb_type_e pdb_type __maybe_unused)
784 return pdcp_insert_cplane_int_only_op(p, swap, cipherdata, authdata,
788 static int pdcp_sdap_insert_with_int_op(
789 struct program *p, bool swap __maybe_unused, struct alginfo *cipherdata,
790 struct alginfo *authdata, enum pdcp_sn_size sn_size,
792 enum pdb_type_e pdb_type)
795 *pdcp_cp_fp[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID])(
796 struct program *, bool swap, struct alginfo *, struct alginfo *,
797 unsigned int dir, enum pdcp_sn_size, enum pdb_type_e pdb_type) = {
800 pdcp_sdap_insert_cplane_null_op, /* NULL */
801 pdcp_sdap_insert_cplane_int_only_op, /* SNOW f9 */
802 pdcp_sdap_insert_cplane_int_only_op, /* AES CMAC */
803 pdcp_sdap_insert_cplane_int_only_op /* ZUC-I */
807 pdcp_sdap_insert_enc_only_op, /* NULL */
808 pdcp_sdap_insert_snoop_op, /* SNOW f9 */
809 pdcp_sdap_insert_no_snoop_op, /* AES CMAC */
810 pdcp_sdap_insert_snoop_op /* ZUC-I */
814 pdcp_sdap_insert_enc_only_op, /* NULL */
815 pdcp_sdap_insert_snoop_op, /* SNOW f9 */
816 pdcp_sdap_insert_no_snoop_op, /* AES CMAC */
817 pdcp_sdap_insert_snoop_op /* ZUC-I */
821 pdcp_sdap_insert_enc_only_op, /* NULL */
822 pdcp_sdap_insert_snoop_op, /* SNOW f9 */
823 pdcp_sdap_insert_no_snoop_op, /* AES CMAC */
824 pdcp_sdap_insert_snoop_op /* ZUC-I */
829 err = pdcp_cp_fp[cipherdata->algtype]
830 [authdata->algtype](p, swap, cipherdata, authdata, dir,
839 cnstr_shdsc_pdcp_sdap_u_plane(uint32_t *descbuf,
842 enum pdcp_sn_size sn_size,
844 unsigned short bearer,
845 unsigned short direction,
846 uint32_t hfn_threshold,
847 struct alginfo *cipherdata,
848 struct alginfo *authdata,
852 struct program *p = &prg;
854 enum pdb_type_e pdb_type;
855 static enum rta_share_type
856 desc_share[PDCP_CIPHER_TYPE_INVALID][PDCP_AUTH_TYPE_INVALID] = {
860 SHR_WAIT, /* SNOW f9 */
861 SHR_WAIT, /* AES CMAC */
867 SHR_WAIT, /* SNOW f9 */
868 SHR_WAIT, /* AES CMAC */
874 SHR_WAIT, /* SNOW f9 */
875 SHR_WAIT, /* AES CMAC */
881 SHR_WAIT, /* SNOW f9 */
882 SHR_WAIT, /* AES CMAC */
889 /* Check the confidentiality algorithm is supported by the code */
890 switch (cipherdata->algtype) {
891 case PDCP_CIPHER_TYPE_NULL:
892 case PDCP_CIPHER_TYPE_SNOW:
893 case PDCP_CIPHER_TYPE_AES:
894 case PDCP_CIPHER_TYPE_ZUC:
897 pr_err("Cipher algorithm not supported: %d\n",
898 cipherdata->algtype);
902 /* Check the authentication algorithm is supported by the code */
904 switch (authdata->algtype) {
905 case PDCP_AUTH_TYPE_NULL:
906 case PDCP_AUTH_TYPE_SNOW:
907 case PDCP_AUTH_TYPE_AES:
908 case PDCP_AUTH_TYPE_ZUC:
911 pr_err("Auth algorithm not supported: %d\n",
917 /* Check the Sequence Number size is supported by the code */
921 case PDCP_SN_SIZE_12:
922 case PDCP_SN_SIZE_15:
923 case PDCP_SN_SIZE_18:
926 pr_err("SN size not supported: %d\n", sn_size);
930 /* Initialize the program */
931 PROGRAM_CNTXT_INIT(p, descbuf, 0);
934 PROGRAM_SET_BSWAP(p);
937 PROGRAM_SET_36BIT_ADDR(p);
939 /* Select the shared descriptor sharing mode */
941 SHR_HDR(p, desc_share[cipherdata->algtype][authdata->algtype],
944 SHR_HDR(p, SHR_WAIT, 0, 0);
946 /* Construct the PDB */
947 pdb_type = cnstr_pdcp_u_plane_pdb(p, sn_size, hfn, bearer, direction,
948 hfn_threshold, cipherdata, authdata);
949 if (pdb_type == PDCP_PDB_TYPE_INVALID) {
950 pr_err("Error creating PDCP UPlane PDB\n");
953 SET_LABEL(p, pdb_end);
955 /* Inser the HFN override operation */
956 err = insert_hfn_ov_op(p, sn_size, pdb_type, false);
960 /* Create the descriptor */
962 if (cipherdata->algtype == PDCP_CIPHER_TYPE_NULL) {
963 insert_copy_frame_op(p, cipherdata,
964 OP_TYPE_ENCAP_PROTOCOL);
966 err = pdcp_sdap_insert_no_int_op(p, swap, cipherdata,
970 pr_err("Fail pdcp_sdap_insert_no_int_op\n");
975 err = pdcp_sdap_insert_with_int_op(p, swap, cipherdata,
977 caps_mode, pdb_type);
979 pr_err("Fail pdcp_sdap_insert_with_int_op\n");
984 PATCH_HDR(p, 0, pdb_end);
986 return PROGRAM_FINALIZE(p);
990 * cnstr_shdsc_pdcp_sdap_u_plane_encap - Function for creating a PDCP-SDAP
991 * User Plane encapsulation descriptor.
992 * @descbuf: pointer to buffer for descriptor construction
993 * @ps: if 36/40bit addressing is desired, this parameter must be true
994 * @swap: must be true when core endianness doesn't match SEC endianness
995 * @sn_size: selects Sequence Number Size: 7/12/15 bits
996 * @hfn: starting Hyper Frame Number to be used together with the SN from the
998 * @bearer: radio bearer ID
999 * @direction: the direction of the PDCP frame (UL/DL)
1000 * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
1001 * keys should be renegotiated at the earliest convenience.
1002 * @cipherdata: pointer to block cipher transform definitions
1003 * Valid algorithm values are those from cipher_type_pdcp enum.
1005 * Return: size of descriptor written in words or negative number on error.
1006 * Once the function returns, the value of this parameter can be used
1007 * for reclaiming the space that wasn't used for the descriptor.
1009 * Note: descbuf must be large enough to contain a full 256 byte long
1010 * descriptor; after the function returns, by subtracting the actual number of
1011 * bytes used, the user can reuse the remaining buffer space for other purposes.
1014 cnstr_shdsc_pdcp_sdap_u_plane_encap(uint32_t *descbuf,
1017 enum pdcp_sn_size sn_size,
1019 unsigned short bearer,
1020 unsigned short direction,
1021 uint32_t hfn_threshold,
1022 struct alginfo *cipherdata,
1023 struct alginfo *authdata)
1025 return cnstr_shdsc_pdcp_sdap_u_plane(descbuf, ps, swap, sn_size,
1026 hfn, bearer, direction, hfn_threshold, cipherdata,
1027 authdata, OP_TYPE_ENCAP_PROTOCOL);
1031 * cnstr_shdsc_pdcp_sdap_u_plane_decap - Function for creating a PDCP-SDAP
1032 * User Plane decapsulation descriptor.
1033 * @descbuf: pointer to buffer for descriptor construction
1034 * @ps: if 36/40bit addressing is desired, this parameter must be true
1035 * @swap: must be true when core endianness doesn't match SEC endianness
1036 * @sn_size: selects Sequence Number Size: 7/12/15 bits
1037 * @hfn: starting Hyper Frame Number to be used together with the SN from the
1039 * @bearer: radio bearer ID
1040 * @direction: the direction of the PDCP frame (UL/DL)
1041 * @hfn_threshold: HFN value that once reached triggers a warning from SEC that
1042 * keys should be renegotiated at the earliest convenience.
1043 * @cipherdata: pointer to block cipher transform definitions
1044 * Valid algorithm values are those from cipher_type_pdcp enum.
1046 * Return: size of descriptor written in words or negative number on error.
1047 * Once the function returns, the value of this parameter can be used
1048 * for reclaiming the space that wasn't used for the descriptor.
1050 * Note: descbuf must be large enough to contain a full 256 byte long
1051 * descriptor; after the function returns, by subtracting the actual number of
1052 * bytes used, the user can reuse the remaining buffer space for other purposes.
1055 cnstr_shdsc_pdcp_sdap_u_plane_decap(uint32_t *descbuf,
1058 enum pdcp_sn_size sn_size,
1060 unsigned short bearer,
1061 unsigned short direction,
1062 uint32_t hfn_threshold,
1063 struct alginfo *cipherdata,
1064 struct alginfo *authdata)
1066 return cnstr_shdsc_pdcp_sdap_u_plane(descbuf, ps, swap, sn_size, hfn,
1067 bearer, direction, hfn_threshold, cipherdata, authdata,
1068 OP_TYPE_DECAP_PROTOCOL);
1071 #endif /* __DESC_SDAP_H__ */