Branch data Line data Source code
1 : : /* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
2 : : *
3 : : * Copyright 2008-2016 Freescale Semiconductor Inc.
4 : : * Copyright 2016,2019 NXP
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 : : 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, 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 : 0 : 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 : 0 : uint16_t offset = 0, opt = 0;
93 : : uint32_t val = 0;
94 : : int ret = -EINVAL;
95 : : bool is_move_len_cmd = false;
96 : 0 : unsigned int start_pc = program->current_pc;
97 : :
98 : : /* write command type */
99 [ # # ]: 0 : if (cmd_type == __MOVEB) {
100 : : opcode = CMD_MOVEB;
101 [ # # ]: 0 : } else if (cmd_type == __MOVEDW) {
102 : : opcode = CMD_MOVEDW;
103 [ # # ]: 0 : } else if (!(flags & IMMED)) {
104 : 0 : if ((length != MATH0) && (length != MATH1) &&
105 [ # # ]: 0 : (length != MATH2) && (length != MATH3)) {
106 : 0 : pr_err("MOVE: MOVE_LEN length must be MATH[0-3]. SEC PC: %d; Instr: %d\n",
107 : : program->current_pc,
108 : : program->current_instruction);
109 : 0 : goto err;
110 : : }
111 : :
112 : : opcode = CMD_MOVE_LEN;
113 : : is_move_len_cmd = true;
114 : : } else {
115 : : opcode = CMD_MOVE;
116 : : }
117 : :
118 : : /* write offset first, to check for invalid combinations or incorrect
119 : : * offset values sooner; decide which offset should be here
120 : : * (src or dst)
121 : : */
122 : 0 : ret = set_move_offset(program, src, src_offset, dst, dst_offset,
123 : : &offset, &opt);
124 [ # # ]: 0 : if (ret < 0)
125 : 0 : goto err;
126 : :
127 : 0 : opcode |= (offset << MOVE_OFFSET_SHIFT) & MOVE_OFFSET_MASK;
128 : :
129 : : /* set AUX field if required */
130 [ # # ]: 0 : if (opt == MOVE_SET_AUX_SRC) {
131 : 0 : opcode |= ((src_offset / 16) << MOVE_AUX_SHIFT) & MOVE_AUX_MASK;
132 [ # # ]: 0 : } else if (opt == MOVE_SET_AUX_DST) {
133 : 0 : opcode |= ((dst_offset / 16) << MOVE_AUX_SHIFT) & MOVE_AUX_MASK;
134 [ # # ]: 0 : } else if (opt == MOVE_SET_AUX_LS) {
135 : 0 : opcode |= MOVE_AUX_LS;
136 [ # # ]: 0 : } else if (opt & MOVE_SET_AUX_MATH) {
137 [ # # ]: 0 : if (opt & MOVE_SET_AUX_SRC)
138 : 0 : offset = src_offset;
139 : : else
140 : 0 : offset = dst_offset;
141 : :
142 [ # # ]: 0 : ret = math_offset(offset);
143 [ # # ]: 0 : if (ret < 0) {
144 : 0 : pr_err("MOVE: Invalid offset in MATH register. SEC PC: %d; Instr: %d\n",
145 : : program->current_pc,
146 : : program->current_instruction);
147 : 0 : goto err;
148 : : }
149 : :
150 : 0 : opcode |= (uint32_t)ret;
151 : : }
152 : :
153 : : /* write source field */
154 : 0 : ret = __rta_map_opcode((uint32_t)src, move_src_table,
155 : 0 : move_src_table_sz[rta_sec_era], &val);
156 : : if (ret < 0) {
157 : 0 : pr_err("MOVE: Invalid SRC. SEC PC: %d; Instr: %d\n",
158 : : program->current_pc, program->current_instruction);
159 : 0 : goto err;
160 : : }
161 : 0 : opcode |= val;
162 : :
163 : : /* write destination field */
164 : 0 : ret = __rta_map_opcode((uint32_t)dst, move_dst_table,
165 : 0 : move_dst_table_sz[rta_sec_era], &val);
166 : : if (ret < 0) {
167 : 0 : pr_err("MOVE: Invalid DST. SEC PC: %d; Instr: %d\n",
168 : : program->current_pc, program->current_instruction);
169 : 0 : goto err;
170 : : }
171 : 0 : opcode |= val;
172 : :
173 : : /* write flags */
174 [ # # ]: 0 : if (flags & (FLUSH1 | FLUSH2))
175 : 0 : opcode |= MOVE_AUX_MS;
176 [ # # ]: 0 : if (flags & (LAST2 | LAST1))
177 : 0 : opcode |= MOVE_AUX_LS;
178 [ # # ]: 0 : if (flags & WAITCOMP)
179 : 0 : opcode |= MOVE_WAITCOMP;
180 : :
181 [ # # ]: 0 : if (!is_move_len_cmd) {
182 : : /* write length */
183 [ # # ]: 0 : if (opt == MOVE_SET_LEN_16b)
184 : 0 : opcode |= (length & (MOVE_OFFSET_MASK | MOVE_LEN_MASK));
185 : : else
186 : 0 : opcode |= (length & MOVE_LEN_MASK);
187 : : } else {
188 : : /* write mrsel */
189 [ # # # # ]: 0 : switch (length) {
190 : : case (MATH0):
191 : : /*
192 : : * opcode |= MOVELEN_MRSEL_MATH0;
193 : : * MOVELEN_MRSEL_MATH0 is 0
194 : : */
195 : : break;
196 : 0 : case (MATH1):
197 : 0 : opcode |= MOVELEN_MRSEL_MATH1;
198 : 0 : break;
199 : 0 : case (MATH2):
200 : 0 : opcode |= MOVELEN_MRSEL_MATH2;
201 : 0 : break;
202 : 0 : case (MATH3):
203 : 0 : opcode |= MOVELEN_MRSEL_MATH3;
204 : 0 : break;
205 : : }
206 : :
207 : : /* write size */
208 [ # # ]: 0 : if (rta_sec_era >= RTA_SEC_ERA_7) {
209 [ # # ]: 0 : if (flags & SIZE_WORD)
210 : 0 : opcode |= MOVELEN_SIZE_WORD;
211 [ # # ]: 0 : else if (flags & SIZE_BYTE)
212 : 0 : opcode |= MOVELEN_SIZE_BYTE;
213 [ # # ]: 0 : else if (flags & SIZE_DWORD)
214 : 0 : opcode |= MOVELEN_SIZE_DWORD;
215 : : }
216 : : }
217 : :
218 : 0 : __rta_out32(program, opcode);
219 : 0 : program->current_instruction++;
220 : :
221 : 0 : return (int)start_pc;
222 : :
223 : 0 : err:
224 : 0 : program->first_error_pc = start_pc;
225 : 0 : program->current_instruction++;
226 : 0 : return ret;
227 : : }
228 : :
229 : : static inline int
230 : 0 : set_move_offset(struct program *program __maybe_unused,
231 : : uint64_t src, uint16_t src_offset,
232 : : uint64_t dst, uint16_t dst_offset,
233 : : uint16_t *offset, uint16_t *opt)
234 : : {
235 [ # # # # : 0 : switch (src) {
# # ]
236 : 0 : case (CONTEXT1):
237 : : case (CONTEXT2):
238 [ # # ]: 0 : if (dst == DESCBUF) {
239 : 0 : *opt = MOVE_SET_AUX_SRC;
240 : 0 : *offset = dst_offset;
241 [ # # ]: 0 : } else if ((dst == KEY1) || (dst == KEY2)) {
242 [ # # ]: 0 : if ((src_offset) && (dst_offset)) {
243 : 0 : pr_err("MOVE: Bad offset. SEC PC: %d; Instr: %d\n",
244 : : program->current_pc,
245 : : program->current_instruction);
246 : 0 : goto err;
247 : : }
248 [ # # ]: 0 : if (dst_offset) {
249 : 0 : *opt = MOVE_SET_AUX_LS;
250 : 0 : *offset = dst_offset;
251 : : } else {
252 : 0 : *offset = src_offset;
253 : : }
254 : : } else {
255 : 0 : if ((dst == MATH0) || (dst == MATH1) ||
256 [ # # ]: 0 : (dst == MATH2) || (dst == MATH3)) {
257 : 0 : *opt = MOVE_SET_AUX_MATH_DST;
258 [ # # # # ]: 0 : } else if (((dst == OFIFO) || (dst == ALTSOURCE)) &&
259 : : (src_offset % 4)) {
260 : 0 : pr_err("MOVE: Bad offset alignment. SEC PC: %d; Instr: %d\n",
261 : : program->current_pc,
262 : : program->current_instruction);
263 : 0 : goto err;
264 : : }
265 : :
266 : 0 : *offset = src_offset;
267 : : }
268 : : break;
269 : :
270 : 0 : case (OFIFO):
271 [ # # ]: 0 : if (dst == OFIFO) {
272 : 0 : pr_err("MOVE: Invalid DST. SEC PC: %d; Instr: %d\n",
273 : : program->current_pc,
274 : : program->current_instruction);
275 : 0 : goto err;
276 : : }
277 : 0 : if (((dst == IFIFOAB1) || (dst == IFIFOAB2) ||
278 [ # # ]: 0 : (dst == IFIFO) || (dst == PKA)) &&
279 [ # # ]: 0 : (src_offset || dst_offset)) {
280 : 0 : pr_err("MOVE: Offset should be zero. SEC PC: %d; Instr: %d\n",
281 : : program->current_pc,
282 : : program->current_instruction);
283 : 0 : goto err;
284 : : }
285 : 0 : *offset = dst_offset;
286 : 0 : break;
287 : :
288 : 0 : case (DESCBUF):
289 [ # # ]: 0 : if ((dst == CONTEXT1) || (dst == CONTEXT2)) {
290 : 0 : *opt = MOVE_SET_AUX_DST;
291 : 0 : } else if ((dst == MATH0) || (dst == MATH1) ||
292 [ # # ]: 0 : (dst == MATH2) || (dst == MATH3)) {
293 : 0 : *opt = MOVE_SET_AUX_MATH_DST;
294 [ # # ]: 0 : } else if (dst == DESCBUF) {
295 : 0 : pr_err("MOVE: Invalid DST. SEC PC: %d; Instr: %d\n",
296 : : program->current_pc,
297 : : program->current_instruction);
298 : 0 : goto err;
299 [ # # # # ]: 0 : } else if (((dst == OFIFO) || (dst == ALTSOURCE)) &&
300 : : (src_offset % 4)) {
301 : 0 : pr_err("MOVE: Invalid offset alignment. SEC PC: %d; Instr %d\n",
302 : : program->current_pc,
303 : : program->current_instruction);
304 : 0 : goto err;
305 : : }
306 : :
307 : 0 : *offset = src_offset;
308 : 0 : break;
309 : :
310 : 0 : case (MATH0):
311 : : case (MATH1):
312 : : case (MATH2):
313 : : case (MATH3):
314 [ # # ]: 0 : if ((dst == OFIFO) || (dst == ALTSOURCE)) {
315 [ # # ]: 0 : if (src_offset % 4) {
316 : 0 : pr_err("MOVE: Bad offset alignment. SEC PC: %d; Instr: %d\n",
317 : : program->current_pc,
318 : : program->current_instruction);
319 : 0 : goto err;
320 : : }
321 : 0 : *offset = src_offset;
322 : 0 : } else if ((dst == IFIFOAB1) || (dst == IFIFOAB2) ||
323 [ # # ]: 0 : (dst == IFIFO) || (dst == PKA)) {
324 : 0 : *offset = src_offset;
325 : : } else {
326 : 0 : *offset = dst_offset;
327 : :
328 : : /*
329 : : * This condition is basically the negation of:
330 : : * dst in { CONTEXT[1-2], MATH[0-3] }
331 : : */
332 [ # # ]: 0 : if ((dst != KEY1) && (dst != KEY2))
333 : 0 : *opt = MOVE_SET_AUX_MATH_SRC;
334 : : }
335 : : break;
336 : :
337 : 0 : case (IFIFOABD):
338 : : case (IFIFOAB1):
339 : : case (IFIFOAB2):
340 : : case (ABD):
341 : : case (AB1):
342 : : case (AB2):
343 : 0 : if ((dst == IFIFOAB1) || (dst == IFIFOAB2) ||
344 [ # # # # ]: 0 : (dst == IFIFO) || (dst == PKA) || (dst == ALTSOURCE)) {
345 : 0 : pr_err("MOVE: Bad DST. SEC PC: %d; Instr: %d\n",
346 : : program->current_pc,
347 : : program->current_instruction);
348 : 0 : goto err;
349 : : } else {
350 [ # # ]: 0 : if (dst == OFIFO) {
351 : 0 : *opt = MOVE_SET_LEN_16b;
352 : : } else {
353 [ # # ]: 0 : if (dst_offset % 4) {
354 : 0 : pr_err("MOVE: Bad offset alignment. SEC PC: %d; Instr: %d\n",
355 : : program->current_pc,
356 : : program->current_instruction);
357 : 0 : goto err;
358 : : }
359 : 0 : *offset = dst_offset;
360 : : }
361 : : }
362 : : break;
363 : : default:
364 : : break;
365 : : }
366 : :
367 : : return 0;
368 : : err:
369 : : return -EINVAL;
370 : : }
371 : :
372 : : static inline int
373 : : math_offset(uint16_t offset)
374 : : {
375 : : switch (offset) {
376 : : case 0:
377 : : return 0;
378 : : case 4:
379 : : return MOVE_AUX_LS;
380 : : case 6:
381 : : return MOVE_AUX_MS;
382 : : case 7:
383 : : return MOVE_AUX_LS | MOVE_AUX_MS;
384 : : }
385 : :
386 : : return -EINVAL;
387 : : }
388 : :
389 : : #endif /* __RTA_MOVE_CMD_H__ */
|