1 /* 2 * Copyright (C) 2016-2017 Netronome Systems, Inc. 3 * 4 * This software is dual licensed under the GNU General License Version 2, 5 * June 1991 as shown in the file COPYING in the top-level directory of this 6 * source tree or the BSD 2-Clause License provided below. You have the 7 * option to license this software under the complete terms of either license. 8 * 9 * The BSD 2-Clause License: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * 1. Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 19 * 2. Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials 22 * provided with the distribution. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 * SOFTWARE. 32 */ 33 34 #include <linux/bitops.h> 35 #include <linux/errno.h> 36 #include <linux/kernel.h> 37 #include <linux/string.h> 38 #include <linux/types.h> 39 40 #include "nfp_asm.h" 41 42 const struct cmd_tgt_act cmd_tgt_act[__CMD_TGT_MAP_SIZE] = { 43 [CMD_TGT_WRITE8] = { 0x00, 0x42 }, 44 [CMD_TGT_READ8] = { 0x01, 0x43 }, 45 [CMD_TGT_READ_LE] = { 0x01, 0x40 }, 46 [CMD_TGT_READ_SWAP_LE] = { 0x03, 0x40 }, 47 }; 48 49 static u16 nfp_swreg_to_unreg(swreg reg, bool is_dst) 50 { 51 bool lm_id, lm_dec = false; 52 u16 val = swreg_value(reg); 53 54 switch (swreg_type(reg)) { 55 case NN_REG_GPR_A: 56 case NN_REG_GPR_B: 57 case NN_REG_GPR_BOTH: 58 return val; 59 case NN_REG_NNR: 60 return UR_REG_NN | val; 61 case NN_REG_XFER: 62 return UR_REG_XFR | val; 63 case NN_REG_LMEM: 64 lm_id = swreg_lm_idx(reg); 65 66 switch (swreg_lm_mode(reg)) { 67 case NN_LM_MOD_NONE: 68 if (val & ~UR_REG_LM_IDX_MAX) { 69 pr_err("LM offset too large\n"); 70 return 0; 71 } 72 return UR_REG_LM | FIELD_PREP(UR_REG_LM_IDX, lm_id) | 73 val; 74 case NN_LM_MOD_DEC: 75 lm_dec = true; 76 /* fall through */ 77 case NN_LM_MOD_INC: 78 if (val) { 79 pr_err("LM offset in inc/dev mode\n"); 80 return 0; 81 } 82 return UR_REG_LM | UR_REG_LM_POST_MOD | 83 FIELD_PREP(UR_REG_LM_IDX, lm_id) | 84 FIELD_PREP(UR_REG_LM_POST_MOD_DEC, lm_dec); 85 default: 86 pr_err("bad LM mode for unrestricted operands %d\n", 87 swreg_lm_mode(reg)); 88 return 0; 89 } 90 case NN_REG_IMM: 91 if (val & ~0xff) { 92 pr_err("immediate too large\n"); 93 return 0; 94 } 95 return UR_REG_IMM_encode(val); 96 case NN_REG_NONE: 97 return is_dst ? UR_REG_NO_DST : REG_NONE; 98 } 99 100 pr_err("unrecognized reg encoding %08x\n", reg); 101 return 0; 102 } 103 104 int swreg_to_unrestricted(swreg dst, swreg lreg, swreg rreg, 105 struct nfp_insn_ur_regs *reg) 106 { 107 memset(reg, 0, sizeof(*reg)); 108 109 /* Decode destination */ 110 if (swreg_type(dst) == NN_REG_IMM) 111 return -EFAULT; 112 113 if (swreg_type(dst) == NN_REG_GPR_B) 114 reg->dst_ab = ALU_DST_B; 115 if (swreg_type(dst) == NN_REG_GPR_BOTH) 116 reg->wr_both = true; 117 reg->dst = nfp_swreg_to_unreg(dst, true); 118 119 /* Decode source operands */ 120 if (swreg_type(lreg) == swreg_type(rreg)) 121 return -EFAULT; 122 123 if (swreg_type(lreg) == NN_REG_GPR_B || 124 swreg_type(rreg) == NN_REG_GPR_A) { 125 reg->areg = nfp_swreg_to_unreg(rreg, false); 126 reg->breg = nfp_swreg_to_unreg(lreg, false); 127 reg->swap = true; 128 } else { 129 reg->areg = nfp_swreg_to_unreg(lreg, false); 130 reg->breg = nfp_swreg_to_unreg(rreg, false); 131 } 132 133 return 0; 134 } 135 136 static u16 nfp_swreg_to_rereg(swreg reg, bool is_dst, bool has_imm8, bool *i8) 137 { 138 u16 val = swreg_value(reg); 139 bool lm_id; 140 141 switch (swreg_type(reg)) { 142 case NN_REG_GPR_A: 143 case NN_REG_GPR_B: 144 case NN_REG_GPR_BOTH: 145 return val; 146 case NN_REG_XFER: 147 return RE_REG_XFR | val; 148 case NN_REG_LMEM: 149 lm_id = swreg_lm_idx(reg); 150 151 if (swreg_lm_mode(reg) != NN_LM_MOD_NONE) { 152 pr_err("bad LM mode for restricted operands %d\n", 153 swreg_lm_mode(reg)); 154 return 0; 155 } 156 157 if (val & ~RE_REG_LM_IDX_MAX) { 158 pr_err("LM offset too large\n"); 159 return 0; 160 } 161 162 return RE_REG_LM | FIELD_PREP(RE_REG_LM_IDX, lm_id) | val; 163 case NN_REG_IMM: 164 if (val & ~(0x7f | has_imm8 << 7)) { 165 pr_err("immediate too large\n"); 166 return 0; 167 } 168 *i8 = val & 0x80; 169 return RE_REG_IMM_encode(val & 0x7f); 170 case NN_REG_NONE: 171 return is_dst ? RE_REG_NO_DST : REG_NONE; 172 case NN_REG_NNR: 173 pr_err("NNRs used with restricted encoding\n"); 174 return 0; 175 } 176 177 pr_err("unrecognized reg encoding\n"); 178 return 0; 179 } 180 181 int swreg_to_restricted(swreg dst, swreg lreg, swreg rreg, 182 struct nfp_insn_re_regs *reg, bool has_imm8) 183 { 184 memset(reg, 0, sizeof(*reg)); 185 186 /* Decode destination */ 187 if (swreg_type(dst) == NN_REG_IMM) 188 return -EFAULT; 189 190 if (swreg_type(dst) == NN_REG_GPR_B) 191 reg->dst_ab = ALU_DST_B; 192 if (swreg_type(dst) == NN_REG_GPR_BOTH) 193 reg->wr_both = true; 194 reg->dst = nfp_swreg_to_rereg(dst, true, false, NULL); 195 196 /* Decode source operands */ 197 if (swreg_type(lreg) == swreg_type(rreg)) 198 return -EFAULT; 199 200 if (swreg_type(lreg) == NN_REG_GPR_B || 201 swreg_type(rreg) == NN_REG_GPR_A) { 202 reg->areg = nfp_swreg_to_rereg(rreg, false, has_imm8, ®->i8); 203 reg->breg = nfp_swreg_to_rereg(lreg, false, has_imm8, ®->i8); 204 reg->swap = true; 205 } else { 206 reg->areg = nfp_swreg_to_rereg(lreg, false, has_imm8, ®->i8); 207 reg->breg = nfp_swreg_to_rereg(rreg, false, has_imm8, ®->i8); 208 } 209 210 return 0; 211 } 212