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