3b9ba792daa0ce8e833b7f8e2ba54d6605316a03
[deb_dpdk.git] / drivers / crypto / dpaa2_sec / hw / rta / move_cmd.h
1 /*-
2  * This file is provided under a dual BSD/GPLv2 license. When using or
3  * redistributing this file, you may do so under either license.
4  *
5  *   BSD LICENSE
6  *
7  * Copyright 2008-2016 Freescale Semiconductor Inc.
8  * Copyright 2016 NXP.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the distribution.
17  * * Neither the name of the above-listed copyright holders nor the
18  * names of any contributors may be used to endorse or promote products
19  * derived from this software without specific prior written permission.
20  *
21  *   GPL LICENSE SUMMARY
22  *
23  * ALTERNATIVELY, this software may be distributed under the terms of the
24  * GNU General Public License ("GPL") as published by the Free Software
25  * Foundation, either version 2 of that License or (at your option) any
26  * later version.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
32  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  */
40
41 #ifndef __RTA_MOVE_CMD_H__
42 #define __RTA_MOVE_CMD_H__
43
44 #define MOVE_SET_AUX_SRC        0x01
45 #define MOVE_SET_AUX_DST        0x02
46 #define MOVE_SET_AUX_LS         0x03
47 #define MOVE_SET_LEN_16b        0x04
48
49 #define MOVE_SET_AUX_MATH       0x10
50 #define MOVE_SET_AUX_MATH_SRC   (MOVE_SET_AUX_SRC | MOVE_SET_AUX_MATH)
51 #define MOVE_SET_AUX_MATH_DST   (MOVE_SET_AUX_DST | MOVE_SET_AUX_MATH)
52
53 #define MASK_16b  0xFF
54
55 /* MOVE command type */
56 #define __MOVE          1
57 #define __MOVEB         2
58 #define __MOVEDW        3
59
60 extern enum rta_sec_era rta_sec_era;
61
62 static const uint32_t move_src_table[][2] = {
63 /*1*/   { CONTEXT1, MOVE_SRC_CLASS1CTX },
64         { CONTEXT2, MOVE_SRC_CLASS2CTX },
65         { OFIFO,    MOVE_SRC_OUTFIFO },
66         { DESCBUF,  MOVE_SRC_DESCBUF },
67         { MATH0,    MOVE_SRC_MATH0 },
68         { MATH1,    MOVE_SRC_MATH1 },
69         { MATH2,    MOVE_SRC_MATH2 },
70         { MATH3,    MOVE_SRC_MATH3 },
71 /*9*/   { IFIFOABD, MOVE_SRC_INFIFO },
72         { IFIFOAB1, MOVE_SRC_INFIFO_CL | MOVE_AUX_LS },
73         { IFIFOAB2, MOVE_SRC_INFIFO_CL },
74 /*12*/  { ABD,      MOVE_SRC_INFIFO_NO_NFIFO },
75         { AB1,      MOVE_SRC_INFIFO_NO_NFIFO | MOVE_AUX_LS },
76         { AB2,      MOVE_SRC_INFIFO_NO_NFIFO | MOVE_AUX_MS }
77 };
78
79 /* Allowed MOVE / MOVE_LEN sources for each SEC Era.
80  * Values represent the number of entries from move_src_table[] that are
81  * supported.
82  */
83 static const unsigned int move_src_table_sz[] = {9, 11, 14, 14, 14, 14, 14, 14};
84
85 static const uint32_t move_dst_table[][2] = {
86 /*1*/   { CONTEXT1,  MOVE_DEST_CLASS1CTX },
87         { CONTEXT2,  MOVE_DEST_CLASS2CTX },
88         { OFIFO,     MOVE_DEST_OUTFIFO },
89         { DESCBUF,   MOVE_DEST_DESCBUF },
90         { MATH0,     MOVE_DEST_MATH0 },
91         { MATH1,     MOVE_DEST_MATH1 },
92         { MATH2,     MOVE_DEST_MATH2 },
93         { MATH3,     MOVE_DEST_MATH3 },
94         { IFIFOAB1,  MOVE_DEST_CLASS1INFIFO },
95         { IFIFOAB2,  MOVE_DEST_CLASS2INFIFO },
96         { PKA,       MOVE_DEST_PK_A },
97         { KEY1,      MOVE_DEST_CLASS1KEY },
98         { KEY2,      MOVE_DEST_CLASS2KEY },
99 /*14*/  { IFIFO,     MOVE_DEST_INFIFO },
100 /*15*/  { ALTSOURCE,  MOVE_DEST_ALTSOURCE}
101 };
102
103 /* Allowed MOVE / MOVE_LEN destinations for each SEC Era.
104  * Values represent the number of entries from move_dst_table[] that are
105  * supported.
106  */
107 static const
108 unsigned int move_dst_table_sz[] = {13, 14, 14, 15, 15, 15, 15, 15};
109
110 static inline int
111 set_move_offset(struct program *program __maybe_unused,
112                 uint64_t src, uint16_t src_offset,
113                 uint64_t dst, uint16_t dst_offset,
114                 uint16_t *offset, uint16_t *opt);
115
116 static inline int
117 math_offset(uint16_t offset);
118
119 static inline int
120 rta_move(struct program *program, int cmd_type, uint64_t src,
121          uint16_t src_offset, uint64_t dst,
122          uint16_t dst_offset, uint32_t length, uint32_t flags)
123 {
124         uint32_t opcode = 0;
125         uint16_t offset = 0, opt = 0;
126         uint32_t val = 0;
127         int ret = -EINVAL;
128         bool is_move_len_cmd = false;
129         unsigned int start_pc = program->current_pc;
130
131         if ((rta_sec_era < RTA_SEC_ERA_7) && (cmd_type != __MOVE)) {
132                 pr_err("MOVE: MOVEB / MOVEDW not supported by SEC Era %d. SEC PC: %d; Instr: %d\n",
133                        USER_SEC_ERA(rta_sec_era), program->current_pc,
134                        program->current_instruction);
135                 goto err;
136         }
137
138         /* write command type */
139         if (cmd_type == __MOVEB) {
140                 opcode = CMD_MOVEB;
141         } else if (cmd_type == __MOVEDW) {
142                 opcode = CMD_MOVEDW;
143         } else if (!(flags & IMMED)) {
144                 if (rta_sec_era < RTA_SEC_ERA_3) {
145                         pr_err("MOVE: MOVE_LEN not supported by SEC Era %d. SEC PC: %d; Instr: %d\n",
146                                USER_SEC_ERA(rta_sec_era), program->current_pc,
147                                program->current_instruction);
148                         goto err;
149                 }
150
151                 if ((length != MATH0) && (length != MATH1) &&
152                     (length != MATH2) && (length != MATH3)) {
153                         pr_err("MOVE: MOVE_LEN length must be MATH[0-3]. SEC PC: %d; Instr: %d\n",
154                                program->current_pc,
155                                program->current_instruction);
156                         goto err;
157                 }
158
159                 opcode = CMD_MOVE_LEN;
160                 is_move_len_cmd = true;
161         } else {
162                 opcode = CMD_MOVE;
163         }
164
165         /* write offset first, to check for invalid combinations or incorrect
166          * offset values sooner; decide which offset should be here
167          * (src or dst)
168          */
169         ret = set_move_offset(program, src, src_offset, dst, dst_offset,
170                               &offset, &opt);
171         if (ret < 0)
172                 goto err;
173
174         opcode |= (offset << MOVE_OFFSET_SHIFT) & MOVE_OFFSET_MASK;
175
176         /* set AUX field if required */
177         if (opt == MOVE_SET_AUX_SRC) {
178                 opcode |= ((src_offset / 16) << MOVE_AUX_SHIFT) & MOVE_AUX_MASK;
179         } else if (opt == MOVE_SET_AUX_DST) {
180                 opcode |= ((dst_offset / 16) << MOVE_AUX_SHIFT) & MOVE_AUX_MASK;
181         } else if (opt == MOVE_SET_AUX_LS) {
182                 opcode |= MOVE_AUX_LS;
183         } else if (opt & MOVE_SET_AUX_MATH) {
184                 if (opt & MOVE_SET_AUX_SRC)
185                         offset = src_offset;
186                 else
187                         offset = dst_offset;
188
189                 if (rta_sec_era < RTA_SEC_ERA_6) {
190                         if (offset)
191                                 pr_debug("MOVE: Offset not supported by SEC Era %d. SEC PC: %d; Instr: %d\n",
192                                          USER_SEC_ERA(rta_sec_era),
193                                          program->current_pc,
194                                          program->current_instruction);
195                         /* nothing to do for offset = 0 */
196                 } else {
197                         ret = math_offset(offset);
198                         if (ret < 0) {
199                                 pr_err("MOVE: Invalid offset in MATH register. SEC PC: %d; Instr: %d\n",
200                                        program->current_pc,
201                                        program->current_instruction);
202                                 goto err;
203                         }
204
205                         opcode |= (uint32_t)ret;
206                 }
207         }
208
209         /* write source field */
210         ret = __rta_map_opcode((uint32_t)src, move_src_table,
211                                move_src_table_sz[rta_sec_era], &val);
212         if (ret < 0) {
213                 pr_err("MOVE: Invalid SRC. SEC PC: %d; Instr: %d\n",
214                        program->current_pc, program->current_instruction);
215                 goto err;
216         }
217         opcode |= val;
218
219         /* write destination field */
220         ret = __rta_map_opcode((uint32_t)dst, move_dst_table,
221                                move_dst_table_sz[rta_sec_era], &val);
222         if (ret < 0) {
223                 pr_err("MOVE: Invalid DST. SEC PC: %d; Instr: %d\n",
224                        program->current_pc, program->current_instruction);
225                 goto err;
226         }
227         opcode |= val;
228
229         /* write flags */
230         if (flags & (FLUSH1 | FLUSH2))
231                 opcode |= MOVE_AUX_MS;
232         if (flags & (LAST2 | LAST1))
233                 opcode |= MOVE_AUX_LS;
234         if (flags & WAITCOMP)
235                 opcode |= MOVE_WAITCOMP;
236
237         if (!is_move_len_cmd) {
238                 /* write length */
239                 if (opt == MOVE_SET_LEN_16b)
240                         opcode |= (length & (MOVE_OFFSET_MASK | MOVE_LEN_MASK));
241                 else
242                         opcode |= (length & MOVE_LEN_MASK);
243         } else {
244                 /* write mrsel */
245                 switch (length) {
246                 case (MATH0):
247                         /*
248                          * opcode |= MOVELEN_MRSEL_MATH0;
249                          * MOVELEN_MRSEL_MATH0 is 0
250                          */
251                         break;
252                 case (MATH1):
253                         opcode |= MOVELEN_MRSEL_MATH1;
254                         break;
255                 case (MATH2):
256                         opcode |= MOVELEN_MRSEL_MATH2;
257                         break;
258                 case (MATH3):
259                         opcode |= MOVELEN_MRSEL_MATH3;
260                         break;
261                 }
262
263                 /* write size */
264                 if (rta_sec_era >= RTA_SEC_ERA_7) {
265                         if (flags & SIZE_WORD)
266                                 opcode |= MOVELEN_SIZE_WORD;
267                         else if (flags & SIZE_BYTE)
268                                 opcode |= MOVELEN_SIZE_BYTE;
269                         else if (flags & SIZE_DWORD)
270                                 opcode |= MOVELEN_SIZE_DWORD;
271                 }
272         }
273
274         __rta_out32(program, opcode);
275         program->current_instruction++;
276
277         return (int)start_pc;
278
279  err:
280         program->first_error_pc = start_pc;
281         program->current_instruction++;
282         return ret;
283 }
284
285 static inline int
286 set_move_offset(struct program *program __maybe_unused,
287                 uint64_t src, uint16_t src_offset,
288                 uint64_t dst, uint16_t dst_offset,
289                 uint16_t *offset, uint16_t *opt)
290 {
291         switch (src) {
292         case (CONTEXT1):
293         case (CONTEXT2):
294                 if (dst == DESCBUF) {
295                         *opt = MOVE_SET_AUX_SRC;
296                         *offset = dst_offset;
297                 } else if ((dst == KEY1) || (dst == KEY2)) {
298                         if ((src_offset) && (dst_offset)) {
299                                 pr_err("MOVE: Bad offset. SEC PC: %d; Instr: %d\n",
300                                        program->current_pc,
301                                        program->current_instruction);
302                                 goto err;
303                         }
304                         if (dst_offset) {
305                                 *opt = MOVE_SET_AUX_LS;
306                                 *offset = dst_offset;
307                         } else {
308                                 *offset = src_offset;
309                         }
310                 } else {
311                         if ((dst == MATH0) || (dst == MATH1) ||
312                             (dst == MATH2) || (dst == MATH3)) {
313                                 *opt = MOVE_SET_AUX_MATH_DST;
314                         } else if (((dst == OFIFO) || (dst == ALTSOURCE)) &&
315                             (src_offset % 4)) {
316                                 pr_err("MOVE: Bad offset alignment. SEC PC: %d; Instr: %d\n",
317                                        program->current_pc,
318                                        program->current_instruction);
319                                 goto err;
320                         }
321
322                         *offset = src_offset;
323                 }
324                 break;
325
326         case (OFIFO):
327                 if (dst == OFIFO) {
328                         pr_err("MOVE: Invalid DST. SEC PC: %d; Instr: %d\n",
329                                program->current_pc,
330                                program->current_instruction);
331                         goto err;
332                 }
333                 if (((dst == IFIFOAB1) || (dst == IFIFOAB2) ||
334                      (dst == IFIFO) || (dst == PKA)) &&
335                     (src_offset || dst_offset)) {
336                         pr_err("MOVE: Offset should be zero. SEC PC: %d; Instr: %d\n",
337                                program->current_pc,
338                                program->current_instruction);
339                         goto err;
340                 }
341                 *offset = dst_offset;
342                 break;
343
344         case (DESCBUF):
345                 if ((dst == CONTEXT1) || (dst == CONTEXT2)) {
346                         *opt = MOVE_SET_AUX_DST;
347                 } else if ((dst == MATH0) || (dst == MATH1) ||
348                            (dst == MATH2) || (dst == MATH3)) {
349                         *opt = MOVE_SET_AUX_MATH_DST;
350                 } else if (dst == DESCBUF) {
351                         pr_err("MOVE: Invalid DST. SEC PC: %d; Instr: %d\n",
352                                program->current_pc,
353                                program->current_instruction);
354                         goto err;
355                 } else if (((dst == OFIFO) || (dst == ALTSOURCE)) &&
356                     (src_offset % 4)) {
357                         pr_err("MOVE: Invalid offset alignment. SEC PC: %d; Instr %d\n",
358                                program->current_pc,
359                                program->current_instruction);
360                         goto err;
361                 }
362
363                 *offset = src_offset;
364                 break;
365
366         case (MATH0):
367         case (MATH1):
368         case (MATH2):
369         case (MATH3):
370                 if ((dst == OFIFO) || (dst == ALTSOURCE)) {
371                         if (src_offset % 4) {
372                                 pr_err("MOVE: Bad offset alignment. SEC PC: %d; Instr: %d\n",
373                                        program->current_pc,
374                                        program->current_instruction);
375                                 goto err;
376                         }
377                         *offset = src_offset;
378                 } else if ((dst == IFIFOAB1) || (dst == IFIFOAB2) ||
379                            (dst == IFIFO) || (dst == PKA)) {
380                         *offset = src_offset;
381                 } else {
382                         *offset = dst_offset;
383
384                         /*
385                          * This condition is basically the negation of:
386                          * dst in { CONTEXT[1-2], MATH[0-3] }
387                          */
388                         if ((dst != KEY1) && (dst != KEY2))
389                                 *opt = MOVE_SET_AUX_MATH_SRC;
390                 }
391                 break;
392
393         case (IFIFOABD):
394         case (IFIFOAB1):
395         case (IFIFOAB2):
396         case (ABD):
397         case (AB1):
398         case (AB2):
399                 if ((dst == IFIFOAB1) || (dst == IFIFOAB2) ||
400                     (dst == IFIFO) || (dst == PKA) || (dst == ALTSOURCE)) {
401                         pr_err("MOVE: Bad DST. SEC PC: %d; Instr: %d\n",
402                                program->current_pc,
403                                program->current_instruction);
404                         goto err;
405                 } else {
406                         if (dst == OFIFO) {
407                                 *opt = MOVE_SET_LEN_16b;
408                         } else {
409                                 if (dst_offset % 4) {
410                                         pr_err("MOVE: Bad offset alignment. SEC PC: %d; Instr: %d\n",
411                                                program->current_pc,
412                                                program->current_instruction);
413                                         goto err;
414                                 }
415                                 *offset = dst_offset;
416                         }
417                 }
418                 break;
419         default:
420                 break;
421         }
422
423         return 0;
424  err:
425         return -EINVAL;
426 }
427
428 static inline int
429 math_offset(uint16_t offset)
430 {
431         switch (offset) {
432         case 0:
433                 return 0;
434         case 4:
435                 return MOVE_AUX_LS;
436         case 6:
437                 return MOVE_AUX_MS;
438         case 7:
439                 return MOVE_AUX_LS | MOVE_AUX_MS;
440         }
441
442         return -EINVAL;
443 }
444
445 #endif /* __RTA_MOVE_CMD_H__ */