171d10453SEric Joyner /* SPDX-License-Identifier: BSD-3-Clause */ 2*015f8cc5SEric Joyner /* Copyright (c) 2024, Intel Corporation 371d10453SEric Joyner * All rights reserved. 471d10453SEric Joyner * 571d10453SEric Joyner * Redistribution and use in source and binary forms, with or without 671d10453SEric Joyner * modification, are permitted provided that the following conditions are met: 771d10453SEric Joyner * 871d10453SEric Joyner * 1. Redistributions of source code must retain the above copyright notice, 971d10453SEric Joyner * this list of conditions and the following disclaimer. 1071d10453SEric Joyner * 1171d10453SEric Joyner * 2. Redistributions in binary form must reproduce the above copyright 1271d10453SEric Joyner * notice, this list of conditions and the following disclaimer in the 1371d10453SEric Joyner * documentation and/or other materials provided with the distribution. 1471d10453SEric Joyner * 1571d10453SEric Joyner * 3. Neither the name of the Intel Corporation nor the names of its 1671d10453SEric Joyner * contributors may be used to endorse or promote products derived from 1771d10453SEric Joyner * this software without specific prior written permission. 1871d10453SEric Joyner * 1971d10453SEric Joyner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2071d10453SEric Joyner * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2171d10453SEric Joyner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2271d10453SEric Joyner * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 2371d10453SEric Joyner * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2471d10453SEric Joyner * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2571d10453SEric Joyner * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2671d10453SEric Joyner * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2771d10453SEric Joyner * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2871d10453SEric Joyner * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2971d10453SEric Joyner * POSSIBILITY OF SUCH DAMAGE. 3071d10453SEric Joyner */ 3171d10453SEric Joyner 3271d10453SEric Joyner #include "ice_common.h" 338923de59SPiotr Kubaj #include "ice_ddp_common.h" 3471d10453SEric Joyner #include "ice_flex_pipe.h" 3571d10453SEric Joyner #include "ice_protocol_type.h" 3671d10453SEric Joyner #include "ice_flow.h" 3771d10453SEric Joyner 3871d10453SEric Joyner static const struct ice_tunnel_type_scan tnls[] = { 3971d10453SEric Joyner { TNL_VXLAN, "TNL_VXLAN_PF" }, 4071d10453SEric Joyner { TNL_GENEVE, "TNL_GENEVE_PF" }, 4171d10453SEric Joyner { TNL_LAST, "" } 4271d10453SEric Joyner }; 4371d10453SEric Joyner 4471d10453SEric Joyner static const u32 ice_sect_lkup[ICE_BLK_COUNT][ICE_SECT_COUNT] = { 4571d10453SEric Joyner /* SWITCH */ 4671d10453SEric Joyner { 4771d10453SEric Joyner ICE_SID_XLT0_SW, 4871d10453SEric Joyner ICE_SID_XLT_KEY_BUILDER_SW, 4971d10453SEric Joyner ICE_SID_XLT1_SW, 5071d10453SEric Joyner ICE_SID_XLT2_SW, 5171d10453SEric Joyner ICE_SID_PROFID_TCAM_SW, 5271d10453SEric Joyner ICE_SID_PROFID_REDIR_SW, 5371d10453SEric Joyner ICE_SID_FLD_VEC_SW, 5471d10453SEric Joyner ICE_SID_CDID_KEY_BUILDER_SW, 5571d10453SEric Joyner ICE_SID_CDID_REDIR_SW 5671d10453SEric Joyner }, 5771d10453SEric Joyner 5871d10453SEric Joyner /* ACL */ 5971d10453SEric Joyner { 6071d10453SEric Joyner ICE_SID_XLT0_ACL, 6171d10453SEric Joyner ICE_SID_XLT_KEY_BUILDER_ACL, 6271d10453SEric Joyner ICE_SID_XLT1_ACL, 6371d10453SEric Joyner ICE_SID_XLT2_ACL, 6471d10453SEric Joyner ICE_SID_PROFID_TCAM_ACL, 6571d10453SEric Joyner ICE_SID_PROFID_REDIR_ACL, 6671d10453SEric Joyner ICE_SID_FLD_VEC_ACL, 6771d10453SEric Joyner ICE_SID_CDID_KEY_BUILDER_ACL, 6871d10453SEric Joyner ICE_SID_CDID_REDIR_ACL 6971d10453SEric Joyner }, 7071d10453SEric Joyner 7171d10453SEric Joyner /* FD */ 7271d10453SEric Joyner { 7371d10453SEric Joyner ICE_SID_XLT0_FD, 7471d10453SEric Joyner ICE_SID_XLT_KEY_BUILDER_FD, 7571d10453SEric Joyner ICE_SID_XLT1_FD, 7671d10453SEric Joyner ICE_SID_XLT2_FD, 7771d10453SEric Joyner ICE_SID_PROFID_TCAM_FD, 7871d10453SEric Joyner ICE_SID_PROFID_REDIR_FD, 7971d10453SEric Joyner ICE_SID_FLD_VEC_FD, 8071d10453SEric Joyner ICE_SID_CDID_KEY_BUILDER_FD, 8171d10453SEric Joyner ICE_SID_CDID_REDIR_FD 8271d10453SEric Joyner }, 8371d10453SEric Joyner 8471d10453SEric Joyner /* RSS */ 8571d10453SEric Joyner { 8671d10453SEric Joyner ICE_SID_XLT0_RSS, 8771d10453SEric Joyner ICE_SID_XLT_KEY_BUILDER_RSS, 8871d10453SEric Joyner ICE_SID_XLT1_RSS, 8971d10453SEric Joyner ICE_SID_XLT2_RSS, 9071d10453SEric Joyner ICE_SID_PROFID_TCAM_RSS, 9171d10453SEric Joyner ICE_SID_PROFID_REDIR_RSS, 9271d10453SEric Joyner ICE_SID_FLD_VEC_RSS, 9371d10453SEric Joyner ICE_SID_CDID_KEY_BUILDER_RSS, 9471d10453SEric Joyner ICE_SID_CDID_REDIR_RSS 9571d10453SEric Joyner }, 9671d10453SEric Joyner 9771d10453SEric Joyner /* PE */ 9871d10453SEric Joyner { 9971d10453SEric Joyner ICE_SID_XLT0_PE, 10071d10453SEric Joyner ICE_SID_XLT_KEY_BUILDER_PE, 10171d10453SEric Joyner ICE_SID_XLT1_PE, 10271d10453SEric Joyner ICE_SID_XLT2_PE, 10371d10453SEric Joyner ICE_SID_PROFID_TCAM_PE, 10471d10453SEric Joyner ICE_SID_PROFID_REDIR_PE, 10571d10453SEric Joyner ICE_SID_FLD_VEC_PE, 10671d10453SEric Joyner ICE_SID_CDID_KEY_BUILDER_PE, 10771d10453SEric Joyner ICE_SID_CDID_REDIR_PE 10871d10453SEric Joyner } 10971d10453SEric Joyner }; 11071d10453SEric Joyner 11171d10453SEric Joyner /** 11271d10453SEric Joyner * ice_sect_id - returns section ID 11371d10453SEric Joyner * @blk: block type 11471d10453SEric Joyner * @sect: section type 11571d10453SEric Joyner * 11671d10453SEric Joyner * This helper function returns the proper section ID given a block type and a 11771d10453SEric Joyner * section type. 11871d10453SEric Joyner */ 11971d10453SEric Joyner static u32 ice_sect_id(enum ice_block blk, enum ice_sect sect) 12071d10453SEric Joyner { 12171d10453SEric Joyner return ice_sect_lkup[blk][sect]; 12271d10453SEric Joyner } 12371d10453SEric Joyner 12471d10453SEric Joyner /** 1259cf1841cSEric Joyner * ice_add_tunnel_hint 1269cf1841cSEric Joyner * @hw: pointer to the HW structure 1279cf1841cSEric Joyner * @label_name: label text 1289cf1841cSEric Joyner * @val: value of the tunnel port boost entry 1299cf1841cSEric Joyner */ 1308923de59SPiotr Kubaj void ice_add_tunnel_hint(struct ice_hw *hw, char *label_name, u16 val) 1319cf1841cSEric Joyner { 1329cf1841cSEric Joyner if (hw->tnl.count < ICE_TUNNEL_MAX_ENTRIES) { 1339cf1841cSEric Joyner u16 i; 1349cf1841cSEric Joyner 1359cf1841cSEric Joyner for (i = 0; tnls[i].type != TNL_LAST; i++) { 1369cf1841cSEric Joyner size_t len = strlen(tnls[i].label_prefix); 1379cf1841cSEric Joyner 1389cf1841cSEric Joyner /* Look for matching label start, before continuing */ 1399cf1841cSEric Joyner if (strncmp(label_name, tnls[i].label_prefix, len)) 1409cf1841cSEric Joyner continue; 1419cf1841cSEric Joyner 1429cf1841cSEric Joyner /* Make sure this label matches our PF. Note that the PF 1439cf1841cSEric Joyner * character ('0' - '7') will be located where our 1449cf1841cSEric Joyner * prefix string's null terminator is located. 1459cf1841cSEric Joyner */ 1469cf1841cSEric Joyner if ((label_name[len] - '0') == hw->pf_id) { 1479cf1841cSEric Joyner hw->tnl.tbl[hw->tnl.count].type = tnls[i].type; 1489cf1841cSEric Joyner hw->tnl.tbl[hw->tnl.count].valid = false; 1499cf1841cSEric Joyner hw->tnl.tbl[hw->tnl.count].in_use = false; 1509cf1841cSEric Joyner hw->tnl.tbl[hw->tnl.count].marked = false; 1519cf1841cSEric Joyner hw->tnl.tbl[hw->tnl.count].boost_addr = val; 1529cf1841cSEric Joyner hw->tnl.tbl[hw->tnl.count].port = 0; 1539cf1841cSEric Joyner hw->tnl.count++; 1549cf1841cSEric Joyner break; 1559cf1841cSEric Joyner } 1569cf1841cSEric Joyner } 1579cf1841cSEric Joyner } 1589cf1841cSEric Joyner } 1599cf1841cSEric Joyner 16071d10453SEric Joyner /* Key creation */ 16171d10453SEric Joyner 16271d10453SEric Joyner #define ICE_DC_KEY 0x1 /* don't care */ 16371d10453SEric Joyner #define ICE_DC_KEYINV 0x1 16471d10453SEric Joyner #define ICE_NM_KEY 0x0 /* never match */ 16571d10453SEric Joyner #define ICE_NM_KEYINV 0x0 16671d10453SEric Joyner #define ICE_0_KEY 0x1 /* match 0 */ 16771d10453SEric Joyner #define ICE_0_KEYINV 0x0 16871d10453SEric Joyner #define ICE_1_KEY 0x0 /* match 1 */ 16971d10453SEric Joyner #define ICE_1_KEYINV 0x1 17071d10453SEric Joyner 17171d10453SEric Joyner /** 17271d10453SEric Joyner * ice_gen_key_word - generate 16-bits of a key/mask word 17371d10453SEric Joyner * @val: the value 17471d10453SEric Joyner * @valid: valid bits mask (change only the valid bits) 17571d10453SEric Joyner * @dont_care: don't care mask 17671d10453SEric Joyner * @nvr_mtch: never match mask 17771d10453SEric Joyner * @key: pointer to an array of where the resulting key portion 17871d10453SEric Joyner * @key_inv: pointer to an array of where the resulting key invert portion 17971d10453SEric Joyner * 18071d10453SEric Joyner * This function generates 16-bits from a 8-bit value, an 8-bit don't care mask 18171d10453SEric Joyner * and an 8-bit never match mask. The 16-bits of output are divided into 8 bits 18271d10453SEric Joyner * of key and 8 bits of key invert. 18371d10453SEric Joyner * 18471d10453SEric Joyner * '0' = b01, always match a 0 bit 18571d10453SEric Joyner * '1' = b10, always match a 1 bit 18671d10453SEric Joyner * '?' = b11, don't care bit (always matches) 18771d10453SEric Joyner * '~' = b00, never match bit 18871d10453SEric Joyner * 18971d10453SEric Joyner * Input: 19071d10453SEric Joyner * val: b0 1 0 1 0 1 19171d10453SEric Joyner * dont_care: b0 0 1 1 0 0 19271d10453SEric Joyner * never_mtch: b0 0 0 0 1 1 19371d10453SEric Joyner * ------------------------------ 19471d10453SEric Joyner * Result: key: b01 10 11 11 00 00 19571d10453SEric Joyner */ 19671d10453SEric Joyner static enum ice_status 19771d10453SEric Joyner ice_gen_key_word(u8 val, u8 valid, u8 dont_care, u8 nvr_mtch, u8 *key, 19871d10453SEric Joyner u8 *key_inv) 19971d10453SEric Joyner { 20071d10453SEric Joyner u8 in_key = *key, in_key_inv = *key_inv; 20171d10453SEric Joyner u8 i; 20271d10453SEric Joyner 20371d10453SEric Joyner /* 'dont_care' and 'nvr_mtch' masks cannot overlap */ 20471d10453SEric Joyner if ((dont_care ^ nvr_mtch) != (dont_care | nvr_mtch)) 20571d10453SEric Joyner return ICE_ERR_CFG; 20671d10453SEric Joyner 20771d10453SEric Joyner *key = 0; 20871d10453SEric Joyner *key_inv = 0; 20971d10453SEric Joyner 21071d10453SEric Joyner /* encode the 8 bits into 8-bit key and 8-bit key invert */ 21171d10453SEric Joyner for (i = 0; i < 8; i++) { 21271d10453SEric Joyner *key >>= 1; 21371d10453SEric Joyner *key_inv >>= 1; 21471d10453SEric Joyner 21571d10453SEric Joyner if (!(valid & 0x1)) { /* change only valid bits */ 21671d10453SEric Joyner *key |= (in_key & 0x1) << 7; 21771d10453SEric Joyner *key_inv |= (in_key_inv & 0x1) << 7; 21871d10453SEric Joyner } else if (dont_care & 0x1) { /* don't care bit */ 21971d10453SEric Joyner *key |= ICE_DC_KEY << 7; 22071d10453SEric Joyner *key_inv |= ICE_DC_KEYINV << 7; 22171d10453SEric Joyner } else if (nvr_mtch & 0x1) { /* never match bit */ 22271d10453SEric Joyner *key |= ICE_NM_KEY << 7; 22371d10453SEric Joyner *key_inv |= ICE_NM_KEYINV << 7; 22471d10453SEric Joyner } else if (val & 0x01) { /* exact 1 match */ 22571d10453SEric Joyner *key |= ICE_1_KEY << 7; 22671d10453SEric Joyner *key_inv |= ICE_1_KEYINV << 7; 22771d10453SEric Joyner } else { /* exact 0 match */ 22871d10453SEric Joyner *key |= ICE_0_KEY << 7; 22971d10453SEric Joyner *key_inv |= ICE_0_KEYINV << 7; 23071d10453SEric Joyner } 23171d10453SEric Joyner 23271d10453SEric Joyner dont_care >>= 1; 23371d10453SEric Joyner nvr_mtch >>= 1; 23471d10453SEric Joyner valid >>= 1; 23571d10453SEric Joyner val >>= 1; 23671d10453SEric Joyner in_key >>= 1; 23771d10453SEric Joyner in_key_inv >>= 1; 23871d10453SEric Joyner } 23971d10453SEric Joyner 24071d10453SEric Joyner return ICE_SUCCESS; 24171d10453SEric Joyner } 24271d10453SEric Joyner 24371d10453SEric Joyner /** 24471d10453SEric Joyner * ice_bits_max_set - determine if the number of bits set is within a maximum 24571d10453SEric Joyner * @mask: pointer to the byte array which is the mask 24671d10453SEric Joyner * @size: the number of bytes in the mask 24771d10453SEric Joyner * @max: the max number of set bits 24871d10453SEric Joyner * 24971d10453SEric Joyner * This function determines if there are at most 'max' number of bits set in an 25071d10453SEric Joyner * array. Returns true if the number for bits set is <= max or will return false 25171d10453SEric Joyner * otherwise. 25271d10453SEric Joyner */ 25371d10453SEric Joyner static bool ice_bits_max_set(const u8 *mask, u16 size, u16 max) 25471d10453SEric Joyner { 25571d10453SEric Joyner u16 count = 0; 25671d10453SEric Joyner u16 i; 25771d10453SEric Joyner 25871d10453SEric Joyner /* check each byte */ 25971d10453SEric Joyner for (i = 0; i < size; i++) { 26071d10453SEric Joyner /* if 0, go to next byte */ 26171d10453SEric Joyner if (!mask[i]) 26271d10453SEric Joyner continue; 26371d10453SEric Joyner 26471d10453SEric Joyner /* We know there is at least one set bit in this byte because of 26571d10453SEric Joyner * the above check; if we already have found 'max' number of 26671d10453SEric Joyner * bits set, then we can return failure now. 26771d10453SEric Joyner */ 26871d10453SEric Joyner if (count == max) 26971d10453SEric Joyner return false; 27071d10453SEric Joyner 27171d10453SEric Joyner /* count the bits in this byte, checking threshold */ 27271d10453SEric Joyner count += ice_hweight8(mask[i]); 27371d10453SEric Joyner if (count > max) 27471d10453SEric Joyner return false; 27571d10453SEric Joyner } 27671d10453SEric Joyner 27771d10453SEric Joyner return true; 27871d10453SEric Joyner } 27971d10453SEric Joyner 28071d10453SEric Joyner /** 28171d10453SEric Joyner * ice_set_key - generate a variable sized key with multiples of 16-bits 28271d10453SEric Joyner * @key: pointer to where the key will be stored 28371d10453SEric Joyner * @size: the size of the complete key in bytes (must be even) 28471d10453SEric Joyner * @val: array of 8-bit values that makes up the value portion of the key 28571d10453SEric Joyner * @upd: array of 8-bit masks that determine what key portion to update 28671d10453SEric Joyner * @dc: array of 8-bit masks that make up the don't care mask 28771d10453SEric Joyner * @nm: array of 8-bit masks that make up the never match mask 28871d10453SEric Joyner * @off: the offset of the first byte in the key to update 28971d10453SEric Joyner * @len: the number of bytes in the key update 29071d10453SEric Joyner * 29171d10453SEric Joyner * This function generates a key from a value, a don't care mask and a never 29271d10453SEric Joyner * match mask. 29371d10453SEric Joyner * upd, dc, and nm are optional parameters, and can be NULL: 2947d7af7f8SEric Joyner * upd == NULL --> upd mask is all 1's (update all bits) 29571d10453SEric Joyner * dc == NULL --> dc mask is all 0's (no don't care bits) 29671d10453SEric Joyner * nm == NULL --> nm mask is all 0's (no never match bits) 29771d10453SEric Joyner */ 2987d7af7f8SEric Joyner static enum ice_status 29971d10453SEric Joyner ice_set_key(u8 *key, u16 size, u8 *val, u8 *upd, u8 *dc, u8 *nm, u16 off, 30071d10453SEric Joyner u16 len) 30171d10453SEric Joyner { 30271d10453SEric Joyner u16 half_size; 30371d10453SEric Joyner u16 i; 30471d10453SEric Joyner 30571d10453SEric Joyner /* size must be a multiple of 2 bytes. */ 30671d10453SEric Joyner if (size % 2) 30771d10453SEric Joyner return ICE_ERR_CFG; 30871d10453SEric Joyner half_size = size / 2; 30971d10453SEric Joyner 31071d10453SEric Joyner if (off + len > half_size) 31171d10453SEric Joyner return ICE_ERR_CFG; 31271d10453SEric Joyner 31371d10453SEric Joyner /* Make sure at most one bit is set in the never match mask. Having more 31471d10453SEric Joyner * than one never match mask bit set will cause HW to consume excessive 31571d10453SEric Joyner * power otherwise; this is a power management efficiency check. 31671d10453SEric Joyner */ 31771d10453SEric Joyner #define ICE_NVR_MTCH_BITS_MAX 1 31871d10453SEric Joyner if (nm && !ice_bits_max_set(nm, len, ICE_NVR_MTCH_BITS_MAX)) 31971d10453SEric Joyner return ICE_ERR_CFG; 32071d10453SEric Joyner 32171d10453SEric Joyner for (i = 0; i < len; i++) 32271d10453SEric Joyner if (ice_gen_key_word(val[i], upd ? upd[i] : 0xff, 32371d10453SEric Joyner dc ? dc[i] : 0, nm ? nm[i] : 0, 32471d10453SEric Joyner key + off + i, key + half_size + off + i)) 32571d10453SEric Joyner return ICE_ERR_CFG; 32671d10453SEric Joyner 32771d10453SEric Joyner return ICE_SUCCESS; 32871d10453SEric Joyner } 32971d10453SEric Joyner 33071d10453SEric Joyner /** 33171d10453SEric Joyner * ice_tunnel_port_in_use_hlpr - helper function to determine tunnel usage 33271d10453SEric Joyner * @hw: pointer to the HW structure 33371d10453SEric Joyner * @port: port to search for 33471d10453SEric Joyner * @index: optionally returns index 33571d10453SEric Joyner * 33671d10453SEric Joyner * Returns whether a port is already in use as a tunnel, and optionally its 33771d10453SEric Joyner * index 33871d10453SEric Joyner */ 33971d10453SEric Joyner static bool ice_tunnel_port_in_use_hlpr(struct ice_hw *hw, u16 port, u16 *index) 34071d10453SEric Joyner { 34171d10453SEric Joyner u16 i; 34271d10453SEric Joyner 34371d10453SEric Joyner for (i = 0; i < hw->tnl.count && i < ICE_TUNNEL_MAX_ENTRIES; i++) 34471d10453SEric Joyner if (hw->tnl.tbl[i].in_use && hw->tnl.tbl[i].port == port) { 34571d10453SEric Joyner if (index) 34671d10453SEric Joyner *index = i; 34771d10453SEric Joyner return true; 34871d10453SEric Joyner } 34971d10453SEric Joyner 35071d10453SEric Joyner return false; 35171d10453SEric Joyner } 35271d10453SEric Joyner 35371d10453SEric Joyner /** 35471d10453SEric Joyner * ice_tunnel_port_in_use 35571d10453SEric Joyner * @hw: pointer to the HW structure 35671d10453SEric Joyner * @port: port to search for 35771d10453SEric Joyner * @index: optionally returns index 35871d10453SEric Joyner * 35971d10453SEric Joyner * Returns whether a port is already in use as a tunnel, and optionally its 36071d10453SEric Joyner * index 36171d10453SEric Joyner */ 36271d10453SEric Joyner bool ice_tunnel_port_in_use(struct ice_hw *hw, u16 port, u16 *index) 36371d10453SEric Joyner { 36471d10453SEric Joyner bool res; 36571d10453SEric Joyner 36671d10453SEric Joyner ice_acquire_lock(&hw->tnl_lock); 36771d10453SEric Joyner res = ice_tunnel_port_in_use_hlpr(hw, port, index); 36871d10453SEric Joyner ice_release_lock(&hw->tnl_lock); 36971d10453SEric Joyner 37071d10453SEric Joyner return res; 37171d10453SEric Joyner } 37271d10453SEric Joyner 37371d10453SEric Joyner /** 37471d10453SEric Joyner * ice_tunnel_get_type 37571d10453SEric Joyner * @hw: pointer to the HW structure 37671d10453SEric Joyner * @port: port to search for 37771d10453SEric Joyner * @type: returns tunnel index 37871d10453SEric Joyner * 37971d10453SEric Joyner * For a given port number, will return the type of tunnel. 38071d10453SEric Joyner */ 38171d10453SEric Joyner bool 38271d10453SEric Joyner ice_tunnel_get_type(struct ice_hw *hw, u16 port, enum ice_tunnel_type *type) 38371d10453SEric Joyner { 38471d10453SEric Joyner bool res = false; 38571d10453SEric Joyner u16 i; 38671d10453SEric Joyner 38771d10453SEric Joyner ice_acquire_lock(&hw->tnl_lock); 38871d10453SEric Joyner 38971d10453SEric Joyner for (i = 0; i < hw->tnl.count && i < ICE_TUNNEL_MAX_ENTRIES; i++) 39071d10453SEric Joyner if (hw->tnl.tbl[i].in_use && hw->tnl.tbl[i].port == port) { 39171d10453SEric Joyner *type = hw->tnl.tbl[i].type; 39271d10453SEric Joyner res = true; 39371d10453SEric Joyner break; 39471d10453SEric Joyner } 39571d10453SEric Joyner 39671d10453SEric Joyner ice_release_lock(&hw->tnl_lock); 39771d10453SEric Joyner 39871d10453SEric Joyner return res; 39971d10453SEric Joyner } 40071d10453SEric Joyner 40171d10453SEric Joyner /** 40271d10453SEric Joyner * ice_find_free_tunnel_entry 40371d10453SEric Joyner * @hw: pointer to the HW structure 40471d10453SEric Joyner * @type: tunnel type 40571d10453SEric Joyner * @index: optionally returns index 40671d10453SEric Joyner * 40771d10453SEric Joyner * Returns whether there is a free tunnel entry, and optionally its index 40871d10453SEric Joyner */ 40971d10453SEric Joyner static bool 41071d10453SEric Joyner ice_find_free_tunnel_entry(struct ice_hw *hw, enum ice_tunnel_type type, 41171d10453SEric Joyner u16 *index) 41271d10453SEric Joyner { 41371d10453SEric Joyner u16 i; 41471d10453SEric Joyner 41571d10453SEric Joyner for (i = 0; i < hw->tnl.count && i < ICE_TUNNEL_MAX_ENTRIES; i++) 41671d10453SEric Joyner if (hw->tnl.tbl[i].valid && !hw->tnl.tbl[i].in_use && 41771d10453SEric Joyner hw->tnl.tbl[i].type == type) { 41871d10453SEric Joyner if (index) 41971d10453SEric Joyner *index = i; 42071d10453SEric Joyner return true; 42171d10453SEric Joyner } 42271d10453SEric Joyner 42371d10453SEric Joyner return false; 42471d10453SEric Joyner } 42571d10453SEric Joyner 42671d10453SEric Joyner /** 42771d10453SEric Joyner * ice_get_open_tunnel_port - retrieve an open tunnel port 42871d10453SEric Joyner * @hw: pointer to the HW structure 42971d10453SEric Joyner * @type: tunnel type (TNL_ALL will return any open port) 43071d10453SEric Joyner * @port: returns open port 43171d10453SEric Joyner */ 43271d10453SEric Joyner bool 43371d10453SEric Joyner ice_get_open_tunnel_port(struct ice_hw *hw, enum ice_tunnel_type type, 43471d10453SEric Joyner u16 *port) 43571d10453SEric Joyner { 43671d10453SEric Joyner bool res = false; 43771d10453SEric Joyner u16 i; 43871d10453SEric Joyner 43971d10453SEric Joyner ice_acquire_lock(&hw->tnl_lock); 44071d10453SEric Joyner 44171d10453SEric Joyner for (i = 0; i < hw->tnl.count && i < ICE_TUNNEL_MAX_ENTRIES; i++) 44271d10453SEric Joyner if (hw->tnl.tbl[i].valid && hw->tnl.tbl[i].in_use && 44371d10453SEric Joyner (type == TNL_ALL || hw->tnl.tbl[i].type == type)) { 44471d10453SEric Joyner *port = hw->tnl.tbl[i].port; 44571d10453SEric Joyner res = true; 44671d10453SEric Joyner break; 44771d10453SEric Joyner } 44871d10453SEric Joyner 44971d10453SEric Joyner ice_release_lock(&hw->tnl_lock); 45071d10453SEric Joyner 45171d10453SEric Joyner return res; 45271d10453SEric Joyner } 45371d10453SEric Joyner 45471d10453SEric Joyner /** 45571d10453SEric Joyner * ice_create_tunnel 45671d10453SEric Joyner * @hw: pointer to the HW structure 45771d10453SEric Joyner * @type: type of tunnel 45871d10453SEric Joyner * @port: port of tunnel to create 45971d10453SEric Joyner * 46071d10453SEric Joyner * Create a tunnel by updating the parse graph in the parser. We do that by 46171d10453SEric Joyner * creating a package buffer with the tunnel info and issuing an update package 46271d10453SEric Joyner * command. 46371d10453SEric Joyner */ 46471d10453SEric Joyner enum ice_status 46571d10453SEric Joyner ice_create_tunnel(struct ice_hw *hw, enum ice_tunnel_type type, u16 port) 46671d10453SEric Joyner { 46771d10453SEric Joyner struct ice_boost_tcam_section *sect_rx, *sect_tx; 46871d10453SEric Joyner enum ice_status status = ICE_ERR_MAX_LIMIT; 46971d10453SEric Joyner struct ice_buf_build *bld; 47071d10453SEric Joyner u16 index; 47171d10453SEric Joyner 47271d10453SEric Joyner ice_acquire_lock(&hw->tnl_lock); 47371d10453SEric Joyner 47471d10453SEric Joyner if (ice_tunnel_port_in_use_hlpr(hw, port, &index)) { 47571d10453SEric Joyner hw->tnl.tbl[index].ref++; 47671d10453SEric Joyner status = ICE_SUCCESS; 47771d10453SEric Joyner goto ice_create_tunnel_end; 47871d10453SEric Joyner } 47971d10453SEric Joyner 48071d10453SEric Joyner if (!ice_find_free_tunnel_entry(hw, type, &index)) { 48171d10453SEric Joyner status = ICE_ERR_OUT_OF_RANGE; 48271d10453SEric Joyner goto ice_create_tunnel_end; 48371d10453SEric Joyner } 48471d10453SEric Joyner 48571d10453SEric Joyner bld = ice_pkg_buf_alloc(hw); 48671d10453SEric Joyner if (!bld) { 48771d10453SEric Joyner status = ICE_ERR_NO_MEMORY; 48871d10453SEric Joyner goto ice_create_tunnel_end; 48971d10453SEric Joyner } 49071d10453SEric Joyner 49171d10453SEric Joyner /* allocate 2 sections, one for Rx parser, one for Tx parser */ 49271d10453SEric Joyner if (ice_pkg_buf_reserve_section(bld, 2)) 49371d10453SEric Joyner goto ice_create_tunnel_err; 49471d10453SEric Joyner 49571d10453SEric Joyner sect_rx = (struct ice_boost_tcam_section *) 49671d10453SEric Joyner ice_pkg_buf_alloc_section(bld, ICE_SID_RXPARSER_BOOST_TCAM, 4977d7af7f8SEric Joyner ice_struct_size(sect_rx, tcam, 1)); 49871d10453SEric Joyner if (!sect_rx) 49971d10453SEric Joyner goto ice_create_tunnel_err; 50071d10453SEric Joyner sect_rx->count = CPU_TO_LE16(1); 50171d10453SEric Joyner 50271d10453SEric Joyner sect_tx = (struct ice_boost_tcam_section *) 50371d10453SEric Joyner ice_pkg_buf_alloc_section(bld, ICE_SID_TXPARSER_BOOST_TCAM, 5047d7af7f8SEric Joyner ice_struct_size(sect_tx, tcam, 1)); 50571d10453SEric Joyner if (!sect_tx) 50671d10453SEric Joyner goto ice_create_tunnel_err; 50771d10453SEric Joyner sect_tx->count = CPU_TO_LE16(1); 50871d10453SEric Joyner 50971d10453SEric Joyner /* copy original boost entry to update package buffer */ 51071d10453SEric Joyner ice_memcpy(sect_rx->tcam, hw->tnl.tbl[index].boost_entry, 51171d10453SEric Joyner sizeof(*sect_rx->tcam), ICE_NONDMA_TO_NONDMA); 51271d10453SEric Joyner 51371d10453SEric Joyner /* over-write the never-match dest port key bits with the encoded port 51471d10453SEric Joyner * bits 51571d10453SEric Joyner */ 51671d10453SEric Joyner ice_set_key((u8 *)§_rx->tcam[0].key, sizeof(sect_rx->tcam[0].key), 51771d10453SEric Joyner (u8 *)&port, NULL, NULL, NULL, 51871d10453SEric Joyner (u16)offsetof(struct ice_boost_key_value, hv_dst_port_key), 51971d10453SEric Joyner sizeof(sect_rx->tcam[0].key.key.hv_dst_port_key)); 52071d10453SEric Joyner 52171d10453SEric Joyner /* exact copy of entry to Tx section entry */ 52271d10453SEric Joyner ice_memcpy(sect_tx->tcam, sect_rx->tcam, sizeof(*sect_tx->tcam), 52371d10453SEric Joyner ICE_NONDMA_TO_NONDMA); 52471d10453SEric Joyner 52571d10453SEric Joyner status = ice_update_pkg(hw, ice_pkg_buf(bld), 1); 52671d10453SEric Joyner if (!status) { 52771d10453SEric Joyner hw->tnl.tbl[index].port = port; 52871d10453SEric Joyner hw->tnl.tbl[index].in_use = true; 52971d10453SEric Joyner hw->tnl.tbl[index].ref = 1; 53071d10453SEric Joyner } 53171d10453SEric Joyner 53271d10453SEric Joyner ice_create_tunnel_err: 53371d10453SEric Joyner ice_pkg_buf_free(hw, bld); 53471d10453SEric Joyner 53571d10453SEric Joyner ice_create_tunnel_end: 53671d10453SEric Joyner ice_release_lock(&hw->tnl_lock); 53771d10453SEric Joyner 53871d10453SEric Joyner return status; 53971d10453SEric Joyner } 54071d10453SEric Joyner 54171d10453SEric Joyner /** 54271d10453SEric Joyner * ice_destroy_tunnel 54371d10453SEric Joyner * @hw: pointer to the HW structure 54471d10453SEric Joyner * @port: port of tunnel to destroy (ignored if the all parameter is true) 54571d10453SEric Joyner * @all: flag that states to destroy all tunnels 54671d10453SEric Joyner * 54771d10453SEric Joyner * Destroys a tunnel or all tunnels by creating an update package buffer 54871d10453SEric Joyner * targeting the specific updates requested and then performing an update 54971d10453SEric Joyner * package. 55071d10453SEric Joyner */ 55171d10453SEric Joyner enum ice_status ice_destroy_tunnel(struct ice_hw *hw, u16 port, bool all) 55271d10453SEric Joyner { 55371d10453SEric Joyner struct ice_boost_tcam_section *sect_rx, *sect_tx; 55471d10453SEric Joyner enum ice_status status = ICE_ERR_MAX_LIMIT; 55571d10453SEric Joyner struct ice_buf_build *bld; 55671d10453SEric Joyner u16 count = 0; 55771d10453SEric Joyner u16 index; 55871d10453SEric Joyner u16 size; 5599cf1841cSEric Joyner u16 i, j; 56071d10453SEric Joyner 56171d10453SEric Joyner ice_acquire_lock(&hw->tnl_lock); 56271d10453SEric Joyner 56371d10453SEric Joyner if (!all && ice_tunnel_port_in_use_hlpr(hw, port, &index)) 56471d10453SEric Joyner if (hw->tnl.tbl[index].ref > 1) { 56571d10453SEric Joyner hw->tnl.tbl[index].ref--; 56671d10453SEric Joyner status = ICE_SUCCESS; 56771d10453SEric Joyner goto ice_destroy_tunnel_end; 56871d10453SEric Joyner } 56971d10453SEric Joyner 57071d10453SEric Joyner /* determine count */ 57171d10453SEric Joyner for (i = 0; i < hw->tnl.count && i < ICE_TUNNEL_MAX_ENTRIES; i++) 57271d10453SEric Joyner if (hw->tnl.tbl[i].valid && hw->tnl.tbl[i].in_use && 57371d10453SEric Joyner (all || hw->tnl.tbl[i].port == port)) 57471d10453SEric Joyner count++; 57571d10453SEric Joyner 57671d10453SEric Joyner if (!count) { 57771d10453SEric Joyner status = ICE_ERR_PARAM; 57871d10453SEric Joyner goto ice_destroy_tunnel_end; 57971d10453SEric Joyner } 58071d10453SEric Joyner 58171d10453SEric Joyner /* size of section - there is at least one entry */ 5827d7af7f8SEric Joyner size = ice_struct_size(sect_rx, tcam, count); 58371d10453SEric Joyner 58471d10453SEric Joyner bld = ice_pkg_buf_alloc(hw); 58571d10453SEric Joyner if (!bld) { 58671d10453SEric Joyner status = ICE_ERR_NO_MEMORY; 58771d10453SEric Joyner goto ice_destroy_tunnel_end; 58871d10453SEric Joyner } 58971d10453SEric Joyner 59071d10453SEric Joyner /* allocate 2 sections, one for Rx parser, one for Tx parser */ 59171d10453SEric Joyner if (ice_pkg_buf_reserve_section(bld, 2)) 59271d10453SEric Joyner goto ice_destroy_tunnel_err; 59371d10453SEric Joyner 59471d10453SEric Joyner sect_rx = (struct ice_boost_tcam_section *) 59571d10453SEric Joyner ice_pkg_buf_alloc_section(bld, ICE_SID_RXPARSER_BOOST_TCAM, 59671d10453SEric Joyner size); 59771d10453SEric Joyner if (!sect_rx) 59871d10453SEric Joyner goto ice_destroy_tunnel_err; 5999cf1841cSEric Joyner sect_rx->count = CPU_TO_LE16(count); 60071d10453SEric Joyner 60171d10453SEric Joyner sect_tx = (struct ice_boost_tcam_section *) 60271d10453SEric Joyner ice_pkg_buf_alloc_section(bld, ICE_SID_TXPARSER_BOOST_TCAM, 60371d10453SEric Joyner size); 60471d10453SEric Joyner if (!sect_tx) 60571d10453SEric Joyner goto ice_destroy_tunnel_err; 6069cf1841cSEric Joyner sect_tx->count = CPU_TO_LE16(count); 60771d10453SEric Joyner 60871d10453SEric Joyner /* copy original boost entry to update package buffer, one copy to Rx 60971d10453SEric Joyner * section, another copy to the Tx section 61071d10453SEric Joyner */ 6119cf1841cSEric Joyner for (i = 0, j = 0; i < hw->tnl.count && i < ICE_TUNNEL_MAX_ENTRIES; i++) 61271d10453SEric Joyner if (hw->tnl.tbl[i].valid && hw->tnl.tbl[i].in_use && 61371d10453SEric Joyner (all || hw->tnl.tbl[i].port == port)) { 6149cf1841cSEric Joyner ice_memcpy(sect_rx->tcam + j, 61571d10453SEric Joyner hw->tnl.tbl[i].boost_entry, 61671d10453SEric Joyner sizeof(*sect_rx->tcam), 61771d10453SEric Joyner ICE_NONDMA_TO_NONDMA); 6189cf1841cSEric Joyner ice_memcpy(sect_tx->tcam + j, 61971d10453SEric Joyner hw->tnl.tbl[i].boost_entry, 62071d10453SEric Joyner sizeof(*sect_tx->tcam), 62171d10453SEric Joyner ICE_NONDMA_TO_NONDMA); 62271d10453SEric Joyner hw->tnl.tbl[i].marked = true; 6239cf1841cSEric Joyner j++; 62471d10453SEric Joyner } 62571d10453SEric Joyner 62671d10453SEric Joyner status = ice_update_pkg(hw, ice_pkg_buf(bld), 1); 62771d10453SEric Joyner if (!status) 62871d10453SEric Joyner for (i = 0; i < hw->tnl.count && 62971d10453SEric Joyner i < ICE_TUNNEL_MAX_ENTRIES; i++) 63071d10453SEric Joyner if (hw->tnl.tbl[i].marked) { 63171d10453SEric Joyner hw->tnl.tbl[i].ref = 0; 63271d10453SEric Joyner hw->tnl.tbl[i].port = 0; 63371d10453SEric Joyner hw->tnl.tbl[i].in_use = false; 63471d10453SEric Joyner hw->tnl.tbl[i].marked = false; 63571d10453SEric Joyner } 63671d10453SEric Joyner 63771d10453SEric Joyner ice_destroy_tunnel_err: 63871d10453SEric Joyner ice_pkg_buf_free(hw, bld); 63971d10453SEric Joyner 64071d10453SEric Joyner ice_destroy_tunnel_end: 64171d10453SEric Joyner ice_release_lock(&hw->tnl_lock); 64271d10453SEric Joyner 64371d10453SEric Joyner return status; 64471d10453SEric Joyner } 64571d10453SEric Joyner 64671d10453SEric Joyner /** 64771d10453SEric Joyner * ice_replay_tunnels 64871d10453SEric Joyner * @hw: pointer to the HW structure 64971d10453SEric Joyner * 65071d10453SEric Joyner * Replays all tunnels 65171d10453SEric Joyner */ 65271d10453SEric Joyner enum ice_status ice_replay_tunnels(struct ice_hw *hw) 65371d10453SEric Joyner { 65471d10453SEric Joyner enum ice_status status = ICE_SUCCESS; 65571d10453SEric Joyner u16 i; 65671d10453SEric Joyner 65771d10453SEric Joyner ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__); 65871d10453SEric Joyner 65971d10453SEric Joyner for (i = 0; i < hw->tnl.count && i < ICE_TUNNEL_MAX_ENTRIES; i++) { 66071d10453SEric Joyner enum ice_tunnel_type type = hw->tnl.tbl[i].type; 66171d10453SEric Joyner u16 refs = hw->tnl.tbl[i].ref; 66271d10453SEric Joyner u16 port = hw->tnl.tbl[i].port; 66371d10453SEric Joyner 66471d10453SEric Joyner if (!hw->tnl.tbl[i].in_use) 66571d10453SEric Joyner continue; 66671d10453SEric Joyner 66771d10453SEric Joyner /* Replay tunnels one at a time by destroying them, then 66871d10453SEric Joyner * recreating them 66971d10453SEric Joyner */ 67071d10453SEric Joyner hw->tnl.tbl[i].ref = 1; /* make sure to destroy in one call */ 67171d10453SEric Joyner status = ice_destroy_tunnel(hw, port, false); 67271d10453SEric Joyner if (status) { 6737d7af7f8SEric Joyner ice_debug(hw, ICE_DBG_PKG, "ERR: 0x%x - destroy tunnel port 0x%x\n", 67471d10453SEric Joyner status, port); 67571d10453SEric Joyner break; 67671d10453SEric Joyner } 67771d10453SEric Joyner 67871d10453SEric Joyner status = ice_create_tunnel(hw, type, port); 67971d10453SEric Joyner if (status) { 6807d7af7f8SEric Joyner ice_debug(hw, ICE_DBG_PKG, "ERR: 0x%x - create tunnel port 0x%x\n", 68171d10453SEric Joyner status, port); 68271d10453SEric Joyner break; 68371d10453SEric Joyner } 68471d10453SEric Joyner 68571d10453SEric Joyner /* reset to original ref count */ 68671d10453SEric Joyner hw->tnl.tbl[i].ref = refs; 68771d10453SEric Joyner } 68871d10453SEric Joyner 68971d10453SEric Joyner return status; 69071d10453SEric Joyner } 69171d10453SEric Joyner 69271d10453SEric Joyner /** 69371d10453SEric Joyner * ice_find_prot_off - find prot ID and offset pair, based on prof and FV index 69471d10453SEric Joyner * @hw: pointer to the hardware structure 69571d10453SEric Joyner * @blk: hardware block 69671d10453SEric Joyner * @prof: profile ID 69771d10453SEric Joyner * @fv_idx: field vector word index 69871d10453SEric Joyner * @prot: variable to receive the protocol ID 69971d10453SEric Joyner * @off: variable to receive the protocol offset 70071d10453SEric Joyner */ 70171d10453SEric Joyner enum ice_status 70271d10453SEric Joyner ice_find_prot_off(struct ice_hw *hw, enum ice_block blk, u8 prof, u16 fv_idx, 70371d10453SEric Joyner u8 *prot, u16 *off) 70471d10453SEric Joyner { 70571d10453SEric Joyner struct ice_fv_word *fv_ext; 70671d10453SEric Joyner 70771d10453SEric Joyner if (prof >= hw->blk[blk].es.count) 70871d10453SEric Joyner return ICE_ERR_PARAM; 70971d10453SEric Joyner 71071d10453SEric Joyner if (fv_idx >= hw->blk[blk].es.fvw) 71171d10453SEric Joyner return ICE_ERR_PARAM; 71271d10453SEric Joyner 71371d10453SEric Joyner fv_ext = hw->blk[blk].es.t + (prof * hw->blk[blk].es.fvw); 71471d10453SEric Joyner 71571d10453SEric Joyner *prot = fv_ext[fv_idx].prot_id; 71671d10453SEric Joyner *off = fv_ext[fv_idx].off; 71771d10453SEric Joyner 71871d10453SEric Joyner return ICE_SUCCESS; 71971d10453SEric Joyner } 72071d10453SEric Joyner 72171d10453SEric Joyner /* PTG Management */ 72271d10453SEric Joyner 72371d10453SEric Joyner /** 72471d10453SEric Joyner * ice_ptg_update_xlt1 - Updates packet type groups in HW via XLT1 table 72571d10453SEric Joyner * @hw: pointer to the hardware structure 72671d10453SEric Joyner * @blk: HW block 72771d10453SEric Joyner * 72871d10453SEric Joyner * This function will update the XLT1 hardware table to reflect the new 72971d10453SEric Joyner * packet type group configuration. 73071d10453SEric Joyner */ 73171d10453SEric Joyner enum ice_status ice_ptg_update_xlt1(struct ice_hw *hw, enum ice_block blk) 73271d10453SEric Joyner { 73371d10453SEric Joyner struct ice_xlt1_section *sect; 73471d10453SEric Joyner struct ice_buf_build *bld; 73571d10453SEric Joyner enum ice_status status; 73671d10453SEric Joyner u16 index; 73771d10453SEric Joyner 73871d10453SEric Joyner bld = ice_pkg_buf_alloc_single_section(hw, ice_sect_id(blk, ICE_XLT1), 7397d7af7f8SEric Joyner ice_struct_size(sect, value, 7407d7af7f8SEric Joyner ICE_XLT1_CNT), 74171d10453SEric Joyner (void **)§); 74271d10453SEric Joyner if (!bld) 74371d10453SEric Joyner return ICE_ERR_NO_MEMORY; 74471d10453SEric Joyner 74571d10453SEric Joyner sect->count = CPU_TO_LE16(ICE_XLT1_CNT); 74671d10453SEric Joyner sect->offset = CPU_TO_LE16(0); 74771d10453SEric Joyner for (index = 0; index < ICE_XLT1_CNT; index++) 74871d10453SEric Joyner sect->value[index] = hw->blk[blk].xlt1.ptypes[index].ptg; 74971d10453SEric Joyner 75071d10453SEric Joyner status = ice_update_pkg(hw, ice_pkg_buf(bld), 1); 75171d10453SEric Joyner 75271d10453SEric Joyner ice_pkg_buf_free(hw, bld); 75371d10453SEric Joyner 75471d10453SEric Joyner return status; 75571d10453SEric Joyner } 75671d10453SEric Joyner 75771d10453SEric Joyner /** 75871d10453SEric Joyner * ice_ptg_find_ptype - Search for packet type group using packet type (ptype) 75971d10453SEric Joyner * @hw: pointer to the hardware structure 76071d10453SEric Joyner * @blk: HW block 76171d10453SEric Joyner * @ptype: the ptype to search for 76271d10453SEric Joyner * @ptg: pointer to variable that receives the PTG 76371d10453SEric Joyner * 76471d10453SEric Joyner * This function will search the PTGs for a particular ptype, returning the 76571d10453SEric Joyner * PTG ID that contains it through the PTG parameter, with the value of 76671d10453SEric Joyner * ICE_DEFAULT_PTG (0) meaning it is part the default PTG. 76771d10453SEric Joyner */ 76871d10453SEric Joyner static enum ice_status 76971d10453SEric Joyner ice_ptg_find_ptype(struct ice_hw *hw, enum ice_block blk, u16 ptype, u8 *ptg) 77071d10453SEric Joyner { 77171d10453SEric Joyner if (ptype >= ICE_XLT1_CNT || !ptg) 77271d10453SEric Joyner return ICE_ERR_PARAM; 77371d10453SEric Joyner 77471d10453SEric Joyner *ptg = hw->blk[blk].xlt1.ptypes[ptype].ptg; 77571d10453SEric Joyner return ICE_SUCCESS; 77671d10453SEric Joyner } 77771d10453SEric Joyner 77871d10453SEric Joyner /** 77971d10453SEric Joyner * ice_ptg_alloc_val - Allocates a new packet type group ID by value 78071d10453SEric Joyner * @hw: pointer to the hardware structure 78171d10453SEric Joyner * @blk: HW block 78271d10453SEric Joyner * @ptg: the PTG to allocate 78371d10453SEric Joyner * 78471d10453SEric Joyner * This function allocates a given packet type group ID specified by the PTG 78571d10453SEric Joyner * parameter. 78671d10453SEric Joyner */ 78771d10453SEric Joyner static void ice_ptg_alloc_val(struct ice_hw *hw, enum ice_block blk, u8 ptg) 78871d10453SEric Joyner { 78971d10453SEric Joyner hw->blk[blk].xlt1.ptg_tbl[ptg].in_use = true; 79071d10453SEric Joyner } 79171d10453SEric Joyner 79271d10453SEric Joyner /** 79371d10453SEric Joyner * ice_ptg_free - Frees a packet type group 79471d10453SEric Joyner * @hw: pointer to the hardware structure 79571d10453SEric Joyner * @blk: HW block 79671d10453SEric Joyner * @ptg: the PTG ID to free 79771d10453SEric Joyner * 79871d10453SEric Joyner * This function frees a packet type group, and returns all the current ptypes 79971d10453SEric Joyner * within it to the default PTG. 80071d10453SEric Joyner */ 80171d10453SEric Joyner void ice_ptg_free(struct ice_hw *hw, enum ice_block blk, u8 ptg) 80271d10453SEric Joyner { 80371d10453SEric Joyner struct ice_ptg_ptype *p, *temp; 80471d10453SEric Joyner 80571d10453SEric Joyner hw->blk[blk].xlt1.ptg_tbl[ptg].in_use = false; 80671d10453SEric Joyner p = hw->blk[blk].xlt1.ptg_tbl[ptg].first_ptype; 80771d10453SEric Joyner while (p) { 80871d10453SEric Joyner p->ptg = ICE_DEFAULT_PTG; 80971d10453SEric Joyner temp = p->next_ptype; 81071d10453SEric Joyner p->next_ptype = NULL; 81171d10453SEric Joyner p = temp; 81271d10453SEric Joyner } 81371d10453SEric Joyner 81471d10453SEric Joyner hw->blk[blk].xlt1.ptg_tbl[ptg].first_ptype = NULL; 81571d10453SEric Joyner } 81671d10453SEric Joyner 81771d10453SEric Joyner /** 81871d10453SEric Joyner * ice_ptg_remove_ptype - Removes ptype from a particular packet type group 81971d10453SEric Joyner * @hw: pointer to the hardware structure 82071d10453SEric Joyner * @blk: HW block 82171d10453SEric Joyner * @ptype: the ptype to remove 82271d10453SEric Joyner * @ptg: the PTG to remove the ptype from 82371d10453SEric Joyner * 82471d10453SEric Joyner * This function will remove the ptype from the specific PTG, and move it to 82571d10453SEric Joyner * the default PTG (ICE_DEFAULT_PTG). 82671d10453SEric Joyner */ 82771d10453SEric Joyner static enum ice_status 82871d10453SEric Joyner ice_ptg_remove_ptype(struct ice_hw *hw, enum ice_block blk, u16 ptype, u8 ptg) 82971d10453SEric Joyner { 83071d10453SEric Joyner struct ice_ptg_ptype **ch; 83171d10453SEric Joyner struct ice_ptg_ptype *p; 83271d10453SEric Joyner 83371d10453SEric Joyner if (ptype > ICE_XLT1_CNT - 1) 83471d10453SEric Joyner return ICE_ERR_PARAM; 83571d10453SEric Joyner 83671d10453SEric Joyner if (!hw->blk[blk].xlt1.ptg_tbl[ptg].in_use) 83771d10453SEric Joyner return ICE_ERR_DOES_NOT_EXIST; 83871d10453SEric Joyner 83971d10453SEric Joyner /* Should not happen if .in_use is set, bad config */ 84071d10453SEric Joyner if (!hw->blk[blk].xlt1.ptg_tbl[ptg].first_ptype) 84171d10453SEric Joyner return ICE_ERR_CFG; 84271d10453SEric Joyner 84371d10453SEric Joyner /* find the ptype within this PTG, and bypass the link over it */ 84471d10453SEric Joyner p = hw->blk[blk].xlt1.ptg_tbl[ptg].first_ptype; 84571d10453SEric Joyner ch = &hw->blk[blk].xlt1.ptg_tbl[ptg].first_ptype; 84671d10453SEric Joyner while (p) { 84771d10453SEric Joyner if (ptype == (p - hw->blk[blk].xlt1.ptypes)) { 84871d10453SEric Joyner *ch = p->next_ptype; 84971d10453SEric Joyner break; 85071d10453SEric Joyner } 85171d10453SEric Joyner 85271d10453SEric Joyner ch = &p->next_ptype; 85371d10453SEric Joyner p = p->next_ptype; 85471d10453SEric Joyner } 85571d10453SEric Joyner 85671d10453SEric Joyner hw->blk[blk].xlt1.ptypes[ptype].ptg = ICE_DEFAULT_PTG; 85771d10453SEric Joyner hw->blk[blk].xlt1.ptypes[ptype].next_ptype = NULL; 85871d10453SEric Joyner 85971d10453SEric Joyner return ICE_SUCCESS; 86071d10453SEric Joyner } 86171d10453SEric Joyner 86271d10453SEric Joyner /** 86371d10453SEric Joyner * ice_ptg_add_mv_ptype - Adds/moves ptype to a particular packet type group 86471d10453SEric Joyner * @hw: pointer to the hardware structure 86571d10453SEric Joyner * @blk: HW block 86671d10453SEric Joyner * @ptype: the ptype to add or move 86771d10453SEric Joyner * @ptg: the PTG to add or move the ptype to 86871d10453SEric Joyner * 86971d10453SEric Joyner * This function will either add or move a ptype to a particular PTG depending 87071d10453SEric Joyner * on if the ptype is already part of another group. Note that using a 87171d10453SEric Joyner * a destination PTG ID of ICE_DEFAULT_PTG (0) will move the ptype to the 87271d10453SEric Joyner * default PTG. 87371d10453SEric Joyner */ 87471d10453SEric Joyner static enum ice_status 87571d10453SEric Joyner ice_ptg_add_mv_ptype(struct ice_hw *hw, enum ice_block blk, u16 ptype, u8 ptg) 87671d10453SEric Joyner { 87771d10453SEric Joyner enum ice_status status; 87871d10453SEric Joyner u8 original_ptg; 87971d10453SEric Joyner 88071d10453SEric Joyner if (ptype > ICE_XLT1_CNT - 1) 88171d10453SEric Joyner return ICE_ERR_PARAM; 88271d10453SEric Joyner 88371d10453SEric Joyner if (!hw->blk[blk].xlt1.ptg_tbl[ptg].in_use && ptg != ICE_DEFAULT_PTG) 88471d10453SEric Joyner return ICE_ERR_DOES_NOT_EXIST; 88571d10453SEric Joyner 88671d10453SEric Joyner status = ice_ptg_find_ptype(hw, blk, ptype, &original_ptg); 88771d10453SEric Joyner if (status) 88871d10453SEric Joyner return status; 88971d10453SEric Joyner 89071d10453SEric Joyner /* Is ptype already in the correct PTG? */ 89171d10453SEric Joyner if (original_ptg == ptg) 89271d10453SEric Joyner return ICE_SUCCESS; 89371d10453SEric Joyner 89471d10453SEric Joyner /* Remove from original PTG and move back to the default PTG */ 89571d10453SEric Joyner if (original_ptg != ICE_DEFAULT_PTG) 89671d10453SEric Joyner ice_ptg_remove_ptype(hw, blk, ptype, original_ptg); 89771d10453SEric Joyner 89871d10453SEric Joyner /* Moving to default PTG? Then we're done with this request */ 89971d10453SEric Joyner if (ptg == ICE_DEFAULT_PTG) 90071d10453SEric Joyner return ICE_SUCCESS; 90171d10453SEric Joyner 90271d10453SEric Joyner /* Add ptype to PTG at beginning of list */ 90371d10453SEric Joyner hw->blk[blk].xlt1.ptypes[ptype].next_ptype = 90471d10453SEric Joyner hw->blk[blk].xlt1.ptg_tbl[ptg].first_ptype; 90571d10453SEric Joyner hw->blk[blk].xlt1.ptg_tbl[ptg].first_ptype = 90671d10453SEric Joyner &hw->blk[blk].xlt1.ptypes[ptype]; 90771d10453SEric Joyner 90871d10453SEric Joyner hw->blk[blk].xlt1.ptypes[ptype].ptg = ptg; 90971d10453SEric Joyner hw->blk[blk].xlt1.t[ptype] = ptg; 91071d10453SEric Joyner 91171d10453SEric Joyner return ICE_SUCCESS; 91271d10453SEric Joyner } 91371d10453SEric Joyner 91471d10453SEric Joyner /* Block / table size info */ 91571d10453SEric Joyner struct ice_blk_size_details { 91671d10453SEric Joyner u16 xlt1; /* # XLT1 entries */ 91771d10453SEric Joyner u16 xlt2; /* # XLT2 entries */ 91871d10453SEric Joyner u16 prof_tcam; /* # profile ID TCAM entries */ 91971d10453SEric Joyner u16 prof_id; /* # profile IDs */ 92071d10453SEric Joyner u8 prof_cdid_bits; /* # CDID one-hot bits used in key */ 92171d10453SEric Joyner u16 prof_redir; /* # profile redirection entries */ 92271d10453SEric Joyner u16 es; /* # extraction sequence entries */ 92371d10453SEric Joyner u16 fvw; /* # field vector words */ 92471d10453SEric Joyner u8 overwrite; /* overwrite existing entries allowed */ 92571d10453SEric Joyner u8 reverse; /* reverse FV order */ 92671d10453SEric Joyner }; 92771d10453SEric Joyner 92871d10453SEric Joyner static const struct ice_blk_size_details blk_sizes[ICE_BLK_COUNT] = { 92971d10453SEric Joyner /** 93071d10453SEric Joyner * Table Definitions 93171d10453SEric Joyner * XLT1 - Number of entries in XLT1 table 93271d10453SEric Joyner * XLT2 - Number of entries in XLT2 table 93371d10453SEric Joyner * TCAM - Number of entries Profile ID TCAM table 93471d10453SEric Joyner * CDID - Control Domain ID of the hardware block 93571d10453SEric Joyner * PRED - Number of entries in the Profile Redirection Table 93671d10453SEric Joyner * FV - Number of entries in the Field Vector 93771d10453SEric Joyner * FVW - Width (in WORDs) of the Field Vector 93871d10453SEric Joyner * OVR - Overwrite existing table entries 93971d10453SEric Joyner * REV - Reverse FV 94071d10453SEric Joyner */ 94171d10453SEric Joyner /* XLT1 , XLT2 ,TCAM, PID,CDID,PRED, FV, FVW */ 94271d10453SEric Joyner /* Overwrite , Reverse FV */ 94371d10453SEric Joyner /* SW */ { ICE_XLT1_CNT, ICE_XLT2_CNT, 512, 256, 0, 256, 256, 48, 94471d10453SEric Joyner false, false }, 94571d10453SEric Joyner /* ACL */ { ICE_XLT1_CNT, ICE_XLT2_CNT, 512, 128, 0, 128, 128, 32, 94671d10453SEric Joyner false, false }, 94771d10453SEric Joyner /* FD */ { ICE_XLT1_CNT, ICE_XLT2_CNT, 512, 128, 0, 128, 128, 24, 94871d10453SEric Joyner false, true }, 94971d10453SEric Joyner /* RSS */ { ICE_XLT1_CNT, ICE_XLT2_CNT, 512, 128, 0, 128, 128, 24, 95071d10453SEric Joyner true, true }, 95171d10453SEric Joyner /* PE */ { ICE_XLT1_CNT, ICE_XLT2_CNT, 64, 32, 0, 32, 32, 24, 95271d10453SEric Joyner false, false }, 95371d10453SEric Joyner }; 95471d10453SEric Joyner 95571d10453SEric Joyner enum ice_sid_all { 95671d10453SEric Joyner ICE_SID_XLT1_OFF = 0, 95771d10453SEric Joyner ICE_SID_XLT2_OFF, 95871d10453SEric Joyner ICE_SID_PR_OFF, 95971d10453SEric Joyner ICE_SID_PR_REDIR_OFF, 96071d10453SEric Joyner ICE_SID_ES_OFF, 96171d10453SEric Joyner ICE_SID_OFF_COUNT, 96271d10453SEric Joyner }; 96371d10453SEric Joyner 96471d10453SEric Joyner /* Characteristic handling */ 96571d10453SEric Joyner 96671d10453SEric Joyner /** 96771d10453SEric Joyner * ice_match_prop_lst - determine if properties of two lists match 96871d10453SEric Joyner * @list1: first properties list 96971d10453SEric Joyner * @list2: second properties list 97071d10453SEric Joyner * 97171d10453SEric Joyner * Count, cookies and the order must match in order to be considered equivalent. 97271d10453SEric Joyner */ 97371d10453SEric Joyner static bool 97471d10453SEric Joyner ice_match_prop_lst(struct LIST_HEAD_TYPE *list1, struct LIST_HEAD_TYPE *list2) 97571d10453SEric Joyner { 97671d10453SEric Joyner struct ice_vsig_prof *tmp1; 97771d10453SEric Joyner struct ice_vsig_prof *tmp2; 97871d10453SEric Joyner u16 chk_count = 0; 97971d10453SEric Joyner u16 count = 0; 98071d10453SEric Joyner 98171d10453SEric Joyner /* compare counts */ 9827d7af7f8SEric Joyner LIST_FOR_EACH_ENTRY(tmp1, list1, ice_vsig_prof, list) 98371d10453SEric Joyner count++; 9847d7af7f8SEric Joyner LIST_FOR_EACH_ENTRY(tmp2, list2, ice_vsig_prof, list) 98571d10453SEric Joyner chk_count++; 98671d10453SEric Joyner if (!count || count != chk_count) 98771d10453SEric Joyner return false; 98871d10453SEric Joyner 98971d10453SEric Joyner tmp1 = LIST_FIRST_ENTRY(list1, struct ice_vsig_prof, list); 99071d10453SEric Joyner tmp2 = LIST_FIRST_ENTRY(list2, struct ice_vsig_prof, list); 99171d10453SEric Joyner 99271d10453SEric Joyner /* profile cookies must compare, and in the exact same order to take 99371d10453SEric Joyner * into account priority 99471d10453SEric Joyner */ 99571d10453SEric Joyner while (count--) { 99671d10453SEric Joyner if (tmp2->profile_cookie != tmp1->profile_cookie) 99771d10453SEric Joyner return false; 99871d10453SEric Joyner 99971d10453SEric Joyner tmp1 = LIST_NEXT_ENTRY(tmp1, struct ice_vsig_prof, list); 100071d10453SEric Joyner tmp2 = LIST_NEXT_ENTRY(tmp2, struct ice_vsig_prof, list); 100171d10453SEric Joyner } 100271d10453SEric Joyner 100371d10453SEric Joyner return true; 100471d10453SEric Joyner } 100571d10453SEric Joyner 100671d10453SEric Joyner /* VSIG Management */ 100771d10453SEric Joyner 100871d10453SEric Joyner /** 100971d10453SEric Joyner * ice_vsig_update_xlt2_sect - update one section of XLT2 table 101071d10453SEric Joyner * @hw: pointer to the hardware structure 101171d10453SEric Joyner * @blk: HW block 101271d10453SEric Joyner * @vsi: HW VSI number to program 101371d10453SEric Joyner * @vsig: VSIG for the VSI 101471d10453SEric Joyner * 101571d10453SEric Joyner * This function will update the XLT2 hardware table with the input VSI 101671d10453SEric Joyner * group configuration. 101771d10453SEric Joyner */ 101871d10453SEric Joyner static enum ice_status 101971d10453SEric Joyner ice_vsig_update_xlt2_sect(struct ice_hw *hw, enum ice_block blk, u16 vsi, 102071d10453SEric Joyner u16 vsig) 102171d10453SEric Joyner { 102271d10453SEric Joyner struct ice_xlt2_section *sect; 102371d10453SEric Joyner struct ice_buf_build *bld; 102471d10453SEric Joyner enum ice_status status; 102571d10453SEric Joyner 102671d10453SEric Joyner bld = ice_pkg_buf_alloc_single_section(hw, ice_sect_id(blk, ICE_XLT2), 10277d7af7f8SEric Joyner ice_struct_size(sect, value, 1), 102871d10453SEric Joyner (void **)§); 102971d10453SEric Joyner if (!bld) 103071d10453SEric Joyner return ICE_ERR_NO_MEMORY; 103171d10453SEric Joyner 103271d10453SEric Joyner sect->count = CPU_TO_LE16(1); 103371d10453SEric Joyner sect->offset = CPU_TO_LE16(vsi); 103471d10453SEric Joyner sect->value[0] = CPU_TO_LE16(vsig); 103571d10453SEric Joyner 103671d10453SEric Joyner status = ice_update_pkg(hw, ice_pkg_buf(bld), 1); 103771d10453SEric Joyner 103871d10453SEric Joyner ice_pkg_buf_free(hw, bld); 103971d10453SEric Joyner 104071d10453SEric Joyner return status; 104171d10453SEric Joyner } 104271d10453SEric Joyner 104371d10453SEric Joyner /** 104471d10453SEric Joyner * ice_vsig_update_xlt2 - update XLT2 table with VSIG configuration 104571d10453SEric Joyner * @hw: pointer to the hardware structure 104671d10453SEric Joyner * @blk: HW block 104771d10453SEric Joyner * 104871d10453SEric Joyner * This function will update the XLT2 hardware table with the input VSI 104971d10453SEric Joyner * group configuration of used vsis. 105071d10453SEric Joyner */ 105171d10453SEric Joyner enum ice_status ice_vsig_update_xlt2(struct ice_hw *hw, enum ice_block blk) 105271d10453SEric Joyner { 105371d10453SEric Joyner u16 vsi; 105471d10453SEric Joyner 105571d10453SEric Joyner for (vsi = 0; vsi < ICE_MAX_VSI; vsi++) { 105671d10453SEric Joyner /* update only vsis that have been changed */ 105771d10453SEric Joyner if (hw->blk[blk].xlt2.vsis[vsi].changed) { 105871d10453SEric Joyner enum ice_status status; 105971d10453SEric Joyner u16 vsig; 106071d10453SEric Joyner 106171d10453SEric Joyner vsig = hw->blk[blk].xlt2.vsis[vsi].vsig; 106271d10453SEric Joyner status = ice_vsig_update_xlt2_sect(hw, blk, vsi, vsig); 106371d10453SEric Joyner if (status) 106471d10453SEric Joyner return status; 106571d10453SEric Joyner 106671d10453SEric Joyner hw->blk[blk].xlt2.vsis[vsi].changed = 0; 106771d10453SEric Joyner } 106871d10453SEric Joyner } 106971d10453SEric Joyner 107071d10453SEric Joyner return ICE_SUCCESS; 107171d10453SEric Joyner } 107271d10453SEric Joyner 107371d10453SEric Joyner /** 107471d10453SEric Joyner * ice_vsig_find_vsi - find a VSIG that contains a specified VSI 107571d10453SEric Joyner * @hw: pointer to the hardware structure 107671d10453SEric Joyner * @blk: HW block 107771d10453SEric Joyner * @vsi: VSI of interest 107871d10453SEric Joyner * @vsig: pointer to receive the VSI group 107971d10453SEric Joyner * 108071d10453SEric Joyner * This function will lookup the VSI entry in the XLT2 list and return 108171d10453SEric Joyner * the VSI group its associated with. 108271d10453SEric Joyner */ 108371d10453SEric Joyner enum ice_status 108471d10453SEric Joyner ice_vsig_find_vsi(struct ice_hw *hw, enum ice_block blk, u16 vsi, u16 *vsig) 108571d10453SEric Joyner { 108671d10453SEric Joyner if (!vsig || vsi >= ICE_MAX_VSI) 108771d10453SEric Joyner return ICE_ERR_PARAM; 108871d10453SEric Joyner 108971d10453SEric Joyner /* As long as there's a default or valid VSIG associated with the input 109071d10453SEric Joyner * VSI, the functions returns a success. Any handling of VSIG will be 109171d10453SEric Joyner * done by the following add, update or remove functions. 109271d10453SEric Joyner */ 109371d10453SEric Joyner *vsig = hw->blk[blk].xlt2.vsis[vsi].vsig; 109471d10453SEric Joyner 109571d10453SEric Joyner return ICE_SUCCESS; 109671d10453SEric Joyner } 109771d10453SEric Joyner 109871d10453SEric Joyner /** 109971d10453SEric Joyner * ice_vsig_alloc_val - allocate a new VSIG by value 110071d10453SEric Joyner * @hw: pointer to the hardware structure 110171d10453SEric Joyner * @blk: HW block 110271d10453SEric Joyner * @vsig: the VSIG to allocate 110371d10453SEric Joyner * 110471d10453SEric Joyner * This function will allocate a given VSIG specified by the VSIG parameter. 110571d10453SEric Joyner */ 110671d10453SEric Joyner static u16 ice_vsig_alloc_val(struct ice_hw *hw, enum ice_block blk, u16 vsig) 110771d10453SEric Joyner { 110871d10453SEric Joyner u16 idx = vsig & ICE_VSIG_IDX_M; 110971d10453SEric Joyner 111071d10453SEric Joyner if (!hw->blk[blk].xlt2.vsig_tbl[idx].in_use) { 111171d10453SEric Joyner INIT_LIST_HEAD(&hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst); 111271d10453SEric Joyner hw->blk[blk].xlt2.vsig_tbl[idx].in_use = true; 111371d10453SEric Joyner } 111471d10453SEric Joyner 111571d10453SEric Joyner return ICE_VSIG_VALUE(idx, hw->pf_id); 111671d10453SEric Joyner } 111771d10453SEric Joyner 111871d10453SEric Joyner /** 111971d10453SEric Joyner * ice_vsig_alloc - Finds a free entry and allocates a new VSIG 112071d10453SEric Joyner * @hw: pointer to the hardware structure 112171d10453SEric Joyner * @blk: HW block 112271d10453SEric Joyner * 112371d10453SEric Joyner * This function will iterate through the VSIG list and mark the first 112471d10453SEric Joyner * unused entry for the new VSIG entry as used and return that value. 112571d10453SEric Joyner */ 112671d10453SEric Joyner static u16 ice_vsig_alloc(struct ice_hw *hw, enum ice_block blk) 112771d10453SEric Joyner { 112871d10453SEric Joyner u16 i; 112971d10453SEric Joyner 113071d10453SEric Joyner for (i = 1; i < ICE_MAX_VSIGS; i++) 113171d10453SEric Joyner if (!hw->blk[blk].xlt2.vsig_tbl[i].in_use) 113271d10453SEric Joyner return ice_vsig_alloc_val(hw, blk, i); 113371d10453SEric Joyner 113471d10453SEric Joyner return ICE_DEFAULT_VSIG; 113571d10453SEric Joyner } 113671d10453SEric Joyner 113771d10453SEric Joyner /** 113871d10453SEric Joyner * ice_find_dup_props_vsig - find VSI group with a specified set of properties 113971d10453SEric Joyner * @hw: pointer to the hardware structure 114071d10453SEric Joyner * @blk: HW block 114171d10453SEric Joyner * @chs: characteristic list 114271d10453SEric Joyner * @vsig: returns the VSIG with the matching profiles, if found 114371d10453SEric Joyner * 114471d10453SEric Joyner * Each VSIG is associated with a characteristic set; i.e. all VSIs under 114571d10453SEric Joyner * a group have the same characteristic set. To check if there exists a VSIG 114671d10453SEric Joyner * which has the same characteristics as the input characteristics; this 114771d10453SEric Joyner * function will iterate through the XLT2 list and return the VSIG that has a 114871d10453SEric Joyner * matching configuration. In order to make sure that priorities are accounted 114971d10453SEric Joyner * for, the list must match exactly, including the order in which the 115071d10453SEric Joyner * characteristics are listed. 115171d10453SEric Joyner */ 115271d10453SEric Joyner static enum ice_status 115371d10453SEric Joyner ice_find_dup_props_vsig(struct ice_hw *hw, enum ice_block blk, 115471d10453SEric Joyner struct LIST_HEAD_TYPE *chs, u16 *vsig) 115571d10453SEric Joyner { 115671d10453SEric Joyner struct ice_xlt2 *xlt2 = &hw->blk[blk].xlt2; 115771d10453SEric Joyner u16 i; 115871d10453SEric Joyner 11597d7af7f8SEric Joyner for (i = 0; i < xlt2->count; i++) 116071d10453SEric Joyner if (xlt2->vsig_tbl[i].in_use && 116171d10453SEric Joyner ice_match_prop_lst(chs, &xlt2->vsig_tbl[i].prop_lst)) { 116271d10453SEric Joyner *vsig = ICE_VSIG_VALUE(i, hw->pf_id); 116371d10453SEric Joyner return ICE_SUCCESS; 116471d10453SEric Joyner } 116571d10453SEric Joyner 116671d10453SEric Joyner return ICE_ERR_DOES_NOT_EXIST; 116771d10453SEric Joyner } 116871d10453SEric Joyner 116971d10453SEric Joyner /** 117071d10453SEric Joyner * ice_vsig_free - free VSI group 117171d10453SEric Joyner * @hw: pointer to the hardware structure 117271d10453SEric Joyner * @blk: HW block 117371d10453SEric Joyner * @vsig: VSIG to remove 117471d10453SEric Joyner * 117571d10453SEric Joyner * The function will remove all VSIs associated with the input VSIG and move 117671d10453SEric Joyner * them to the DEFAULT_VSIG and mark the VSIG available. 117771d10453SEric Joyner */ 117871d10453SEric Joyner static enum ice_status 117971d10453SEric Joyner ice_vsig_free(struct ice_hw *hw, enum ice_block blk, u16 vsig) 118071d10453SEric Joyner { 118171d10453SEric Joyner struct ice_vsig_prof *dtmp, *del; 118271d10453SEric Joyner struct ice_vsig_vsi *vsi_cur; 118371d10453SEric Joyner u16 idx; 118471d10453SEric Joyner 118571d10453SEric Joyner idx = vsig & ICE_VSIG_IDX_M; 118671d10453SEric Joyner if (idx >= ICE_MAX_VSIGS) 118771d10453SEric Joyner return ICE_ERR_PARAM; 118871d10453SEric Joyner 118971d10453SEric Joyner if (!hw->blk[blk].xlt2.vsig_tbl[idx].in_use) 119071d10453SEric Joyner return ICE_ERR_DOES_NOT_EXIST; 119171d10453SEric Joyner 119271d10453SEric Joyner hw->blk[blk].xlt2.vsig_tbl[idx].in_use = false; 119371d10453SEric Joyner 119471d10453SEric Joyner vsi_cur = hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi; 119571d10453SEric Joyner /* If the VSIG has at least 1 VSI then iterate through the 119671d10453SEric Joyner * list and remove the VSIs before deleting the group. 119771d10453SEric Joyner */ 119871d10453SEric Joyner if (vsi_cur) { 119971d10453SEric Joyner /* remove all vsis associated with this VSIG XLT2 entry */ 120071d10453SEric Joyner do { 120171d10453SEric Joyner struct ice_vsig_vsi *tmp = vsi_cur->next_vsi; 120271d10453SEric Joyner 120371d10453SEric Joyner vsi_cur->vsig = ICE_DEFAULT_VSIG; 120471d10453SEric Joyner vsi_cur->changed = 1; 120571d10453SEric Joyner vsi_cur->next_vsi = NULL; 120671d10453SEric Joyner vsi_cur = tmp; 120771d10453SEric Joyner } while (vsi_cur); 120871d10453SEric Joyner 120971d10453SEric Joyner /* NULL terminate head of VSI list */ 121071d10453SEric Joyner hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi = NULL; 121171d10453SEric Joyner } 121271d10453SEric Joyner 121371d10453SEric Joyner /* free characteristic list */ 121471d10453SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(del, dtmp, 121571d10453SEric Joyner &hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst, 121671d10453SEric Joyner ice_vsig_prof, list) { 121771d10453SEric Joyner LIST_DEL(&del->list); 121871d10453SEric Joyner ice_free(hw, del); 121971d10453SEric Joyner } 122071d10453SEric Joyner 122171d10453SEric Joyner /* if VSIG characteristic list was cleared for reset 122271d10453SEric Joyner * re-initialize the list head 122371d10453SEric Joyner */ 122471d10453SEric Joyner INIT_LIST_HEAD(&hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst); 122571d10453SEric Joyner 122671d10453SEric Joyner return ICE_SUCCESS; 122771d10453SEric Joyner } 122871d10453SEric Joyner 122971d10453SEric Joyner /** 123071d10453SEric Joyner * ice_vsig_remove_vsi - remove VSI from VSIG 123171d10453SEric Joyner * @hw: pointer to the hardware structure 123271d10453SEric Joyner * @blk: HW block 123371d10453SEric Joyner * @vsi: VSI to remove 123471d10453SEric Joyner * @vsig: VSI group to remove from 123571d10453SEric Joyner * 123671d10453SEric Joyner * The function will remove the input VSI from its VSI group and move it 123771d10453SEric Joyner * to the DEFAULT_VSIG. 123871d10453SEric Joyner */ 123971d10453SEric Joyner static enum ice_status 124071d10453SEric Joyner ice_vsig_remove_vsi(struct ice_hw *hw, enum ice_block blk, u16 vsi, u16 vsig) 124171d10453SEric Joyner { 124271d10453SEric Joyner struct ice_vsig_vsi **vsi_head, *vsi_cur, *vsi_tgt; 124371d10453SEric Joyner u16 idx; 124471d10453SEric Joyner 124571d10453SEric Joyner idx = vsig & ICE_VSIG_IDX_M; 124671d10453SEric Joyner 124771d10453SEric Joyner if (vsi >= ICE_MAX_VSI || idx >= ICE_MAX_VSIGS) 124871d10453SEric Joyner return ICE_ERR_PARAM; 124971d10453SEric Joyner 125071d10453SEric Joyner if (!hw->blk[blk].xlt2.vsig_tbl[idx].in_use) 125171d10453SEric Joyner return ICE_ERR_DOES_NOT_EXIST; 125271d10453SEric Joyner 125371d10453SEric Joyner /* entry already in default VSIG, don't have to remove */ 125471d10453SEric Joyner if (idx == ICE_DEFAULT_VSIG) 125571d10453SEric Joyner return ICE_SUCCESS; 125671d10453SEric Joyner 125771d10453SEric Joyner vsi_head = &hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi; 125871d10453SEric Joyner if (!(*vsi_head)) 125971d10453SEric Joyner return ICE_ERR_CFG; 126071d10453SEric Joyner 126171d10453SEric Joyner vsi_tgt = &hw->blk[blk].xlt2.vsis[vsi]; 126271d10453SEric Joyner vsi_cur = (*vsi_head); 126371d10453SEric Joyner 126471d10453SEric Joyner /* iterate the VSI list, skip over the entry to be removed */ 126571d10453SEric Joyner while (vsi_cur) { 126671d10453SEric Joyner if (vsi_tgt == vsi_cur) { 126771d10453SEric Joyner (*vsi_head) = vsi_cur->next_vsi; 126871d10453SEric Joyner break; 126971d10453SEric Joyner } 127071d10453SEric Joyner vsi_head = &vsi_cur->next_vsi; 127171d10453SEric Joyner vsi_cur = vsi_cur->next_vsi; 127271d10453SEric Joyner } 127371d10453SEric Joyner 127471d10453SEric Joyner /* verify if VSI was removed from group list */ 127571d10453SEric Joyner if (!vsi_cur) 127671d10453SEric Joyner return ICE_ERR_DOES_NOT_EXIST; 127771d10453SEric Joyner 127871d10453SEric Joyner vsi_cur->vsig = ICE_DEFAULT_VSIG; 127971d10453SEric Joyner vsi_cur->changed = 1; 128071d10453SEric Joyner vsi_cur->next_vsi = NULL; 128171d10453SEric Joyner 128271d10453SEric Joyner return ICE_SUCCESS; 128371d10453SEric Joyner } 128471d10453SEric Joyner 128571d10453SEric Joyner /** 128671d10453SEric Joyner * ice_vsig_add_mv_vsi - add or move a VSI to a VSI group 128771d10453SEric Joyner * @hw: pointer to the hardware structure 128871d10453SEric Joyner * @blk: HW block 128971d10453SEric Joyner * @vsi: VSI to move 129071d10453SEric Joyner * @vsig: destination VSI group 129171d10453SEric Joyner * 129271d10453SEric Joyner * This function will move or add the input VSI to the target VSIG. 129371d10453SEric Joyner * The function will find the original VSIG the VSI belongs to and 129471d10453SEric Joyner * move the entry to the DEFAULT_VSIG, update the original VSIG and 129571d10453SEric Joyner * then move entry to the new VSIG. 129671d10453SEric Joyner */ 129771d10453SEric Joyner static enum ice_status 129871d10453SEric Joyner ice_vsig_add_mv_vsi(struct ice_hw *hw, enum ice_block blk, u16 vsi, u16 vsig) 129971d10453SEric Joyner { 130071d10453SEric Joyner struct ice_vsig_vsi *tmp; 130171d10453SEric Joyner enum ice_status status; 130271d10453SEric Joyner u16 orig_vsig, idx; 130371d10453SEric Joyner 130471d10453SEric Joyner idx = vsig & ICE_VSIG_IDX_M; 130571d10453SEric Joyner 130671d10453SEric Joyner if (vsi >= ICE_MAX_VSI || idx >= ICE_MAX_VSIGS) 130771d10453SEric Joyner return ICE_ERR_PARAM; 130871d10453SEric Joyner 130971d10453SEric Joyner /* if VSIG not in use and VSIG is not default type this VSIG 131071d10453SEric Joyner * doesn't exist. 131171d10453SEric Joyner */ 131271d10453SEric Joyner if (!hw->blk[blk].xlt2.vsig_tbl[idx].in_use && 131371d10453SEric Joyner vsig != ICE_DEFAULT_VSIG) 131471d10453SEric Joyner return ICE_ERR_DOES_NOT_EXIST; 131571d10453SEric Joyner 131671d10453SEric Joyner status = ice_vsig_find_vsi(hw, blk, vsi, &orig_vsig); 131771d10453SEric Joyner if (status) 131871d10453SEric Joyner return status; 131971d10453SEric Joyner 132071d10453SEric Joyner /* no update required if vsigs match */ 132171d10453SEric Joyner if (orig_vsig == vsig) 132271d10453SEric Joyner return ICE_SUCCESS; 132371d10453SEric Joyner 132471d10453SEric Joyner if (orig_vsig != ICE_DEFAULT_VSIG) { 132571d10453SEric Joyner /* remove entry from orig_vsig and add to default VSIG */ 132671d10453SEric Joyner status = ice_vsig_remove_vsi(hw, blk, vsi, orig_vsig); 132771d10453SEric Joyner if (status) 132871d10453SEric Joyner return status; 132971d10453SEric Joyner } 133071d10453SEric Joyner 133171d10453SEric Joyner if (idx == ICE_DEFAULT_VSIG) 133271d10453SEric Joyner return ICE_SUCCESS; 133371d10453SEric Joyner 133471d10453SEric Joyner /* Create VSI entry and add VSIG and prop_mask values */ 133571d10453SEric Joyner hw->blk[blk].xlt2.vsis[vsi].vsig = vsig; 133671d10453SEric Joyner hw->blk[blk].xlt2.vsis[vsi].changed = 1; 133771d10453SEric Joyner 133871d10453SEric Joyner /* Add new entry to the head of the VSIG list */ 133971d10453SEric Joyner tmp = hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi; 134071d10453SEric Joyner hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi = 134171d10453SEric Joyner &hw->blk[blk].xlt2.vsis[vsi]; 134271d10453SEric Joyner hw->blk[blk].xlt2.vsis[vsi].next_vsi = tmp; 134371d10453SEric Joyner hw->blk[blk].xlt2.t[vsi] = vsig; 134471d10453SEric Joyner 134571d10453SEric Joyner return ICE_SUCCESS; 134671d10453SEric Joyner } 134771d10453SEric Joyner 134871d10453SEric Joyner /** 134971d10453SEric Joyner * ice_find_prof_id - find profile ID for a given field vector 135071d10453SEric Joyner * @hw: pointer to the hardware structure 135171d10453SEric Joyner * @blk: HW block 135271d10453SEric Joyner * @fv: field vector to search for 135371d10453SEric Joyner * @prof_id: receives the profile ID 135471d10453SEric Joyner */ 135571d10453SEric Joyner static enum ice_status 135671d10453SEric Joyner ice_find_prof_id(struct ice_hw *hw, enum ice_block blk, 135771d10453SEric Joyner struct ice_fv_word *fv, u8 *prof_id) 135871d10453SEric Joyner { 135971d10453SEric Joyner struct ice_es *es = &hw->blk[blk].es; 136071d10453SEric Joyner u16 off; 136171d10453SEric Joyner u8 i; 136271d10453SEric Joyner 136371d10453SEric Joyner for (i = 0; i < (u8)es->count; i++) { 136471d10453SEric Joyner off = i * es->fvw; 136571d10453SEric Joyner 136671d10453SEric Joyner if (memcmp(&es->t[off], fv, es->fvw * sizeof(*fv))) 136771d10453SEric Joyner continue; 136871d10453SEric Joyner 136971d10453SEric Joyner *prof_id = i; 137071d10453SEric Joyner return ICE_SUCCESS; 137171d10453SEric Joyner } 137271d10453SEric Joyner 137371d10453SEric Joyner return ICE_ERR_DOES_NOT_EXIST; 137471d10453SEric Joyner } 137571d10453SEric Joyner 137671d10453SEric Joyner /** 137771d10453SEric Joyner * ice_prof_id_rsrc_type - get profile ID resource type for a block type 137871d10453SEric Joyner * @blk: the block type 137971d10453SEric Joyner * @rsrc_type: pointer to variable to receive the resource type 138071d10453SEric Joyner */ 138171d10453SEric Joyner static bool ice_prof_id_rsrc_type(enum ice_block blk, u16 *rsrc_type) 138271d10453SEric Joyner { 138371d10453SEric Joyner switch (blk) { 138471d10453SEric Joyner case ICE_BLK_RSS: 138571d10453SEric Joyner *rsrc_type = ICE_AQC_RES_TYPE_HASH_PROF_BLDR_PROFID; 138671d10453SEric Joyner break; 138771d10453SEric Joyner case ICE_BLK_PE: 138871d10453SEric Joyner *rsrc_type = ICE_AQC_RES_TYPE_QHASH_PROF_BLDR_PROFID; 138971d10453SEric Joyner break; 139071d10453SEric Joyner default: 139171d10453SEric Joyner return false; 139271d10453SEric Joyner } 139371d10453SEric Joyner return true; 139471d10453SEric Joyner } 139571d10453SEric Joyner 139671d10453SEric Joyner /** 139771d10453SEric Joyner * ice_tcam_ent_rsrc_type - get TCAM entry resource type for a block type 139871d10453SEric Joyner * @blk: the block type 139971d10453SEric Joyner * @rsrc_type: pointer to variable to receive the resource type 140071d10453SEric Joyner */ 140171d10453SEric Joyner static bool ice_tcam_ent_rsrc_type(enum ice_block blk, u16 *rsrc_type) 140271d10453SEric Joyner { 140371d10453SEric Joyner switch (blk) { 140471d10453SEric Joyner case ICE_BLK_RSS: 140571d10453SEric Joyner *rsrc_type = ICE_AQC_RES_TYPE_HASH_PROF_BLDR_TCAM; 140671d10453SEric Joyner break; 140771d10453SEric Joyner case ICE_BLK_PE: 140871d10453SEric Joyner *rsrc_type = ICE_AQC_RES_TYPE_QHASH_PROF_BLDR_TCAM; 140971d10453SEric Joyner break; 141071d10453SEric Joyner default: 141171d10453SEric Joyner return false; 141271d10453SEric Joyner } 141371d10453SEric Joyner return true; 141471d10453SEric Joyner } 141571d10453SEric Joyner 141671d10453SEric Joyner /** 141771d10453SEric Joyner * ice_alloc_tcam_ent - allocate hardware TCAM entry 141871d10453SEric Joyner * @hw: pointer to the HW struct 141971d10453SEric Joyner * @blk: the block to allocate the TCAM for 14207d7af7f8SEric Joyner * @btm: true to allocate from bottom of table, false to allocate from top 142171d10453SEric Joyner * @tcam_idx: pointer to variable to receive the TCAM entry 142271d10453SEric Joyner * 142371d10453SEric Joyner * This function allocates a new entry in a Profile ID TCAM for a specific 142471d10453SEric Joyner * block. 142571d10453SEric Joyner */ 142671d10453SEric Joyner static enum ice_status 14277d7af7f8SEric Joyner ice_alloc_tcam_ent(struct ice_hw *hw, enum ice_block blk, bool btm, 14287d7af7f8SEric Joyner u16 *tcam_idx) 142971d10453SEric Joyner { 143071d10453SEric Joyner u16 res_type; 143171d10453SEric Joyner 143271d10453SEric Joyner if (!ice_tcam_ent_rsrc_type(blk, &res_type)) 143371d10453SEric Joyner return ICE_ERR_PARAM; 143471d10453SEric Joyner 14357d7af7f8SEric Joyner return ice_alloc_hw_res(hw, res_type, 1, btm, tcam_idx); 143671d10453SEric Joyner } 143771d10453SEric Joyner 143871d10453SEric Joyner /** 143971d10453SEric Joyner * ice_free_tcam_ent - free hardware TCAM entry 144071d10453SEric Joyner * @hw: pointer to the HW struct 144171d10453SEric Joyner * @blk: the block from which to free the TCAM entry 144271d10453SEric Joyner * @tcam_idx: the TCAM entry to free 144371d10453SEric Joyner * 144471d10453SEric Joyner * This function frees an entry in a Profile ID TCAM for a specific block. 144571d10453SEric Joyner */ 144671d10453SEric Joyner static enum ice_status 144771d10453SEric Joyner ice_free_tcam_ent(struct ice_hw *hw, enum ice_block blk, u16 tcam_idx) 144871d10453SEric Joyner { 144971d10453SEric Joyner u16 res_type; 145071d10453SEric Joyner 145171d10453SEric Joyner if (!ice_tcam_ent_rsrc_type(blk, &res_type)) 145271d10453SEric Joyner return ICE_ERR_PARAM; 145371d10453SEric Joyner 145471d10453SEric Joyner return ice_free_hw_res(hw, res_type, 1, &tcam_idx); 145571d10453SEric Joyner } 145671d10453SEric Joyner 145771d10453SEric Joyner /** 145871d10453SEric Joyner * ice_alloc_prof_id - allocate profile ID 145971d10453SEric Joyner * @hw: pointer to the HW struct 146071d10453SEric Joyner * @blk: the block to allocate the profile ID for 146171d10453SEric Joyner * @prof_id: pointer to variable to receive the profile ID 146271d10453SEric Joyner * 146371d10453SEric Joyner * This function allocates a new profile ID, which also corresponds to a Field 146471d10453SEric Joyner * Vector (Extraction Sequence) entry. 146571d10453SEric Joyner */ 146671d10453SEric Joyner static enum ice_status 146771d10453SEric Joyner ice_alloc_prof_id(struct ice_hw *hw, enum ice_block blk, u8 *prof_id) 146871d10453SEric Joyner { 146971d10453SEric Joyner enum ice_status status; 147071d10453SEric Joyner u16 res_type; 147171d10453SEric Joyner u16 get_prof; 147271d10453SEric Joyner 147371d10453SEric Joyner if (!ice_prof_id_rsrc_type(blk, &res_type)) 147471d10453SEric Joyner return ICE_ERR_PARAM; 147571d10453SEric Joyner 147671d10453SEric Joyner status = ice_alloc_hw_res(hw, res_type, 1, false, &get_prof); 147771d10453SEric Joyner if (!status) 147871d10453SEric Joyner *prof_id = (u8)get_prof; 147971d10453SEric Joyner 148071d10453SEric Joyner return status; 148171d10453SEric Joyner } 148271d10453SEric Joyner 148371d10453SEric Joyner /** 148471d10453SEric Joyner * ice_free_prof_id - free profile ID 148571d10453SEric Joyner * @hw: pointer to the HW struct 148671d10453SEric Joyner * @blk: the block from which to free the profile ID 148771d10453SEric Joyner * @prof_id: the profile ID to free 148871d10453SEric Joyner * 148971d10453SEric Joyner * This function frees a profile ID, which also corresponds to a Field Vector. 149071d10453SEric Joyner */ 149171d10453SEric Joyner static enum ice_status 149271d10453SEric Joyner ice_free_prof_id(struct ice_hw *hw, enum ice_block blk, u8 prof_id) 149371d10453SEric Joyner { 149471d10453SEric Joyner u16 tmp_prof_id = (u16)prof_id; 149571d10453SEric Joyner u16 res_type; 149671d10453SEric Joyner 149771d10453SEric Joyner if (!ice_prof_id_rsrc_type(blk, &res_type)) 149871d10453SEric Joyner return ICE_ERR_PARAM; 149971d10453SEric Joyner 150071d10453SEric Joyner return ice_free_hw_res(hw, res_type, 1, &tmp_prof_id); 150171d10453SEric Joyner } 150271d10453SEric Joyner 150371d10453SEric Joyner /** 150471d10453SEric Joyner * ice_prof_inc_ref - increment reference count for profile 150571d10453SEric Joyner * @hw: pointer to the HW struct 150671d10453SEric Joyner * @blk: the block from which to free the profile ID 150771d10453SEric Joyner * @prof_id: the profile ID for which to increment the reference count 150871d10453SEric Joyner */ 150971d10453SEric Joyner static enum ice_status 151071d10453SEric Joyner ice_prof_inc_ref(struct ice_hw *hw, enum ice_block blk, u8 prof_id) 151171d10453SEric Joyner { 151271d10453SEric Joyner if (prof_id > hw->blk[blk].es.count) 151371d10453SEric Joyner return ICE_ERR_PARAM; 151471d10453SEric Joyner 151571d10453SEric Joyner hw->blk[blk].es.ref_count[prof_id]++; 151671d10453SEric Joyner 151771d10453SEric Joyner return ICE_SUCCESS; 151871d10453SEric Joyner } 151971d10453SEric Joyner 152071d10453SEric Joyner /** 152171d10453SEric Joyner * ice_write_es - write an extraction sequence to hardware 152271d10453SEric Joyner * @hw: pointer to the HW struct 152371d10453SEric Joyner * @blk: the block in which to write the extraction sequence 152471d10453SEric Joyner * @prof_id: the profile ID to write 152571d10453SEric Joyner * @fv: pointer to the extraction sequence to write - NULL to clear extraction 152671d10453SEric Joyner */ 152771d10453SEric Joyner static void 152871d10453SEric Joyner ice_write_es(struct ice_hw *hw, enum ice_block blk, u8 prof_id, 152971d10453SEric Joyner struct ice_fv_word *fv) 153071d10453SEric Joyner { 153171d10453SEric Joyner u16 off; 153271d10453SEric Joyner 153371d10453SEric Joyner off = prof_id * hw->blk[blk].es.fvw; 153471d10453SEric Joyner if (!fv) { 153571d10453SEric Joyner ice_memset(&hw->blk[blk].es.t[off], 0, hw->blk[blk].es.fvw * 153671d10453SEric Joyner sizeof(*fv), ICE_NONDMA_MEM); 153771d10453SEric Joyner hw->blk[blk].es.written[prof_id] = false; 153871d10453SEric Joyner } else { 153971d10453SEric Joyner ice_memcpy(&hw->blk[blk].es.t[off], fv, hw->blk[blk].es.fvw * 154071d10453SEric Joyner sizeof(*fv), ICE_NONDMA_TO_NONDMA); 154171d10453SEric Joyner } 154271d10453SEric Joyner } 154371d10453SEric Joyner 154471d10453SEric Joyner /** 154571d10453SEric Joyner * ice_prof_dec_ref - decrement reference count for profile 154671d10453SEric Joyner * @hw: pointer to the HW struct 154771d10453SEric Joyner * @blk: the block from which to free the profile ID 154871d10453SEric Joyner * @prof_id: the profile ID for which to decrement the reference count 154971d10453SEric Joyner */ 155071d10453SEric Joyner static enum ice_status 155171d10453SEric Joyner ice_prof_dec_ref(struct ice_hw *hw, enum ice_block blk, u8 prof_id) 155271d10453SEric Joyner { 155371d10453SEric Joyner if (prof_id > hw->blk[blk].es.count) 155471d10453SEric Joyner return ICE_ERR_PARAM; 155571d10453SEric Joyner 155671d10453SEric Joyner if (hw->blk[blk].es.ref_count[prof_id] > 0) { 155771d10453SEric Joyner if (!--hw->blk[blk].es.ref_count[prof_id]) { 155871d10453SEric Joyner ice_write_es(hw, blk, prof_id, NULL); 155971d10453SEric Joyner return ice_free_prof_id(hw, blk, prof_id); 156071d10453SEric Joyner } 156171d10453SEric Joyner } 156271d10453SEric Joyner 156371d10453SEric Joyner return ICE_SUCCESS; 156471d10453SEric Joyner } 156571d10453SEric Joyner 156671d10453SEric Joyner /* Block / table section IDs */ 156771d10453SEric Joyner static const u32 ice_blk_sids[ICE_BLK_COUNT][ICE_SID_OFF_COUNT] = { 156871d10453SEric Joyner /* SWITCH */ 156971d10453SEric Joyner { ICE_SID_XLT1_SW, 157071d10453SEric Joyner ICE_SID_XLT2_SW, 157171d10453SEric Joyner ICE_SID_PROFID_TCAM_SW, 157271d10453SEric Joyner ICE_SID_PROFID_REDIR_SW, 157371d10453SEric Joyner ICE_SID_FLD_VEC_SW 157471d10453SEric Joyner }, 157571d10453SEric Joyner 157671d10453SEric Joyner /* ACL */ 157771d10453SEric Joyner { ICE_SID_XLT1_ACL, 157871d10453SEric Joyner ICE_SID_XLT2_ACL, 157971d10453SEric Joyner ICE_SID_PROFID_TCAM_ACL, 158071d10453SEric Joyner ICE_SID_PROFID_REDIR_ACL, 158171d10453SEric Joyner ICE_SID_FLD_VEC_ACL 158271d10453SEric Joyner }, 158371d10453SEric Joyner 158471d10453SEric Joyner /* FD */ 158571d10453SEric Joyner { ICE_SID_XLT1_FD, 158671d10453SEric Joyner ICE_SID_XLT2_FD, 158771d10453SEric Joyner ICE_SID_PROFID_TCAM_FD, 158871d10453SEric Joyner ICE_SID_PROFID_REDIR_FD, 158971d10453SEric Joyner ICE_SID_FLD_VEC_FD 159071d10453SEric Joyner }, 159171d10453SEric Joyner 159271d10453SEric Joyner /* RSS */ 159371d10453SEric Joyner { ICE_SID_XLT1_RSS, 159471d10453SEric Joyner ICE_SID_XLT2_RSS, 159571d10453SEric Joyner ICE_SID_PROFID_TCAM_RSS, 159671d10453SEric Joyner ICE_SID_PROFID_REDIR_RSS, 159771d10453SEric Joyner ICE_SID_FLD_VEC_RSS 159871d10453SEric Joyner }, 159971d10453SEric Joyner 160071d10453SEric Joyner /* PE */ 160171d10453SEric Joyner { ICE_SID_XLT1_PE, 160271d10453SEric Joyner ICE_SID_XLT2_PE, 160371d10453SEric Joyner ICE_SID_PROFID_TCAM_PE, 160471d10453SEric Joyner ICE_SID_PROFID_REDIR_PE, 160571d10453SEric Joyner ICE_SID_FLD_VEC_PE 160671d10453SEric Joyner } 160771d10453SEric Joyner }; 160871d10453SEric Joyner 160971d10453SEric Joyner /** 161071d10453SEric Joyner * ice_init_sw_xlt1_db - init software XLT1 database from HW tables 161171d10453SEric Joyner * @hw: pointer to the hardware structure 161271d10453SEric Joyner * @blk: the HW block to initialize 161371d10453SEric Joyner */ 161471d10453SEric Joyner static void ice_init_sw_xlt1_db(struct ice_hw *hw, enum ice_block blk) 161571d10453SEric Joyner { 161671d10453SEric Joyner u16 pt; 161771d10453SEric Joyner 161871d10453SEric Joyner for (pt = 0; pt < hw->blk[blk].xlt1.count; pt++) { 161971d10453SEric Joyner u8 ptg; 162071d10453SEric Joyner 162171d10453SEric Joyner ptg = hw->blk[blk].xlt1.t[pt]; 162271d10453SEric Joyner if (ptg != ICE_DEFAULT_PTG) { 162371d10453SEric Joyner ice_ptg_alloc_val(hw, blk, ptg); 162471d10453SEric Joyner ice_ptg_add_mv_ptype(hw, blk, pt, ptg); 162571d10453SEric Joyner } 162671d10453SEric Joyner } 162771d10453SEric Joyner } 162871d10453SEric Joyner 162971d10453SEric Joyner /** 163071d10453SEric Joyner * ice_init_sw_xlt2_db - init software XLT2 database from HW tables 163171d10453SEric Joyner * @hw: pointer to the hardware structure 163271d10453SEric Joyner * @blk: the HW block to initialize 163371d10453SEric Joyner */ 163471d10453SEric Joyner static void ice_init_sw_xlt2_db(struct ice_hw *hw, enum ice_block blk) 163571d10453SEric Joyner { 163671d10453SEric Joyner u16 vsi; 163771d10453SEric Joyner 163871d10453SEric Joyner for (vsi = 0; vsi < hw->blk[blk].xlt2.count; vsi++) { 163971d10453SEric Joyner u16 vsig; 164071d10453SEric Joyner 164171d10453SEric Joyner vsig = hw->blk[blk].xlt2.t[vsi]; 164271d10453SEric Joyner if (vsig) { 164371d10453SEric Joyner ice_vsig_alloc_val(hw, blk, vsig); 164471d10453SEric Joyner ice_vsig_add_mv_vsi(hw, blk, vsi, vsig); 164571d10453SEric Joyner /* no changes at this time, since this has been 164671d10453SEric Joyner * initialized from the original package 164771d10453SEric Joyner */ 164871d10453SEric Joyner hw->blk[blk].xlt2.vsis[vsi].changed = 0; 164971d10453SEric Joyner } 165071d10453SEric Joyner } 165171d10453SEric Joyner } 165271d10453SEric Joyner 165371d10453SEric Joyner /** 165471d10453SEric Joyner * ice_init_sw_db - init software database from HW tables 165571d10453SEric Joyner * @hw: pointer to the hardware structure 165671d10453SEric Joyner */ 165771d10453SEric Joyner static void ice_init_sw_db(struct ice_hw *hw) 165871d10453SEric Joyner { 165971d10453SEric Joyner u16 i; 166071d10453SEric Joyner 166171d10453SEric Joyner for (i = 0; i < ICE_BLK_COUNT; i++) { 166271d10453SEric Joyner ice_init_sw_xlt1_db(hw, (enum ice_block)i); 166371d10453SEric Joyner ice_init_sw_xlt2_db(hw, (enum ice_block)i); 166471d10453SEric Joyner } 166571d10453SEric Joyner } 166671d10453SEric Joyner 166771d10453SEric Joyner /** 166871d10453SEric Joyner * ice_fill_tbl - Reads content of a single table type into database 166971d10453SEric Joyner * @hw: pointer to the hardware structure 167071d10453SEric Joyner * @block_id: Block ID of the table to copy 167171d10453SEric Joyner * @sid: Section ID of the table to copy 167271d10453SEric Joyner * 167371d10453SEric Joyner * Will attempt to read the entire content of a given table of a single block 167471d10453SEric Joyner * into the driver database. We assume that the buffer will always 167571d10453SEric Joyner * be as large or larger than the data contained in the package. If 167671d10453SEric Joyner * this condition is not met, there is most likely an error in the package 167771d10453SEric Joyner * contents. 167871d10453SEric Joyner */ 167971d10453SEric Joyner static void ice_fill_tbl(struct ice_hw *hw, enum ice_block block_id, u32 sid) 168071d10453SEric Joyner { 168171d10453SEric Joyner u32 dst_len, sect_len, offset = 0; 168271d10453SEric Joyner struct ice_prof_redir_section *pr; 168371d10453SEric Joyner struct ice_prof_id_section *pid; 168471d10453SEric Joyner struct ice_xlt1_section *xlt1; 168571d10453SEric Joyner struct ice_xlt2_section *xlt2; 168671d10453SEric Joyner struct ice_sw_fv_section *es; 168771d10453SEric Joyner struct ice_pkg_enum state; 168871d10453SEric Joyner u8 *src, *dst; 168971d10453SEric Joyner void *sect; 169071d10453SEric Joyner 169171d10453SEric Joyner /* if the HW segment pointer is null then the first iteration of 169271d10453SEric Joyner * ice_pkg_enum_section() will fail. In this case the HW tables will 169371d10453SEric Joyner * not be filled and return success. 169471d10453SEric Joyner */ 169571d10453SEric Joyner if (!hw->seg) { 169671d10453SEric Joyner ice_debug(hw, ICE_DBG_PKG, "hw->seg is NULL, tables are not filled\n"); 169771d10453SEric Joyner return; 169871d10453SEric Joyner } 169971d10453SEric Joyner 170071d10453SEric Joyner ice_memset(&state, 0, sizeof(state), ICE_NONDMA_MEM); 170171d10453SEric Joyner 170271d10453SEric Joyner sect = ice_pkg_enum_section(hw->seg, &state, sid); 170371d10453SEric Joyner 170471d10453SEric Joyner while (sect) { 170571d10453SEric Joyner switch (sid) { 170671d10453SEric Joyner case ICE_SID_XLT1_SW: 170771d10453SEric Joyner case ICE_SID_XLT1_FD: 170871d10453SEric Joyner case ICE_SID_XLT1_RSS: 170971d10453SEric Joyner case ICE_SID_XLT1_ACL: 171071d10453SEric Joyner case ICE_SID_XLT1_PE: 171171d10453SEric Joyner xlt1 = (struct ice_xlt1_section *)sect; 171271d10453SEric Joyner src = xlt1->value; 171371d10453SEric Joyner sect_len = LE16_TO_CPU(xlt1->count) * 171471d10453SEric Joyner sizeof(*hw->blk[block_id].xlt1.t); 171571d10453SEric Joyner dst = hw->blk[block_id].xlt1.t; 171671d10453SEric Joyner dst_len = hw->blk[block_id].xlt1.count * 171771d10453SEric Joyner sizeof(*hw->blk[block_id].xlt1.t); 171871d10453SEric Joyner break; 171971d10453SEric Joyner case ICE_SID_XLT2_SW: 172071d10453SEric Joyner case ICE_SID_XLT2_FD: 172171d10453SEric Joyner case ICE_SID_XLT2_RSS: 172271d10453SEric Joyner case ICE_SID_XLT2_ACL: 172371d10453SEric Joyner case ICE_SID_XLT2_PE: 172471d10453SEric Joyner xlt2 = (struct ice_xlt2_section *)sect; 172571d10453SEric Joyner src = (_FORCE_ u8 *)xlt2->value; 172671d10453SEric Joyner sect_len = LE16_TO_CPU(xlt2->count) * 172771d10453SEric Joyner sizeof(*hw->blk[block_id].xlt2.t); 172871d10453SEric Joyner dst = (u8 *)hw->blk[block_id].xlt2.t; 172971d10453SEric Joyner dst_len = hw->blk[block_id].xlt2.count * 173071d10453SEric Joyner sizeof(*hw->blk[block_id].xlt2.t); 173171d10453SEric Joyner break; 173271d10453SEric Joyner case ICE_SID_PROFID_TCAM_SW: 173371d10453SEric Joyner case ICE_SID_PROFID_TCAM_FD: 173471d10453SEric Joyner case ICE_SID_PROFID_TCAM_RSS: 173571d10453SEric Joyner case ICE_SID_PROFID_TCAM_ACL: 173671d10453SEric Joyner case ICE_SID_PROFID_TCAM_PE: 173771d10453SEric Joyner pid = (struct ice_prof_id_section *)sect; 173871d10453SEric Joyner src = (u8 *)pid->entry; 173971d10453SEric Joyner sect_len = LE16_TO_CPU(pid->count) * 174071d10453SEric Joyner sizeof(*hw->blk[block_id].prof.t); 174171d10453SEric Joyner dst = (u8 *)hw->blk[block_id].prof.t; 174271d10453SEric Joyner dst_len = hw->blk[block_id].prof.count * 174371d10453SEric Joyner sizeof(*hw->blk[block_id].prof.t); 174471d10453SEric Joyner break; 174571d10453SEric Joyner case ICE_SID_PROFID_REDIR_SW: 174671d10453SEric Joyner case ICE_SID_PROFID_REDIR_FD: 174771d10453SEric Joyner case ICE_SID_PROFID_REDIR_RSS: 174871d10453SEric Joyner case ICE_SID_PROFID_REDIR_ACL: 174971d10453SEric Joyner case ICE_SID_PROFID_REDIR_PE: 175071d10453SEric Joyner pr = (struct ice_prof_redir_section *)sect; 175171d10453SEric Joyner src = pr->redir_value; 175271d10453SEric Joyner sect_len = LE16_TO_CPU(pr->count) * 175371d10453SEric Joyner sizeof(*hw->blk[block_id].prof_redir.t); 175471d10453SEric Joyner dst = hw->blk[block_id].prof_redir.t; 175571d10453SEric Joyner dst_len = hw->blk[block_id].prof_redir.count * 175671d10453SEric Joyner sizeof(*hw->blk[block_id].prof_redir.t); 175771d10453SEric Joyner break; 175871d10453SEric Joyner case ICE_SID_FLD_VEC_SW: 175971d10453SEric Joyner case ICE_SID_FLD_VEC_FD: 176071d10453SEric Joyner case ICE_SID_FLD_VEC_RSS: 176171d10453SEric Joyner case ICE_SID_FLD_VEC_ACL: 176271d10453SEric Joyner case ICE_SID_FLD_VEC_PE: 176371d10453SEric Joyner es = (struct ice_sw_fv_section *)sect; 176471d10453SEric Joyner src = (u8 *)es->fv; 176571d10453SEric Joyner sect_len = (u32)(LE16_TO_CPU(es->count) * 176671d10453SEric Joyner hw->blk[block_id].es.fvw) * 176771d10453SEric Joyner sizeof(*hw->blk[block_id].es.t); 176871d10453SEric Joyner dst = (u8 *)hw->blk[block_id].es.t; 176971d10453SEric Joyner dst_len = (u32)(hw->blk[block_id].es.count * 177071d10453SEric Joyner hw->blk[block_id].es.fvw) * 177171d10453SEric Joyner sizeof(*hw->blk[block_id].es.t); 177271d10453SEric Joyner break; 177371d10453SEric Joyner default: 177471d10453SEric Joyner return; 177571d10453SEric Joyner } 177671d10453SEric Joyner 177771d10453SEric Joyner /* if the section offset exceeds destination length, terminate 177871d10453SEric Joyner * table fill. 177971d10453SEric Joyner */ 178071d10453SEric Joyner if (offset > dst_len) 178171d10453SEric Joyner return; 178271d10453SEric Joyner 178371d10453SEric Joyner /* if the sum of section size and offset exceed destination size 178471d10453SEric Joyner * then we are out of bounds of the HW table size for that PF. 178571d10453SEric Joyner * Changing section length to fill the remaining table space 178671d10453SEric Joyner * of that PF. 178771d10453SEric Joyner */ 178871d10453SEric Joyner if ((offset + sect_len) > dst_len) 178971d10453SEric Joyner sect_len = dst_len - offset; 179071d10453SEric Joyner 179171d10453SEric Joyner ice_memcpy(dst + offset, src, sect_len, ICE_NONDMA_TO_NONDMA); 179271d10453SEric Joyner offset += sect_len; 179371d10453SEric Joyner sect = ice_pkg_enum_section(NULL, &state, sid); 179471d10453SEric Joyner } 179571d10453SEric Joyner } 179671d10453SEric Joyner 179771d10453SEric Joyner /** 17988923de59SPiotr Kubaj * ice_init_flow_profs - init flow profile locks and list heads 17998923de59SPiotr Kubaj * @hw: pointer to the hardware structure 18008923de59SPiotr Kubaj * @blk_idx: HW block index 18018923de59SPiotr Kubaj */ 18028923de59SPiotr Kubaj static 18038923de59SPiotr Kubaj void ice_init_flow_profs(struct ice_hw *hw, u8 blk_idx) 18048923de59SPiotr Kubaj { 18058923de59SPiotr Kubaj ice_init_lock(&hw->fl_profs_locks[blk_idx]); 18068923de59SPiotr Kubaj INIT_LIST_HEAD(&hw->fl_profs[blk_idx]); 18078923de59SPiotr Kubaj } 18088923de59SPiotr Kubaj 18098923de59SPiotr Kubaj /** 18108923de59SPiotr Kubaj * ice_init_hw_tbls - init hardware table memory 18118923de59SPiotr Kubaj * @hw: pointer to the hardware structure 18128923de59SPiotr Kubaj */ 18138923de59SPiotr Kubaj enum ice_status ice_init_hw_tbls(struct ice_hw *hw) 18148923de59SPiotr Kubaj { 18158923de59SPiotr Kubaj u8 i; 18168923de59SPiotr Kubaj 18178923de59SPiotr Kubaj ice_init_lock(&hw->rss_locks); 18188923de59SPiotr Kubaj INIT_LIST_HEAD(&hw->rss_list_head); 18198923de59SPiotr Kubaj for (i = 0; i < ICE_BLK_COUNT; i++) { 18208923de59SPiotr Kubaj struct ice_prof_redir *prof_redir = &hw->blk[i].prof_redir; 18218923de59SPiotr Kubaj struct ice_prof_tcam *prof = &hw->blk[i].prof; 18228923de59SPiotr Kubaj struct ice_xlt1 *xlt1 = &hw->blk[i].xlt1; 18238923de59SPiotr Kubaj struct ice_xlt2 *xlt2 = &hw->blk[i].xlt2; 18248923de59SPiotr Kubaj struct ice_es *es = &hw->blk[i].es; 18258923de59SPiotr Kubaj u16 j; 18268923de59SPiotr Kubaj 18278923de59SPiotr Kubaj if (hw->blk[i].is_list_init) 18288923de59SPiotr Kubaj continue; 18298923de59SPiotr Kubaj 18308923de59SPiotr Kubaj ice_init_flow_profs(hw, i); 18318923de59SPiotr Kubaj ice_init_lock(&es->prof_map_lock); 18328923de59SPiotr Kubaj INIT_LIST_HEAD(&es->prof_map); 18338923de59SPiotr Kubaj hw->blk[i].is_list_init = true; 18348923de59SPiotr Kubaj 18358923de59SPiotr Kubaj hw->blk[i].overwrite = blk_sizes[i].overwrite; 18368923de59SPiotr Kubaj es->reverse = blk_sizes[i].reverse; 18378923de59SPiotr Kubaj 18388923de59SPiotr Kubaj xlt1->sid = ice_blk_sids[i][ICE_SID_XLT1_OFF]; 18398923de59SPiotr Kubaj xlt1->count = blk_sizes[i].xlt1; 18408923de59SPiotr Kubaj 18418923de59SPiotr Kubaj xlt1->ptypes = (struct ice_ptg_ptype *) 18428923de59SPiotr Kubaj ice_calloc(hw, xlt1->count, sizeof(*xlt1->ptypes)); 18438923de59SPiotr Kubaj 18448923de59SPiotr Kubaj if (!xlt1->ptypes) 18458923de59SPiotr Kubaj goto err; 18468923de59SPiotr Kubaj 18478923de59SPiotr Kubaj xlt1->ptg_tbl = (struct ice_ptg_entry *) 18488923de59SPiotr Kubaj ice_calloc(hw, ICE_MAX_PTGS, sizeof(*xlt1->ptg_tbl)); 18498923de59SPiotr Kubaj 18508923de59SPiotr Kubaj if (!xlt1->ptg_tbl) 18518923de59SPiotr Kubaj goto err; 18528923de59SPiotr Kubaj 18538923de59SPiotr Kubaj xlt1->t = (u8 *)ice_calloc(hw, xlt1->count, sizeof(*xlt1->t)); 18548923de59SPiotr Kubaj if (!xlt1->t) 18558923de59SPiotr Kubaj goto err; 18568923de59SPiotr Kubaj 18578923de59SPiotr Kubaj xlt2->sid = ice_blk_sids[i][ICE_SID_XLT2_OFF]; 18588923de59SPiotr Kubaj xlt2->count = blk_sizes[i].xlt2; 18598923de59SPiotr Kubaj 18608923de59SPiotr Kubaj xlt2->vsis = (struct ice_vsig_vsi *) 18618923de59SPiotr Kubaj ice_calloc(hw, xlt2->count, sizeof(*xlt2->vsis)); 18628923de59SPiotr Kubaj 18638923de59SPiotr Kubaj if (!xlt2->vsis) 18648923de59SPiotr Kubaj goto err; 18658923de59SPiotr Kubaj 18668923de59SPiotr Kubaj xlt2->vsig_tbl = (struct ice_vsig_entry *) 18678923de59SPiotr Kubaj ice_calloc(hw, xlt2->count, sizeof(*xlt2->vsig_tbl)); 18688923de59SPiotr Kubaj if (!xlt2->vsig_tbl) 18698923de59SPiotr Kubaj goto err; 18708923de59SPiotr Kubaj 18718923de59SPiotr Kubaj for (j = 0; j < xlt2->count; j++) 18728923de59SPiotr Kubaj INIT_LIST_HEAD(&xlt2->vsig_tbl[j].prop_lst); 18738923de59SPiotr Kubaj 18748923de59SPiotr Kubaj xlt2->t = (u16 *)ice_calloc(hw, xlt2->count, sizeof(*xlt2->t)); 18758923de59SPiotr Kubaj if (!xlt2->t) 18768923de59SPiotr Kubaj goto err; 18778923de59SPiotr Kubaj 18788923de59SPiotr Kubaj prof->sid = ice_blk_sids[i][ICE_SID_PR_OFF]; 18798923de59SPiotr Kubaj prof->count = blk_sizes[i].prof_tcam; 18808923de59SPiotr Kubaj prof->max_prof_id = blk_sizes[i].prof_id; 18818923de59SPiotr Kubaj prof->cdid_bits = blk_sizes[i].prof_cdid_bits; 18828923de59SPiotr Kubaj prof->t = (struct ice_prof_tcam_entry *) 18838923de59SPiotr Kubaj ice_calloc(hw, prof->count, sizeof(*prof->t)); 18848923de59SPiotr Kubaj 18858923de59SPiotr Kubaj if (!prof->t) 18868923de59SPiotr Kubaj goto err; 18878923de59SPiotr Kubaj 18888923de59SPiotr Kubaj prof_redir->sid = ice_blk_sids[i][ICE_SID_PR_REDIR_OFF]; 18898923de59SPiotr Kubaj prof_redir->count = blk_sizes[i].prof_redir; 18908923de59SPiotr Kubaj prof_redir->t = (u8 *)ice_calloc(hw, prof_redir->count, 18918923de59SPiotr Kubaj sizeof(*prof_redir->t)); 18928923de59SPiotr Kubaj 18938923de59SPiotr Kubaj if (!prof_redir->t) 18948923de59SPiotr Kubaj goto err; 18958923de59SPiotr Kubaj 18968923de59SPiotr Kubaj es->sid = ice_blk_sids[i][ICE_SID_ES_OFF]; 18978923de59SPiotr Kubaj es->count = blk_sizes[i].es; 18988923de59SPiotr Kubaj es->fvw = blk_sizes[i].fvw; 18998923de59SPiotr Kubaj es->t = (struct ice_fv_word *) 19008923de59SPiotr Kubaj ice_calloc(hw, (u32)(es->count * es->fvw), 19018923de59SPiotr Kubaj sizeof(*es->t)); 19028923de59SPiotr Kubaj if (!es->t) 19038923de59SPiotr Kubaj goto err; 19048923de59SPiotr Kubaj 19058923de59SPiotr Kubaj es->ref_count = (u16 *) 19068923de59SPiotr Kubaj ice_calloc(hw, es->count, sizeof(*es->ref_count)); 19078923de59SPiotr Kubaj 19088923de59SPiotr Kubaj if (!es->ref_count) 19098923de59SPiotr Kubaj goto err; 19108923de59SPiotr Kubaj 19118923de59SPiotr Kubaj es->written = (u8 *) 19128923de59SPiotr Kubaj ice_calloc(hw, es->count, sizeof(*es->written)); 19138923de59SPiotr Kubaj 19148923de59SPiotr Kubaj if (!es->written) 19158923de59SPiotr Kubaj goto err; 19168923de59SPiotr Kubaj 19178923de59SPiotr Kubaj } 19188923de59SPiotr Kubaj return ICE_SUCCESS; 19198923de59SPiotr Kubaj 19208923de59SPiotr Kubaj err: 19218923de59SPiotr Kubaj ice_free_hw_tbls(hw); 19228923de59SPiotr Kubaj return ICE_ERR_NO_MEMORY; 19238923de59SPiotr Kubaj } 19248923de59SPiotr Kubaj 19258923de59SPiotr Kubaj /** 192671d10453SEric Joyner * ice_fill_blk_tbls - Read package context for tables 192771d10453SEric Joyner * @hw: pointer to the hardware structure 192871d10453SEric Joyner * 192971d10453SEric Joyner * Reads the current package contents and populates the driver 193071d10453SEric Joyner * database with the data iteratively for all advanced feature 193171d10453SEric Joyner * blocks. Assume that the HW tables have been allocated. 193271d10453SEric Joyner */ 193371d10453SEric Joyner void ice_fill_blk_tbls(struct ice_hw *hw) 193471d10453SEric Joyner { 193571d10453SEric Joyner u8 i; 193671d10453SEric Joyner 193771d10453SEric Joyner for (i = 0; i < ICE_BLK_COUNT; i++) { 193871d10453SEric Joyner enum ice_block blk_id = (enum ice_block)i; 193971d10453SEric Joyner 194071d10453SEric Joyner ice_fill_tbl(hw, blk_id, hw->blk[blk_id].xlt1.sid); 194171d10453SEric Joyner ice_fill_tbl(hw, blk_id, hw->blk[blk_id].xlt2.sid); 194271d10453SEric Joyner ice_fill_tbl(hw, blk_id, hw->blk[blk_id].prof.sid); 194371d10453SEric Joyner ice_fill_tbl(hw, blk_id, hw->blk[blk_id].prof_redir.sid); 194471d10453SEric Joyner ice_fill_tbl(hw, blk_id, hw->blk[blk_id].es.sid); 194571d10453SEric Joyner } 194671d10453SEric Joyner 194771d10453SEric Joyner ice_init_sw_db(hw); 194871d10453SEric Joyner } 194971d10453SEric Joyner 195071d10453SEric Joyner /** 195171d10453SEric Joyner * ice_free_prof_map - free profile map 195271d10453SEric Joyner * @hw: pointer to the hardware structure 195371d10453SEric Joyner * @blk_idx: HW block index 195471d10453SEric Joyner */ 195571d10453SEric Joyner static void ice_free_prof_map(struct ice_hw *hw, u8 blk_idx) 195671d10453SEric Joyner { 195771d10453SEric Joyner struct ice_es *es = &hw->blk[blk_idx].es; 195871d10453SEric Joyner struct ice_prof_map *del, *tmp; 195971d10453SEric Joyner 196071d10453SEric Joyner ice_acquire_lock(&es->prof_map_lock); 196171d10453SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(del, tmp, &es->prof_map, 196271d10453SEric Joyner ice_prof_map, list) { 196371d10453SEric Joyner LIST_DEL(&del->list); 196471d10453SEric Joyner ice_free(hw, del); 196571d10453SEric Joyner } 196671d10453SEric Joyner INIT_LIST_HEAD(&es->prof_map); 196771d10453SEric Joyner ice_release_lock(&es->prof_map_lock); 196871d10453SEric Joyner } 196971d10453SEric Joyner 197071d10453SEric Joyner /** 197171d10453SEric Joyner * ice_free_flow_profs - free flow profile entries 197271d10453SEric Joyner * @hw: pointer to the hardware structure 197371d10453SEric Joyner * @blk_idx: HW block index 197471d10453SEric Joyner */ 197571d10453SEric Joyner static void ice_free_flow_profs(struct ice_hw *hw, u8 blk_idx) 197671d10453SEric Joyner { 197771d10453SEric Joyner struct ice_flow_prof *p, *tmp; 197871d10453SEric Joyner 197971d10453SEric Joyner ice_acquire_lock(&hw->fl_profs_locks[blk_idx]); 198071d10453SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(p, tmp, &hw->fl_profs[blk_idx], 198171d10453SEric Joyner ice_flow_prof, l_entry) { 198271d10453SEric Joyner LIST_DEL(&p->l_entry); 19837d7af7f8SEric Joyner 198471d10453SEric Joyner ice_free(hw, p); 198571d10453SEric Joyner } 198671d10453SEric Joyner ice_release_lock(&hw->fl_profs_locks[blk_idx]); 198771d10453SEric Joyner 198871d10453SEric Joyner /* if driver is in reset and tables are being cleared 198971d10453SEric Joyner * re-initialize the flow profile list heads 199071d10453SEric Joyner */ 199171d10453SEric Joyner INIT_LIST_HEAD(&hw->fl_profs[blk_idx]); 199271d10453SEric Joyner } 199371d10453SEric Joyner 199471d10453SEric Joyner /** 199571d10453SEric Joyner * ice_free_vsig_tbl - free complete VSIG table entries 199671d10453SEric Joyner * @hw: pointer to the hardware structure 199771d10453SEric Joyner * @blk: the HW block on which to free the VSIG table entries 199871d10453SEric Joyner */ 199971d10453SEric Joyner static void ice_free_vsig_tbl(struct ice_hw *hw, enum ice_block blk) 200071d10453SEric Joyner { 200171d10453SEric Joyner u16 i; 200271d10453SEric Joyner 200371d10453SEric Joyner if (!hw->blk[blk].xlt2.vsig_tbl) 200471d10453SEric Joyner return; 200571d10453SEric Joyner 200671d10453SEric Joyner for (i = 1; i < ICE_MAX_VSIGS; i++) 200771d10453SEric Joyner if (hw->blk[blk].xlt2.vsig_tbl[i].in_use) 200871d10453SEric Joyner ice_vsig_free(hw, blk, i); 200971d10453SEric Joyner } 201071d10453SEric Joyner 201171d10453SEric Joyner /** 201271d10453SEric Joyner * ice_free_hw_tbls - free hardware table memory 201371d10453SEric Joyner * @hw: pointer to the hardware structure 201471d10453SEric Joyner */ 201571d10453SEric Joyner void ice_free_hw_tbls(struct ice_hw *hw) 201671d10453SEric Joyner { 201771d10453SEric Joyner struct ice_rss_cfg *r, *rt; 201871d10453SEric Joyner u8 i; 201971d10453SEric Joyner 202071d10453SEric Joyner for (i = 0; i < ICE_BLK_COUNT; i++) { 202171d10453SEric Joyner if (hw->blk[i].is_list_init) { 202271d10453SEric Joyner struct ice_es *es = &hw->blk[i].es; 202371d10453SEric Joyner 202471d10453SEric Joyner ice_free_prof_map(hw, i); 202571d10453SEric Joyner ice_destroy_lock(&es->prof_map_lock); 202671d10453SEric Joyner 202771d10453SEric Joyner ice_free_flow_profs(hw, i); 202871d10453SEric Joyner ice_destroy_lock(&hw->fl_profs_locks[i]); 202971d10453SEric Joyner 203071d10453SEric Joyner hw->blk[i].is_list_init = false; 203171d10453SEric Joyner } 203271d10453SEric Joyner ice_free_vsig_tbl(hw, (enum ice_block)i); 203371d10453SEric Joyner ice_free(hw, hw->blk[i].xlt1.ptypes); 203471d10453SEric Joyner ice_free(hw, hw->blk[i].xlt1.ptg_tbl); 203571d10453SEric Joyner ice_free(hw, hw->blk[i].xlt1.t); 203671d10453SEric Joyner ice_free(hw, hw->blk[i].xlt2.t); 203771d10453SEric Joyner ice_free(hw, hw->blk[i].xlt2.vsig_tbl); 203871d10453SEric Joyner ice_free(hw, hw->blk[i].xlt2.vsis); 203971d10453SEric Joyner ice_free(hw, hw->blk[i].prof.t); 204071d10453SEric Joyner ice_free(hw, hw->blk[i].prof_redir.t); 204171d10453SEric Joyner ice_free(hw, hw->blk[i].es.t); 204271d10453SEric Joyner ice_free(hw, hw->blk[i].es.ref_count); 204371d10453SEric Joyner ice_free(hw, hw->blk[i].es.written); 204471d10453SEric Joyner } 204571d10453SEric Joyner 204671d10453SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(r, rt, &hw->rss_list_head, 204771d10453SEric Joyner ice_rss_cfg, l_entry) { 204871d10453SEric Joyner LIST_DEL(&r->l_entry); 204971d10453SEric Joyner ice_free(hw, r); 205071d10453SEric Joyner } 205171d10453SEric Joyner ice_destroy_lock(&hw->rss_locks); 205271d10453SEric Joyner ice_memset(hw->blk, 0, sizeof(hw->blk), ICE_NONDMA_MEM); 205371d10453SEric Joyner } 205471d10453SEric Joyner 205571d10453SEric Joyner /** 205671d10453SEric Joyner * ice_clear_hw_tbls - clear HW tables and flow profiles 205771d10453SEric Joyner * @hw: pointer to the hardware structure 205871d10453SEric Joyner */ 205971d10453SEric Joyner void ice_clear_hw_tbls(struct ice_hw *hw) 206071d10453SEric Joyner { 206171d10453SEric Joyner u8 i; 206271d10453SEric Joyner 206371d10453SEric Joyner for (i = 0; i < ICE_BLK_COUNT; i++) { 206471d10453SEric Joyner struct ice_prof_redir *prof_redir = &hw->blk[i].prof_redir; 206571d10453SEric Joyner struct ice_prof_tcam *prof = &hw->blk[i].prof; 206671d10453SEric Joyner struct ice_xlt1 *xlt1 = &hw->blk[i].xlt1; 206771d10453SEric Joyner struct ice_xlt2 *xlt2 = &hw->blk[i].xlt2; 206871d10453SEric Joyner struct ice_es *es = &hw->blk[i].es; 206971d10453SEric Joyner 207071d10453SEric Joyner if (hw->blk[i].is_list_init) { 207171d10453SEric Joyner ice_free_prof_map(hw, i); 207271d10453SEric Joyner ice_free_flow_profs(hw, i); 207371d10453SEric Joyner } 207471d10453SEric Joyner 207571d10453SEric Joyner ice_free_vsig_tbl(hw, (enum ice_block)i); 207671d10453SEric Joyner 20778923de59SPiotr Kubaj if (xlt1->ptypes) 20788923de59SPiotr Kubaj ice_memset(xlt1->ptypes, 0, 20798923de59SPiotr Kubaj xlt1->count * sizeof(*xlt1->ptypes), 208071d10453SEric Joyner ICE_NONDMA_MEM); 20818923de59SPiotr Kubaj 20828923de59SPiotr Kubaj if (xlt1->ptg_tbl) 208371d10453SEric Joyner ice_memset(xlt1->ptg_tbl, 0, 208471d10453SEric Joyner ICE_MAX_PTGS * sizeof(*xlt1->ptg_tbl), 208571d10453SEric Joyner ICE_NONDMA_MEM); 20868923de59SPiotr Kubaj 20878923de59SPiotr Kubaj if (xlt1->t) 208871d10453SEric Joyner ice_memset(xlt1->t, 0, xlt1->count * sizeof(*xlt1->t), 208971d10453SEric Joyner ICE_NONDMA_MEM); 209071d10453SEric Joyner 20918923de59SPiotr Kubaj if (xlt2->vsis) 20928923de59SPiotr Kubaj ice_memset(xlt2->vsis, 0, 20938923de59SPiotr Kubaj xlt2->count * sizeof(*xlt2->vsis), 209471d10453SEric Joyner ICE_NONDMA_MEM); 20958923de59SPiotr Kubaj 20968923de59SPiotr Kubaj if (xlt2->vsig_tbl) 209771d10453SEric Joyner ice_memset(xlt2->vsig_tbl, 0, 209871d10453SEric Joyner xlt2->count * sizeof(*xlt2->vsig_tbl), 209971d10453SEric Joyner ICE_NONDMA_MEM); 21008923de59SPiotr Kubaj 21018923de59SPiotr Kubaj if (xlt2->t) 210271d10453SEric Joyner ice_memset(xlt2->t, 0, xlt2->count * sizeof(*xlt2->t), 210371d10453SEric Joyner ICE_NONDMA_MEM); 210471d10453SEric Joyner 21058923de59SPiotr Kubaj if (prof->t) 210671d10453SEric Joyner ice_memset(prof->t, 0, prof->count * sizeof(*prof->t), 210771d10453SEric Joyner ICE_NONDMA_MEM); 21088923de59SPiotr Kubaj 21098923de59SPiotr Kubaj if (prof_redir->t) 211071d10453SEric Joyner ice_memset(prof_redir->t, 0, 211171d10453SEric Joyner prof_redir->count * sizeof(*prof_redir->t), 211271d10453SEric Joyner ICE_NONDMA_MEM); 211371d10453SEric Joyner 21148923de59SPiotr Kubaj if (es->t) 21158923de59SPiotr Kubaj ice_memset(es->t, 0, 21168923de59SPiotr Kubaj es->count * sizeof(*es->t) * es->fvw, 211771d10453SEric Joyner ICE_NONDMA_MEM); 21188923de59SPiotr Kubaj 21198923de59SPiotr Kubaj if (es->ref_count) 21208923de59SPiotr Kubaj ice_memset(es->ref_count, 0, 21218923de59SPiotr Kubaj es->count * sizeof(*es->ref_count), 212271d10453SEric Joyner ICE_NONDMA_MEM); 21238923de59SPiotr Kubaj 21248923de59SPiotr Kubaj if (es->written) 21258923de59SPiotr Kubaj ice_memset(es->written, 0, 21268923de59SPiotr Kubaj es->count * sizeof(*es->written), 212771d10453SEric Joyner ICE_NONDMA_MEM); 21287d7af7f8SEric Joyner 212971d10453SEric Joyner } 213071d10453SEric Joyner } 213171d10453SEric Joyner 213271d10453SEric Joyner /** 213371d10453SEric Joyner * ice_prof_gen_key - generate profile ID key 213471d10453SEric Joyner * @hw: pointer to the HW struct 213571d10453SEric Joyner * @blk: the block in which to write profile ID to 213671d10453SEric Joyner * @ptg: packet type group (PTG) portion of key 213771d10453SEric Joyner * @vsig: VSIG portion of key 213871d10453SEric Joyner * @cdid: CDID portion of key 213971d10453SEric Joyner * @flags: flag portion of key 214071d10453SEric Joyner * @vl_msk: valid mask 214171d10453SEric Joyner * @dc_msk: don't care mask 214271d10453SEric Joyner * @nm_msk: never match mask 214371d10453SEric Joyner * @key: output of profile ID key 214471d10453SEric Joyner */ 214571d10453SEric Joyner static enum ice_status 214671d10453SEric Joyner ice_prof_gen_key(struct ice_hw *hw, enum ice_block blk, u8 ptg, u16 vsig, 214771d10453SEric Joyner u8 cdid, u16 flags, u8 vl_msk[ICE_TCAM_KEY_VAL_SZ], 214871d10453SEric Joyner u8 dc_msk[ICE_TCAM_KEY_VAL_SZ], u8 nm_msk[ICE_TCAM_KEY_VAL_SZ], 214971d10453SEric Joyner u8 key[ICE_TCAM_KEY_SZ]) 215071d10453SEric Joyner { 215171d10453SEric Joyner struct ice_prof_id_key inkey; 215271d10453SEric Joyner 215371d10453SEric Joyner inkey.xlt1 = ptg; 215471d10453SEric Joyner inkey.xlt2_cdid = CPU_TO_LE16(vsig); 215571d10453SEric Joyner inkey.flags = CPU_TO_LE16(flags); 215671d10453SEric Joyner 215771d10453SEric Joyner switch (hw->blk[blk].prof.cdid_bits) { 215871d10453SEric Joyner case 0: 215971d10453SEric Joyner break; 216071d10453SEric Joyner case 2: 216171d10453SEric Joyner #define ICE_CD_2_M 0xC000U 216271d10453SEric Joyner #define ICE_CD_2_S 14 216371d10453SEric Joyner inkey.xlt2_cdid &= ~CPU_TO_LE16(ICE_CD_2_M); 216471d10453SEric Joyner inkey.xlt2_cdid |= CPU_TO_LE16(BIT(cdid) << ICE_CD_2_S); 216571d10453SEric Joyner break; 216671d10453SEric Joyner case 4: 216771d10453SEric Joyner #define ICE_CD_4_M 0xF000U 216871d10453SEric Joyner #define ICE_CD_4_S 12 216971d10453SEric Joyner inkey.xlt2_cdid &= ~CPU_TO_LE16(ICE_CD_4_M); 217071d10453SEric Joyner inkey.xlt2_cdid |= CPU_TO_LE16(BIT(cdid) << ICE_CD_4_S); 217171d10453SEric Joyner break; 217271d10453SEric Joyner case 8: 217371d10453SEric Joyner #define ICE_CD_8_M 0xFF00U 217471d10453SEric Joyner #define ICE_CD_8_S 16 217571d10453SEric Joyner inkey.xlt2_cdid &= ~CPU_TO_LE16(ICE_CD_8_M); 217671d10453SEric Joyner inkey.xlt2_cdid |= CPU_TO_LE16(BIT(cdid) << ICE_CD_8_S); 217771d10453SEric Joyner break; 217871d10453SEric Joyner default: 217971d10453SEric Joyner ice_debug(hw, ICE_DBG_PKG, "Error in profile config\n"); 218071d10453SEric Joyner break; 218171d10453SEric Joyner } 218271d10453SEric Joyner 218371d10453SEric Joyner return ice_set_key(key, ICE_TCAM_KEY_SZ, (u8 *)&inkey, vl_msk, dc_msk, 218471d10453SEric Joyner nm_msk, 0, ICE_TCAM_KEY_SZ / 2); 218571d10453SEric Joyner } 218671d10453SEric Joyner 218771d10453SEric Joyner /** 218871d10453SEric Joyner * ice_tcam_write_entry - write TCAM entry 218971d10453SEric Joyner * @hw: pointer to the HW struct 219071d10453SEric Joyner * @blk: the block in which to write profile ID to 219171d10453SEric Joyner * @idx: the entry index to write to 219271d10453SEric Joyner * @prof_id: profile ID 219371d10453SEric Joyner * @ptg: packet type group (PTG) portion of key 219471d10453SEric Joyner * @vsig: VSIG portion of key 21957d7af7f8SEric Joyner * @cdid: CDID portion of key 219671d10453SEric Joyner * @flags: flag portion of key 219771d10453SEric Joyner * @vl_msk: valid mask 219871d10453SEric Joyner * @dc_msk: don't care mask 219971d10453SEric Joyner * @nm_msk: never match mask 220071d10453SEric Joyner */ 220171d10453SEric Joyner static enum ice_status 220271d10453SEric Joyner ice_tcam_write_entry(struct ice_hw *hw, enum ice_block blk, u16 idx, 220371d10453SEric Joyner u8 prof_id, u8 ptg, u16 vsig, u8 cdid, u16 flags, 220471d10453SEric Joyner u8 vl_msk[ICE_TCAM_KEY_VAL_SZ], 220571d10453SEric Joyner u8 dc_msk[ICE_TCAM_KEY_VAL_SZ], 220671d10453SEric Joyner u8 nm_msk[ICE_TCAM_KEY_VAL_SZ]) 220771d10453SEric Joyner { 220871d10453SEric Joyner struct ice_prof_tcam_entry; 220971d10453SEric Joyner enum ice_status status; 221071d10453SEric Joyner 221171d10453SEric Joyner status = ice_prof_gen_key(hw, blk, ptg, vsig, cdid, flags, vl_msk, 221271d10453SEric Joyner dc_msk, nm_msk, hw->blk[blk].prof.t[idx].key); 221371d10453SEric Joyner if (!status) { 221471d10453SEric Joyner hw->blk[blk].prof.t[idx].addr = CPU_TO_LE16(idx); 221571d10453SEric Joyner hw->blk[blk].prof.t[idx].prof_id = prof_id; 221671d10453SEric Joyner } 221771d10453SEric Joyner 221871d10453SEric Joyner return status; 221971d10453SEric Joyner } 222071d10453SEric Joyner 222171d10453SEric Joyner /** 222271d10453SEric Joyner * ice_vsig_get_ref - returns number of VSIs belong to a VSIG 222371d10453SEric Joyner * @hw: pointer to the hardware structure 222471d10453SEric Joyner * @blk: HW block 222571d10453SEric Joyner * @vsig: VSIG to query 222671d10453SEric Joyner * @refs: pointer to variable to receive the reference count 222771d10453SEric Joyner */ 222871d10453SEric Joyner static enum ice_status 222971d10453SEric Joyner ice_vsig_get_ref(struct ice_hw *hw, enum ice_block blk, u16 vsig, u16 *refs) 223071d10453SEric Joyner { 223171d10453SEric Joyner u16 idx = vsig & ICE_VSIG_IDX_M; 223271d10453SEric Joyner struct ice_vsig_vsi *ptr; 223371d10453SEric Joyner 223471d10453SEric Joyner *refs = 0; 223571d10453SEric Joyner 223671d10453SEric Joyner if (!hw->blk[blk].xlt2.vsig_tbl[idx].in_use) 223771d10453SEric Joyner return ICE_ERR_DOES_NOT_EXIST; 223871d10453SEric Joyner 223971d10453SEric Joyner ptr = hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi; 224071d10453SEric Joyner while (ptr) { 224171d10453SEric Joyner (*refs)++; 224271d10453SEric Joyner ptr = ptr->next_vsi; 224371d10453SEric Joyner } 224471d10453SEric Joyner 224571d10453SEric Joyner return ICE_SUCCESS; 224671d10453SEric Joyner } 224771d10453SEric Joyner 224871d10453SEric Joyner /** 224971d10453SEric Joyner * ice_has_prof_vsig - check to see if VSIG has a specific profile 225071d10453SEric Joyner * @hw: pointer to the hardware structure 225171d10453SEric Joyner * @blk: HW block 225271d10453SEric Joyner * @vsig: VSIG to check against 225371d10453SEric Joyner * @hdl: profile handle 225471d10453SEric Joyner */ 225571d10453SEric Joyner static bool 225671d10453SEric Joyner ice_has_prof_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, u64 hdl) 225771d10453SEric Joyner { 225871d10453SEric Joyner u16 idx = vsig & ICE_VSIG_IDX_M; 225971d10453SEric Joyner struct ice_vsig_prof *ent; 226071d10453SEric Joyner 226171d10453SEric Joyner LIST_FOR_EACH_ENTRY(ent, &hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst, 22627d7af7f8SEric Joyner ice_vsig_prof, list) 226371d10453SEric Joyner if (ent->profile_cookie == hdl) 226471d10453SEric Joyner return true; 226571d10453SEric Joyner 22667d7af7f8SEric Joyner ice_debug(hw, ICE_DBG_INIT, "Characteristic list for VSI group %d not found.\n", 226771d10453SEric Joyner vsig); 226871d10453SEric Joyner return false; 226971d10453SEric Joyner } 227071d10453SEric Joyner 227171d10453SEric Joyner /** 227271d10453SEric Joyner * ice_prof_bld_es - build profile ID extraction sequence changes 227371d10453SEric Joyner * @hw: pointer to the HW struct 227471d10453SEric Joyner * @blk: hardware block 227571d10453SEric Joyner * @bld: the update package buffer build to add to 227671d10453SEric Joyner * @chgs: the list of changes to make in hardware 227771d10453SEric Joyner */ 227871d10453SEric Joyner static enum ice_status 227971d10453SEric Joyner ice_prof_bld_es(struct ice_hw *hw, enum ice_block blk, 228071d10453SEric Joyner struct ice_buf_build *bld, struct LIST_HEAD_TYPE *chgs) 228171d10453SEric Joyner { 228271d10453SEric Joyner u16 vec_size = hw->blk[blk].es.fvw * sizeof(struct ice_fv_word); 228371d10453SEric Joyner struct ice_chs_chg *tmp; 228471d10453SEric Joyner 22857d7af7f8SEric Joyner LIST_FOR_EACH_ENTRY(tmp, chgs, ice_chs_chg, list_entry) 228671d10453SEric Joyner if (tmp->type == ICE_PTG_ES_ADD && tmp->add_prof) { 228771d10453SEric Joyner u16 off = tmp->prof_id * hw->blk[blk].es.fvw; 228871d10453SEric Joyner struct ice_pkg_es *p; 228971d10453SEric Joyner u32 id; 229071d10453SEric Joyner 229171d10453SEric Joyner id = ice_sect_id(blk, ICE_VEC_TBL); 229271d10453SEric Joyner p = (struct ice_pkg_es *) 22937d7af7f8SEric Joyner ice_pkg_buf_alloc_section(bld, id, 22947d7af7f8SEric Joyner ice_struct_size(p, es, 22957d7af7f8SEric Joyner 1) + 229671d10453SEric Joyner vec_size - 229771d10453SEric Joyner sizeof(p->es[0])); 229871d10453SEric Joyner 229971d10453SEric Joyner if (!p) 230071d10453SEric Joyner return ICE_ERR_MAX_LIMIT; 230171d10453SEric Joyner 230271d10453SEric Joyner p->count = CPU_TO_LE16(1); 230371d10453SEric Joyner p->offset = CPU_TO_LE16(tmp->prof_id); 230471d10453SEric Joyner 230571d10453SEric Joyner ice_memcpy(p->es, &hw->blk[blk].es.t[off], vec_size, 230671d10453SEric Joyner ICE_NONDMA_TO_NONDMA); 230771d10453SEric Joyner } 230871d10453SEric Joyner 230971d10453SEric Joyner return ICE_SUCCESS; 231071d10453SEric Joyner } 231171d10453SEric Joyner 231271d10453SEric Joyner /** 231371d10453SEric Joyner * ice_prof_bld_tcam - build profile ID TCAM changes 231471d10453SEric Joyner * @hw: pointer to the HW struct 231571d10453SEric Joyner * @blk: hardware block 231671d10453SEric Joyner * @bld: the update package buffer build to add to 231771d10453SEric Joyner * @chgs: the list of changes to make in hardware 231871d10453SEric Joyner */ 231971d10453SEric Joyner static enum ice_status 232071d10453SEric Joyner ice_prof_bld_tcam(struct ice_hw *hw, enum ice_block blk, 232171d10453SEric Joyner struct ice_buf_build *bld, struct LIST_HEAD_TYPE *chgs) 232271d10453SEric Joyner { 232371d10453SEric Joyner struct ice_chs_chg *tmp; 232471d10453SEric Joyner 23257d7af7f8SEric Joyner LIST_FOR_EACH_ENTRY(tmp, chgs, ice_chs_chg, list_entry) 232671d10453SEric Joyner if (tmp->type == ICE_TCAM_ADD && tmp->add_tcam_idx) { 232771d10453SEric Joyner struct ice_prof_id_section *p; 232871d10453SEric Joyner u32 id; 232971d10453SEric Joyner 233071d10453SEric Joyner id = ice_sect_id(blk, ICE_PROF_TCAM); 233171d10453SEric Joyner p = (struct ice_prof_id_section *) 23327d7af7f8SEric Joyner ice_pkg_buf_alloc_section(bld, id, 23337d7af7f8SEric Joyner ice_struct_size(p, 23347d7af7f8SEric Joyner entry, 23357d7af7f8SEric Joyner 1)); 233671d10453SEric Joyner 233771d10453SEric Joyner if (!p) 233871d10453SEric Joyner return ICE_ERR_MAX_LIMIT; 233971d10453SEric Joyner 234071d10453SEric Joyner p->count = CPU_TO_LE16(1); 234171d10453SEric Joyner p->entry[0].addr = CPU_TO_LE16(tmp->tcam_idx); 234271d10453SEric Joyner p->entry[0].prof_id = tmp->prof_id; 234371d10453SEric Joyner 234471d10453SEric Joyner ice_memcpy(p->entry[0].key, 234571d10453SEric Joyner &hw->blk[blk].prof.t[tmp->tcam_idx].key, 234671d10453SEric Joyner sizeof(hw->blk[blk].prof.t->key), 234771d10453SEric Joyner ICE_NONDMA_TO_NONDMA); 234871d10453SEric Joyner } 234971d10453SEric Joyner 235071d10453SEric Joyner return ICE_SUCCESS; 235171d10453SEric Joyner } 235271d10453SEric Joyner 235371d10453SEric Joyner /** 235471d10453SEric Joyner * ice_prof_bld_xlt1 - build XLT1 changes 235571d10453SEric Joyner * @blk: hardware block 235671d10453SEric Joyner * @bld: the update package buffer build to add to 235771d10453SEric Joyner * @chgs: the list of changes to make in hardware 235871d10453SEric Joyner */ 235971d10453SEric Joyner static enum ice_status 236071d10453SEric Joyner ice_prof_bld_xlt1(enum ice_block blk, struct ice_buf_build *bld, 236171d10453SEric Joyner struct LIST_HEAD_TYPE *chgs) 236271d10453SEric Joyner { 236371d10453SEric Joyner struct ice_chs_chg *tmp; 236471d10453SEric Joyner 23657d7af7f8SEric Joyner LIST_FOR_EACH_ENTRY(tmp, chgs, ice_chs_chg, list_entry) 236671d10453SEric Joyner if (tmp->type == ICE_PTG_ES_ADD && tmp->add_ptg) { 236771d10453SEric Joyner struct ice_xlt1_section *p; 236871d10453SEric Joyner u32 id; 236971d10453SEric Joyner 237071d10453SEric Joyner id = ice_sect_id(blk, ICE_XLT1); 237171d10453SEric Joyner p = (struct ice_xlt1_section *) 23727d7af7f8SEric Joyner ice_pkg_buf_alloc_section(bld, id, 23737d7af7f8SEric Joyner ice_struct_size(p, 23747d7af7f8SEric Joyner value, 23757d7af7f8SEric Joyner 1)); 237671d10453SEric Joyner 237771d10453SEric Joyner if (!p) 237871d10453SEric Joyner return ICE_ERR_MAX_LIMIT; 237971d10453SEric Joyner 238071d10453SEric Joyner p->count = CPU_TO_LE16(1); 238171d10453SEric Joyner p->offset = CPU_TO_LE16(tmp->ptype); 238271d10453SEric Joyner p->value[0] = tmp->ptg; 238371d10453SEric Joyner } 238471d10453SEric Joyner 238571d10453SEric Joyner return ICE_SUCCESS; 238671d10453SEric Joyner } 238771d10453SEric Joyner 238871d10453SEric Joyner /** 238971d10453SEric Joyner * ice_prof_bld_xlt2 - build XLT2 changes 239071d10453SEric Joyner * @blk: hardware block 239171d10453SEric Joyner * @bld: the update package buffer build to add to 239271d10453SEric Joyner * @chgs: the list of changes to make in hardware 239371d10453SEric Joyner */ 239471d10453SEric Joyner static enum ice_status 239571d10453SEric Joyner ice_prof_bld_xlt2(enum ice_block blk, struct ice_buf_build *bld, 239671d10453SEric Joyner struct LIST_HEAD_TYPE *chgs) 239771d10453SEric Joyner { 239871d10453SEric Joyner struct ice_chs_chg *tmp; 239971d10453SEric Joyner 240071d10453SEric Joyner LIST_FOR_EACH_ENTRY(tmp, chgs, ice_chs_chg, list_entry) { 240171d10453SEric Joyner struct ice_xlt2_section *p; 240271d10453SEric Joyner u32 id; 240371d10453SEric Joyner 240471d10453SEric Joyner switch (tmp->type) { 240571d10453SEric Joyner case ICE_VSIG_ADD: 240671d10453SEric Joyner case ICE_VSI_MOVE: 240771d10453SEric Joyner case ICE_VSIG_REM: 240871d10453SEric Joyner id = ice_sect_id(blk, ICE_XLT2); 240971d10453SEric Joyner p = (struct ice_xlt2_section *) 24107d7af7f8SEric Joyner ice_pkg_buf_alloc_section(bld, id, 24117d7af7f8SEric Joyner ice_struct_size(p, 24127d7af7f8SEric Joyner value, 24137d7af7f8SEric Joyner 1)); 241471d10453SEric Joyner 241571d10453SEric Joyner if (!p) 241671d10453SEric Joyner return ICE_ERR_MAX_LIMIT; 241771d10453SEric Joyner 241871d10453SEric Joyner p->count = CPU_TO_LE16(1); 241971d10453SEric Joyner p->offset = CPU_TO_LE16(tmp->vsi); 242071d10453SEric Joyner p->value[0] = CPU_TO_LE16(tmp->vsig); 242171d10453SEric Joyner break; 242271d10453SEric Joyner default: 242371d10453SEric Joyner break; 242471d10453SEric Joyner } 242571d10453SEric Joyner } 242671d10453SEric Joyner 242771d10453SEric Joyner return ICE_SUCCESS; 242871d10453SEric Joyner } 242971d10453SEric Joyner 243071d10453SEric Joyner /** 243171d10453SEric Joyner * ice_upd_prof_hw - update hardware using the change list 243271d10453SEric Joyner * @hw: pointer to the HW struct 243371d10453SEric Joyner * @blk: hardware block 243471d10453SEric Joyner * @chgs: the list of changes to make in hardware 243571d10453SEric Joyner */ 243671d10453SEric Joyner static enum ice_status 243771d10453SEric Joyner ice_upd_prof_hw(struct ice_hw *hw, enum ice_block blk, 243871d10453SEric Joyner struct LIST_HEAD_TYPE *chgs) 243971d10453SEric Joyner { 244071d10453SEric Joyner struct ice_buf_build *b; 244171d10453SEric Joyner struct ice_chs_chg *tmp; 244271d10453SEric Joyner enum ice_status status; 244371d10453SEric Joyner u16 pkg_sects; 244471d10453SEric Joyner u16 xlt1 = 0; 244571d10453SEric Joyner u16 xlt2 = 0; 244671d10453SEric Joyner u16 tcam = 0; 244771d10453SEric Joyner u16 es = 0; 244871d10453SEric Joyner u16 sects; 244971d10453SEric Joyner 245071d10453SEric Joyner /* count number of sections we need */ 245171d10453SEric Joyner LIST_FOR_EACH_ENTRY(tmp, chgs, ice_chs_chg, list_entry) { 245271d10453SEric Joyner switch (tmp->type) { 245371d10453SEric Joyner case ICE_PTG_ES_ADD: 245471d10453SEric Joyner if (tmp->add_ptg) 245571d10453SEric Joyner xlt1++; 245671d10453SEric Joyner if (tmp->add_prof) 245771d10453SEric Joyner es++; 245871d10453SEric Joyner break; 245971d10453SEric Joyner case ICE_TCAM_ADD: 246071d10453SEric Joyner tcam++; 246171d10453SEric Joyner break; 246271d10453SEric Joyner case ICE_VSIG_ADD: 246371d10453SEric Joyner case ICE_VSI_MOVE: 246471d10453SEric Joyner case ICE_VSIG_REM: 246571d10453SEric Joyner xlt2++; 246671d10453SEric Joyner break; 246771d10453SEric Joyner default: 246871d10453SEric Joyner break; 246971d10453SEric Joyner } 247071d10453SEric Joyner } 247171d10453SEric Joyner sects = xlt1 + xlt2 + tcam + es; 247271d10453SEric Joyner 247371d10453SEric Joyner if (!sects) 247471d10453SEric Joyner return ICE_SUCCESS; 247571d10453SEric Joyner 247671d10453SEric Joyner /* Build update package buffer */ 247771d10453SEric Joyner b = ice_pkg_buf_alloc(hw); 247871d10453SEric Joyner if (!b) 247971d10453SEric Joyner return ICE_ERR_NO_MEMORY; 248071d10453SEric Joyner 248171d10453SEric Joyner status = ice_pkg_buf_reserve_section(b, sects); 248271d10453SEric Joyner if (status) 248371d10453SEric Joyner goto error_tmp; 248471d10453SEric Joyner 248571d10453SEric Joyner /* Preserve order of table update: ES, TCAM, PTG, VSIG */ 248671d10453SEric Joyner if (es) { 248771d10453SEric Joyner status = ice_prof_bld_es(hw, blk, b, chgs); 248871d10453SEric Joyner if (status) 248971d10453SEric Joyner goto error_tmp; 249071d10453SEric Joyner } 249171d10453SEric Joyner 249271d10453SEric Joyner if (tcam) { 249371d10453SEric Joyner status = ice_prof_bld_tcam(hw, blk, b, chgs); 249471d10453SEric Joyner if (status) 249571d10453SEric Joyner goto error_tmp; 249671d10453SEric Joyner } 249771d10453SEric Joyner 249871d10453SEric Joyner if (xlt1) { 249971d10453SEric Joyner status = ice_prof_bld_xlt1(blk, b, chgs); 250071d10453SEric Joyner if (status) 250171d10453SEric Joyner goto error_tmp; 250271d10453SEric Joyner } 250371d10453SEric Joyner 250471d10453SEric Joyner if (xlt2) { 250571d10453SEric Joyner status = ice_prof_bld_xlt2(blk, b, chgs); 250671d10453SEric Joyner if (status) 250771d10453SEric Joyner goto error_tmp; 250871d10453SEric Joyner } 250971d10453SEric Joyner 251071d10453SEric Joyner /* After package buffer build check if the section count in buffer is 251171d10453SEric Joyner * non-zero and matches the number of sections detected for package 251271d10453SEric Joyner * update. 251371d10453SEric Joyner */ 251471d10453SEric Joyner pkg_sects = ice_pkg_buf_get_active_sections(b); 251571d10453SEric Joyner if (!pkg_sects || pkg_sects != sects) { 251671d10453SEric Joyner status = ICE_ERR_INVAL_SIZE; 251771d10453SEric Joyner goto error_tmp; 251871d10453SEric Joyner } 251971d10453SEric Joyner 252071d10453SEric Joyner /* update package */ 252171d10453SEric Joyner status = ice_update_pkg(hw, ice_pkg_buf(b), 1); 252271d10453SEric Joyner if (status == ICE_ERR_AQ_ERROR) 252371d10453SEric Joyner ice_debug(hw, ICE_DBG_INIT, "Unable to update HW profile\n"); 252471d10453SEric Joyner 252571d10453SEric Joyner error_tmp: 252671d10453SEric Joyner ice_pkg_buf_free(hw, b); 252771d10453SEric Joyner return status; 252871d10453SEric Joyner } 252971d10453SEric Joyner 253071d10453SEric Joyner /** 253171d10453SEric Joyner * ice_add_prof - add profile 253271d10453SEric Joyner * @hw: pointer to the HW struct 253371d10453SEric Joyner * @blk: hardware block 253471d10453SEric Joyner * @id: profile tracking ID 25358923de59SPiotr Kubaj * @ptypes: bitmap indicating ptypes (ICE_FLOW_PTYPE_MAX bits) 253671d10453SEric Joyner * @es: extraction sequence (length of array is determined by the block) 253771d10453SEric Joyner * 253871d10453SEric Joyner * This function registers a profile, which matches a set of PTGs with a 253971d10453SEric Joyner * particular extraction sequence. While the hardware profile is allocated 254071d10453SEric Joyner * it will not be written until the first call to ice_add_flow that specifies 254171d10453SEric Joyner * the ID value used here. 254271d10453SEric Joyner */ 254371d10453SEric Joyner enum ice_status 25448923de59SPiotr Kubaj ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, 25458923de59SPiotr Kubaj ice_bitmap_t *ptypes, struct ice_fv_word *es) 254671d10453SEric Joyner { 254771d10453SEric Joyner ice_declare_bitmap(ptgs_used, ICE_XLT1_CNT); 254871d10453SEric Joyner struct ice_prof_map *prof; 254971d10453SEric Joyner enum ice_status status; 255071d10453SEric Joyner u8 prof_id; 25518923de59SPiotr Kubaj u16 ptype; 255271d10453SEric Joyner 255371d10453SEric Joyner ice_zero_bitmap(ptgs_used, ICE_XLT1_CNT); 255471d10453SEric Joyner 255571d10453SEric Joyner ice_acquire_lock(&hw->blk[blk].es.prof_map_lock); 255671d10453SEric Joyner 255771d10453SEric Joyner /* search for existing profile */ 255871d10453SEric Joyner status = ice_find_prof_id(hw, blk, es, &prof_id); 255971d10453SEric Joyner if (status) { 256071d10453SEric Joyner /* allocate profile ID */ 256171d10453SEric Joyner status = ice_alloc_prof_id(hw, blk, &prof_id); 256271d10453SEric Joyner if (status) 256371d10453SEric Joyner goto err_ice_add_prof; 256471d10453SEric Joyner 256571d10453SEric Joyner /* and write new es */ 256671d10453SEric Joyner ice_write_es(hw, blk, prof_id, es); 256771d10453SEric Joyner } 256871d10453SEric Joyner 256971d10453SEric Joyner ice_prof_inc_ref(hw, blk, prof_id); 257071d10453SEric Joyner 257171d10453SEric Joyner /* add profile info */ 257271d10453SEric Joyner 257371d10453SEric Joyner prof = (struct ice_prof_map *)ice_malloc(hw, sizeof(*prof)); 257471d10453SEric Joyner if (!prof) 257571d10453SEric Joyner goto err_ice_add_prof; 257671d10453SEric Joyner 257771d10453SEric Joyner prof->profile_cookie = id; 257871d10453SEric Joyner prof->prof_id = prof_id; 257971d10453SEric Joyner prof->ptg_cnt = 0; 258071d10453SEric Joyner prof->context = 0; 258171d10453SEric Joyner 258271d10453SEric Joyner /* build list of ptgs */ 25838923de59SPiotr Kubaj ice_for_each_set_bit(ptype, ptypes, ICE_FLOW_PTYPE_MAX) { 258471d10453SEric Joyner u8 ptg; 258571d10453SEric Joyner 25867d7af7f8SEric Joyner /* The package should place all ptypes in a non-zero 25877d7af7f8SEric Joyner * PTG, so the following call should never fail. 258871d10453SEric Joyner */ 258971d10453SEric Joyner if (ice_ptg_find_ptype(hw, blk, ptype, &ptg)) 259071d10453SEric Joyner continue; 259171d10453SEric Joyner 259271d10453SEric Joyner /* If PTG is already added, skip and continue */ 259371d10453SEric Joyner if (ice_is_bit_set(ptgs_used, ptg)) 259471d10453SEric Joyner continue; 259571d10453SEric Joyner 259671d10453SEric Joyner ice_set_bit(ptg, ptgs_used); 259771d10453SEric Joyner prof->ptg[prof->ptg_cnt] = ptg; 259871d10453SEric Joyner 259971d10453SEric Joyner if (++prof->ptg_cnt >= ICE_MAX_PTG_PER_PROFILE) 260071d10453SEric Joyner break; 260171d10453SEric Joyner } 260271d10453SEric Joyner 260371d10453SEric Joyner LIST_ADD(&prof->list, &hw->blk[blk].es.prof_map); 260471d10453SEric Joyner status = ICE_SUCCESS; 260571d10453SEric Joyner 260671d10453SEric Joyner err_ice_add_prof: 260771d10453SEric Joyner ice_release_lock(&hw->blk[blk].es.prof_map_lock); 260871d10453SEric Joyner return status; 260971d10453SEric Joyner } 261071d10453SEric Joyner 261171d10453SEric Joyner /** 261271d10453SEric Joyner * ice_search_prof_id - Search for a profile tracking ID 261371d10453SEric Joyner * @hw: pointer to the HW struct 261471d10453SEric Joyner * @blk: hardware block 261571d10453SEric Joyner * @id: profile tracking ID 261671d10453SEric Joyner * 261771d10453SEric Joyner * This will search for a profile tracking ID which was previously added. 26187d7af7f8SEric Joyner * The profile map lock should be held before calling this function. 261971d10453SEric Joyner */ 262071d10453SEric Joyner struct ice_prof_map * 262171d10453SEric Joyner ice_search_prof_id(struct ice_hw *hw, enum ice_block blk, u64 id) 262271d10453SEric Joyner { 26237d7af7f8SEric Joyner struct ice_prof_map *entry = NULL; 26247d7af7f8SEric Joyner struct ice_prof_map *map; 262571d10453SEric Joyner 26267d7af7f8SEric Joyner LIST_FOR_EACH_ENTRY(map, &hw->blk[blk].es.prof_map, ice_prof_map, list) 26277d7af7f8SEric Joyner if (map->profile_cookie == id) { 26287d7af7f8SEric Joyner entry = map; 26297d7af7f8SEric Joyner break; 26307d7af7f8SEric Joyner } 263171d10453SEric Joyner 263271d10453SEric Joyner return entry; 263371d10453SEric Joyner } 263471d10453SEric Joyner 263571d10453SEric Joyner /** 263671d10453SEric Joyner * ice_set_prof_context - Set context for a given profile 263771d10453SEric Joyner * @hw: pointer to the HW struct 263871d10453SEric Joyner * @blk: hardware block 263971d10453SEric Joyner * @id: profile tracking ID 264071d10453SEric Joyner * @cntxt: context 264171d10453SEric Joyner */ 26427d7af7f8SEric Joyner enum ice_status 264371d10453SEric Joyner ice_set_prof_context(struct ice_hw *hw, enum ice_block blk, u64 id, u64 cntxt) 264471d10453SEric Joyner { 26457d7af7f8SEric Joyner enum ice_status status = ICE_ERR_DOES_NOT_EXIST; 264671d10453SEric Joyner struct ice_prof_map *entry; 264771d10453SEric Joyner 26487d7af7f8SEric Joyner ice_acquire_lock(&hw->blk[blk].es.prof_map_lock); 264971d10453SEric Joyner entry = ice_search_prof_id(hw, blk, id); 26507d7af7f8SEric Joyner if (entry) { 265171d10453SEric Joyner entry->context = cntxt; 26527d7af7f8SEric Joyner status = ICE_SUCCESS; 26537d7af7f8SEric Joyner } 26547d7af7f8SEric Joyner ice_release_lock(&hw->blk[blk].es.prof_map_lock); 26557d7af7f8SEric Joyner return status; 265671d10453SEric Joyner } 265771d10453SEric Joyner 265871d10453SEric Joyner /** 265971d10453SEric Joyner * ice_get_prof_context - Get context for a given profile 266071d10453SEric Joyner * @hw: pointer to the HW struct 266171d10453SEric Joyner * @blk: hardware block 266271d10453SEric Joyner * @id: profile tracking ID 266371d10453SEric Joyner * @cntxt: pointer to variable to receive the context 266471d10453SEric Joyner */ 26657d7af7f8SEric Joyner enum ice_status 266671d10453SEric Joyner ice_get_prof_context(struct ice_hw *hw, enum ice_block blk, u64 id, u64 *cntxt) 266771d10453SEric Joyner { 26687d7af7f8SEric Joyner enum ice_status status = ICE_ERR_DOES_NOT_EXIST; 266971d10453SEric Joyner struct ice_prof_map *entry; 267071d10453SEric Joyner 26717d7af7f8SEric Joyner ice_acquire_lock(&hw->blk[blk].es.prof_map_lock); 267271d10453SEric Joyner entry = ice_search_prof_id(hw, blk, id); 26737d7af7f8SEric Joyner if (entry) { 267471d10453SEric Joyner *cntxt = entry->context; 26757d7af7f8SEric Joyner status = ICE_SUCCESS; 26767d7af7f8SEric Joyner } 26777d7af7f8SEric Joyner ice_release_lock(&hw->blk[blk].es.prof_map_lock); 26787d7af7f8SEric Joyner return status; 267971d10453SEric Joyner } 268071d10453SEric Joyner 268171d10453SEric Joyner /** 268271d10453SEric Joyner * ice_vsig_prof_id_count - count profiles in a VSIG 268371d10453SEric Joyner * @hw: pointer to the HW struct 268471d10453SEric Joyner * @blk: hardware block 268571d10453SEric Joyner * @vsig: VSIG to remove the profile from 268671d10453SEric Joyner */ 268771d10453SEric Joyner static u16 268871d10453SEric Joyner ice_vsig_prof_id_count(struct ice_hw *hw, enum ice_block blk, u16 vsig) 268971d10453SEric Joyner { 269071d10453SEric Joyner u16 idx = vsig & ICE_VSIG_IDX_M, count = 0; 269171d10453SEric Joyner struct ice_vsig_prof *p; 269271d10453SEric Joyner 269371d10453SEric Joyner LIST_FOR_EACH_ENTRY(p, &hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst, 26947d7af7f8SEric Joyner ice_vsig_prof, list) 269571d10453SEric Joyner count++; 269671d10453SEric Joyner 269771d10453SEric Joyner return count; 269871d10453SEric Joyner } 269971d10453SEric Joyner 270071d10453SEric Joyner /** 270171d10453SEric Joyner * ice_rel_tcam_idx - release a TCAM index 270271d10453SEric Joyner * @hw: pointer to the HW struct 270371d10453SEric Joyner * @blk: hardware block 270471d10453SEric Joyner * @idx: the index to release 270571d10453SEric Joyner */ 270671d10453SEric Joyner static enum ice_status 270771d10453SEric Joyner ice_rel_tcam_idx(struct ice_hw *hw, enum ice_block blk, u16 idx) 270871d10453SEric Joyner { 270971d10453SEric Joyner /* Masks to invoke a never match entry */ 271071d10453SEric Joyner u8 vl_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 271171d10453SEric Joyner u8 dc_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFE, 0xFF, 0xFF, 0xFF, 0xFF }; 271271d10453SEric Joyner u8 nm_msk[ICE_TCAM_KEY_VAL_SZ] = { 0x01, 0x00, 0x00, 0x00, 0x00 }; 271371d10453SEric Joyner enum ice_status status; 271471d10453SEric Joyner 271571d10453SEric Joyner /* write the TCAM entry */ 271671d10453SEric Joyner status = ice_tcam_write_entry(hw, blk, idx, 0, 0, 0, 0, 0, vl_msk, 271771d10453SEric Joyner dc_msk, nm_msk); 271871d10453SEric Joyner if (status) 271971d10453SEric Joyner return status; 272071d10453SEric Joyner 272171d10453SEric Joyner /* release the TCAM entry */ 272271d10453SEric Joyner status = ice_free_tcam_ent(hw, blk, idx); 272371d10453SEric Joyner 272471d10453SEric Joyner return status; 272571d10453SEric Joyner } 272671d10453SEric Joyner 272771d10453SEric Joyner /** 272871d10453SEric Joyner * ice_rem_prof_id - remove one profile from a VSIG 272971d10453SEric Joyner * @hw: pointer to the HW struct 273071d10453SEric Joyner * @blk: hardware block 273171d10453SEric Joyner * @prof: pointer to profile structure to remove 273271d10453SEric Joyner */ 273371d10453SEric Joyner static enum ice_status 273471d10453SEric Joyner ice_rem_prof_id(struct ice_hw *hw, enum ice_block blk, 273571d10453SEric Joyner struct ice_vsig_prof *prof) 273671d10453SEric Joyner { 273771d10453SEric Joyner enum ice_status status; 273871d10453SEric Joyner u16 i; 273971d10453SEric Joyner 27407d7af7f8SEric Joyner for (i = 0; i < prof->tcam_count; i++) 274171d10453SEric Joyner if (prof->tcam[i].in_use) { 274271d10453SEric Joyner prof->tcam[i].in_use = false; 274371d10453SEric Joyner status = ice_rel_tcam_idx(hw, blk, 274471d10453SEric Joyner prof->tcam[i].tcam_idx); 274571d10453SEric Joyner if (status) 274671d10453SEric Joyner return ICE_ERR_HW_TABLE; 274771d10453SEric Joyner } 274871d10453SEric Joyner 274971d10453SEric Joyner return ICE_SUCCESS; 275071d10453SEric Joyner } 275171d10453SEric Joyner 275271d10453SEric Joyner /** 275371d10453SEric Joyner * ice_rem_vsig - remove VSIG 275471d10453SEric Joyner * @hw: pointer to the HW struct 275571d10453SEric Joyner * @blk: hardware block 275671d10453SEric Joyner * @vsig: the VSIG to remove 275771d10453SEric Joyner * @chg: the change list 275871d10453SEric Joyner */ 275971d10453SEric Joyner static enum ice_status 276071d10453SEric Joyner ice_rem_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, 276171d10453SEric Joyner struct LIST_HEAD_TYPE *chg) 276271d10453SEric Joyner { 276371d10453SEric Joyner u16 idx = vsig & ICE_VSIG_IDX_M; 276471d10453SEric Joyner struct ice_vsig_vsi *vsi_cur; 276571d10453SEric Joyner struct ice_vsig_prof *d, *t; 276671d10453SEric Joyner 276771d10453SEric Joyner /* remove TCAM entries */ 276871d10453SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(d, t, 276971d10453SEric Joyner &hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst, 277071d10453SEric Joyner ice_vsig_prof, list) { 27718923de59SPiotr Kubaj enum ice_status status; 27728923de59SPiotr Kubaj 277371d10453SEric Joyner status = ice_rem_prof_id(hw, blk, d); 277471d10453SEric Joyner if (status) 277571d10453SEric Joyner return status; 277671d10453SEric Joyner 277771d10453SEric Joyner LIST_DEL(&d->list); 277871d10453SEric Joyner ice_free(hw, d); 277971d10453SEric Joyner } 278071d10453SEric Joyner 278171d10453SEric Joyner /* Move all VSIS associated with this VSIG to the default VSIG */ 278271d10453SEric Joyner vsi_cur = hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi; 278371d10453SEric Joyner /* If the VSIG has at least 1 VSI then iterate through the list 278471d10453SEric Joyner * and remove the VSIs before deleting the group. 278571d10453SEric Joyner */ 27867d7af7f8SEric Joyner if (vsi_cur) 278771d10453SEric Joyner do { 278871d10453SEric Joyner struct ice_vsig_vsi *tmp = vsi_cur->next_vsi; 278971d10453SEric Joyner struct ice_chs_chg *p; 279071d10453SEric Joyner 279171d10453SEric Joyner p = (struct ice_chs_chg *)ice_malloc(hw, sizeof(*p)); 279271d10453SEric Joyner if (!p) 279371d10453SEric Joyner return ICE_ERR_NO_MEMORY; 279471d10453SEric Joyner 279571d10453SEric Joyner p->type = ICE_VSIG_REM; 279671d10453SEric Joyner p->orig_vsig = vsig; 279771d10453SEric Joyner p->vsig = ICE_DEFAULT_VSIG; 27988923de59SPiotr Kubaj p->vsi = (u16)(vsi_cur - hw->blk[blk].xlt2.vsis); 279971d10453SEric Joyner 280071d10453SEric Joyner LIST_ADD(&p->list_entry, chg); 280171d10453SEric Joyner 280271d10453SEric Joyner vsi_cur = tmp; 280371d10453SEric Joyner } while (vsi_cur); 280471d10453SEric Joyner 280571d10453SEric Joyner return ice_vsig_free(hw, blk, vsig); 280671d10453SEric Joyner } 280771d10453SEric Joyner 280871d10453SEric Joyner /** 280971d10453SEric Joyner * ice_rem_prof_id_vsig - remove a specific profile from a VSIG 281071d10453SEric Joyner * @hw: pointer to the HW struct 281171d10453SEric Joyner * @blk: hardware block 281271d10453SEric Joyner * @vsig: VSIG to remove the profile from 281371d10453SEric Joyner * @hdl: profile handle indicating which profile to remove 281471d10453SEric Joyner * @chg: list to receive a record of changes 281571d10453SEric Joyner */ 281671d10453SEric Joyner static enum ice_status 281771d10453SEric Joyner ice_rem_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, u64 hdl, 281871d10453SEric Joyner struct LIST_HEAD_TYPE *chg) 281971d10453SEric Joyner { 282071d10453SEric Joyner u16 idx = vsig & ICE_VSIG_IDX_M; 282171d10453SEric Joyner struct ice_vsig_prof *p, *t; 282271d10453SEric Joyner 282371d10453SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(p, t, 282471d10453SEric Joyner &hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst, 28257d7af7f8SEric Joyner ice_vsig_prof, list) 282671d10453SEric Joyner if (p->profile_cookie == hdl) { 28278923de59SPiotr Kubaj enum ice_status status; 28288923de59SPiotr Kubaj 282971d10453SEric Joyner if (ice_vsig_prof_id_count(hw, blk, vsig) == 1) 283071d10453SEric Joyner /* this is the last profile, remove the VSIG */ 283171d10453SEric Joyner return ice_rem_vsig(hw, blk, vsig, chg); 283271d10453SEric Joyner 283371d10453SEric Joyner status = ice_rem_prof_id(hw, blk, p); 283471d10453SEric Joyner if (!status) { 283571d10453SEric Joyner LIST_DEL(&p->list); 283671d10453SEric Joyner ice_free(hw, p); 283771d10453SEric Joyner } 283871d10453SEric Joyner return status; 283971d10453SEric Joyner } 284071d10453SEric Joyner 284171d10453SEric Joyner return ICE_ERR_DOES_NOT_EXIST; 284271d10453SEric Joyner } 284371d10453SEric Joyner 284471d10453SEric Joyner /** 284571d10453SEric Joyner * ice_rem_flow_all - remove all flows with a particular profile 284671d10453SEric Joyner * @hw: pointer to the HW struct 284771d10453SEric Joyner * @blk: hardware block 284871d10453SEric Joyner * @id: profile tracking ID 284971d10453SEric Joyner */ 285071d10453SEric Joyner static enum ice_status 285171d10453SEric Joyner ice_rem_flow_all(struct ice_hw *hw, enum ice_block blk, u64 id) 285271d10453SEric Joyner { 285371d10453SEric Joyner struct ice_chs_chg *del, *tmp; 285471d10453SEric Joyner enum ice_status status; 28557d7af7f8SEric Joyner struct LIST_HEAD_TYPE chg; 285671d10453SEric Joyner u16 i; 285771d10453SEric Joyner 285871d10453SEric Joyner INIT_LIST_HEAD(&chg); 285971d10453SEric Joyner 28607d7af7f8SEric Joyner for (i = 1; i < ICE_MAX_VSIGS; i++) 286171d10453SEric Joyner if (hw->blk[blk].xlt2.vsig_tbl[i].in_use) { 286271d10453SEric Joyner if (ice_has_prof_vsig(hw, blk, i, id)) { 286371d10453SEric Joyner status = ice_rem_prof_id_vsig(hw, blk, i, id, 286471d10453SEric Joyner &chg); 286571d10453SEric Joyner if (status) 286671d10453SEric Joyner goto err_ice_rem_flow_all; 286771d10453SEric Joyner } 286871d10453SEric Joyner } 286971d10453SEric Joyner 287071d10453SEric Joyner status = ice_upd_prof_hw(hw, blk, &chg); 287171d10453SEric Joyner 287271d10453SEric Joyner err_ice_rem_flow_all: 287371d10453SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(del, tmp, &chg, ice_chs_chg, list_entry) { 287471d10453SEric Joyner LIST_DEL(&del->list_entry); 287571d10453SEric Joyner ice_free(hw, del); 287671d10453SEric Joyner } 287771d10453SEric Joyner 287871d10453SEric Joyner return status; 287971d10453SEric Joyner } 288071d10453SEric Joyner 288171d10453SEric Joyner /** 288271d10453SEric Joyner * ice_rem_prof - remove profile 288371d10453SEric Joyner * @hw: pointer to the HW struct 288471d10453SEric Joyner * @blk: hardware block 288571d10453SEric Joyner * @id: profile tracking ID 288671d10453SEric Joyner * 288771d10453SEric Joyner * This will remove the profile specified by the ID parameter, which was 288871d10453SEric Joyner * previously created through ice_add_prof. If any existing entries 288971d10453SEric Joyner * are associated with this profile, they will be removed as well. 289071d10453SEric Joyner */ 289171d10453SEric Joyner enum ice_status ice_rem_prof(struct ice_hw *hw, enum ice_block blk, u64 id) 289271d10453SEric Joyner { 289371d10453SEric Joyner struct ice_prof_map *pmap; 289471d10453SEric Joyner enum ice_status status; 289571d10453SEric Joyner 289671d10453SEric Joyner ice_acquire_lock(&hw->blk[blk].es.prof_map_lock); 289771d10453SEric Joyner 28987d7af7f8SEric Joyner pmap = ice_search_prof_id(hw, blk, id); 289971d10453SEric Joyner if (!pmap) { 290071d10453SEric Joyner status = ICE_ERR_DOES_NOT_EXIST; 290171d10453SEric Joyner goto err_ice_rem_prof; 290271d10453SEric Joyner } 290371d10453SEric Joyner 290471d10453SEric Joyner /* remove all flows with this profile */ 290571d10453SEric Joyner status = ice_rem_flow_all(hw, blk, pmap->profile_cookie); 290671d10453SEric Joyner if (status) 290771d10453SEric Joyner goto err_ice_rem_prof; 290871d10453SEric Joyner 290971d10453SEric Joyner /* dereference profile, and possibly remove */ 291071d10453SEric Joyner ice_prof_dec_ref(hw, blk, pmap->prof_id); 291171d10453SEric Joyner 291271d10453SEric Joyner LIST_DEL(&pmap->list); 291371d10453SEric Joyner ice_free(hw, pmap); 291471d10453SEric Joyner 291571d10453SEric Joyner err_ice_rem_prof: 291671d10453SEric Joyner ice_release_lock(&hw->blk[blk].es.prof_map_lock); 291771d10453SEric Joyner return status; 291871d10453SEric Joyner } 291971d10453SEric Joyner 292071d10453SEric Joyner /** 292171d10453SEric Joyner * ice_get_prof - get profile 292271d10453SEric Joyner * @hw: pointer to the HW struct 292371d10453SEric Joyner * @blk: hardware block 292471d10453SEric Joyner * @hdl: profile handle 292571d10453SEric Joyner * @chg: change list 292671d10453SEric Joyner */ 292771d10453SEric Joyner static enum ice_status 292871d10453SEric Joyner ice_get_prof(struct ice_hw *hw, enum ice_block blk, u64 hdl, 292971d10453SEric Joyner struct LIST_HEAD_TYPE *chg) 293071d10453SEric Joyner { 29317d7af7f8SEric Joyner enum ice_status status = ICE_SUCCESS; 293271d10453SEric Joyner struct ice_prof_map *map; 293371d10453SEric Joyner struct ice_chs_chg *p; 293471d10453SEric Joyner u16 i; 293571d10453SEric Joyner 29367d7af7f8SEric Joyner ice_acquire_lock(&hw->blk[blk].es.prof_map_lock); 293771d10453SEric Joyner /* Get the details on the profile specified by the handle ID */ 293871d10453SEric Joyner map = ice_search_prof_id(hw, blk, hdl); 29397d7af7f8SEric Joyner if (!map) { 29407d7af7f8SEric Joyner status = ICE_ERR_DOES_NOT_EXIST; 29417d7af7f8SEric Joyner goto err_ice_get_prof; 29427d7af7f8SEric Joyner } 294371d10453SEric Joyner 29447d7af7f8SEric Joyner for (i = 0; i < map->ptg_cnt; i++) 294571d10453SEric Joyner if (!hw->blk[blk].es.written[map->prof_id]) { 294671d10453SEric Joyner /* add ES to change list */ 294771d10453SEric Joyner p = (struct ice_chs_chg *)ice_malloc(hw, sizeof(*p)); 29487d7af7f8SEric Joyner if (!p) { 29497d7af7f8SEric Joyner status = ICE_ERR_NO_MEMORY; 295071d10453SEric Joyner goto err_ice_get_prof; 29517d7af7f8SEric Joyner } 295271d10453SEric Joyner 295371d10453SEric Joyner p->type = ICE_PTG_ES_ADD; 295471d10453SEric Joyner p->ptype = 0; 295571d10453SEric Joyner p->ptg = map->ptg[i]; 295671d10453SEric Joyner p->add_ptg = 0; 295771d10453SEric Joyner 295871d10453SEric Joyner p->add_prof = 1; 295971d10453SEric Joyner p->prof_id = map->prof_id; 296071d10453SEric Joyner 296171d10453SEric Joyner hw->blk[blk].es.written[map->prof_id] = true; 296271d10453SEric Joyner 296371d10453SEric Joyner LIST_ADD(&p->list_entry, chg); 296471d10453SEric Joyner } 296571d10453SEric Joyner 296671d10453SEric Joyner err_ice_get_prof: 29677d7af7f8SEric Joyner ice_release_lock(&hw->blk[blk].es.prof_map_lock); 296871d10453SEric Joyner /* let caller clean up the change list */ 29697d7af7f8SEric Joyner return status; 297071d10453SEric Joyner } 297171d10453SEric Joyner 297271d10453SEric Joyner /** 297371d10453SEric Joyner * ice_get_profs_vsig - get a copy of the list of profiles from a VSIG 297471d10453SEric Joyner * @hw: pointer to the HW struct 297571d10453SEric Joyner * @blk: hardware block 297671d10453SEric Joyner * @vsig: VSIG from which to copy the list 297771d10453SEric Joyner * @lst: output list 297871d10453SEric Joyner * 297971d10453SEric Joyner * This routine makes a copy of the list of profiles in the specified VSIG. 298071d10453SEric Joyner */ 298171d10453SEric Joyner static enum ice_status 298271d10453SEric Joyner ice_get_profs_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, 298371d10453SEric Joyner struct LIST_HEAD_TYPE *lst) 298471d10453SEric Joyner { 298571d10453SEric Joyner struct ice_vsig_prof *ent1, *ent2; 298671d10453SEric Joyner u16 idx = vsig & ICE_VSIG_IDX_M; 298771d10453SEric Joyner 298871d10453SEric Joyner LIST_FOR_EACH_ENTRY(ent1, &hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst, 298971d10453SEric Joyner ice_vsig_prof, list) { 299071d10453SEric Joyner struct ice_vsig_prof *p; 299171d10453SEric Joyner 299271d10453SEric Joyner /* copy to the input list */ 299371d10453SEric Joyner p = (struct ice_vsig_prof *)ice_memdup(hw, ent1, sizeof(*p), 299471d10453SEric Joyner ICE_NONDMA_TO_NONDMA); 299571d10453SEric Joyner if (!p) 299671d10453SEric Joyner goto err_ice_get_profs_vsig; 299771d10453SEric Joyner 299871d10453SEric Joyner LIST_ADD_TAIL(&p->list, lst); 299971d10453SEric Joyner } 300071d10453SEric Joyner 300171d10453SEric Joyner return ICE_SUCCESS; 300271d10453SEric Joyner 300371d10453SEric Joyner err_ice_get_profs_vsig: 300471d10453SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(ent1, ent2, lst, ice_vsig_prof, list) { 300571d10453SEric Joyner LIST_DEL(&ent1->list); 300671d10453SEric Joyner ice_free(hw, ent1); 300771d10453SEric Joyner } 300871d10453SEric Joyner 300971d10453SEric Joyner return ICE_ERR_NO_MEMORY; 301071d10453SEric Joyner } 301171d10453SEric Joyner 301271d10453SEric Joyner /** 301371d10453SEric Joyner * ice_add_prof_to_lst - add profile entry to a list 301471d10453SEric Joyner * @hw: pointer to the HW struct 301571d10453SEric Joyner * @blk: hardware block 301671d10453SEric Joyner * @lst: the list to be added to 301771d10453SEric Joyner * @hdl: profile handle of entry to add 301871d10453SEric Joyner */ 301971d10453SEric Joyner static enum ice_status 302071d10453SEric Joyner ice_add_prof_to_lst(struct ice_hw *hw, enum ice_block blk, 302171d10453SEric Joyner struct LIST_HEAD_TYPE *lst, u64 hdl) 302271d10453SEric Joyner { 30237d7af7f8SEric Joyner enum ice_status status = ICE_SUCCESS; 302471d10453SEric Joyner struct ice_prof_map *map; 302571d10453SEric Joyner struct ice_vsig_prof *p; 302671d10453SEric Joyner u16 i; 302771d10453SEric Joyner 30287d7af7f8SEric Joyner ice_acquire_lock(&hw->blk[blk].es.prof_map_lock); 302971d10453SEric Joyner map = ice_search_prof_id(hw, blk, hdl); 30307d7af7f8SEric Joyner if (!map) { 30317d7af7f8SEric Joyner status = ICE_ERR_DOES_NOT_EXIST; 30327d7af7f8SEric Joyner goto err_ice_add_prof_to_lst; 30337d7af7f8SEric Joyner } 303471d10453SEric Joyner 303571d10453SEric Joyner p = (struct ice_vsig_prof *)ice_malloc(hw, sizeof(*p)); 30367d7af7f8SEric Joyner if (!p) { 30377d7af7f8SEric Joyner status = ICE_ERR_NO_MEMORY; 30387d7af7f8SEric Joyner goto err_ice_add_prof_to_lst; 30397d7af7f8SEric Joyner } 304071d10453SEric Joyner 304171d10453SEric Joyner p->profile_cookie = map->profile_cookie; 304271d10453SEric Joyner p->prof_id = map->prof_id; 304371d10453SEric Joyner p->tcam_count = map->ptg_cnt; 304471d10453SEric Joyner 304571d10453SEric Joyner for (i = 0; i < map->ptg_cnt; i++) { 304671d10453SEric Joyner p->tcam[i].prof_id = map->prof_id; 304771d10453SEric Joyner p->tcam[i].tcam_idx = ICE_INVALID_TCAM; 304871d10453SEric Joyner p->tcam[i].ptg = map->ptg[i]; 304971d10453SEric Joyner } 305071d10453SEric Joyner 305171d10453SEric Joyner LIST_ADD(&p->list, lst); 305271d10453SEric Joyner 30537d7af7f8SEric Joyner err_ice_add_prof_to_lst: 30547d7af7f8SEric Joyner ice_release_lock(&hw->blk[blk].es.prof_map_lock); 30557d7af7f8SEric Joyner return status; 305671d10453SEric Joyner } 305771d10453SEric Joyner 305871d10453SEric Joyner /** 305971d10453SEric Joyner * ice_move_vsi - move VSI to another VSIG 306071d10453SEric Joyner * @hw: pointer to the HW struct 306171d10453SEric Joyner * @blk: hardware block 306271d10453SEric Joyner * @vsi: the VSI to move 306371d10453SEric Joyner * @vsig: the VSIG to move the VSI to 306471d10453SEric Joyner * @chg: the change list 306571d10453SEric Joyner */ 306671d10453SEric Joyner static enum ice_status 306771d10453SEric Joyner ice_move_vsi(struct ice_hw *hw, enum ice_block blk, u16 vsi, u16 vsig, 306871d10453SEric Joyner struct LIST_HEAD_TYPE *chg) 306971d10453SEric Joyner { 307071d10453SEric Joyner enum ice_status status; 307171d10453SEric Joyner struct ice_chs_chg *p; 307271d10453SEric Joyner u16 orig_vsig; 307371d10453SEric Joyner 307471d10453SEric Joyner p = (struct ice_chs_chg *)ice_malloc(hw, sizeof(*p)); 307571d10453SEric Joyner if (!p) 307671d10453SEric Joyner return ICE_ERR_NO_MEMORY; 307771d10453SEric Joyner 307871d10453SEric Joyner status = ice_vsig_find_vsi(hw, blk, vsi, &orig_vsig); 307971d10453SEric Joyner if (!status) 308071d10453SEric Joyner status = ice_vsig_add_mv_vsi(hw, blk, vsi, vsig); 308171d10453SEric Joyner 308271d10453SEric Joyner if (status) { 308371d10453SEric Joyner ice_free(hw, p); 308471d10453SEric Joyner return status; 308571d10453SEric Joyner } 308671d10453SEric Joyner 308771d10453SEric Joyner p->type = ICE_VSI_MOVE; 308871d10453SEric Joyner p->vsi = vsi; 308971d10453SEric Joyner p->orig_vsig = orig_vsig; 309071d10453SEric Joyner p->vsig = vsig; 309171d10453SEric Joyner 309271d10453SEric Joyner LIST_ADD(&p->list_entry, chg); 309371d10453SEric Joyner 309471d10453SEric Joyner return ICE_SUCCESS; 309571d10453SEric Joyner } 309671d10453SEric Joyner 309771d10453SEric Joyner /** 309871d10453SEric Joyner * ice_rem_chg_tcam_ent - remove a specific TCAM entry from change list 309971d10453SEric Joyner * @hw: pointer to the HW struct 310071d10453SEric Joyner * @idx: the index of the TCAM entry to remove 310171d10453SEric Joyner * @chg: the list of change structures to search 310271d10453SEric Joyner */ 310371d10453SEric Joyner static void 310471d10453SEric Joyner ice_rem_chg_tcam_ent(struct ice_hw *hw, u16 idx, struct LIST_HEAD_TYPE *chg) 310571d10453SEric Joyner { 310671d10453SEric Joyner struct ice_chs_chg *pos, *tmp; 310771d10453SEric Joyner 31087d7af7f8SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(tmp, pos, chg, ice_chs_chg, list_entry) 310971d10453SEric Joyner if (tmp->type == ICE_TCAM_ADD && tmp->tcam_idx == idx) { 311071d10453SEric Joyner LIST_DEL(&tmp->list_entry); 311171d10453SEric Joyner ice_free(hw, tmp); 311271d10453SEric Joyner } 311371d10453SEric Joyner } 311471d10453SEric Joyner 311571d10453SEric Joyner /** 311671d10453SEric Joyner * ice_prof_tcam_ena_dis - add enable or disable TCAM change 311771d10453SEric Joyner * @hw: pointer to the HW struct 311871d10453SEric Joyner * @blk: hardware block 311971d10453SEric Joyner * @enable: true to enable, false to disable 312071d10453SEric Joyner * @vsig: the VSIG of the TCAM entry 312171d10453SEric Joyner * @tcam: pointer the TCAM info structure of the TCAM to disable 312271d10453SEric Joyner * @chg: the change list 312371d10453SEric Joyner * 312471d10453SEric Joyner * This function appends an enable or disable TCAM entry in the change log 312571d10453SEric Joyner */ 312671d10453SEric Joyner static enum ice_status 312771d10453SEric Joyner ice_prof_tcam_ena_dis(struct ice_hw *hw, enum ice_block blk, bool enable, 312871d10453SEric Joyner u16 vsig, struct ice_tcam_inf *tcam, 312971d10453SEric Joyner struct LIST_HEAD_TYPE *chg) 313071d10453SEric Joyner { 313171d10453SEric Joyner enum ice_status status; 313271d10453SEric Joyner struct ice_chs_chg *p; 313371d10453SEric Joyner 313471d10453SEric Joyner u8 vl_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 313571d10453SEric Joyner u8 dc_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFF, 0xFF, 0x00, 0x00, 0x00 }; 313671d10453SEric Joyner u8 nm_msk[ICE_TCAM_KEY_VAL_SZ] = { 0x00, 0x00, 0x00, 0x00, 0x00 }; 313771d10453SEric Joyner 313871d10453SEric Joyner /* if disabling, free the TCAM */ 313971d10453SEric Joyner if (!enable) { 314071d10453SEric Joyner status = ice_rel_tcam_idx(hw, blk, tcam->tcam_idx); 314171d10453SEric Joyner 314271d10453SEric Joyner /* if we have already created a change for this TCAM entry, then 314371d10453SEric Joyner * we need to remove that entry, in order to prevent writing to 314471d10453SEric Joyner * a TCAM entry we no longer will have ownership of. 314571d10453SEric Joyner */ 314671d10453SEric Joyner ice_rem_chg_tcam_ent(hw, tcam->tcam_idx, chg); 314771d10453SEric Joyner tcam->tcam_idx = 0; 314871d10453SEric Joyner tcam->in_use = 0; 314971d10453SEric Joyner return status; 315071d10453SEric Joyner } 315171d10453SEric Joyner 315271d10453SEric Joyner /* for re-enabling, reallocate a TCAM */ 31537d7af7f8SEric Joyner status = ice_alloc_tcam_ent(hw, blk, true, &tcam->tcam_idx); 315471d10453SEric Joyner if (status) 315571d10453SEric Joyner return status; 315671d10453SEric Joyner 315771d10453SEric Joyner /* add TCAM to change list */ 315871d10453SEric Joyner p = (struct ice_chs_chg *)ice_malloc(hw, sizeof(*p)); 315971d10453SEric Joyner if (!p) 316071d10453SEric Joyner return ICE_ERR_NO_MEMORY; 316171d10453SEric Joyner 316271d10453SEric Joyner status = ice_tcam_write_entry(hw, blk, tcam->tcam_idx, tcam->prof_id, 316371d10453SEric Joyner tcam->ptg, vsig, 0, 0, vl_msk, dc_msk, 316471d10453SEric Joyner nm_msk); 316571d10453SEric Joyner if (status) 316671d10453SEric Joyner goto err_ice_prof_tcam_ena_dis; 316771d10453SEric Joyner 316871d10453SEric Joyner tcam->in_use = 1; 316971d10453SEric Joyner 317071d10453SEric Joyner p->type = ICE_TCAM_ADD; 317171d10453SEric Joyner p->add_tcam_idx = true; 317271d10453SEric Joyner p->prof_id = tcam->prof_id; 317371d10453SEric Joyner p->ptg = tcam->ptg; 317471d10453SEric Joyner p->vsig = 0; 317571d10453SEric Joyner p->tcam_idx = tcam->tcam_idx; 317671d10453SEric Joyner 317771d10453SEric Joyner /* log change */ 317871d10453SEric Joyner LIST_ADD(&p->list_entry, chg); 317971d10453SEric Joyner 318071d10453SEric Joyner return ICE_SUCCESS; 318171d10453SEric Joyner 318271d10453SEric Joyner err_ice_prof_tcam_ena_dis: 318371d10453SEric Joyner ice_free(hw, p); 318471d10453SEric Joyner return status; 318571d10453SEric Joyner } 318671d10453SEric Joyner 318771d10453SEric Joyner /** 318871d10453SEric Joyner * ice_adj_prof_priorities - adjust profile based on priorities 318971d10453SEric Joyner * @hw: pointer to the HW struct 319071d10453SEric Joyner * @blk: hardware block 319171d10453SEric Joyner * @vsig: the VSIG for which to adjust profile priorities 319271d10453SEric Joyner * @chg: the change list 319371d10453SEric Joyner */ 319471d10453SEric Joyner static enum ice_status 319571d10453SEric Joyner ice_adj_prof_priorities(struct ice_hw *hw, enum ice_block blk, u16 vsig, 319671d10453SEric Joyner struct LIST_HEAD_TYPE *chg) 319771d10453SEric Joyner { 319871d10453SEric Joyner ice_declare_bitmap(ptgs_used, ICE_XLT1_CNT); 319971d10453SEric Joyner enum ice_status status = ICE_SUCCESS; 320071d10453SEric Joyner struct ice_vsig_prof *t; 320171d10453SEric Joyner u16 idx; 320271d10453SEric Joyner 320371d10453SEric Joyner ice_zero_bitmap(ptgs_used, ICE_XLT1_CNT); 320471d10453SEric Joyner idx = vsig & ICE_VSIG_IDX_M; 320571d10453SEric Joyner 320671d10453SEric Joyner /* Priority is based on the order in which the profiles are added. The 320771d10453SEric Joyner * newest added profile has highest priority and the oldest added 320871d10453SEric Joyner * profile has the lowest priority. Since the profile property list for 320971d10453SEric Joyner * a VSIG is sorted from newest to oldest, this code traverses the list 321071d10453SEric Joyner * in order and enables the first of each PTG that it finds (that is not 321171d10453SEric Joyner * already enabled); it also disables any duplicate PTGs that it finds 321271d10453SEric Joyner * in the older profiles (that are currently enabled). 321371d10453SEric Joyner */ 321471d10453SEric Joyner 321571d10453SEric Joyner LIST_FOR_EACH_ENTRY(t, &hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst, 321671d10453SEric Joyner ice_vsig_prof, list) { 321771d10453SEric Joyner u16 i; 321871d10453SEric Joyner 321971d10453SEric Joyner for (i = 0; i < t->tcam_count; i++) { 322071d10453SEric Joyner bool used; 322171d10453SEric Joyner 322271d10453SEric Joyner /* Scan the priorities from newest to oldest. 322371d10453SEric Joyner * Make sure that the newest profiles take priority. 322471d10453SEric Joyner */ 322571d10453SEric Joyner used = ice_is_bit_set(ptgs_used, t->tcam[i].ptg); 322671d10453SEric Joyner 322771d10453SEric Joyner if (used && t->tcam[i].in_use) { 322871d10453SEric Joyner /* need to mark this PTG as never match, as it 322971d10453SEric Joyner * was already in use and therefore duplicate 323071d10453SEric Joyner * (and lower priority) 323171d10453SEric Joyner */ 323271d10453SEric Joyner status = ice_prof_tcam_ena_dis(hw, blk, false, 323371d10453SEric Joyner vsig, 323471d10453SEric Joyner &t->tcam[i], 323571d10453SEric Joyner chg); 323671d10453SEric Joyner if (status) 323771d10453SEric Joyner return status; 323871d10453SEric Joyner } else if (!used && !t->tcam[i].in_use) { 323971d10453SEric Joyner /* need to enable this PTG, as it in not in use 324071d10453SEric Joyner * and not enabled (highest priority) 324171d10453SEric Joyner */ 324271d10453SEric Joyner status = ice_prof_tcam_ena_dis(hw, blk, true, 324371d10453SEric Joyner vsig, 324471d10453SEric Joyner &t->tcam[i], 324571d10453SEric Joyner chg); 324671d10453SEric Joyner if (status) 324771d10453SEric Joyner return status; 324871d10453SEric Joyner } 324971d10453SEric Joyner 325071d10453SEric Joyner /* keep track of used ptgs */ 325171d10453SEric Joyner ice_set_bit(t->tcam[i].ptg, ptgs_used); 325271d10453SEric Joyner } 325371d10453SEric Joyner } 325471d10453SEric Joyner 325571d10453SEric Joyner return status; 325671d10453SEric Joyner } 325771d10453SEric Joyner 325871d10453SEric Joyner /** 325971d10453SEric Joyner * ice_add_prof_id_vsig - add profile to VSIG 326071d10453SEric Joyner * @hw: pointer to the HW struct 326171d10453SEric Joyner * @blk: hardware block 326271d10453SEric Joyner * @vsig: the VSIG to which this profile is to be added 326371d10453SEric Joyner * @hdl: the profile handle indicating the profile to add 326471d10453SEric Joyner * @rev: true to add entries to the end of the list 326571d10453SEric Joyner * @chg: the change list 326671d10453SEric Joyner */ 326771d10453SEric Joyner static enum ice_status 326871d10453SEric Joyner ice_add_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, u64 hdl, 326971d10453SEric Joyner bool rev, struct LIST_HEAD_TYPE *chg) 327071d10453SEric Joyner { 327171d10453SEric Joyner /* Masks that ignore flags */ 327271d10453SEric Joyner u8 vl_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 327371d10453SEric Joyner u8 dc_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFF, 0xFF, 0x00, 0x00, 0x00 }; 327471d10453SEric Joyner u8 nm_msk[ICE_TCAM_KEY_VAL_SZ] = { 0x00, 0x00, 0x00, 0x00, 0x00 }; 32757d7af7f8SEric Joyner enum ice_status status = ICE_SUCCESS; 327671d10453SEric Joyner struct ice_prof_map *map; 327771d10453SEric Joyner struct ice_vsig_prof *t; 327871d10453SEric Joyner struct ice_chs_chg *p; 327971d10453SEric Joyner u16 vsig_idx, i; 328071d10453SEric Joyner 328171d10453SEric Joyner /* Error, if this VSIG already has this profile */ 328271d10453SEric Joyner if (ice_has_prof_vsig(hw, blk, vsig, hdl)) 328371d10453SEric Joyner return ICE_ERR_ALREADY_EXISTS; 328471d10453SEric Joyner 328571d10453SEric Joyner /* new VSIG profile structure */ 328671d10453SEric Joyner t = (struct ice_vsig_prof *)ice_malloc(hw, sizeof(*t)); 328771d10453SEric Joyner if (!t) 328871d10453SEric Joyner return ICE_ERR_NO_MEMORY; 328971d10453SEric Joyner 32907d7af7f8SEric Joyner ice_acquire_lock(&hw->blk[blk].es.prof_map_lock); 32917d7af7f8SEric Joyner /* Get the details on the profile specified by the handle ID */ 32927d7af7f8SEric Joyner map = ice_search_prof_id(hw, blk, hdl); 32937d7af7f8SEric Joyner if (!map) { 32947d7af7f8SEric Joyner status = ICE_ERR_DOES_NOT_EXIST; 32957d7af7f8SEric Joyner goto err_ice_add_prof_id_vsig; 32967d7af7f8SEric Joyner } 32977d7af7f8SEric Joyner 329871d10453SEric Joyner t->profile_cookie = map->profile_cookie; 329971d10453SEric Joyner t->prof_id = map->prof_id; 330071d10453SEric Joyner t->tcam_count = map->ptg_cnt; 330171d10453SEric Joyner 330271d10453SEric Joyner /* create TCAM entries */ 330371d10453SEric Joyner for (i = 0; i < map->ptg_cnt; i++) { 330471d10453SEric Joyner u16 tcam_idx; 330571d10453SEric Joyner 330671d10453SEric Joyner /* add TCAM to change list */ 330771d10453SEric Joyner p = (struct ice_chs_chg *)ice_malloc(hw, sizeof(*p)); 33087d7af7f8SEric Joyner if (!p) { 33097d7af7f8SEric Joyner status = ICE_ERR_NO_MEMORY; 331071d10453SEric Joyner goto err_ice_add_prof_id_vsig; 33117d7af7f8SEric Joyner } 331271d10453SEric Joyner 331371d10453SEric Joyner /* allocate the TCAM entry index */ 33147d7af7f8SEric Joyner status = ice_alloc_tcam_ent(hw, blk, true, &tcam_idx); 331571d10453SEric Joyner if (status) { 331671d10453SEric Joyner ice_free(hw, p); 331771d10453SEric Joyner goto err_ice_add_prof_id_vsig; 331871d10453SEric Joyner } 331971d10453SEric Joyner 332071d10453SEric Joyner t->tcam[i].ptg = map->ptg[i]; 332171d10453SEric Joyner t->tcam[i].prof_id = map->prof_id; 332271d10453SEric Joyner t->tcam[i].tcam_idx = tcam_idx; 332371d10453SEric Joyner t->tcam[i].in_use = true; 332471d10453SEric Joyner 332571d10453SEric Joyner p->type = ICE_TCAM_ADD; 332671d10453SEric Joyner p->add_tcam_idx = true; 332771d10453SEric Joyner p->prof_id = t->tcam[i].prof_id; 332871d10453SEric Joyner p->ptg = t->tcam[i].ptg; 332971d10453SEric Joyner p->vsig = vsig; 333071d10453SEric Joyner p->tcam_idx = t->tcam[i].tcam_idx; 333171d10453SEric Joyner 333271d10453SEric Joyner /* write the TCAM entry */ 333371d10453SEric Joyner status = ice_tcam_write_entry(hw, blk, t->tcam[i].tcam_idx, 333471d10453SEric Joyner t->tcam[i].prof_id, 333571d10453SEric Joyner t->tcam[i].ptg, vsig, 0, 0, 333671d10453SEric Joyner vl_msk, dc_msk, nm_msk); 333771d10453SEric Joyner if (status) { 333871d10453SEric Joyner ice_free(hw, p); 333971d10453SEric Joyner goto err_ice_add_prof_id_vsig; 334071d10453SEric Joyner } 334171d10453SEric Joyner 334271d10453SEric Joyner /* log change */ 334371d10453SEric Joyner LIST_ADD(&p->list_entry, chg); 334471d10453SEric Joyner } 334571d10453SEric Joyner 334671d10453SEric Joyner /* add profile to VSIG */ 334771d10453SEric Joyner vsig_idx = vsig & ICE_VSIG_IDX_M; 334871d10453SEric Joyner if (rev) 334971d10453SEric Joyner LIST_ADD_TAIL(&t->list, 335071d10453SEric Joyner &hw->blk[blk].xlt2.vsig_tbl[vsig_idx].prop_lst); 335171d10453SEric Joyner else 335271d10453SEric Joyner LIST_ADD(&t->list, 335371d10453SEric Joyner &hw->blk[blk].xlt2.vsig_tbl[vsig_idx].prop_lst); 335471d10453SEric Joyner 33557d7af7f8SEric Joyner ice_release_lock(&hw->blk[blk].es.prof_map_lock); 33567d7af7f8SEric Joyner return status; 335771d10453SEric Joyner 335871d10453SEric Joyner err_ice_add_prof_id_vsig: 33597d7af7f8SEric Joyner ice_release_lock(&hw->blk[blk].es.prof_map_lock); 336071d10453SEric Joyner /* let caller clean up the change list */ 336171d10453SEric Joyner ice_free(hw, t); 33627d7af7f8SEric Joyner return status; 336371d10453SEric Joyner } 336471d10453SEric Joyner 336571d10453SEric Joyner /** 336671d10453SEric Joyner * ice_create_prof_id_vsig - add a new VSIG with a single profile 336771d10453SEric Joyner * @hw: pointer to the HW struct 336871d10453SEric Joyner * @blk: hardware block 336971d10453SEric Joyner * @vsi: the initial VSI that will be in VSIG 337071d10453SEric Joyner * @hdl: the profile handle of the profile that will be added to the VSIG 337171d10453SEric Joyner * @chg: the change list 337271d10453SEric Joyner */ 337371d10453SEric Joyner static enum ice_status 337471d10453SEric Joyner ice_create_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl, 337571d10453SEric Joyner struct LIST_HEAD_TYPE *chg) 337671d10453SEric Joyner { 337771d10453SEric Joyner enum ice_status status; 337871d10453SEric Joyner struct ice_chs_chg *p; 337971d10453SEric Joyner u16 new_vsig; 338071d10453SEric Joyner 338171d10453SEric Joyner p = (struct ice_chs_chg *)ice_malloc(hw, sizeof(*p)); 338271d10453SEric Joyner if (!p) 338371d10453SEric Joyner return ICE_ERR_NO_MEMORY; 338471d10453SEric Joyner 338571d10453SEric Joyner new_vsig = ice_vsig_alloc(hw, blk); 338671d10453SEric Joyner if (!new_vsig) { 338771d10453SEric Joyner status = ICE_ERR_HW_TABLE; 338871d10453SEric Joyner goto err_ice_create_prof_id_vsig; 338971d10453SEric Joyner } 339071d10453SEric Joyner 339171d10453SEric Joyner status = ice_move_vsi(hw, blk, vsi, new_vsig, chg); 339271d10453SEric Joyner if (status) 339371d10453SEric Joyner goto err_ice_create_prof_id_vsig; 339471d10453SEric Joyner 339571d10453SEric Joyner status = ice_add_prof_id_vsig(hw, blk, new_vsig, hdl, false, chg); 339671d10453SEric Joyner if (status) 339771d10453SEric Joyner goto err_ice_create_prof_id_vsig; 339871d10453SEric Joyner 339971d10453SEric Joyner p->type = ICE_VSIG_ADD; 340071d10453SEric Joyner p->vsi = vsi; 340171d10453SEric Joyner p->orig_vsig = ICE_DEFAULT_VSIG; 340271d10453SEric Joyner p->vsig = new_vsig; 340371d10453SEric Joyner 340471d10453SEric Joyner LIST_ADD(&p->list_entry, chg); 340571d10453SEric Joyner 340671d10453SEric Joyner return ICE_SUCCESS; 340771d10453SEric Joyner 340871d10453SEric Joyner err_ice_create_prof_id_vsig: 340971d10453SEric Joyner /* let caller clean up the change list */ 341071d10453SEric Joyner ice_free(hw, p); 341171d10453SEric Joyner return status; 341271d10453SEric Joyner } 341371d10453SEric Joyner 341471d10453SEric Joyner /** 341571d10453SEric Joyner * ice_create_vsig_from_lst - create a new VSIG with a list of profiles 341671d10453SEric Joyner * @hw: pointer to the HW struct 341771d10453SEric Joyner * @blk: hardware block 341871d10453SEric Joyner * @vsi: the initial VSI that will be in VSIG 341971d10453SEric Joyner * @lst: the list of profile that will be added to the VSIG 342071d10453SEric Joyner * @new_vsig: return of new VSIG 342171d10453SEric Joyner * @chg: the change list 342271d10453SEric Joyner */ 342371d10453SEric Joyner static enum ice_status 342471d10453SEric Joyner ice_create_vsig_from_lst(struct ice_hw *hw, enum ice_block blk, u16 vsi, 342571d10453SEric Joyner struct LIST_HEAD_TYPE *lst, u16 *new_vsig, 342671d10453SEric Joyner struct LIST_HEAD_TYPE *chg) 342771d10453SEric Joyner { 342871d10453SEric Joyner struct ice_vsig_prof *t; 342971d10453SEric Joyner enum ice_status status; 343071d10453SEric Joyner u16 vsig; 343171d10453SEric Joyner 343271d10453SEric Joyner vsig = ice_vsig_alloc(hw, blk); 343371d10453SEric Joyner if (!vsig) 343471d10453SEric Joyner return ICE_ERR_HW_TABLE; 343571d10453SEric Joyner 343671d10453SEric Joyner status = ice_move_vsi(hw, blk, vsi, vsig, chg); 343771d10453SEric Joyner if (status) 343871d10453SEric Joyner return status; 343971d10453SEric Joyner 344071d10453SEric Joyner LIST_FOR_EACH_ENTRY(t, lst, ice_vsig_prof, list) { 344171d10453SEric Joyner /* Reverse the order here since we are copying the list */ 344271d10453SEric Joyner status = ice_add_prof_id_vsig(hw, blk, vsig, t->profile_cookie, 344371d10453SEric Joyner true, chg); 344471d10453SEric Joyner if (status) 344571d10453SEric Joyner return status; 344671d10453SEric Joyner } 344771d10453SEric Joyner 344871d10453SEric Joyner *new_vsig = vsig; 344971d10453SEric Joyner 345071d10453SEric Joyner return ICE_SUCCESS; 345171d10453SEric Joyner } 345271d10453SEric Joyner 345371d10453SEric Joyner /** 345471d10453SEric Joyner * ice_find_prof_vsig - find a VSIG with a specific profile handle 345571d10453SEric Joyner * @hw: pointer to the HW struct 345671d10453SEric Joyner * @blk: hardware block 345771d10453SEric Joyner * @hdl: the profile handle of the profile to search for 345871d10453SEric Joyner * @vsig: returns the VSIG with the matching profile 345971d10453SEric Joyner */ 346071d10453SEric Joyner static bool 346171d10453SEric Joyner ice_find_prof_vsig(struct ice_hw *hw, enum ice_block blk, u64 hdl, u16 *vsig) 346271d10453SEric Joyner { 346371d10453SEric Joyner struct ice_vsig_prof *t; 346471d10453SEric Joyner enum ice_status status; 34657d7af7f8SEric Joyner struct LIST_HEAD_TYPE lst; 346671d10453SEric Joyner 346771d10453SEric Joyner INIT_LIST_HEAD(&lst); 346871d10453SEric Joyner 346971d10453SEric Joyner t = (struct ice_vsig_prof *)ice_malloc(hw, sizeof(*t)); 347071d10453SEric Joyner if (!t) 347171d10453SEric Joyner return false; 347271d10453SEric Joyner 347371d10453SEric Joyner t->profile_cookie = hdl; 347471d10453SEric Joyner LIST_ADD(&t->list, &lst); 347571d10453SEric Joyner 347671d10453SEric Joyner status = ice_find_dup_props_vsig(hw, blk, &lst, vsig); 347771d10453SEric Joyner 347871d10453SEric Joyner LIST_DEL(&t->list); 347971d10453SEric Joyner ice_free(hw, t); 348071d10453SEric Joyner 348171d10453SEric Joyner return status == ICE_SUCCESS; 348271d10453SEric Joyner } 348371d10453SEric Joyner 348471d10453SEric Joyner /** 348571d10453SEric Joyner * ice_add_vsi_flow - add VSI flow 348671d10453SEric Joyner * @hw: pointer to the HW struct 348771d10453SEric Joyner * @blk: hardware block 348871d10453SEric Joyner * @vsi: input VSI 348971d10453SEric Joyner * @vsig: target VSIG to include the input VSI 349071d10453SEric Joyner * 349171d10453SEric Joyner * Calling this function will add the VSI to a given VSIG and 349271d10453SEric Joyner * update the HW tables accordingly. This call can be used to 349371d10453SEric Joyner * add multiple VSIs to a VSIG if we know beforehand that those 349471d10453SEric Joyner * VSIs have the same characteristics of the VSIG. This will 349571d10453SEric Joyner * save time in generating a new VSIG and TCAMs till a match is 349671d10453SEric Joyner * found and subsequent rollback when a matching VSIG is found. 349771d10453SEric Joyner */ 349871d10453SEric Joyner enum ice_status 349971d10453SEric Joyner ice_add_vsi_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u16 vsig) 350071d10453SEric Joyner { 350171d10453SEric Joyner struct ice_chs_chg *tmp, *del; 350271d10453SEric Joyner struct LIST_HEAD_TYPE chg; 350371d10453SEric Joyner enum ice_status status; 350471d10453SEric Joyner 350571d10453SEric Joyner /* if target VSIG is default the move is invalid */ 350671d10453SEric Joyner if ((vsig & ICE_VSIG_IDX_M) == ICE_DEFAULT_VSIG) 350771d10453SEric Joyner return ICE_ERR_PARAM; 350871d10453SEric Joyner 350971d10453SEric Joyner INIT_LIST_HEAD(&chg); 351071d10453SEric Joyner 351171d10453SEric Joyner /* move VSI to the VSIG that matches */ 351271d10453SEric Joyner status = ice_move_vsi(hw, blk, vsi, vsig, &chg); 351371d10453SEric Joyner /* update hardware if success */ 351471d10453SEric Joyner if (!status) 351571d10453SEric Joyner status = ice_upd_prof_hw(hw, blk, &chg); 351671d10453SEric Joyner 351771d10453SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(del, tmp, &chg, ice_chs_chg, list_entry) { 351871d10453SEric Joyner LIST_DEL(&del->list_entry); 351971d10453SEric Joyner ice_free(hw, del); 352071d10453SEric Joyner } 352171d10453SEric Joyner 352271d10453SEric Joyner return status; 352371d10453SEric Joyner } 352471d10453SEric Joyner 352571d10453SEric Joyner /** 352671d10453SEric Joyner * ice_add_prof_id_flow - add profile flow 352771d10453SEric Joyner * @hw: pointer to the HW struct 352871d10453SEric Joyner * @blk: hardware block 352971d10453SEric Joyner * @vsi: the VSI to enable with the profile specified by ID 353071d10453SEric Joyner * @hdl: profile handle 353171d10453SEric Joyner * 353271d10453SEric Joyner * Calling this function will update the hardware tables to enable the 353371d10453SEric Joyner * profile indicated by the ID parameter for the VSIs specified in the VSI 353471d10453SEric Joyner * array. Once successfully called, the flow will be enabled. 353571d10453SEric Joyner */ 353671d10453SEric Joyner enum ice_status 353771d10453SEric Joyner ice_add_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl) 353871d10453SEric Joyner { 353971d10453SEric Joyner struct ice_vsig_prof *tmp1, *del1; 354071d10453SEric Joyner struct ice_chs_chg *tmp, *del; 35417d7af7f8SEric Joyner struct LIST_HEAD_TYPE union_lst; 354271d10453SEric Joyner enum ice_status status; 35437d7af7f8SEric Joyner struct LIST_HEAD_TYPE chg; 354471d10453SEric Joyner u16 vsig; 354571d10453SEric Joyner 354671d10453SEric Joyner INIT_LIST_HEAD(&union_lst); 354771d10453SEric Joyner INIT_LIST_HEAD(&chg); 354871d10453SEric Joyner 354971d10453SEric Joyner /* Get profile */ 355071d10453SEric Joyner status = ice_get_prof(hw, blk, hdl, &chg); 355171d10453SEric Joyner if (status) 355271d10453SEric Joyner return status; 355371d10453SEric Joyner 355471d10453SEric Joyner /* determine if VSI is already part of a VSIG */ 355571d10453SEric Joyner status = ice_vsig_find_vsi(hw, blk, vsi, &vsig); 355671d10453SEric Joyner if (!status && vsig) { 355771d10453SEric Joyner bool only_vsi; 355871d10453SEric Joyner u16 or_vsig; 355971d10453SEric Joyner u16 ref; 356071d10453SEric Joyner 356171d10453SEric Joyner /* found in VSIG */ 356271d10453SEric Joyner or_vsig = vsig; 356371d10453SEric Joyner 356471d10453SEric Joyner /* make sure that there is no overlap/conflict between the new 356571d10453SEric Joyner * characteristics and the existing ones; we don't support that 356671d10453SEric Joyner * scenario 356771d10453SEric Joyner */ 356871d10453SEric Joyner if (ice_has_prof_vsig(hw, blk, vsig, hdl)) { 356971d10453SEric Joyner status = ICE_ERR_ALREADY_EXISTS; 357071d10453SEric Joyner goto err_ice_add_prof_id_flow; 357171d10453SEric Joyner } 357271d10453SEric Joyner 357371d10453SEric Joyner /* last VSI in the VSIG? */ 357471d10453SEric Joyner status = ice_vsig_get_ref(hw, blk, vsig, &ref); 357571d10453SEric Joyner if (status) 357671d10453SEric Joyner goto err_ice_add_prof_id_flow; 357771d10453SEric Joyner only_vsi = (ref == 1); 357871d10453SEric Joyner 357971d10453SEric Joyner /* create a union of the current profiles and the one being 358071d10453SEric Joyner * added 358171d10453SEric Joyner */ 358271d10453SEric Joyner status = ice_get_profs_vsig(hw, blk, vsig, &union_lst); 358371d10453SEric Joyner if (status) 358471d10453SEric Joyner goto err_ice_add_prof_id_flow; 358571d10453SEric Joyner 358671d10453SEric Joyner status = ice_add_prof_to_lst(hw, blk, &union_lst, hdl); 358771d10453SEric Joyner if (status) 358871d10453SEric Joyner goto err_ice_add_prof_id_flow; 358971d10453SEric Joyner 359071d10453SEric Joyner /* search for an existing VSIG with an exact charc match */ 359171d10453SEric Joyner status = ice_find_dup_props_vsig(hw, blk, &union_lst, &vsig); 359271d10453SEric Joyner if (!status) { 359371d10453SEric Joyner /* move VSI to the VSIG that matches */ 359471d10453SEric Joyner status = ice_move_vsi(hw, blk, vsi, vsig, &chg); 359571d10453SEric Joyner if (status) 359671d10453SEric Joyner goto err_ice_add_prof_id_flow; 359771d10453SEric Joyner 359871d10453SEric Joyner /* VSI has been moved out of or_vsig. If the or_vsig had 359971d10453SEric Joyner * only that VSI it is now empty and can be removed. 360071d10453SEric Joyner */ 360171d10453SEric Joyner if (only_vsi) { 360271d10453SEric Joyner status = ice_rem_vsig(hw, blk, or_vsig, &chg); 360371d10453SEric Joyner if (status) 360471d10453SEric Joyner goto err_ice_add_prof_id_flow; 360571d10453SEric Joyner } 360671d10453SEric Joyner } else if (only_vsi) { 360771d10453SEric Joyner /* If the original VSIG only contains one VSI, then it 360871d10453SEric Joyner * will be the requesting VSI. In this case the VSI is 360971d10453SEric Joyner * not sharing entries and we can simply add the new 361071d10453SEric Joyner * profile to the VSIG. 361171d10453SEric Joyner */ 361271d10453SEric Joyner status = ice_add_prof_id_vsig(hw, blk, vsig, hdl, false, 361371d10453SEric Joyner &chg); 361471d10453SEric Joyner if (status) 361571d10453SEric Joyner goto err_ice_add_prof_id_flow; 361671d10453SEric Joyner 361771d10453SEric Joyner /* Adjust priorities */ 361871d10453SEric Joyner status = ice_adj_prof_priorities(hw, blk, vsig, &chg); 361971d10453SEric Joyner if (status) 362071d10453SEric Joyner goto err_ice_add_prof_id_flow; 362171d10453SEric Joyner } else { 362271d10453SEric Joyner /* No match, so we need a new VSIG */ 362371d10453SEric Joyner status = ice_create_vsig_from_lst(hw, blk, vsi, 362471d10453SEric Joyner &union_lst, &vsig, 362571d10453SEric Joyner &chg); 362671d10453SEric Joyner if (status) 362771d10453SEric Joyner goto err_ice_add_prof_id_flow; 362871d10453SEric Joyner 362971d10453SEric Joyner /* Adjust priorities */ 363071d10453SEric Joyner status = ice_adj_prof_priorities(hw, blk, vsig, &chg); 363171d10453SEric Joyner if (status) 363271d10453SEric Joyner goto err_ice_add_prof_id_flow; 363371d10453SEric Joyner } 363471d10453SEric Joyner } else { 363571d10453SEric Joyner /* need to find or add a VSIG */ 363671d10453SEric Joyner /* search for an existing VSIG with an exact charc match */ 363771d10453SEric Joyner if (ice_find_prof_vsig(hw, blk, hdl, &vsig)) { 363871d10453SEric Joyner /* found an exact match */ 363971d10453SEric Joyner /* add or move VSI to the VSIG that matches */ 364071d10453SEric Joyner status = ice_move_vsi(hw, blk, vsi, vsig, &chg); 364171d10453SEric Joyner if (status) 364271d10453SEric Joyner goto err_ice_add_prof_id_flow; 364371d10453SEric Joyner } else { 364471d10453SEric Joyner /* we did not find an exact match */ 364571d10453SEric Joyner /* we need to add a VSIG */ 364671d10453SEric Joyner status = ice_create_prof_id_vsig(hw, blk, vsi, hdl, 364771d10453SEric Joyner &chg); 364871d10453SEric Joyner if (status) 364971d10453SEric Joyner goto err_ice_add_prof_id_flow; 365071d10453SEric Joyner } 365171d10453SEric Joyner } 365271d10453SEric Joyner 365371d10453SEric Joyner /* update hardware */ 365471d10453SEric Joyner if (!status) 365571d10453SEric Joyner status = ice_upd_prof_hw(hw, blk, &chg); 365671d10453SEric Joyner 365771d10453SEric Joyner err_ice_add_prof_id_flow: 365871d10453SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(del, tmp, &chg, ice_chs_chg, list_entry) { 365971d10453SEric Joyner LIST_DEL(&del->list_entry); 366071d10453SEric Joyner ice_free(hw, del); 366171d10453SEric Joyner } 366271d10453SEric Joyner 366371d10453SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(del1, tmp1, &union_lst, ice_vsig_prof, list) { 366471d10453SEric Joyner LIST_DEL(&del1->list); 366571d10453SEric Joyner ice_free(hw, del1); 366671d10453SEric Joyner } 366771d10453SEric Joyner 366871d10453SEric Joyner return status; 366971d10453SEric Joyner } 367071d10453SEric Joyner 367171d10453SEric Joyner /** 367271d10453SEric Joyner * ice_add_flow - add flow 367371d10453SEric Joyner * @hw: pointer to the HW struct 367471d10453SEric Joyner * @blk: hardware block 367571d10453SEric Joyner * @vsi: array of VSIs to enable with the profile specified by ID 367671d10453SEric Joyner * @count: number of elements in the VSI array 367771d10453SEric Joyner * @id: profile tracking ID 367871d10453SEric Joyner * 367971d10453SEric Joyner * Calling this function will update the hardware tables to enable the 368071d10453SEric Joyner * profile indicated by the ID parameter for the VSIs specified in the VSI 368171d10453SEric Joyner * array. Once successfully called, the flow will be enabled. 368271d10453SEric Joyner */ 368371d10453SEric Joyner enum ice_status 368471d10453SEric Joyner ice_add_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi[], u8 count, 368571d10453SEric Joyner u64 id) 368671d10453SEric Joyner { 368771d10453SEric Joyner u16 i; 368871d10453SEric Joyner 368971d10453SEric Joyner for (i = 0; i < count; i++) { 36908923de59SPiotr Kubaj enum ice_status status; 36918923de59SPiotr Kubaj 369271d10453SEric Joyner status = ice_add_prof_id_flow(hw, blk, vsi[i], id); 369371d10453SEric Joyner if (status) 369471d10453SEric Joyner return status; 369571d10453SEric Joyner } 369671d10453SEric Joyner 369771d10453SEric Joyner return ICE_SUCCESS; 369871d10453SEric Joyner } 369971d10453SEric Joyner 370071d10453SEric Joyner /** 370171d10453SEric Joyner * ice_rem_prof_from_list - remove a profile from list 370271d10453SEric Joyner * @hw: pointer to the HW struct 370371d10453SEric Joyner * @lst: list to remove the profile from 370471d10453SEric Joyner * @hdl: the profile handle indicating the profile to remove 370571d10453SEric Joyner */ 370671d10453SEric Joyner static enum ice_status 370771d10453SEric Joyner ice_rem_prof_from_list(struct ice_hw *hw, struct LIST_HEAD_TYPE *lst, u64 hdl) 370871d10453SEric Joyner { 370971d10453SEric Joyner struct ice_vsig_prof *ent, *tmp; 371071d10453SEric Joyner 37117d7af7f8SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(ent, tmp, lst, ice_vsig_prof, list) 371271d10453SEric Joyner if (ent->profile_cookie == hdl) { 371371d10453SEric Joyner LIST_DEL(&ent->list); 371471d10453SEric Joyner ice_free(hw, ent); 371571d10453SEric Joyner return ICE_SUCCESS; 371671d10453SEric Joyner } 371771d10453SEric Joyner 371871d10453SEric Joyner return ICE_ERR_DOES_NOT_EXIST; 371971d10453SEric Joyner } 372071d10453SEric Joyner 372171d10453SEric Joyner /** 372271d10453SEric Joyner * ice_rem_prof_id_flow - remove flow 372371d10453SEric Joyner * @hw: pointer to the HW struct 372471d10453SEric Joyner * @blk: hardware block 372571d10453SEric Joyner * @vsi: the VSI from which to remove the profile specified by ID 372671d10453SEric Joyner * @hdl: profile tracking handle 372771d10453SEric Joyner * 372871d10453SEric Joyner * Calling this function will update the hardware tables to remove the 372971d10453SEric Joyner * profile indicated by the ID parameter for the VSIs specified in the VSI 373071d10453SEric Joyner * array. Once successfully called, the flow will be disabled. 373171d10453SEric Joyner */ 373271d10453SEric Joyner enum ice_status 373371d10453SEric Joyner ice_rem_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl) 373471d10453SEric Joyner { 373571d10453SEric Joyner struct ice_vsig_prof *tmp1, *del1; 373671d10453SEric Joyner struct ice_chs_chg *tmp, *del; 37377d7af7f8SEric Joyner struct LIST_HEAD_TYPE chg, copy; 373871d10453SEric Joyner enum ice_status status; 373971d10453SEric Joyner u16 vsig; 374071d10453SEric Joyner 374171d10453SEric Joyner INIT_LIST_HEAD(©); 374271d10453SEric Joyner INIT_LIST_HEAD(&chg); 374371d10453SEric Joyner 374471d10453SEric Joyner /* determine if VSI is already part of a VSIG */ 374571d10453SEric Joyner status = ice_vsig_find_vsi(hw, blk, vsi, &vsig); 374671d10453SEric Joyner if (!status && vsig) { 374771d10453SEric Joyner bool last_profile; 374871d10453SEric Joyner bool only_vsi; 374971d10453SEric Joyner u16 ref; 375071d10453SEric Joyner 375171d10453SEric Joyner /* found in VSIG */ 375271d10453SEric Joyner last_profile = ice_vsig_prof_id_count(hw, blk, vsig) == 1; 375371d10453SEric Joyner status = ice_vsig_get_ref(hw, blk, vsig, &ref); 375471d10453SEric Joyner if (status) 375571d10453SEric Joyner goto err_ice_rem_prof_id_flow; 375671d10453SEric Joyner only_vsi = (ref == 1); 375771d10453SEric Joyner 375871d10453SEric Joyner if (only_vsi) { 375971d10453SEric Joyner /* If the original VSIG only contains one reference, 376071d10453SEric Joyner * which will be the requesting VSI, then the VSI is not 376171d10453SEric Joyner * sharing entries and we can simply remove the specific 376271d10453SEric Joyner * characteristics from the VSIG. 376371d10453SEric Joyner */ 376471d10453SEric Joyner 376571d10453SEric Joyner if (last_profile) { 376671d10453SEric Joyner /* If there are no profiles left for this VSIG, 37677d7af7f8SEric Joyner * then simply remove the VSIG. 376871d10453SEric Joyner */ 376971d10453SEric Joyner status = ice_rem_vsig(hw, blk, vsig, &chg); 377071d10453SEric Joyner if (status) 377171d10453SEric Joyner goto err_ice_rem_prof_id_flow; 377271d10453SEric Joyner } else { 377371d10453SEric Joyner status = ice_rem_prof_id_vsig(hw, blk, vsig, 377471d10453SEric Joyner hdl, &chg); 377571d10453SEric Joyner if (status) 377671d10453SEric Joyner goto err_ice_rem_prof_id_flow; 377771d10453SEric Joyner 377871d10453SEric Joyner /* Adjust priorities */ 377971d10453SEric Joyner status = ice_adj_prof_priorities(hw, blk, vsig, 378071d10453SEric Joyner &chg); 378171d10453SEric Joyner if (status) 378271d10453SEric Joyner goto err_ice_rem_prof_id_flow; 378371d10453SEric Joyner } 378471d10453SEric Joyner 378571d10453SEric Joyner } else { 378671d10453SEric Joyner /* Make a copy of the VSIG's list of Profiles */ 378771d10453SEric Joyner status = ice_get_profs_vsig(hw, blk, vsig, ©); 378871d10453SEric Joyner if (status) 378971d10453SEric Joyner goto err_ice_rem_prof_id_flow; 379071d10453SEric Joyner 379171d10453SEric Joyner /* Remove specified profile entry from the list */ 379271d10453SEric Joyner status = ice_rem_prof_from_list(hw, ©, hdl); 379371d10453SEric Joyner if (status) 379471d10453SEric Joyner goto err_ice_rem_prof_id_flow; 379571d10453SEric Joyner 379671d10453SEric Joyner if (LIST_EMPTY(©)) { 379771d10453SEric Joyner status = ice_move_vsi(hw, blk, vsi, 379871d10453SEric Joyner ICE_DEFAULT_VSIG, &chg); 379971d10453SEric Joyner if (status) 380071d10453SEric Joyner goto err_ice_rem_prof_id_flow; 380171d10453SEric Joyner 380271d10453SEric Joyner } else if (!ice_find_dup_props_vsig(hw, blk, ©, 380371d10453SEric Joyner &vsig)) { 380471d10453SEric Joyner /* found an exact match */ 380571d10453SEric Joyner /* add or move VSI to the VSIG that matches */ 380671d10453SEric Joyner /* Search for a VSIG with a matching profile 380771d10453SEric Joyner * list 380871d10453SEric Joyner */ 380971d10453SEric Joyner 381071d10453SEric Joyner /* Found match, move VSI to the matching VSIG */ 381171d10453SEric Joyner status = ice_move_vsi(hw, blk, vsi, vsig, &chg); 381271d10453SEric Joyner if (status) 381371d10453SEric Joyner goto err_ice_rem_prof_id_flow; 381471d10453SEric Joyner } else { 381571d10453SEric Joyner /* since no existing VSIG supports this 381671d10453SEric Joyner * characteristic pattern, we need to create a 381771d10453SEric Joyner * new VSIG and TCAM entries 381871d10453SEric Joyner */ 381971d10453SEric Joyner status = ice_create_vsig_from_lst(hw, blk, vsi, 382071d10453SEric Joyner ©, &vsig, 382171d10453SEric Joyner &chg); 382271d10453SEric Joyner if (status) 382371d10453SEric Joyner goto err_ice_rem_prof_id_flow; 382471d10453SEric Joyner 382571d10453SEric Joyner /* Adjust priorities */ 382671d10453SEric Joyner status = ice_adj_prof_priorities(hw, blk, vsig, 382771d10453SEric Joyner &chg); 382871d10453SEric Joyner if (status) 382971d10453SEric Joyner goto err_ice_rem_prof_id_flow; 383071d10453SEric Joyner } 383171d10453SEric Joyner } 383271d10453SEric Joyner } else { 383371d10453SEric Joyner status = ICE_ERR_DOES_NOT_EXIST; 383471d10453SEric Joyner } 383571d10453SEric Joyner 383671d10453SEric Joyner /* update hardware tables */ 383771d10453SEric Joyner if (!status) 383871d10453SEric Joyner status = ice_upd_prof_hw(hw, blk, &chg); 383971d10453SEric Joyner 384071d10453SEric Joyner err_ice_rem_prof_id_flow: 384171d10453SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(del, tmp, &chg, ice_chs_chg, list_entry) { 384271d10453SEric Joyner LIST_DEL(&del->list_entry); 384371d10453SEric Joyner ice_free(hw, del); 384471d10453SEric Joyner } 384571d10453SEric Joyner 384671d10453SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(del1, tmp1, ©, ice_vsig_prof, list) { 384771d10453SEric Joyner LIST_DEL(&del1->list); 384871d10453SEric Joyner ice_free(hw, del1); 384971d10453SEric Joyner } 385071d10453SEric Joyner 385171d10453SEric Joyner return status; 385271d10453SEric Joyner } 385371d10453SEric Joyner 385471d10453SEric Joyner /** 385571d10453SEric Joyner * ice_rem_flow - remove flow 385671d10453SEric Joyner * @hw: pointer to the HW struct 385771d10453SEric Joyner * @blk: hardware block 385871d10453SEric Joyner * @vsi: array of VSIs from which to remove the profile specified by ID 385971d10453SEric Joyner * @count: number of elements in the VSI array 386071d10453SEric Joyner * @id: profile tracking ID 386171d10453SEric Joyner * 386271d10453SEric Joyner * The function will remove flows from the specified VSIs that were enabled 386371d10453SEric Joyner * using ice_add_flow. The ID value will indicated which profile will be 386471d10453SEric Joyner * removed. Once successfully called, the flow will be disabled. 386571d10453SEric Joyner */ 386671d10453SEric Joyner enum ice_status 386771d10453SEric Joyner ice_rem_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi[], u8 count, 386871d10453SEric Joyner u64 id) 386971d10453SEric Joyner { 387071d10453SEric Joyner u16 i; 387171d10453SEric Joyner 387271d10453SEric Joyner for (i = 0; i < count; i++) { 38738923de59SPiotr Kubaj enum ice_status status; 38748923de59SPiotr Kubaj 387571d10453SEric Joyner status = ice_rem_prof_id_flow(hw, blk, vsi[i], id); 387671d10453SEric Joyner if (status) 387771d10453SEric Joyner return status; 387871d10453SEric Joyner } 387971d10453SEric Joyner 388071d10453SEric Joyner return ICE_SUCCESS; 388171d10453SEric Joyner } 3882