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] = { 43e663fe38SJakub Kicinski [CMD_TGT_WRITE8_SWAP] = { 0x02, 0x42 }, 449879a381SJiong Wang [CMD_TGT_WRITE32_SWAP] = { 0x02, 0x5f }, 452a15bb1aSJakub Kicinski [CMD_TGT_READ8] = { 0x01, 0x43 }, 462ca71441SJakub Kicinski [CMD_TGT_READ32] = { 0x00, 0x5c }, 472ca71441SJakub Kicinski [CMD_TGT_READ32_LE] = { 0x01, 0x5c }, 482ca71441SJakub Kicinski [CMD_TGT_READ32_SWAP] = { 0x02, 0x5c }, 492a15bb1aSJakub Kicinski [CMD_TGT_READ_LE] = { 0x01, 0x40 }, 502a15bb1aSJakub Kicinski [CMD_TGT_READ_SWAP_LE] = { 0x03, 0x40 }, 51*41aed09cSJakub Kicinski [CMD_TGT_ADD] = { 0x00, 0x47 }, 52dcb0c27fSJakub Kicinski [CMD_TGT_ADD_IMM] = { 0x02, 0x47 }, 532a15bb1aSJakub Kicinski }; 542a15bb1aSJakub Kicinski 55ce4ebfd8SJakub Kicinski static bool unreg_is_imm(u16 reg) 56ce4ebfd8SJakub Kicinski { 57ce4ebfd8SJakub Kicinski return (reg & UR_REG_IMM) == UR_REG_IMM; 58ce4ebfd8SJakub Kicinski } 59ce4ebfd8SJakub Kicinski 60488feeafSJakub Kicinski u16 br_get_offset(u64 instr) 61488feeafSJakub Kicinski { 62488feeafSJakub Kicinski u16 addr_lo, addr_hi; 63488feeafSJakub Kicinski 64488feeafSJakub Kicinski addr_lo = FIELD_GET(OP_BR_ADDR_LO, instr); 65488feeafSJakub Kicinski addr_hi = FIELD_GET(OP_BR_ADDR_HI, instr); 66488feeafSJakub Kicinski 67488feeafSJakub Kicinski return (addr_hi * ((OP_BR_ADDR_LO >> __bf_shf(OP_BR_ADDR_LO)) + 1)) | 68488feeafSJakub Kicinski addr_lo; 69488feeafSJakub Kicinski } 70488feeafSJakub Kicinski 71488feeafSJakub Kicinski void br_set_offset(u64 *instr, u16 offset) 72488feeafSJakub Kicinski { 73488feeafSJakub Kicinski u16 addr_lo, addr_hi; 74488feeafSJakub Kicinski 75488feeafSJakub Kicinski addr_lo = offset & (OP_BR_ADDR_LO >> __bf_shf(OP_BR_ADDR_LO)); 76488feeafSJakub Kicinski addr_hi = offset != addr_lo; 77488feeafSJakub Kicinski *instr &= ~(OP_BR_ADDR_HI | OP_BR_ADDR_LO); 78488feeafSJakub Kicinski *instr |= FIELD_PREP(OP_BR_ADDR_HI, addr_hi); 79488feeafSJakub Kicinski *instr |= FIELD_PREP(OP_BR_ADDR_LO, addr_lo); 80488feeafSJakub Kicinski } 81488feeafSJakub Kicinski 82488feeafSJakub Kicinski void br_add_offset(u64 *instr, u16 offset) 83488feeafSJakub Kicinski { 84488feeafSJakub Kicinski u16 addr; 85488feeafSJakub Kicinski 86488feeafSJakub Kicinski addr = br_get_offset(*instr); 87488feeafSJakub Kicinski br_set_offset(instr, addr + offset); 88488feeafSJakub Kicinski } 89488feeafSJakub Kicinski 90ce4ebfd8SJakub Kicinski static bool immed_can_modify(u64 instr) 91ce4ebfd8SJakub Kicinski { 92ce4ebfd8SJakub Kicinski if (FIELD_GET(OP_IMMED_INV, instr) || 93ce4ebfd8SJakub Kicinski FIELD_GET(OP_IMMED_SHIFT, instr) || 94ce4ebfd8SJakub Kicinski FIELD_GET(OP_IMMED_WIDTH, instr) != IMMED_WIDTH_ALL) { 95ce4ebfd8SJakub Kicinski pr_err("Can't decode/encode immed!\n"); 96ce4ebfd8SJakub Kicinski return false; 97ce4ebfd8SJakub Kicinski } 98ce4ebfd8SJakub Kicinski return true; 99ce4ebfd8SJakub Kicinski } 100ce4ebfd8SJakub Kicinski 101ce4ebfd8SJakub Kicinski u16 immed_get_value(u64 instr) 102ce4ebfd8SJakub Kicinski { 103ce4ebfd8SJakub Kicinski u16 reg; 104ce4ebfd8SJakub Kicinski 105ce4ebfd8SJakub Kicinski if (!immed_can_modify(instr)) 106ce4ebfd8SJakub Kicinski return 0; 107ce4ebfd8SJakub Kicinski 108ce4ebfd8SJakub Kicinski reg = FIELD_GET(OP_IMMED_A_SRC, instr); 109ce4ebfd8SJakub Kicinski if (!unreg_is_imm(reg)) 110ce4ebfd8SJakub Kicinski reg = FIELD_GET(OP_IMMED_B_SRC, instr); 111ce4ebfd8SJakub Kicinski 112b7d99235SJakub Kicinski return (reg & 0xff) | FIELD_GET(OP_IMMED_IMM, instr) << 8; 113ce4ebfd8SJakub Kicinski } 114ce4ebfd8SJakub Kicinski 115ce4ebfd8SJakub Kicinski void immed_set_value(u64 *instr, u16 immed) 116ce4ebfd8SJakub Kicinski { 117ce4ebfd8SJakub Kicinski if (!immed_can_modify(*instr)) 118ce4ebfd8SJakub Kicinski return; 119ce4ebfd8SJakub Kicinski 120ce4ebfd8SJakub Kicinski if (unreg_is_imm(FIELD_GET(OP_IMMED_A_SRC, *instr))) { 121ce4ebfd8SJakub Kicinski *instr &= ~FIELD_PREP(OP_IMMED_A_SRC, 0xff); 122ce4ebfd8SJakub Kicinski *instr |= FIELD_PREP(OP_IMMED_A_SRC, immed & 0xff); 123ce4ebfd8SJakub Kicinski } else { 124ce4ebfd8SJakub Kicinski *instr &= ~FIELD_PREP(OP_IMMED_B_SRC, 0xff); 125ce4ebfd8SJakub Kicinski *instr |= FIELD_PREP(OP_IMMED_B_SRC, immed & 0xff); 126ce4ebfd8SJakub Kicinski } 127ce4ebfd8SJakub Kicinski 128ce4ebfd8SJakub Kicinski *instr &= ~OP_IMMED_IMM; 129ce4ebfd8SJakub Kicinski *instr |= FIELD_PREP(OP_IMMED_IMM, immed >> 8); 130ce4ebfd8SJakub Kicinski } 131ce4ebfd8SJakub Kicinski 132ce4ebfd8SJakub Kicinski void immed_add_value(u64 *instr, u16 offset) 133ce4ebfd8SJakub Kicinski { 134ce4ebfd8SJakub Kicinski u16 val; 135ce4ebfd8SJakub Kicinski 136ce4ebfd8SJakub Kicinski if (!immed_can_modify(*instr)) 137ce4ebfd8SJakub Kicinski return; 138ce4ebfd8SJakub Kicinski 139ce4ebfd8SJakub Kicinski val = immed_get_value(*instr); 140ce4ebfd8SJakub Kicinski immed_set_value(instr, val + offset); 141ce4ebfd8SJakub Kicinski } 142ce4ebfd8SJakub Kicinski 1432a15bb1aSJakub Kicinski static u16 nfp_swreg_to_unreg(swreg reg, bool is_dst) 1442a15bb1aSJakub Kicinski { 1459f15d0f4SJakub Kicinski bool lm_id, lm_dec = false; 1462a15bb1aSJakub Kicinski u16 val = swreg_value(reg); 1472a15bb1aSJakub Kicinski 1482a15bb1aSJakub Kicinski switch (swreg_type(reg)) { 1492a15bb1aSJakub Kicinski case NN_REG_GPR_A: 1502a15bb1aSJakub Kicinski case NN_REG_GPR_B: 1512a15bb1aSJakub Kicinski case NN_REG_GPR_BOTH: 1522a15bb1aSJakub Kicinski return val; 1532a15bb1aSJakub Kicinski case NN_REG_NNR: 1542a15bb1aSJakub Kicinski return UR_REG_NN | val; 1552a15bb1aSJakub Kicinski case NN_REG_XFER: 1562a15bb1aSJakub Kicinski return UR_REG_XFR | val; 1579f15d0f4SJakub Kicinski case NN_REG_LMEM: 1589f15d0f4SJakub Kicinski lm_id = swreg_lm_idx(reg); 1599f15d0f4SJakub Kicinski 1609f15d0f4SJakub Kicinski switch (swreg_lm_mode(reg)) { 1619f15d0f4SJakub Kicinski case NN_LM_MOD_NONE: 1629f15d0f4SJakub Kicinski if (val & ~UR_REG_LM_IDX_MAX) { 1639f15d0f4SJakub Kicinski pr_err("LM offset too large\n"); 1649f15d0f4SJakub Kicinski return 0; 1659f15d0f4SJakub Kicinski } 1669f15d0f4SJakub Kicinski return UR_REG_LM | FIELD_PREP(UR_REG_LM_IDX, lm_id) | 1679f15d0f4SJakub Kicinski val; 1689f15d0f4SJakub Kicinski case NN_LM_MOD_DEC: 1699f15d0f4SJakub Kicinski lm_dec = true; 1709f15d0f4SJakub Kicinski /* fall through */ 1719f15d0f4SJakub Kicinski case NN_LM_MOD_INC: 1729f15d0f4SJakub Kicinski if (val) { 1739f15d0f4SJakub Kicinski pr_err("LM offset in inc/dev mode\n"); 1749f15d0f4SJakub Kicinski return 0; 1759f15d0f4SJakub Kicinski } 1769f15d0f4SJakub Kicinski return UR_REG_LM | UR_REG_LM_POST_MOD | 1779f15d0f4SJakub Kicinski FIELD_PREP(UR_REG_LM_IDX, lm_id) | 1789f15d0f4SJakub Kicinski FIELD_PREP(UR_REG_LM_POST_MOD_DEC, lm_dec); 1799f15d0f4SJakub Kicinski default: 1809f15d0f4SJakub Kicinski pr_err("bad LM mode for unrestricted operands %d\n", 1819f15d0f4SJakub Kicinski swreg_lm_mode(reg)); 1829f15d0f4SJakub Kicinski return 0; 1839f15d0f4SJakub Kicinski } 1842a15bb1aSJakub Kicinski case NN_REG_IMM: 1852a15bb1aSJakub Kicinski if (val & ~0xff) { 1862a15bb1aSJakub Kicinski pr_err("immediate too large\n"); 1872a15bb1aSJakub Kicinski return 0; 1882a15bb1aSJakub Kicinski } 1892a15bb1aSJakub Kicinski return UR_REG_IMM_encode(val); 1902a15bb1aSJakub Kicinski case NN_REG_NONE: 1912a15bb1aSJakub Kicinski return is_dst ? UR_REG_NO_DST : REG_NONE; 1922a15bb1aSJakub Kicinski } 1932a15bb1aSJakub Kicinski 1942a15bb1aSJakub Kicinski pr_err("unrecognized reg encoding %08x\n", reg); 1952a15bb1aSJakub Kicinski return 0; 1962a15bb1aSJakub Kicinski } 1972a15bb1aSJakub Kicinski 1982a15bb1aSJakub Kicinski int swreg_to_unrestricted(swreg dst, swreg lreg, swreg rreg, 1992a15bb1aSJakub Kicinski struct nfp_insn_ur_regs *reg) 2002a15bb1aSJakub Kicinski { 2012a15bb1aSJakub Kicinski memset(reg, 0, sizeof(*reg)); 2022a15bb1aSJakub Kicinski 2032a15bb1aSJakub Kicinski /* Decode destination */ 2042a15bb1aSJakub Kicinski if (swreg_type(dst) == NN_REG_IMM) 2052a15bb1aSJakub Kicinski return -EFAULT; 2062a15bb1aSJakub Kicinski 2072a15bb1aSJakub Kicinski if (swreg_type(dst) == NN_REG_GPR_B) 2082a15bb1aSJakub Kicinski reg->dst_ab = ALU_DST_B; 2092a15bb1aSJakub Kicinski if (swreg_type(dst) == NN_REG_GPR_BOTH) 2102a15bb1aSJakub Kicinski reg->wr_both = true; 2112a15bb1aSJakub Kicinski reg->dst = nfp_swreg_to_unreg(dst, true); 2122a15bb1aSJakub Kicinski 2132a15bb1aSJakub Kicinski /* Decode source operands */ 21408859f15SJiong Wang if (swreg_type(lreg) == swreg_type(rreg) && 21508859f15SJiong Wang swreg_type(lreg) != NN_REG_NONE) 2162a15bb1aSJakub Kicinski return -EFAULT; 2172a15bb1aSJakub Kicinski 2182a15bb1aSJakub Kicinski if (swreg_type(lreg) == NN_REG_GPR_B || 2192a15bb1aSJakub Kicinski swreg_type(rreg) == NN_REG_GPR_A) { 2202a15bb1aSJakub Kicinski reg->areg = nfp_swreg_to_unreg(rreg, false); 2212a15bb1aSJakub Kicinski reg->breg = nfp_swreg_to_unreg(lreg, false); 2222a15bb1aSJakub Kicinski reg->swap = true; 2232a15bb1aSJakub Kicinski } else { 2242a15bb1aSJakub Kicinski reg->areg = nfp_swreg_to_unreg(lreg, false); 2252a15bb1aSJakub Kicinski reg->breg = nfp_swreg_to_unreg(rreg, false); 2262a15bb1aSJakub Kicinski } 2272a15bb1aSJakub Kicinski 228995e101fSJakub Kicinski reg->dst_lmextn = swreg_lmextn(dst); 229995e101fSJakub Kicinski reg->src_lmextn = swreg_lmextn(lreg) | swreg_lmextn(rreg); 230995e101fSJakub Kicinski 2312a15bb1aSJakub Kicinski return 0; 2322a15bb1aSJakub Kicinski } 2332a15bb1aSJakub Kicinski 2342a15bb1aSJakub Kicinski static u16 nfp_swreg_to_rereg(swreg reg, bool is_dst, bool has_imm8, bool *i8) 2352a15bb1aSJakub Kicinski { 2362a15bb1aSJakub Kicinski u16 val = swreg_value(reg); 2379f15d0f4SJakub Kicinski bool lm_id; 2382a15bb1aSJakub Kicinski 2392a15bb1aSJakub Kicinski switch (swreg_type(reg)) { 2402a15bb1aSJakub Kicinski case NN_REG_GPR_A: 2412a15bb1aSJakub Kicinski case NN_REG_GPR_B: 2422a15bb1aSJakub Kicinski case NN_REG_GPR_BOTH: 2432a15bb1aSJakub Kicinski return val; 2442a15bb1aSJakub Kicinski case NN_REG_XFER: 2452a15bb1aSJakub Kicinski return RE_REG_XFR | val; 2469f15d0f4SJakub Kicinski case NN_REG_LMEM: 2479f15d0f4SJakub Kicinski lm_id = swreg_lm_idx(reg); 2489f15d0f4SJakub Kicinski 2499f15d0f4SJakub Kicinski if (swreg_lm_mode(reg) != NN_LM_MOD_NONE) { 2509f15d0f4SJakub Kicinski pr_err("bad LM mode for restricted operands %d\n", 2519f15d0f4SJakub Kicinski swreg_lm_mode(reg)); 2529f15d0f4SJakub Kicinski return 0; 2539f15d0f4SJakub Kicinski } 2549f15d0f4SJakub Kicinski 2559f15d0f4SJakub Kicinski if (val & ~RE_REG_LM_IDX_MAX) { 2569f15d0f4SJakub Kicinski pr_err("LM offset too large\n"); 2579f15d0f4SJakub Kicinski return 0; 2589f15d0f4SJakub Kicinski } 2599f15d0f4SJakub Kicinski 2609f15d0f4SJakub Kicinski return RE_REG_LM | FIELD_PREP(RE_REG_LM_IDX, lm_id) | val; 2612a15bb1aSJakub Kicinski case NN_REG_IMM: 2622a15bb1aSJakub Kicinski if (val & ~(0x7f | has_imm8 << 7)) { 2632a15bb1aSJakub Kicinski pr_err("immediate too large\n"); 2642a15bb1aSJakub Kicinski return 0; 2652a15bb1aSJakub Kicinski } 2662a15bb1aSJakub Kicinski *i8 = val & 0x80; 2672a15bb1aSJakub Kicinski return RE_REG_IMM_encode(val & 0x7f); 2682a15bb1aSJakub Kicinski case NN_REG_NONE: 2692a15bb1aSJakub Kicinski return is_dst ? RE_REG_NO_DST : REG_NONE; 2702a15bb1aSJakub Kicinski case NN_REG_NNR: 2712a15bb1aSJakub Kicinski pr_err("NNRs used with restricted encoding\n"); 2722a15bb1aSJakub Kicinski return 0; 2732a15bb1aSJakub Kicinski } 2742a15bb1aSJakub Kicinski 2752a15bb1aSJakub Kicinski pr_err("unrecognized reg encoding\n"); 2762a15bb1aSJakub Kicinski return 0; 2772a15bb1aSJakub Kicinski } 2782a15bb1aSJakub Kicinski 2792a15bb1aSJakub Kicinski int swreg_to_restricted(swreg dst, swreg lreg, swreg rreg, 2802a15bb1aSJakub Kicinski struct nfp_insn_re_regs *reg, bool has_imm8) 2812a15bb1aSJakub Kicinski { 2822a15bb1aSJakub Kicinski memset(reg, 0, sizeof(*reg)); 2832a15bb1aSJakub Kicinski 2842a15bb1aSJakub Kicinski /* Decode destination */ 2852a15bb1aSJakub Kicinski if (swreg_type(dst) == NN_REG_IMM) 2862a15bb1aSJakub Kicinski return -EFAULT; 2872a15bb1aSJakub Kicinski 2882a15bb1aSJakub Kicinski if (swreg_type(dst) == NN_REG_GPR_B) 2892a15bb1aSJakub Kicinski reg->dst_ab = ALU_DST_B; 2902a15bb1aSJakub Kicinski if (swreg_type(dst) == NN_REG_GPR_BOTH) 2912a15bb1aSJakub Kicinski reg->wr_both = true; 2922a15bb1aSJakub Kicinski reg->dst = nfp_swreg_to_rereg(dst, true, false, NULL); 2932a15bb1aSJakub Kicinski 2942a15bb1aSJakub Kicinski /* Decode source operands */ 29508859f15SJiong Wang if (swreg_type(lreg) == swreg_type(rreg) && 29608859f15SJiong Wang swreg_type(lreg) != NN_REG_NONE) 2972a15bb1aSJakub Kicinski return -EFAULT; 2982a15bb1aSJakub Kicinski 2992a15bb1aSJakub Kicinski if (swreg_type(lreg) == NN_REG_GPR_B || 3002a15bb1aSJakub Kicinski swreg_type(rreg) == NN_REG_GPR_A) { 3012a15bb1aSJakub Kicinski reg->areg = nfp_swreg_to_rereg(rreg, false, has_imm8, ®->i8); 3022a15bb1aSJakub Kicinski reg->breg = nfp_swreg_to_rereg(lreg, false, has_imm8, ®->i8); 3032a15bb1aSJakub Kicinski reg->swap = true; 3042a15bb1aSJakub Kicinski } else { 3052a15bb1aSJakub Kicinski reg->areg = nfp_swreg_to_rereg(lreg, false, has_imm8, ®->i8); 3062a15bb1aSJakub Kicinski reg->breg = nfp_swreg_to_rereg(rreg, false, has_imm8, ®->i8); 3072a15bb1aSJakub Kicinski } 3082a15bb1aSJakub Kicinski 309995e101fSJakub Kicinski reg->dst_lmextn = swreg_lmextn(dst); 310995e101fSJakub Kicinski reg->src_lmextn = swreg_lmextn(lreg) | swreg_lmextn(rreg); 311995e101fSJakub Kicinski 3122a15bb1aSJakub Kicinski return 0; 3132a15bb1aSJakub Kicinski } 314fd068ddcSJakub Kicinski 315fd068ddcSJakub Kicinski #define NFP_USTORE_ECC_POLY_WORDS 7 316fd068ddcSJakub Kicinski #define NFP_USTORE_OP_BITS 45 317fd068ddcSJakub Kicinski 318fd068ddcSJakub Kicinski static const u64 nfp_ustore_ecc_polynomials[NFP_USTORE_ECC_POLY_WORDS] = { 319fd068ddcSJakub Kicinski 0x0ff800007fffULL, 320fd068ddcSJakub Kicinski 0x11f801ff801fULL, 321fd068ddcSJakub Kicinski 0x1e387e0781e1ULL, 322fd068ddcSJakub Kicinski 0x17cb8e388e22ULL, 323fd068ddcSJakub Kicinski 0x1af5b2c93244ULL, 324fd068ddcSJakub Kicinski 0x1f56d5525488ULL, 325fd068ddcSJakub Kicinski 0x0daf69a46910ULL, 326fd068ddcSJakub Kicinski }; 327fd068ddcSJakub Kicinski 328fd068ddcSJakub Kicinski static bool parity(u64 value) 329fd068ddcSJakub Kicinski { 330fd068ddcSJakub Kicinski return hweight64(value) & 1; 331fd068ddcSJakub Kicinski } 332fd068ddcSJakub Kicinski 333fd068ddcSJakub Kicinski int nfp_ustore_check_valid_no_ecc(u64 insn) 334fd068ddcSJakub Kicinski { 335fd068ddcSJakub Kicinski if (insn & ~GENMASK_ULL(NFP_USTORE_OP_BITS, 0)) 336fd068ddcSJakub Kicinski return -EINVAL; 337fd068ddcSJakub Kicinski 338fd068ddcSJakub Kicinski return 0; 339fd068ddcSJakub Kicinski } 340fd068ddcSJakub Kicinski 341fd068ddcSJakub Kicinski u64 nfp_ustore_calc_ecc_insn(u64 insn) 342fd068ddcSJakub Kicinski { 343fd068ddcSJakub Kicinski u8 ecc = 0; 344fd068ddcSJakub Kicinski int i; 345fd068ddcSJakub Kicinski 346fd068ddcSJakub Kicinski for (i = 0; i < NFP_USTORE_ECC_POLY_WORDS; i++) 347fd068ddcSJakub Kicinski ecc |= parity(nfp_ustore_ecc_polynomials[i] & insn) << i; 348fd068ddcSJakub Kicinski 349fd068ddcSJakub Kicinski return insn | (u64)ecc << NFP_USTORE_OP_BITS; 350fd068ddcSJakub Kicinski } 351