12a15bb1aSJakub Kicinski /* 22a15bb1aSJakub Kicinski * Copyright (C) 2016-2017 Netronome Systems, Inc. 32a15bb1aSJakub Kicinski * 42a15bb1aSJakub Kicinski * This software is dual licensed under the GNU General License Version 2, 52a15bb1aSJakub Kicinski * June 1991 as shown in the file COPYING in the top-level directory of this 62a15bb1aSJakub Kicinski * source tree or the BSD 2-Clause License provided below. You have the 72a15bb1aSJakub Kicinski * option to license this software under the complete terms of either license. 82a15bb1aSJakub Kicinski * 92a15bb1aSJakub Kicinski * The BSD 2-Clause License: 102a15bb1aSJakub Kicinski * 112a15bb1aSJakub Kicinski * Redistribution and use in source and binary forms, with or 122a15bb1aSJakub Kicinski * without modification, are permitted provided that the following 132a15bb1aSJakub Kicinski * conditions are met: 142a15bb1aSJakub Kicinski * 152a15bb1aSJakub Kicinski * 1. Redistributions of source code must retain the above 162a15bb1aSJakub Kicinski * copyright notice, this list of conditions and the following 172a15bb1aSJakub Kicinski * disclaimer. 182a15bb1aSJakub Kicinski * 192a15bb1aSJakub Kicinski * 2. Redistributions in binary form must reproduce the above 202a15bb1aSJakub Kicinski * copyright notice, this list of conditions and the following 212a15bb1aSJakub Kicinski * disclaimer in the documentation and/or other materials 222a15bb1aSJakub Kicinski * provided with the distribution. 232a15bb1aSJakub Kicinski * 242a15bb1aSJakub Kicinski * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 252a15bb1aSJakub Kicinski * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 262a15bb1aSJakub Kicinski * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 272a15bb1aSJakub Kicinski * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 282a15bb1aSJakub Kicinski * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 292a15bb1aSJakub Kicinski * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 302a15bb1aSJakub Kicinski * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 312a15bb1aSJakub Kicinski * SOFTWARE. 322a15bb1aSJakub Kicinski */ 332a15bb1aSJakub Kicinski 342a15bb1aSJakub Kicinski #include <linux/bitops.h> 352a15bb1aSJakub Kicinski #include <linux/errno.h> 362a15bb1aSJakub Kicinski #include <linux/kernel.h> 372a15bb1aSJakub Kicinski #include <linux/string.h> 382a15bb1aSJakub Kicinski #include <linux/types.h> 392a15bb1aSJakub Kicinski 402a15bb1aSJakub Kicinski #include "nfp_asm.h" 412a15bb1aSJakub Kicinski 422a15bb1aSJakub Kicinski const struct cmd_tgt_act cmd_tgt_act[__CMD_TGT_MAP_SIZE] = { 432a15bb1aSJakub Kicinski [CMD_TGT_WRITE8] = { 0x00, 0x42 }, 442a15bb1aSJakub Kicinski [CMD_TGT_READ8] = { 0x01, 0x43 }, 452a15bb1aSJakub Kicinski [CMD_TGT_READ_LE] = { 0x01, 0x40 }, 462a15bb1aSJakub Kicinski [CMD_TGT_READ_SWAP_LE] = { 0x03, 0x40 }, 472a15bb1aSJakub Kicinski }; 482a15bb1aSJakub Kicinski 492a15bb1aSJakub Kicinski static u16 nfp_swreg_to_unreg(swreg reg, bool is_dst) 502a15bb1aSJakub Kicinski { 519f15d0f4SJakub Kicinski bool lm_id, lm_dec = false; 522a15bb1aSJakub Kicinski u16 val = swreg_value(reg); 532a15bb1aSJakub Kicinski 542a15bb1aSJakub Kicinski switch (swreg_type(reg)) { 552a15bb1aSJakub Kicinski case NN_REG_GPR_A: 562a15bb1aSJakub Kicinski case NN_REG_GPR_B: 572a15bb1aSJakub Kicinski case NN_REG_GPR_BOTH: 582a15bb1aSJakub Kicinski return val; 592a15bb1aSJakub Kicinski case NN_REG_NNR: 602a15bb1aSJakub Kicinski return UR_REG_NN | val; 612a15bb1aSJakub Kicinski case NN_REG_XFER: 622a15bb1aSJakub Kicinski return UR_REG_XFR | val; 639f15d0f4SJakub Kicinski case NN_REG_LMEM: 649f15d0f4SJakub Kicinski lm_id = swreg_lm_idx(reg); 659f15d0f4SJakub Kicinski 669f15d0f4SJakub Kicinski switch (swreg_lm_mode(reg)) { 679f15d0f4SJakub Kicinski case NN_LM_MOD_NONE: 689f15d0f4SJakub Kicinski if (val & ~UR_REG_LM_IDX_MAX) { 699f15d0f4SJakub Kicinski pr_err("LM offset too large\n"); 709f15d0f4SJakub Kicinski return 0; 719f15d0f4SJakub Kicinski } 729f15d0f4SJakub Kicinski return UR_REG_LM | FIELD_PREP(UR_REG_LM_IDX, lm_id) | 739f15d0f4SJakub Kicinski val; 749f15d0f4SJakub Kicinski case NN_LM_MOD_DEC: 759f15d0f4SJakub Kicinski lm_dec = true; 769f15d0f4SJakub Kicinski /* fall through */ 779f15d0f4SJakub Kicinski case NN_LM_MOD_INC: 789f15d0f4SJakub Kicinski if (val) { 799f15d0f4SJakub Kicinski pr_err("LM offset in inc/dev mode\n"); 809f15d0f4SJakub Kicinski return 0; 819f15d0f4SJakub Kicinski } 829f15d0f4SJakub Kicinski return UR_REG_LM | UR_REG_LM_POST_MOD | 839f15d0f4SJakub Kicinski FIELD_PREP(UR_REG_LM_IDX, lm_id) | 849f15d0f4SJakub Kicinski FIELD_PREP(UR_REG_LM_POST_MOD_DEC, lm_dec); 859f15d0f4SJakub Kicinski default: 869f15d0f4SJakub Kicinski pr_err("bad LM mode for unrestricted operands %d\n", 879f15d0f4SJakub Kicinski swreg_lm_mode(reg)); 889f15d0f4SJakub Kicinski return 0; 899f15d0f4SJakub Kicinski } 902a15bb1aSJakub Kicinski case NN_REG_IMM: 912a15bb1aSJakub Kicinski if (val & ~0xff) { 922a15bb1aSJakub Kicinski pr_err("immediate too large\n"); 932a15bb1aSJakub Kicinski return 0; 942a15bb1aSJakub Kicinski } 952a15bb1aSJakub Kicinski return UR_REG_IMM_encode(val); 962a15bb1aSJakub Kicinski case NN_REG_NONE: 972a15bb1aSJakub Kicinski return is_dst ? UR_REG_NO_DST : REG_NONE; 982a15bb1aSJakub Kicinski } 992a15bb1aSJakub Kicinski 1002a15bb1aSJakub Kicinski pr_err("unrecognized reg encoding %08x\n", reg); 1012a15bb1aSJakub Kicinski return 0; 1022a15bb1aSJakub Kicinski } 1032a15bb1aSJakub Kicinski 1042a15bb1aSJakub Kicinski int swreg_to_unrestricted(swreg dst, swreg lreg, swreg rreg, 1052a15bb1aSJakub Kicinski struct nfp_insn_ur_regs *reg) 1062a15bb1aSJakub Kicinski { 1072a15bb1aSJakub Kicinski memset(reg, 0, sizeof(*reg)); 1082a15bb1aSJakub Kicinski 1092a15bb1aSJakub Kicinski /* Decode destination */ 1102a15bb1aSJakub Kicinski if (swreg_type(dst) == NN_REG_IMM) 1112a15bb1aSJakub Kicinski return -EFAULT; 1122a15bb1aSJakub Kicinski 1132a15bb1aSJakub Kicinski if (swreg_type(dst) == NN_REG_GPR_B) 1142a15bb1aSJakub Kicinski reg->dst_ab = ALU_DST_B; 1152a15bb1aSJakub Kicinski if (swreg_type(dst) == NN_REG_GPR_BOTH) 1162a15bb1aSJakub Kicinski reg->wr_both = true; 1172a15bb1aSJakub Kicinski reg->dst = nfp_swreg_to_unreg(dst, true); 1182a15bb1aSJakub Kicinski 1192a15bb1aSJakub Kicinski /* Decode source operands */ 1202a15bb1aSJakub Kicinski if (swreg_type(lreg) == swreg_type(rreg)) 1212a15bb1aSJakub Kicinski return -EFAULT; 1222a15bb1aSJakub Kicinski 1232a15bb1aSJakub Kicinski if (swreg_type(lreg) == NN_REG_GPR_B || 1242a15bb1aSJakub Kicinski swreg_type(rreg) == NN_REG_GPR_A) { 1252a15bb1aSJakub Kicinski reg->areg = nfp_swreg_to_unreg(rreg, false); 1262a15bb1aSJakub Kicinski reg->breg = nfp_swreg_to_unreg(lreg, false); 1272a15bb1aSJakub Kicinski reg->swap = true; 1282a15bb1aSJakub Kicinski } else { 1292a15bb1aSJakub Kicinski reg->areg = nfp_swreg_to_unreg(lreg, false); 1302a15bb1aSJakub Kicinski reg->breg = nfp_swreg_to_unreg(rreg, false); 1312a15bb1aSJakub Kicinski } 1322a15bb1aSJakub Kicinski 133995e101fSJakub Kicinski reg->dst_lmextn = swreg_lmextn(dst); 134995e101fSJakub Kicinski reg->src_lmextn = swreg_lmextn(lreg) | swreg_lmextn(rreg); 135995e101fSJakub Kicinski 1362a15bb1aSJakub Kicinski return 0; 1372a15bb1aSJakub Kicinski } 1382a15bb1aSJakub Kicinski 1392a15bb1aSJakub Kicinski static u16 nfp_swreg_to_rereg(swreg reg, bool is_dst, bool has_imm8, bool *i8) 1402a15bb1aSJakub Kicinski { 1412a15bb1aSJakub Kicinski u16 val = swreg_value(reg); 1429f15d0f4SJakub Kicinski bool lm_id; 1432a15bb1aSJakub Kicinski 1442a15bb1aSJakub Kicinski switch (swreg_type(reg)) { 1452a15bb1aSJakub Kicinski case NN_REG_GPR_A: 1462a15bb1aSJakub Kicinski case NN_REG_GPR_B: 1472a15bb1aSJakub Kicinski case NN_REG_GPR_BOTH: 1482a15bb1aSJakub Kicinski return val; 1492a15bb1aSJakub Kicinski case NN_REG_XFER: 1502a15bb1aSJakub Kicinski return RE_REG_XFR | val; 1519f15d0f4SJakub Kicinski case NN_REG_LMEM: 1529f15d0f4SJakub Kicinski lm_id = swreg_lm_idx(reg); 1539f15d0f4SJakub Kicinski 1549f15d0f4SJakub Kicinski if (swreg_lm_mode(reg) != NN_LM_MOD_NONE) { 1559f15d0f4SJakub Kicinski pr_err("bad LM mode for restricted operands %d\n", 1569f15d0f4SJakub Kicinski swreg_lm_mode(reg)); 1579f15d0f4SJakub Kicinski return 0; 1589f15d0f4SJakub Kicinski } 1599f15d0f4SJakub Kicinski 1609f15d0f4SJakub Kicinski if (val & ~RE_REG_LM_IDX_MAX) { 1619f15d0f4SJakub Kicinski pr_err("LM offset too large\n"); 1629f15d0f4SJakub Kicinski return 0; 1639f15d0f4SJakub Kicinski } 1649f15d0f4SJakub Kicinski 1659f15d0f4SJakub Kicinski return RE_REG_LM | FIELD_PREP(RE_REG_LM_IDX, lm_id) | val; 1662a15bb1aSJakub Kicinski case NN_REG_IMM: 1672a15bb1aSJakub Kicinski if (val & ~(0x7f | has_imm8 << 7)) { 1682a15bb1aSJakub Kicinski pr_err("immediate too large\n"); 1692a15bb1aSJakub Kicinski return 0; 1702a15bb1aSJakub Kicinski } 1712a15bb1aSJakub Kicinski *i8 = val & 0x80; 1722a15bb1aSJakub Kicinski return RE_REG_IMM_encode(val & 0x7f); 1732a15bb1aSJakub Kicinski case NN_REG_NONE: 1742a15bb1aSJakub Kicinski return is_dst ? RE_REG_NO_DST : REG_NONE; 1752a15bb1aSJakub Kicinski case NN_REG_NNR: 1762a15bb1aSJakub Kicinski pr_err("NNRs used with restricted encoding\n"); 1772a15bb1aSJakub Kicinski return 0; 1782a15bb1aSJakub Kicinski } 1792a15bb1aSJakub Kicinski 1802a15bb1aSJakub Kicinski pr_err("unrecognized reg encoding\n"); 1812a15bb1aSJakub Kicinski return 0; 1822a15bb1aSJakub Kicinski } 1832a15bb1aSJakub Kicinski 1842a15bb1aSJakub Kicinski int swreg_to_restricted(swreg dst, swreg lreg, swreg rreg, 1852a15bb1aSJakub Kicinski struct nfp_insn_re_regs *reg, bool has_imm8) 1862a15bb1aSJakub Kicinski { 1872a15bb1aSJakub Kicinski memset(reg, 0, sizeof(*reg)); 1882a15bb1aSJakub Kicinski 1892a15bb1aSJakub Kicinski /* Decode destination */ 1902a15bb1aSJakub Kicinski if (swreg_type(dst) == NN_REG_IMM) 1912a15bb1aSJakub Kicinski return -EFAULT; 1922a15bb1aSJakub Kicinski 1932a15bb1aSJakub Kicinski if (swreg_type(dst) == NN_REG_GPR_B) 1942a15bb1aSJakub Kicinski reg->dst_ab = ALU_DST_B; 1952a15bb1aSJakub Kicinski if (swreg_type(dst) == NN_REG_GPR_BOTH) 1962a15bb1aSJakub Kicinski reg->wr_both = true; 1972a15bb1aSJakub Kicinski reg->dst = nfp_swreg_to_rereg(dst, true, false, NULL); 1982a15bb1aSJakub Kicinski 1992a15bb1aSJakub Kicinski /* Decode source operands */ 2002a15bb1aSJakub Kicinski if (swreg_type(lreg) == swreg_type(rreg)) 2012a15bb1aSJakub Kicinski return -EFAULT; 2022a15bb1aSJakub Kicinski 2032a15bb1aSJakub Kicinski if (swreg_type(lreg) == NN_REG_GPR_B || 2042a15bb1aSJakub Kicinski swreg_type(rreg) == NN_REG_GPR_A) { 2052a15bb1aSJakub Kicinski reg->areg = nfp_swreg_to_rereg(rreg, false, has_imm8, ®->i8); 2062a15bb1aSJakub Kicinski reg->breg = nfp_swreg_to_rereg(lreg, false, has_imm8, ®->i8); 2072a15bb1aSJakub Kicinski reg->swap = true; 2082a15bb1aSJakub Kicinski } else { 2092a15bb1aSJakub Kicinski reg->areg = nfp_swreg_to_rereg(lreg, false, has_imm8, ®->i8); 2102a15bb1aSJakub Kicinski reg->breg = nfp_swreg_to_rereg(rreg, false, has_imm8, ®->i8); 2112a15bb1aSJakub Kicinski } 2122a15bb1aSJakub Kicinski 213995e101fSJakub Kicinski reg->dst_lmextn = swreg_lmextn(dst); 214995e101fSJakub Kicinski reg->src_lmextn = swreg_lmextn(lreg) | swreg_lmextn(rreg); 215995e101fSJakub Kicinski 2162a15bb1aSJakub Kicinski return 0; 2172a15bb1aSJakub Kicinski } 218*fd068ddcSJakub Kicinski 219*fd068ddcSJakub Kicinski #define NFP_USTORE_ECC_POLY_WORDS 7 220*fd068ddcSJakub Kicinski #define NFP_USTORE_OP_BITS 45 221*fd068ddcSJakub Kicinski 222*fd068ddcSJakub Kicinski static const u64 nfp_ustore_ecc_polynomials[NFP_USTORE_ECC_POLY_WORDS] = { 223*fd068ddcSJakub Kicinski 0x0ff800007fffULL, 224*fd068ddcSJakub Kicinski 0x11f801ff801fULL, 225*fd068ddcSJakub Kicinski 0x1e387e0781e1ULL, 226*fd068ddcSJakub Kicinski 0x17cb8e388e22ULL, 227*fd068ddcSJakub Kicinski 0x1af5b2c93244ULL, 228*fd068ddcSJakub Kicinski 0x1f56d5525488ULL, 229*fd068ddcSJakub Kicinski 0x0daf69a46910ULL, 230*fd068ddcSJakub Kicinski }; 231*fd068ddcSJakub Kicinski 232*fd068ddcSJakub Kicinski static bool parity(u64 value) 233*fd068ddcSJakub Kicinski { 234*fd068ddcSJakub Kicinski return hweight64(value) & 1; 235*fd068ddcSJakub Kicinski } 236*fd068ddcSJakub Kicinski 237*fd068ddcSJakub Kicinski int nfp_ustore_check_valid_no_ecc(u64 insn) 238*fd068ddcSJakub Kicinski { 239*fd068ddcSJakub Kicinski if (insn & ~GENMASK_ULL(NFP_USTORE_OP_BITS, 0)) 240*fd068ddcSJakub Kicinski return -EINVAL; 241*fd068ddcSJakub Kicinski 242*fd068ddcSJakub Kicinski return 0; 243*fd068ddcSJakub Kicinski } 244*fd068ddcSJakub Kicinski 245*fd068ddcSJakub Kicinski u64 nfp_ustore_calc_ecc_insn(u64 insn) 246*fd068ddcSJakub Kicinski { 247*fd068ddcSJakub Kicinski u8 ecc = 0; 248*fd068ddcSJakub Kicinski int i; 249*fd068ddcSJakub Kicinski 250*fd068ddcSJakub Kicinski for (i = 0; i < NFP_USTORE_ECC_POLY_WORDS; i++) 251*fd068ddcSJakub Kicinski ecc |= parity(nfp_ustore_ecc_polynomials[i] & insn) << i; 252*fd068ddcSJakub Kicinski 253*fd068ddcSJakub Kicinski return insn | (u64)ecc << NFP_USTORE_OP_BITS; 254*fd068ddcSJakub Kicinski } 255