brintos

brintos / linux-shallow public Read only

0
0
Text · 7.3 KiB · 154399c Raw
321 lines · c
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)2/* Copyright (C) 2016-2018 Netronome Systems, Inc. */3 4#include <linux/bitops.h>5#include <linux/errno.h>6#include <linux/kernel.h>7#include <linux/string.h>8#include <linux/types.h>9 10#include "nfp_asm.h"11 12const struct cmd_tgt_act cmd_tgt_act[__CMD_TGT_MAP_SIZE] = {13	[CMD_TGT_WRITE8_SWAP] =		{ 0x02, 0x42 },14	[CMD_TGT_WRITE32_SWAP] =	{ 0x02, 0x5f },15	[CMD_TGT_READ8] =		{ 0x01, 0x43 },16	[CMD_TGT_READ32] =		{ 0x00, 0x5c },17	[CMD_TGT_READ32_LE] =		{ 0x01, 0x5c },18	[CMD_TGT_READ32_SWAP] =		{ 0x02, 0x5c },19	[CMD_TGT_READ_LE] =		{ 0x01, 0x40 },20	[CMD_TGT_READ_SWAP_LE] =	{ 0x03, 0x40 },21	[CMD_TGT_ADD] =			{ 0x00, 0x47 },22	[CMD_TGT_ADD_IMM] =		{ 0x02, 0x47 },23};24 25static bool unreg_is_imm(u16 reg)26{27	return (reg & UR_REG_IMM) == UR_REG_IMM;28}29 30u16 br_get_offset(u64 instr)31{32	u16 addr_lo, addr_hi;33 34	addr_lo = FIELD_GET(OP_BR_ADDR_LO, instr);35	addr_hi = FIELD_GET(OP_BR_ADDR_HI, instr);36 37	return (addr_hi * ((OP_BR_ADDR_LO >> __bf_shf(OP_BR_ADDR_LO)) + 1)) |38		addr_lo;39}40 41void br_set_offset(u64 *instr, u16 offset)42{43	u16 addr_lo, addr_hi;44 45	addr_lo = offset & (OP_BR_ADDR_LO >> __bf_shf(OP_BR_ADDR_LO));46	addr_hi = offset != addr_lo;47	*instr &= ~(OP_BR_ADDR_HI | OP_BR_ADDR_LO);48	*instr |= FIELD_PREP(OP_BR_ADDR_HI, addr_hi);49	*instr |= FIELD_PREP(OP_BR_ADDR_LO, addr_lo);50}51 52void br_add_offset(u64 *instr, u16 offset)53{54	u16 addr;55 56	addr = br_get_offset(*instr);57	br_set_offset(instr, addr + offset);58}59 60static bool immed_can_modify(u64 instr)61{62	if (FIELD_GET(OP_IMMED_INV, instr) ||63	    FIELD_GET(OP_IMMED_SHIFT, instr) ||64	    FIELD_GET(OP_IMMED_WIDTH, instr) != IMMED_WIDTH_ALL) {65		pr_err("Can't decode/encode immed!\n");66		return false;67	}68	return true;69}70 71u16 immed_get_value(u64 instr)72{73	u16 reg;74 75	if (!immed_can_modify(instr))76		return 0;77 78	reg = FIELD_GET(OP_IMMED_A_SRC, instr);79	if (!unreg_is_imm(reg))80		reg = FIELD_GET(OP_IMMED_B_SRC, instr);81 82	return (reg & 0xff) | FIELD_GET(OP_IMMED_IMM, instr) << 8;83}84 85void immed_set_value(u64 *instr, u16 immed)86{87	if (!immed_can_modify(*instr))88		return;89 90	if (unreg_is_imm(FIELD_GET(OP_IMMED_A_SRC, *instr))) {91		*instr &= ~FIELD_PREP(OP_IMMED_A_SRC, 0xff);92		*instr |= FIELD_PREP(OP_IMMED_A_SRC, immed & 0xff);93	} else {94		*instr &= ~FIELD_PREP(OP_IMMED_B_SRC, 0xff);95		*instr |= FIELD_PREP(OP_IMMED_B_SRC, immed & 0xff);96	}97 98	*instr &= ~OP_IMMED_IMM;99	*instr |= FIELD_PREP(OP_IMMED_IMM, immed >> 8);100}101 102void immed_add_value(u64 *instr, u16 offset)103{104	u16 val;105 106	if (!immed_can_modify(*instr))107		return;108 109	val = immed_get_value(*instr);110	immed_set_value(instr, val + offset);111}112 113static u16 nfp_swreg_to_unreg(swreg reg, bool is_dst)114{115	bool lm_id, lm_dec = false;116	u16 val = swreg_value(reg);117 118	switch (swreg_type(reg)) {119	case NN_REG_GPR_A:120	case NN_REG_GPR_B:121	case NN_REG_GPR_BOTH:122		return val;123	case NN_REG_NNR:124		return UR_REG_NN | val;125	case NN_REG_XFER:126		return UR_REG_XFR | val;127	case NN_REG_LMEM:128		lm_id = swreg_lm_idx(reg);129 130		switch (swreg_lm_mode(reg)) {131		case NN_LM_MOD_NONE:132			if (val & ~UR_REG_LM_IDX_MAX) {133				pr_err("LM offset too large\n");134				return 0;135			}136			return UR_REG_LM | FIELD_PREP(UR_REG_LM_IDX, lm_id) |137				val;138		case NN_LM_MOD_DEC:139			lm_dec = true;140			fallthrough;141		case NN_LM_MOD_INC:142			if (val) {143				pr_err("LM offset in inc/dev mode\n");144				return 0;145			}146			return UR_REG_LM | UR_REG_LM_POST_MOD |147				FIELD_PREP(UR_REG_LM_IDX, lm_id) |148				FIELD_PREP(UR_REG_LM_POST_MOD_DEC, lm_dec);149		default:150			pr_err("bad LM mode for unrestricted operands %d\n",151			       swreg_lm_mode(reg));152			return 0;153		}154	case NN_REG_IMM:155		if (val & ~0xff) {156			pr_err("immediate too large\n");157			return 0;158		}159		return UR_REG_IMM_encode(val);160	case NN_REG_NONE:161		return is_dst ? UR_REG_NO_DST : REG_NONE;162	}163 164	pr_err("unrecognized reg encoding %08x\n", reg);165	return 0;166}167 168int swreg_to_unrestricted(swreg dst, swreg lreg, swreg rreg,169			  struct nfp_insn_ur_regs *reg)170{171	memset(reg, 0, sizeof(*reg));172 173	/* Decode destination */174	if (swreg_type(dst) == NN_REG_IMM)175		return -EFAULT;176 177	if (swreg_type(dst) == NN_REG_GPR_B)178		reg->dst_ab = ALU_DST_B;179	if (swreg_type(dst) == NN_REG_GPR_BOTH)180		reg->wr_both = true;181	reg->dst = nfp_swreg_to_unreg(dst, true);182 183	/* Decode source operands */184	if (swreg_type(lreg) == swreg_type(rreg) &&185	    swreg_type(lreg) != NN_REG_NONE)186		return -EFAULT;187 188	if (swreg_type(lreg) == NN_REG_GPR_B ||189	    swreg_type(rreg) == NN_REG_GPR_A) {190		reg->areg = nfp_swreg_to_unreg(rreg, false);191		reg->breg = nfp_swreg_to_unreg(lreg, false);192		reg->swap = true;193	} else {194		reg->areg = nfp_swreg_to_unreg(lreg, false);195		reg->breg = nfp_swreg_to_unreg(rreg, false);196	}197 198	reg->dst_lmextn = swreg_lmextn(dst);199	reg->src_lmextn = swreg_lmextn(lreg) || swreg_lmextn(rreg);200 201	return 0;202}203 204static u16 nfp_swreg_to_rereg(swreg reg, bool is_dst, bool has_imm8, bool *i8)205{206	u16 val = swreg_value(reg);207	bool lm_id;208 209	switch (swreg_type(reg)) {210	case NN_REG_GPR_A:211	case NN_REG_GPR_B:212	case NN_REG_GPR_BOTH:213		return val;214	case NN_REG_XFER:215		return RE_REG_XFR | val;216	case NN_REG_LMEM:217		lm_id = swreg_lm_idx(reg);218 219		if (swreg_lm_mode(reg) != NN_LM_MOD_NONE) {220			pr_err("bad LM mode for restricted operands %d\n",221			       swreg_lm_mode(reg));222			return 0;223		}224 225		if (val & ~RE_REG_LM_IDX_MAX) {226			pr_err("LM offset too large\n");227			return 0;228		}229 230		return RE_REG_LM | FIELD_PREP(RE_REG_LM_IDX, lm_id) | val;231	case NN_REG_IMM:232		if (val & ~(0x7f | has_imm8 << 7)) {233			pr_err("immediate too large\n");234			return 0;235		}236		*i8 = val & 0x80;237		return RE_REG_IMM_encode(val & 0x7f);238	case NN_REG_NONE:239		return is_dst ? RE_REG_NO_DST : REG_NONE;240	case NN_REG_NNR:241		pr_err("NNRs used with restricted encoding\n");242		return 0;243	}244 245	pr_err("unrecognized reg encoding\n");246	return 0;247}248 249int swreg_to_restricted(swreg dst, swreg lreg, swreg rreg,250			struct nfp_insn_re_regs *reg, bool has_imm8)251{252	memset(reg, 0, sizeof(*reg));253 254	/* Decode destination */255	if (swreg_type(dst) == NN_REG_IMM)256		return -EFAULT;257 258	if (swreg_type(dst) == NN_REG_GPR_B)259		reg->dst_ab = ALU_DST_B;260	if (swreg_type(dst) == NN_REG_GPR_BOTH)261		reg->wr_both = true;262	reg->dst = nfp_swreg_to_rereg(dst, true, false, NULL);263 264	/* Decode source operands */265	if (swreg_type(lreg) == swreg_type(rreg) &&266	    swreg_type(lreg) != NN_REG_NONE)267		return -EFAULT;268 269	if (swreg_type(lreg) == NN_REG_GPR_B ||270	    swreg_type(rreg) == NN_REG_GPR_A) {271		reg->areg = nfp_swreg_to_rereg(rreg, false, has_imm8, &reg->i8);272		reg->breg = nfp_swreg_to_rereg(lreg, false, has_imm8, &reg->i8);273		reg->swap = true;274	} else {275		reg->areg = nfp_swreg_to_rereg(lreg, false, has_imm8, &reg->i8);276		reg->breg = nfp_swreg_to_rereg(rreg, false, has_imm8, &reg->i8);277	}278 279	reg->dst_lmextn = swreg_lmextn(dst);280	reg->src_lmextn = swreg_lmextn(lreg) || swreg_lmextn(rreg);281 282	return 0;283}284 285#define NFP_USTORE_ECC_POLY_WORDS		7286#define NFP_USTORE_OP_BITS			45287 288static const u64 nfp_ustore_ecc_polynomials[NFP_USTORE_ECC_POLY_WORDS] = {289	0x0ff800007fffULL,290	0x11f801ff801fULL,291	0x1e387e0781e1ULL,292	0x17cb8e388e22ULL,293	0x1af5b2c93244ULL,294	0x1f56d5525488ULL,295	0x0daf69a46910ULL,296};297 298static bool parity(u64 value)299{300	return hweight64(value) & 1;301}302 303int nfp_ustore_check_valid_no_ecc(u64 insn)304{305	if (insn & ~GENMASK_ULL(NFP_USTORE_OP_BITS, 0))306		return -EINVAL;307 308	return 0;309}310 311u64 nfp_ustore_calc_ecc_insn(u64 insn)312{313	u8 ecc = 0;314	int i;315 316	for (i = 0; i < NFP_USTORE_ECC_POLY_WORDS; i++)317		ecc |= parity(nfp_ustore_ecc_polynomials[i] & insn) << i;318 319	return insn | (u64)ecc << NFP_USTORE_OP_BITS;320}321