Imported Upstream version 17.05
[deb_dpdk.git] / drivers / crypto / dpaa2_sec / hw / rta / move_cmd.h
diff --git a/drivers/crypto/dpaa2_sec/hw/rta/move_cmd.h b/drivers/crypto/dpaa2_sec/hw/rta/move_cmd.h
new file mode 100644 (file)
index 0000000..10d2e19
--- /dev/null
@@ -0,0 +1,445 @@
+/*-
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ *   BSD LICENSE
+ *
+ * Copyright 2008-2016 Freescale Semiconductor Inc.
+ * Copyright (c) 2016 NXP.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the above-listed copyright holders nor the
+ * names of any contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *   GPL LICENSE SUMMARY
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __RTA_MOVE_CMD_H__
+#define __RTA_MOVE_CMD_H__
+
+#define MOVE_SET_AUX_SRC       0x01
+#define MOVE_SET_AUX_DST       0x02
+#define MOVE_SET_AUX_LS                0x03
+#define MOVE_SET_LEN_16b       0x04
+
+#define MOVE_SET_AUX_MATH      0x10
+#define MOVE_SET_AUX_MATH_SRC  (MOVE_SET_AUX_SRC | MOVE_SET_AUX_MATH)
+#define MOVE_SET_AUX_MATH_DST  (MOVE_SET_AUX_DST | MOVE_SET_AUX_MATH)
+
+#define MASK_16b  0xFF
+
+/* MOVE command type */
+#define __MOVE         1
+#define __MOVEB                2
+#define __MOVEDW       3
+
+extern enum rta_sec_era rta_sec_era;
+
+static const uint32_t move_src_table[][2] = {
+/*1*/  { CONTEXT1, MOVE_SRC_CLASS1CTX },
+       { CONTEXT2, MOVE_SRC_CLASS2CTX },
+       { OFIFO,    MOVE_SRC_OUTFIFO },
+       { DESCBUF,  MOVE_SRC_DESCBUF },
+       { MATH0,    MOVE_SRC_MATH0 },
+       { MATH1,    MOVE_SRC_MATH1 },
+       { MATH2,    MOVE_SRC_MATH2 },
+       { MATH3,    MOVE_SRC_MATH3 },
+/*9*/  { IFIFOABD, MOVE_SRC_INFIFO },
+       { IFIFOAB1, MOVE_SRC_INFIFO_CL | MOVE_AUX_LS },
+       { IFIFOAB2, MOVE_SRC_INFIFO_CL },
+/*12*/ { ABD,      MOVE_SRC_INFIFO_NO_NFIFO },
+       { AB1,      MOVE_SRC_INFIFO_NO_NFIFO | MOVE_AUX_LS },
+       { AB2,      MOVE_SRC_INFIFO_NO_NFIFO | MOVE_AUX_MS }
+};
+
+/* Allowed MOVE / MOVE_LEN sources for each SEC Era.
+ * Values represent the number of entries from move_src_table[] that are
+ * supported.
+ */
+static const unsigned int move_src_table_sz[] = {9, 11, 14, 14, 14, 14, 14, 14};
+
+static const uint32_t move_dst_table[][2] = {
+/*1*/  { CONTEXT1,  MOVE_DEST_CLASS1CTX },
+       { CONTEXT2,  MOVE_DEST_CLASS2CTX },
+       { OFIFO,     MOVE_DEST_OUTFIFO },
+       { DESCBUF,   MOVE_DEST_DESCBUF },
+       { MATH0,     MOVE_DEST_MATH0 },
+       { MATH1,     MOVE_DEST_MATH1 },
+       { MATH2,     MOVE_DEST_MATH2 },
+       { MATH3,     MOVE_DEST_MATH3 },
+       { IFIFOAB1,  MOVE_DEST_CLASS1INFIFO },
+       { IFIFOAB2,  MOVE_DEST_CLASS2INFIFO },
+       { PKA,       MOVE_DEST_PK_A },
+       { KEY1,      MOVE_DEST_CLASS1KEY },
+       { KEY2,      MOVE_DEST_CLASS2KEY },
+/*14*/ { IFIFO,     MOVE_DEST_INFIFO },
+/*15*/ { ALTSOURCE,  MOVE_DEST_ALTSOURCE}
+};
+
+/* Allowed MOVE / MOVE_LEN destinations for each SEC Era.
+ * Values represent the number of entries from move_dst_table[] that are
+ * supported.
+ */
+static const
+unsigned int move_dst_table_sz[] = {13, 14, 14, 15, 15, 15, 15, 15};
+
+static inline int
+set_move_offset(struct program *program __maybe_unused,
+               uint64_t src, uint16_t src_offset,
+               uint64_t dst, uint16_t dst_offset,
+               uint16_t *offset, uint16_t *opt);
+
+static inline int
+math_offset(uint16_t offset);
+
+static inline int
+rta_move(struct program *program, int cmd_type, uint64_t src,
+        uint16_t src_offset, uint64_t dst,
+        uint16_t dst_offset, uint32_t length, uint32_t flags)
+{
+       uint32_t opcode = 0;
+       uint16_t offset = 0, opt = 0;
+       uint32_t val = 0;
+       int ret = -EINVAL;
+       bool is_move_len_cmd = false;
+       unsigned int start_pc = program->current_pc;
+
+       if ((rta_sec_era < RTA_SEC_ERA_7) && (cmd_type != __MOVE)) {
+               pr_err("MOVE: MOVEB / MOVEDW not supported by SEC Era %d. SEC PC: %d; Instr: %d\n",
+                      USER_SEC_ERA(rta_sec_era), program->current_pc,
+                      program->current_instruction);
+               goto err;
+       }
+
+       /* write command type */
+       if (cmd_type == __MOVEB) {
+               opcode = CMD_MOVEB;
+       } else if (cmd_type == __MOVEDW) {
+               opcode = CMD_MOVEDW;
+       } else if (!(flags & IMMED)) {
+               if (rta_sec_era < RTA_SEC_ERA_3) {
+                       pr_err("MOVE: MOVE_LEN not supported by SEC Era %d. SEC PC: %d; Instr: %d\n",
+                              USER_SEC_ERA(rta_sec_era), program->current_pc,
+                              program->current_instruction);
+                       goto err;
+               }
+
+               if ((length != MATH0) && (length != MATH1) &&
+                   (length != MATH2) && (length != MATH3)) {
+                       pr_err("MOVE: MOVE_LEN length must be MATH[0-3]. SEC PC: %d; Instr: %d\n",
+                              program->current_pc,
+                              program->current_instruction);
+                       goto err;
+               }
+
+               opcode = CMD_MOVE_LEN;
+               is_move_len_cmd = true;
+       } else {
+               opcode = CMD_MOVE;
+       }
+
+       /* write offset first, to check for invalid combinations or incorrect
+        * offset values sooner; decide which offset should be here
+        * (src or dst)
+        */
+       ret = set_move_offset(program, src, src_offset, dst, dst_offset,
+                             &offset, &opt);
+       if (ret < 0)
+               goto err;
+
+       opcode |= (offset << MOVE_OFFSET_SHIFT) & MOVE_OFFSET_MASK;
+
+       /* set AUX field if required */
+       if (opt == MOVE_SET_AUX_SRC) {
+               opcode |= ((src_offset / 16) << MOVE_AUX_SHIFT) & MOVE_AUX_MASK;
+       } else if (opt == MOVE_SET_AUX_DST) {
+               opcode |= ((dst_offset / 16) << MOVE_AUX_SHIFT) & MOVE_AUX_MASK;
+       } else if (opt == MOVE_SET_AUX_LS) {
+               opcode |= MOVE_AUX_LS;
+       } else if (opt & MOVE_SET_AUX_MATH) {
+               if (opt & MOVE_SET_AUX_SRC)
+                       offset = src_offset;
+               else
+                       offset = dst_offset;
+
+               if (rta_sec_era < RTA_SEC_ERA_6) {
+                       if (offset)
+                               pr_debug("MOVE: Offset not supported by SEC Era %d. SEC PC: %d; Instr: %d\n",
+                                        USER_SEC_ERA(rta_sec_era),
+                                        program->current_pc,
+                                        program->current_instruction);
+                       /* nothing to do for offset = 0 */
+               } else {
+                       ret = math_offset(offset);
+                       if (ret < 0) {
+                               pr_err("MOVE: Invalid offset in MATH register. SEC PC: %d; Instr: %d\n",
+                                      program->current_pc,
+                                      program->current_instruction);
+                               goto err;
+                       }
+
+                       opcode |= (uint32_t)ret;
+               }
+       }
+
+       /* write source field */
+       ret = __rta_map_opcode((uint32_t)src, move_src_table,
+                              move_src_table_sz[rta_sec_era], &val);
+       if (ret < 0) {
+               pr_err("MOVE: Invalid SRC. SEC PC: %d; Instr: %d\n",
+                      program->current_pc, program->current_instruction);
+               goto err;
+       }
+       opcode |= val;
+
+       /* write destination field */
+       ret = __rta_map_opcode((uint32_t)dst, move_dst_table,
+                              move_dst_table_sz[rta_sec_era], &val);
+       if (ret < 0) {
+               pr_err("MOVE: Invalid DST. SEC PC: %d; Instr: %d\n",
+                      program->current_pc, program->current_instruction);
+               goto err;
+       }
+       opcode |= val;
+
+       /* write flags */
+       if (flags & (FLUSH1 | FLUSH2))
+               opcode |= MOVE_AUX_MS;
+       if (flags & (LAST2 | LAST1))
+               opcode |= MOVE_AUX_LS;
+       if (flags & WAITCOMP)
+               opcode |= MOVE_WAITCOMP;
+
+       if (!is_move_len_cmd) {
+               /* write length */
+               if (opt == MOVE_SET_LEN_16b)
+                       opcode |= (length & (MOVE_OFFSET_MASK | MOVE_LEN_MASK));
+               else
+                       opcode |= (length & MOVE_LEN_MASK);
+       } else {
+               /* write mrsel */
+               switch (length) {
+               case (MATH0):
+                       /*
+                        * opcode |= MOVELEN_MRSEL_MATH0;
+                        * MOVELEN_MRSEL_MATH0 is 0
+                        */
+                       break;
+               case (MATH1):
+                       opcode |= MOVELEN_MRSEL_MATH1;
+                       break;
+               case (MATH2):
+                       opcode |= MOVELEN_MRSEL_MATH2;
+                       break;
+               case (MATH3):
+                       opcode |= MOVELEN_MRSEL_MATH3;
+                       break;
+               }
+
+               /* write size */
+               if (rta_sec_era >= RTA_SEC_ERA_7) {
+                       if (flags & SIZE_WORD)
+                               opcode |= MOVELEN_SIZE_WORD;
+                       else if (flags & SIZE_BYTE)
+                               opcode |= MOVELEN_SIZE_BYTE;
+                       else if (flags & SIZE_DWORD)
+                               opcode |= MOVELEN_SIZE_DWORD;
+               }
+       }
+
+       __rta_out32(program, opcode);
+       program->current_instruction++;
+
+       return (int)start_pc;
+
+ err:
+       program->first_error_pc = start_pc;
+       program->current_instruction++;
+       return ret;
+}
+
+static inline int
+set_move_offset(struct program *program __maybe_unused,
+               uint64_t src, uint16_t src_offset,
+               uint64_t dst, uint16_t dst_offset,
+               uint16_t *offset, uint16_t *opt)
+{
+       switch (src) {
+       case (CONTEXT1):
+       case (CONTEXT2):
+               if (dst == DESCBUF) {
+                       *opt = MOVE_SET_AUX_SRC;
+                       *offset = dst_offset;
+               } else if ((dst == KEY1) || (dst == KEY2)) {
+                       if ((src_offset) && (dst_offset)) {
+                               pr_err("MOVE: Bad offset. SEC PC: %d; Instr: %d\n",
+                                      program->current_pc,
+                                      program->current_instruction);
+                               goto err;
+                       }
+                       if (dst_offset) {
+                               *opt = MOVE_SET_AUX_LS;
+                               *offset = dst_offset;
+                       } else {
+                               *offset = src_offset;
+                       }
+               } else {
+                       if ((dst == MATH0) || (dst == MATH1) ||
+                           (dst == MATH2) || (dst == MATH3)) {
+                               *opt = MOVE_SET_AUX_MATH_DST;
+                       } else if (((dst == OFIFO) || (dst == ALTSOURCE)) &&
+                           (src_offset % 4)) {
+                               pr_err("MOVE: Bad offset alignment. SEC PC: %d; Instr: %d\n",
+                                      program->current_pc,
+                                      program->current_instruction);
+                               goto err;
+                       }
+
+                       *offset = src_offset;
+               }
+               break;
+
+       case (OFIFO):
+               if (dst == OFIFO) {
+                       pr_err("MOVE: Invalid DST. SEC PC: %d; Instr: %d\n",
+                              program->current_pc,
+                              program->current_instruction);
+                       goto err;
+               }
+               if (((dst == IFIFOAB1) || (dst == IFIFOAB2) ||
+                    (dst == IFIFO) || (dst == PKA)) &&
+                   (src_offset || dst_offset)) {
+                       pr_err("MOVE: Offset should be zero. SEC PC: %d; Instr: %d\n",
+                              program->current_pc,
+                              program->current_instruction);
+                       goto err;
+               }
+               *offset = dst_offset;
+               break;
+
+       case (DESCBUF):
+               if ((dst == CONTEXT1) || (dst == CONTEXT2)) {
+                       *opt = MOVE_SET_AUX_DST;
+               } else if ((dst == MATH0) || (dst == MATH1) ||
+                          (dst == MATH2) || (dst == MATH3)) {
+                       *opt = MOVE_SET_AUX_MATH_DST;
+               } else if (dst == DESCBUF) {
+                       pr_err("MOVE: Invalid DST. SEC PC: %d; Instr: %d\n",
+                              program->current_pc,
+                              program->current_instruction);
+                       goto err;
+               } else if (((dst == OFIFO) || (dst == ALTSOURCE)) &&
+                   (src_offset % 4)) {
+                       pr_err("MOVE: Invalid offset alignment. SEC PC: %d; Instr %d\n",
+                              program->current_pc,
+                              program->current_instruction);
+                       goto err;
+               }
+
+               *offset = src_offset;
+               break;
+
+       case (MATH0):
+       case (MATH1):
+       case (MATH2):
+       case (MATH3):
+               if ((dst == OFIFO) || (dst == ALTSOURCE)) {
+                       if (src_offset % 4) {
+                               pr_err("MOVE: Bad offset alignment. SEC PC: %d; Instr: %d\n",
+                                      program->current_pc,
+                                      program->current_instruction);
+                               goto err;
+                       }
+                       *offset = src_offset;
+               } else if ((dst == IFIFOAB1) || (dst == IFIFOAB2) ||
+                          (dst == IFIFO) || (dst == PKA)) {
+                       *offset = src_offset;
+               } else {
+                       *offset = dst_offset;
+
+                       /*
+                        * This condition is basically the negation of:
+                        * dst in { CONTEXT[1-2], MATH[0-3] }
+                        */
+                       if ((dst != KEY1) && (dst != KEY2))
+                               *opt = MOVE_SET_AUX_MATH_SRC;
+               }
+               break;
+
+       case (IFIFOABD):
+       case (IFIFOAB1):
+       case (IFIFOAB2):
+       case (ABD):
+       case (AB1):
+       case (AB2):
+               if ((dst == IFIFOAB1) || (dst == IFIFOAB2) ||
+                   (dst == IFIFO) || (dst == PKA) || (dst == ALTSOURCE)) {
+                       pr_err("MOVE: Bad DST. SEC PC: %d; Instr: %d\n",
+                              program->current_pc,
+                              program->current_instruction);
+                       goto err;
+               } else {
+                       if (dst == OFIFO) {
+                               *opt = MOVE_SET_LEN_16b;
+                       } else {
+                               if (dst_offset % 4) {
+                                       pr_err("MOVE: Bad offset alignment. SEC PC: %d; Instr: %d\n",
+                                              program->current_pc,
+                                              program->current_instruction);
+                                       goto err;
+                               }
+                               *offset = dst_offset;
+                       }
+               }
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+ err:
+       return -EINVAL;
+}
+
+static inline int
+math_offset(uint16_t offset)
+{
+       switch (offset) {
+       case 0:
+               return 0;
+       case 4:
+               return MOVE_AUX_LS;
+       case 6:
+               return MOVE_AUX_MS;
+       case 7:
+               return MOVE_AUX_LS | MOVE_AUX_MS;
+       }
+
+       return -EINVAL;
+}
+
+#endif /* __RTA_MOVE_CMD_H__ */