New upstream version 18.02
[deb_dpdk.git] / drivers / crypto / dpaa2_sec / hw / rta / move_cmd.h
1 /* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
2  *
3  * Copyright 2008-2016 Freescale Semiconductor Inc.
4  * Copyright 2016 NXP
5  *
6  */
7
8 #ifndef __RTA_MOVE_CMD_H__
9 #define __RTA_MOVE_CMD_H__
10
11 #define MOVE_SET_AUX_SRC        0x01
12 #define MOVE_SET_AUX_DST        0x02
13 #define MOVE_SET_AUX_LS         0x03
14 #define MOVE_SET_LEN_16b        0x04
15
16 #define MOVE_SET_AUX_MATH       0x10
17 #define MOVE_SET_AUX_MATH_SRC   (MOVE_SET_AUX_SRC | MOVE_SET_AUX_MATH)
18 #define MOVE_SET_AUX_MATH_DST   (MOVE_SET_AUX_DST | MOVE_SET_AUX_MATH)
19
20 #define MASK_16b  0xFF
21
22 /* MOVE command type */
23 #define __MOVE          1
24 #define __MOVEB         2
25 #define __MOVEDW        3
26
27 extern enum rta_sec_era rta_sec_era;
28
29 static const uint32_t move_src_table[][2] = {
30 /*1*/   { CONTEXT1, MOVE_SRC_CLASS1CTX },
31         { CONTEXT2, MOVE_SRC_CLASS2CTX },
32         { OFIFO,    MOVE_SRC_OUTFIFO },
33         { DESCBUF,  MOVE_SRC_DESCBUF },
34         { MATH0,    MOVE_SRC_MATH0 },
35         { MATH1,    MOVE_SRC_MATH1 },
36         { MATH2,    MOVE_SRC_MATH2 },
37         { MATH3,    MOVE_SRC_MATH3 },
38 /*9*/   { IFIFOABD, MOVE_SRC_INFIFO },
39         { IFIFOAB1, MOVE_SRC_INFIFO_CL | MOVE_AUX_LS },
40         { IFIFOAB2, MOVE_SRC_INFIFO_CL },
41 /*12*/  { ABD,      MOVE_SRC_INFIFO_NO_NFIFO },
42         { AB1,      MOVE_SRC_INFIFO_NO_NFIFO | MOVE_AUX_LS },
43         { AB2,      MOVE_SRC_INFIFO_NO_NFIFO | MOVE_AUX_MS }
44 };
45
46 /* Allowed MOVE / MOVE_LEN sources for each SEC Era.
47  * Values represent the number of entries from move_src_table[] that are
48  * supported.
49  */
50 static const unsigned int move_src_table_sz[] = {9, 11, 14, 14, 14, 14, 14, 14};
51
52 static const uint32_t move_dst_table[][2] = {
53 /*1*/   { CONTEXT1,  MOVE_DEST_CLASS1CTX },
54         { CONTEXT2,  MOVE_DEST_CLASS2CTX },
55         { OFIFO,     MOVE_DEST_OUTFIFO },
56         { DESCBUF,   MOVE_DEST_DESCBUF },
57         { MATH0,     MOVE_DEST_MATH0 },
58         { MATH1,     MOVE_DEST_MATH1 },
59         { MATH2,     MOVE_DEST_MATH2 },
60         { MATH3,     MOVE_DEST_MATH3 },
61         { IFIFOAB1,  MOVE_DEST_CLASS1INFIFO },
62         { IFIFOAB2,  MOVE_DEST_CLASS2INFIFO },
63         { PKA,       MOVE_DEST_PK_A },
64         { KEY1,      MOVE_DEST_CLASS1KEY },
65         { KEY2,      MOVE_DEST_CLASS2KEY },
66 /*14*/  { IFIFO,     MOVE_DEST_INFIFO },
67 /*15*/  { ALTSOURCE,  MOVE_DEST_ALTSOURCE}
68 };
69
70 /* Allowed MOVE / MOVE_LEN destinations for each SEC Era.
71  * Values represent the number of entries from move_dst_table[] that are
72  * supported.
73  */
74 static const
75 unsigned int move_dst_table_sz[] = {13, 14, 14, 15, 15, 15, 15, 15};
76
77 static inline int
78 set_move_offset(struct program *program __maybe_unused,
79                 uint64_t src, uint16_t src_offset,
80                 uint64_t dst, uint16_t dst_offset,
81                 uint16_t *offset, uint16_t *opt);
82
83 static inline int
84 math_offset(uint16_t offset);
85
86 static inline int
87 rta_move(struct program *program, int cmd_type, uint64_t src,
88          uint16_t src_offset, uint64_t dst,
89          uint16_t dst_offset, uint32_t length, uint32_t flags)
90 {
91         uint32_t opcode = 0;
92         uint16_t offset = 0, opt = 0;
93         uint32_t val = 0;
94         int ret = -EINVAL;
95         bool is_move_len_cmd = false;
96         unsigned int start_pc = program->current_pc;
97
98         if ((rta_sec_era < RTA_SEC_ERA_7) && (cmd_type != __MOVE)) {
99                 pr_err("MOVE: MOVEB / MOVEDW not supported by SEC Era %d. SEC PC: %d; Instr: %d\n",
100                        USER_SEC_ERA(rta_sec_era), program->current_pc,
101                        program->current_instruction);
102                 goto err;
103         }
104
105         /* write command type */
106         if (cmd_type == __MOVEB) {
107                 opcode = CMD_MOVEB;
108         } else if (cmd_type == __MOVEDW) {
109                 opcode = CMD_MOVEDW;
110         } else if (!(flags & IMMED)) {
111                 if (rta_sec_era < RTA_SEC_ERA_3) {
112                         pr_err("MOVE: MOVE_LEN not supported by SEC Era %d. SEC PC: %d; Instr: %d\n",
113                                USER_SEC_ERA(rta_sec_era), program->current_pc,
114                                program->current_instruction);
115                         goto err;
116                 }
117
118                 if ((length != MATH0) && (length != MATH1) &&
119                     (length != MATH2) && (length != MATH3)) {
120                         pr_err("MOVE: MOVE_LEN length must be MATH[0-3]. SEC PC: %d; Instr: %d\n",
121                                program->current_pc,
122                                program->current_instruction);
123                         goto err;
124                 }
125
126                 opcode = CMD_MOVE_LEN;
127                 is_move_len_cmd = true;
128         } else {
129                 opcode = CMD_MOVE;
130         }
131
132         /* write offset first, to check for invalid combinations or incorrect
133          * offset values sooner; decide which offset should be here
134          * (src or dst)
135          */
136         ret = set_move_offset(program, src, src_offset, dst, dst_offset,
137                               &offset, &opt);
138         if (ret < 0)
139                 goto err;
140
141         opcode |= (offset << MOVE_OFFSET_SHIFT) & MOVE_OFFSET_MASK;
142
143         /* set AUX field if required */
144         if (opt == MOVE_SET_AUX_SRC) {
145                 opcode |= ((src_offset / 16) << MOVE_AUX_SHIFT) & MOVE_AUX_MASK;
146         } else if (opt == MOVE_SET_AUX_DST) {
147                 opcode |= ((dst_offset / 16) << MOVE_AUX_SHIFT) & MOVE_AUX_MASK;
148         } else if (opt == MOVE_SET_AUX_LS) {
149                 opcode |= MOVE_AUX_LS;
150         } else if (opt & MOVE_SET_AUX_MATH) {
151                 if (opt & MOVE_SET_AUX_SRC)
152                         offset = src_offset;
153                 else
154                         offset = dst_offset;
155
156                 if (rta_sec_era < RTA_SEC_ERA_6) {
157                         if (offset)
158                                 pr_debug("MOVE: Offset not supported by SEC Era %d. SEC PC: %d; Instr: %d\n",
159                                          USER_SEC_ERA(rta_sec_era),
160                                          program->current_pc,
161                                          program->current_instruction);
162                         /* nothing to do for offset = 0 */
163                 } else {
164                         ret = math_offset(offset);
165                         if (ret < 0) {
166                                 pr_err("MOVE: Invalid offset in MATH register. SEC PC: %d; Instr: %d\n",
167                                        program->current_pc,
168                                        program->current_instruction);
169                                 goto err;
170                         }
171
172                         opcode |= (uint32_t)ret;
173                 }
174         }
175
176         /* write source field */
177         ret = __rta_map_opcode((uint32_t)src, move_src_table,
178                                move_src_table_sz[rta_sec_era], &val);
179         if (ret < 0) {
180                 pr_err("MOVE: Invalid SRC. SEC PC: %d; Instr: %d\n",
181                        program->current_pc, program->current_instruction);
182                 goto err;
183         }
184         opcode |= val;
185
186         /* write destination field */
187         ret = __rta_map_opcode((uint32_t)dst, move_dst_table,
188                                move_dst_table_sz[rta_sec_era], &val);
189         if (ret < 0) {
190                 pr_err("MOVE: Invalid DST. SEC PC: %d; Instr: %d\n",
191                        program->current_pc, program->current_instruction);
192                 goto err;
193         }
194         opcode |= val;
195
196         /* write flags */
197         if (flags & (FLUSH1 | FLUSH2))
198                 opcode |= MOVE_AUX_MS;
199         if (flags & (LAST2 | LAST1))
200                 opcode |= MOVE_AUX_LS;
201         if (flags & WAITCOMP)
202                 opcode |= MOVE_WAITCOMP;
203
204         if (!is_move_len_cmd) {
205                 /* write length */
206                 if (opt == MOVE_SET_LEN_16b)
207                         opcode |= (length & (MOVE_OFFSET_MASK | MOVE_LEN_MASK));
208                 else
209                         opcode |= (length & MOVE_LEN_MASK);
210         } else {
211                 /* write mrsel */
212                 switch (length) {
213                 case (MATH0):
214                         /*
215                          * opcode |= MOVELEN_MRSEL_MATH0;
216                          * MOVELEN_MRSEL_MATH0 is 0
217                          */
218                         break;
219                 case (MATH1):
220                         opcode |= MOVELEN_MRSEL_MATH1;
221                         break;
222                 case (MATH2):
223                         opcode |= MOVELEN_MRSEL_MATH2;
224                         break;
225                 case (MATH3):
226                         opcode |= MOVELEN_MRSEL_MATH3;
227                         break;
228                 }
229
230                 /* write size */
231                 if (rta_sec_era >= RTA_SEC_ERA_7) {
232                         if (flags & SIZE_WORD)
233                                 opcode |= MOVELEN_SIZE_WORD;
234                         else if (flags & SIZE_BYTE)
235                                 opcode |= MOVELEN_SIZE_BYTE;
236                         else if (flags & SIZE_DWORD)
237                                 opcode |= MOVELEN_SIZE_DWORD;
238                 }
239         }
240
241         __rta_out32(program, opcode);
242         program->current_instruction++;
243
244         return (int)start_pc;
245
246  err:
247         program->first_error_pc = start_pc;
248         program->current_instruction++;
249         return ret;
250 }
251
252 static inline int
253 set_move_offset(struct program *program __maybe_unused,
254                 uint64_t src, uint16_t src_offset,
255                 uint64_t dst, uint16_t dst_offset,
256                 uint16_t *offset, uint16_t *opt)
257 {
258         switch (src) {
259         case (CONTEXT1):
260         case (CONTEXT2):
261                 if (dst == DESCBUF) {
262                         *opt = MOVE_SET_AUX_SRC;
263                         *offset = dst_offset;
264                 } else if ((dst == KEY1) || (dst == KEY2)) {
265                         if ((src_offset) && (dst_offset)) {
266                                 pr_err("MOVE: Bad offset. SEC PC: %d; Instr: %d\n",
267                                        program->current_pc,
268                                        program->current_instruction);
269                                 goto err;
270                         }
271                         if (dst_offset) {
272                                 *opt = MOVE_SET_AUX_LS;
273                                 *offset = dst_offset;
274                         } else {
275                                 *offset = src_offset;
276                         }
277                 } else {
278                         if ((dst == MATH0) || (dst == MATH1) ||
279                             (dst == MATH2) || (dst == MATH3)) {
280                                 *opt = MOVE_SET_AUX_MATH_DST;
281                         } else if (((dst == OFIFO) || (dst == ALTSOURCE)) &&
282                             (src_offset % 4)) {
283                                 pr_err("MOVE: Bad offset alignment. SEC PC: %d; Instr: %d\n",
284                                        program->current_pc,
285                                        program->current_instruction);
286                                 goto err;
287                         }
288
289                         *offset = src_offset;
290                 }
291                 break;
292
293         case (OFIFO):
294                 if (dst == OFIFO) {
295                         pr_err("MOVE: Invalid DST. SEC PC: %d; Instr: %d\n",
296                                program->current_pc,
297                                program->current_instruction);
298                         goto err;
299                 }
300                 if (((dst == IFIFOAB1) || (dst == IFIFOAB2) ||
301                      (dst == IFIFO) || (dst == PKA)) &&
302                     (src_offset || dst_offset)) {
303                         pr_err("MOVE: Offset should be zero. SEC PC: %d; Instr: %d\n",
304                                program->current_pc,
305                                program->current_instruction);
306                         goto err;
307                 }
308                 *offset = dst_offset;
309                 break;
310
311         case (DESCBUF):
312                 if ((dst == CONTEXT1) || (dst == CONTEXT2)) {
313                         *opt = MOVE_SET_AUX_DST;
314                 } else if ((dst == MATH0) || (dst == MATH1) ||
315                            (dst == MATH2) || (dst == MATH3)) {
316                         *opt = MOVE_SET_AUX_MATH_DST;
317                 } else if (dst == DESCBUF) {
318                         pr_err("MOVE: Invalid DST. SEC PC: %d; Instr: %d\n",
319                                program->current_pc,
320                                program->current_instruction);
321                         goto err;
322                 } else if (((dst == OFIFO) || (dst == ALTSOURCE)) &&
323                     (src_offset % 4)) {
324                         pr_err("MOVE: Invalid offset alignment. SEC PC: %d; Instr %d\n",
325                                program->current_pc,
326                                program->current_instruction);
327                         goto err;
328                 }
329
330                 *offset = src_offset;
331                 break;
332
333         case (MATH0):
334         case (MATH1):
335         case (MATH2):
336         case (MATH3):
337                 if ((dst == OFIFO) || (dst == ALTSOURCE)) {
338                         if (src_offset % 4) {
339                                 pr_err("MOVE: Bad offset alignment. SEC PC: %d; Instr: %d\n",
340                                        program->current_pc,
341                                        program->current_instruction);
342                                 goto err;
343                         }
344                         *offset = src_offset;
345                 } else if ((dst == IFIFOAB1) || (dst == IFIFOAB2) ||
346                            (dst == IFIFO) || (dst == PKA)) {
347                         *offset = src_offset;
348                 } else {
349                         *offset = dst_offset;
350
351                         /*
352                          * This condition is basically the negation of:
353                          * dst in { CONTEXT[1-2], MATH[0-3] }
354                          */
355                         if ((dst != KEY1) && (dst != KEY2))
356                                 *opt = MOVE_SET_AUX_MATH_SRC;
357                 }
358                 break;
359
360         case (IFIFOABD):
361         case (IFIFOAB1):
362         case (IFIFOAB2):
363         case (ABD):
364         case (AB1):
365         case (AB2):
366                 if ((dst == IFIFOAB1) || (dst == IFIFOAB2) ||
367                     (dst == IFIFO) || (dst == PKA) || (dst == ALTSOURCE)) {
368                         pr_err("MOVE: Bad DST. SEC PC: %d; Instr: %d\n",
369                                program->current_pc,
370                                program->current_instruction);
371                         goto err;
372                 } else {
373                         if (dst == OFIFO) {
374                                 *opt = MOVE_SET_LEN_16b;
375                         } else {
376                                 if (dst_offset % 4) {
377                                         pr_err("MOVE: Bad offset alignment. SEC PC: %d; Instr: %d\n",
378                                                program->current_pc,
379                                                program->current_instruction);
380                                         goto err;
381                                 }
382                                 *offset = dst_offset;
383                         }
384                 }
385                 break;
386         default:
387                 break;
388         }
389
390         return 0;
391  err:
392         return -EINVAL;
393 }
394
395 static inline int
396 math_offset(uint16_t offset)
397 {
398         switch (offset) {
399         case 0:
400                 return 0;
401         case 4:
402                 return MOVE_AUX_LS;
403         case 6:
404                 return MOVE_AUX_MS;
405         case 7:
406                 return MOVE_AUX_LS | MOVE_AUX_MS;
407         }
408
409         return -EINVAL;
410 }
411
412 #endif /* __RTA_MOVE_CMD_H__ */