mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-04-13 09:59:31 +00:00

Fix &ice_parser_rt::bst_key size. It was wrongly set to 10 instead of 20
in the initial impl commit (see Fixes tag). All usage code assumed it was
of size 20. That was also the initial size present up to v2 of the intro
series [2], but halved by v3 [3] refactor described as "Replace magic
hardcoded values with macros." The introducing series was so big that
some ugliness was unnoticed, same for bugs :/
ICE_BST_KEY_TCAM_SIZE and ICE_BST_TCAM_KEY_SIZE were differing by one.
There was tmp variable @j in the scope of edited function, but was not
used in all places. This ugliness is now gone.
I'm moving ice_parser_rt::pg_prio a few positions up, to fill up one of
the holes in order to compensate for the added 10 bytes to the ::bst_key,
resulting in the same size of the whole as prior to the fix, and minimal
changes in the offsets of the fields.
Extend also the debug dump print of the key to cover all bytes. To not
have string with 20 "%02x" and 20 params, switch to
ice_debug_array_w_prefix().
This fix obsoletes Ahmed's attempt at [1].
[1] https://lore.kernel.org/intel-wired-lan/20240823230847.172295-1-ahmed.zaki@intel.com
[2] https://lore.kernel.org/intel-wired-lan/20230605054641.2865142-13-junfeng.guo@intel.com
[3] https://lore.kernel.org/intel-wired-lan/20230817093442.2576997-13-junfeng.guo@intel.com
Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
Closes: https://lore.kernel.org/intel-wired-lan/b1fb6ff9-b69e-4026-9988-3c783d86c2e0@stanley.mountain
Fixes: 9a4c07aaa0
("ice: add parser execution main loop")
CC: Ahmed Zaki <ahmed.zaki@intel.com>
Reviewed-by: Larysa Zaremba <larysa.zaremba@intel.com>
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Tested-by: Rafal Romanowski <rafal.romanowski@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
859 lines
22 KiB
C
859 lines
22 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* Copyright (C) 2024 Intel Corporation */
|
|
|
|
#include "ice_common.h"
|
|
|
|
static void ice_rt_tsr_set(struct ice_parser_rt *rt, u16 tsr)
|
|
{
|
|
rt->gpr[ICE_GPR_TSR_IDX] = tsr;
|
|
}
|
|
|
|
static void ice_rt_ho_set(struct ice_parser_rt *rt, u16 ho)
|
|
{
|
|
rt->gpr[ICE_GPR_HO_IDX] = ho;
|
|
memcpy(&rt->gpr[ICE_GPR_HV_IDX], &rt->pkt_buf[ho], ICE_GPR_HV_SIZE);
|
|
}
|
|
|
|
static void ice_rt_np_set(struct ice_parser_rt *rt, u16 pc)
|
|
{
|
|
rt->gpr[ICE_GPR_NP_IDX] = pc;
|
|
}
|
|
|
|
static void ice_rt_nn_set(struct ice_parser_rt *rt, u16 node)
|
|
{
|
|
rt->gpr[ICE_GPR_NN_IDX] = node;
|
|
}
|
|
|
|
static void
|
|
ice_rt_flag_set(struct ice_parser_rt *rt, unsigned int idx, bool set)
|
|
{
|
|
struct ice_hw *hw = rt->psr->hw;
|
|
unsigned int word, id;
|
|
|
|
word = idx / ICE_GPR_FLG_SIZE;
|
|
id = idx % ICE_GPR_FLG_SIZE;
|
|
|
|
if (set) {
|
|
rt->gpr[ICE_GPR_FLG_IDX + word] |= (u16)BIT(id);
|
|
ice_debug(hw, ICE_DBG_PARSER, "Set parser flag %u\n", idx);
|
|
} else {
|
|
rt->gpr[ICE_GPR_FLG_IDX + word] &= ~(u16)BIT(id);
|
|
ice_debug(hw, ICE_DBG_PARSER, "Clear parser flag %u\n", idx);
|
|
}
|
|
}
|
|
|
|
static void ice_rt_gpr_set(struct ice_parser_rt *rt, int idx, u16 val)
|
|
{
|
|
struct ice_hw *hw = rt->psr->hw;
|
|
|
|
if (idx == ICE_GPR_HO_IDX)
|
|
ice_rt_ho_set(rt, val);
|
|
else
|
|
rt->gpr[idx] = val;
|
|
|
|
ice_debug(hw, ICE_DBG_PARSER, "Set GPR %d value %d\n", idx, val);
|
|
}
|
|
|
|
static void ice_rt_err_set(struct ice_parser_rt *rt, unsigned int idx, bool set)
|
|
{
|
|
struct ice_hw *hw = rt->psr->hw;
|
|
|
|
if (set) {
|
|
rt->gpr[ICE_GPR_ERR_IDX] |= (u16)BIT(idx);
|
|
ice_debug(hw, ICE_DBG_PARSER, "Set parser error %u\n", idx);
|
|
} else {
|
|
rt->gpr[ICE_GPR_ERR_IDX] &= ~(u16)BIT(idx);
|
|
ice_debug(hw, ICE_DBG_PARSER, "Reset parser error %u\n", idx);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* ice_parser_rt_reset - reset the parser runtime
|
|
* @rt: pointer to the parser runtime
|
|
*/
|
|
void ice_parser_rt_reset(struct ice_parser_rt *rt)
|
|
{
|
|
struct ice_parser *psr = rt->psr;
|
|
struct ice_metainit_item *mi;
|
|
unsigned int i;
|
|
|
|
mi = &psr->mi_table[0];
|
|
|
|
memset(rt, 0, sizeof(*rt));
|
|
rt->psr = psr;
|
|
|
|
ice_rt_tsr_set(rt, mi->tsr);
|
|
ice_rt_ho_set(rt, mi->ho);
|
|
ice_rt_np_set(rt, mi->pc);
|
|
ice_rt_nn_set(rt, mi->pg_rn);
|
|
|
|
for (i = 0; i < ICE_PARSER_FLG_NUM; i++) {
|
|
if (mi->flags & BIT(i))
|
|
ice_rt_flag_set(rt, i, true);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* ice_parser_rt_pktbuf_set - set a packet into parser runtime
|
|
* @rt: pointer to the parser runtime
|
|
* @pkt_buf: buffer with packet data
|
|
* @pkt_len: packet buffer length
|
|
*/
|
|
void ice_parser_rt_pktbuf_set(struct ice_parser_rt *rt, const u8 *pkt_buf,
|
|
int pkt_len)
|
|
{
|
|
int len = min(ICE_PARSER_MAX_PKT_LEN, pkt_len);
|
|
u16 ho = rt->gpr[ICE_GPR_HO_IDX];
|
|
|
|
memcpy(rt->pkt_buf, pkt_buf, len);
|
|
rt->pkt_len = pkt_len;
|
|
|
|
memcpy(&rt->gpr[ICE_GPR_HV_IDX], &rt->pkt_buf[ho], ICE_GPR_HV_SIZE);
|
|
}
|
|
|
|
static void ice_bst_key_init(struct ice_parser_rt *rt,
|
|
struct ice_imem_item *imem)
|
|
{
|
|
u8 tsr = (u8)rt->gpr[ICE_GPR_TSR_IDX];
|
|
u16 ho = rt->gpr[ICE_GPR_HO_IDX];
|
|
u8 *key = rt->bst_key;
|
|
int idd, i;
|
|
|
|
idd = ICE_BST_TCAM_KEY_SIZE - 1;
|
|
if (imem->b_kb.tsr_ctrl)
|
|
key[idd] = tsr;
|
|
else
|
|
key[idd] = imem->b_kb.prio;
|
|
|
|
idd = ICE_BST_TCAM_KEY_SIZE - 2;
|
|
for (i = idd; i >= 0; i--) {
|
|
int j;
|
|
|
|
j = ho + idd - i;
|
|
if (j < ICE_PARSER_MAX_PKT_LEN)
|
|
key[i] = rt->pkt_buf[j];
|
|
else
|
|
key[i] = 0;
|
|
}
|
|
|
|
ice_debug_array_w_prefix(rt->psr->hw, ICE_DBG_PARSER,
|
|
KBUILD_MODNAME ": Generated Boost TCAM Key",
|
|
key, ICE_BST_TCAM_KEY_SIZE);
|
|
}
|
|
|
|
static u16 ice_bit_rev_u16(u16 v, int len)
|
|
{
|
|
return bitrev16(v) >> (BITS_PER_TYPE(v) - len);
|
|
}
|
|
|
|
static u32 ice_bit_rev_u32(u32 v, int len)
|
|
{
|
|
return bitrev32(v) >> (BITS_PER_TYPE(v) - len);
|
|
}
|
|
|
|
static u32 ice_hv_bit_sel(struct ice_parser_rt *rt, int start, int len)
|
|
{
|
|
int offset;
|
|
u32 buf[2];
|
|
u64 val;
|
|
|
|
offset = ICE_GPR_HV_IDX + (start / BITS_PER_TYPE(u16));
|
|
|
|
memcpy(buf, &rt->gpr[offset], sizeof(buf));
|
|
|
|
buf[0] = bitrev8x4(buf[0]);
|
|
buf[1] = bitrev8x4(buf[1]);
|
|
|
|
val = *(u64 *)buf;
|
|
val >>= start % BITS_PER_TYPE(u16);
|
|
|
|
return ice_bit_rev_u32(val, len);
|
|
}
|
|
|
|
static u32 ice_pk_build(struct ice_parser_rt *rt,
|
|
struct ice_np_keybuilder *kb)
|
|
{
|
|
if (kb->opc == ICE_NPKB_OPC_EXTRACT)
|
|
return ice_hv_bit_sel(rt, kb->start_reg0, kb->len_reg1);
|
|
else if (kb->opc == ICE_NPKB_OPC_BUILD)
|
|
return rt->gpr[kb->start_reg0] |
|
|
((u32)rt->gpr[kb->len_reg1] << BITS_PER_TYPE(u16));
|
|
else if (kb->opc == ICE_NPKB_OPC_BYPASS)
|
|
return 0;
|
|
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Unsupported OP Code %u\n",
|
|
kb->opc);
|
|
return U32_MAX;
|
|
}
|
|
|
|
static bool ice_flag_get(struct ice_parser_rt *rt, unsigned int index)
|
|
{
|
|
int word = index / ICE_GPR_FLG_SIZE;
|
|
int id = index % ICE_GPR_FLG_SIZE;
|
|
|
|
return !!(rt->gpr[ICE_GPR_FLG_IDX + word] & (u16)BIT(id));
|
|
}
|
|
|
|
static int ice_imem_pgk_init(struct ice_parser_rt *rt,
|
|
struct ice_imem_item *imem)
|
|
{
|
|
memset(&rt->pg_key, 0, sizeof(rt->pg_key));
|
|
rt->pg_key.next_proto = ice_pk_build(rt, &imem->np_kb);
|
|
if (rt->pg_key.next_proto == U32_MAX)
|
|
return -EINVAL;
|
|
|
|
if (imem->pg_kb.flag0_ena)
|
|
rt->pg_key.flag0 = ice_flag_get(rt, imem->pg_kb.flag0_idx);
|
|
if (imem->pg_kb.flag1_ena)
|
|
rt->pg_key.flag1 = ice_flag_get(rt, imem->pg_kb.flag1_idx);
|
|
if (imem->pg_kb.flag2_ena)
|
|
rt->pg_key.flag2 = ice_flag_get(rt, imem->pg_kb.flag2_idx);
|
|
if (imem->pg_kb.flag3_ena)
|
|
rt->pg_key.flag3 = ice_flag_get(rt, imem->pg_kb.flag3_idx);
|
|
|
|
rt->pg_key.alu_reg = rt->gpr[imem->pg_kb.alu_reg_idx];
|
|
rt->pg_key.node_id = rt->gpr[ICE_GPR_NN_IDX];
|
|
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Generate Parse Graph Key: node_id(%d), flag0-3(%d,%d,%d,%d), boost_idx(%d), alu_reg(0x%04x), next_proto(0x%08x)\n",
|
|
rt->pg_key.node_id,
|
|
rt->pg_key.flag0,
|
|
rt->pg_key.flag1,
|
|
rt->pg_key.flag2,
|
|
rt->pg_key.flag3,
|
|
rt->pg_key.boost_idx,
|
|
rt->pg_key.alu_reg,
|
|
rt->pg_key.next_proto);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void ice_imem_alu0_set(struct ice_parser_rt *rt,
|
|
struct ice_imem_item *imem)
|
|
{
|
|
rt->alu0 = &imem->alu0;
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Load ALU0 from imem pc %d\n",
|
|
imem->idx);
|
|
}
|
|
|
|
static void ice_imem_alu1_set(struct ice_parser_rt *rt,
|
|
struct ice_imem_item *imem)
|
|
{
|
|
rt->alu1 = &imem->alu1;
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Load ALU1 from imem pc %d\n",
|
|
imem->idx);
|
|
}
|
|
|
|
static void ice_imem_alu2_set(struct ice_parser_rt *rt,
|
|
struct ice_imem_item *imem)
|
|
{
|
|
rt->alu2 = &imem->alu2;
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Load ALU2 from imem pc %d\n",
|
|
imem->idx);
|
|
}
|
|
|
|
static void ice_imem_pgp_set(struct ice_parser_rt *rt,
|
|
struct ice_imem_item *imem)
|
|
{
|
|
rt->pg_prio = imem->pg_prio;
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Load PG priority %d from imem pc %d\n",
|
|
rt->pg_prio, imem->idx);
|
|
}
|
|
|
|
static int ice_bst_pgk_init(struct ice_parser_rt *rt,
|
|
struct ice_bst_tcam_item *bst)
|
|
{
|
|
memset(&rt->pg_key, 0, sizeof(rt->pg_key));
|
|
rt->pg_key.boost_idx = bst->hit_idx_grp;
|
|
rt->pg_key.next_proto = ice_pk_build(rt, &bst->np_kb);
|
|
if (rt->pg_key.next_proto == U32_MAX)
|
|
return -EINVAL;
|
|
|
|
if (bst->pg_kb.flag0_ena)
|
|
rt->pg_key.flag0 = ice_flag_get(rt, bst->pg_kb.flag0_idx);
|
|
if (bst->pg_kb.flag1_ena)
|
|
rt->pg_key.flag1 = ice_flag_get(rt, bst->pg_kb.flag1_idx);
|
|
if (bst->pg_kb.flag2_ena)
|
|
rt->pg_key.flag2 = ice_flag_get(rt, bst->pg_kb.flag2_idx);
|
|
if (bst->pg_kb.flag3_ena)
|
|
rt->pg_key.flag3 = ice_flag_get(rt, bst->pg_kb.flag3_idx);
|
|
|
|
rt->pg_key.alu_reg = rt->gpr[bst->pg_kb.alu_reg_idx];
|
|
rt->pg_key.node_id = rt->gpr[ICE_GPR_NN_IDX];
|
|
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Generate Parse Graph Key: node_id(%d), flag0-3(%d,%d,%d,%d), boost_idx(%d), alu_reg(0x%04x), next_proto(0x%08x)\n",
|
|
rt->pg_key.node_id,
|
|
rt->pg_key.flag0,
|
|
rt->pg_key.flag1,
|
|
rt->pg_key.flag2,
|
|
rt->pg_key.flag3,
|
|
rt->pg_key.boost_idx,
|
|
rt->pg_key.alu_reg,
|
|
rt->pg_key.next_proto);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void ice_bst_alu0_set(struct ice_parser_rt *rt,
|
|
struct ice_bst_tcam_item *bst)
|
|
{
|
|
rt->alu0 = &bst->alu0;
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Load ALU0 from boost address %d\n",
|
|
bst->addr);
|
|
}
|
|
|
|
static void ice_bst_alu1_set(struct ice_parser_rt *rt,
|
|
struct ice_bst_tcam_item *bst)
|
|
{
|
|
rt->alu1 = &bst->alu1;
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Load ALU1 from boost address %d\n",
|
|
bst->addr);
|
|
}
|
|
|
|
static void ice_bst_alu2_set(struct ice_parser_rt *rt,
|
|
struct ice_bst_tcam_item *bst)
|
|
{
|
|
rt->alu2 = &bst->alu2;
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Load ALU2 from boost address %d\n",
|
|
bst->addr);
|
|
}
|
|
|
|
static void ice_bst_pgp_set(struct ice_parser_rt *rt,
|
|
struct ice_bst_tcam_item *bst)
|
|
{
|
|
rt->pg_prio = bst->pg_prio;
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Load PG priority %d from boost address %d\n",
|
|
rt->pg_prio, bst->addr);
|
|
}
|
|
|
|
static struct ice_pg_cam_item *ice_rt_pg_cam_match(struct ice_parser_rt *rt)
|
|
{
|
|
struct ice_parser *psr = rt->psr;
|
|
struct ice_pg_cam_item *item;
|
|
|
|
item = ice_pg_cam_match(psr->pg_cam_table, ICE_PG_CAM_TABLE_SIZE,
|
|
&rt->pg_key);
|
|
if (!item)
|
|
item = ice_pg_cam_match(psr->pg_sp_cam_table,
|
|
ICE_PG_SP_CAM_TABLE_SIZE, &rt->pg_key);
|
|
return item;
|
|
}
|
|
|
|
static
|
|
struct ice_pg_nm_cam_item *ice_rt_pg_nm_cam_match(struct ice_parser_rt *rt)
|
|
{
|
|
struct ice_parser *psr = rt->psr;
|
|
struct ice_pg_nm_cam_item *item;
|
|
|
|
item = ice_pg_nm_cam_match(psr->pg_nm_cam_table,
|
|
ICE_PG_NM_CAM_TABLE_SIZE, &rt->pg_key);
|
|
|
|
if (!item)
|
|
item = ice_pg_nm_cam_match(psr->pg_nm_sp_cam_table,
|
|
ICE_PG_NM_SP_CAM_TABLE_SIZE,
|
|
&rt->pg_key);
|
|
return item;
|
|
}
|
|
|
|
static void ice_gpr_add(struct ice_parser_rt *rt, int idx, u16 val)
|
|
{
|
|
rt->pu.gpr_val_upd[idx] = true;
|
|
rt->pu.gpr_val[idx] = val;
|
|
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Pending update for register %d value %d\n",
|
|
idx, val);
|
|
}
|
|
|
|
static void ice_pg_exe(struct ice_parser_rt *rt)
|
|
{
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Executing ParseGraph action ...\n");
|
|
|
|
ice_gpr_add(rt, ICE_GPR_NP_IDX, rt->action->next_pc);
|
|
ice_gpr_add(rt, ICE_GPR_NN_IDX, rt->action->next_node);
|
|
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Executing ParseGraph action done.\n");
|
|
}
|
|
|
|
static void ice_flg_add(struct ice_parser_rt *rt, int idx, bool val)
|
|
{
|
|
rt->pu.flg_msk |= BIT_ULL(idx);
|
|
if (val)
|
|
rt->pu.flg_val |= BIT_ULL(idx);
|
|
else
|
|
rt->pu.flg_val &= ~BIT_ULL(idx);
|
|
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Pending update for flag %d value %d\n",
|
|
idx, val);
|
|
}
|
|
|
|
static void ice_flg_update(struct ice_parser_rt *rt, struct ice_alu *alu)
|
|
{
|
|
u32 hv_bit_sel;
|
|
int i;
|
|
|
|
if (!alu->dedicate_flags_ena)
|
|
return;
|
|
|
|
if (alu->flags_extr_imm) {
|
|
for (i = 0; i < alu->dst_len; i++)
|
|
ice_flg_add(rt, alu->dst_start + i,
|
|
!!(alu->flags_start_imm & BIT(i)));
|
|
} else {
|
|
for (i = 0; i < alu->dst_len; i++) {
|
|
hv_bit_sel = ice_hv_bit_sel(rt,
|
|
alu->flags_start_imm + i,
|
|
1);
|
|
ice_flg_add(rt, alu->dst_start + i, !!hv_bit_sel);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ice_po_update(struct ice_parser_rt *rt, struct ice_alu *alu)
|
|
{
|
|
if (alu->proto_offset_opc == ICE_PO_OFF_HDR_ADD)
|
|
rt->po = (u16)(rt->gpr[ICE_GPR_HO_IDX] + alu->proto_offset);
|
|
else if (alu->proto_offset_opc == ICE_PO_OFF_HDR_SUB)
|
|
rt->po = (u16)(rt->gpr[ICE_GPR_HO_IDX] - alu->proto_offset);
|
|
else if (alu->proto_offset_opc == ICE_PO_OFF_REMAIN)
|
|
rt->po = rt->gpr[ICE_GPR_HO_IDX];
|
|
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Update Protocol Offset = %d\n",
|
|
rt->po);
|
|
}
|
|
|
|
static u16 ice_reg_bit_sel(struct ice_parser_rt *rt, int reg_idx,
|
|
int start, int len)
|
|
{
|
|
int offset;
|
|
u32 val;
|
|
|
|
offset = ICE_GPR_HV_IDX + (start / BITS_PER_TYPE(u16));
|
|
|
|
memcpy(&val, &rt->gpr[offset], sizeof(val));
|
|
|
|
val = bitrev8x4(val);
|
|
val >>= start % BITS_PER_TYPE(u16);
|
|
|
|
return ice_bit_rev_u16(val, len);
|
|
}
|
|
|
|
static void ice_err_add(struct ice_parser_rt *rt, int idx, bool val)
|
|
{
|
|
rt->pu.err_msk |= (u16)BIT(idx);
|
|
if (val)
|
|
rt->pu.flg_val |= (u64)BIT_ULL(idx);
|
|
else
|
|
rt->pu.flg_val &= ~(u64)BIT_ULL(idx);
|
|
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Pending update for error %d value %d\n",
|
|
idx, val);
|
|
}
|
|
|
|
static void ice_dst_reg_bit_set(struct ice_parser_rt *rt, struct ice_alu *alu,
|
|
bool val)
|
|
{
|
|
u16 flg_idx;
|
|
|
|
if (alu->dedicate_flags_ena) {
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "DedicatedFlagsEnable should not be enabled in opcode %d\n",
|
|
alu->opc);
|
|
return;
|
|
}
|
|
|
|
if (alu->dst_reg_id == ICE_GPR_ERR_IDX) {
|
|
if (alu->dst_start >= ICE_PARSER_ERR_NUM) {
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Invalid error %d\n",
|
|
alu->dst_start);
|
|
return;
|
|
}
|
|
ice_err_add(rt, alu->dst_start, val);
|
|
} else if (alu->dst_reg_id >= ICE_GPR_FLG_IDX) {
|
|
flg_idx = (u16)(((alu->dst_reg_id - ICE_GPR_FLG_IDX) << 4) +
|
|
alu->dst_start);
|
|
|
|
if (flg_idx >= ICE_PARSER_FLG_NUM) {
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Invalid flag %d\n",
|
|
flg_idx);
|
|
return;
|
|
}
|
|
ice_flg_add(rt, flg_idx, val);
|
|
} else {
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Unexpected Dest Register Bit set, RegisterID %d Start %d\n",
|
|
alu->dst_reg_id, alu->dst_start);
|
|
}
|
|
}
|
|
|
|
static void ice_alu_exe(struct ice_parser_rt *rt, struct ice_alu *alu)
|
|
{
|
|
u16 dst, src, shift, imm;
|
|
|
|
if (alu->shift_xlate_sel) {
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "shift_xlate_sel != 0 is not expected\n");
|
|
return;
|
|
}
|
|
|
|
ice_po_update(rt, alu);
|
|
ice_flg_update(rt, alu);
|
|
|
|
dst = rt->gpr[alu->dst_reg_id];
|
|
src = ice_reg_bit_sel(rt, alu->src_reg_id,
|
|
alu->src_start, alu->src_len);
|
|
shift = alu->shift_xlate_key;
|
|
imm = alu->imm;
|
|
|
|
switch (alu->opc) {
|
|
case ICE_ALU_PARK:
|
|
break;
|
|
case ICE_ALU_MOV_ADD:
|
|
dst = (src << shift) + imm;
|
|
ice_gpr_add(rt, alu->dst_reg_id, dst);
|
|
break;
|
|
case ICE_ALU_ADD:
|
|
dst += (src << shift) + imm;
|
|
ice_gpr_add(rt, alu->dst_reg_id, dst);
|
|
break;
|
|
case ICE_ALU_ORLT:
|
|
if (src < imm)
|
|
ice_dst_reg_bit_set(rt, alu, true);
|
|
ice_gpr_add(rt, ICE_GPR_NP_IDX, alu->branch_addr);
|
|
break;
|
|
case ICE_ALU_OREQ:
|
|
if (src == imm)
|
|
ice_dst_reg_bit_set(rt, alu, true);
|
|
ice_gpr_add(rt, ICE_GPR_NP_IDX, alu->branch_addr);
|
|
break;
|
|
case ICE_ALU_SETEQ:
|
|
ice_dst_reg_bit_set(rt, alu, src == imm);
|
|
ice_gpr_add(rt, ICE_GPR_NP_IDX, alu->branch_addr);
|
|
break;
|
|
case ICE_ALU_MOV_XOR:
|
|
dst = (src << shift) ^ imm;
|
|
ice_gpr_add(rt, alu->dst_reg_id, dst);
|
|
break;
|
|
default:
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Unsupported ALU instruction %d\n",
|
|
alu->opc);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void ice_alu0_exe(struct ice_parser_rt *rt)
|
|
{
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Executing ALU0 ...\n");
|
|
ice_alu_exe(rt, rt->alu0);
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Executing ALU0 done.\n");
|
|
}
|
|
|
|
static void ice_alu1_exe(struct ice_parser_rt *rt)
|
|
{
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Executing ALU1 ...\n");
|
|
ice_alu_exe(rt, rt->alu1);
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Executing ALU1 done.\n");
|
|
}
|
|
|
|
static void ice_alu2_exe(struct ice_parser_rt *rt)
|
|
{
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Executing ALU2 ...\n");
|
|
ice_alu_exe(rt, rt->alu2);
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Executing ALU2 done.\n");
|
|
}
|
|
|
|
static void ice_pu_exe(struct ice_parser_rt *rt)
|
|
{
|
|
struct ice_gpr_pu *pu = &rt->pu;
|
|
unsigned int i;
|
|
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Updating Registers ...\n");
|
|
|
|
for (i = 0; i < ICE_PARSER_GPR_NUM; i++) {
|
|
if (pu->gpr_val_upd[i])
|
|
ice_rt_gpr_set(rt, i, pu->gpr_val[i]);
|
|
}
|
|
|
|
for (i = 0; i < ICE_PARSER_FLG_NUM; i++) {
|
|
if (pu->flg_msk & BIT(i))
|
|
ice_rt_flag_set(rt, i, pu->flg_val & BIT(i));
|
|
}
|
|
|
|
for (i = 0; i < ICE_PARSER_ERR_NUM; i++) {
|
|
if (pu->err_msk & BIT(i))
|
|
ice_rt_err_set(rt, i, pu->err_val & BIT(i));
|
|
}
|
|
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Updating Registers done.\n");
|
|
}
|
|
|
|
static void ice_alu_pg_exe(struct ice_parser_rt *rt)
|
|
{
|
|
memset(&rt->pu, 0, sizeof(rt->pu));
|
|
|
|
switch (rt->pg_prio) {
|
|
case (ICE_PG_P0):
|
|
ice_pg_exe(rt);
|
|
ice_alu0_exe(rt);
|
|
ice_alu1_exe(rt);
|
|
ice_alu2_exe(rt);
|
|
break;
|
|
case (ICE_PG_P1):
|
|
ice_alu0_exe(rt);
|
|
ice_pg_exe(rt);
|
|
ice_alu1_exe(rt);
|
|
ice_alu2_exe(rt);
|
|
break;
|
|
case (ICE_PG_P2):
|
|
ice_alu0_exe(rt);
|
|
ice_alu1_exe(rt);
|
|
ice_pg_exe(rt);
|
|
ice_alu2_exe(rt);
|
|
break;
|
|
case (ICE_PG_P3):
|
|
ice_alu0_exe(rt);
|
|
ice_alu1_exe(rt);
|
|
ice_alu2_exe(rt);
|
|
ice_pg_exe(rt);
|
|
break;
|
|
}
|
|
|
|
ice_pu_exe(rt);
|
|
|
|
if (rt->action->ho_inc == 0)
|
|
return;
|
|
|
|
if (rt->action->ho_polarity)
|
|
ice_rt_ho_set(rt, rt->gpr[ICE_GPR_HO_IDX] + rt->action->ho_inc);
|
|
else
|
|
ice_rt_ho_set(rt, rt->gpr[ICE_GPR_HO_IDX] - rt->action->ho_inc);
|
|
}
|
|
|
|
static void ice_proto_off_update(struct ice_parser_rt *rt)
|
|
{
|
|
struct ice_parser *psr = rt->psr;
|
|
|
|
if (rt->action->is_pg) {
|
|
struct ice_proto_grp_item *proto_grp =
|
|
&psr->proto_grp_table[rt->action->proto_id];
|
|
u16 po;
|
|
int i;
|
|
|
|
for (i = 0; i < ICE_PROTO_COUNT_PER_GRP; i++) {
|
|
struct ice_proto_off *entry = &proto_grp->po[i];
|
|
|
|
if (entry->proto_id == U8_MAX)
|
|
break;
|
|
|
|
if (!entry->polarity)
|
|
po = rt->po + entry->offset;
|
|
else
|
|
po = rt->po - entry->offset;
|
|
|
|
rt->protocols[entry->proto_id] = true;
|
|
rt->offsets[entry->proto_id] = po;
|
|
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Set Protocol %d at offset %d\n",
|
|
entry->proto_id, po);
|
|
}
|
|
} else {
|
|
rt->protocols[rt->action->proto_id] = true;
|
|
rt->offsets[rt->action->proto_id] = rt->po;
|
|
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Set Protocol %d at offset %d\n",
|
|
rt->action->proto_id, rt->po);
|
|
}
|
|
}
|
|
|
|
static void ice_marker_set(struct ice_parser_rt *rt, int idx)
|
|
{
|
|
unsigned int byte = idx / BITS_PER_BYTE;
|
|
unsigned int bit = idx % BITS_PER_BYTE;
|
|
|
|
rt->markers[byte] |= (u8)BIT(bit);
|
|
}
|
|
|
|
static void ice_marker_update(struct ice_parser_rt *rt)
|
|
{
|
|
struct ice_parser *psr = rt->psr;
|
|
|
|
if (rt->action->is_mg) {
|
|
struct ice_mk_grp_item *mk_grp =
|
|
&psr->mk_grp_table[rt->action->marker_id];
|
|
int i;
|
|
|
|
for (i = 0; i < ICE_MARKER_ID_NUM; i++) {
|
|
u8 marker = mk_grp->markers[i];
|
|
|
|
if (marker == ICE_MARKER_MAX_SIZE)
|
|
break;
|
|
|
|
ice_marker_set(rt, marker);
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Set Marker %d\n",
|
|
marker);
|
|
}
|
|
} else {
|
|
if (rt->action->marker_id != ICE_MARKER_MAX_SIZE)
|
|
ice_marker_set(rt, rt->action->marker_id);
|
|
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Set Marker %d\n",
|
|
rt->action->marker_id);
|
|
}
|
|
}
|
|
|
|
static u16 ice_ptype_resolve(struct ice_parser_rt *rt)
|
|
{
|
|
struct ice_ptype_mk_tcam_item *item;
|
|
struct ice_parser *psr = rt->psr;
|
|
|
|
item = ice_ptype_mk_tcam_match(psr->ptype_mk_tcam_table,
|
|
rt->markers, ICE_MARKER_ID_SIZE);
|
|
if (item)
|
|
return item->ptype;
|
|
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Could not resolve PTYPE\n");
|
|
return U16_MAX;
|
|
}
|
|
|
|
static void ice_proto_off_resolve(struct ice_parser_rt *rt,
|
|
struct ice_parser_result *rslt)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ICE_PO_PAIR_SIZE - 1; i++) {
|
|
if (rt->protocols[i]) {
|
|
rslt->po[rslt->po_num].proto_id = (u8)i;
|
|
rslt->po[rslt->po_num].offset = rt->offsets[i];
|
|
rslt->po_num++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ice_result_resolve(struct ice_parser_rt *rt,
|
|
struct ice_parser_result *rslt)
|
|
{
|
|
struct ice_parser *psr = rt->psr;
|
|
|
|
memset(rslt, 0, sizeof(*rslt));
|
|
|
|
memcpy(&rslt->flags_psr, &rt->gpr[ICE_GPR_FLG_IDX],
|
|
ICE_PARSER_FLAG_PSR_SIZE);
|
|
rslt->flags_pkt = ice_flg_redirect(psr->flg_rd_table, rslt->flags_psr);
|
|
rslt->flags_sw = ice_xlt_kb_flag_get(psr->xlt_kb_sw, rslt->flags_pkt);
|
|
rslt->flags_fd = ice_xlt_kb_flag_get(psr->xlt_kb_fd, rslt->flags_pkt);
|
|
rslt->flags_rss = ice_xlt_kb_flag_get(psr->xlt_kb_rss, rslt->flags_pkt);
|
|
|
|
ice_proto_off_resolve(rt, rslt);
|
|
rslt->ptype = ice_ptype_resolve(rt);
|
|
}
|
|
|
|
/**
|
|
* ice_parser_rt_execute - parser execution routine
|
|
* @rt: pointer to the parser runtime
|
|
* @rslt: input/output parameter to save parser result
|
|
*
|
|
* Return: 0 on success or errno.
|
|
*/
|
|
int ice_parser_rt_execute(struct ice_parser_rt *rt,
|
|
struct ice_parser_result *rslt)
|
|
{
|
|
struct ice_pg_nm_cam_item *pg_nm_cam;
|
|
struct ice_parser *psr = rt->psr;
|
|
struct ice_pg_cam_item *pg_cam;
|
|
int status = 0;
|
|
u16 node;
|
|
u16 pc;
|
|
|
|
node = rt->gpr[ICE_GPR_NN_IDX];
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Start with Node: %u\n", node);
|
|
|
|
while (true) {
|
|
struct ice_bst_tcam_item *bst;
|
|
struct ice_imem_item *imem;
|
|
|
|
pc = rt->gpr[ICE_GPR_NP_IDX];
|
|
imem = &psr->imem_table[pc];
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Load imem at pc: %u\n",
|
|
pc);
|
|
|
|
ice_bst_key_init(rt, imem);
|
|
bst = ice_bst_tcam_match(psr->bst_tcam_table, rt->bst_key);
|
|
if (!bst) {
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "No Boost TCAM Match\n");
|
|
status = ice_imem_pgk_init(rt, imem);
|
|
if (status)
|
|
break;
|
|
ice_imem_alu0_set(rt, imem);
|
|
ice_imem_alu1_set(rt, imem);
|
|
ice_imem_alu2_set(rt, imem);
|
|
ice_imem_pgp_set(rt, imem);
|
|
} else {
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Boost TCAM Match address: %u\n",
|
|
bst->addr);
|
|
if (imem->b_m.pg) {
|
|
status = ice_bst_pgk_init(rt, bst);
|
|
if (status)
|
|
break;
|
|
ice_bst_pgp_set(rt, bst);
|
|
} else {
|
|
status = ice_imem_pgk_init(rt, imem);
|
|
if (status)
|
|
break;
|
|
ice_imem_pgp_set(rt, imem);
|
|
}
|
|
|
|
if (imem->b_m.alu0)
|
|
ice_bst_alu0_set(rt, bst);
|
|
else
|
|
ice_imem_alu0_set(rt, imem);
|
|
|
|
if (imem->b_m.alu1)
|
|
ice_bst_alu1_set(rt, bst);
|
|
else
|
|
ice_imem_alu1_set(rt, imem);
|
|
|
|
if (imem->b_m.alu2)
|
|
ice_bst_alu2_set(rt, bst);
|
|
else
|
|
ice_imem_alu2_set(rt, imem);
|
|
}
|
|
|
|
rt->action = NULL;
|
|
pg_cam = ice_rt_pg_cam_match(rt);
|
|
if (!pg_cam) {
|
|
pg_nm_cam = ice_rt_pg_nm_cam_match(rt);
|
|
if (pg_nm_cam) {
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Match ParseGraph Nomatch CAM Address %u\n",
|
|
pg_nm_cam->idx);
|
|
rt->action = &pg_nm_cam->action;
|
|
}
|
|
} else {
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Match ParseGraph CAM Address %u\n",
|
|
pg_cam->idx);
|
|
rt->action = &pg_cam->action;
|
|
}
|
|
|
|
if (!rt->action) {
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Failed to match ParseGraph CAM, stop parsing.\n");
|
|
status = -EINVAL;
|
|
break;
|
|
}
|
|
|
|
ice_alu_pg_exe(rt);
|
|
ice_marker_update(rt);
|
|
ice_proto_off_update(rt);
|
|
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Go to node %u\n",
|
|
rt->action->next_node);
|
|
|
|
if (rt->action->is_last_round) {
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Last Round in ParseGraph Action, stop parsing.\n");
|
|
break;
|
|
}
|
|
|
|
if (rt->gpr[ICE_GPR_HO_IDX] >= rt->pkt_len) {
|
|
ice_debug(rt->psr->hw, ICE_DBG_PARSER, "Header Offset (%u) is larger than packet len (%u), stop parsing\n",
|
|
rt->gpr[ICE_GPR_HO_IDX], rt->pkt_len);
|
|
break;
|
|
}
|
|
}
|
|
|
|
ice_result_resolve(rt, rslt);
|
|
|
|
return status;
|
|
}
|