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 u16 val = swreg_value(reg); 52 53 switch (swreg_type(reg)) { 54 case NN_REG_GPR_A: 55 case NN_REG_GPR_B: 56 case NN_REG_GPR_BOTH: 57 return val; 58 case NN_REG_NNR: 59 return UR_REG_NN | val; 60 case NN_REG_XFER: 61 return UR_REG_XFR | val; 62 case NN_REG_IMM: 63 if (val & ~0xff) { 64 pr_err("immediate too large\n"); 65 return 0; 66 } 67 return UR_REG_IMM_encode(val); 68 case NN_REG_NONE: 69 return is_dst ? UR_REG_NO_DST : REG_NONE; 70 } 71 72 pr_err("unrecognized reg encoding %08x\n", reg); 73 return 0; 74 } 75 76 int swreg_to_unrestricted(swreg dst, swreg lreg, swreg rreg, 77 struct nfp_insn_ur_regs *reg) 78 { 79 memset(reg, 0, sizeof(*reg)); 80 81 /* Decode destination */ 82 if (swreg_type(dst) == NN_REG_IMM) 83 return -EFAULT; 84 85 if (swreg_type(dst) == NN_REG_GPR_B) 86 reg->dst_ab = ALU_DST_B; 87 if (swreg_type(dst) == NN_REG_GPR_BOTH) 88 reg->wr_both = true; 89 reg->dst = nfp_swreg_to_unreg(dst, true); 90 91 /* Decode source operands */ 92 if (swreg_type(lreg) == swreg_type(rreg)) 93 return -EFAULT; 94 95 if (swreg_type(lreg) == NN_REG_GPR_B || 96 swreg_type(rreg) == NN_REG_GPR_A) { 97 reg->areg = nfp_swreg_to_unreg(rreg, false); 98 reg->breg = nfp_swreg_to_unreg(lreg, false); 99 reg->swap = true; 100 } else { 101 reg->areg = nfp_swreg_to_unreg(lreg, false); 102 reg->breg = nfp_swreg_to_unreg(rreg, false); 103 } 104 105 return 0; 106 } 107 108 static u16 nfp_swreg_to_rereg(swreg reg, bool is_dst, bool has_imm8, bool *i8) 109 { 110 u16 val = swreg_value(reg); 111 112 switch (swreg_type(reg)) { 113 case NN_REG_GPR_A: 114 case NN_REG_GPR_B: 115 case NN_REG_GPR_BOTH: 116 return val; 117 case NN_REG_XFER: 118 return RE_REG_XFR | val; 119 case NN_REG_IMM: 120 if (val & ~(0x7f | has_imm8 << 7)) { 121 pr_err("immediate too large\n"); 122 return 0; 123 } 124 *i8 = val & 0x80; 125 return RE_REG_IMM_encode(val & 0x7f); 126 case NN_REG_NONE: 127 return is_dst ? RE_REG_NO_DST : REG_NONE; 128 case NN_REG_NNR: 129 pr_err("NNRs used with restricted encoding\n"); 130 return 0; 131 } 132 133 pr_err("unrecognized reg encoding\n"); 134 return 0; 135 } 136 137 int swreg_to_restricted(swreg dst, swreg lreg, swreg rreg, 138 struct nfp_insn_re_regs *reg, bool has_imm8) 139 { 140 memset(reg, 0, sizeof(*reg)); 141 142 /* Decode destination */ 143 if (swreg_type(dst) == NN_REG_IMM) 144 return -EFAULT; 145 146 if (swreg_type(dst) == NN_REG_GPR_B) 147 reg->dst_ab = ALU_DST_B; 148 if (swreg_type(dst) == NN_REG_GPR_BOTH) 149 reg->wr_both = true; 150 reg->dst = nfp_swreg_to_rereg(dst, true, false, NULL); 151 152 /* Decode source operands */ 153 if (swreg_type(lreg) == swreg_type(rreg)) 154 return -EFAULT; 155 156 if (swreg_type(lreg) == NN_REG_GPR_B || 157 swreg_type(rreg) == NN_REG_GPR_A) { 158 reg->areg = nfp_swreg_to_rereg(rreg, false, has_imm8, ®->i8); 159 reg->breg = nfp_swreg_to_rereg(lreg, false, has_imm8, ®->i8); 160 reg->swap = true; 161 } else { 162 reg->areg = nfp_swreg_to_rereg(lreg, false, has_imm8, ®->i8); 163 reg->breg = nfp_swreg_to_rereg(rreg, false, has_imm8, ®->i8); 164 } 165 166 return 0; 167 } 168