/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) * * Copyright 2008-2016 Freescale Semiconductor Inc. * Copyright 2016 NXP * */ #ifndef __RTA_LOAD_CMD_H__ #define __RTA_LOAD_CMD_H__ extern enum rta_sec_era rta_sec_era; /* Allowed length and offset masks for each SEC Era in case DST = DCTRL */ static const uint32_t load_len_mask_allowed[] = { 0x000000ee, 0x000000fe, 0x000000fe, 0x000000fe, 0x000000fe, 0x000000fe, 0x000000fe, 0x000000fe }; static const uint32_t load_off_mask_allowed[] = { 0x0000000f, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff }; #define IMM_MUST 0 #define IMM_CAN 1 #define IMM_NO 2 #define IMM_DSNM 3 /* it doesn't matter the src type */ enum e_lenoff { LENOF_03, LENOF_4, LENOF_48, LENOF_448, LENOF_18, LENOF_32, LENOF_24, LENOF_16, LENOF_8, LENOF_128, LENOF_256, DSNM /* it doesn't matter the length/offset values */ }; struct load_map { uint32_t dst; uint32_t dst_opcode; enum e_lenoff len_off; uint8_t imm_src; }; static const struct load_map load_dst[] = { /*1*/ { KEY1SZ, LDST_CLASS_1_CCB | LDST_SRCDST_WORD_KEYSZ_REG, LENOF_4, IMM_MUST }, { KEY2SZ, LDST_CLASS_2_CCB | LDST_SRCDST_WORD_KEYSZ_REG, LENOF_4, IMM_MUST }, { DATA1SZ, LDST_CLASS_1_CCB | LDST_SRCDST_WORD_DATASZ_REG, LENOF_448, IMM_MUST }, { DATA2SZ, LDST_CLASS_2_CCB | LDST_SRCDST_WORD_DATASZ_REG, LENOF_448, IMM_MUST }, { ICV1SZ, LDST_CLASS_1_CCB | LDST_SRCDST_WORD_ICVSZ_REG, LENOF_4, IMM_MUST }, { ICV2SZ, LDST_CLASS_2_CCB | LDST_SRCDST_WORD_ICVSZ_REG, LENOF_4, IMM_MUST }, { CCTRL, LDST_CLASS_IND_CCB | LDST_SRCDST_WORD_CHACTRL, LENOF_4, IMM_MUST }, { DCTRL, LDST_CLASS_DECO | LDST_IMM | LDST_SRCDST_WORD_DECOCTRL, DSNM, IMM_DSNM }, { ICTRL, LDST_CLASS_IND_CCB | LDST_SRCDST_WORD_IRQCTRL, LENOF_4, IMM_MUST }, { DPOVRD, LDST_CLASS_DECO | LDST_SRCDST_WORD_DECO_PCLOVRD, LENOF_4, IMM_MUST }, { CLRW, LDST_CLASS_IND_CCB | LDST_SRCDST_WORD_CLRW, LENOF_4, IMM_MUST }, { AAD1SZ, LDST_CLASS_1_CCB | LDST_SRCDST_WORD_DECO_AAD_SZ, LENOF_4, IMM_MUST }, { IV1SZ, LDST_CLASS_1_CCB | LDST_SRCDST_WORD_CLASS1_IV_SZ, LENOF_4, IMM_MUST }, { ALTDS1, LDST_CLASS_1_CCB | LDST_SRCDST_WORD_ALTDS_CLASS1, LENOF_448, IMM_MUST }, { PKASZ, LDST_CLASS_1_CCB | LDST_SRCDST_WORD_PKHA_A_SZ, LENOF_4, IMM_MUST, }, { PKBSZ, LDST_CLASS_1_CCB | LDST_SRCDST_WORD_PKHA_B_SZ, LENOF_4, IMM_MUST }, { PKNSZ, LDST_CLASS_1_CCB | LDST_SRCDST_WORD_PKHA_N_SZ, LENOF_4, IMM_MUST }, { PKESZ, LDST_CLASS_1_CCB | LDST_SRCDST_WORD_PKHA_E_SZ, LENOF_4, IMM_MUST }, { NFIFO, LDST_CLASS_IND_CCB | LDST_SRCDST_WORD_INFO_FIFO, LENOF_48, IMM_MUST }, { IFIFO, LDST_SRCDST_BYTE_INFIFO, LENOF_18, IMM_MUST }, { OFIFO, LDST_SRCDST_BYTE_OUTFIFO, LENOF_18, IMM_MUST }, { MATH0, LDST_CLASS_DECO | LDST_SRCDST_WORD_DECO_MATH0, LENOF_32, IMM_CAN }, { MATH1, LDST_CLASS_DECO | LDST_SRCDST_WORD_DECO_MATH1, LENOF_24, IMM_CAN }, { MATH2, LDST_CLASS_DECO | LDST_SRCDST_WORD_DECO_MATH2, LENOF_16, IMM_CAN }, { MATH3, LDST_CLASS_DECO | LDST_SRCDST_WORD_DECO_MATH3, LENOF_8, IMM_CAN }, { CONTEXT1, LDST_CLASS_1_CCB | LDST_SRCDST_BYTE_CONTEXT, LENOF_128, IMM_CAN }, { CONTEXT2, LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_CONTEXT, LENOF_128, IMM_CAN }, { KEY1, LDST_CLASS_1_CCB | LDST_SRCDST_BYTE_KEY, LENOF_32, IMM_CAN }, { KEY2, LDST_CLASS_2_CCB | LDST_SRCDST_BYTE_KEY, LENOF_32, IMM_CAN }, { DESCBUF, LDST_CLASS_DECO | LDST_SRCDST_WORD_DESCBUF, LENOF_256, IMM_NO }, { DPID, LDST_CLASS_DECO | LDST_SRCDST_WORD_PID, LENOF_448, IMM_MUST }, /*32*/ { IDFNS, LDST_SRCDST_WORD_IFNSR, LENOF_18, IMM_MUST }, { ODFNS, LDST_SRCDST_WORD_OFNSR, LENOF_18, IMM_MUST }, { ALTSOURCE, LDST_SRCDST_BYTE_ALTSOURCE, LENOF_18, IMM_MUST }, /*35*/ { NFIFO_SZL, LDST_SRCDST_WORD_INFO_FIFO_SZL, LENOF_48, IMM_MUST }, { NFIFO_SZM, LDST_SRCDST_WORD_INFO_FIFO_SZM, LENOF_03, IMM_MUST }, { NFIFO_L, LDST_SRCDST_WORD_INFO_FIFO_L, LENOF_48, IMM_MUST }, { NFIFO_M, LDST_SRCDST_WORD_INFO_FIFO_M, LENOF_03, IMM_MUST }, { SZL, LDST_SRCDST_WORD_SZL, LENOF_48, IMM_MUST }, /*40*/ { SZM, LDST_SRCDST_WORD_SZM, LENOF_03, IMM_MUST } }; /* * Allowed LOAD destinations for each SEC Era. * Values represent the number of entries from load_dst[] that are supported. */ static const unsigned int load_dst_sz[] = { 31, 34, 34, 40, 40, 40, 40, 40 }; static inline int load_check_len_offset(int pos, uint32_t length, uint32_t offset) { if ((load_dst[pos].dst == DCTRL) && ((length & ~load_len_mask_allowed[rta_sec_era]) || (offset & ~load_off_mask_allowed[rta_sec_era]))) goto err; switch (load_dst[pos].len_off) { case (LENOF_03): if ((length > 3) || (offset)) goto err; break; case (LENOF_4): if ((length != 4) || (offset != 0)) goto err; break; case (LENOF_48): if (!(((length == 4) && (offset == 0)) || ((length == 8) && (offset == 0)))) goto err; break; case (LENOF_448): if (!(((length == 4) && (offset == 0)) || ((length == 4) && (offset == 4)) || ((length == 8) && (offset == 0)))) goto err; break; case (LENOF_18): if ((length < 1) || (length > 8) || (offset != 0)) goto err; break; case (LENOF_32): if ((length > 32) || (offset > 32) || ((offset + length) > 32)) goto err; break; case (LENOF_24): if ((length > 24) || (offset > 24) || ((offset + length) > 24)) goto err; break; case (LENOF_16): if ((length > 16) || (offset > 16) || ((offset + length) > 16)) goto err; break; case (LENOF_8): if ((length > 8) || (offset > 8) || ((offset + length) > 8)) goto err; break; case (LENOF_128): if ((length > 128) || (offset > 128) || ((offset + length) > 128)) goto err; break; case (LENOF_256): if ((length < 1) || (length > 256) || ((length + offset) > 256)) goto err; break; case (DSNM): break; default: goto err; } return 0; err: return -EINVAL; } static inline int rta_load(struct program *program, uint64_t src, uint64_t dst, uint32_t offset, uint32_t length, uint32_t flags) { uint32_t opcode = 0; int pos = -1, ret = -EINVAL; unsigned int start_pc = program->current_pc, i; if (flags & SEQ) opcode = CMD_SEQ_LOAD; else opcode = CMD_LOAD; if ((length & 0xffffff00) || (offset & 0xffffff00)) { pr_err("LOAD: Bad length/offset passed. Should be 8 bits\n"); goto err; } if (flags & SGF) opcode |= LDST_SGF; if (flags & VLF) opcode |= LDST_VLF; /* check load destination, length and offset and source type */ for (i = 0; i < load_dst_sz[rta_sec_era]; i++) if (dst == load_dst[i].dst) { pos = (int)i; break; } if (-1 == pos) { pr_err("LOAD: Invalid dst. SEC Program Line: %d\n", program->current_pc); goto err; } if (flags & IMMED) { if (load_dst[pos].imm_src == IMM_NO) { pr_err("LOAD: Invalid source type. SEC Program Line: %d\n", program->current_pc); goto err; } opcode |= LDST_IMM; } else if (load_dst[pos].imm_src == IMM_MUST) { pr_err("LOAD IMM: Invalid source type. SEC Program Line: %d\n", program->current_pc); goto err; } ret = load_check_len_offset(pos, length, offset); if (ret < 0) { pr_err("LOAD: Invalid length/offset. SEC Program Line: %d\n", program->current_pc); goto err; } opcode |= load_dst[pos].dst_opcode; /* DESC BUFFER: length / offset values are specified in 4-byte words */ if (dst == DESCBUF) { opcode |= (length >> 2); opcode |= ((offset >> 2) << LDST_OFFSET_SHIFT); } else { opcode |= length; opcode |= (offset << LDST_OFFSET_SHIFT); } __rta_out32(program, opcode); program->current_instruction++; /* DECO CONTROL: skip writing pointer of imm data */ if (dst == DCTRL) return (int)start_pc; /* * For data copy, 3 possible ways to specify how to copy data: * - IMMED & !COPY: copy data directly from src( max 8 bytes) * - IMMED & COPY: copy data imm from the location specified by user * - !IMMED and is not SEQ cmd: copy the address */ if (flags & IMMED) __rta_inline_data(program, src, flags & __COPY_MASK, length); else if (!(flags & SEQ)) __rta_out64(program, program->ps, src); return (int)start_pc; err: program->first_error_pc = start_pc; program->current_instruction++; return ret; } #endif /* __RTA_LOAD_CMD_H__*/