171d10453SEric Joyner /* SPDX-License-Identifier: BSD-3-Clause */ 2015f8cc5SEric 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_sched.h" 3371d10453SEric Joyner 3471d10453SEric Joyner /** 3571d10453SEric Joyner * ice_sched_add_root_node - Insert the Tx scheduler root node in SW DB 3671d10453SEric Joyner * @pi: port information structure 3771d10453SEric Joyner * @info: Scheduler element information from firmware 3871d10453SEric Joyner * 3971d10453SEric Joyner * This function inserts the root node of the scheduling tree topology 4071d10453SEric Joyner * to the SW DB. 4171d10453SEric Joyner */ 42*f2635e84SEric Joyner static int 4371d10453SEric Joyner ice_sched_add_root_node(struct ice_port_info *pi, 4471d10453SEric Joyner struct ice_aqc_txsched_elem_data *info) 4571d10453SEric Joyner { 4671d10453SEric Joyner struct ice_sched_node *root; 4771d10453SEric Joyner struct ice_hw *hw; 4871d10453SEric Joyner 4971d10453SEric Joyner if (!pi) 5071d10453SEric Joyner return ICE_ERR_PARAM; 5171d10453SEric Joyner 5271d10453SEric Joyner hw = pi->hw; 5371d10453SEric Joyner 5471d10453SEric Joyner root = (struct ice_sched_node *)ice_malloc(hw, sizeof(*root)); 5571d10453SEric Joyner if (!root) 5671d10453SEric Joyner return ICE_ERR_NO_MEMORY; 5771d10453SEric Joyner 5871d10453SEric Joyner root->children = (struct ice_sched_node **) 599e54973fSEric Joyner ice_calloc(hw, hw->max_children[0], sizeof(*root->children)); 6071d10453SEric Joyner if (!root->children) { 6171d10453SEric Joyner ice_free(hw, root); 6271d10453SEric Joyner return ICE_ERR_NO_MEMORY; 6371d10453SEric Joyner } 6471d10453SEric Joyner 65*f2635e84SEric Joyner ice_memcpy(&root->info, info, sizeof(*info), ICE_NONDMA_TO_NONDMA); 6671d10453SEric Joyner pi->root = root; 67*f2635e84SEric Joyner return 0; 6871d10453SEric Joyner } 6971d10453SEric Joyner 7071d10453SEric Joyner /** 7171d10453SEric Joyner * ice_sched_find_node_by_teid - Find the Tx scheduler node in SW DB 7271d10453SEric Joyner * @start_node: pointer to the starting ice_sched_node struct in a sub-tree 7371d10453SEric Joyner * @teid: node TEID to search 7471d10453SEric Joyner * 7571d10453SEric Joyner * This function searches for a node matching the TEID in the scheduling tree 7671d10453SEric Joyner * from the SW DB. The search is recursive and is restricted by the number of 7771d10453SEric Joyner * layers it has searched through; stopping at the max supported layer. 7871d10453SEric Joyner * 7971d10453SEric Joyner * This function needs to be called when holding the port_info->sched_lock 8071d10453SEric Joyner */ 8171d10453SEric Joyner struct ice_sched_node * 8271d10453SEric Joyner ice_sched_find_node_by_teid(struct ice_sched_node *start_node, u32 teid) 8371d10453SEric Joyner { 8471d10453SEric Joyner u16 i; 8571d10453SEric Joyner 86*f2635e84SEric Joyner if (!start_node) 87*f2635e84SEric Joyner return NULL; 88*f2635e84SEric Joyner 8971d10453SEric Joyner /* The TEID is same as that of the start_node */ 9071d10453SEric Joyner if (ICE_TXSCHED_GET_NODE_TEID(start_node) == teid) 9171d10453SEric Joyner return start_node; 9271d10453SEric Joyner 9371d10453SEric Joyner /* The node has no children or is at the max layer */ 9471d10453SEric Joyner if (!start_node->num_children || 9571d10453SEric Joyner start_node->tx_sched_layer >= ICE_AQC_TOPO_MAX_LEVEL_NUM || 9671d10453SEric Joyner start_node->info.data.elem_type == ICE_AQC_ELEM_TYPE_LEAF) 9771d10453SEric Joyner return NULL; 9871d10453SEric Joyner 9971d10453SEric Joyner /* Check if TEID matches to any of the children nodes */ 10071d10453SEric Joyner for (i = 0; i < start_node->num_children; i++) 10171d10453SEric Joyner if (ICE_TXSCHED_GET_NODE_TEID(start_node->children[i]) == teid) 10271d10453SEric Joyner return start_node->children[i]; 10371d10453SEric Joyner 10471d10453SEric Joyner /* Search within each child's sub-tree */ 10571d10453SEric Joyner for (i = 0; i < start_node->num_children; i++) { 10671d10453SEric Joyner struct ice_sched_node *tmp; 10771d10453SEric Joyner 10871d10453SEric Joyner tmp = ice_sched_find_node_by_teid(start_node->children[i], 10971d10453SEric Joyner teid); 11071d10453SEric Joyner if (tmp) 11171d10453SEric Joyner return tmp; 11271d10453SEric Joyner } 11371d10453SEric Joyner 11471d10453SEric Joyner return NULL; 11571d10453SEric Joyner } 11671d10453SEric Joyner 11771d10453SEric Joyner /** 11871d10453SEric Joyner * ice_aqc_send_sched_elem_cmd - send scheduling elements cmd 11971d10453SEric Joyner * @hw: pointer to the HW struct 12071d10453SEric Joyner * @cmd_opc: cmd opcode 12171d10453SEric Joyner * @elems_req: number of elements to request 12271d10453SEric Joyner * @buf: pointer to buffer 12371d10453SEric Joyner * @buf_size: buffer size in bytes 12471d10453SEric Joyner * @elems_resp: returns total number of elements response 12571d10453SEric Joyner * @cd: pointer to command details structure or NULL 12671d10453SEric Joyner * 12771d10453SEric Joyner * This function sends a scheduling elements cmd (cmd_opc) 12871d10453SEric Joyner */ 129*f2635e84SEric Joyner static int 13071d10453SEric Joyner ice_aqc_send_sched_elem_cmd(struct ice_hw *hw, enum ice_adminq_opc cmd_opc, 13171d10453SEric Joyner u16 elems_req, void *buf, u16 buf_size, 13271d10453SEric Joyner u16 *elems_resp, struct ice_sq_cd *cd) 13371d10453SEric Joyner { 13471d10453SEric Joyner struct ice_aqc_sched_elem_cmd *cmd; 13571d10453SEric Joyner struct ice_aq_desc desc; 136*f2635e84SEric Joyner int status; 13771d10453SEric Joyner 13871d10453SEric Joyner cmd = &desc.params.sched_elem_cmd; 13971d10453SEric Joyner ice_fill_dflt_direct_cmd_desc(&desc, cmd_opc); 14071d10453SEric Joyner cmd->num_elem_req = CPU_TO_LE16(elems_req); 14171d10453SEric Joyner desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD); 14271d10453SEric Joyner status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); 14371d10453SEric Joyner if (!status && elems_resp) 14471d10453SEric Joyner *elems_resp = LE16_TO_CPU(cmd->num_elem_resp); 14571d10453SEric Joyner 14671d10453SEric Joyner return status; 14771d10453SEric Joyner } 14871d10453SEric Joyner 14971d10453SEric Joyner /** 15071d10453SEric Joyner * ice_aq_query_sched_elems - query scheduler elements 15171d10453SEric Joyner * @hw: pointer to the HW struct 15271d10453SEric Joyner * @elems_req: number of elements to query 15371d10453SEric Joyner * @buf: pointer to buffer 15471d10453SEric Joyner * @buf_size: buffer size in bytes 15571d10453SEric Joyner * @elems_ret: returns total number of elements returned 15671d10453SEric Joyner * @cd: pointer to command details structure or NULL 15771d10453SEric Joyner * 15871d10453SEric Joyner * Query scheduling elements (0x0404) 15971d10453SEric Joyner */ 160*f2635e84SEric Joyner int 16171d10453SEric Joyner ice_aq_query_sched_elems(struct ice_hw *hw, u16 elems_req, 1627d7af7f8SEric Joyner struct ice_aqc_txsched_elem_data *buf, u16 buf_size, 16371d10453SEric Joyner u16 *elems_ret, struct ice_sq_cd *cd) 16471d10453SEric Joyner { 16571d10453SEric Joyner return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_get_sched_elems, 16671d10453SEric Joyner elems_req, (void *)buf, buf_size, 16771d10453SEric Joyner elems_ret, cd); 16871d10453SEric Joyner } 16971d10453SEric Joyner 17071d10453SEric Joyner /** 17171d10453SEric Joyner * ice_sched_add_node - Insert the Tx scheduler node in SW DB 17271d10453SEric Joyner * @pi: port information structure 17371d10453SEric Joyner * @layer: Scheduler layer of the node 17471d10453SEric Joyner * @info: Scheduler element information from firmware 1759c30461dSEric Joyner * @prealloc_node: preallocated ice_sched_node struct for SW DB 17671d10453SEric Joyner * 17771d10453SEric Joyner * This function inserts a scheduler node to the SW DB. 17871d10453SEric Joyner */ 179*f2635e84SEric Joyner int 18071d10453SEric Joyner ice_sched_add_node(struct ice_port_info *pi, u8 layer, 1819c30461dSEric Joyner struct ice_aqc_txsched_elem_data *info, 1829c30461dSEric Joyner struct ice_sched_node *prealloc_node) 18371d10453SEric Joyner { 1847d7af7f8SEric Joyner struct ice_aqc_txsched_elem_data elem; 18571d10453SEric Joyner struct ice_sched_node *parent; 18671d10453SEric Joyner struct ice_sched_node *node; 18771d10453SEric Joyner struct ice_hw *hw; 188*f2635e84SEric Joyner int status; 18971d10453SEric Joyner 19071d10453SEric Joyner if (!pi) 19171d10453SEric Joyner return ICE_ERR_PARAM; 19271d10453SEric Joyner 19371d10453SEric Joyner hw = pi->hw; 19471d10453SEric Joyner 19571d10453SEric Joyner /* A valid parent node should be there */ 19671d10453SEric Joyner parent = ice_sched_find_node_by_teid(pi->root, 19771d10453SEric Joyner LE32_TO_CPU(info->parent_teid)); 19871d10453SEric Joyner if (!parent) { 1997d7af7f8SEric Joyner ice_debug(hw, ICE_DBG_SCHED, "Parent Node not found for parent_teid=0x%x\n", 20071d10453SEric Joyner LE32_TO_CPU(info->parent_teid)); 20171d10453SEric Joyner return ICE_ERR_PARAM; 20271d10453SEric Joyner } 20371d10453SEric Joyner 2047d7af7f8SEric Joyner /* query the current node information from FW before adding it 20571d10453SEric Joyner * to the SW DB 20671d10453SEric Joyner */ 20771d10453SEric Joyner status = ice_sched_query_elem(hw, LE32_TO_CPU(info->node_teid), &elem); 20871d10453SEric Joyner if (status) 20971d10453SEric Joyner return status; 2109c30461dSEric Joyner 2119c30461dSEric Joyner if (prealloc_node) 2129c30461dSEric Joyner node = prealloc_node; 2139c30461dSEric Joyner else 21471d10453SEric Joyner node = (struct ice_sched_node *)ice_malloc(hw, sizeof(*node)); 21571d10453SEric Joyner if (!node) 21671d10453SEric Joyner return ICE_ERR_NO_MEMORY; 21771d10453SEric Joyner if (hw->max_children[layer]) { 21871d10453SEric Joyner node->children = (struct ice_sched_node **) 2199e54973fSEric Joyner ice_calloc(hw, hw->max_children[layer], 2209e54973fSEric Joyner sizeof(*node->children)); 22171d10453SEric Joyner if (!node->children) { 22271d10453SEric Joyner ice_free(hw, node); 22371d10453SEric Joyner return ICE_ERR_NO_MEMORY; 22471d10453SEric Joyner } 22571d10453SEric Joyner } 22671d10453SEric Joyner 22771d10453SEric Joyner node->in_use = true; 22871d10453SEric Joyner node->parent = parent; 22971d10453SEric Joyner node->tx_sched_layer = layer; 23071d10453SEric Joyner parent->children[parent->num_children++] = node; 2317d7af7f8SEric Joyner node->info = elem; 232*f2635e84SEric Joyner return 0; 23371d10453SEric Joyner } 23471d10453SEric Joyner 23571d10453SEric Joyner /** 23671d10453SEric Joyner * ice_aq_delete_sched_elems - delete scheduler elements 23771d10453SEric Joyner * @hw: pointer to the HW struct 23871d10453SEric Joyner * @grps_req: number of groups to delete 23971d10453SEric Joyner * @buf: pointer to buffer 24071d10453SEric Joyner * @buf_size: buffer size in bytes 24171d10453SEric Joyner * @grps_del: returns total number of elements deleted 24271d10453SEric Joyner * @cd: pointer to command details structure or NULL 24371d10453SEric Joyner * 24471d10453SEric Joyner * Delete scheduling elements (0x040F) 24571d10453SEric Joyner */ 246*f2635e84SEric Joyner static int 24771d10453SEric Joyner ice_aq_delete_sched_elems(struct ice_hw *hw, u16 grps_req, 24871d10453SEric Joyner struct ice_aqc_delete_elem *buf, u16 buf_size, 24971d10453SEric Joyner u16 *grps_del, struct ice_sq_cd *cd) 25071d10453SEric Joyner { 25171d10453SEric Joyner return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_delete_sched_elems, 25271d10453SEric Joyner grps_req, (void *)buf, buf_size, 25371d10453SEric Joyner grps_del, cd); 25471d10453SEric Joyner } 25571d10453SEric Joyner 25671d10453SEric Joyner /** 25771d10453SEric Joyner * ice_sched_remove_elems - remove nodes from HW 25871d10453SEric Joyner * @hw: pointer to the HW struct 25971d10453SEric Joyner * @parent: pointer to the parent node 26071d10453SEric Joyner * @num_nodes: number of nodes 26171d10453SEric Joyner * @node_teids: array of node teids to be deleted 26271d10453SEric Joyner * 26371d10453SEric Joyner * This function remove nodes from HW 26471d10453SEric Joyner */ 265*f2635e84SEric Joyner static int 26671d10453SEric Joyner ice_sched_remove_elems(struct ice_hw *hw, struct ice_sched_node *parent, 26771d10453SEric Joyner u16 num_nodes, u32 *node_teids) 26871d10453SEric Joyner { 26971d10453SEric Joyner struct ice_aqc_delete_elem *buf; 27071d10453SEric Joyner u16 i, num_groups_removed = 0; 27171d10453SEric Joyner u16 buf_size; 272*f2635e84SEric Joyner int status; 27371d10453SEric Joyner 2747d7af7f8SEric Joyner buf_size = ice_struct_size(buf, teid, num_nodes); 27571d10453SEric Joyner buf = (struct ice_aqc_delete_elem *)ice_malloc(hw, buf_size); 27671d10453SEric Joyner if (!buf) 27771d10453SEric Joyner return ICE_ERR_NO_MEMORY; 27871d10453SEric Joyner 27971d10453SEric Joyner buf->hdr.parent_teid = parent->info.node_teid; 28071d10453SEric Joyner buf->hdr.num_elems = CPU_TO_LE16(num_nodes); 28171d10453SEric Joyner for (i = 0; i < num_nodes; i++) 28271d10453SEric Joyner buf->teid[i] = CPU_TO_LE32(node_teids[i]); 28371d10453SEric Joyner 28471d10453SEric Joyner status = ice_aq_delete_sched_elems(hw, 1, buf, buf_size, 28571d10453SEric Joyner &num_groups_removed, NULL); 286*f2635e84SEric Joyner if (status || num_groups_removed != 1) 28771d10453SEric Joyner ice_debug(hw, ICE_DBG_SCHED, "remove node failed FW error %d\n", 28871d10453SEric Joyner hw->adminq.sq_last_status); 28971d10453SEric Joyner 29071d10453SEric Joyner ice_free(hw, buf); 29171d10453SEric Joyner return status; 29271d10453SEric Joyner } 29371d10453SEric Joyner 29471d10453SEric Joyner /** 29571d10453SEric Joyner * ice_sched_get_first_node - get the first node of the given layer 29671d10453SEric Joyner * @pi: port information structure 29771d10453SEric Joyner * @parent: pointer the base node of the subtree 29871d10453SEric Joyner * @layer: layer number 29971d10453SEric Joyner * 30071d10453SEric Joyner * This function retrieves the first node of the given layer from the subtree 30171d10453SEric Joyner */ 30271d10453SEric Joyner static struct ice_sched_node * 30371d10453SEric Joyner ice_sched_get_first_node(struct ice_port_info *pi, 30471d10453SEric Joyner struct ice_sched_node *parent, u8 layer) 30571d10453SEric Joyner { 30671d10453SEric Joyner return pi->sib_head[parent->tc_num][layer]; 30771d10453SEric Joyner } 30871d10453SEric Joyner 30971d10453SEric Joyner /** 31071d10453SEric Joyner * ice_sched_get_tc_node - get pointer to TC node 31171d10453SEric Joyner * @pi: port information structure 31271d10453SEric Joyner * @tc: TC number 31371d10453SEric Joyner * 31471d10453SEric Joyner * This function returns the TC node pointer 31571d10453SEric Joyner */ 31671d10453SEric Joyner struct ice_sched_node *ice_sched_get_tc_node(struct ice_port_info *pi, u8 tc) 31771d10453SEric Joyner { 31871d10453SEric Joyner u8 i; 31971d10453SEric Joyner 32071d10453SEric Joyner if (!pi || !pi->root) 32171d10453SEric Joyner return NULL; 32271d10453SEric Joyner for (i = 0; i < pi->root->num_children; i++) 32371d10453SEric Joyner if (pi->root->children[i]->tc_num == tc) 32471d10453SEric Joyner return pi->root->children[i]; 32571d10453SEric Joyner return NULL; 32671d10453SEric Joyner } 32771d10453SEric Joyner 32871d10453SEric Joyner /** 32971d10453SEric Joyner * ice_free_sched_node - Free a Tx scheduler node from SW DB 33071d10453SEric Joyner * @pi: port information structure 33171d10453SEric Joyner * @node: pointer to the ice_sched_node struct 33271d10453SEric Joyner * 33371d10453SEric Joyner * This function frees up a node from SW DB as well as from HW 33471d10453SEric Joyner * 33571d10453SEric Joyner * This function needs to be called with the port_info->sched_lock held 33671d10453SEric Joyner */ 33771d10453SEric Joyner void ice_free_sched_node(struct ice_port_info *pi, struct ice_sched_node *node) 33871d10453SEric Joyner { 33971d10453SEric Joyner struct ice_sched_node *parent; 34071d10453SEric Joyner struct ice_hw *hw = pi->hw; 34171d10453SEric Joyner u8 i, j; 34271d10453SEric Joyner 34371d10453SEric Joyner /* Free the children before freeing up the parent node 34471d10453SEric Joyner * The parent array is updated below and that shifts the nodes 34571d10453SEric Joyner * in the array. So always pick the first child if num children > 0 34671d10453SEric Joyner */ 34771d10453SEric Joyner while (node->num_children) 34871d10453SEric Joyner ice_free_sched_node(pi, node->children[0]); 34971d10453SEric Joyner 35071d10453SEric Joyner /* Leaf, TC and root nodes can't be deleted by SW */ 35171d10453SEric Joyner if (node->tx_sched_layer >= hw->sw_entry_point_layer && 35271d10453SEric Joyner node->info.data.elem_type != ICE_AQC_ELEM_TYPE_TC && 35371d10453SEric Joyner node->info.data.elem_type != ICE_AQC_ELEM_TYPE_ROOT_PORT && 35471d10453SEric Joyner node->info.data.elem_type != ICE_AQC_ELEM_TYPE_LEAF) { 35571d10453SEric Joyner u32 teid = LE32_TO_CPU(node->info.node_teid); 35671d10453SEric Joyner 35771d10453SEric Joyner ice_sched_remove_elems(hw, node->parent, 1, &teid); 35871d10453SEric Joyner } 35971d10453SEric Joyner parent = node->parent; 36071d10453SEric Joyner /* root has no parent */ 36171d10453SEric Joyner if (parent) { 36271d10453SEric Joyner struct ice_sched_node *p; 36371d10453SEric Joyner 36471d10453SEric Joyner /* update the parent */ 36571d10453SEric Joyner for (i = 0; i < parent->num_children; i++) 36671d10453SEric Joyner if (parent->children[i] == node) { 36771d10453SEric Joyner for (j = i + 1; j < parent->num_children; j++) 36871d10453SEric Joyner parent->children[j - 1] = 36971d10453SEric Joyner parent->children[j]; 37071d10453SEric Joyner parent->num_children--; 37171d10453SEric Joyner break; 37271d10453SEric Joyner } 37371d10453SEric Joyner 37471d10453SEric Joyner p = ice_sched_get_first_node(pi, node, node->tx_sched_layer); 37571d10453SEric Joyner while (p) { 37671d10453SEric Joyner if (p->sibling == node) { 37771d10453SEric Joyner p->sibling = node->sibling; 37871d10453SEric Joyner break; 37971d10453SEric Joyner } 38071d10453SEric Joyner p = p->sibling; 38171d10453SEric Joyner } 38271d10453SEric Joyner 38371d10453SEric Joyner /* update the sibling head if head is getting removed */ 38471d10453SEric Joyner if (pi->sib_head[node->tc_num][node->tx_sched_layer] == node) 38571d10453SEric Joyner pi->sib_head[node->tc_num][node->tx_sched_layer] = 38671d10453SEric Joyner node->sibling; 38771d10453SEric Joyner } 38871d10453SEric Joyner 38971d10453SEric Joyner /* leaf nodes have no children */ 39071d10453SEric Joyner if (node->children) 39171d10453SEric Joyner ice_free(hw, node->children); 39271d10453SEric Joyner ice_free(hw, node); 39371d10453SEric Joyner } 39471d10453SEric Joyner 39571d10453SEric Joyner /** 39671d10453SEric Joyner * ice_aq_get_dflt_topo - gets default scheduler topology 39771d10453SEric Joyner * @hw: pointer to the HW struct 39871d10453SEric Joyner * @lport: logical port number 39971d10453SEric Joyner * @buf: pointer to buffer 40071d10453SEric Joyner * @buf_size: buffer size in bytes 40171d10453SEric Joyner * @num_branches: returns total number of queue to port branches 40271d10453SEric Joyner * @cd: pointer to command details structure or NULL 40371d10453SEric Joyner * 40471d10453SEric Joyner * Get default scheduler topology (0x400) 40571d10453SEric Joyner */ 406*f2635e84SEric Joyner static int 40771d10453SEric Joyner ice_aq_get_dflt_topo(struct ice_hw *hw, u8 lport, 40871d10453SEric Joyner struct ice_aqc_get_topo_elem *buf, u16 buf_size, 40971d10453SEric Joyner u8 *num_branches, struct ice_sq_cd *cd) 41071d10453SEric Joyner { 41171d10453SEric Joyner struct ice_aqc_get_topo *cmd; 41271d10453SEric Joyner struct ice_aq_desc desc; 413*f2635e84SEric Joyner int status; 41471d10453SEric Joyner 41571d10453SEric Joyner cmd = &desc.params.get_topo; 41671d10453SEric Joyner ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_dflt_topo); 41771d10453SEric Joyner cmd->port_num = lport; 41871d10453SEric Joyner status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); 41971d10453SEric Joyner if (!status && num_branches) 42071d10453SEric Joyner *num_branches = cmd->num_branches; 42171d10453SEric Joyner 42271d10453SEric Joyner return status; 42371d10453SEric Joyner } 42471d10453SEric Joyner 42571d10453SEric Joyner /** 42671d10453SEric Joyner * ice_aq_add_sched_elems - adds scheduling element 42771d10453SEric Joyner * @hw: pointer to the HW struct 42871d10453SEric Joyner * @grps_req: the number of groups that are requested to be added 42971d10453SEric Joyner * @buf: pointer to buffer 43071d10453SEric Joyner * @buf_size: buffer size in bytes 43171d10453SEric Joyner * @grps_added: returns total number of groups added 43271d10453SEric Joyner * @cd: pointer to command details structure or NULL 43371d10453SEric Joyner * 43471d10453SEric Joyner * Add scheduling elements (0x0401) 43571d10453SEric Joyner */ 436*f2635e84SEric Joyner static int 43771d10453SEric Joyner ice_aq_add_sched_elems(struct ice_hw *hw, u16 grps_req, 43871d10453SEric Joyner struct ice_aqc_add_elem *buf, u16 buf_size, 43971d10453SEric Joyner u16 *grps_added, struct ice_sq_cd *cd) 44071d10453SEric Joyner { 44171d10453SEric Joyner return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_add_sched_elems, 44271d10453SEric Joyner grps_req, (void *)buf, buf_size, 44371d10453SEric Joyner grps_added, cd); 44471d10453SEric Joyner } 44571d10453SEric Joyner 44671d10453SEric Joyner /** 44771d10453SEric Joyner * ice_aq_cfg_sched_elems - configures scheduler elements 44871d10453SEric Joyner * @hw: pointer to the HW struct 44971d10453SEric Joyner * @elems_req: number of elements to configure 45071d10453SEric Joyner * @buf: pointer to buffer 45171d10453SEric Joyner * @buf_size: buffer size in bytes 45271d10453SEric Joyner * @elems_cfgd: returns total number of elements configured 45371d10453SEric Joyner * @cd: pointer to command details structure or NULL 45471d10453SEric Joyner * 45571d10453SEric Joyner * Configure scheduling elements (0x0403) 45671d10453SEric Joyner */ 457*f2635e84SEric Joyner static int 45871d10453SEric Joyner ice_aq_cfg_sched_elems(struct ice_hw *hw, u16 elems_req, 4597d7af7f8SEric Joyner struct ice_aqc_txsched_elem_data *buf, u16 buf_size, 46071d10453SEric Joyner u16 *elems_cfgd, struct ice_sq_cd *cd) 46171d10453SEric Joyner { 46271d10453SEric Joyner return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_cfg_sched_elems, 46371d10453SEric Joyner elems_req, (void *)buf, buf_size, 46471d10453SEric Joyner elems_cfgd, cd); 46571d10453SEric Joyner } 46671d10453SEric Joyner 46771d10453SEric Joyner /** 46871d10453SEric Joyner * ice_aq_move_sched_elems - move scheduler elements 46971d10453SEric Joyner * @hw: pointer to the HW struct 47071d10453SEric Joyner * @grps_req: number of groups to move 47171d10453SEric Joyner * @buf: pointer to buffer 47271d10453SEric Joyner * @buf_size: buffer size in bytes 47371d10453SEric Joyner * @grps_movd: returns total number of groups moved 47471d10453SEric Joyner * @cd: pointer to command details structure or NULL 47571d10453SEric Joyner * 47671d10453SEric Joyner * Move scheduling elements (0x0408) 47771d10453SEric Joyner */ 478*f2635e84SEric Joyner int 47971d10453SEric Joyner ice_aq_move_sched_elems(struct ice_hw *hw, u16 grps_req, 48071d10453SEric Joyner struct ice_aqc_move_elem *buf, u16 buf_size, 48171d10453SEric Joyner u16 *grps_movd, struct ice_sq_cd *cd) 48271d10453SEric Joyner { 48371d10453SEric Joyner return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_move_sched_elems, 48471d10453SEric Joyner grps_req, (void *)buf, buf_size, 48571d10453SEric Joyner grps_movd, cd); 48671d10453SEric Joyner } 48771d10453SEric Joyner 48871d10453SEric Joyner /** 48971d10453SEric Joyner * ice_aq_suspend_sched_elems - suspend scheduler elements 49071d10453SEric Joyner * @hw: pointer to the HW struct 49171d10453SEric Joyner * @elems_req: number of elements to suspend 49271d10453SEric Joyner * @buf: pointer to buffer 49371d10453SEric Joyner * @buf_size: buffer size in bytes 49471d10453SEric Joyner * @elems_ret: returns total number of elements suspended 49571d10453SEric Joyner * @cd: pointer to command details structure or NULL 49671d10453SEric Joyner * 49771d10453SEric Joyner * Suspend scheduling elements (0x0409) 49871d10453SEric Joyner */ 499*f2635e84SEric Joyner static int 5007d7af7f8SEric Joyner ice_aq_suspend_sched_elems(struct ice_hw *hw, u16 elems_req, __le32 *buf, 50171d10453SEric Joyner u16 buf_size, u16 *elems_ret, struct ice_sq_cd *cd) 50271d10453SEric Joyner { 50371d10453SEric Joyner return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_suspend_sched_elems, 50471d10453SEric Joyner elems_req, (void *)buf, buf_size, 50571d10453SEric Joyner elems_ret, cd); 50671d10453SEric Joyner } 50771d10453SEric Joyner 50871d10453SEric Joyner /** 50971d10453SEric Joyner * ice_aq_resume_sched_elems - resume scheduler elements 51071d10453SEric Joyner * @hw: pointer to the HW struct 51171d10453SEric Joyner * @elems_req: number of elements to resume 51271d10453SEric Joyner * @buf: pointer to buffer 51371d10453SEric Joyner * @buf_size: buffer size in bytes 51471d10453SEric Joyner * @elems_ret: returns total number of elements resumed 51571d10453SEric Joyner * @cd: pointer to command details structure or NULL 51671d10453SEric Joyner * 51771d10453SEric Joyner * resume scheduling elements (0x040A) 51871d10453SEric Joyner */ 519*f2635e84SEric Joyner static int 5207d7af7f8SEric Joyner ice_aq_resume_sched_elems(struct ice_hw *hw, u16 elems_req, __le32 *buf, 52171d10453SEric Joyner u16 buf_size, u16 *elems_ret, struct ice_sq_cd *cd) 52271d10453SEric Joyner { 52371d10453SEric Joyner return ice_aqc_send_sched_elem_cmd(hw, ice_aqc_opc_resume_sched_elems, 52471d10453SEric Joyner elems_req, (void *)buf, buf_size, 52571d10453SEric Joyner elems_ret, cd); 52671d10453SEric Joyner } 52771d10453SEric Joyner 52871d10453SEric Joyner /** 52971d10453SEric Joyner * ice_aq_query_sched_res - query scheduler resource 53071d10453SEric Joyner * @hw: pointer to the HW struct 53171d10453SEric Joyner * @buf_size: buffer size in bytes 53271d10453SEric Joyner * @buf: pointer to buffer 53371d10453SEric Joyner * @cd: pointer to command details structure or NULL 53471d10453SEric Joyner * 53571d10453SEric Joyner * Query scheduler resource allocation (0x0412) 53671d10453SEric Joyner */ 537*f2635e84SEric Joyner static int 53871d10453SEric Joyner ice_aq_query_sched_res(struct ice_hw *hw, u16 buf_size, 53971d10453SEric Joyner struct ice_aqc_query_txsched_res_resp *buf, 54071d10453SEric Joyner struct ice_sq_cd *cd) 54171d10453SEric Joyner { 54271d10453SEric Joyner struct ice_aq_desc desc; 54371d10453SEric Joyner 54471d10453SEric Joyner ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_query_sched_res); 54571d10453SEric Joyner return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); 54671d10453SEric Joyner } 54771d10453SEric Joyner 54871d10453SEric Joyner /** 54971d10453SEric Joyner * ice_sched_suspend_resume_elems - suspend or resume HW nodes 55071d10453SEric Joyner * @hw: pointer to the HW struct 55171d10453SEric Joyner * @num_nodes: number of nodes 55271d10453SEric Joyner * @node_teids: array of node teids to be suspended or resumed 55371d10453SEric Joyner * @suspend: true means suspend / false means resume 55471d10453SEric Joyner * 55571d10453SEric Joyner * This function suspends or resumes HW nodes 55671d10453SEric Joyner */ 557*f2635e84SEric Joyner static int 55871d10453SEric Joyner ice_sched_suspend_resume_elems(struct ice_hw *hw, u8 num_nodes, u32 *node_teids, 55971d10453SEric Joyner bool suspend) 56071d10453SEric Joyner { 56171d10453SEric Joyner u16 i, buf_size, num_elem_ret = 0; 5627d7af7f8SEric Joyner __le32 *buf; 563*f2635e84SEric Joyner int status; 56471d10453SEric Joyner 56571d10453SEric Joyner buf_size = sizeof(*buf) * num_nodes; 5667d7af7f8SEric Joyner buf = (__le32 *)ice_malloc(hw, buf_size); 56771d10453SEric Joyner if (!buf) 56871d10453SEric Joyner return ICE_ERR_NO_MEMORY; 56971d10453SEric Joyner 57071d10453SEric Joyner for (i = 0; i < num_nodes; i++) 5717d7af7f8SEric Joyner buf[i] = CPU_TO_LE32(node_teids[i]); 57271d10453SEric Joyner 57371d10453SEric Joyner if (suspend) 57471d10453SEric Joyner status = ice_aq_suspend_sched_elems(hw, num_nodes, buf, 57571d10453SEric Joyner buf_size, &num_elem_ret, 57671d10453SEric Joyner NULL); 57771d10453SEric Joyner else 57871d10453SEric Joyner status = ice_aq_resume_sched_elems(hw, num_nodes, buf, 57971d10453SEric Joyner buf_size, &num_elem_ret, 58071d10453SEric Joyner NULL); 581*f2635e84SEric Joyner if (status || num_elem_ret != num_nodes) 58271d10453SEric Joyner ice_debug(hw, ICE_DBG_SCHED, "suspend/resume failed\n"); 58371d10453SEric Joyner 58471d10453SEric Joyner ice_free(hw, buf); 58571d10453SEric Joyner return status; 58671d10453SEric Joyner } 58771d10453SEric Joyner 58871d10453SEric Joyner /** 58971d10453SEric Joyner * ice_alloc_lan_q_ctx - allocate LAN queue contexts for the given VSI and TC 59071d10453SEric Joyner * @hw: pointer to the HW struct 59171d10453SEric Joyner * @vsi_handle: VSI handle 59271d10453SEric Joyner * @tc: TC number 59371d10453SEric Joyner * @new_numqs: number of queues 59471d10453SEric Joyner */ 595*f2635e84SEric Joyner static int 59671d10453SEric Joyner ice_alloc_lan_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 new_numqs) 59771d10453SEric Joyner { 59871d10453SEric Joyner struct ice_vsi_ctx *vsi_ctx; 59971d10453SEric Joyner struct ice_q_ctx *q_ctx; 60071d10453SEric Joyner 60171d10453SEric Joyner vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle); 60271d10453SEric Joyner if (!vsi_ctx) 60371d10453SEric Joyner return ICE_ERR_PARAM; 60471d10453SEric Joyner /* allocate LAN queue contexts */ 60571d10453SEric Joyner if (!vsi_ctx->lan_q_ctx[tc]) { 60671d10453SEric Joyner vsi_ctx->lan_q_ctx[tc] = (struct ice_q_ctx *) 60771d10453SEric Joyner ice_calloc(hw, new_numqs, sizeof(*q_ctx)); 60871d10453SEric Joyner if (!vsi_ctx->lan_q_ctx[tc]) 60971d10453SEric Joyner return ICE_ERR_NO_MEMORY; 61071d10453SEric Joyner vsi_ctx->num_lan_q_entries[tc] = new_numqs; 611*f2635e84SEric Joyner return 0; 61271d10453SEric Joyner } 61371d10453SEric Joyner /* num queues are increased, update the queue contexts */ 61471d10453SEric Joyner if (new_numqs > vsi_ctx->num_lan_q_entries[tc]) { 61571d10453SEric Joyner u16 prev_num = vsi_ctx->num_lan_q_entries[tc]; 61671d10453SEric Joyner 61771d10453SEric Joyner q_ctx = (struct ice_q_ctx *) 61871d10453SEric Joyner ice_calloc(hw, new_numqs, sizeof(*q_ctx)); 61971d10453SEric Joyner if (!q_ctx) 62071d10453SEric Joyner return ICE_ERR_NO_MEMORY; 62171d10453SEric Joyner ice_memcpy(q_ctx, vsi_ctx->lan_q_ctx[tc], 62271d10453SEric Joyner prev_num * sizeof(*q_ctx), ICE_DMA_TO_NONDMA); 62371d10453SEric Joyner ice_free(hw, vsi_ctx->lan_q_ctx[tc]); 62471d10453SEric Joyner vsi_ctx->lan_q_ctx[tc] = q_ctx; 62571d10453SEric Joyner vsi_ctx->num_lan_q_entries[tc] = new_numqs; 62671d10453SEric Joyner } 627*f2635e84SEric Joyner return 0; 62871d10453SEric Joyner } 62971d10453SEric Joyner 63071d10453SEric Joyner /** 6318a13362dSEric Joyner * ice_alloc_rdma_q_ctx - allocate RDMA queue contexts for the given VSI and TC 6328a13362dSEric Joyner * @hw: pointer to the HW struct 6338a13362dSEric Joyner * @vsi_handle: VSI handle 6348a13362dSEric Joyner * @tc: TC number 6358a13362dSEric Joyner * @new_numqs: number of queues 6368a13362dSEric Joyner */ 637*f2635e84SEric Joyner static int 6388a13362dSEric Joyner ice_alloc_rdma_q_ctx(struct ice_hw *hw, u16 vsi_handle, u8 tc, u16 new_numqs) 6398a13362dSEric Joyner { 6408a13362dSEric Joyner struct ice_vsi_ctx *vsi_ctx; 6418a13362dSEric Joyner struct ice_q_ctx *q_ctx; 6428a13362dSEric Joyner 6438a13362dSEric Joyner vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle); 6448a13362dSEric Joyner if (!vsi_ctx) 6458a13362dSEric Joyner return ICE_ERR_PARAM; 6468a13362dSEric Joyner /* allocate RDMA queue contexts */ 6478a13362dSEric Joyner if (!vsi_ctx->rdma_q_ctx[tc]) { 6488a13362dSEric Joyner vsi_ctx->rdma_q_ctx[tc] = (struct ice_q_ctx *) 6498a13362dSEric Joyner ice_calloc(hw, new_numqs, sizeof(*q_ctx)); 6508a13362dSEric Joyner if (!vsi_ctx->rdma_q_ctx[tc]) 6518a13362dSEric Joyner return ICE_ERR_NO_MEMORY; 6528a13362dSEric Joyner vsi_ctx->num_rdma_q_entries[tc] = new_numqs; 653*f2635e84SEric Joyner return 0; 6548a13362dSEric Joyner } 6558a13362dSEric Joyner /* num queues are increased, update the queue contexts */ 6568a13362dSEric Joyner if (new_numqs > vsi_ctx->num_rdma_q_entries[tc]) { 6578a13362dSEric Joyner u16 prev_num = vsi_ctx->num_rdma_q_entries[tc]; 6588a13362dSEric Joyner 6598a13362dSEric Joyner q_ctx = (struct ice_q_ctx *) 6608a13362dSEric Joyner ice_calloc(hw, new_numqs, sizeof(*q_ctx)); 6618a13362dSEric Joyner if (!q_ctx) 6628a13362dSEric Joyner return ICE_ERR_NO_MEMORY; 6638a13362dSEric Joyner ice_memcpy(q_ctx, vsi_ctx->rdma_q_ctx[tc], 6648a13362dSEric Joyner prev_num * sizeof(*q_ctx), ICE_DMA_TO_NONDMA); 6658a13362dSEric Joyner ice_free(hw, vsi_ctx->rdma_q_ctx[tc]); 6668a13362dSEric Joyner vsi_ctx->rdma_q_ctx[tc] = q_ctx; 6678a13362dSEric Joyner vsi_ctx->num_rdma_q_entries[tc] = new_numqs; 6688a13362dSEric Joyner } 669*f2635e84SEric Joyner return 0; 6708a13362dSEric Joyner } 6718a13362dSEric Joyner 6728a13362dSEric Joyner /** 67371d10453SEric Joyner * ice_aq_rl_profile - performs a rate limiting task 67471d10453SEric Joyner * @hw: pointer to the HW struct 67571d10453SEric Joyner * @opcode: opcode for add, query, or remove profile(s) 67671d10453SEric Joyner * @num_profiles: the number of profiles 67771d10453SEric Joyner * @buf: pointer to buffer 67871d10453SEric Joyner * @buf_size: buffer size in bytes 67971d10453SEric Joyner * @num_processed: number of processed add or remove profile(s) to return 68071d10453SEric Joyner * @cd: pointer to command details structure 68171d10453SEric Joyner * 6827d7af7f8SEric Joyner * RL profile function to add, query, or remove profile(s) 68371d10453SEric Joyner */ 684*f2635e84SEric Joyner static int 68571d10453SEric Joyner ice_aq_rl_profile(struct ice_hw *hw, enum ice_adminq_opc opcode, 6867d7af7f8SEric Joyner u16 num_profiles, struct ice_aqc_rl_profile_elem *buf, 68771d10453SEric Joyner u16 buf_size, u16 *num_processed, struct ice_sq_cd *cd) 68871d10453SEric Joyner { 68971d10453SEric Joyner struct ice_aqc_rl_profile *cmd; 69071d10453SEric Joyner struct ice_aq_desc desc; 691*f2635e84SEric Joyner int status; 69271d10453SEric Joyner 69371d10453SEric Joyner cmd = &desc.params.rl_profile; 69471d10453SEric Joyner 69571d10453SEric Joyner ice_fill_dflt_direct_cmd_desc(&desc, opcode); 69671d10453SEric Joyner desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD); 69771d10453SEric Joyner cmd->num_profiles = CPU_TO_LE16(num_profiles); 69871d10453SEric Joyner status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); 69971d10453SEric Joyner if (!status && num_processed) 70071d10453SEric Joyner *num_processed = LE16_TO_CPU(cmd->num_processed); 70171d10453SEric Joyner return status; 70271d10453SEric Joyner } 70371d10453SEric Joyner 70471d10453SEric Joyner /** 70571d10453SEric Joyner * ice_aq_add_rl_profile - adds rate limiting profile(s) 70671d10453SEric Joyner * @hw: pointer to the HW struct 70771d10453SEric Joyner * @num_profiles: the number of profile(s) to be add 70871d10453SEric Joyner * @buf: pointer to buffer 70971d10453SEric Joyner * @buf_size: buffer size in bytes 71071d10453SEric Joyner * @num_profiles_added: total number of profiles added to return 71171d10453SEric Joyner * @cd: pointer to command details structure 71271d10453SEric Joyner * 71371d10453SEric Joyner * Add RL profile (0x0410) 71471d10453SEric Joyner */ 715*f2635e84SEric Joyner static int 71671d10453SEric Joyner ice_aq_add_rl_profile(struct ice_hw *hw, u16 num_profiles, 7177d7af7f8SEric Joyner struct ice_aqc_rl_profile_elem *buf, u16 buf_size, 7187d7af7f8SEric Joyner u16 *num_profiles_added, struct ice_sq_cd *cd) 71971d10453SEric Joyner { 7207d7af7f8SEric Joyner return ice_aq_rl_profile(hw, ice_aqc_opc_add_rl_profiles, num_profiles, 7217d7af7f8SEric Joyner buf, buf_size, num_profiles_added, cd); 72271d10453SEric Joyner } 72371d10453SEric Joyner 72471d10453SEric Joyner /** 72571d10453SEric Joyner * ice_aq_query_rl_profile - query rate limiting profile(s) 72671d10453SEric Joyner * @hw: pointer to the HW struct 72771d10453SEric Joyner * @num_profiles: the number of profile(s) to query 72871d10453SEric Joyner * @buf: pointer to buffer 72971d10453SEric Joyner * @buf_size: buffer size in bytes 73071d10453SEric Joyner * @cd: pointer to command details structure 73171d10453SEric Joyner * 73271d10453SEric Joyner * Query RL profile (0x0411) 73371d10453SEric Joyner */ 734*f2635e84SEric Joyner int 73571d10453SEric Joyner ice_aq_query_rl_profile(struct ice_hw *hw, u16 num_profiles, 7367d7af7f8SEric Joyner struct ice_aqc_rl_profile_elem *buf, u16 buf_size, 7377d7af7f8SEric Joyner struct ice_sq_cd *cd) 73871d10453SEric Joyner { 73971d10453SEric Joyner return ice_aq_rl_profile(hw, ice_aqc_opc_query_rl_profiles, 74071d10453SEric Joyner num_profiles, buf, buf_size, NULL, cd); 74171d10453SEric Joyner } 74271d10453SEric Joyner 74371d10453SEric Joyner /** 74471d10453SEric Joyner * ice_aq_remove_rl_profile - removes RL profile(s) 74571d10453SEric Joyner * @hw: pointer to the HW struct 74671d10453SEric Joyner * @num_profiles: the number of profile(s) to remove 74771d10453SEric Joyner * @buf: pointer to buffer 74871d10453SEric Joyner * @buf_size: buffer size in bytes 74971d10453SEric Joyner * @num_profiles_removed: total number of profiles removed to return 75071d10453SEric Joyner * @cd: pointer to command details structure or NULL 75171d10453SEric Joyner * 75271d10453SEric Joyner * Remove RL profile (0x0415) 75371d10453SEric Joyner */ 754*f2635e84SEric Joyner static int 75571d10453SEric Joyner ice_aq_remove_rl_profile(struct ice_hw *hw, u16 num_profiles, 7567d7af7f8SEric Joyner struct ice_aqc_rl_profile_elem *buf, u16 buf_size, 7577d7af7f8SEric Joyner u16 *num_profiles_removed, struct ice_sq_cd *cd) 75871d10453SEric Joyner { 75971d10453SEric Joyner return ice_aq_rl_profile(hw, ice_aqc_opc_remove_rl_profiles, 7607d7af7f8SEric Joyner num_profiles, buf, buf_size, 7617d7af7f8SEric Joyner num_profiles_removed, cd); 76271d10453SEric Joyner } 76371d10453SEric Joyner 76471d10453SEric Joyner /** 76571d10453SEric Joyner * ice_sched_del_rl_profile - remove RL profile 76671d10453SEric Joyner * @hw: pointer to the HW struct 76771d10453SEric Joyner * @rl_info: rate limit profile information 76871d10453SEric Joyner * 76971d10453SEric Joyner * If the profile ID is not referenced anymore, it removes profile ID with 77071d10453SEric Joyner * its associated parameters from HW DB,and locally. The caller needs to 77171d10453SEric Joyner * hold scheduler lock. 77271d10453SEric Joyner */ 773*f2635e84SEric Joyner static int 77471d10453SEric Joyner ice_sched_del_rl_profile(struct ice_hw *hw, 77571d10453SEric Joyner struct ice_aqc_rl_profile_info *rl_info) 77671d10453SEric Joyner { 7777d7af7f8SEric Joyner struct ice_aqc_rl_profile_elem *buf; 77871d10453SEric Joyner u16 num_profiles_removed; 77971d10453SEric Joyner u16 num_profiles = 1; 780*f2635e84SEric Joyner int status; 78171d10453SEric Joyner 78271d10453SEric Joyner if (rl_info->prof_id_ref != 0) 78371d10453SEric Joyner return ICE_ERR_IN_USE; 78471d10453SEric Joyner 78571d10453SEric Joyner /* Safe to remove profile ID */ 7867d7af7f8SEric Joyner buf = &rl_info->profile; 78771d10453SEric Joyner status = ice_aq_remove_rl_profile(hw, num_profiles, buf, sizeof(*buf), 78871d10453SEric Joyner &num_profiles_removed, NULL); 78971d10453SEric Joyner if (status || num_profiles_removed != num_profiles) 79071d10453SEric Joyner return ICE_ERR_CFG; 79171d10453SEric Joyner 79271d10453SEric Joyner /* Delete stale entry now */ 79371d10453SEric Joyner LIST_DEL(&rl_info->list_entry); 79471d10453SEric Joyner ice_free(hw, rl_info); 79571d10453SEric Joyner return status; 79671d10453SEric Joyner } 79771d10453SEric Joyner 79871d10453SEric Joyner /** 79971d10453SEric Joyner * ice_sched_clear_rl_prof - clears RL prof entries 80071d10453SEric Joyner * @pi: port information structure 80171d10453SEric Joyner * 80271d10453SEric Joyner * This function removes all RL profile from HW as well as from SW DB. 80371d10453SEric Joyner */ 80471d10453SEric Joyner static void ice_sched_clear_rl_prof(struct ice_port_info *pi) 80571d10453SEric Joyner { 80671d10453SEric Joyner u16 ln; 807d08b8680SEric Joyner struct ice_hw *hw = pi->hw; 80871d10453SEric Joyner 809d08b8680SEric Joyner for (ln = 0; ln < hw->num_tx_sched_layers; ln++) { 81071d10453SEric Joyner struct ice_aqc_rl_profile_info *rl_prof_elem; 81171d10453SEric Joyner struct ice_aqc_rl_profile_info *rl_prof_tmp; 81271d10453SEric Joyner 81371d10453SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(rl_prof_elem, rl_prof_tmp, 814d08b8680SEric Joyner &hw->rl_prof_list[ln], 81571d10453SEric Joyner ice_aqc_rl_profile_info, list_entry) { 816*f2635e84SEric Joyner int status; 81771d10453SEric Joyner 81871d10453SEric Joyner rl_prof_elem->prof_id_ref = 0; 81971d10453SEric Joyner status = ice_sched_del_rl_profile(hw, rl_prof_elem); 82071d10453SEric Joyner if (status) { 8217d7af7f8SEric Joyner ice_debug(hw, ICE_DBG_SCHED, "Remove rl profile failed\n"); 82271d10453SEric Joyner /* On error, free mem required */ 82371d10453SEric Joyner LIST_DEL(&rl_prof_elem->list_entry); 82471d10453SEric Joyner ice_free(hw, rl_prof_elem); 82571d10453SEric Joyner } 82671d10453SEric Joyner } 82771d10453SEric Joyner } 82871d10453SEric Joyner } 82971d10453SEric Joyner 83071d10453SEric Joyner /** 83171d10453SEric Joyner * ice_sched_clear_agg - clears the aggregator related information 83271d10453SEric Joyner * @hw: pointer to the hardware structure 83371d10453SEric Joyner * 83471d10453SEric Joyner * This function removes aggregator list and free up aggregator related memory 83571d10453SEric Joyner * previously allocated. 83671d10453SEric Joyner */ 83771d10453SEric Joyner void ice_sched_clear_agg(struct ice_hw *hw) 83871d10453SEric Joyner { 83971d10453SEric Joyner struct ice_sched_agg_info *agg_info; 84071d10453SEric Joyner struct ice_sched_agg_info *atmp; 84171d10453SEric Joyner 84271d10453SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(agg_info, atmp, &hw->agg_list, 84371d10453SEric Joyner ice_sched_agg_info, 84471d10453SEric Joyner list_entry) { 84571d10453SEric Joyner struct ice_sched_agg_vsi_info *agg_vsi_info; 84671d10453SEric Joyner struct ice_sched_agg_vsi_info *vtmp; 84771d10453SEric Joyner 84871d10453SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(agg_vsi_info, vtmp, 84971d10453SEric Joyner &agg_info->agg_vsi_list, 85071d10453SEric Joyner ice_sched_agg_vsi_info, list_entry) { 85171d10453SEric Joyner LIST_DEL(&agg_vsi_info->list_entry); 85271d10453SEric Joyner ice_free(hw, agg_vsi_info); 85371d10453SEric Joyner } 85471d10453SEric Joyner LIST_DEL(&agg_info->list_entry); 85571d10453SEric Joyner ice_free(hw, agg_info); 85671d10453SEric Joyner } 85771d10453SEric Joyner } 85871d10453SEric Joyner 85971d10453SEric Joyner /** 8607d7af7f8SEric Joyner * ice_sched_clear_tx_topo - clears the scheduler tree nodes 86171d10453SEric Joyner * @pi: port information structure 86271d10453SEric Joyner * 86371d10453SEric Joyner * This function removes all the nodes from HW as well as from SW DB. 86471d10453SEric Joyner */ 86571d10453SEric Joyner static void ice_sched_clear_tx_topo(struct ice_port_info *pi) 86671d10453SEric Joyner { 86771d10453SEric Joyner if (!pi) 86871d10453SEric Joyner return; 86971d10453SEric Joyner /* remove RL profiles related lists */ 87071d10453SEric Joyner ice_sched_clear_rl_prof(pi); 87171d10453SEric Joyner if (pi->root) { 87271d10453SEric Joyner ice_free_sched_node(pi, pi->root); 87371d10453SEric Joyner pi->root = NULL; 87471d10453SEric Joyner } 87571d10453SEric Joyner } 87671d10453SEric Joyner 87771d10453SEric Joyner /** 87871d10453SEric Joyner * ice_sched_clear_port - clear the scheduler elements from SW DB for a port 87971d10453SEric Joyner * @pi: port information structure 88071d10453SEric Joyner * 88171d10453SEric Joyner * Cleanup scheduling elements from SW DB 88271d10453SEric Joyner */ 88371d10453SEric Joyner void ice_sched_clear_port(struct ice_port_info *pi) 88471d10453SEric Joyner { 88571d10453SEric Joyner if (!pi || pi->port_state != ICE_SCHED_PORT_STATE_READY) 88671d10453SEric Joyner return; 88771d10453SEric Joyner 88871d10453SEric Joyner pi->port_state = ICE_SCHED_PORT_STATE_INIT; 88971d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 89071d10453SEric Joyner ice_sched_clear_tx_topo(pi); 89171d10453SEric Joyner ice_release_lock(&pi->sched_lock); 89271d10453SEric Joyner ice_destroy_lock(&pi->sched_lock); 89371d10453SEric Joyner } 89471d10453SEric Joyner 89571d10453SEric Joyner /** 89671d10453SEric Joyner * ice_sched_cleanup_all - cleanup scheduler elements from SW DB for all ports 89771d10453SEric Joyner * @hw: pointer to the HW struct 89871d10453SEric Joyner * 89971d10453SEric Joyner * Cleanup scheduling elements from SW DB for all the ports 90071d10453SEric Joyner */ 90171d10453SEric Joyner void ice_sched_cleanup_all(struct ice_hw *hw) 90271d10453SEric Joyner { 90371d10453SEric Joyner if (!hw) 90471d10453SEric Joyner return; 90571d10453SEric Joyner 90671d10453SEric Joyner if (hw->layer_info) { 90771d10453SEric Joyner ice_free(hw, hw->layer_info); 90871d10453SEric Joyner hw->layer_info = NULL; 90971d10453SEric Joyner } 91071d10453SEric Joyner 91171d10453SEric Joyner ice_sched_clear_port(hw->port_info); 91271d10453SEric Joyner 91371d10453SEric Joyner hw->num_tx_sched_layers = 0; 91471d10453SEric Joyner hw->num_tx_sched_phys_layers = 0; 91571d10453SEric Joyner hw->flattened_layers = 0; 91671d10453SEric Joyner hw->max_cgds = 0; 91771d10453SEric Joyner } 91871d10453SEric Joyner 91971d10453SEric Joyner /** 9208923de59SPiotr Kubaj * ice_aq_cfg_node_attr - configure nodes' per-cone flattening attributes 9218923de59SPiotr Kubaj * @hw: pointer to the HW struct 9228923de59SPiotr Kubaj * @num_nodes: the number of nodes whose attributes to configure 9238923de59SPiotr Kubaj * @buf: pointer to buffer 9248923de59SPiotr Kubaj * @buf_size: buffer size in bytes 9258923de59SPiotr Kubaj * @cd: pointer to command details structure or NULL 9268923de59SPiotr Kubaj * 9278923de59SPiotr Kubaj * Configure Node Attributes (0x0417) 9288923de59SPiotr Kubaj */ 929*f2635e84SEric Joyner int 9308923de59SPiotr Kubaj ice_aq_cfg_node_attr(struct ice_hw *hw, u16 num_nodes, 9318923de59SPiotr Kubaj struct ice_aqc_node_attr_elem *buf, u16 buf_size, 9328923de59SPiotr Kubaj struct ice_sq_cd *cd) 9338923de59SPiotr Kubaj { 9348923de59SPiotr Kubaj struct ice_aqc_node_attr *cmd; 9358923de59SPiotr Kubaj struct ice_aq_desc desc; 9368923de59SPiotr Kubaj 9378923de59SPiotr Kubaj cmd = &desc.params.node_attr; 9388923de59SPiotr Kubaj ice_fill_dflt_direct_cmd_desc(&desc, 9398923de59SPiotr Kubaj ice_aqc_opc_cfg_node_attr); 9408923de59SPiotr Kubaj desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD); 9418923de59SPiotr Kubaj 9428923de59SPiotr Kubaj cmd->num_entries = CPU_TO_LE16(num_nodes); 9438923de59SPiotr Kubaj return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); 9448923de59SPiotr Kubaj } 9458923de59SPiotr Kubaj 9468923de59SPiotr Kubaj /** 94771d10453SEric Joyner * ice_aq_cfg_l2_node_cgd - configures L2 node to CGD mapping 94871d10453SEric Joyner * @hw: pointer to the HW struct 94971d10453SEric Joyner * @num_l2_nodes: the number of L2 nodes whose CGDs to configure 95071d10453SEric Joyner * @buf: pointer to buffer 95171d10453SEric Joyner * @buf_size: buffer size in bytes 95271d10453SEric Joyner * @cd: pointer to command details structure or NULL 95371d10453SEric Joyner * 95471d10453SEric Joyner * Configure L2 Node CGD (0x0414) 95571d10453SEric Joyner */ 956*f2635e84SEric Joyner int 95771d10453SEric Joyner ice_aq_cfg_l2_node_cgd(struct ice_hw *hw, u16 num_l2_nodes, 9587d7af7f8SEric Joyner struct ice_aqc_cfg_l2_node_cgd_elem *buf, 95971d10453SEric Joyner u16 buf_size, struct ice_sq_cd *cd) 96071d10453SEric Joyner { 96171d10453SEric Joyner struct ice_aqc_cfg_l2_node_cgd *cmd; 96271d10453SEric Joyner struct ice_aq_desc desc; 96371d10453SEric Joyner 96471d10453SEric Joyner cmd = &desc.params.cfg_l2_node_cgd; 96571d10453SEric Joyner ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_cfg_l2_node_cgd); 96671d10453SEric Joyner desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD); 96771d10453SEric Joyner 96871d10453SEric Joyner cmd->num_l2_nodes = CPU_TO_LE16(num_l2_nodes); 96971d10453SEric Joyner return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); 97071d10453SEric Joyner } 97171d10453SEric Joyner 97271d10453SEric Joyner /** 97371d10453SEric Joyner * ice_sched_add_elems - add nodes to HW and SW DB 97471d10453SEric Joyner * @pi: port information structure 97571d10453SEric Joyner * @tc_node: pointer to the branch node 97671d10453SEric Joyner * @parent: pointer to the parent node 97771d10453SEric Joyner * @layer: layer number to add nodes 97871d10453SEric Joyner * @num_nodes: number of nodes 97971d10453SEric Joyner * @num_nodes_added: pointer to num nodes added 98071d10453SEric Joyner * @first_node_teid: if new nodes are added then return the TEID of first node 9819c30461dSEric Joyner * @prealloc_nodes: preallocated nodes struct for software DB 98271d10453SEric Joyner * 98371d10453SEric Joyner * This function add nodes to HW as well as to SW DB for a given layer 98471d10453SEric Joyner */ 985*f2635e84SEric Joyner int 98671d10453SEric Joyner ice_sched_add_elems(struct ice_port_info *pi, struct ice_sched_node *tc_node, 98771d10453SEric Joyner struct ice_sched_node *parent, u8 layer, u16 num_nodes, 9889c30461dSEric Joyner u16 *num_nodes_added, u32 *first_node_teid, 9899c30461dSEric Joyner struct ice_sched_node **prealloc_nodes) 99071d10453SEric Joyner { 99171d10453SEric Joyner struct ice_sched_node *prev, *new_node; 99271d10453SEric Joyner struct ice_aqc_add_elem *buf; 99371d10453SEric Joyner u16 i, num_groups_added = 0; 99471d10453SEric Joyner struct ice_hw *hw = pi->hw; 995*f2635e84SEric Joyner int status = 0; 99671d10453SEric Joyner u16 buf_size; 99771d10453SEric Joyner u32 teid; 99871d10453SEric Joyner 9997d7af7f8SEric Joyner buf_size = ice_struct_size(buf, generic, num_nodes); 100071d10453SEric Joyner buf = (struct ice_aqc_add_elem *)ice_malloc(hw, buf_size); 100171d10453SEric Joyner if (!buf) 100271d10453SEric Joyner return ICE_ERR_NO_MEMORY; 100371d10453SEric Joyner 100471d10453SEric Joyner buf->hdr.parent_teid = parent->info.node_teid; 100571d10453SEric Joyner buf->hdr.num_elems = CPU_TO_LE16(num_nodes); 100671d10453SEric Joyner for (i = 0; i < num_nodes; i++) { 100771d10453SEric Joyner buf->generic[i].parent_teid = parent->info.node_teid; 100871d10453SEric Joyner buf->generic[i].data.elem_type = ICE_AQC_ELEM_TYPE_SE_GENERIC; 100971d10453SEric Joyner buf->generic[i].data.valid_sections = 101071d10453SEric Joyner ICE_AQC_ELEM_VALID_GENERIC | ICE_AQC_ELEM_VALID_CIR | 101171d10453SEric Joyner ICE_AQC_ELEM_VALID_EIR; 101271d10453SEric Joyner buf->generic[i].data.generic = 0; 101371d10453SEric Joyner buf->generic[i].data.cir_bw.bw_profile_idx = 101471d10453SEric Joyner CPU_TO_LE16(ICE_SCHED_DFLT_RL_PROF_ID); 101571d10453SEric Joyner buf->generic[i].data.cir_bw.bw_alloc = 101671d10453SEric Joyner CPU_TO_LE16(ICE_SCHED_DFLT_BW_WT); 101771d10453SEric Joyner buf->generic[i].data.eir_bw.bw_profile_idx = 101871d10453SEric Joyner CPU_TO_LE16(ICE_SCHED_DFLT_RL_PROF_ID); 101971d10453SEric Joyner buf->generic[i].data.eir_bw.bw_alloc = 102071d10453SEric Joyner CPU_TO_LE16(ICE_SCHED_DFLT_BW_WT); 102171d10453SEric Joyner } 102271d10453SEric Joyner 102371d10453SEric Joyner status = ice_aq_add_sched_elems(hw, 1, buf, buf_size, 102471d10453SEric Joyner &num_groups_added, NULL); 1025*f2635e84SEric Joyner if (status || num_groups_added != 1) { 102671d10453SEric Joyner ice_debug(hw, ICE_DBG_SCHED, "add node failed FW Error %d\n", 102771d10453SEric Joyner hw->adminq.sq_last_status); 102871d10453SEric Joyner ice_free(hw, buf); 102971d10453SEric Joyner return ICE_ERR_CFG; 103071d10453SEric Joyner } 103171d10453SEric Joyner 103271d10453SEric Joyner *num_nodes_added = num_nodes; 103371d10453SEric Joyner /* add nodes to the SW DB */ 103471d10453SEric Joyner for (i = 0; i < num_nodes; i++) { 10359c30461dSEric Joyner if (prealloc_nodes) 10369c30461dSEric Joyner status = ice_sched_add_node(pi, layer, &buf->generic[i], prealloc_nodes[i]); 10379c30461dSEric Joyner else 10389c30461dSEric Joyner status = ice_sched_add_node(pi, layer, &buf->generic[i], NULL); 10399c30461dSEric Joyner 1040*f2635e84SEric Joyner if (status) { 10417d7af7f8SEric Joyner ice_debug(hw, ICE_DBG_SCHED, "add nodes in SW DB failed status =%d\n", 104271d10453SEric Joyner status); 104371d10453SEric Joyner break; 104471d10453SEric Joyner } 104571d10453SEric Joyner 104671d10453SEric Joyner teid = LE32_TO_CPU(buf->generic[i].node_teid); 104771d10453SEric Joyner new_node = ice_sched_find_node_by_teid(parent, teid); 104871d10453SEric Joyner if (!new_node) { 10497d7af7f8SEric Joyner ice_debug(hw, ICE_DBG_SCHED, "Node is missing for teid =%d\n", teid); 105071d10453SEric Joyner break; 105171d10453SEric Joyner } 105271d10453SEric Joyner 105371d10453SEric Joyner new_node->sibling = NULL; 105471d10453SEric Joyner new_node->tc_num = tc_node->tc_num; 105571d10453SEric Joyner 105671d10453SEric Joyner /* add it to previous node sibling pointer */ 105771d10453SEric Joyner /* Note: siblings are not linked across branches */ 105871d10453SEric Joyner prev = ice_sched_get_first_node(pi, tc_node, layer); 105971d10453SEric Joyner if (prev && prev != new_node) { 106071d10453SEric Joyner while (prev->sibling) 106171d10453SEric Joyner prev = prev->sibling; 106271d10453SEric Joyner prev->sibling = new_node; 106371d10453SEric Joyner } 106471d10453SEric Joyner 106571d10453SEric Joyner /* initialize the sibling head */ 106671d10453SEric Joyner if (!pi->sib_head[tc_node->tc_num][layer]) 106771d10453SEric Joyner pi->sib_head[tc_node->tc_num][layer] = new_node; 106871d10453SEric Joyner 106971d10453SEric Joyner if (i == 0) 107071d10453SEric Joyner *first_node_teid = teid; 107171d10453SEric Joyner } 107271d10453SEric Joyner 107371d10453SEric Joyner ice_free(hw, buf); 107471d10453SEric Joyner return status; 107571d10453SEric Joyner } 107671d10453SEric Joyner 107771d10453SEric Joyner /** 10789cf1841cSEric Joyner * ice_sched_add_nodes_to_hw_layer - Add nodes to hw layer 10799cf1841cSEric Joyner * @pi: port information structure 10809cf1841cSEric Joyner * @tc_node: pointer to TC node 10819cf1841cSEric Joyner * @parent: pointer to parent node 10829cf1841cSEric Joyner * @layer: layer number to add nodes 10839cf1841cSEric Joyner * @num_nodes: number of nodes to be added 10849cf1841cSEric Joyner * @first_node_teid: pointer to the first node TEID 10859cf1841cSEric Joyner * @num_nodes_added: pointer to number of nodes added 10869cf1841cSEric Joyner * 10879cf1841cSEric Joyner * Add nodes into specific hw layer. 10889cf1841cSEric Joyner */ 1089*f2635e84SEric Joyner static int 10909cf1841cSEric Joyner ice_sched_add_nodes_to_hw_layer(struct ice_port_info *pi, 10919cf1841cSEric Joyner struct ice_sched_node *tc_node, 10929cf1841cSEric Joyner struct ice_sched_node *parent, u8 layer, 10939cf1841cSEric Joyner u16 num_nodes, u32 *first_node_teid, 10949cf1841cSEric Joyner u16 *num_nodes_added) 10959cf1841cSEric Joyner { 10969cf1841cSEric Joyner u16 max_child_nodes; 10979cf1841cSEric Joyner 10989cf1841cSEric Joyner *num_nodes_added = 0; 10999cf1841cSEric Joyner 11009cf1841cSEric Joyner if (!num_nodes) 1101*f2635e84SEric Joyner return 0; 11029cf1841cSEric Joyner 11039cf1841cSEric Joyner if (!parent || layer < pi->hw->sw_entry_point_layer) 11049cf1841cSEric Joyner return ICE_ERR_PARAM; 11059cf1841cSEric Joyner 11069cf1841cSEric Joyner /* max children per node per layer */ 11079cf1841cSEric Joyner max_child_nodes = pi->hw->max_children[parent->tx_sched_layer]; 11089cf1841cSEric Joyner 11099cf1841cSEric Joyner /* current number of children + required nodes exceed max children */ 11109cf1841cSEric Joyner if ((parent->num_children + num_nodes) > max_child_nodes) { 11119cf1841cSEric Joyner /* Fail if the parent is a TC node */ 11129cf1841cSEric Joyner if (parent == tc_node) 11139cf1841cSEric Joyner return ICE_ERR_CFG; 11149cf1841cSEric Joyner return ICE_ERR_MAX_LIMIT; 11159cf1841cSEric Joyner } 11169cf1841cSEric Joyner 11179cf1841cSEric Joyner return ice_sched_add_elems(pi, tc_node, parent, layer, num_nodes, 11189c30461dSEric Joyner num_nodes_added, first_node_teid, NULL); 11199cf1841cSEric Joyner } 11209cf1841cSEric Joyner 11219cf1841cSEric Joyner /** 112271d10453SEric Joyner * ice_sched_add_nodes_to_layer - Add nodes to a given layer 112371d10453SEric Joyner * @pi: port information structure 112471d10453SEric Joyner * @tc_node: pointer to TC node 112571d10453SEric Joyner * @parent: pointer to parent node 112671d10453SEric Joyner * @layer: layer number to add nodes 112771d10453SEric Joyner * @num_nodes: number of nodes to be added 112871d10453SEric Joyner * @first_node_teid: pointer to the first node TEID 112971d10453SEric Joyner * @num_nodes_added: pointer to number of nodes added 113071d10453SEric Joyner * 113171d10453SEric Joyner * This function add nodes to a given layer. 113271d10453SEric Joyner */ 1133*f2635e84SEric Joyner static int 113471d10453SEric Joyner ice_sched_add_nodes_to_layer(struct ice_port_info *pi, 113571d10453SEric Joyner struct ice_sched_node *tc_node, 113671d10453SEric Joyner struct ice_sched_node *parent, u8 layer, 113771d10453SEric Joyner u16 num_nodes, u32 *first_node_teid, 113871d10453SEric Joyner u16 *num_nodes_added) 113971d10453SEric Joyner { 114071d10453SEric Joyner u32 *first_teid_ptr = first_node_teid; 11419cf1841cSEric Joyner u16 new_num_nodes = num_nodes; 1142*f2635e84SEric Joyner int status = 0; 11439c30461dSEric Joyner u32 temp; 114471d10453SEric Joyner 114571d10453SEric Joyner *num_nodes_added = 0; 11469cf1841cSEric Joyner while (*num_nodes_added < num_nodes) { 11479cf1841cSEric Joyner u16 max_child_nodes, num_added = 0; 114871d10453SEric Joyner 11499cf1841cSEric Joyner status = ice_sched_add_nodes_to_hw_layer(pi, tc_node, parent, 11509cf1841cSEric Joyner layer, new_num_nodes, 11519cf1841cSEric Joyner first_teid_ptr, 11529cf1841cSEric Joyner &num_added); 1153*f2635e84SEric Joyner if (!status) 11549cf1841cSEric Joyner *num_nodes_added += num_added; 11559cf1841cSEric Joyner /* added more nodes than requested ? */ 11569cf1841cSEric Joyner if (*num_nodes_added > num_nodes) { 11579cf1841cSEric Joyner ice_debug(pi->hw, ICE_DBG_SCHED, "added extra nodes %d %d\n", num_nodes, 11589cf1841cSEric Joyner *num_nodes_added); 11599cf1841cSEric Joyner status = ICE_ERR_CFG; 11609cf1841cSEric Joyner break; 11619cf1841cSEric Joyner } 11629cf1841cSEric Joyner /* break if all the nodes are added successfully */ 1163*f2635e84SEric Joyner if (!status && (*num_nodes_added == num_nodes)) 11649cf1841cSEric Joyner break; 11659cf1841cSEric Joyner /* break if the error is not max limit */ 1166*f2635e84SEric Joyner if (status && status != ICE_ERR_MAX_LIMIT) 11679cf1841cSEric Joyner break; 11689cf1841cSEric Joyner /* Exceeded the max children */ 11699cf1841cSEric Joyner max_child_nodes = pi->hw->max_children[parent->tx_sched_layer]; 117071d10453SEric Joyner /* utilize all the spaces if the parent is not full */ 117171d10453SEric Joyner if (parent->num_children < max_child_nodes) { 117271d10453SEric Joyner new_num_nodes = max_child_nodes - parent->num_children; 11739cf1841cSEric Joyner } else { 11749cf1841cSEric Joyner /* This parent is full, try the next sibling */ 11759cf1841cSEric Joyner parent = parent->sibling; 11769cf1841cSEric Joyner /* Don't modify the first node TEID memory if the 11779cf1841cSEric Joyner * first node was added already in the above call. 11789cf1841cSEric Joyner * Instead send some temp memory for all other 11799cf1841cSEric Joyner * recursive calls. 118071d10453SEric Joyner */ 118171d10453SEric Joyner if (num_added) 118271d10453SEric Joyner first_teid_ptr = &temp; 118371d10453SEric Joyner 11849cf1841cSEric Joyner new_num_nodes = num_nodes - *num_nodes_added; 118571d10453SEric Joyner } 11869cf1841cSEric Joyner } 118771d10453SEric Joyner return status; 118871d10453SEric Joyner } 118971d10453SEric Joyner 119071d10453SEric Joyner /** 119171d10453SEric Joyner * ice_sched_get_qgrp_layer - get the current queue group layer number 119271d10453SEric Joyner * @hw: pointer to the HW struct 119371d10453SEric Joyner * 119471d10453SEric Joyner * This function returns the current queue group layer number 119571d10453SEric Joyner */ 119671d10453SEric Joyner static u8 ice_sched_get_qgrp_layer(struct ice_hw *hw) 119771d10453SEric Joyner { 119871d10453SEric Joyner /* It's always total layers - 1, the array is 0 relative so -2 */ 119971d10453SEric Joyner return hw->num_tx_sched_layers - ICE_QGRP_LAYER_OFFSET; 120071d10453SEric Joyner } 120171d10453SEric Joyner 120271d10453SEric Joyner /** 120371d10453SEric Joyner * ice_sched_get_vsi_layer - get the current VSI layer number 120471d10453SEric Joyner * @hw: pointer to the HW struct 120571d10453SEric Joyner * 120671d10453SEric Joyner * This function returns the current VSI layer number 120771d10453SEric Joyner */ 120871d10453SEric Joyner static u8 ice_sched_get_vsi_layer(struct ice_hw *hw) 120971d10453SEric Joyner { 121071d10453SEric Joyner /* Num Layers VSI layer 121171d10453SEric Joyner * 9 6 121271d10453SEric Joyner * 7 4 121371d10453SEric Joyner * 5 or less sw_entry_point_layer 121471d10453SEric Joyner */ 121571d10453SEric Joyner /* calculate the VSI layer based on number of layers. */ 12168923de59SPiotr Kubaj if (hw->num_tx_sched_layers == ICE_SCHED_9_LAYERS) 12178923de59SPiotr Kubaj return hw->num_tx_sched_layers - ICE_VSI_LAYER_OFFSET; 12188923de59SPiotr Kubaj else if (hw->num_tx_sched_layers == ICE_SCHED_5_LAYERS) 12198923de59SPiotr Kubaj /* qgroup and VSI layers are same */ 12208923de59SPiotr Kubaj return hw->num_tx_sched_layers - ICE_QGRP_LAYER_OFFSET; 122171d10453SEric Joyner return hw->sw_entry_point_layer; 122271d10453SEric Joyner } 122371d10453SEric Joyner 122471d10453SEric Joyner /** 122571d10453SEric Joyner * ice_sched_get_agg_layer - get the current aggregator layer number 122671d10453SEric Joyner * @hw: pointer to the HW struct 122771d10453SEric Joyner * 122871d10453SEric Joyner * This function returns the current aggregator layer number 122971d10453SEric Joyner */ 123071d10453SEric Joyner static u8 ice_sched_get_agg_layer(struct ice_hw *hw) 123171d10453SEric Joyner { 123271d10453SEric Joyner /* Num Layers aggregator layer 123371d10453SEric Joyner * 9 4 123471d10453SEric Joyner * 7 or less sw_entry_point_layer 123571d10453SEric Joyner */ 123671d10453SEric Joyner /* calculate the aggregator layer based on number of layers. */ 12378923de59SPiotr Kubaj if (hw->num_tx_sched_layers == ICE_SCHED_9_LAYERS) 12388923de59SPiotr Kubaj return hw->num_tx_sched_layers - ICE_AGG_LAYER_OFFSET; 123971d10453SEric Joyner return hw->sw_entry_point_layer; 124071d10453SEric Joyner } 124171d10453SEric Joyner 124271d10453SEric Joyner /** 124371d10453SEric Joyner * ice_rm_dflt_leaf_node - remove the default leaf node in the tree 124471d10453SEric Joyner * @pi: port information structure 124571d10453SEric Joyner * 124671d10453SEric Joyner * This function removes the leaf node that was created by the FW 124771d10453SEric Joyner * during initialization 124871d10453SEric Joyner */ 124971d10453SEric Joyner static void ice_rm_dflt_leaf_node(struct ice_port_info *pi) 125071d10453SEric Joyner { 125171d10453SEric Joyner struct ice_sched_node *node; 125271d10453SEric Joyner 125371d10453SEric Joyner node = pi->root; 125471d10453SEric Joyner while (node) { 125571d10453SEric Joyner if (!node->num_children) 125671d10453SEric Joyner break; 125771d10453SEric Joyner node = node->children[0]; 125871d10453SEric Joyner } 125971d10453SEric Joyner if (node && node->info.data.elem_type == ICE_AQC_ELEM_TYPE_LEAF) { 126071d10453SEric Joyner u32 teid = LE32_TO_CPU(node->info.node_teid); 1261*f2635e84SEric Joyner int status; 126271d10453SEric Joyner 126371d10453SEric Joyner /* remove the default leaf node */ 126471d10453SEric Joyner status = ice_sched_remove_elems(pi->hw, node->parent, 1, &teid); 126571d10453SEric Joyner if (!status) 126671d10453SEric Joyner ice_free_sched_node(pi, node); 126771d10453SEric Joyner } 126871d10453SEric Joyner } 126971d10453SEric Joyner 127071d10453SEric Joyner /** 127171d10453SEric Joyner * ice_sched_rm_dflt_nodes - free the default nodes in the tree 127271d10453SEric Joyner * @pi: port information structure 127371d10453SEric Joyner * 127471d10453SEric Joyner * This function frees all the nodes except root and TC that were created by 127571d10453SEric Joyner * the FW during initialization 127671d10453SEric Joyner */ 127771d10453SEric Joyner static void ice_sched_rm_dflt_nodes(struct ice_port_info *pi) 127871d10453SEric Joyner { 127971d10453SEric Joyner struct ice_sched_node *node; 128071d10453SEric Joyner 128171d10453SEric Joyner ice_rm_dflt_leaf_node(pi); 128271d10453SEric Joyner 128371d10453SEric Joyner /* remove the default nodes except TC and root nodes */ 128471d10453SEric Joyner node = pi->root; 128571d10453SEric Joyner while (node) { 128671d10453SEric Joyner if (node->tx_sched_layer >= pi->hw->sw_entry_point_layer && 128771d10453SEric Joyner node->info.data.elem_type != ICE_AQC_ELEM_TYPE_TC && 128871d10453SEric Joyner node->info.data.elem_type != ICE_AQC_ELEM_TYPE_ROOT_PORT) { 128971d10453SEric Joyner ice_free_sched_node(pi, node); 129071d10453SEric Joyner break; 129171d10453SEric Joyner } 129271d10453SEric Joyner 129371d10453SEric Joyner if (!node->num_children) 129471d10453SEric Joyner break; 129571d10453SEric Joyner node = node->children[0]; 129671d10453SEric Joyner } 129771d10453SEric Joyner } 129871d10453SEric Joyner 129971d10453SEric Joyner /** 130071d10453SEric Joyner * ice_sched_init_port - Initialize scheduler by querying information from FW 130171d10453SEric Joyner * @pi: port info structure for the tree to cleanup 130271d10453SEric Joyner * 130371d10453SEric Joyner * This function is the initial call to find the total number of Tx scheduler 130471d10453SEric Joyner * resources, default topology created by firmware and storing the information 130571d10453SEric Joyner * in SW DB. 130671d10453SEric Joyner */ 1307*f2635e84SEric Joyner int ice_sched_init_port(struct ice_port_info *pi) 130871d10453SEric Joyner { 130971d10453SEric Joyner struct ice_aqc_get_topo_elem *buf; 131071d10453SEric Joyner struct ice_hw *hw; 131171d10453SEric Joyner u8 num_branches; 131271d10453SEric Joyner u16 num_elems; 1313*f2635e84SEric Joyner int status; 131471d10453SEric Joyner u8 i, j; 131571d10453SEric Joyner 131671d10453SEric Joyner if (!pi) 131771d10453SEric Joyner return ICE_ERR_PARAM; 131871d10453SEric Joyner hw = pi->hw; 131971d10453SEric Joyner 132071d10453SEric Joyner /* Query the Default Topology from FW */ 132171d10453SEric Joyner buf = (struct ice_aqc_get_topo_elem *)ice_malloc(hw, 132271d10453SEric Joyner ICE_AQ_MAX_BUF_LEN); 132371d10453SEric Joyner if (!buf) 132471d10453SEric Joyner return ICE_ERR_NO_MEMORY; 132571d10453SEric Joyner 132671d10453SEric Joyner /* Query default scheduling tree topology */ 132771d10453SEric Joyner status = ice_aq_get_dflt_topo(hw, pi->lport, buf, ICE_AQ_MAX_BUF_LEN, 132871d10453SEric Joyner &num_branches, NULL); 132971d10453SEric Joyner if (status) 133071d10453SEric Joyner goto err_init_port; 133171d10453SEric Joyner 133271d10453SEric Joyner /* num_branches should be between 1-8 */ 133371d10453SEric Joyner if (num_branches < 1 || num_branches > ICE_TXSCHED_MAX_BRANCHES) { 133471d10453SEric Joyner ice_debug(hw, ICE_DBG_SCHED, "num_branches unexpected %d\n", 133571d10453SEric Joyner num_branches); 133671d10453SEric Joyner status = ICE_ERR_PARAM; 133771d10453SEric Joyner goto err_init_port; 133871d10453SEric Joyner } 133971d10453SEric Joyner 134071d10453SEric Joyner /* get the number of elements on the default/first branch */ 134171d10453SEric Joyner num_elems = LE16_TO_CPU(buf[0].hdr.num_elems); 134271d10453SEric Joyner 134371d10453SEric Joyner /* num_elems should always be between 1-9 */ 134471d10453SEric Joyner if (num_elems < 1 || num_elems > ICE_AQC_TOPO_MAX_LEVEL_NUM) { 134571d10453SEric Joyner ice_debug(hw, ICE_DBG_SCHED, "num_elems unexpected %d\n", 134671d10453SEric Joyner num_elems); 134771d10453SEric Joyner status = ICE_ERR_PARAM; 134871d10453SEric Joyner goto err_init_port; 134971d10453SEric Joyner } 135071d10453SEric Joyner 135171d10453SEric Joyner /* If the last node is a leaf node then the index of the queue group 135271d10453SEric Joyner * layer is two less than the number of elements. 135371d10453SEric Joyner */ 135471d10453SEric Joyner if (num_elems > 2 && buf[0].generic[num_elems - 1].data.elem_type == 135571d10453SEric Joyner ICE_AQC_ELEM_TYPE_LEAF) 135671d10453SEric Joyner pi->last_node_teid = 135771d10453SEric Joyner LE32_TO_CPU(buf[0].generic[num_elems - 2].node_teid); 135871d10453SEric Joyner else 135971d10453SEric Joyner pi->last_node_teid = 136071d10453SEric Joyner LE32_TO_CPU(buf[0].generic[num_elems - 1].node_teid); 136171d10453SEric Joyner 136271d10453SEric Joyner /* Insert the Tx Sched root node */ 136371d10453SEric Joyner status = ice_sched_add_root_node(pi, &buf[0].generic[0]); 136471d10453SEric Joyner if (status) 136571d10453SEric Joyner goto err_init_port; 136671d10453SEric Joyner 136771d10453SEric Joyner /* Parse the default tree and cache the information */ 136871d10453SEric Joyner for (i = 0; i < num_branches; i++) { 136971d10453SEric Joyner num_elems = LE16_TO_CPU(buf[i].hdr.num_elems); 137071d10453SEric Joyner 137171d10453SEric Joyner /* Skip root element as already inserted */ 137271d10453SEric Joyner for (j = 1; j < num_elems; j++) { 137371d10453SEric Joyner /* update the sw entry point */ 137471d10453SEric Joyner if (buf[0].generic[j].data.elem_type == 137571d10453SEric Joyner ICE_AQC_ELEM_TYPE_ENTRY_POINT) 137671d10453SEric Joyner hw->sw_entry_point_layer = j; 137771d10453SEric Joyner 13789c30461dSEric Joyner status = ice_sched_add_node(pi, j, &buf[i].generic[j], NULL); 137971d10453SEric Joyner if (status) 138071d10453SEric Joyner goto err_init_port; 138171d10453SEric Joyner } 138271d10453SEric Joyner } 138371d10453SEric Joyner 138471d10453SEric Joyner /* Remove the default nodes. */ 138571d10453SEric Joyner if (pi->root) 138671d10453SEric Joyner ice_sched_rm_dflt_nodes(pi); 138771d10453SEric Joyner 138871d10453SEric Joyner /* initialize the port for handling the scheduler tree */ 138971d10453SEric Joyner pi->port_state = ICE_SCHED_PORT_STATE_READY; 139071d10453SEric Joyner ice_init_lock(&pi->sched_lock); 139171d10453SEric Joyner for (i = 0; i < ICE_AQC_TOPO_MAX_LEVEL_NUM; i++) 1392d08b8680SEric Joyner INIT_LIST_HEAD(&hw->rl_prof_list[i]); 139371d10453SEric Joyner 139471d10453SEric Joyner err_init_port: 139571d10453SEric Joyner if (status && pi->root) { 139671d10453SEric Joyner ice_free_sched_node(pi, pi->root); 139771d10453SEric Joyner pi->root = NULL; 139871d10453SEric Joyner } 139971d10453SEric Joyner 140071d10453SEric Joyner ice_free(hw, buf); 140171d10453SEric Joyner return status; 140271d10453SEric Joyner } 140371d10453SEric Joyner 140471d10453SEric Joyner /** 140571d10453SEric Joyner * ice_sched_get_node - Get the struct ice_sched_node for given TEID 140671d10453SEric Joyner * @pi: port information structure 140771d10453SEric Joyner * @teid: Scheduler node TEID 140871d10453SEric Joyner * 140971d10453SEric Joyner * This function retrieves the ice_sched_node struct for given TEID from 141071d10453SEric Joyner * the SW DB and returns it to the caller. 141171d10453SEric Joyner */ 141271d10453SEric Joyner struct ice_sched_node *ice_sched_get_node(struct ice_port_info *pi, u32 teid) 141371d10453SEric Joyner { 141471d10453SEric Joyner struct ice_sched_node *node; 141571d10453SEric Joyner 141671d10453SEric Joyner if (!pi) 141771d10453SEric Joyner return NULL; 141871d10453SEric Joyner 141971d10453SEric Joyner /* Find the node starting from root */ 142071d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 142171d10453SEric Joyner node = ice_sched_find_node_by_teid(pi->root, teid); 142271d10453SEric Joyner ice_release_lock(&pi->sched_lock); 142371d10453SEric Joyner 142471d10453SEric Joyner if (!node) 14257d7af7f8SEric Joyner ice_debug(pi->hw, ICE_DBG_SCHED, "Node not found for teid=0x%x\n", teid); 142671d10453SEric Joyner 142771d10453SEric Joyner return node; 142871d10453SEric Joyner } 142971d10453SEric Joyner 143071d10453SEric Joyner /** 143171d10453SEric Joyner * ice_sched_query_res_alloc - query the FW for num of logical sched layers 143271d10453SEric Joyner * @hw: pointer to the HW struct 143371d10453SEric Joyner * 143471d10453SEric Joyner * query FW for allocated scheduler resources and store in HW struct 143571d10453SEric Joyner */ 1436*f2635e84SEric Joyner int ice_sched_query_res_alloc(struct ice_hw *hw) 143771d10453SEric Joyner { 143871d10453SEric Joyner struct ice_aqc_query_txsched_res_resp *buf; 143971d10453SEric Joyner __le16 max_sibl; 1440*f2635e84SEric Joyner int status = 0; 1441*f2635e84SEric Joyner u16 i; 144271d10453SEric Joyner 144371d10453SEric Joyner if (hw->layer_info) 144471d10453SEric Joyner return status; 144571d10453SEric Joyner 144671d10453SEric Joyner buf = (struct ice_aqc_query_txsched_res_resp *) 144771d10453SEric Joyner ice_malloc(hw, sizeof(*buf)); 144871d10453SEric Joyner if (!buf) 144971d10453SEric Joyner return ICE_ERR_NO_MEMORY; 145071d10453SEric Joyner 145171d10453SEric Joyner status = ice_aq_query_sched_res(hw, sizeof(*buf), buf, NULL); 145271d10453SEric Joyner if (status) 145371d10453SEric Joyner goto sched_query_out; 145471d10453SEric Joyner 14558923de59SPiotr Kubaj hw->num_tx_sched_layers = 14568923de59SPiotr Kubaj (u8)LE16_TO_CPU(buf->sched_props.logical_levels); 145771d10453SEric Joyner hw->num_tx_sched_phys_layers = 14588923de59SPiotr Kubaj (u8)LE16_TO_CPU(buf->sched_props.phys_levels); 145971d10453SEric Joyner hw->flattened_layers = buf->sched_props.flattening_bitmap; 146071d10453SEric Joyner hw->max_cgds = buf->sched_props.max_pf_cgds; 146171d10453SEric Joyner 146271d10453SEric Joyner /* max sibling group size of current layer refers to the max children 146371d10453SEric Joyner * of the below layer node. 146471d10453SEric Joyner * layer 1 node max children will be layer 2 max sibling group size 146571d10453SEric Joyner * layer 2 node max children will be layer 3 max sibling group size 146671d10453SEric Joyner * and so on. This array will be populated from root (index 0) to 146771d10453SEric Joyner * qgroup layer 7. Leaf node has no children. 146871d10453SEric Joyner */ 146971d10453SEric Joyner for (i = 0; i < hw->num_tx_sched_layers - 1; i++) { 147071d10453SEric Joyner max_sibl = buf->layer_props[i + 1].max_sibl_grp_sz; 147171d10453SEric Joyner hw->max_children[i] = LE16_TO_CPU(max_sibl); 147271d10453SEric Joyner } 147371d10453SEric Joyner 147471d10453SEric Joyner hw->layer_info = (struct ice_aqc_layer_props *) 147571d10453SEric Joyner ice_memdup(hw, buf->layer_props, 147671d10453SEric Joyner (hw->num_tx_sched_layers * 147771d10453SEric Joyner sizeof(*hw->layer_info)), 14789cf1841cSEric Joyner ICE_NONDMA_TO_NONDMA); 147971d10453SEric Joyner if (!hw->layer_info) { 148071d10453SEric Joyner status = ICE_ERR_NO_MEMORY; 148171d10453SEric Joyner goto sched_query_out; 148271d10453SEric Joyner } 148371d10453SEric Joyner 148471d10453SEric Joyner sched_query_out: 148571d10453SEric Joyner ice_free(hw, buf); 148671d10453SEric Joyner return status; 148771d10453SEric Joyner } 148871d10453SEric Joyner 148971d10453SEric Joyner /** 149071d10453SEric Joyner * ice_sched_get_psm_clk_freq - determine the PSM clock frequency 149171d10453SEric Joyner * @hw: pointer to the HW struct 149271d10453SEric Joyner * 149371d10453SEric Joyner * Determine the PSM clock frequency and store in HW struct 149471d10453SEric Joyner */ 149571d10453SEric Joyner void ice_sched_get_psm_clk_freq(struct ice_hw *hw) 149671d10453SEric Joyner { 149771d10453SEric Joyner u32 val, clk_src; 149871d10453SEric Joyner 149971d10453SEric Joyner val = rd32(hw, GLGEN_CLKSTAT_SRC); 150071d10453SEric Joyner clk_src = (val & GLGEN_CLKSTAT_SRC_PSM_CLK_SRC_M) >> 150171d10453SEric Joyner GLGEN_CLKSTAT_SRC_PSM_CLK_SRC_S; 150271d10453SEric Joyner 150371d10453SEric Joyner switch (clk_src) { 150471d10453SEric Joyner case PSM_CLK_SRC_367_MHZ: 150571d10453SEric Joyner hw->psm_clk_freq = ICE_PSM_CLK_367MHZ_IN_HZ; 150671d10453SEric Joyner break; 150771d10453SEric Joyner case PSM_CLK_SRC_416_MHZ: 150871d10453SEric Joyner hw->psm_clk_freq = ICE_PSM_CLK_416MHZ_IN_HZ; 150971d10453SEric Joyner break; 151071d10453SEric Joyner case PSM_CLK_SRC_446_MHZ: 151171d10453SEric Joyner hw->psm_clk_freq = ICE_PSM_CLK_446MHZ_IN_HZ; 151271d10453SEric Joyner break; 151371d10453SEric Joyner case PSM_CLK_SRC_390_MHZ: 151471d10453SEric Joyner hw->psm_clk_freq = ICE_PSM_CLK_390MHZ_IN_HZ; 151571d10453SEric Joyner break; 15169c30461dSEric Joyner 15179c30461dSEric Joyner /* default condition is not required as clk_src is restricted 15189c30461dSEric Joyner * to a 2-bit value from GLGEN_CLKSTAT_SRC_PSM_CLK_SRC_M mask. 15199c30461dSEric Joyner * The above switch statements cover the possible values of 15209c30461dSEric Joyner * this variable. 15219c30461dSEric Joyner */ 152271d10453SEric Joyner } 152371d10453SEric Joyner } 152471d10453SEric Joyner 152571d10453SEric Joyner /** 152671d10453SEric Joyner * ice_sched_find_node_in_subtree - Find node in part of base node subtree 152771d10453SEric Joyner * @hw: pointer to the HW struct 152871d10453SEric Joyner * @base: pointer to the base node 152971d10453SEric Joyner * @node: pointer to the node to search 153071d10453SEric Joyner * 153171d10453SEric Joyner * This function checks whether a given node is part of the base node 153271d10453SEric Joyner * subtree or not 153371d10453SEric Joyner */ 153471d10453SEric Joyner bool 153571d10453SEric Joyner ice_sched_find_node_in_subtree(struct ice_hw *hw, struct ice_sched_node *base, 153671d10453SEric Joyner struct ice_sched_node *node) 153771d10453SEric Joyner { 153871d10453SEric Joyner u8 i; 153971d10453SEric Joyner 154071d10453SEric Joyner for (i = 0; i < base->num_children; i++) { 154171d10453SEric Joyner struct ice_sched_node *child = base->children[i]; 154271d10453SEric Joyner 154371d10453SEric Joyner if (node == child) 154471d10453SEric Joyner return true; 154571d10453SEric Joyner 154671d10453SEric Joyner if (child->tx_sched_layer > node->tx_sched_layer) 154771d10453SEric Joyner return false; 154871d10453SEric Joyner 154971d10453SEric Joyner /* this recursion is intentional, and wouldn't 155071d10453SEric Joyner * go more than 8 calls 155171d10453SEric Joyner */ 155271d10453SEric Joyner if (ice_sched_find_node_in_subtree(hw, child, node)) 155371d10453SEric Joyner return true; 155471d10453SEric Joyner } 155571d10453SEric Joyner return false; 155671d10453SEric Joyner } 155771d10453SEric Joyner 155871d10453SEric Joyner /** 15597d7af7f8SEric Joyner * ice_sched_get_free_qgrp - Scan all queue group siblings and find a free node 15607d7af7f8SEric Joyner * @pi: port information structure 15617d7af7f8SEric Joyner * @vsi_node: software VSI handle 15627d7af7f8SEric Joyner * @qgrp_node: first queue group node identified for scanning 15637d7af7f8SEric Joyner * @owner: LAN or RDMA 15647d7af7f8SEric Joyner * 15657d7af7f8SEric Joyner * This function retrieves a free LAN or RDMA queue group node by scanning 15667d7af7f8SEric Joyner * qgrp_node and its siblings for the queue group with the fewest number 15677d7af7f8SEric Joyner * of queues currently assigned. 15687d7af7f8SEric Joyner */ 15697d7af7f8SEric Joyner static struct ice_sched_node * 15707d7af7f8SEric Joyner ice_sched_get_free_qgrp(struct ice_port_info *pi, 15717d7af7f8SEric Joyner struct ice_sched_node *vsi_node, 15727d7af7f8SEric Joyner struct ice_sched_node *qgrp_node, u8 owner) 15737d7af7f8SEric Joyner { 15747d7af7f8SEric Joyner struct ice_sched_node *min_qgrp; 15757d7af7f8SEric Joyner u8 min_children; 15767d7af7f8SEric Joyner 15777d7af7f8SEric Joyner if (!qgrp_node) 15787d7af7f8SEric Joyner return qgrp_node; 15797d7af7f8SEric Joyner min_children = qgrp_node->num_children; 15807d7af7f8SEric Joyner if (!min_children) 15817d7af7f8SEric Joyner return qgrp_node; 15827d7af7f8SEric Joyner min_qgrp = qgrp_node; 15837d7af7f8SEric Joyner /* scan all queue groups until find a node which has less than the 15847d7af7f8SEric Joyner * minimum number of children. This way all queue group nodes get 15857d7af7f8SEric Joyner * equal number of shares and active. The bandwidth will be equally 15867d7af7f8SEric Joyner * distributed across all queues. 15877d7af7f8SEric Joyner */ 15887d7af7f8SEric Joyner while (qgrp_node) { 15897d7af7f8SEric Joyner /* make sure the qgroup node is part of the VSI subtree */ 15907d7af7f8SEric Joyner if (ice_sched_find_node_in_subtree(pi->hw, vsi_node, qgrp_node)) 15917d7af7f8SEric Joyner if (qgrp_node->num_children < min_children && 15927d7af7f8SEric Joyner qgrp_node->owner == owner) { 15937d7af7f8SEric Joyner /* replace the new min queue group node */ 15947d7af7f8SEric Joyner min_qgrp = qgrp_node; 15957d7af7f8SEric Joyner min_children = min_qgrp->num_children; 15967d7af7f8SEric Joyner /* break if it has no children, */ 15977d7af7f8SEric Joyner if (!min_children) 15987d7af7f8SEric Joyner break; 15997d7af7f8SEric Joyner } 16007d7af7f8SEric Joyner qgrp_node = qgrp_node->sibling; 16017d7af7f8SEric Joyner } 16027d7af7f8SEric Joyner return min_qgrp; 16037d7af7f8SEric Joyner } 16047d7af7f8SEric Joyner 16057d7af7f8SEric Joyner /** 160671d10453SEric Joyner * ice_sched_get_free_qparent - Get a free LAN or RDMA queue group node 160771d10453SEric Joyner * @pi: port information structure 160871d10453SEric Joyner * @vsi_handle: software VSI handle 160971d10453SEric Joyner * @tc: branch number 161071d10453SEric Joyner * @owner: LAN or RDMA 161171d10453SEric Joyner * 161271d10453SEric Joyner * This function retrieves a free LAN or RDMA queue group node 161371d10453SEric Joyner */ 161471d10453SEric Joyner struct ice_sched_node * 161571d10453SEric Joyner ice_sched_get_free_qparent(struct ice_port_info *pi, u16 vsi_handle, u8 tc, 161671d10453SEric Joyner u8 owner) 161771d10453SEric Joyner { 16187d7af7f8SEric Joyner struct ice_sched_node *vsi_node, *qgrp_node; 161971d10453SEric Joyner struct ice_vsi_ctx *vsi_ctx; 16208923de59SPiotr Kubaj u8 qgrp_layer, vsi_layer; 162171d10453SEric Joyner u16 max_children; 162271d10453SEric Joyner 162371d10453SEric Joyner qgrp_layer = ice_sched_get_qgrp_layer(pi->hw); 16248923de59SPiotr Kubaj vsi_layer = ice_sched_get_vsi_layer(pi->hw); 162571d10453SEric Joyner max_children = pi->hw->max_children[qgrp_layer]; 162671d10453SEric Joyner 162771d10453SEric Joyner vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle); 162871d10453SEric Joyner if (!vsi_ctx) 162971d10453SEric Joyner return NULL; 163071d10453SEric Joyner vsi_node = vsi_ctx->sched.vsi_node[tc]; 163171d10453SEric Joyner /* validate invalid VSI ID */ 163271d10453SEric Joyner if (!vsi_node) 16337d7af7f8SEric Joyner return NULL; 163471d10453SEric Joyner 16358923de59SPiotr Kubaj /* If the queue group and vsi layer are same then queues 16368923de59SPiotr Kubaj * are all attached directly to VSI 16378923de59SPiotr Kubaj */ 16388923de59SPiotr Kubaj if (qgrp_layer == vsi_layer) 16398923de59SPiotr Kubaj return vsi_node; 16408923de59SPiotr Kubaj 164171d10453SEric Joyner /* get the first queue group node from VSI sub-tree */ 164271d10453SEric Joyner qgrp_node = ice_sched_get_first_node(pi, vsi_node, qgrp_layer); 164371d10453SEric Joyner while (qgrp_node) { 164471d10453SEric Joyner /* make sure the qgroup node is part of the VSI subtree */ 164571d10453SEric Joyner if (ice_sched_find_node_in_subtree(pi->hw, vsi_node, qgrp_node)) 164671d10453SEric Joyner if (qgrp_node->num_children < max_children && 164771d10453SEric Joyner qgrp_node->owner == owner) 164871d10453SEric Joyner break; 164971d10453SEric Joyner qgrp_node = qgrp_node->sibling; 165071d10453SEric Joyner } 165171d10453SEric Joyner 16527d7af7f8SEric Joyner /* Select the best queue group */ 16537d7af7f8SEric Joyner return ice_sched_get_free_qgrp(pi, vsi_node, qgrp_node, owner); 165471d10453SEric Joyner } 165571d10453SEric Joyner 165671d10453SEric Joyner /** 165771d10453SEric Joyner * ice_sched_get_vsi_node - Get a VSI node based on VSI ID 165871d10453SEric Joyner * @pi: pointer to the port information structure 165971d10453SEric Joyner * @tc_node: pointer to the TC node 166071d10453SEric Joyner * @vsi_handle: software VSI handle 166171d10453SEric Joyner * 166271d10453SEric Joyner * This function retrieves a VSI node for a given VSI ID from a given 166371d10453SEric Joyner * TC branch 166471d10453SEric Joyner */ 166571d10453SEric Joyner struct ice_sched_node * 166671d10453SEric Joyner ice_sched_get_vsi_node(struct ice_port_info *pi, struct ice_sched_node *tc_node, 166771d10453SEric Joyner u16 vsi_handle) 166871d10453SEric Joyner { 166971d10453SEric Joyner struct ice_sched_node *node; 167071d10453SEric Joyner u8 vsi_layer; 167171d10453SEric Joyner 167271d10453SEric Joyner vsi_layer = ice_sched_get_vsi_layer(pi->hw); 167371d10453SEric Joyner node = ice_sched_get_first_node(pi, tc_node, vsi_layer); 167471d10453SEric Joyner 167571d10453SEric Joyner /* Check whether it already exists */ 167671d10453SEric Joyner while (node) { 167771d10453SEric Joyner if (node->vsi_handle == vsi_handle) 167871d10453SEric Joyner return node; 167971d10453SEric Joyner node = node->sibling; 168071d10453SEric Joyner } 168171d10453SEric Joyner 168271d10453SEric Joyner return node; 168371d10453SEric Joyner } 168471d10453SEric Joyner 168571d10453SEric Joyner /** 168671d10453SEric Joyner * ice_sched_get_agg_node - Get an aggregator node based on aggregator ID 168771d10453SEric Joyner * @pi: pointer to the port information structure 168871d10453SEric Joyner * @tc_node: pointer to the TC node 168971d10453SEric Joyner * @agg_id: aggregator ID 169071d10453SEric Joyner * 169171d10453SEric Joyner * This function retrieves an aggregator node for a given aggregator ID from 169271d10453SEric Joyner * a given TC branch 169371d10453SEric Joyner */ 169471d10453SEric Joyner static struct ice_sched_node * 169571d10453SEric Joyner ice_sched_get_agg_node(struct ice_port_info *pi, struct ice_sched_node *tc_node, 169671d10453SEric Joyner u32 agg_id) 169771d10453SEric Joyner { 169871d10453SEric Joyner struct ice_sched_node *node; 169971d10453SEric Joyner struct ice_hw *hw = pi->hw; 170071d10453SEric Joyner u8 agg_layer; 170171d10453SEric Joyner 170271d10453SEric Joyner if (!hw) 170371d10453SEric Joyner return NULL; 170471d10453SEric Joyner agg_layer = ice_sched_get_agg_layer(hw); 170571d10453SEric Joyner node = ice_sched_get_first_node(pi, tc_node, agg_layer); 170671d10453SEric Joyner 170771d10453SEric Joyner /* Check whether it already exists */ 170871d10453SEric Joyner while (node) { 170971d10453SEric Joyner if (node->agg_id == agg_id) 171071d10453SEric Joyner return node; 171171d10453SEric Joyner node = node->sibling; 171271d10453SEric Joyner } 171371d10453SEric Joyner 171471d10453SEric Joyner return node; 171571d10453SEric Joyner } 171671d10453SEric Joyner 171771d10453SEric Joyner /** 171871d10453SEric Joyner * ice_sched_check_node - Compare node parameters between SW DB and HW DB 171971d10453SEric Joyner * @hw: pointer to the HW struct 172071d10453SEric Joyner * @node: pointer to the ice_sched_node struct 172171d10453SEric Joyner * 172271d10453SEric Joyner * This function queries and compares the HW element with SW DB node parameters 172371d10453SEric Joyner */ 172471d10453SEric Joyner static bool ice_sched_check_node(struct ice_hw *hw, struct ice_sched_node *node) 172571d10453SEric Joyner { 17267d7af7f8SEric Joyner struct ice_aqc_txsched_elem_data buf; 172771d10453SEric Joyner u32 node_teid; 1728*f2635e84SEric Joyner int status; 172971d10453SEric Joyner 173071d10453SEric Joyner node_teid = LE32_TO_CPU(node->info.node_teid); 173171d10453SEric Joyner status = ice_sched_query_elem(hw, node_teid, &buf); 1732*f2635e84SEric Joyner if (status) 173371d10453SEric Joyner return false; 173471d10453SEric Joyner 17357d7af7f8SEric Joyner if (memcmp(&buf, &node->info, sizeof(buf))) { 173671d10453SEric Joyner ice_debug(hw, ICE_DBG_SCHED, "Node mismatch for teid=0x%x\n", 173771d10453SEric Joyner node_teid); 173871d10453SEric Joyner return false; 173971d10453SEric Joyner } 174071d10453SEric Joyner 174171d10453SEric Joyner return true; 174271d10453SEric Joyner } 174371d10453SEric Joyner 174471d10453SEric Joyner /** 174571d10453SEric Joyner * ice_sched_calc_vsi_child_nodes - calculate number of VSI child nodes 174671d10453SEric Joyner * @hw: pointer to the HW struct 174771d10453SEric Joyner * @num_qs: number of queues 174871d10453SEric Joyner * @num_nodes: num nodes array 174971d10453SEric Joyner * 175071d10453SEric Joyner * This function calculates the number of VSI child nodes based on the 175171d10453SEric Joyner * number of queues. 175271d10453SEric Joyner */ 175371d10453SEric Joyner static void 175471d10453SEric Joyner ice_sched_calc_vsi_child_nodes(struct ice_hw *hw, u16 num_qs, u16 *num_nodes) 175571d10453SEric Joyner { 175671d10453SEric Joyner u16 num = num_qs; 175771d10453SEric Joyner u8 i, qgl, vsil; 175871d10453SEric Joyner 175971d10453SEric Joyner qgl = ice_sched_get_qgrp_layer(hw); 176071d10453SEric Joyner vsil = ice_sched_get_vsi_layer(hw); 176171d10453SEric Joyner 176271d10453SEric Joyner /* calculate num nodes from queue group to VSI layer */ 176371d10453SEric Joyner for (i = qgl; i > vsil; i--) { 176471d10453SEric Joyner /* round to the next integer if there is a remainder */ 176571d10453SEric Joyner num = DIVIDE_AND_ROUND_UP(num, hw->max_children[i]); 176671d10453SEric Joyner 176771d10453SEric Joyner /* need at least one node */ 176871d10453SEric Joyner num_nodes[i] = num ? num : 1; 176971d10453SEric Joyner } 177071d10453SEric Joyner } 177171d10453SEric Joyner 177271d10453SEric Joyner /** 177371d10453SEric Joyner * ice_sched_add_vsi_child_nodes - add VSI child nodes to tree 177471d10453SEric Joyner * @pi: port information structure 177571d10453SEric Joyner * @vsi_handle: software VSI handle 177671d10453SEric Joyner * @tc_node: pointer to the TC node 177771d10453SEric Joyner * @num_nodes: pointer to the num nodes that needs to be added per layer 177871d10453SEric Joyner * @owner: node owner (LAN or RDMA) 177971d10453SEric Joyner * 178071d10453SEric Joyner * This function adds the VSI child nodes to tree. It gets called for 178171d10453SEric Joyner * LAN and RDMA separately. 178271d10453SEric Joyner */ 1783*f2635e84SEric Joyner static int 178471d10453SEric Joyner ice_sched_add_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_handle, 178571d10453SEric Joyner struct ice_sched_node *tc_node, u16 *num_nodes, 178671d10453SEric Joyner u8 owner) 178771d10453SEric Joyner { 178871d10453SEric Joyner struct ice_sched_node *parent, *node; 178971d10453SEric Joyner struct ice_hw *hw = pi->hw; 179071d10453SEric Joyner u32 first_node_teid; 179171d10453SEric Joyner u16 num_added = 0; 179271d10453SEric Joyner u8 i, qgl, vsil; 179371d10453SEric Joyner 179471d10453SEric Joyner qgl = ice_sched_get_qgrp_layer(hw); 179571d10453SEric Joyner vsil = ice_sched_get_vsi_layer(hw); 179671d10453SEric Joyner parent = ice_sched_get_vsi_node(pi, tc_node, vsi_handle); 179771d10453SEric Joyner for (i = vsil + 1; i <= qgl; i++) { 1798*f2635e84SEric Joyner int status; 17998923de59SPiotr Kubaj 180071d10453SEric Joyner if (!parent) 180171d10453SEric Joyner return ICE_ERR_CFG; 180271d10453SEric Joyner 180371d10453SEric Joyner status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, i, 180471d10453SEric Joyner num_nodes[i], 180571d10453SEric Joyner &first_node_teid, 180671d10453SEric Joyner &num_added); 1807*f2635e84SEric Joyner if (status || num_nodes[i] != num_added) 180871d10453SEric Joyner return ICE_ERR_CFG; 180971d10453SEric Joyner 181071d10453SEric Joyner /* The newly added node can be a new parent for the next 181171d10453SEric Joyner * layer nodes 181271d10453SEric Joyner */ 181371d10453SEric Joyner if (num_added) { 181471d10453SEric Joyner parent = ice_sched_find_node_by_teid(tc_node, 181571d10453SEric Joyner first_node_teid); 181671d10453SEric Joyner node = parent; 181771d10453SEric Joyner while (node) { 181871d10453SEric Joyner node->owner = owner; 181971d10453SEric Joyner node = node->sibling; 182071d10453SEric Joyner } 182171d10453SEric Joyner } else { 182271d10453SEric Joyner parent = parent->children[0]; 182371d10453SEric Joyner } 182471d10453SEric Joyner } 182571d10453SEric Joyner 1826*f2635e84SEric Joyner return 0; 182771d10453SEric Joyner } 182871d10453SEric Joyner 182971d10453SEric Joyner /** 183071d10453SEric Joyner * ice_sched_calc_vsi_support_nodes - calculate number of VSI support nodes 183171d10453SEric Joyner * @pi: pointer to the port info structure 183271d10453SEric Joyner * @tc_node: pointer to TC node 183371d10453SEric Joyner * @num_nodes: pointer to num nodes array 183471d10453SEric Joyner * 183571d10453SEric Joyner * This function calculates the number of supported nodes needed to add this 183671d10453SEric Joyner * VSI into Tx tree including the VSI, parent and intermediate nodes in below 183771d10453SEric Joyner * layers 183871d10453SEric Joyner */ 183971d10453SEric Joyner static void 184071d10453SEric Joyner ice_sched_calc_vsi_support_nodes(struct ice_port_info *pi, 184171d10453SEric Joyner struct ice_sched_node *tc_node, u16 *num_nodes) 184271d10453SEric Joyner { 184371d10453SEric Joyner struct ice_sched_node *node; 184471d10453SEric Joyner u8 vsil; 184571d10453SEric Joyner int i; 184671d10453SEric Joyner 184771d10453SEric Joyner vsil = ice_sched_get_vsi_layer(pi->hw); 184871d10453SEric Joyner for (i = vsil; i >= pi->hw->sw_entry_point_layer; i--) 184971d10453SEric Joyner /* Add intermediate nodes if TC has no children and 185071d10453SEric Joyner * need at least one node for VSI 185171d10453SEric Joyner */ 185271d10453SEric Joyner if (!tc_node->num_children || i == vsil) { 185371d10453SEric Joyner num_nodes[i]++; 185471d10453SEric Joyner } else { 185571d10453SEric Joyner /* If intermediate nodes are reached max children 185671d10453SEric Joyner * then add a new one. 185771d10453SEric Joyner */ 185871d10453SEric Joyner node = ice_sched_get_first_node(pi, tc_node, (u8)i); 185971d10453SEric Joyner /* scan all the siblings */ 186071d10453SEric Joyner while (node) { 186171d10453SEric Joyner if (node->num_children < 186271d10453SEric Joyner pi->hw->max_children[i]) 186371d10453SEric Joyner break; 186471d10453SEric Joyner node = node->sibling; 186571d10453SEric Joyner } 186671d10453SEric Joyner 186771d10453SEric Joyner /* tree has one intermediate node to add this new VSI. 186871d10453SEric Joyner * So no need to calculate supported nodes for below 186971d10453SEric Joyner * layers. 187071d10453SEric Joyner */ 187171d10453SEric Joyner if (node) 187271d10453SEric Joyner break; 187371d10453SEric Joyner /* all the nodes are full, allocate a new one */ 187471d10453SEric Joyner num_nodes[i]++; 187571d10453SEric Joyner } 187671d10453SEric Joyner } 187771d10453SEric Joyner 187871d10453SEric Joyner /** 187971d10453SEric Joyner * ice_sched_add_vsi_support_nodes - add VSI supported nodes into Tx tree 188071d10453SEric Joyner * @pi: port information structure 188171d10453SEric Joyner * @vsi_handle: software VSI handle 188271d10453SEric Joyner * @tc_node: pointer to TC node 188371d10453SEric Joyner * @num_nodes: pointer to num nodes array 188471d10453SEric Joyner * 188571d10453SEric Joyner * This function adds the VSI supported nodes into Tx tree including the 188671d10453SEric Joyner * VSI, its parent and intermediate nodes in below layers 188771d10453SEric Joyner */ 1888*f2635e84SEric Joyner static int 188971d10453SEric Joyner ice_sched_add_vsi_support_nodes(struct ice_port_info *pi, u16 vsi_handle, 189071d10453SEric Joyner struct ice_sched_node *tc_node, u16 *num_nodes) 189171d10453SEric Joyner { 189271d10453SEric Joyner struct ice_sched_node *parent = tc_node; 189371d10453SEric Joyner u32 first_node_teid; 189471d10453SEric Joyner u16 num_added = 0; 189571d10453SEric Joyner u8 i, vsil; 189671d10453SEric Joyner 189771d10453SEric Joyner if (!pi) 189871d10453SEric Joyner return ICE_ERR_PARAM; 189971d10453SEric Joyner 190071d10453SEric Joyner vsil = ice_sched_get_vsi_layer(pi->hw); 190171d10453SEric Joyner for (i = pi->hw->sw_entry_point_layer; i <= vsil; i++) { 1902*f2635e84SEric Joyner int status; 19038923de59SPiotr Kubaj 190471d10453SEric Joyner status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, 190571d10453SEric Joyner i, num_nodes[i], 190671d10453SEric Joyner &first_node_teid, 190771d10453SEric Joyner &num_added); 1908*f2635e84SEric Joyner if (status || num_nodes[i] != num_added) 190971d10453SEric Joyner return ICE_ERR_CFG; 191071d10453SEric Joyner 191171d10453SEric Joyner /* The newly added node can be a new parent for the next 191271d10453SEric Joyner * layer nodes 191371d10453SEric Joyner */ 191471d10453SEric Joyner if (num_added) 191571d10453SEric Joyner parent = ice_sched_find_node_by_teid(tc_node, 191671d10453SEric Joyner first_node_teid); 191771d10453SEric Joyner else 191871d10453SEric Joyner parent = parent->children[0]; 191971d10453SEric Joyner 192071d10453SEric Joyner if (!parent) 192171d10453SEric Joyner return ICE_ERR_CFG; 192271d10453SEric Joyner 192371d10453SEric Joyner if (i == vsil) 192471d10453SEric Joyner parent->vsi_handle = vsi_handle; 192571d10453SEric Joyner } 192671d10453SEric Joyner 1927*f2635e84SEric Joyner return 0; 192871d10453SEric Joyner } 192971d10453SEric Joyner 193071d10453SEric Joyner /** 193171d10453SEric Joyner * ice_sched_add_vsi_to_topo - add a new VSI into tree 193271d10453SEric Joyner * @pi: port information structure 193371d10453SEric Joyner * @vsi_handle: software VSI handle 193471d10453SEric Joyner * @tc: TC number 193571d10453SEric Joyner * 193671d10453SEric Joyner * This function adds a new VSI into scheduler tree 193771d10453SEric Joyner */ 1938*f2635e84SEric Joyner static int 193971d10453SEric Joyner ice_sched_add_vsi_to_topo(struct ice_port_info *pi, u16 vsi_handle, u8 tc) 194071d10453SEric Joyner { 194171d10453SEric Joyner u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 }; 194271d10453SEric Joyner struct ice_sched_node *tc_node; 194371d10453SEric Joyner 194471d10453SEric Joyner tc_node = ice_sched_get_tc_node(pi, tc); 194571d10453SEric Joyner if (!tc_node) 194671d10453SEric Joyner return ICE_ERR_PARAM; 194771d10453SEric Joyner 194871d10453SEric Joyner /* calculate number of supported nodes needed for this VSI */ 194971d10453SEric Joyner ice_sched_calc_vsi_support_nodes(pi, tc_node, num_nodes); 195071d10453SEric Joyner 195171d10453SEric Joyner /* add VSI supported nodes to TC subtree */ 195271d10453SEric Joyner return ice_sched_add_vsi_support_nodes(pi, vsi_handle, tc_node, 195371d10453SEric Joyner num_nodes); 195471d10453SEric Joyner } 195571d10453SEric Joyner 195671d10453SEric Joyner /** 195771d10453SEric Joyner * ice_sched_update_vsi_child_nodes - update VSI child nodes 195871d10453SEric Joyner * @pi: port information structure 195971d10453SEric Joyner * @vsi_handle: software VSI handle 196071d10453SEric Joyner * @tc: TC number 196171d10453SEric Joyner * @new_numqs: new number of max queues 196271d10453SEric Joyner * @owner: owner of this subtree 196371d10453SEric Joyner * 196471d10453SEric Joyner * This function updates the VSI child nodes based on the number of queues 196571d10453SEric Joyner */ 1966*f2635e84SEric Joyner static int 196771d10453SEric Joyner ice_sched_update_vsi_child_nodes(struct ice_port_info *pi, u16 vsi_handle, 196871d10453SEric Joyner u8 tc, u16 new_numqs, u8 owner) 196971d10453SEric Joyner { 197071d10453SEric Joyner u16 new_num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 }; 197171d10453SEric Joyner struct ice_sched_node *vsi_node; 197271d10453SEric Joyner struct ice_sched_node *tc_node; 197371d10453SEric Joyner struct ice_vsi_ctx *vsi_ctx; 197471d10453SEric Joyner struct ice_hw *hw = pi->hw; 1975*f2635e84SEric Joyner int status = 0; 197671d10453SEric Joyner u16 prev_numqs; 197771d10453SEric Joyner 197871d10453SEric Joyner tc_node = ice_sched_get_tc_node(pi, tc); 197971d10453SEric Joyner if (!tc_node) 198071d10453SEric Joyner return ICE_ERR_CFG; 198171d10453SEric Joyner 198271d10453SEric Joyner vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle); 198371d10453SEric Joyner if (!vsi_node) 198471d10453SEric Joyner return ICE_ERR_CFG; 198571d10453SEric Joyner 198671d10453SEric Joyner vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle); 198771d10453SEric Joyner if (!vsi_ctx) 198871d10453SEric Joyner return ICE_ERR_PARAM; 198971d10453SEric Joyner 19908a13362dSEric Joyner if (owner == ICE_SCHED_NODE_OWNER_LAN) 199171d10453SEric Joyner prev_numqs = vsi_ctx->sched.max_lanq[tc]; 19928a13362dSEric Joyner else 19938a13362dSEric Joyner prev_numqs = vsi_ctx->sched.max_rdmaq[tc]; 199471d10453SEric Joyner /* num queues are not changed or less than the previous number */ 199571d10453SEric Joyner if (new_numqs <= prev_numqs) 199671d10453SEric Joyner return status; 19978a13362dSEric Joyner if (owner == ICE_SCHED_NODE_OWNER_LAN) { 199871d10453SEric Joyner status = ice_alloc_lan_q_ctx(hw, vsi_handle, tc, new_numqs); 199971d10453SEric Joyner if (status) 200071d10453SEric Joyner return status; 20018a13362dSEric Joyner } else { 20028a13362dSEric Joyner status = ice_alloc_rdma_q_ctx(hw, vsi_handle, tc, new_numqs); 20038a13362dSEric Joyner if (status) 20048a13362dSEric Joyner return status; 20058a13362dSEric Joyner } 200671d10453SEric Joyner 200771d10453SEric Joyner if (new_numqs) 200871d10453SEric Joyner ice_sched_calc_vsi_child_nodes(hw, new_numqs, new_num_nodes); 200971d10453SEric Joyner /* Keep the max number of queue configuration all the time. Update the 201071d10453SEric Joyner * tree only if number of queues > previous number of queues. This may 201171d10453SEric Joyner * leave some extra nodes in the tree if number of queues < previous 201271d10453SEric Joyner * number but that wouldn't harm anything. Removing those extra nodes 201371d10453SEric Joyner * may complicate the code if those nodes are part of SRL or 201471d10453SEric Joyner * individually rate limited. 201571d10453SEric Joyner */ 201671d10453SEric Joyner status = ice_sched_add_vsi_child_nodes(pi, vsi_handle, tc_node, 201771d10453SEric Joyner new_num_nodes, owner); 201871d10453SEric Joyner if (status) 201971d10453SEric Joyner return status; 20208a13362dSEric Joyner if (owner == ICE_SCHED_NODE_OWNER_LAN) 202171d10453SEric Joyner vsi_ctx->sched.max_lanq[tc] = new_numqs; 20228a13362dSEric Joyner else 20238a13362dSEric Joyner vsi_ctx->sched.max_rdmaq[tc] = new_numqs; 202471d10453SEric Joyner 2025*f2635e84SEric Joyner return 0; 202671d10453SEric Joyner } 202771d10453SEric Joyner 202871d10453SEric Joyner /** 202971d10453SEric Joyner * ice_sched_cfg_vsi - configure the new/existing VSI 203071d10453SEric Joyner * @pi: port information structure 203171d10453SEric Joyner * @vsi_handle: software VSI handle 203271d10453SEric Joyner * @tc: TC number 203371d10453SEric Joyner * @maxqs: max number of queues 203471d10453SEric Joyner * @owner: LAN or RDMA 203571d10453SEric Joyner * @enable: TC enabled or disabled 203671d10453SEric Joyner * 203771d10453SEric Joyner * This function adds/updates VSI nodes based on the number of queues. If TC is 203871d10453SEric Joyner * enabled and VSI is in suspended state then resume the VSI back. If TC is 203971d10453SEric Joyner * disabled then suspend the VSI if it is not already. 204071d10453SEric Joyner */ 2041*f2635e84SEric Joyner int 204271d10453SEric Joyner ice_sched_cfg_vsi(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u16 maxqs, 204371d10453SEric Joyner u8 owner, bool enable) 204471d10453SEric Joyner { 204571d10453SEric Joyner struct ice_sched_node *vsi_node, *tc_node; 204671d10453SEric Joyner struct ice_vsi_ctx *vsi_ctx; 204771d10453SEric Joyner struct ice_hw *hw = pi->hw; 2048*f2635e84SEric Joyner int status = 0; 204971d10453SEric Joyner 205071d10453SEric Joyner ice_debug(pi->hw, ICE_DBG_SCHED, "add/config VSI %d\n", vsi_handle); 205171d10453SEric Joyner tc_node = ice_sched_get_tc_node(pi, tc); 205271d10453SEric Joyner if (!tc_node) 205371d10453SEric Joyner return ICE_ERR_PARAM; 205471d10453SEric Joyner vsi_ctx = ice_get_vsi_ctx(hw, vsi_handle); 205571d10453SEric Joyner if (!vsi_ctx) 205671d10453SEric Joyner return ICE_ERR_PARAM; 205771d10453SEric Joyner vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle); 205871d10453SEric Joyner 205971d10453SEric Joyner /* suspend the VSI if TC is not enabled */ 206071d10453SEric Joyner if (!enable) { 206171d10453SEric Joyner if (vsi_node && vsi_node->in_use) { 206271d10453SEric Joyner u32 teid = LE32_TO_CPU(vsi_node->info.node_teid); 206371d10453SEric Joyner 206471d10453SEric Joyner status = ice_sched_suspend_resume_elems(hw, 1, &teid, 206571d10453SEric Joyner true); 206671d10453SEric Joyner if (!status) 206771d10453SEric Joyner vsi_node->in_use = false; 206871d10453SEric Joyner } 206971d10453SEric Joyner return status; 207071d10453SEric Joyner } 207171d10453SEric Joyner 207271d10453SEric Joyner /* TC is enabled, if it is a new VSI then add it to the tree */ 207371d10453SEric Joyner if (!vsi_node) { 207471d10453SEric Joyner status = ice_sched_add_vsi_to_topo(pi, vsi_handle, tc); 207571d10453SEric Joyner if (status) 207671d10453SEric Joyner return status; 207771d10453SEric Joyner 207871d10453SEric Joyner vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle); 207971d10453SEric Joyner if (!vsi_node) 208071d10453SEric Joyner return ICE_ERR_CFG; 208171d10453SEric Joyner 208271d10453SEric Joyner vsi_ctx->sched.vsi_node[tc] = vsi_node; 208371d10453SEric Joyner vsi_node->in_use = true; 208471d10453SEric Joyner /* invalidate the max queues whenever VSI gets added first time 208571d10453SEric Joyner * into the scheduler tree (boot or after reset). We need to 208671d10453SEric Joyner * recreate the child nodes all the time in these cases. 208771d10453SEric Joyner */ 208871d10453SEric Joyner vsi_ctx->sched.max_lanq[tc] = 0; 20898a13362dSEric Joyner vsi_ctx->sched.max_rdmaq[tc] = 0; 209071d10453SEric Joyner } 209171d10453SEric Joyner 209271d10453SEric Joyner /* update the VSI child nodes */ 209371d10453SEric Joyner status = ice_sched_update_vsi_child_nodes(pi, vsi_handle, tc, maxqs, 209471d10453SEric Joyner owner); 209571d10453SEric Joyner if (status) 209671d10453SEric Joyner return status; 209771d10453SEric Joyner 209871d10453SEric Joyner /* TC is enabled, resume the VSI if it is in the suspend state */ 209971d10453SEric Joyner if (!vsi_node->in_use) { 210071d10453SEric Joyner u32 teid = LE32_TO_CPU(vsi_node->info.node_teid); 210171d10453SEric Joyner 210271d10453SEric Joyner status = ice_sched_suspend_resume_elems(hw, 1, &teid, false); 210371d10453SEric Joyner if (!status) 210471d10453SEric Joyner vsi_node->in_use = true; 210571d10453SEric Joyner } 210671d10453SEric Joyner 210771d10453SEric Joyner return status; 210871d10453SEric Joyner } 210971d10453SEric Joyner 211071d10453SEric Joyner /** 211156429daeSEric Joyner * ice_sched_rm_agg_vsi_info - remove aggregator related VSI info entry 211271d10453SEric Joyner * @pi: port information structure 211371d10453SEric Joyner * @vsi_handle: software VSI handle 211471d10453SEric Joyner * 211571d10453SEric Joyner * This function removes single aggregator VSI info entry from 211671d10453SEric Joyner * aggregator list. 211771d10453SEric Joyner */ 21187d7af7f8SEric Joyner static void ice_sched_rm_agg_vsi_info(struct ice_port_info *pi, u16 vsi_handle) 211971d10453SEric Joyner { 212071d10453SEric Joyner struct ice_sched_agg_info *agg_info; 212171d10453SEric Joyner struct ice_sched_agg_info *atmp; 212271d10453SEric Joyner 212371d10453SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(agg_info, atmp, &pi->hw->agg_list, 212471d10453SEric Joyner ice_sched_agg_info, 212571d10453SEric Joyner list_entry) { 212671d10453SEric Joyner struct ice_sched_agg_vsi_info *agg_vsi_info; 212771d10453SEric Joyner struct ice_sched_agg_vsi_info *vtmp; 212871d10453SEric Joyner 212971d10453SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(agg_vsi_info, vtmp, 213071d10453SEric Joyner &agg_info->agg_vsi_list, 213171d10453SEric Joyner ice_sched_agg_vsi_info, list_entry) 213271d10453SEric Joyner if (agg_vsi_info->vsi_handle == vsi_handle) { 213371d10453SEric Joyner LIST_DEL(&agg_vsi_info->list_entry); 213471d10453SEric Joyner ice_free(pi->hw, agg_vsi_info); 213571d10453SEric Joyner return; 213671d10453SEric Joyner } 213771d10453SEric Joyner } 213871d10453SEric Joyner } 213971d10453SEric Joyner 214071d10453SEric Joyner /** 214171d10453SEric Joyner * ice_sched_is_leaf_node_present - check for a leaf node in the sub-tree 214271d10453SEric Joyner * @node: pointer to the sub-tree node 214371d10453SEric Joyner * 214471d10453SEric Joyner * This function checks for a leaf node presence in a given sub-tree node. 214571d10453SEric Joyner */ 214671d10453SEric Joyner static bool ice_sched_is_leaf_node_present(struct ice_sched_node *node) 214771d10453SEric Joyner { 214871d10453SEric Joyner u8 i; 214971d10453SEric Joyner 215071d10453SEric Joyner for (i = 0; i < node->num_children; i++) 215171d10453SEric Joyner if (ice_sched_is_leaf_node_present(node->children[i])) 215271d10453SEric Joyner return true; 215371d10453SEric Joyner /* check for a leaf node */ 215471d10453SEric Joyner return (node->info.data.elem_type == ICE_AQC_ELEM_TYPE_LEAF); 215571d10453SEric Joyner } 215671d10453SEric Joyner 215771d10453SEric Joyner /** 215871d10453SEric Joyner * ice_sched_rm_vsi_cfg - remove the VSI and its children nodes 215971d10453SEric Joyner * @pi: port information structure 216071d10453SEric Joyner * @vsi_handle: software VSI handle 216171d10453SEric Joyner * @owner: LAN or RDMA 216271d10453SEric Joyner * 216371d10453SEric Joyner * This function removes the VSI and its LAN or RDMA children nodes from the 216471d10453SEric Joyner * scheduler tree. 216571d10453SEric Joyner */ 2166*f2635e84SEric Joyner static int 216771d10453SEric Joyner ice_sched_rm_vsi_cfg(struct ice_port_info *pi, u16 vsi_handle, u8 owner) 216871d10453SEric Joyner { 216971d10453SEric Joyner struct ice_vsi_ctx *vsi_ctx; 2170*f2635e84SEric Joyner int status = ICE_ERR_PARAM; 217171d10453SEric Joyner u8 i; 217271d10453SEric Joyner 217371d10453SEric Joyner ice_debug(pi->hw, ICE_DBG_SCHED, "removing VSI %d\n", vsi_handle); 217471d10453SEric Joyner if (!ice_is_vsi_valid(pi->hw, vsi_handle)) 217571d10453SEric Joyner return status; 217671d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 217771d10453SEric Joyner vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle); 217871d10453SEric Joyner if (!vsi_ctx) 217971d10453SEric Joyner goto exit_sched_rm_vsi_cfg; 218071d10453SEric Joyner 218171d10453SEric Joyner ice_for_each_traffic_class(i) { 218271d10453SEric Joyner struct ice_sched_node *vsi_node, *tc_node; 218371d10453SEric Joyner u8 j = 0; 218471d10453SEric Joyner 218571d10453SEric Joyner tc_node = ice_sched_get_tc_node(pi, i); 218671d10453SEric Joyner if (!tc_node) 218771d10453SEric Joyner continue; 218871d10453SEric Joyner 218971d10453SEric Joyner vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle); 219071d10453SEric Joyner if (!vsi_node) 219171d10453SEric Joyner continue; 219271d10453SEric Joyner 219371d10453SEric Joyner if (ice_sched_is_leaf_node_present(vsi_node)) { 21947d7af7f8SEric Joyner ice_debug(pi->hw, ICE_DBG_SCHED, "VSI has leaf nodes in TC %d\n", i); 219571d10453SEric Joyner status = ICE_ERR_IN_USE; 219671d10453SEric Joyner goto exit_sched_rm_vsi_cfg; 219771d10453SEric Joyner } 219871d10453SEric Joyner while (j < vsi_node->num_children) { 219971d10453SEric Joyner if (vsi_node->children[j]->owner == owner) { 220071d10453SEric Joyner ice_free_sched_node(pi, vsi_node->children[j]); 220171d10453SEric Joyner 220271d10453SEric Joyner /* reset the counter again since the num 220371d10453SEric Joyner * children will be updated after node removal 220471d10453SEric Joyner */ 220571d10453SEric Joyner j = 0; 220671d10453SEric Joyner } else { 220771d10453SEric Joyner j++; 220871d10453SEric Joyner } 220971d10453SEric Joyner } 221071d10453SEric Joyner /* remove the VSI if it has no children */ 221171d10453SEric Joyner if (!vsi_node->num_children) { 221271d10453SEric Joyner ice_free_sched_node(pi, vsi_node); 221371d10453SEric Joyner vsi_ctx->sched.vsi_node[i] = NULL; 221471d10453SEric Joyner 221571d10453SEric Joyner /* clean up aggregator related VSI info if any */ 221671d10453SEric Joyner ice_sched_rm_agg_vsi_info(pi, vsi_handle); 221771d10453SEric Joyner } 221871d10453SEric Joyner if (owner == ICE_SCHED_NODE_OWNER_LAN) 221971d10453SEric Joyner vsi_ctx->sched.max_lanq[i] = 0; 22208a13362dSEric Joyner else 22218a13362dSEric Joyner vsi_ctx->sched.max_rdmaq[i] = 0; 222271d10453SEric Joyner } 2223*f2635e84SEric Joyner status = 0; 222471d10453SEric Joyner 222571d10453SEric Joyner exit_sched_rm_vsi_cfg: 222671d10453SEric Joyner ice_release_lock(&pi->sched_lock); 222771d10453SEric Joyner return status; 222871d10453SEric Joyner } 222971d10453SEric Joyner 223071d10453SEric Joyner /** 223171d10453SEric Joyner * ice_rm_vsi_lan_cfg - remove VSI and its LAN children nodes 223271d10453SEric Joyner * @pi: port information structure 223371d10453SEric Joyner * @vsi_handle: software VSI handle 223471d10453SEric Joyner * 223571d10453SEric Joyner * This function clears the VSI and its LAN children nodes from scheduler tree 223671d10453SEric Joyner * for all TCs. 223771d10453SEric Joyner */ 2238*f2635e84SEric Joyner int ice_rm_vsi_lan_cfg(struct ice_port_info *pi, u16 vsi_handle) 223971d10453SEric Joyner { 224071d10453SEric Joyner return ice_sched_rm_vsi_cfg(pi, vsi_handle, ICE_SCHED_NODE_OWNER_LAN); 224171d10453SEric Joyner } 224271d10453SEric Joyner 224371d10453SEric Joyner /** 22448a13362dSEric Joyner * ice_rm_vsi_rdma_cfg - remove VSI and its RDMA children nodes 22458a13362dSEric Joyner * @pi: port information structure 22468a13362dSEric Joyner * @vsi_handle: software VSI handle 22478a13362dSEric Joyner * 22488a13362dSEric Joyner * This function clears the VSI and its RDMA children nodes from scheduler tree 22498a13362dSEric Joyner * for all TCs. 22508a13362dSEric Joyner */ 2251*f2635e84SEric Joyner int ice_rm_vsi_rdma_cfg(struct ice_port_info *pi, u16 vsi_handle) 22528a13362dSEric Joyner { 22538a13362dSEric Joyner return ice_sched_rm_vsi_cfg(pi, vsi_handle, ICE_SCHED_NODE_OWNER_RDMA); 22548a13362dSEric Joyner } 22558a13362dSEric Joyner 22568a13362dSEric Joyner /** 225771d10453SEric Joyner * ice_sched_is_tree_balanced - Check tree nodes are identical or not 225871d10453SEric Joyner * @hw: pointer to the HW struct 225971d10453SEric Joyner * @node: pointer to the ice_sched_node struct 226071d10453SEric Joyner * 226171d10453SEric Joyner * This function compares all the nodes for a given tree against HW DB nodes 226271d10453SEric Joyner * This function needs to be called with the port_info->sched_lock held 226371d10453SEric Joyner */ 226471d10453SEric Joyner bool ice_sched_is_tree_balanced(struct ice_hw *hw, struct ice_sched_node *node) 226571d10453SEric Joyner { 226671d10453SEric Joyner u8 i; 226771d10453SEric Joyner 226871d10453SEric Joyner /* start from the leaf node */ 226971d10453SEric Joyner for (i = 0; i < node->num_children; i++) 227071d10453SEric Joyner /* Fail if node doesn't match with the SW DB 227171d10453SEric Joyner * this recursion is intentional, and wouldn't 227271d10453SEric Joyner * go more than 9 calls 227371d10453SEric Joyner */ 227471d10453SEric Joyner if (!ice_sched_is_tree_balanced(hw, node->children[i])) 227571d10453SEric Joyner return false; 227671d10453SEric Joyner 227771d10453SEric Joyner return ice_sched_check_node(hw, node); 227871d10453SEric Joyner } 227971d10453SEric Joyner 228071d10453SEric Joyner /** 228171d10453SEric Joyner * ice_aq_query_node_to_root - retrieve the tree topology for a given node TEID 228271d10453SEric Joyner * @hw: pointer to the HW struct 228371d10453SEric Joyner * @node_teid: node TEID 228471d10453SEric Joyner * @buf: pointer to buffer 228571d10453SEric Joyner * @buf_size: buffer size in bytes 228671d10453SEric Joyner * @cd: pointer to command details structure or NULL 228771d10453SEric Joyner * 228871d10453SEric Joyner * This function retrieves the tree topology from the firmware for a given 228971d10453SEric Joyner * node TEID to the root node. 229071d10453SEric Joyner */ 2291*f2635e84SEric Joyner int 229271d10453SEric Joyner ice_aq_query_node_to_root(struct ice_hw *hw, u32 node_teid, 22937d7af7f8SEric Joyner struct ice_aqc_txsched_elem_data *buf, u16 buf_size, 229471d10453SEric Joyner struct ice_sq_cd *cd) 229571d10453SEric Joyner { 229671d10453SEric Joyner struct ice_aqc_query_node_to_root *cmd; 229771d10453SEric Joyner struct ice_aq_desc desc; 229871d10453SEric Joyner 229971d10453SEric Joyner cmd = &desc.params.query_node_to_root; 230071d10453SEric Joyner ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_query_node_to_root); 230171d10453SEric Joyner cmd->teid = CPU_TO_LE32(node_teid); 230271d10453SEric Joyner return ice_aq_send_cmd(hw, &desc, buf, buf_size, cd); 230371d10453SEric Joyner } 230471d10453SEric Joyner 230571d10453SEric Joyner /** 230671d10453SEric Joyner * ice_get_agg_info - get the aggregator ID 230771d10453SEric Joyner * @hw: pointer to the hardware structure 230871d10453SEric Joyner * @agg_id: aggregator ID 230971d10453SEric Joyner * 231071d10453SEric Joyner * This function validates aggregator ID. The function returns info if 231171d10453SEric Joyner * aggregator ID is present in list otherwise it returns null. 231271d10453SEric Joyner */ 231371d10453SEric Joyner static struct ice_sched_agg_info * 231471d10453SEric Joyner ice_get_agg_info(struct ice_hw *hw, u32 agg_id) 231571d10453SEric Joyner { 231671d10453SEric Joyner struct ice_sched_agg_info *agg_info; 231771d10453SEric Joyner 231871d10453SEric Joyner LIST_FOR_EACH_ENTRY(agg_info, &hw->agg_list, ice_sched_agg_info, 231971d10453SEric Joyner list_entry) 232071d10453SEric Joyner if (agg_info->agg_id == agg_id) 232171d10453SEric Joyner return agg_info; 232271d10453SEric Joyner 232371d10453SEric Joyner return NULL; 232471d10453SEric Joyner } 232571d10453SEric Joyner 232671d10453SEric Joyner /** 232771d10453SEric Joyner * ice_sched_get_free_vsi_parent - Find a free parent node in aggregator subtree 232871d10453SEric Joyner * @hw: pointer to the HW struct 232971d10453SEric Joyner * @node: pointer to a child node 233071d10453SEric Joyner * @num_nodes: num nodes count array 233171d10453SEric Joyner * 233271d10453SEric Joyner * This function walks through the aggregator subtree to find a free parent 233371d10453SEric Joyner * node 233471d10453SEric Joyner */ 233571d10453SEric Joyner static struct ice_sched_node * 233671d10453SEric Joyner ice_sched_get_free_vsi_parent(struct ice_hw *hw, struct ice_sched_node *node, 233771d10453SEric Joyner u16 *num_nodes) 233871d10453SEric Joyner { 233971d10453SEric Joyner u8 l = node->tx_sched_layer; 234071d10453SEric Joyner u8 vsil, i; 234171d10453SEric Joyner 234271d10453SEric Joyner vsil = ice_sched_get_vsi_layer(hw); 234371d10453SEric Joyner 234471d10453SEric Joyner /* Is it VSI parent layer ? */ 234571d10453SEric Joyner if (l == vsil - 1) 234671d10453SEric Joyner return (node->num_children < hw->max_children[l]) ? node : NULL; 234771d10453SEric Joyner 234871d10453SEric Joyner /* We have intermediate nodes. Let's walk through the subtree. If the 234971d10453SEric Joyner * intermediate node has space to add a new node then clear the count 235071d10453SEric Joyner */ 235171d10453SEric Joyner if (node->num_children < hw->max_children[l]) 235271d10453SEric Joyner num_nodes[l] = 0; 235371d10453SEric Joyner /* The below recursive call is intentional and wouldn't go more than 235471d10453SEric Joyner * 2 or 3 iterations. 235571d10453SEric Joyner */ 235671d10453SEric Joyner 235771d10453SEric Joyner for (i = 0; i < node->num_children; i++) { 235871d10453SEric Joyner struct ice_sched_node *parent; 235971d10453SEric Joyner 236071d10453SEric Joyner parent = ice_sched_get_free_vsi_parent(hw, node->children[i], 236171d10453SEric Joyner num_nodes); 236271d10453SEric Joyner if (parent) 236371d10453SEric Joyner return parent; 236471d10453SEric Joyner } 236571d10453SEric Joyner 236671d10453SEric Joyner return NULL; 236771d10453SEric Joyner } 236871d10453SEric Joyner 236971d10453SEric Joyner /** 237071d10453SEric Joyner * ice_sched_update_parent - update the new parent in SW DB 237171d10453SEric Joyner * @new_parent: pointer to a new parent node 237271d10453SEric Joyner * @node: pointer to a child node 237371d10453SEric Joyner * 237471d10453SEric Joyner * This function removes the child from the old parent and adds it to a new 237571d10453SEric Joyner * parent 237671d10453SEric Joyner */ 23779c30461dSEric Joyner void 237871d10453SEric Joyner ice_sched_update_parent(struct ice_sched_node *new_parent, 237971d10453SEric Joyner struct ice_sched_node *node) 238071d10453SEric Joyner { 238171d10453SEric Joyner struct ice_sched_node *old_parent; 238271d10453SEric Joyner u8 i, j; 238371d10453SEric Joyner 238471d10453SEric Joyner old_parent = node->parent; 238571d10453SEric Joyner 238671d10453SEric Joyner /* update the old parent children */ 238771d10453SEric Joyner for (i = 0; i < old_parent->num_children; i++) 238871d10453SEric Joyner if (old_parent->children[i] == node) { 238971d10453SEric Joyner for (j = i + 1; j < old_parent->num_children; j++) 239071d10453SEric Joyner old_parent->children[j - 1] = 239171d10453SEric Joyner old_parent->children[j]; 239271d10453SEric Joyner old_parent->num_children--; 239371d10453SEric Joyner break; 239471d10453SEric Joyner } 239571d10453SEric Joyner 239671d10453SEric Joyner /* now move the node to a new parent */ 239771d10453SEric Joyner new_parent->children[new_parent->num_children++] = node; 239871d10453SEric Joyner node->parent = new_parent; 239971d10453SEric Joyner node->info.parent_teid = new_parent->info.node_teid; 240071d10453SEric Joyner } 240171d10453SEric Joyner 240271d10453SEric Joyner /** 240371d10453SEric Joyner * ice_sched_move_nodes - move child nodes to a given parent 240471d10453SEric Joyner * @pi: port information structure 240571d10453SEric Joyner * @parent: pointer to parent node 240671d10453SEric Joyner * @num_items: number of child nodes to be moved 240771d10453SEric Joyner * @list: pointer to child node teids 240871d10453SEric Joyner * 240971d10453SEric Joyner * This function move the child nodes to a given parent. 241071d10453SEric Joyner */ 2411*f2635e84SEric Joyner int 241271d10453SEric Joyner ice_sched_move_nodes(struct ice_port_info *pi, struct ice_sched_node *parent, 241371d10453SEric Joyner u16 num_items, u32 *list) 241471d10453SEric Joyner { 241571d10453SEric Joyner struct ice_aqc_move_elem *buf; 241671d10453SEric Joyner struct ice_sched_node *node; 241771d10453SEric Joyner u16 i, grps_movd = 0; 241871d10453SEric Joyner struct ice_hw *hw; 2419*f2635e84SEric Joyner int status = 0; 24207d7af7f8SEric Joyner u16 buf_len; 242171d10453SEric Joyner 242271d10453SEric Joyner hw = pi->hw; 242371d10453SEric Joyner 242471d10453SEric Joyner if (!parent || !num_items) 242571d10453SEric Joyner return ICE_ERR_PARAM; 242671d10453SEric Joyner 242771d10453SEric Joyner /* Does parent have enough space */ 24287d7af7f8SEric Joyner if (parent->num_children + num_items > 242971d10453SEric Joyner hw->max_children[parent->tx_sched_layer]) 243071d10453SEric Joyner return ICE_ERR_AQ_FULL; 243171d10453SEric Joyner 24327d7af7f8SEric Joyner buf_len = ice_struct_size(buf, teid, 1); 24337d7af7f8SEric Joyner buf = (struct ice_aqc_move_elem *)ice_malloc(hw, buf_len); 243471d10453SEric Joyner if (!buf) 243571d10453SEric Joyner return ICE_ERR_NO_MEMORY; 243671d10453SEric Joyner 243771d10453SEric Joyner for (i = 0; i < num_items; i++) { 243871d10453SEric Joyner node = ice_sched_find_node_by_teid(pi->root, list[i]); 243971d10453SEric Joyner if (!node) { 244071d10453SEric Joyner status = ICE_ERR_PARAM; 244171d10453SEric Joyner goto move_err_exit; 244271d10453SEric Joyner } 244371d10453SEric Joyner 244471d10453SEric Joyner buf->hdr.src_parent_teid = node->info.parent_teid; 244571d10453SEric Joyner buf->hdr.dest_parent_teid = parent->info.node_teid; 244671d10453SEric Joyner buf->teid[0] = node->info.node_teid; 244771d10453SEric Joyner buf->hdr.num_elems = CPU_TO_LE16(1); 24487d7af7f8SEric Joyner status = ice_aq_move_sched_elems(hw, 1, buf, buf_len, 244971d10453SEric Joyner &grps_movd, NULL); 245071d10453SEric Joyner if (status && grps_movd != 1) { 245171d10453SEric Joyner status = ICE_ERR_CFG; 245271d10453SEric Joyner goto move_err_exit; 245371d10453SEric Joyner } 245471d10453SEric Joyner 245571d10453SEric Joyner /* update the SW DB */ 245671d10453SEric Joyner ice_sched_update_parent(parent, node); 245771d10453SEric Joyner } 245871d10453SEric Joyner 245971d10453SEric Joyner move_err_exit: 246071d10453SEric Joyner ice_free(hw, buf); 246171d10453SEric Joyner return status; 246271d10453SEric Joyner } 246371d10453SEric Joyner 246471d10453SEric Joyner /** 246571d10453SEric Joyner * ice_sched_move_vsi_to_agg - move VSI to aggregator node 246671d10453SEric Joyner * @pi: port information structure 246771d10453SEric Joyner * @vsi_handle: software VSI handle 246871d10453SEric Joyner * @agg_id: aggregator ID 246971d10453SEric Joyner * @tc: TC number 247071d10453SEric Joyner * 247171d10453SEric Joyner * This function moves a VSI to an aggregator node or its subtree. 247271d10453SEric Joyner * Intermediate nodes may be created if required. 247371d10453SEric Joyner */ 2474*f2635e84SEric Joyner static int 247571d10453SEric Joyner ice_sched_move_vsi_to_agg(struct ice_port_info *pi, u16 vsi_handle, u32 agg_id, 247671d10453SEric Joyner u8 tc) 247771d10453SEric Joyner { 247871d10453SEric Joyner struct ice_sched_node *vsi_node, *agg_node, *tc_node, *parent; 247971d10453SEric Joyner u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 }; 248071d10453SEric Joyner u32 first_node_teid, vsi_teid; 248171d10453SEric Joyner u16 num_nodes_added; 248271d10453SEric Joyner u8 aggl, vsil, i; 2483*f2635e84SEric Joyner int status; 248471d10453SEric Joyner 248571d10453SEric Joyner tc_node = ice_sched_get_tc_node(pi, tc); 248671d10453SEric Joyner if (!tc_node) 248771d10453SEric Joyner return ICE_ERR_CFG; 248871d10453SEric Joyner 248971d10453SEric Joyner agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id); 249071d10453SEric Joyner if (!agg_node) 249171d10453SEric Joyner return ICE_ERR_DOES_NOT_EXIST; 249271d10453SEric Joyner 249371d10453SEric Joyner vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle); 249471d10453SEric Joyner if (!vsi_node) 249571d10453SEric Joyner return ICE_ERR_DOES_NOT_EXIST; 249671d10453SEric Joyner 24977d7af7f8SEric Joyner /* Is this VSI already part of given aggregator? */ 24987d7af7f8SEric Joyner if (ice_sched_find_node_in_subtree(pi->hw, agg_node, vsi_node)) 2499*f2635e84SEric Joyner return 0; 25007d7af7f8SEric Joyner 250171d10453SEric Joyner aggl = ice_sched_get_agg_layer(pi->hw); 250271d10453SEric Joyner vsil = ice_sched_get_vsi_layer(pi->hw); 250371d10453SEric Joyner 250471d10453SEric Joyner /* set intermediate node count to 1 between aggregator and VSI layers */ 250571d10453SEric Joyner for (i = aggl + 1; i < vsil; i++) 250671d10453SEric Joyner num_nodes[i] = 1; 250771d10453SEric Joyner 250871d10453SEric Joyner /* Check if the aggregator subtree has any free node to add the VSI */ 250971d10453SEric Joyner for (i = 0; i < agg_node->num_children; i++) { 251071d10453SEric Joyner parent = ice_sched_get_free_vsi_parent(pi->hw, 251171d10453SEric Joyner agg_node->children[i], 251271d10453SEric Joyner num_nodes); 251371d10453SEric Joyner if (parent) 251471d10453SEric Joyner goto move_nodes; 251571d10453SEric Joyner } 251671d10453SEric Joyner 251771d10453SEric Joyner /* add new nodes */ 251871d10453SEric Joyner parent = agg_node; 251971d10453SEric Joyner for (i = aggl + 1; i < vsil; i++) { 252071d10453SEric Joyner status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, i, 252171d10453SEric Joyner num_nodes[i], 252271d10453SEric Joyner &first_node_teid, 252371d10453SEric Joyner &num_nodes_added); 2524*f2635e84SEric Joyner if (status || num_nodes[i] != num_nodes_added) 252571d10453SEric Joyner return ICE_ERR_CFG; 252671d10453SEric Joyner 252771d10453SEric Joyner /* The newly added node can be a new parent for the next 252871d10453SEric Joyner * layer nodes 252971d10453SEric Joyner */ 253071d10453SEric Joyner if (num_nodes_added) 253171d10453SEric Joyner parent = ice_sched_find_node_by_teid(tc_node, 253271d10453SEric Joyner first_node_teid); 253371d10453SEric Joyner else 253471d10453SEric Joyner parent = parent->children[0]; 253571d10453SEric Joyner 253671d10453SEric Joyner if (!parent) 253771d10453SEric Joyner return ICE_ERR_CFG; 253871d10453SEric Joyner } 253971d10453SEric Joyner 254071d10453SEric Joyner move_nodes: 254171d10453SEric Joyner vsi_teid = LE32_TO_CPU(vsi_node->info.node_teid); 254271d10453SEric Joyner return ice_sched_move_nodes(pi, parent, 1, &vsi_teid); 254371d10453SEric Joyner } 254471d10453SEric Joyner 254571d10453SEric Joyner /** 254671d10453SEric Joyner * ice_move_all_vsi_to_dflt_agg - move all VSI(s) to default aggregator 254771d10453SEric Joyner * @pi: port information structure 254871d10453SEric Joyner * @agg_info: aggregator info 254971d10453SEric Joyner * @tc: traffic class number 255071d10453SEric Joyner * @rm_vsi_info: true or false 255171d10453SEric Joyner * 255271d10453SEric Joyner * This function move all the VSI(s) to the default aggregator and delete 255371d10453SEric Joyner * aggregator VSI info based on passed in boolean parameter rm_vsi_info. The 255471d10453SEric Joyner * caller holds the scheduler lock. 255571d10453SEric Joyner */ 2556*f2635e84SEric Joyner static int 255771d10453SEric Joyner ice_move_all_vsi_to_dflt_agg(struct ice_port_info *pi, 255871d10453SEric Joyner struct ice_sched_agg_info *agg_info, u8 tc, 255971d10453SEric Joyner bool rm_vsi_info) 256071d10453SEric Joyner { 256171d10453SEric Joyner struct ice_sched_agg_vsi_info *agg_vsi_info; 256271d10453SEric Joyner struct ice_sched_agg_vsi_info *tmp; 2563*f2635e84SEric Joyner int status = 0; 256471d10453SEric Joyner 256571d10453SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(agg_vsi_info, tmp, &agg_info->agg_vsi_list, 256671d10453SEric Joyner ice_sched_agg_vsi_info, list_entry) { 256771d10453SEric Joyner u16 vsi_handle = agg_vsi_info->vsi_handle; 256871d10453SEric Joyner 256971d10453SEric Joyner /* Move VSI to default aggregator */ 257071d10453SEric Joyner if (!ice_is_tc_ena(agg_vsi_info->tc_bitmap[0], tc)) 257171d10453SEric Joyner continue; 257271d10453SEric Joyner 257371d10453SEric Joyner status = ice_sched_move_vsi_to_agg(pi, vsi_handle, 257471d10453SEric Joyner ICE_DFLT_AGG_ID, tc); 257571d10453SEric Joyner if (status) 257671d10453SEric Joyner break; 257771d10453SEric Joyner 257871d10453SEric Joyner ice_clear_bit(tc, agg_vsi_info->tc_bitmap); 257971d10453SEric Joyner if (rm_vsi_info && !agg_vsi_info->tc_bitmap[0]) { 258071d10453SEric Joyner LIST_DEL(&agg_vsi_info->list_entry); 258171d10453SEric Joyner ice_free(pi->hw, agg_vsi_info); 258271d10453SEric Joyner } 258371d10453SEric Joyner } 258471d10453SEric Joyner 258571d10453SEric Joyner return status; 258671d10453SEric Joyner } 258771d10453SEric Joyner 258871d10453SEric Joyner /** 258971d10453SEric Joyner * ice_sched_is_agg_inuse - check whether the aggregator is in use or not 259071d10453SEric Joyner * @pi: port information structure 259171d10453SEric Joyner * @node: node pointer 259271d10453SEric Joyner * 259371d10453SEric Joyner * This function checks whether the aggregator is attached with any VSI or not. 259471d10453SEric Joyner */ 259571d10453SEric Joyner static bool 259671d10453SEric Joyner ice_sched_is_agg_inuse(struct ice_port_info *pi, struct ice_sched_node *node) 259771d10453SEric Joyner { 259871d10453SEric Joyner u8 vsil, i; 259971d10453SEric Joyner 260071d10453SEric Joyner vsil = ice_sched_get_vsi_layer(pi->hw); 260171d10453SEric Joyner if (node->tx_sched_layer < vsil - 1) { 260271d10453SEric Joyner for (i = 0; i < node->num_children; i++) 260371d10453SEric Joyner if (ice_sched_is_agg_inuse(pi, node->children[i])) 260471d10453SEric Joyner return true; 260571d10453SEric Joyner return false; 260671d10453SEric Joyner } else { 260771d10453SEric Joyner return node->num_children ? true : false; 260871d10453SEric Joyner } 260971d10453SEric Joyner } 261071d10453SEric Joyner 261171d10453SEric Joyner /** 261271d10453SEric Joyner * ice_sched_rm_agg_cfg - remove the aggregator node 261371d10453SEric Joyner * @pi: port information structure 261471d10453SEric Joyner * @agg_id: aggregator ID 261571d10453SEric Joyner * @tc: TC number 261671d10453SEric Joyner * 261771d10453SEric Joyner * This function removes the aggregator node and intermediate nodes if any 261871d10453SEric Joyner * from the given TC 261971d10453SEric Joyner */ 2620*f2635e84SEric Joyner static int 262171d10453SEric Joyner ice_sched_rm_agg_cfg(struct ice_port_info *pi, u32 agg_id, u8 tc) 262271d10453SEric Joyner { 262371d10453SEric Joyner struct ice_sched_node *tc_node, *agg_node; 262471d10453SEric Joyner struct ice_hw *hw = pi->hw; 262571d10453SEric Joyner 262671d10453SEric Joyner tc_node = ice_sched_get_tc_node(pi, tc); 262771d10453SEric Joyner if (!tc_node) 262871d10453SEric Joyner return ICE_ERR_CFG; 262971d10453SEric Joyner 263071d10453SEric Joyner agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id); 263171d10453SEric Joyner if (!agg_node) 263271d10453SEric Joyner return ICE_ERR_DOES_NOT_EXIST; 263371d10453SEric Joyner 263471d10453SEric Joyner /* Can't remove the aggregator node if it has children */ 263571d10453SEric Joyner if (ice_sched_is_agg_inuse(pi, agg_node)) 263671d10453SEric Joyner return ICE_ERR_IN_USE; 263771d10453SEric Joyner 263871d10453SEric Joyner /* need to remove the whole subtree if aggregator node is the 263971d10453SEric Joyner * only child. 264071d10453SEric Joyner */ 264171d10453SEric Joyner while (agg_node->tx_sched_layer > hw->sw_entry_point_layer) { 264271d10453SEric Joyner struct ice_sched_node *parent = agg_node->parent; 264371d10453SEric Joyner 264471d10453SEric Joyner if (!parent) 264571d10453SEric Joyner return ICE_ERR_CFG; 264671d10453SEric Joyner 264771d10453SEric Joyner if (parent->num_children > 1) 264871d10453SEric Joyner break; 264971d10453SEric Joyner 265071d10453SEric Joyner agg_node = parent; 265171d10453SEric Joyner } 265271d10453SEric Joyner 265371d10453SEric Joyner ice_free_sched_node(pi, agg_node); 2654*f2635e84SEric Joyner return 0; 265571d10453SEric Joyner } 265671d10453SEric Joyner 265771d10453SEric Joyner /** 265871d10453SEric Joyner * ice_rm_agg_cfg_tc - remove aggregator configuration for TC 265971d10453SEric Joyner * @pi: port information structure 266071d10453SEric Joyner * @agg_info: aggregator ID 266171d10453SEric Joyner * @tc: TC number 266271d10453SEric Joyner * @rm_vsi_info: bool value true or false 266371d10453SEric Joyner * 266471d10453SEric Joyner * This function removes aggregator reference to VSI of given TC. It removes 266571d10453SEric Joyner * the aggregator configuration completely for requested TC. The caller needs 266671d10453SEric Joyner * to hold the scheduler lock. 266771d10453SEric Joyner */ 2668*f2635e84SEric Joyner static int 266971d10453SEric Joyner ice_rm_agg_cfg_tc(struct ice_port_info *pi, struct ice_sched_agg_info *agg_info, 267071d10453SEric Joyner u8 tc, bool rm_vsi_info) 267171d10453SEric Joyner { 2672*f2635e84SEric Joyner int status = 0; 267371d10453SEric Joyner 267471d10453SEric Joyner /* If nothing to remove - return success */ 267571d10453SEric Joyner if (!ice_is_tc_ena(agg_info->tc_bitmap[0], tc)) 267671d10453SEric Joyner goto exit_rm_agg_cfg_tc; 267771d10453SEric Joyner 267871d10453SEric Joyner status = ice_move_all_vsi_to_dflt_agg(pi, agg_info, tc, rm_vsi_info); 267971d10453SEric Joyner if (status) 268071d10453SEric Joyner goto exit_rm_agg_cfg_tc; 268171d10453SEric Joyner 268271d10453SEric Joyner /* Delete aggregator node(s) */ 268371d10453SEric Joyner status = ice_sched_rm_agg_cfg(pi, agg_info->agg_id, tc); 268471d10453SEric Joyner if (status) 268571d10453SEric Joyner goto exit_rm_agg_cfg_tc; 268671d10453SEric Joyner 268771d10453SEric Joyner ice_clear_bit(tc, agg_info->tc_bitmap); 268871d10453SEric Joyner exit_rm_agg_cfg_tc: 268971d10453SEric Joyner return status; 269071d10453SEric Joyner } 269171d10453SEric Joyner 269271d10453SEric Joyner /** 269371d10453SEric Joyner * ice_save_agg_tc_bitmap - save aggregator TC bitmap 269471d10453SEric Joyner * @pi: port information structure 269571d10453SEric Joyner * @agg_id: aggregator ID 269671d10453SEric Joyner * @tc_bitmap: 8 bits TC bitmap 269771d10453SEric Joyner * 269871d10453SEric Joyner * Save aggregator TC bitmap. This function needs to be called with scheduler 269971d10453SEric Joyner * lock held. 270071d10453SEric Joyner */ 2701*f2635e84SEric Joyner static int 270271d10453SEric Joyner ice_save_agg_tc_bitmap(struct ice_port_info *pi, u32 agg_id, 270371d10453SEric Joyner ice_bitmap_t *tc_bitmap) 270471d10453SEric Joyner { 270571d10453SEric Joyner struct ice_sched_agg_info *agg_info; 270671d10453SEric Joyner 270771d10453SEric Joyner agg_info = ice_get_agg_info(pi->hw, agg_id); 270871d10453SEric Joyner if (!agg_info) 270971d10453SEric Joyner return ICE_ERR_PARAM; 271071d10453SEric Joyner ice_cp_bitmap(agg_info->replay_tc_bitmap, tc_bitmap, 271171d10453SEric Joyner ICE_MAX_TRAFFIC_CLASS); 2712*f2635e84SEric Joyner return 0; 271371d10453SEric Joyner } 271471d10453SEric Joyner 271571d10453SEric Joyner /** 271671d10453SEric Joyner * ice_sched_add_agg_cfg - create an aggregator node 271771d10453SEric Joyner * @pi: port information structure 271871d10453SEric Joyner * @agg_id: aggregator ID 271971d10453SEric Joyner * @tc: TC number 272071d10453SEric Joyner * 272171d10453SEric Joyner * This function creates an aggregator node and intermediate nodes if required 272271d10453SEric Joyner * for the given TC 272371d10453SEric Joyner */ 2724*f2635e84SEric Joyner static int 272571d10453SEric Joyner ice_sched_add_agg_cfg(struct ice_port_info *pi, u32 agg_id, u8 tc) 272671d10453SEric Joyner { 272771d10453SEric Joyner struct ice_sched_node *parent, *agg_node, *tc_node; 272871d10453SEric Joyner u16 num_nodes[ICE_AQC_TOPO_MAX_LEVEL_NUM] = { 0 }; 272971d10453SEric Joyner struct ice_hw *hw = pi->hw; 273071d10453SEric Joyner u32 first_node_teid; 273171d10453SEric Joyner u16 num_nodes_added; 2732*f2635e84SEric Joyner int status = 0; 273371d10453SEric Joyner u8 i, aggl; 273471d10453SEric Joyner 273571d10453SEric Joyner tc_node = ice_sched_get_tc_node(pi, tc); 273671d10453SEric Joyner if (!tc_node) 273771d10453SEric Joyner return ICE_ERR_CFG; 273871d10453SEric Joyner 273971d10453SEric Joyner agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id); 274071d10453SEric Joyner /* Does Agg node already exist ? */ 274171d10453SEric Joyner if (agg_node) 274271d10453SEric Joyner return status; 274371d10453SEric Joyner 274471d10453SEric Joyner aggl = ice_sched_get_agg_layer(hw); 274571d10453SEric Joyner 274671d10453SEric Joyner /* need one node in Agg layer */ 274771d10453SEric Joyner num_nodes[aggl] = 1; 274871d10453SEric Joyner 274971d10453SEric Joyner /* Check whether the intermediate nodes have space to add the 275071d10453SEric Joyner * new aggregator. If they are full, then SW needs to allocate a new 275171d10453SEric Joyner * intermediate node on those layers 275271d10453SEric Joyner */ 275371d10453SEric Joyner for (i = hw->sw_entry_point_layer; i < aggl; i++) { 275471d10453SEric Joyner parent = ice_sched_get_first_node(pi, tc_node, i); 275571d10453SEric Joyner 275671d10453SEric Joyner /* scan all the siblings */ 275771d10453SEric Joyner while (parent) { 275871d10453SEric Joyner if (parent->num_children < hw->max_children[i]) 275971d10453SEric Joyner break; 276071d10453SEric Joyner parent = parent->sibling; 276171d10453SEric Joyner } 276271d10453SEric Joyner 276371d10453SEric Joyner /* all the nodes are full, reserve one for this layer */ 276471d10453SEric Joyner if (!parent) 276571d10453SEric Joyner num_nodes[i]++; 276671d10453SEric Joyner } 276771d10453SEric Joyner 276871d10453SEric Joyner /* add the aggregator node */ 276971d10453SEric Joyner parent = tc_node; 277071d10453SEric Joyner for (i = hw->sw_entry_point_layer; i <= aggl; i++) { 277171d10453SEric Joyner if (!parent) 277271d10453SEric Joyner return ICE_ERR_CFG; 277371d10453SEric Joyner 277471d10453SEric Joyner status = ice_sched_add_nodes_to_layer(pi, tc_node, parent, i, 277571d10453SEric Joyner num_nodes[i], 277671d10453SEric Joyner &first_node_teid, 277771d10453SEric Joyner &num_nodes_added); 2778*f2635e84SEric Joyner if (status || num_nodes[i] != num_nodes_added) 277971d10453SEric Joyner return ICE_ERR_CFG; 278071d10453SEric Joyner 278171d10453SEric Joyner /* The newly added node can be a new parent for the next 278271d10453SEric Joyner * layer nodes 278371d10453SEric Joyner */ 278471d10453SEric Joyner if (num_nodes_added) { 278571d10453SEric Joyner parent = ice_sched_find_node_by_teid(tc_node, 278671d10453SEric Joyner first_node_teid); 278771d10453SEric Joyner /* register aggregator ID with the aggregator node */ 278871d10453SEric Joyner if (parent && i == aggl) 278971d10453SEric Joyner parent->agg_id = agg_id; 279071d10453SEric Joyner } else { 279171d10453SEric Joyner parent = parent->children[0]; 279271d10453SEric Joyner } 279371d10453SEric Joyner } 279471d10453SEric Joyner 2795*f2635e84SEric Joyner return 0; 279671d10453SEric Joyner } 279771d10453SEric Joyner 279871d10453SEric Joyner /** 279971d10453SEric Joyner * ice_sched_cfg_agg - configure aggregator node 280071d10453SEric Joyner * @pi: port information structure 280171d10453SEric Joyner * @agg_id: aggregator ID 280271d10453SEric Joyner * @agg_type: aggregator type queue, VSI, or aggregator group 280371d10453SEric Joyner * @tc_bitmap: bits TC bitmap 280471d10453SEric Joyner * 280571d10453SEric Joyner * It registers a unique aggregator node into scheduler services. It 280671d10453SEric Joyner * allows a user to register with a unique ID to track it's resources. 280771d10453SEric Joyner * The aggregator type determines if this is a queue group, VSI group 280871d10453SEric Joyner * or aggregator group. It then creates the aggregator node(s) for requested 280971d10453SEric Joyner * TC(s) or removes an existing aggregator node including its configuration 281071d10453SEric Joyner * if indicated via tc_bitmap. Call ice_rm_agg_cfg to release aggregator 281171d10453SEric Joyner * resources and remove aggregator ID. 281271d10453SEric Joyner * This function needs to be called with scheduler lock held. 281371d10453SEric Joyner */ 2814*f2635e84SEric Joyner static int 281571d10453SEric Joyner ice_sched_cfg_agg(struct ice_port_info *pi, u32 agg_id, 281671d10453SEric Joyner enum ice_agg_type agg_type, ice_bitmap_t *tc_bitmap) 281771d10453SEric Joyner { 281871d10453SEric Joyner struct ice_sched_agg_info *agg_info; 281971d10453SEric Joyner struct ice_hw *hw = pi->hw; 2820*f2635e84SEric Joyner int status = 0; 282171d10453SEric Joyner u8 tc; 282271d10453SEric Joyner 282371d10453SEric Joyner agg_info = ice_get_agg_info(hw, agg_id); 282471d10453SEric Joyner if (!agg_info) { 282571d10453SEric Joyner /* Create new entry for new aggregator ID */ 282671d10453SEric Joyner agg_info = (struct ice_sched_agg_info *) 282771d10453SEric Joyner ice_malloc(hw, sizeof(*agg_info)); 2828d08b8680SEric Joyner if (!agg_info) 2829d08b8680SEric Joyner return ICE_ERR_NO_MEMORY; 2830d08b8680SEric Joyner 283171d10453SEric Joyner agg_info->agg_id = agg_id; 283271d10453SEric Joyner agg_info->agg_type = agg_type; 283371d10453SEric Joyner agg_info->tc_bitmap[0] = 0; 283471d10453SEric Joyner 283571d10453SEric Joyner /* Initialize the aggregator VSI list head */ 283671d10453SEric Joyner INIT_LIST_HEAD(&agg_info->agg_vsi_list); 283771d10453SEric Joyner 283871d10453SEric Joyner /* Add new entry in aggregator list */ 283971d10453SEric Joyner LIST_ADD(&agg_info->list_entry, &hw->agg_list); 284071d10453SEric Joyner } 284171d10453SEric Joyner /* Create aggregator node(s) for requested TC(s) */ 284271d10453SEric Joyner ice_for_each_traffic_class(tc) { 284371d10453SEric Joyner if (!ice_is_tc_ena(*tc_bitmap, tc)) { 284471d10453SEric Joyner /* Delete aggregator cfg TC if it exists previously */ 284571d10453SEric Joyner status = ice_rm_agg_cfg_tc(pi, agg_info, tc, false); 284671d10453SEric Joyner if (status) 284771d10453SEric Joyner break; 284871d10453SEric Joyner continue; 284971d10453SEric Joyner } 285071d10453SEric Joyner 285171d10453SEric Joyner /* Check if aggregator node for TC already exists */ 285271d10453SEric Joyner if (ice_is_tc_ena(agg_info->tc_bitmap[0], tc)) 285371d10453SEric Joyner continue; 285471d10453SEric Joyner 285571d10453SEric Joyner /* Create new aggregator node for TC */ 285671d10453SEric Joyner status = ice_sched_add_agg_cfg(pi, agg_id, tc); 285771d10453SEric Joyner if (status) 285871d10453SEric Joyner break; 285971d10453SEric Joyner 286071d10453SEric Joyner /* Save aggregator node's TC information */ 286171d10453SEric Joyner ice_set_bit(tc, agg_info->tc_bitmap); 286271d10453SEric Joyner } 2863d08b8680SEric Joyner 286471d10453SEric Joyner return status; 286571d10453SEric Joyner } 286671d10453SEric Joyner 286771d10453SEric Joyner /** 286871d10453SEric Joyner * ice_cfg_agg - config aggregator node 286971d10453SEric Joyner * @pi: port information structure 287071d10453SEric Joyner * @agg_id: aggregator ID 287171d10453SEric Joyner * @agg_type: aggregator type queue, VSI, or aggregator group 287271d10453SEric Joyner * @tc_bitmap: bits TC bitmap 287371d10453SEric Joyner * 287471d10453SEric Joyner * This function configures aggregator node(s). 287571d10453SEric Joyner */ 2876*f2635e84SEric Joyner int 287771d10453SEric Joyner ice_cfg_agg(struct ice_port_info *pi, u32 agg_id, enum ice_agg_type agg_type, 287871d10453SEric Joyner u8 tc_bitmap) 287971d10453SEric Joyner { 288071d10453SEric Joyner ice_bitmap_t bitmap = tc_bitmap; 2881*f2635e84SEric Joyner int status; 288271d10453SEric Joyner 288371d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 288471d10453SEric Joyner status = ice_sched_cfg_agg(pi, agg_id, agg_type, 288571d10453SEric Joyner (ice_bitmap_t *)&bitmap); 288671d10453SEric Joyner if (!status) 288771d10453SEric Joyner status = ice_save_agg_tc_bitmap(pi, agg_id, 288871d10453SEric Joyner (ice_bitmap_t *)&bitmap); 288971d10453SEric Joyner ice_release_lock(&pi->sched_lock); 289071d10453SEric Joyner return status; 289171d10453SEric Joyner } 289271d10453SEric Joyner 289371d10453SEric Joyner /** 289471d10453SEric Joyner * ice_get_agg_vsi_info - get the aggregator ID 289571d10453SEric Joyner * @agg_info: aggregator info 289671d10453SEric Joyner * @vsi_handle: software VSI handle 289771d10453SEric Joyner * 289871d10453SEric Joyner * The function returns aggregator VSI info based on VSI handle. This function 289971d10453SEric Joyner * needs to be called with scheduler lock held. 290071d10453SEric Joyner */ 290171d10453SEric Joyner static struct ice_sched_agg_vsi_info * 290271d10453SEric Joyner ice_get_agg_vsi_info(struct ice_sched_agg_info *agg_info, u16 vsi_handle) 290371d10453SEric Joyner { 290471d10453SEric Joyner struct ice_sched_agg_vsi_info *agg_vsi_info; 290571d10453SEric Joyner 290671d10453SEric Joyner LIST_FOR_EACH_ENTRY(agg_vsi_info, &agg_info->agg_vsi_list, 290771d10453SEric Joyner ice_sched_agg_vsi_info, list_entry) 290871d10453SEric Joyner if (agg_vsi_info->vsi_handle == vsi_handle) 290971d10453SEric Joyner return agg_vsi_info; 291071d10453SEric Joyner 291171d10453SEric Joyner return NULL; 291271d10453SEric Joyner } 291371d10453SEric Joyner 291471d10453SEric Joyner /** 291571d10453SEric Joyner * ice_get_vsi_agg_info - get the aggregator info of VSI 291671d10453SEric Joyner * @hw: pointer to the hardware structure 291771d10453SEric Joyner * @vsi_handle: Sw VSI handle 291871d10453SEric Joyner * 291971d10453SEric Joyner * The function returns aggregator info of VSI represented via vsi_handle. The 292071d10453SEric Joyner * VSI has in this case a different aggregator than the default one. This 292171d10453SEric Joyner * function needs to be called with scheduler lock held. 292271d10453SEric Joyner */ 292371d10453SEric Joyner static struct ice_sched_agg_info * 292471d10453SEric Joyner ice_get_vsi_agg_info(struct ice_hw *hw, u16 vsi_handle) 292571d10453SEric Joyner { 292671d10453SEric Joyner struct ice_sched_agg_info *agg_info; 292771d10453SEric Joyner 292871d10453SEric Joyner LIST_FOR_EACH_ENTRY(agg_info, &hw->agg_list, ice_sched_agg_info, 292971d10453SEric Joyner list_entry) { 293071d10453SEric Joyner struct ice_sched_agg_vsi_info *agg_vsi_info; 293171d10453SEric Joyner 293271d10453SEric Joyner agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle); 293371d10453SEric Joyner if (agg_vsi_info) 293471d10453SEric Joyner return agg_info; 293571d10453SEric Joyner } 293671d10453SEric Joyner return NULL; 293771d10453SEric Joyner } 293871d10453SEric Joyner 293971d10453SEric Joyner /** 294071d10453SEric Joyner * ice_save_agg_vsi_tc_bitmap - save aggregator VSI TC bitmap 294171d10453SEric Joyner * @pi: port information structure 294271d10453SEric Joyner * @agg_id: aggregator ID 294371d10453SEric Joyner * @vsi_handle: software VSI handle 294471d10453SEric Joyner * @tc_bitmap: TC bitmap of enabled TC(s) 294571d10453SEric Joyner * 294671d10453SEric Joyner * Save VSI to aggregator TC bitmap. This function needs to call with scheduler 294771d10453SEric Joyner * lock held. 294871d10453SEric Joyner */ 2949*f2635e84SEric Joyner static int 295071d10453SEric Joyner ice_save_agg_vsi_tc_bitmap(struct ice_port_info *pi, u32 agg_id, u16 vsi_handle, 295171d10453SEric Joyner ice_bitmap_t *tc_bitmap) 295271d10453SEric Joyner { 295371d10453SEric Joyner struct ice_sched_agg_vsi_info *agg_vsi_info; 295471d10453SEric Joyner struct ice_sched_agg_info *agg_info; 295571d10453SEric Joyner 295671d10453SEric Joyner agg_info = ice_get_agg_info(pi->hw, agg_id); 295771d10453SEric Joyner if (!agg_info) 295871d10453SEric Joyner return ICE_ERR_PARAM; 295971d10453SEric Joyner /* check if entry already exist */ 296071d10453SEric Joyner agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle); 296171d10453SEric Joyner if (!agg_vsi_info) 296271d10453SEric Joyner return ICE_ERR_PARAM; 296371d10453SEric Joyner ice_cp_bitmap(agg_vsi_info->replay_tc_bitmap, tc_bitmap, 296471d10453SEric Joyner ICE_MAX_TRAFFIC_CLASS); 2965*f2635e84SEric Joyner return 0; 296671d10453SEric Joyner } 296771d10453SEric Joyner 296871d10453SEric Joyner /** 296971d10453SEric Joyner * ice_sched_assoc_vsi_to_agg - associate/move VSI to new/default aggregator 297071d10453SEric Joyner * @pi: port information structure 297171d10453SEric Joyner * @agg_id: aggregator ID 297271d10453SEric Joyner * @vsi_handle: software VSI handle 297371d10453SEric Joyner * @tc_bitmap: TC bitmap of enabled TC(s) 297471d10453SEric Joyner * 297571d10453SEric Joyner * This function moves VSI to a new or default aggregator node. If VSI is 297671d10453SEric Joyner * already associated to the aggregator node then no operation is performed on 297771d10453SEric Joyner * the tree. This function needs to be called with scheduler lock held. 297871d10453SEric Joyner */ 2979*f2635e84SEric Joyner static int 298071d10453SEric Joyner ice_sched_assoc_vsi_to_agg(struct ice_port_info *pi, u32 agg_id, 298171d10453SEric Joyner u16 vsi_handle, ice_bitmap_t *tc_bitmap) 298271d10453SEric Joyner { 298356429daeSEric Joyner struct ice_sched_agg_vsi_info *agg_vsi_info, *old_agg_vsi_info = NULL; 298456429daeSEric Joyner struct ice_sched_agg_info *agg_info, *old_agg_info; 298571d10453SEric Joyner struct ice_hw *hw = pi->hw; 2986*f2635e84SEric Joyner int status = 0; 298771d10453SEric Joyner u8 tc; 298871d10453SEric Joyner 298971d10453SEric Joyner if (!ice_is_vsi_valid(pi->hw, vsi_handle)) 299071d10453SEric Joyner return ICE_ERR_PARAM; 299171d10453SEric Joyner agg_info = ice_get_agg_info(hw, agg_id); 299271d10453SEric Joyner if (!agg_info) 299371d10453SEric Joyner return ICE_ERR_PARAM; 299456429daeSEric Joyner /* If the vsi is already part of another aggregator then update 299556429daeSEric Joyner * its vsi info list 299656429daeSEric Joyner */ 299756429daeSEric Joyner old_agg_info = ice_get_vsi_agg_info(hw, vsi_handle); 299856429daeSEric Joyner if (old_agg_info && old_agg_info != agg_info) { 299956429daeSEric Joyner struct ice_sched_agg_vsi_info *vtmp; 300056429daeSEric Joyner 300156429daeSEric Joyner LIST_FOR_EACH_ENTRY_SAFE(old_agg_vsi_info, vtmp, 300256429daeSEric Joyner &old_agg_info->agg_vsi_list, 300356429daeSEric Joyner ice_sched_agg_vsi_info, list_entry) 300456429daeSEric Joyner if (old_agg_vsi_info->vsi_handle == vsi_handle) 300556429daeSEric Joyner break; 300656429daeSEric Joyner } 300756429daeSEric Joyner 300871d10453SEric Joyner /* check if entry already exist */ 300971d10453SEric Joyner agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle); 301071d10453SEric Joyner if (!agg_vsi_info) { 301171d10453SEric Joyner /* Create new entry for VSI under aggregator list */ 301271d10453SEric Joyner agg_vsi_info = (struct ice_sched_agg_vsi_info *) 301371d10453SEric Joyner ice_malloc(hw, sizeof(*agg_vsi_info)); 301471d10453SEric Joyner if (!agg_vsi_info) 301571d10453SEric Joyner return ICE_ERR_PARAM; 301671d10453SEric Joyner 301771d10453SEric Joyner /* add VSI ID into the aggregator list */ 301871d10453SEric Joyner agg_vsi_info->vsi_handle = vsi_handle; 301971d10453SEric Joyner LIST_ADD(&agg_vsi_info->list_entry, &agg_info->agg_vsi_list); 302071d10453SEric Joyner } 302171d10453SEric Joyner /* Move VSI node to new aggregator node for requested TC(s) */ 302271d10453SEric Joyner ice_for_each_traffic_class(tc) { 302371d10453SEric Joyner if (!ice_is_tc_ena(*tc_bitmap, tc)) 302471d10453SEric Joyner continue; 302571d10453SEric Joyner 302671d10453SEric Joyner /* Move VSI to new aggregator */ 302771d10453SEric Joyner status = ice_sched_move_vsi_to_agg(pi, vsi_handle, agg_id, tc); 302871d10453SEric Joyner if (status) 302971d10453SEric Joyner break; 303071d10453SEric Joyner 303171d10453SEric Joyner ice_set_bit(tc, agg_vsi_info->tc_bitmap); 303256429daeSEric Joyner if (old_agg_vsi_info) 303356429daeSEric Joyner ice_clear_bit(tc, old_agg_vsi_info->tc_bitmap); 303456429daeSEric Joyner } 303556429daeSEric Joyner if (old_agg_vsi_info && !old_agg_vsi_info->tc_bitmap[0]) { 303656429daeSEric Joyner LIST_DEL(&old_agg_vsi_info->list_entry); 303756429daeSEric Joyner ice_free(pi->hw, old_agg_vsi_info); 303871d10453SEric Joyner } 303971d10453SEric Joyner return status; 304071d10453SEric Joyner } 304171d10453SEric Joyner 304271d10453SEric Joyner /** 304371d10453SEric Joyner * ice_sched_rm_unused_rl_prof - remove unused RL profile 3044d08b8680SEric Joyner * @hw: pointer to the hardware structure 304571d10453SEric Joyner * 304671d10453SEric Joyner * This function removes unused rate limit profiles from the HW and 304771d10453SEric Joyner * SW DB. The caller needs to hold scheduler lock. 304871d10453SEric Joyner */ 3049d08b8680SEric Joyner static void ice_sched_rm_unused_rl_prof(struct ice_hw *hw) 305071d10453SEric Joyner { 305171d10453SEric Joyner u16 ln; 305271d10453SEric Joyner 3053d08b8680SEric Joyner for (ln = 0; ln < hw->num_tx_sched_layers; ln++) { 305471d10453SEric Joyner struct ice_aqc_rl_profile_info *rl_prof_elem; 305571d10453SEric Joyner struct ice_aqc_rl_profile_info *rl_prof_tmp; 305671d10453SEric Joyner 305771d10453SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(rl_prof_elem, rl_prof_tmp, 3058d08b8680SEric Joyner &hw->rl_prof_list[ln], 305971d10453SEric Joyner ice_aqc_rl_profile_info, list_entry) { 3060d08b8680SEric Joyner if (!ice_sched_del_rl_profile(hw, rl_prof_elem)) 3061d08b8680SEric Joyner ice_debug(hw, ICE_DBG_SCHED, "Removed rl profile\n"); 306271d10453SEric Joyner } 306371d10453SEric Joyner } 306471d10453SEric Joyner } 306571d10453SEric Joyner 306671d10453SEric Joyner /** 306771d10453SEric Joyner * ice_sched_update_elem - update element 306871d10453SEric Joyner * @hw: pointer to the HW struct 306971d10453SEric Joyner * @node: pointer to node 307071d10453SEric Joyner * @info: node info to update 307171d10453SEric Joyner * 30727d7af7f8SEric Joyner * Update the HW DB, and local SW DB of node. Update the scheduling 307371d10453SEric Joyner * parameters of node from argument info data buffer (Info->data buf) and 307471d10453SEric Joyner * returns success or error on config sched element failure. The caller 307571d10453SEric Joyner * needs to hold scheduler lock. 307671d10453SEric Joyner */ 3077*f2635e84SEric Joyner static int 307871d10453SEric Joyner ice_sched_update_elem(struct ice_hw *hw, struct ice_sched_node *node, 307971d10453SEric Joyner struct ice_aqc_txsched_elem_data *info) 308071d10453SEric Joyner { 30817d7af7f8SEric Joyner struct ice_aqc_txsched_elem_data buf; 308271d10453SEric Joyner u16 elem_cfgd = 0; 308371d10453SEric Joyner u16 num_elems = 1; 3084*f2635e84SEric Joyner int status; 308571d10453SEric Joyner 30867d7af7f8SEric Joyner buf = *info; 308756429daeSEric Joyner /* For TC nodes, CIR config is not supported */ 308856429daeSEric Joyner if (node->info.data.elem_type == ICE_AQC_ELEM_TYPE_TC) 308956429daeSEric Joyner buf.data.valid_sections &= ~ICE_AQC_ELEM_VALID_CIR; 309071d10453SEric Joyner /* Parent TEID is reserved field in this aq call */ 30917d7af7f8SEric Joyner buf.parent_teid = 0; 309271d10453SEric Joyner /* Element type is reserved field in this aq call */ 30937d7af7f8SEric Joyner buf.data.elem_type = 0; 309471d10453SEric Joyner /* Flags is reserved field in this aq call */ 30957d7af7f8SEric Joyner buf.data.flags = 0; 309671d10453SEric Joyner 309771d10453SEric Joyner /* Update HW DB */ 309871d10453SEric Joyner /* Configure element node */ 309971d10453SEric Joyner status = ice_aq_cfg_sched_elems(hw, num_elems, &buf, sizeof(buf), 310071d10453SEric Joyner &elem_cfgd, NULL); 310171d10453SEric Joyner if (status || elem_cfgd != num_elems) { 310271d10453SEric Joyner ice_debug(hw, ICE_DBG_SCHED, "Config sched elem error\n"); 310371d10453SEric Joyner return ICE_ERR_CFG; 310471d10453SEric Joyner } 310571d10453SEric Joyner 310671d10453SEric Joyner /* Config success case */ 310771d10453SEric Joyner /* Now update local SW DB */ 310871d10453SEric Joyner /* Only copy the data portion of info buffer */ 310971d10453SEric Joyner node->info.data = info->data; 311071d10453SEric Joyner return status; 311171d10453SEric Joyner } 311271d10453SEric Joyner 311371d10453SEric Joyner /** 311471d10453SEric Joyner * ice_sched_cfg_node_bw_alloc - configure node BW weight/alloc params 311571d10453SEric Joyner * @hw: pointer to the HW struct 311671d10453SEric Joyner * @node: sched node to configure 311771d10453SEric Joyner * @rl_type: rate limit type CIR, EIR, or shared 311871d10453SEric Joyner * @bw_alloc: BW weight/allocation 311971d10453SEric Joyner * 312071d10453SEric Joyner * This function configures node element's BW allocation. 312171d10453SEric Joyner */ 3122*f2635e84SEric Joyner static int 312371d10453SEric Joyner ice_sched_cfg_node_bw_alloc(struct ice_hw *hw, struct ice_sched_node *node, 312471d10453SEric Joyner enum ice_rl_type rl_type, u16 bw_alloc) 312571d10453SEric Joyner { 312671d10453SEric Joyner struct ice_aqc_txsched_elem_data buf; 312771d10453SEric Joyner struct ice_aqc_txsched_elem *data; 3128*f2635e84SEric Joyner int status; 312971d10453SEric Joyner 313071d10453SEric Joyner buf = node->info; 313171d10453SEric Joyner data = &buf.data; 313271d10453SEric Joyner if (rl_type == ICE_MIN_BW) { 313371d10453SEric Joyner data->valid_sections |= ICE_AQC_ELEM_VALID_CIR; 313471d10453SEric Joyner data->cir_bw.bw_alloc = CPU_TO_LE16(bw_alloc); 313571d10453SEric Joyner } else if (rl_type == ICE_MAX_BW) { 313671d10453SEric Joyner data->valid_sections |= ICE_AQC_ELEM_VALID_EIR; 313771d10453SEric Joyner data->eir_bw.bw_alloc = CPU_TO_LE16(bw_alloc); 313871d10453SEric Joyner } else { 313971d10453SEric Joyner return ICE_ERR_PARAM; 314071d10453SEric Joyner } 314171d10453SEric Joyner 314271d10453SEric Joyner /* Configure element */ 314371d10453SEric Joyner status = ice_sched_update_elem(hw, node, &buf); 314471d10453SEric Joyner return status; 314571d10453SEric Joyner } 314671d10453SEric Joyner 314771d10453SEric Joyner /** 314871d10453SEric Joyner * ice_move_vsi_to_agg - moves VSI to new or default aggregator 314971d10453SEric Joyner * @pi: port information structure 315071d10453SEric Joyner * @agg_id: aggregator ID 315171d10453SEric Joyner * @vsi_handle: software VSI handle 315271d10453SEric Joyner * @tc_bitmap: TC bitmap of enabled TC(s) 315371d10453SEric Joyner * 315471d10453SEric Joyner * Move or associate VSI to a new or default aggregator node. 315571d10453SEric Joyner */ 3156*f2635e84SEric Joyner int 315771d10453SEric Joyner ice_move_vsi_to_agg(struct ice_port_info *pi, u32 agg_id, u16 vsi_handle, 315871d10453SEric Joyner u8 tc_bitmap) 315971d10453SEric Joyner { 316071d10453SEric Joyner ice_bitmap_t bitmap = tc_bitmap; 3161*f2635e84SEric Joyner int status; 316271d10453SEric Joyner 316371d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 316471d10453SEric Joyner status = ice_sched_assoc_vsi_to_agg(pi, agg_id, vsi_handle, 316571d10453SEric Joyner (ice_bitmap_t *)&bitmap); 316671d10453SEric Joyner if (!status) 316771d10453SEric Joyner status = ice_save_agg_vsi_tc_bitmap(pi, agg_id, vsi_handle, 316871d10453SEric Joyner (ice_bitmap_t *)&bitmap); 316971d10453SEric Joyner ice_release_lock(&pi->sched_lock); 317071d10453SEric Joyner return status; 317171d10453SEric Joyner } 317271d10453SEric Joyner 317371d10453SEric Joyner /** 317471d10453SEric Joyner * ice_rm_agg_cfg - remove aggregator configuration 317571d10453SEric Joyner * @pi: port information structure 317671d10453SEric Joyner * @agg_id: aggregator ID 317771d10453SEric Joyner * 317871d10453SEric Joyner * This function removes aggregator reference to VSI and delete aggregator ID 317971d10453SEric Joyner * info. It removes the aggregator configuration completely. 318071d10453SEric Joyner */ 3181*f2635e84SEric Joyner int ice_rm_agg_cfg(struct ice_port_info *pi, u32 agg_id) 318271d10453SEric Joyner { 318371d10453SEric Joyner struct ice_sched_agg_info *agg_info; 3184*f2635e84SEric Joyner int status = 0; 318571d10453SEric Joyner u8 tc; 318671d10453SEric Joyner 318771d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 318871d10453SEric Joyner agg_info = ice_get_agg_info(pi->hw, agg_id); 318971d10453SEric Joyner if (!agg_info) { 319071d10453SEric Joyner status = ICE_ERR_DOES_NOT_EXIST; 319171d10453SEric Joyner goto exit_ice_rm_agg_cfg; 319271d10453SEric Joyner } 319371d10453SEric Joyner 319471d10453SEric Joyner ice_for_each_traffic_class(tc) { 319571d10453SEric Joyner status = ice_rm_agg_cfg_tc(pi, agg_info, tc, true); 319671d10453SEric Joyner if (status) 319771d10453SEric Joyner goto exit_ice_rm_agg_cfg; 319871d10453SEric Joyner } 319971d10453SEric Joyner 320071d10453SEric Joyner if (ice_is_any_bit_set(agg_info->tc_bitmap, ICE_MAX_TRAFFIC_CLASS)) { 320171d10453SEric Joyner status = ICE_ERR_IN_USE; 320271d10453SEric Joyner goto exit_ice_rm_agg_cfg; 320371d10453SEric Joyner } 320471d10453SEric Joyner 320571d10453SEric Joyner /* Safe to delete entry now */ 320671d10453SEric Joyner LIST_DEL(&agg_info->list_entry); 320771d10453SEric Joyner ice_free(pi->hw, agg_info); 320871d10453SEric Joyner 320971d10453SEric Joyner /* Remove unused RL profile IDs from HW and SW DB */ 3210d08b8680SEric Joyner ice_sched_rm_unused_rl_prof(pi->hw); 321171d10453SEric Joyner 321271d10453SEric Joyner exit_ice_rm_agg_cfg: 321371d10453SEric Joyner ice_release_lock(&pi->sched_lock); 321471d10453SEric Joyner return status; 321571d10453SEric Joyner } 321671d10453SEric Joyner 321771d10453SEric Joyner /** 321871d10453SEric Joyner * ice_set_clear_cir_bw_alloc - set or clear CIR BW alloc information 321971d10453SEric Joyner * @bw_t_info: bandwidth type information structure 322071d10453SEric Joyner * @bw_alloc: Bandwidth allocation information 322171d10453SEric Joyner * 322271d10453SEric Joyner * Save or clear CIR BW alloc information (bw_alloc) in the passed param 322371d10453SEric Joyner * bw_t_info. 322471d10453SEric Joyner */ 322571d10453SEric Joyner static void 322671d10453SEric Joyner ice_set_clear_cir_bw_alloc(struct ice_bw_type_info *bw_t_info, u16 bw_alloc) 322771d10453SEric Joyner { 322871d10453SEric Joyner bw_t_info->cir_bw.bw_alloc = bw_alloc; 322971d10453SEric Joyner if (bw_t_info->cir_bw.bw_alloc) 323071d10453SEric Joyner ice_set_bit(ICE_BW_TYPE_CIR_WT, bw_t_info->bw_t_bitmap); 323171d10453SEric Joyner else 323271d10453SEric Joyner ice_clear_bit(ICE_BW_TYPE_CIR_WT, bw_t_info->bw_t_bitmap); 323371d10453SEric Joyner } 323471d10453SEric Joyner 323571d10453SEric Joyner /** 323671d10453SEric Joyner * ice_set_clear_eir_bw_alloc - set or clear EIR BW alloc information 323771d10453SEric Joyner * @bw_t_info: bandwidth type information structure 323871d10453SEric Joyner * @bw_alloc: Bandwidth allocation information 323971d10453SEric Joyner * 324071d10453SEric Joyner * Save or clear EIR BW alloc information (bw_alloc) in the passed param 324171d10453SEric Joyner * bw_t_info. 324271d10453SEric Joyner */ 324371d10453SEric Joyner static void 324471d10453SEric Joyner ice_set_clear_eir_bw_alloc(struct ice_bw_type_info *bw_t_info, u16 bw_alloc) 324571d10453SEric Joyner { 324671d10453SEric Joyner bw_t_info->eir_bw.bw_alloc = bw_alloc; 324771d10453SEric Joyner if (bw_t_info->eir_bw.bw_alloc) 324871d10453SEric Joyner ice_set_bit(ICE_BW_TYPE_EIR_WT, bw_t_info->bw_t_bitmap); 324971d10453SEric Joyner else 325071d10453SEric Joyner ice_clear_bit(ICE_BW_TYPE_EIR_WT, bw_t_info->bw_t_bitmap); 325171d10453SEric Joyner } 325271d10453SEric Joyner 325371d10453SEric Joyner /** 325471d10453SEric Joyner * ice_sched_save_vsi_bw_alloc - save VSI node's BW alloc information 325571d10453SEric Joyner * @pi: port information structure 325671d10453SEric Joyner * @vsi_handle: sw VSI handle 325771d10453SEric Joyner * @tc: traffic class 325871d10453SEric Joyner * @rl_type: rate limit type min or max 325971d10453SEric Joyner * @bw_alloc: Bandwidth allocation information 326071d10453SEric Joyner * 326171d10453SEric Joyner * Save BW alloc information of VSI type node for post replay use. 326271d10453SEric Joyner */ 3263*f2635e84SEric Joyner static int 326471d10453SEric Joyner ice_sched_save_vsi_bw_alloc(struct ice_port_info *pi, u16 vsi_handle, u8 tc, 326571d10453SEric Joyner enum ice_rl_type rl_type, u16 bw_alloc) 326671d10453SEric Joyner { 326771d10453SEric Joyner struct ice_vsi_ctx *vsi_ctx; 326871d10453SEric Joyner 326971d10453SEric Joyner if (!ice_is_vsi_valid(pi->hw, vsi_handle)) 327071d10453SEric Joyner return ICE_ERR_PARAM; 327171d10453SEric Joyner vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle); 327271d10453SEric Joyner if (!vsi_ctx) 327371d10453SEric Joyner return ICE_ERR_PARAM; 327471d10453SEric Joyner switch (rl_type) { 327571d10453SEric Joyner case ICE_MIN_BW: 327671d10453SEric Joyner ice_set_clear_cir_bw_alloc(&vsi_ctx->sched.bw_t_info[tc], 327771d10453SEric Joyner bw_alloc); 327871d10453SEric Joyner break; 327971d10453SEric Joyner case ICE_MAX_BW: 328071d10453SEric Joyner ice_set_clear_eir_bw_alloc(&vsi_ctx->sched.bw_t_info[tc], 328171d10453SEric Joyner bw_alloc); 328271d10453SEric Joyner break; 328371d10453SEric Joyner default: 328471d10453SEric Joyner return ICE_ERR_PARAM; 328571d10453SEric Joyner } 3286*f2635e84SEric Joyner return 0; 328771d10453SEric Joyner } 328871d10453SEric Joyner 328971d10453SEric Joyner /** 329071d10453SEric Joyner * ice_set_clear_cir_bw - set or clear CIR BW 329171d10453SEric Joyner * @bw_t_info: bandwidth type information structure 329271d10453SEric Joyner * @bw: bandwidth in Kbps - Kilo bits per sec 329371d10453SEric Joyner * 329471d10453SEric Joyner * Save or clear CIR bandwidth (BW) in the passed param bw_t_info. 329571d10453SEric Joyner */ 32967d7af7f8SEric Joyner static void ice_set_clear_cir_bw(struct ice_bw_type_info *bw_t_info, u32 bw) 329771d10453SEric Joyner { 329871d10453SEric Joyner if (bw == ICE_SCHED_DFLT_BW) { 329971d10453SEric Joyner ice_clear_bit(ICE_BW_TYPE_CIR, bw_t_info->bw_t_bitmap); 330071d10453SEric Joyner bw_t_info->cir_bw.bw = 0; 330171d10453SEric Joyner } else { 330271d10453SEric Joyner /* Save type of BW information */ 330371d10453SEric Joyner ice_set_bit(ICE_BW_TYPE_CIR, bw_t_info->bw_t_bitmap); 330471d10453SEric Joyner bw_t_info->cir_bw.bw = bw; 330571d10453SEric Joyner } 330671d10453SEric Joyner } 330771d10453SEric Joyner 330871d10453SEric Joyner /** 330971d10453SEric Joyner * ice_set_clear_eir_bw - set or clear EIR BW 331071d10453SEric Joyner * @bw_t_info: bandwidth type information structure 331171d10453SEric Joyner * @bw: bandwidth in Kbps - Kilo bits per sec 331271d10453SEric Joyner * 331371d10453SEric Joyner * Save or clear EIR bandwidth (BW) in the passed param bw_t_info. 331471d10453SEric Joyner */ 33157d7af7f8SEric Joyner static void ice_set_clear_eir_bw(struct ice_bw_type_info *bw_t_info, u32 bw) 331671d10453SEric Joyner { 331771d10453SEric Joyner if (bw == ICE_SCHED_DFLT_BW) { 331871d10453SEric Joyner ice_clear_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap); 331971d10453SEric Joyner bw_t_info->eir_bw.bw = 0; 332071d10453SEric Joyner } else { 332171d10453SEric Joyner /* save EIR BW information */ 332271d10453SEric Joyner ice_set_bit(ICE_BW_TYPE_EIR, bw_t_info->bw_t_bitmap); 332371d10453SEric Joyner bw_t_info->eir_bw.bw = bw; 332471d10453SEric Joyner } 332571d10453SEric Joyner } 332671d10453SEric Joyner 332771d10453SEric Joyner /** 332871d10453SEric Joyner * ice_set_clear_shared_bw - set or clear shared BW 332971d10453SEric Joyner * @bw_t_info: bandwidth type information structure 333071d10453SEric Joyner * @bw: bandwidth in Kbps - Kilo bits per sec 333171d10453SEric Joyner * 333271d10453SEric Joyner * Save or clear shared bandwidth (BW) in the passed param bw_t_info. 333371d10453SEric Joyner */ 33347d7af7f8SEric Joyner static void ice_set_clear_shared_bw(struct ice_bw_type_info *bw_t_info, u32 bw) 333571d10453SEric Joyner { 333671d10453SEric Joyner if (bw == ICE_SCHED_DFLT_BW) { 333771d10453SEric Joyner ice_clear_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap); 333871d10453SEric Joyner bw_t_info->shared_bw = 0; 333971d10453SEric Joyner } else { 334071d10453SEric Joyner /* save shared BW information */ 334171d10453SEric Joyner ice_set_bit(ICE_BW_TYPE_SHARED, bw_t_info->bw_t_bitmap); 334271d10453SEric Joyner bw_t_info->shared_bw = bw; 334371d10453SEric Joyner } 334471d10453SEric Joyner } 334571d10453SEric Joyner 334671d10453SEric Joyner /** 334771d10453SEric Joyner * ice_sched_save_vsi_bw - save VSI node's BW information 334871d10453SEric Joyner * @pi: port information structure 334971d10453SEric Joyner * @vsi_handle: sw VSI handle 335071d10453SEric Joyner * @tc: traffic class 335171d10453SEric Joyner * @rl_type: rate limit type min, max, or shared 335271d10453SEric Joyner * @bw: bandwidth in Kbps - Kilo bits per sec 335371d10453SEric Joyner * 335471d10453SEric Joyner * Save BW information of VSI type node for post replay use. 335571d10453SEric Joyner */ 3356*f2635e84SEric Joyner static int 335771d10453SEric Joyner ice_sched_save_vsi_bw(struct ice_port_info *pi, u16 vsi_handle, u8 tc, 335871d10453SEric Joyner enum ice_rl_type rl_type, u32 bw) 335971d10453SEric Joyner { 336071d10453SEric Joyner struct ice_vsi_ctx *vsi_ctx; 336171d10453SEric Joyner 336271d10453SEric Joyner if (!ice_is_vsi_valid(pi->hw, vsi_handle)) 336371d10453SEric Joyner return ICE_ERR_PARAM; 336471d10453SEric Joyner vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle); 336571d10453SEric Joyner if (!vsi_ctx) 336671d10453SEric Joyner return ICE_ERR_PARAM; 336771d10453SEric Joyner switch (rl_type) { 336871d10453SEric Joyner case ICE_MIN_BW: 336971d10453SEric Joyner ice_set_clear_cir_bw(&vsi_ctx->sched.bw_t_info[tc], bw); 337071d10453SEric Joyner break; 337171d10453SEric Joyner case ICE_MAX_BW: 337271d10453SEric Joyner ice_set_clear_eir_bw(&vsi_ctx->sched.bw_t_info[tc], bw); 337371d10453SEric Joyner break; 337471d10453SEric Joyner case ICE_SHARED_BW: 337571d10453SEric Joyner ice_set_clear_shared_bw(&vsi_ctx->sched.bw_t_info[tc], bw); 337671d10453SEric Joyner break; 337771d10453SEric Joyner default: 337871d10453SEric Joyner return ICE_ERR_PARAM; 337971d10453SEric Joyner } 3380*f2635e84SEric Joyner return 0; 338171d10453SEric Joyner } 338271d10453SEric Joyner 338371d10453SEric Joyner /** 338471d10453SEric Joyner * ice_set_clear_prio - set or clear priority information 338571d10453SEric Joyner * @bw_t_info: bandwidth type information structure 338671d10453SEric Joyner * @prio: priority to save 338771d10453SEric Joyner * 338871d10453SEric Joyner * Save or clear priority (prio) in the passed param bw_t_info. 338971d10453SEric Joyner */ 33907d7af7f8SEric Joyner static void ice_set_clear_prio(struct ice_bw_type_info *bw_t_info, u8 prio) 339171d10453SEric Joyner { 339271d10453SEric Joyner bw_t_info->generic = prio; 339371d10453SEric Joyner if (bw_t_info->generic) 339471d10453SEric Joyner ice_set_bit(ICE_BW_TYPE_PRIO, bw_t_info->bw_t_bitmap); 339571d10453SEric Joyner else 339671d10453SEric Joyner ice_clear_bit(ICE_BW_TYPE_PRIO, bw_t_info->bw_t_bitmap); 339771d10453SEric Joyner } 339871d10453SEric Joyner 339971d10453SEric Joyner /** 340071d10453SEric Joyner * ice_sched_save_vsi_prio - save VSI node's priority information 340171d10453SEric Joyner * @pi: port information structure 340271d10453SEric Joyner * @vsi_handle: Software VSI handle 340371d10453SEric Joyner * @tc: traffic class 340471d10453SEric Joyner * @prio: priority to save 340571d10453SEric Joyner * 340671d10453SEric Joyner * Save priority information of VSI type node for post replay use. 340771d10453SEric Joyner */ 3408*f2635e84SEric Joyner static int 340971d10453SEric Joyner ice_sched_save_vsi_prio(struct ice_port_info *pi, u16 vsi_handle, u8 tc, 341071d10453SEric Joyner u8 prio) 341171d10453SEric Joyner { 341271d10453SEric Joyner struct ice_vsi_ctx *vsi_ctx; 341371d10453SEric Joyner 341471d10453SEric Joyner if (!ice_is_vsi_valid(pi->hw, vsi_handle)) 341571d10453SEric Joyner return ICE_ERR_PARAM; 341671d10453SEric Joyner vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle); 341771d10453SEric Joyner if (!vsi_ctx) 341871d10453SEric Joyner return ICE_ERR_PARAM; 341971d10453SEric Joyner if (tc >= ICE_MAX_TRAFFIC_CLASS) 342071d10453SEric Joyner return ICE_ERR_PARAM; 342171d10453SEric Joyner ice_set_clear_prio(&vsi_ctx->sched.bw_t_info[tc], prio); 3422*f2635e84SEric Joyner return 0; 342371d10453SEric Joyner } 342471d10453SEric Joyner 342571d10453SEric Joyner /** 342671d10453SEric Joyner * ice_sched_save_agg_bw_alloc - save aggregator node's BW alloc information 342771d10453SEric Joyner * @pi: port information structure 342871d10453SEric Joyner * @agg_id: node aggregator ID 342971d10453SEric Joyner * @tc: traffic class 343071d10453SEric Joyner * @rl_type: rate limit type min or max 343171d10453SEric Joyner * @bw_alloc: bandwidth alloc information 343271d10453SEric Joyner * 343371d10453SEric Joyner * Save BW alloc information of AGG type node for post replay use. 343471d10453SEric Joyner */ 3435*f2635e84SEric Joyner static int 343671d10453SEric Joyner ice_sched_save_agg_bw_alloc(struct ice_port_info *pi, u32 agg_id, u8 tc, 343771d10453SEric Joyner enum ice_rl_type rl_type, u16 bw_alloc) 343871d10453SEric Joyner { 343971d10453SEric Joyner struct ice_sched_agg_info *agg_info; 344071d10453SEric Joyner 344171d10453SEric Joyner agg_info = ice_get_agg_info(pi->hw, agg_id); 344271d10453SEric Joyner if (!agg_info) 344371d10453SEric Joyner return ICE_ERR_PARAM; 344471d10453SEric Joyner if (!ice_is_tc_ena(agg_info->tc_bitmap[0], tc)) 344571d10453SEric Joyner return ICE_ERR_PARAM; 344671d10453SEric Joyner switch (rl_type) { 344771d10453SEric Joyner case ICE_MIN_BW: 344871d10453SEric Joyner ice_set_clear_cir_bw_alloc(&agg_info->bw_t_info[tc], bw_alloc); 344971d10453SEric Joyner break; 345071d10453SEric Joyner case ICE_MAX_BW: 345171d10453SEric Joyner ice_set_clear_eir_bw_alloc(&agg_info->bw_t_info[tc], bw_alloc); 345271d10453SEric Joyner break; 345371d10453SEric Joyner default: 345471d10453SEric Joyner return ICE_ERR_PARAM; 345571d10453SEric Joyner } 3456*f2635e84SEric Joyner return 0; 345771d10453SEric Joyner } 345871d10453SEric Joyner 345971d10453SEric Joyner /** 346071d10453SEric Joyner * ice_sched_save_agg_bw - save aggregator node's BW information 346171d10453SEric Joyner * @pi: port information structure 346271d10453SEric Joyner * @agg_id: node aggregator ID 346371d10453SEric Joyner * @tc: traffic class 346471d10453SEric Joyner * @rl_type: rate limit type min, max, or shared 346571d10453SEric Joyner * @bw: bandwidth in Kbps - Kilo bits per sec 346671d10453SEric Joyner * 346771d10453SEric Joyner * Save BW information of AGG type node for post replay use. 346871d10453SEric Joyner */ 3469*f2635e84SEric Joyner static int 347071d10453SEric Joyner ice_sched_save_agg_bw(struct ice_port_info *pi, u32 agg_id, u8 tc, 347171d10453SEric Joyner enum ice_rl_type rl_type, u32 bw) 347271d10453SEric Joyner { 347371d10453SEric Joyner struct ice_sched_agg_info *agg_info; 347471d10453SEric Joyner 347571d10453SEric Joyner agg_info = ice_get_agg_info(pi->hw, agg_id); 347671d10453SEric Joyner if (!agg_info) 347771d10453SEric Joyner return ICE_ERR_PARAM; 347871d10453SEric Joyner if (!ice_is_tc_ena(agg_info->tc_bitmap[0], tc)) 347971d10453SEric Joyner return ICE_ERR_PARAM; 348071d10453SEric Joyner switch (rl_type) { 348171d10453SEric Joyner case ICE_MIN_BW: 348271d10453SEric Joyner ice_set_clear_cir_bw(&agg_info->bw_t_info[tc], bw); 348371d10453SEric Joyner break; 348471d10453SEric Joyner case ICE_MAX_BW: 348571d10453SEric Joyner ice_set_clear_eir_bw(&agg_info->bw_t_info[tc], bw); 348671d10453SEric Joyner break; 348771d10453SEric Joyner case ICE_SHARED_BW: 348871d10453SEric Joyner ice_set_clear_shared_bw(&agg_info->bw_t_info[tc], bw); 348971d10453SEric Joyner break; 349071d10453SEric Joyner default: 349171d10453SEric Joyner return ICE_ERR_PARAM; 349271d10453SEric Joyner } 3493*f2635e84SEric Joyner return 0; 349471d10453SEric Joyner } 349571d10453SEric Joyner 349671d10453SEric Joyner /** 349771d10453SEric Joyner * ice_cfg_vsi_bw_lmt_per_tc - configure VSI BW limit per TC 349871d10453SEric Joyner * @pi: port information structure 349971d10453SEric Joyner * @vsi_handle: software VSI handle 350071d10453SEric Joyner * @tc: traffic class 350171d10453SEric Joyner * @rl_type: min or max 350271d10453SEric Joyner * @bw: bandwidth in Kbps 350371d10453SEric Joyner * 350471d10453SEric Joyner * This function configures BW limit of VSI scheduling node based on TC 350571d10453SEric Joyner * information. 350671d10453SEric Joyner */ 3507*f2635e84SEric Joyner int 350871d10453SEric Joyner ice_cfg_vsi_bw_lmt_per_tc(struct ice_port_info *pi, u16 vsi_handle, u8 tc, 350971d10453SEric Joyner enum ice_rl_type rl_type, u32 bw) 351071d10453SEric Joyner { 3511*f2635e84SEric Joyner int status; 351271d10453SEric Joyner 351371d10453SEric Joyner status = ice_sched_set_node_bw_lmt_per_tc(pi, vsi_handle, 351471d10453SEric Joyner ICE_AGG_TYPE_VSI, 351571d10453SEric Joyner tc, rl_type, bw); 351671d10453SEric Joyner if (!status) { 351771d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 351871d10453SEric Joyner status = ice_sched_save_vsi_bw(pi, vsi_handle, tc, rl_type, bw); 351971d10453SEric Joyner ice_release_lock(&pi->sched_lock); 352071d10453SEric Joyner } 352171d10453SEric Joyner return status; 352271d10453SEric Joyner } 352371d10453SEric Joyner 352471d10453SEric Joyner /** 352556429daeSEric Joyner * ice_cfg_vsi_bw_dflt_lmt_per_tc - configure default VSI BW limit per TC 352671d10453SEric Joyner * @pi: port information structure 352771d10453SEric Joyner * @vsi_handle: software VSI handle 352871d10453SEric Joyner * @tc: traffic class 352971d10453SEric Joyner * @rl_type: min or max 353071d10453SEric Joyner * 353171d10453SEric Joyner * This function configures default BW limit of VSI scheduling node based on TC 353271d10453SEric Joyner * information. 353371d10453SEric Joyner */ 3534*f2635e84SEric Joyner int 353571d10453SEric Joyner ice_cfg_vsi_bw_dflt_lmt_per_tc(struct ice_port_info *pi, u16 vsi_handle, u8 tc, 353671d10453SEric Joyner enum ice_rl_type rl_type) 353771d10453SEric Joyner { 3538*f2635e84SEric Joyner int status; 353971d10453SEric Joyner 354071d10453SEric Joyner status = ice_sched_set_node_bw_lmt_per_tc(pi, vsi_handle, 354171d10453SEric Joyner ICE_AGG_TYPE_VSI, 354271d10453SEric Joyner tc, rl_type, 354371d10453SEric Joyner ICE_SCHED_DFLT_BW); 354471d10453SEric Joyner if (!status) { 354571d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 354671d10453SEric Joyner status = ice_sched_save_vsi_bw(pi, vsi_handle, tc, rl_type, 354771d10453SEric Joyner ICE_SCHED_DFLT_BW); 354871d10453SEric Joyner ice_release_lock(&pi->sched_lock); 354971d10453SEric Joyner } 355071d10453SEric Joyner return status; 355171d10453SEric Joyner } 355271d10453SEric Joyner 355371d10453SEric Joyner /** 355471d10453SEric Joyner * ice_cfg_agg_bw_lmt_per_tc - configure aggregator BW limit per TC 355571d10453SEric Joyner * @pi: port information structure 355671d10453SEric Joyner * @agg_id: aggregator ID 355771d10453SEric Joyner * @tc: traffic class 355871d10453SEric Joyner * @rl_type: min or max 355971d10453SEric Joyner * @bw: bandwidth in Kbps 356071d10453SEric Joyner * 356171d10453SEric Joyner * This function applies BW limit to aggregator scheduling node based on TC 356271d10453SEric Joyner * information. 356371d10453SEric Joyner */ 3564*f2635e84SEric Joyner int 356571d10453SEric Joyner ice_cfg_agg_bw_lmt_per_tc(struct ice_port_info *pi, u32 agg_id, u8 tc, 356671d10453SEric Joyner enum ice_rl_type rl_type, u32 bw) 356771d10453SEric Joyner { 3568*f2635e84SEric Joyner int status; 356971d10453SEric Joyner 357071d10453SEric Joyner status = ice_sched_set_node_bw_lmt_per_tc(pi, agg_id, ICE_AGG_TYPE_AGG, 357171d10453SEric Joyner tc, rl_type, bw); 357271d10453SEric Joyner if (!status) { 357371d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 357471d10453SEric Joyner status = ice_sched_save_agg_bw(pi, agg_id, tc, rl_type, bw); 357571d10453SEric Joyner ice_release_lock(&pi->sched_lock); 357671d10453SEric Joyner } 357771d10453SEric Joyner return status; 357871d10453SEric Joyner } 357971d10453SEric Joyner 358071d10453SEric Joyner /** 358171d10453SEric Joyner * ice_cfg_agg_bw_dflt_lmt_per_tc - configure aggregator BW default limit per TC 358271d10453SEric Joyner * @pi: port information structure 358371d10453SEric Joyner * @agg_id: aggregator ID 358471d10453SEric Joyner * @tc: traffic class 358571d10453SEric Joyner * @rl_type: min or max 358671d10453SEric Joyner * 358771d10453SEric Joyner * This function applies default BW limit to aggregator scheduling node based 358871d10453SEric Joyner * on TC information. 358971d10453SEric Joyner */ 3590*f2635e84SEric Joyner int 359171d10453SEric Joyner ice_cfg_agg_bw_dflt_lmt_per_tc(struct ice_port_info *pi, u32 agg_id, u8 tc, 359271d10453SEric Joyner enum ice_rl_type rl_type) 359371d10453SEric Joyner { 3594*f2635e84SEric Joyner int status; 359571d10453SEric Joyner 359671d10453SEric Joyner status = ice_sched_set_node_bw_lmt_per_tc(pi, agg_id, ICE_AGG_TYPE_AGG, 359771d10453SEric Joyner tc, rl_type, 359871d10453SEric Joyner ICE_SCHED_DFLT_BW); 359971d10453SEric Joyner if (!status) { 360071d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 360171d10453SEric Joyner status = ice_sched_save_agg_bw(pi, agg_id, tc, rl_type, 360271d10453SEric Joyner ICE_SCHED_DFLT_BW); 360371d10453SEric Joyner ice_release_lock(&pi->sched_lock); 360471d10453SEric Joyner } 360571d10453SEric Joyner return status; 360671d10453SEric Joyner } 360771d10453SEric Joyner 360871d10453SEric Joyner /** 360971d10453SEric Joyner * ice_cfg_vsi_bw_shared_lmt - configure VSI BW shared limit 361071d10453SEric Joyner * @pi: port information structure 361171d10453SEric Joyner * @vsi_handle: software VSI handle 3612d08b8680SEric Joyner * @min_bw: minimum bandwidth in Kbps 3613d08b8680SEric Joyner * @max_bw: maximum bandwidth in Kbps 3614d08b8680SEric Joyner * @shared_bw: shared bandwidth in Kbps 361571d10453SEric Joyner * 3616d08b8680SEric Joyner * Configure shared rate limiter(SRL) of all VSI type nodes across all traffic 3617d08b8680SEric Joyner * classes for VSI matching handle. 361871d10453SEric Joyner */ 3619*f2635e84SEric Joyner int 3620d08b8680SEric Joyner ice_cfg_vsi_bw_shared_lmt(struct ice_port_info *pi, u16 vsi_handle, u32 min_bw, 3621d08b8680SEric Joyner u32 max_bw, u32 shared_bw) 362271d10453SEric Joyner { 3623d08b8680SEric Joyner return ice_sched_set_vsi_bw_shared_lmt(pi, vsi_handle, min_bw, max_bw, 3624d08b8680SEric Joyner shared_bw); 362571d10453SEric Joyner } 362671d10453SEric Joyner 362771d10453SEric Joyner /** 362871d10453SEric Joyner * ice_cfg_vsi_bw_no_shared_lmt - configure VSI BW for no shared limiter 362971d10453SEric Joyner * @pi: port information structure 363071d10453SEric Joyner * @vsi_handle: software VSI handle 363171d10453SEric Joyner * 363271d10453SEric Joyner * This function removes the shared rate limiter(SRL) of all VSI type nodes 363371d10453SEric Joyner * across all traffic classes for VSI matching handle. 363471d10453SEric Joyner */ 3635*f2635e84SEric Joyner int 363671d10453SEric Joyner ice_cfg_vsi_bw_no_shared_lmt(struct ice_port_info *pi, u16 vsi_handle) 363771d10453SEric Joyner { 363871d10453SEric Joyner return ice_sched_set_vsi_bw_shared_lmt(pi, vsi_handle, 3639d08b8680SEric Joyner ICE_SCHED_DFLT_BW, 3640d08b8680SEric Joyner ICE_SCHED_DFLT_BW, 364171d10453SEric Joyner ICE_SCHED_DFLT_BW); 364271d10453SEric Joyner } 364371d10453SEric Joyner 364471d10453SEric Joyner /** 364571d10453SEric Joyner * ice_cfg_agg_bw_shared_lmt - configure aggregator BW shared limit 364671d10453SEric Joyner * @pi: port information structure 364771d10453SEric Joyner * @agg_id: aggregator ID 3648d08b8680SEric Joyner * @min_bw: minimum bandwidth in Kbps 3649d08b8680SEric Joyner * @max_bw: maximum bandwidth in Kbps 3650d08b8680SEric Joyner * @shared_bw: shared bandwidth in Kbps 365171d10453SEric Joyner * 365271d10453SEric Joyner * This function configures the shared rate limiter(SRL) of all aggregator type 365371d10453SEric Joyner * nodes across all traffic classes for aggregator matching agg_id. 365471d10453SEric Joyner */ 3655*f2635e84SEric Joyner int 3656d08b8680SEric Joyner ice_cfg_agg_bw_shared_lmt(struct ice_port_info *pi, u32 agg_id, u32 min_bw, 3657d08b8680SEric Joyner u32 max_bw, u32 shared_bw) 365871d10453SEric Joyner { 3659d08b8680SEric Joyner return ice_sched_set_agg_bw_shared_lmt(pi, agg_id, min_bw, max_bw, 3660d08b8680SEric Joyner shared_bw); 366171d10453SEric Joyner } 366271d10453SEric Joyner 366371d10453SEric Joyner /** 366471d10453SEric Joyner * ice_cfg_agg_bw_no_shared_lmt - configure aggregator BW for no shared limiter 366571d10453SEric Joyner * @pi: port information structure 366671d10453SEric Joyner * @agg_id: aggregator ID 366771d10453SEric Joyner * 366871d10453SEric Joyner * This function removes the shared rate limiter(SRL) of all aggregator type 366971d10453SEric Joyner * nodes across all traffic classes for aggregator matching agg_id. 367071d10453SEric Joyner */ 3671*f2635e84SEric Joyner int 367271d10453SEric Joyner ice_cfg_agg_bw_no_shared_lmt(struct ice_port_info *pi, u32 agg_id) 367371d10453SEric Joyner { 3674d08b8680SEric Joyner return ice_sched_set_agg_bw_shared_lmt(pi, agg_id, ICE_SCHED_DFLT_BW, 3675d08b8680SEric Joyner ICE_SCHED_DFLT_BW, 3676d08b8680SEric Joyner ICE_SCHED_DFLT_BW); 3677d08b8680SEric Joyner } 3678d08b8680SEric Joyner 3679d08b8680SEric Joyner /** 368056429daeSEric Joyner * ice_cfg_agg_bw_shared_lmt_per_tc - config aggregator BW shared limit per tc 3681d08b8680SEric Joyner * @pi: port information structure 3682d08b8680SEric Joyner * @agg_id: aggregator ID 3683d08b8680SEric Joyner * @tc: traffic class 3684d08b8680SEric Joyner * @min_bw: minimum bandwidth in Kbps 3685d08b8680SEric Joyner * @max_bw: maximum bandwidth in Kbps 3686d08b8680SEric Joyner * @shared_bw: shared bandwidth in Kbps 3687d08b8680SEric Joyner * 3688d08b8680SEric Joyner * This function configures the shared rate limiter(SRL) of all aggregator type 3689d08b8680SEric Joyner * nodes across all traffic classes for aggregator matching agg_id. 3690d08b8680SEric Joyner */ 3691*f2635e84SEric Joyner int 3692d08b8680SEric Joyner ice_cfg_agg_bw_shared_lmt_per_tc(struct ice_port_info *pi, u32 agg_id, u8 tc, 3693d08b8680SEric Joyner u32 min_bw, u32 max_bw, u32 shared_bw) 3694d08b8680SEric Joyner { 3695d08b8680SEric Joyner return ice_sched_set_agg_bw_shared_lmt_per_tc(pi, agg_id, tc, min_bw, 3696d08b8680SEric Joyner max_bw, shared_bw); 3697d08b8680SEric Joyner } 3698d08b8680SEric Joyner 3699d08b8680SEric Joyner /** 370056429daeSEric Joyner * ice_cfg_agg_bw_no_shared_lmt_per_tc - cfg aggregator BW shared limit per tc 3701d08b8680SEric Joyner * @pi: port information structure 3702d08b8680SEric Joyner * @agg_id: aggregator ID 3703d08b8680SEric Joyner * @tc: traffic class 3704d08b8680SEric Joyner * 3705d08b8680SEric Joyner * This function configures the shared rate limiter(SRL) of all aggregator type 3706d08b8680SEric Joyner * nodes across all traffic classes for aggregator matching agg_id. 3707d08b8680SEric Joyner */ 3708*f2635e84SEric Joyner int 3709d08b8680SEric Joyner ice_cfg_agg_bw_no_shared_lmt_per_tc(struct ice_port_info *pi, u32 agg_id, u8 tc) 3710d08b8680SEric Joyner { 3711d08b8680SEric Joyner return ice_sched_set_agg_bw_shared_lmt_per_tc(pi, agg_id, tc, 3712d08b8680SEric Joyner ICE_SCHED_DFLT_BW, 3713d08b8680SEric Joyner ICE_SCHED_DFLT_BW, 3714d08b8680SEric Joyner ICE_SCHED_DFLT_BW); 371571d10453SEric Joyner } 371671d10453SEric Joyner 371771d10453SEric Joyner /** 371856429daeSEric Joyner * ice_cfg_vsi_q_priority - config VSI queue priority of node 371971d10453SEric Joyner * @pi: port information structure 372071d10453SEric Joyner * @num_qs: number of VSI queues 372171d10453SEric Joyner * @q_ids: queue IDs array 372271d10453SEric Joyner * @q_prio: queue priority array 372371d10453SEric Joyner * 372471d10453SEric Joyner * This function configures the queue node priority (Sibling Priority) of the 372571d10453SEric Joyner * passed in VSI's queue(s) for a given traffic class (TC). 372671d10453SEric Joyner */ 3727*f2635e84SEric Joyner int 372871d10453SEric Joyner ice_cfg_vsi_q_priority(struct ice_port_info *pi, u16 num_qs, u32 *q_ids, 372971d10453SEric Joyner u8 *q_prio) 373071d10453SEric Joyner { 3731*f2635e84SEric Joyner int status = ICE_ERR_PARAM; 373271d10453SEric Joyner u16 i; 373371d10453SEric Joyner 373471d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 373571d10453SEric Joyner 373671d10453SEric Joyner for (i = 0; i < num_qs; i++) { 373771d10453SEric Joyner struct ice_sched_node *node; 373871d10453SEric Joyner 373971d10453SEric Joyner node = ice_sched_find_node_by_teid(pi->root, q_ids[i]); 374071d10453SEric Joyner if (!node || node->info.data.elem_type != 374171d10453SEric Joyner ICE_AQC_ELEM_TYPE_LEAF) { 374271d10453SEric Joyner status = ICE_ERR_PARAM; 374371d10453SEric Joyner break; 374471d10453SEric Joyner } 374571d10453SEric Joyner /* Configure Priority */ 374671d10453SEric Joyner status = ice_sched_cfg_sibl_node_prio(pi, node, q_prio[i]); 374771d10453SEric Joyner if (status) 374871d10453SEric Joyner break; 374971d10453SEric Joyner } 375071d10453SEric Joyner 375171d10453SEric Joyner ice_release_lock(&pi->sched_lock); 375271d10453SEric Joyner return status; 375371d10453SEric Joyner } 375471d10453SEric Joyner 375571d10453SEric Joyner /** 375671d10453SEric Joyner * ice_cfg_agg_vsi_priority_per_tc - config aggregator's VSI priority per TC 375771d10453SEric Joyner * @pi: port information structure 375871d10453SEric Joyner * @agg_id: Aggregator ID 375971d10453SEric Joyner * @num_vsis: number of VSI(s) 376071d10453SEric Joyner * @vsi_handle_arr: array of software VSI handles 376171d10453SEric Joyner * @node_prio: pointer to node priority 376271d10453SEric Joyner * @tc: traffic class 376371d10453SEric Joyner * 376471d10453SEric Joyner * This function configures the node priority (Sibling Priority) of the 376571d10453SEric Joyner * passed in VSI's for a given traffic class (TC) of an Aggregator ID. 376671d10453SEric Joyner */ 3767*f2635e84SEric Joyner int 376871d10453SEric Joyner ice_cfg_agg_vsi_priority_per_tc(struct ice_port_info *pi, u32 agg_id, 376971d10453SEric Joyner u16 num_vsis, u16 *vsi_handle_arr, 377071d10453SEric Joyner u8 *node_prio, u8 tc) 377171d10453SEric Joyner { 377271d10453SEric Joyner struct ice_sched_agg_vsi_info *agg_vsi_info; 377371d10453SEric Joyner struct ice_sched_node *tc_node, *agg_node; 377471d10453SEric Joyner struct ice_sched_agg_info *agg_info; 377571d10453SEric Joyner bool agg_id_present = false; 377671d10453SEric Joyner struct ice_hw *hw = pi->hw; 3777*f2635e84SEric Joyner int status = ICE_ERR_PARAM; 377871d10453SEric Joyner u16 i; 377971d10453SEric Joyner 378071d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 378171d10453SEric Joyner LIST_FOR_EACH_ENTRY(agg_info, &hw->agg_list, ice_sched_agg_info, 378271d10453SEric Joyner list_entry) 378371d10453SEric Joyner if (agg_info->agg_id == agg_id) { 378471d10453SEric Joyner agg_id_present = true; 378571d10453SEric Joyner break; 378671d10453SEric Joyner } 378771d10453SEric Joyner if (!agg_id_present) 378871d10453SEric Joyner goto exit_agg_priority_per_tc; 378971d10453SEric Joyner 379071d10453SEric Joyner tc_node = ice_sched_get_tc_node(pi, tc); 379171d10453SEric Joyner if (!tc_node) 379271d10453SEric Joyner goto exit_agg_priority_per_tc; 379371d10453SEric Joyner 379471d10453SEric Joyner agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id); 379571d10453SEric Joyner if (!agg_node) 379671d10453SEric Joyner goto exit_agg_priority_per_tc; 379771d10453SEric Joyner 379871d10453SEric Joyner if (num_vsis > hw->max_children[agg_node->tx_sched_layer]) 379971d10453SEric Joyner goto exit_agg_priority_per_tc; 380071d10453SEric Joyner 380171d10453SEric Joyner for (i = 0; i < num_vsis; i++) { 380271d10453SEric Joyner struct ice_sched_node *vsi_node; 380371d10453SEric Joyner bool vsi_handle_valid = false; 380471d10453SEric Joyner u16 vsi_handle; 380571d10453SEric Joyner 380671d10453SEric Joyner status = ICE_ERR_PARAM; 380771d10453SEric Joyner vsi_handle = vsi_handle_arr[i]; 380871d10453SEric Joyner if (!ice_is_vsi_valid(hw, vsi_handle)) 380971d10453SEric Joyner goto exit_agg_priority_per_tc; 381071d10453SEric Joyner /* Verify child nodes before applying settings */ 381171d10453SEric Joyner LIST_FOR_EACH_ENTRY(agg_vsi_info, &agg_info->agg_vsi_list, 381271d10453SEric Joyner ice_sched_agg_vsi_info, list_entry) 381371d10453SEric Joyner if (agg_vsi_info->vsi_handle == vsi_handle) { 381471d10453SEric Joyner vsi_handle_valid = true; 381571d10453SEric Joyner break; 381671d10453SEric Joyner } 381771d10453SEric Joyner 381871d10453SEric Joyner if (!vsi_handle_valid) 381971d10453SEric Joyner goto exit_agg_priority_per_tc; 382071d10453SEric Joyner 382171d10453SEric Joyner vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle); 382271d10453SEric Joyner if (!vsi_node) 382371d10453SEric Joyner goto exit_agg_priority_per_tc; 382471d10453SEric Joyner 382571d10453SEric Joyner if (ice_sched_find_node_in_subtree(hw, agg_node, vsi_node)) { 382671d10453SEric Joyner /* Configure Priority */ 382771d10453SEric Joyner status = ice_sched_cfg_sibl_node_prio(pi, vsi_node, 382871d10453SEric Joyner node_prio[i]); 382971d10453SEric Joyner if (status) 383071d10453SEric Joyner break; 383171d10453SEric Joyner status = ice_sched_save_vsi_prio(pi, vsi_handle, tc, 383271d10453SEric Joyner node_prio[i]); 383371d10453SEric Joyner if (status) 383471d10453SEric Joyner break; 383571d10453SEric Joyner } 383671d10453SEric Joyner } 383771d10453SEric Joyner 383871d10453SEric Joyner exit_agg_priority_per_tc: 383971d10453SEric Joyner ice_release_lock(&pi->sched_lock); 384071d10453SEric Joyner return status; 384171d10453SEric Joyner } 384271d10453SEric Joyner 384371d10453SEric Joyner /** 384471d10453SEric Joyner * ice_cfg_vsi_bw_alloc - config VSI BW alloc per TC 384571d10453SEric Joyner * @pi: port information structure 384671d10453SEric Joyner * @vsi_handle: software VSI handle 384771d10453SEric Joyner * @ena_tcmap: enabled TC map 384871d10453SEric Joyner * @rl_type: Rate limit type CIR/EIR 384971d10453SEric Joyner * @bw_alloc: Array of BW alloc 385071d10453SEric Joyner * 385171d10453SEric Joyner * This function configures the BW allocation of the passed in VSI's 385271d10453SEric Joyner * node(s) for enabled traffic class. 385371d10453SEric Joyner */ 3854*f2635e84SEric Joyner int 385571d10453SEric Joyner ice_cfg_vsi_bw_alloc(struct ice_port_info *pi, u16 vsi_handle, u8 ena_tcmap, 385671d10453SEric Joyner enum ice_rl_type rl_type, u8 *bw_alloc) 385771d10453SEric Joyner { 3858*f2635e84SEric Joyner int status = 0; 385971d10453SEric Joyner u8 tc; 386071d10453SEric Joyner 386171d10453SEric Joyner if (!ice_is_vsi_valid(pi->hw, vsi_handle)) 386271d10453SEric Joyner return ICE_ERR_PARAM; 386371d10453SEric Joyner 386471d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 386571d10453SEric Joyner 386671d10453SEric Joyner /* Return success if no nodes are present across TC */ 386771d10453SEric Joyner ice_for_each_traffic_class(tc) { 386871d10453SEric Joyner struct ice_sched_node *tc_node, *vsi_node; 386971d10453SEric Joyner 387071d10453SEric Joyner if (!ice_is_tc_ena(ena_tcmap, tc)) 387171d10453SEric Joyner continue; 387271d10453SEric Joyner 387371d10453SEric Joyner tc_node = ice_sched_get_tc_node(pi, tc); 387471d10453SEric Joyner if (!tc_node) 387571d10453SEric Joyner continue; 387671d10453SEric Joyner 387771d10453SEric Joyner vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle); 387871d10453SEric Joyner if (!vsi_node) 387971d10453SEric Joyner continue; 388071d10453SEric Joyner 388171d10453SEric Joyner status = ice_sched_cfg_node_bw_alloc(pi->hw, vsi_node, rl_type, 388271d10453SEric Joyner bw_alloc[tc]); 388371d10453SEric Joyner if (status) 388471d10453SEric Joyner break; 388571d10453SEric Joyner status = ice_sched_save_vsi_bw_alloc(pi, vsi_handle, tc, 388671d10453SEric Joyner rl_type, bw_alloc[tc]); 388771d10453SEric Joyner if (status) 388871d10453SEric Joyner break; 388971d10453SEric Joyner } 389071d10453SEric Joyner 389171d10453SEric Joyner ice_release_lock(&pi->sched_lock); 389271d10453SEric Joyner return status; 389371d10453SEric Joyner } 389471d10453SEric Joyner 389571d10453SEric Joyner /** 389671d10453SEric Joyner * ice_cfg_agg_bw_alloc - config aggregator BW alloc 389771d10453SEric Joyner * @pi: port information structure 389871d10453SEric Joyner * @agg_id: aggregator ID 389971d10453SEric Joyner * @ena_tcmap: enabled TC map 390071d10453SEric Joyner * @rl_type: rate limit type CIR/EIR 390171d10453SEric Joyner * @bw_alloc: array of BW alloc 390271d10453SEric Joyner * 390371d10453SEric Joyner * This function configures the BW allocation of passed in aggregator for 390471d10453SEric Joyner * enabled traffic class(s). 390571d10453SEric Joyner */ 3906*f2635e84SEric Joyner int 390771d10453SEric Joyner ice_cfg_agg_bw_alloc(struct ice_port_info *pi, u32 agg_id, u8 ena_tcmap, 390871d10453SEric Joyner enum ice_rl_type rl_type, u8 *bw_alloc) 390971d10453SEric Joyner { 391071d10453SEric Joyner struct ice_sched_agg_info *agg_info; 391171d10453SEric Joyner bool agg_id_present = false; 391271d10453SEric Joyner struct ice_hw *hw = pi->hw; 3913*f2635e84SEric Joyner int status = 0; 391471d10453SEric Joyner u8 tc; 391571d10453SEric Joyner 391671d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 391771d10453SEric Joyner LIST_FOR_EACH_ENTRY(agg_info, &hw->agg_list, ice_sched_agg_info, 391871d10453SEric Joyner list_entry) 391971d10453SEric Joyner if (agg_info->agg_id == agg_id) { 392071d10453SEric Joyner agg_id_present = true; 392171d10453SEric Joyner break; 392271d10453SEric Joyner } 392371d10453SEric Joyner if (!agg_id_present) { 392471d10453SEric Joyner status = ICE_ERR_PARAM; 392571d10453SEric Joyner goto exit_cfg_agg_bw_alloc; 392671d10453SEric Joyner } 392771d10453SEric Joyner 392871d10453SEric Joyner /* Return success if no nodes are present across TC */ 392971d10453SEric Joyner ice_for_each_traffic_class(tc) { 393071d10453SEric Joyner struct ice_sched_node *tc_node, *agg_node; 393171d10453SEric Joyner 393271d10453SEric Joyner if (!ice_is_tc_ena(ena_tcmap, tc)) 393371d10453SEric Joyner continue; 393471d10453SEric Joyner 393571d10453SEric Joyner tc_node = ice_sched_get_tc_node(pi, tc); 393671d10453SEric Joyner if (!tc_node) 393771d10453SEric Joyner continue; 393871d10453SEric Joyner 393971d10453SEric Joyner agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id); 394071d10453SEric Joyner if (!agg_node) 394171d10453SEric Joyner continue; 394271d10453SEric Joyner 394371d10453SEric Joyner status = ice_sched_cfg_node_bw_alloc(hw, agg_node, rl_type, 394471d10453SEric Joyner bw_alloc[tc]); 394571d10453SEric Joyner if (status) 394671d10453SEric Joyner break; 394771d10453SEric Joyner status = ice_sched_save_agg_bw_alloc(pi, agg_id, tc, rl_type, 394871d10453SEric Joyner bw_alloc[tc]); 394971d10453SEric Joyner if (status) 395071d10453SEric Joyner break; 395171d10453SEric Joyner } 395271d10453SEric Joyner 395371d10453SEric Joyner exit_cfg_agg_bw_alloc: 395471d10453SEric Joyner ice_release_lock(&pi->sched_lock); 395571d10453SEric Joyner return status; 395671d10453SEric Joyner } 395771d10453SEric Joyner 395871d10453SEric Joyner /** 395971d10453SEric Joyner * ice_sched_calc_wakeup - calculate RL profile wakeup parameter 396071d10453SEric Joyner * @hw: pointer to the HW struct 396171d10453SEric Joyner * @bw: bandwidth in Kbps 396271d10453SEric Joyner * 396371d10453SEric Joyner * This function calculates the wakeup parameter of RL profile. 396471d10453SEric Joyner */ 396571d10453SEric Joyner static u16 ice_sched_calc_wakeup(struct ice_hw *hw, s32 bw) 396671d10453SEric Joyner { 396771d10453SEric Joyner s64 bytes_per_sec, wakeup_int, wakeup_a, wakeup_b, wakeup_f; 396871d10453SEric Joyner s32 wakeup_f_int; 396971d10453SEric Joyner u16 wakeup = 0; 397071d10453SEric Joyner 397171d10453SEric Joyner /* Get the wakeup integer value */ 39728923de59SPiotr Kubaj bytes_per_sec = DIV_S64((s64)bw * 1000, BITS_PER_BYTE); 397356429daeSEric Joyner wakeup_int = DIV_S64(hw->psm_clk_freq, bytes_per_sec); 397471d10453SEric Joyner if (wakeup_int > 63) { 397571d10453SEric Joyner wakeup = (u16)((1 << 15) | wakeup_int); 397671d10453SEric Joyner } else { 397771d10453SEric Joyner /* Calculate fraction value up to 4 decimals 397871d10453SEric Joyner * Convert Integer value to a constant multiplier 397971d10453SEric Joyner */ 398071d10453SEric Joyner wakeup_b = (s64)ICE_RL_PROF_MULTIPLIER * wakeup_int; 39818923de59SPiotr Kubaj wakeup_a = DIV_S64((s64)ICE_RL_PROF_MULTIPLIER * 398271d10453SEric Joyner hw->psm_clk_freq, bytes_per_sec); 398371d10453SEric Joyner 398471d10453SEric Joyner /* Get Fraction value */ 398571d10453SEric Joyner wakeup_f = wakeup_a - wakeup_b; 398671d10453SEric Joyner 398771d10453SEric Joyner /* Round up the Fractional value via Ceil(Fractional value) */ 398856429daeSEric Joyner if (wakeup_f > DIV_S64(ICE_RL_PROF_MULTIPLIER, 2)) 398971d10453SEric Joyner wakeup_f += 1; 399071d10453SEric Joyner 399156429daeSEric Joyner wakeup_f_int = (s32)DIV_S64(wakeup_f * ICE_RL_PROF_FRACTION, 399271d10453SEric Joyner ICE_RL_PROF_MULTIPLIER); 399371d10453SEric Joyner wakeup |= (u16)(wakeup_int << 9); 399471d10453SEric Joyner wakeup |= (u16)(0x1ff & wakeup_f_int); 399571d10453SEric Joyner } 399671d10453SEric Joyner 399771d10453SEric Joyner return wakeup; 399871d10453SEric Joyner } 399971d10453SEric Joyner 400071d10453SEric Joyner /** 400171d10453SEric Joyner * ice_sched_bw_to_rl_profile - convert BW to profile parameters 400271d10453SEric Joyner * @hw: pointer to the HW struct 400371d10453SEric Joyner * @bw: bandwidth in Kbps 400471d10453SEric Joyner * @profile: profile parameters to return 400571d10453SEric Joyner * 400671d10453SEric Joyner * This function converts the BW to profile structure format. 400771d10453SEric Joyner */ 4008*f2635e84SEric Joyner static int 400971d10453SEric Joyner ice_sched_bw_to_rl_profile(struct ice_hw *hw, u32 bw, 401071d10453SEric Joyner struct ice_aqc_rl_profile_elem *profile) 401171d10453SEric Joyner { 401271d10453SEric Joyner s64 bytes_per_sec, ts_rate, mv_tmp; 4013*f2635e84SEric Joyner int status = ICE_ERR_PARAM; 401471d10453SEric Joyner bool found = false; 401571d10453SEric Joyner s32 encode = 0; 401671d10453SEric Joyner s64 mv = 0; 401771d10453SEric Joyner s32 i; 401871d10453SEric Joyner 401971d10453SEric Joyner /* Bw settings range is from 0.5Mb/sec to 100Gb/sec */ 402071d10453SEric Joyner if (bw < ICE_SCHED_MIN_BW || bw > ICE_SCHED_MAX_BW) 402171d10453SEric Joyner return status; 402271d10453SEric Joyner 402371d10453SEric Joyner /* Bytes per second from Kbps */ 40248923de59SPiotr Kubaj bytes_per_sec = DIV_S64((s64)bw * 1000, BITS_PER_BYTE); 402571d10453SEric Joyner 402671d10453SEric Joyner /* encode is 6 bits but really useful are 5 bits */ 402771d10453SEric Joyner for (i = 0; i < 64; i++) { 402871d10453SEric Joyner u64 pow_result = BIT_ULL(i); 402971d10453SEric Joyner 40308923de59SPiotr Kubaj ts_rate = DIV_S64((s64)hw->psm_clk_freq, 403171d10453SEric Joyner pow_result * ICE_RL_PROF_TS_MULTIPLIER); 403271d10453SEric Joyner if (ts_rate <= 0) 403371d10453SEric Joyner continue; 403471d10453SEric Joyner 403571d10453SEric Joyner /* Multiplier value */ 403656429daeSEric Joyner mv_tmp = DIV_S64(bytes_per_sec * ICE_RL_PROF_MULTIPLIER, 403771d10453SEric Joyner ts_rate); 403871d10453SEric Joyner 403971d10453SEric Joyner /* Round to the nearest ICE_RL_PROF_MULTIPLIER */ 404071d10453SEric Joyner mv = round_up_64bit(mv_tmp, ICE_RL_PROF_MULTIPLIER); 404171d10453SEric Joyner 404271d10453SEric Joyner /* First multiplier value greater than the given 404371d10453SEric Joyner * accuracy bytes 404471d10453SEric Joyner */ 404571d10453SEric Joyner if (mv > ICE_RL_PROF_ACCURACY_BYTES) { 404671d10453SEric Joyner encode = i; 404771d10453SEric Joyner found = true; 404871d10453SEric Joyner break; 404971d10453SEric Joyner } 405071d10453SEric Joyner } 405171d10453SEric Joyner if (found) { 405271d10453SEric Joyner u16 wm; 405371d10453SEric Joyner 405471d10453SEric Joyner wm = ice_sched_calc_wakeup(hw, bw); 405571d10453SEric Joyner profile->rl_multiply = CPU_TO_LE16(mv); 405671d10453SEric Joyner profile->wake_up_calc = CPU_TO_LE16(wm); 405771d10453SEric Joyner profile->rl_encode = CPU_TO_LE16(encode); 4058*f2635e84SEric Joyner status = 0; 405971d10453SEric Joyner } else { 406071d10453SEric Joyner status = ICE_ERR_DOES_NOT_EXIST; 406171d10453SEric Joyner } 406271d10453SEric Joyner 406371d10453SEric Joyner return status; 406471d10453SEric Joyner } 406571d10453SEric Joyner 406671d10453SEric Joyner /** 406771d10453SEric Joyner * ice_sched_add_rl_profile - add RL profile 4068d08b8680SEric Joyner * @hw: pointer to the hardware structure 406971d10453SEric Joyner * @rl_type: type of rate limit BW - min, max, or shared 407071d10453SEric Joyner * @bw: bandwidth in Kbps - Kilo bits per sec 407171d10453SEric Joyner * @layer_num: specifies in which layer to create profile 407271d10453SEric Joyner * 407371d10453SEric Joyner * This function first checks the existing list for corresponding BW 407471d10453SEric Joyner * parameter. If it exists, it returns the associated profile otherwise 407571d10453SEric Joyner * it creates a new rate limit profile for requested BW, and adds it to 407671d10453SEric Joyner * the HW DB and local list. It returns the new profile or null on error. 407771d10453SEric Joyner * The caller needs to hold the scheduler lock. 407871d10453SEric Joyner */ 407971d10453SEric Joyner static struct ice_aqc_rl_profile_info * 4080d08b8680SEric Joyner ice_sched_add_rl_profile(struct ice_hw *hw, enum ice_rl_type rl_type, 4081d08b8680SEric Joyner u32 bw, u8 layer_num) 408271d10453SEric Joyner { 408371d10453SEric Joyner struct ice_aqc_rl_profile_info *rl_prof_elem; 408471d10453SEric Joyner u16 profiles_added = 0, num_profiles = 1; 40857d7af7f8SEric Joyner struct ice_aqc_rl_profile_elem *buf; 408671d10453SEric Joyner u8 profile_type; 4087*f2635e84SEric Joyner int status; 408871d10453SEric Joyner 40898923de59SPiotr Kubaj if (!hw || layer_num >= hw->num_tx_sched_layers) 409071d10453SEric Joyner return NULL; 409171d10453SEric Joyner switch (rl_type) { 409271d10453SEric Joyner case ICE_MIN_BW: 409371d10453SEric Joyner profile_type = ICE_AQC_RL_PROFILE_TYPE_CIR; 409471d10453SEric Joyner break; 409571d10453SEric Joyner case ICE_MAX_BW: 409671d10453SEric Joyner profile_type = ICE_AQC_RL_PROFILE_TYPE_EIR; 409771d10453SEric Joyner break; 409871d10453SEric Joyner case ICE_SHARED_BW: 409971d10453SEric Joyner profile_type = ICE_AQC_RL_PROFILE_TYPE_SRL; 410071d10453SEric Joyner break; 410171d10453SEric Joyner default: 410271d10453SEric Joyner return NULL; 410371d10453SEric Joyner } 410471d10453SEric Joyner 4105d08b8680SEric Joyner LIST_FOR_EACH_ENTRY(rl_prof_elem, &hw->rl_prof_list[layer_num], 410671d10453SEric Joyner ice_aqc_rl_profile_info, list_entry) 41077d7af7f8SEric Joyner if ((rl_prof_elem->profile.flags & ICE_AQC_RL_PROFILE_TYPE_M) == 41087d7af7f8SEric Joyner profile_type && rl_prof_elem->bw == bw) 410971d10453SEric Joyner /* Return existing profile ID info */ 411071d10453SEric Joyner return rl_prof_elem; 411171d10453SEric Joyner 411271d10453SEric Joyner /* Create new profile ID */ 411371d10453SEric Joyner rl_prof_elem = (struct ice_aqc_rl_profile_info *) 411471d10453SEric Joyner ice_malloc(hw, sizeof(*rl_prof_elem)); 411571d10453SEric Joyner 411671d10453SEric Joyner if (!rl_prof_elem) 411771d10453SEric Joyner return NULL; 411871d10453SEric Joyner 411971d10453SEric Joyner status = ice_sched_bw_to_rl_profile(hw, bw, &rl_prof_elem->profile); 4120*f2635e84SEric Joyner if (status) 412171d10453SEric Joyner goto exit_add_rl_prof; 412271d10453SEric Joyner 412371d10453SEric Joyner rl_prof_elem->bw = bw; 412471d10453SEric Joyner /* layer_num is zero relative, and fw expects level from 1 to 9 */ 412571d10453SEric Joyner rl_prof_elem->profile.level = layer_num + 1; 412671d10453SEric Joyner rl_prof_elem->profile.flags = profile_type; 412771d10453SEric Joyner rl_prof_elem->profile.max_burst_size = CPU_TO_LE16(hw->max_burst_size); 412871d10453SEric Joyner 412971d10453SEric Joyner /* Create new entry in HW DB */ 41307d7af7f8SEric Joyner buf = &rl_prof_elem->profile; 413171d10453SEric Joyner status = ice_aq_add_rl_profile(hw, num_profiles, buf, sizeof(*buf), 413271d10453SEric Joyner &profiles_added, NULL); 413371d10453SEric Joyner if (status || profiles_added != num_profiles) 413471d10453SEric Joyner goto exit_add_rl_prof; 413571d10453SEric Joyner 413671d10453SEric Joyner /* Good entry - add in the list */ 413771d10453SEric Joyner rl_prof_elem->prof_id_ref = 0; 4138d08b8680SEric Joyner LIST_ADD(&rl_prof_elem->list_entry, &hw->rl_prof_list[layer_num]); 413971d10453SEric Joyner return rl_prof_elem; 414071d10453SEric Joyner 414171d10453SEric Joyner exit_add_rl_prof: 414271d10453SEric Joyner ice_free(hw, rl_prof_elem); 414371d10453SEric Joyner return NULL; 414471d10453SEric Joyner } 414571d10453SEric Joyner 414671d10453SEric Joyner /** 414771d10453SEric Joyner * ice_sched_cfg_node_bw_lmt - configure node sched params 414871d10453SEric Joyner * @hw: pointer to the HW struct 414971d10453SEric Joyner * @node: sched node to configure 415071d10453SEric Joyner * @rl_type: rate limit type CIR, EIR, or shared 415171d10453SEric Joyner * @rl_prof_id: rate limit profile ID 415271d10453SEric Joyner * 415371d10453SEric Joyner * This function configures node element's BW limit. 415471d10453SEric Joyner */ 4155*f2635e84SEric Joyner static int 415671d10453SEric Joyner ice_sched_cfg_node_bw_lmt(struct ice_hw *hw, struct ice_sched_node *node, 415771d10453SEric Joyner enum ice_rl_type rl_type, u16 rl_prof_id) 415871d10453SEric Joyner { 415971d10453SEric Joyner struct ice_aqc_txsched_elem_data buf; 416071d10453SEric Joyner struct ice_aqc_txsched_elem *data; 416171d10453SEric Joyner 416271d10453SEric Joyner buf = node->info; 416371d10453SEric Joyner data = &buf.data; 416471d10453SEric Joyner switch (rl_type) { 416571d10453SEric Joyner case ICE_MIN_BW: 416671d10453SEric Joyner data->valid_sections |= ICE_AQC_ELEM_VALID_CIR; 416771d10453SEric Joyner data->cir_bw.bw_profile_idx = CPU_TO_LE16(rl_prof_id); 416871d10453SEric Joyner break; 416971d10453SEric Joyner case ICE_MAX_BW: 417071d10453SEric Joyner data->valid_sections |= ICE_AQC_ELEM_VALID_EIR; 417171d10453SEric Joyner data->eir_bw.bw_profile_idx = CPU_TO_LE16(rl_prof_id); 417271d10453SEric Joyner break; 417371d10453SEric Joyner case ICE_SHARED_BW: 417471d10453SEric Joyner data->valid_sections |= ICE_AQC_ELEM_VALID_SHARED; 417571d10453SEric Joyner data->srl_id = CPU_TO_LE16(rl_prof_id); 417671d10453SEric Joyner break; 417771d10453SEric Joyner default: 417871d10453SEric Joyner /* Unknown rate limit type */ 417971d10453SEric Joyner return ICE_ERR_PARAM; 418071d10453SEric Joyner } 418171d10453SEric Joyner 418271d10453SEric Joyner /* Configure element */ 418371d10453SEric Joyner return ice_sched_update_elem(hw, node, &buf); 418471d10453SEric Joyner } 418571d10453SEric Joyner 418671d10453SEric Joyner /** 418771d10453SEric Joyner * ice_sched_get_node_rl_prof_id - get node's rate limit profile ID 418871d10453SEric Joyner * @node: sched node 418971d10453SEric Joyner * @rl_type: rate limit type 419071d10453SEric Joyner * 419171d10453SEric Joyner * If existing profile matches, it returns the corresponding rate 419271d10453SEric Joyner * limit profile ID, otherwise it returns an invalid ID as error. 419371d10453SEric Joyner */ 419471d10453SEric Joyner static u16 419571d10453SEric Joyner ice_sched_get_node_rl_prof_id(struct ice_sched_node *node, 419671d10453SEric Joyner enum ice_rl_type rl_type) 419771d10453SEric Joyner { 419871d10453SEric Joyner u16 rl_prof_id = ICE_SCHED_INVAL_PROF_ID; 419971d10453SEric Joyner struct ice_aqc_txsched_elem *data; 420071d10453SEric Joyner 420171d10453SEric Joyner data = &node->info.data; 420271d10453SEric Joyner switch (rl_type) { 420371d10453SEric Joyner case ICE_MIN_BW: 420471d10453SEric Joyner if (data->valid_sections & ICE_AQC_ELEM_VALID_CIR) 420571d10453SEric Joyner rl_prof_id = LE16_TO_CPU(data->cir_bw.bw_profile_idx); 420671d10453SEric Joyner break; 420771d10453SEric Joyner case ICE_MAX_BW: 420871d10453SEric Joyner if (data->valid_sections & ICE_AQC_ELEM_VALID_EIR) 420971d10453SEric Joyner rl_prof_id = LE16_TO_CPU(data->eir_bw.bw_profile_idx); 421071d10453SEric Joyner break; 421171d10453SEric Joyner case ICE_SHARED_BW: 421271d10453SEric Joyner if (data->valid_sections & ICE_AQC_ELEM_VALID_SHARED) 421371d10453SEric Joyner rl_prof_id = LE16_TO_CPU(data->srl_id); 421471d10453SEric Joyner break; 421571d10453SEric Joyner default: 421671d10453SEric Joyner break; 421771d10453SEric Joyner } 421871d10453SEric Joyner 421971d10453SEric Joyner return rl_prof_id; 422071d10453SEric Joyner } 422171d10453SEric Joyner 422271d10453SEric Joyner /** 422371d10453SEric Joyner * ice_sched_get_rl_prof_layer - selects rate limit profile creation layer 422471d10453SEric Joyner * @pi: port information structure 422571d10453SEric Joyner * @rl_type: type of rate limit BW - min, max, or shared 422671d10453SEric Joyner * @layer_index: layer index 422771d10453SEric Joyner * 422871d10453SEric Joyner * This function returns requested profile creation layer. 422971d10453SEric Joyner */ 423071d10453SEric Joyner static u8 423171d10453SEric Joyner ice_sched_get_rl_prof_layer(struct ice_port_info *pi, enum ice_rl_type rl_type, 423271d10453SEric Joyner u8 layer_index) 423371d10453SEric Joyner { 423471d10453SEric Joyner struct ice_hw *hw = pi->hw; 423571d10453SEric Joyner 423671d10453SEric Joyner if (layer_index >= hw->num_tx_sched_layers) 423771d10453SEric Joyner return ICE_SCHED_INVAL_LAYER_NUM; 423871d10453SEric Joyner switch (rl_type) { 423971d10453SEric Joyner case ICE_MIN_BW: 424071d10453SEric Joyner if (hw->layer_info[layer_index].max_cir_rl_profiles) 424171d10453SEric Joyner return layer_index; 424271d10453SEric Joyner break; 424371d10453SEric Joyner case ICE_MAX_BW: 424471d10453SEric Joyner if (hw->layer_info[layer_index].max_eir_rl_profiles) 424571d10453SEric Joyner return layer_index; 424671d10453SEric Joyner break; 424771d10453SEric Joyner case ICE_SHARED_BW: 424871d10453SEric Joyner /* if current layer doesn't support SRL profile creation 424971d10453SEric Joyner * then try a layer up or down. 425071d10453SEric Joyner */ 425171d10453SEric Joyner if (hw->layer_info[layer_index].max_srl_profiles) 425271d10453SEric Joyner return layer_index; 425371d10453SEric Joyner else if (layer_index < hw->num_tx_sched_layers - 1 && 425471d10453SEric Joyner hw->layer_info[layer_index + 1].max_srl_profiles) 425571d10453SEric Joyner return layer_index + 1; 425671d10453SEric Joyner else if (layer_index > 0 && 425771d10453SEric Joyner hw->layer_info[layer_index - 1].max_srl_profiles) 425871d10453SEric Joyner return layer_index - 1; 425971d10453SEric Joyner break; 426071d10453SEric Joyner default: 426171d10453SEric Joyner break; 426271d10453SEric Joyner } 426371d10453SEric Joyner return ICE_SCHED_INVAL_LAYER_NUM; 426471d10453SEric Joyner } 426571d10453SEric Joyner 426671d10453SEric Joyner /** 426771d10453SEric Joyner * ice_sched_get_srl_node - get shared rate limit node 426871d10453SEric Joyner * @node: tree node 426971d10453SEric Joyner * @srl_layer: shared rate limit layer 427071d10453SEric Joyner * 427171d10453SEric Joyner * This function returns SRL node to be used for shared rate limit purpose. 427271d10453SEric Joyner * The caller needs to hold scheduler lock. 427371d10453SEric Joyner */ 427471d10453SEric Joyner static struct ice_sched_node * 427571d10453SEric Joyner ice_sched_get_srl_node(struct ice_sched_node *node, u8 srl_layer) 427671d10453SEric Joyner { 427771d10453SEric Joyner if (srl_layer > node->tx_sched_layer) 427871d10453SEric Joyner return node->children[0]; 427971d10453SEric Joyner else if (srl_layer < node->tx_sched_layer) 428071d10453SEric Joyner /* Node can't be created without a parent. It will always 428171d10453SEric Joyner * have a valid parent except root node. 428271d10453SEric Joyner */ 428371d10453SEric Joyner return node->parent; 428471d10453SEric Joyner else 428571d10453SEric Joyner return node; 428671d10453SEric Joyner } 428771d10453SEric Joyner 428871d10453SEric Joyner /** 428971d10453SEric Joyner * ice_sched_rm_rl_profile - remove RL profile ID 4290d08b8680SEric Joyner * @hw: pointer to the hardware structure 429171d10453SEric Joyner * @layer_num: layer number where profiles are saved 429271d10453SEric Joyner * @profile_type: profile type like EIR, CIR, or SRL 429371d10453SEric Joyner * @profile_id: profile ID to remove 429471d10453SEric Joyner * 429571d10453SEric Joyner * This function removes rate limit profile from layer 'layer_num' of type 429671d10453SEric Joyner * 'profile_type' and profile ID as 'profile_id'. The caller needs to hold 429771d10453SEric Joyner * scheduler lock. 429871d10453SEric Joyner */ 4299*f2635e84SEric Joyner static int 4300d08b8680SEric Joyner ice_sched_rm_rl_profile(struct ice_hw *hw, u8 layer_num, u8 profile_type, 430171d10453SEric Joyner u16 profile_id) 430271d10453SEric Joyner { 430371d10453SEric Joyner struct ice_aqc_rl_profile_info *rl_prof_elem; 4304*f2635e84SEric Joyner int status = 0; 430571d10453SEric Joyner 43068923de59SPiotr Kubaj if (!hw || layer_num >= hw->num_tx_sched_layers) 430771d10453SEric Joyner return ICE_ERR_PARAM; 430871d10453SEric Joyner /* Check the existing list for RL profile */ 4309d08b8680SEric Joyner LIST_FOR_EACH_ENTRY(rl_prof_elem, &hw->rl_prof_list[layer_num], 431071d10453SEric Joyner ice_aqc_rl_profile_info, list_entry) 43117d7af7f8SEric Joyner if ((rl_prof_elem->profile.flags & ICE_AQC_RL_PROFILE_TYPE_M) == 43127d7af7f8SEric Joyner profile_type && 431371d10453SEric Joyner LE16_TO_CPU(rl_prof_elem->profile.profile_id) == 431471d10453SEric Joyner profile_id) { 431571d10453SEric Joyner if (rl_prof_elem->prof_id_ref) 431671d10453SEric Joyner rl_prof_elem->prof_id_ref--; 431771d10453SEric Joyner 431871d10453SEric Joyner /* Remove old profile ID from database */ 4319d08b8680SEric Joyner status = ice_sched_del_rl_profile(hw, rl_prof_elem); 432071d10453SEric Joyner if (status && status != ICE_ERR_IN_USE) 4321d08b8680SEric Joyner ice_debug(hw, ICE_DBG_SCHED, "Remove rl profile failed\n"); 432271d10453SEric Joyner break; 432371d10453SEric Joyner } 432471d10453SEric Joyner if (status == ICE_ERR_IN_USE) 4325*f2635e84SEric Joyner status = 0; 432671d10453SEric Joyner return status; 432771d10453SEric Joyner } 432871d10453SEric Joyner 432971d10453SEric Joyner /** 433071d10453SEric Joyner * ice_sched_set_node_bw_dflt - set node's bandwidth limit to default 433171d10453SEric Joyner * @pi: port information structure 433271d10453SEric Joyner * @node: pointer to node structure 433371d10453SEric Joyner * @rl_type: rate limit type min, max, or shared 433471d10453SEric Joyner * @layer_num: layer number where RL profiles are saved 433571d10453SEric Joyner * 433671d10453SEric Joyner * This function configures node element's BW rate limit profile ID of 433771d10453SEric Joyner * type CIR, EIR, or SRL to default. This function needs to be called 433871d10453SEric Joyner * with the scheduler lock held. 433971d10453SEric Joyner */ 4340*f2635e84SEric Joyner static int 434171d10453SEric Joyner ice_sched_set_node_bw_dflt(struct ice_port_info *pi, 434271d10453SEric Joyner struct ice_sched_node *node, 434371d10453SEric Joyner enum ice_rl_type rl_type, u8 layer_num) 434471d10453SEric Joyner { 434571d10453SEric Joyner struct ice_hw *hw; 434671d10453SEric Joyner u8 profile_type; 434771d10453SEric Joyner u16 rl_prof_id; 4348*f2635e84SEric Joyner int status; 434971d10453SEric Joyner u16 old_id; 435071d10453SEric Joyner 435171d10453SEric Joyner hw = pi->hw; 435271d10453SEric Joyner switch (rl_type) { 435371d10453SEric Joyner case ICE_MIN_BW: 435471d10453SEric Joyner profile_type = ICE_AQC_RL_PROFILE_TYPE_CIR; 435571d10453SEric Joyner rl_prof_id = ICE_SCHED_DFLT_RL_PROF_ID; 435671d10453SEric Joyner break; 435771d10453SEric Joyner case ICE_MAX_BW: 435871d10453SEric Joyner profile_type = ICE_AQC_RL_PROFILE_TYPE_EIR; 435971d10453SEric Joyner rl_prof_id = ICE_SCHED_DFLT_RL_PROF_ID; 436071d10453SEric Joyner break; 436171d10453SEric Joyner case ICE_SHARED_BW: 436271d10453SEric Joyner profile_type = ICE_AQC_RL_PROFILE_TYPE_SRL; 436371d10453SEric Joyner /* No SRL is configured for default case */ 436471d10453SEric Joyner rl_prof_id = ICE_SCHED_NO_SHARED_RL_PROF_ID; 436571d10453SEric Joyner break; 436671d10453SEric Joyner default: 436771d10453SEric Joyner return ICE_ERR_PARAM; 436871d10453SEric Joyner } 436971d10453SEric Joyner /* Save existing RL prof ID for later clean up */ 437071d10453SEric Joyner old_id = ice_sched_get_node_rl_prof_id(node, rl_type); 437171d10453SEric Joyner /* Configure BW scheduling parameters */ 437271d10453SEric Joyner status = ice_sched_cfg_node_bw_lmt(hw, node, rl_type, rl_prof_id); 437371d10453SEric Joyner if (status) 437471d10453SEric Joyner return status; 437571d10453SEric Joyner 437671d10453SEric Joyner /* Remove stale RL profile ID */ 437771d10453SEric Joyner if (old_id == ICE_SCHED_DFLT_RL_PROF_ID || 437871d10453SEric Joyner old_id == ICE_SCHED_INVAL_PROF_ID) 4379*f2635e84SEric Joyner return 0; 438071d10453SEric Joyner 4381d08b8680SEric Joyner return ice_sched_rm_rl_profile(hw, layer_num, profile_type, old_id); 438271d10453SEric Joyner } 438371d10453SEric Joyner 438471d10453SEric Joyner /** 438571d10453SEric Joyner * ice_sched_set_node_bw - set node's bandwidth 438671d10453SEric Joyner * @pi: port information structure 438771d10453SEric Joyner * @node: tree node 438871d10453SEric Joyner * @rl_type: rate limit type min, max, or shared 438971d10453SEric Joyner * @bw: bandwidth in Kbps - Kilo bits per sec 439071d10453SEric Joyner * @layer_num: layer number 439171d10453SEric Joyner * 439271d10453SEric Joyner * This function adds new profile corresponding to requested BW, configures 439371d10453SEric Joyner * node's RL profile ID of type CIR, EIR, or SRL, and removes old profile 439471d10453SEric Joyner * ID from local database. The caller needs to hold scheduler lock. 439571d10453SEric Joyner */ 4396*f2635e84SEric Joyner int 439771d10453SEric Joyner ice_sched_set_node_bw(struct ice_port_info *pi, struct ice_sched_node *node, 439871d10453SEric Joyner enum ice_rl_type rl_type, u32 bw, u8 layer_num) 439971d10453SEric Joyner { 440071d10453SEric Joyner struct ice_aqc_rl_profile_info *rl_prof_info; 440171d10453SEric Joyner struct ice_hw *hw = pi->hw; 440271d10453SEric Joyner u16 old_id, rl_prof_id; 4403*f2635e84SEric Joyner int status = ICE_ERR_PARAM; 440471d10453SEric Joyner 4405d08b8680SEric Joyner rl_prof_info = ice_sched_add_rl_profile(hw, rl_type, bw, layer_num); 440671d10453SEric Joyner if (!rl_prof_info) 440771d10453SEric Joyner return status; 440871d10453SEric Joyner 440971d10453SEric Joyner rl_prof_id = LE16_TO_CPU(rl_prof_info->profile.profile_id); 441071d10453SEric Joyner 441171d10453SEric Joyner /* Save existing RL prof ID for later clean up */ 441271d10453SEric Joyner old_id = ice_sched_get_node_rl_prof_id(node, rl_type); 441371d10453SEric Joyner /* Configure BW scheduling parameters */ 441471d10453SEric Joyner status = ice_sched_cfg_node_bw_lmt(hw, node, rl_type, rl_prof_id); 441571d10453SEric Joyner if (status) 441671d10453SEric Joyner return status; 441771d10453SEric Joyner 441871d10453SEric Joyner /* New changes has been applied */ 441971d10453SEric Joyner /* Increment the profile ID reference count */ 442071d10453SEric Joyner rl_prof_info->prof_id_ref++; 442171d10453SEric Joyner 442271d10453SEric Joyner /* Check for old ID removal */ 442371d10453SEric Joyner if ((old_id == ICE_SCHED_DFLT_RL_PROF_ID && rl_type != ICE_SHARED_BW) || 442471d10453SEric Joyner old_id == ICE_SCHED_INVAL_PROF_ID || old_id == rl_prof_id) 4425*f2635e84SEric Joyner return 0; 442671d10453SEric Joyner 4427d08b8680SEric Joyner return ice_sched_rm_rl_profile(hw, layer_num, 44287d7af7f8SEric Joyner rl_prof_info->profile.flags & 44297d7af7f8SEric Joyner ICE_AQC_RL_PROFILE_TYPE_M, old_id); 443071d10453SEric Joyner } 443171d10453SEric Joyner 443271d10453SEric Joyner /** 44339c30461dSEric Joyner * ice_sched_set_node_priority - set node's priority 44349c30461dSEric Joyner * @pi: port information structure 44359c30461dSEric Joyner * @node: tree node 44369c30461dSEric Joyner * @priority: number 0-7 representing priority among siblings 44379c30461dSEric Joyner * 44389c30461dSEric Joyner * This function sets priority of a node among it's siblings. 44399c30461dSEric Joyner */ 4440*f2635e84SEric Joyner int 44419c30461dSEric Joyner ice_sched_set_node_priority(struct ice_port_info *pi, struct ice_sched_node *node, 44429c30461dSEric Joyner u16 priority) 44439c30461dSEric Joyner { 44449c30461dSEric Joyner struct ice_aqc_txsched_elem_data buf; 44459c30461dSEric Joyner struct ice_aqc_txsched_elem *data; 44469c30461dSEric Joyner 44479c30461dSEric Joyner buf = node->info; 44489c30461dSEric Joyner data = &buf.data; 44499c30461dSEric Joyner 44509c30461dSEric Joyner data->valid_sections |= ICE_AQC_ELEM_VALID_GENERIC; 44519c30461dSEric Joyner data->generic |= ICE_AQC_ELEM_GENERIC_PRIO_M & 44529c30461dSEric Joyner (priority << ICE_AQC_ELEM_GENERIC_PRIO_S); 44539c30461dSEric Joyner 44549c30461dSEric Joyner return ice_sched_update_elem(pi->hw, node, &buf); 44559c30461dSEric Joyner } 44569c30461dSEric Joyner 44579c30461dSEric Joyner /** 44589c30461dSEric Joyner * ice_sched_set_node_weight - set node's weight 44599c30461dSEric Joyner * @pi: port information structure 44609c30461dSEric Joyner * @node: tree node 44619c30461dSEric Joyner * @weight: number 1-200 representing weight for WFQ 44629c30461dSEric Joyner * 44639c30461dSEric Joyner * This function sets weight of the node for WFQ algorithm. 44649c30461dSEric Joyner */ 4465*f2635e84SEric Joyner int 44669c30461dSEric Joyner ice_sched_set_node_weight(struct ice_port_info *pi, struct ice_sched_node *node, u16 weight) 44679c30461dSEric Joyner { 44689c30461dSEric Joyner struct ice_aqc_txsched_elem_data buf; 44699c30461dSEric Joyner struct ice_aqc_txsched_elem *data; 44709c30461dSEric Joyner 44719c30461dSEric Joyner buf = node->info; 44729c30461dSEric Joyner data = &buf.data; 44739c30461dSEric Joyner 44749c30461dSEric Joyner data->valid_sections = ICE_AQC_ELEM_VALID_CIR | ICE_AQC_ELEM_VALID_EIR | 44759c30461dSEric Joyner ICE_AQC_ELEM_VALID_GENERIC; 44769c30461dSEric Joyner data->cir_bw.bw_alloc = CPU_TO_LE16(weight); 44779c30461dSEric Joyner data->eir_bw.bw_alloc = CPU_TO_LE16(weight); 44789c30461dSEric Joyner data->generic |= ICE_AQC_ELEM_GENERIC_SP_M & 44799c30461dSEric Joyner (0x0 << ICE_AQC_ELEM_GENERIC_SP_S); 44809c30461dSEric Joyner 44819c30461dSEric Joyner return ice_sched_update_elem(pi->hw, node, &buf); 44829c30461dSEric Joyner } 44839c30461dSEric Joyner 44849c30461dSEric Joyner /** 448571d10453SEric Joyner * ice_sched_set_node_bw_lmt - set node's BW limit 448671d10453SEric Joyner * @pi: port information structure 448771d10453SEric Joyner * @node: tree node 448871d10453SEric Joyner * @rl_type: rate limit type min, max, or shared 448971d10453SEric Joyner * @bw: bandwidth in Kbps - Kilo bits per sec 449071d10453SEric Joyner * 449171d10453SEric Joyner * It updates node's BW limit parameters like BW RL profile ID of type CIR, 449271d10453SEric Joyner * EIR, or SRL. The caller needs to hold scheduler lock. 4493d08b8680SEric Joyner * 4494d08b8680SEric Joyner * NOTE: Caller provides the correct SRL node in case of shared profile 4495d08b8680SEric Joyner * settings. 449671d10453SEric Joyner */ 4497*f2635e84SEric Joyner int 449871d10453SEric Joyner ice_sched_set_node_bw_lmt(struct ice_port_info *pi, struct ice_sched_node *node, 449971d10453SEric Joyner enum ice_rl_type rl_type, u32 bw) 450071d10453SEric Joyner { 450171d10453SEric Joyner struct ice_hw *hw; 450271d10453SEric Joyner u8 layer_num; 450371d10453SEric Joyner 450471d10453SEric Joyner if (!pi) 450571d10453SEric Joyner return ICE_ERR_PARAM; 450671d10453SEric Joyner hw = pi->hw; 450771d10453SEric Joyner /* Remove unused RL profile IDs from HW and SW DB */ 4508d08b8680SEric Joyner ice_sched_rm_unused_rl_prof(hw); 4509d08b8680SEric Joyner 451071d10453SEric Joyner layer_num = ice_sched_get_rl_prof_layer(pi, rl_type, 451171d10453SEric Joyner node->tx_sched_layer); 451271d10453SEric Joyner if (layer_num >= hw->num_tx_sched_layers) 451371d10453SEric Joyner return ICE_ERR_PARAM; 451471d10453SEric Joyner 451571d10453SEric Joyner if (bw == ICE_SCHED_DFLT_BW) 4516d08b8680SEric Joyner return ice_sched_set_node_bw_dflt(pi, node, rl_type, layer_num); 4517d08b8680SEric Joyner return ice_sched_set_node_bw(pi, node, rl_type, bw, layer_num); 451871d10453SEric Joyner } 451971d10453SEric Joyner 452071d10453SEric Joyner /** 452171d10453SEric Joyner * ice_sched_set_node_bw_dflt_lmt - set node's BW limit to default 452271d10453SEric Joyner * @pi: port information structure 452371d10453SEric Joyner * @node: pointer to node structure 452471d10453SEric Joyner * @rl_type: rate limit type min, max, or shared 452571d10453SEric Joyner * 452671d10453SEric Joyner * This function configures node element's BW rate limit profile ID of 452771d10453SEric Joyner * type CIR, EIR, or SRL to default. This function needs to be called 452871d10453SEric Joyner * with the scheduler lock held. 452971d10453SEric Joyner */ 4530*f2635e84SEric Joyner static int 453171d10453SEric Joyner ice_sched_set_node_bw_dflt_lmt(struct ice_port_info *pi, 453271d10453SEric Joyner struct ice_sched_node *node, 453371d10453SEric Joyner enum ice_rl_type rl_type) 453471d10453SEric Joyner { 453571d10453SEric Joyner return ice_sched_set_node_bw_lmt(pi, node, rl_type, 453671d10453SEric Joyner ICE_SCHED_DFLT_BW); 453771d10453SEric Joyner } 453871d10453SEric Joyner 453971d10453SEric Joyner /** 454071d10453SEric Joyner * ice_sched_validate_srl_node - Check node for SRL applicability 454171d10453SEric Joyner * @node: sched node to configure 454271d10453SEric Joyner * @sel_layer: selected SRL layer 454371d10453SEric Joyner * 454471d10453SEric Joyner * This function checks if the SRL can be applied to a selceted layer node on 454571d10453SEric Joyner * behalf of the requested node (first argument). This function needs to be 454671d10453SEric Joyner * called with scheduler lock held. 454771d10453SEric Joyner */ 4548*f2635e84SEric Joyner static int 454971d10453SEric Joyner ice_sched_validate_srl_node(struct ice_sched_node *node, u8 sel_layer) 455071d10453SEric Joyner { 455171d10453SEric Joyner /* SRL profiles are not available on all layers. Check if the 455271d10453SEric Joyner * SRL profile can be applied to a node above or below the 455371d10453SEric Joyner * requested node. SRL configuration is possible only if the 455471d10453SEric Joyner * selected layer's node has single child. 455571d10453SEric Joyner */ 455671d10453SEric Joyner if (sel_layer == node->tx_sched_layer || 455771d10453SEric Joyner ((sel_layer == node->tx_sched_layer + 1) && 455871d10453SEric Joyner node->num_children == 1) || 455971d10453SEric Joyner ((sel_layer == node->tx_sched_layer - 1) && 456071d10453SEric Joyner (node->parent && node->parent->num_children == 1))) 4561*f2635e84SEric Joyner return 0; 456271d10453SEric Joyner 456371d10453SEric Joyner return ICE_ERR_CFG; 456471d10453SEric Joyner } 456571d10453SEric Joyner 456671d10453SEric Joyner /** 456771d10453SEric Joyner * ice_sched_save_q_bw - save queue node's BW information 456871d10453SEric Joyner * @q_ctx: queue context structure 456971d10453SEric Joyner * @rl_type: rate limit type min, max, or shared 457071d10453SEric Joyner * @bw: bandwidth in Kbps - Kilo bits per sec 457171d10453SEric Joyner * 457271d10453SEric Joyner * Save BW information of queue type node for post replay use. 457371d10453SEric Joyner */ 4574*f2635e84SEric Joyner static int 457571d10453SEric Joyner ice_sched_save_q_bw(struct ice_q_ctx *q_ctx, enum ice_rl_type rl_type, u32 bw) 457671d10453SEric Joyner { 457771d10453SEric Joyner switch (rl_type) { 457871d10453SEric Joyner case ICE_MIN_BW: 457971d10453SEric Joyner ice_set_clear_cir_bw(&q_ctx->bw_t_info, bw); 458071d10453SEric Joyner break; 458171d10453SEric Joyner case ICE_MAX_BW: 458271d10453SEric Joyner ice_set_clear_eir_bw(&q_ctx->bw_t_info, bw); 458371d10453SEric Joyner break; 458471d10453SEric Joyner case ICE_SHARED_BW: 458571d10453SEric Joyner ice_set_clear_shared_bw(&q_ctx->bw_t_info, bw); 458671d10453SEric Joyner break; 458771d10453SEric Joyner default: 458871d10453SEric Joyner return ICE_ERR_PARAM; 458971d10453SEric Joyner } 4590*f2635e84SEric Joyner return 0; 459171d10453SEric Joyner } 459271d10453SEric Joyner 459371d10453SEric Joyner /** 459471d10453SEric Joyner * ice_sched_set_q_bw_lmt - sets queue BW limit 459571d10453SEric Joyner * @pi: port information structure 459671d10453SEric Joyner * @vsi_handle: sw VSI handle 459771d10453SEric Joyner * @tc: traffic class 459871d10453SEric Joyner * @q_handle: software queue handle 459971d10453SEric Joyner * @rl_type: min, max, or shared 460071d10453SEric Joyner * @bw: bandwidth in Kbps 460171d10453SEric Joyner * 460271d10453SEric Joyner * This function sets BW limit of queue scheduling node. 460371d10453SEric Joyner */ 4604*f2635e84SEric Joyner static int 460571d10453SEric Joyner ice_sched_set_q_bw_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc, 460671d10453SEric Joyner u16 q_handle, enum ice_rl_type rl_type, u32 bw) 460771d10453SEric Joyner { 460871d10453SEric Joyner struct ice_sched_node *node; 460971d10453SEric Joyner struct ice_q_ctx *q_ctx; 4610*f2635e84SEric Joyner int status = ICE_ERR_PARAM; 461171d10453SEric Joyner 461271d10453SEric Joyner if (!ice_is_vsi_valid(pi->hw, vsi_handle)) 461371d10453SEric Joyner return ICE_ERR_PARAM; 461471d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 461571d10453SEric Joyner q_ctx = ice_get_lan_q_ctx(pi->hw, vsi_handle, tc, q_handle); 461671d10453SEric Joyner if (!q_ctx) 461771d10453SEric Joyner goto exit_q_bw_lmt; 461871d10453SEric Joyner node = ice_sched_find_node_by_teid(pi->root, q_ctx->q_teid); 461971d10453SEric Joyner if (!node) { 462071d10453SEric Joyner ice_debug(pi->hw, ICE_DBG_SCHED, "Wrong q_teid\n"); 462171d10453SEric Joyner goto exit_q_bw_lmt; 462271d10453SEric Joyner } 462371d10453SEric Joyner 462471d10453SEric Joyner /* Return error if it is not a leaf node */ 462571d10453SEric Joyner if (node->info.data.elem_type != ICE_AQC_ELEM_TYPE_LEAF) 462671d10453SEric Joyner goto exit_q_bw_lmt; 462771d10453SEric Joyner 462871d10453SEric Joyner /* SRL bandwidth layer selection */ 462971d10453SEric Joyner if (rl_type == ICE_SHARED_BW) { 463071d10453SEric Joyner u8 sel_layer; /* selected layer */ 463171d10453SEric Joyner 463271d10453SEric Joyner sel_layer = ice_sched_get_rl_prof_layer(pi, rl_type, 463371d10453SEric Joyner node->tx_sched_layer); 463471d10453SEric Joyner if (sel_layer >= pi->hw->num_tx_sched_layers) { 463571d10453SEric Joyner status = ICE_ERR_PARAM; 463671d10453SEric Joyner goto exit_q_bw_lmt; 463771d10453SEric Joyner } 463871d10453SEric Joyner status = ice_sched_validate_srl_node(node, sel_layer); 463971d10453SEric Joyner if (status) 464071d10453SEric Joyner goto exit_q_bw_lmt; 464171d10453SEric Joyner } 464271d10453SEric Joyner 464371d10453SEric Joyner if (bw == ICE_SCHED_DFLT_BW) 464471d10453SEric Joyner status = ice_sched_set_node_bw_dflt_lmt(pi, node, rl_type); 464571d10453SEric Joyner else 464671d10453SEric Joyner status = ice_sched_set_node_bw_lmt(pi, node, rl_type, bw); 464771d10453SEric Joyner 464871d10453SEric Joyner if (!status) 464971d10453SEric Joyner status = ice_sched_save_q_bw(q_ctx, rl_type, bw); 465071d10453SEric Joyner 465171d10453SEric Joyner exit_q_bw_lmt: 465271d10453SEric Joyner ice_release_lock(&pi->sched_lock); 465371d10453SEric Joyner return status; 465471d10453SEric Joyner } 465571d10453SEric Joyner 465671d10453SEric Joyner /** 465771d10453SEric Joyner * ice_cfg_q_bw_lmt - configure queue BW limit 465871d10453SEric Joyner * @pi: port information structure 465971d10453SEric Joyner * @vsi_handle: sw VSI handle 466071d10453SEric Joyner * @tc: traffic class 466171d10453SEric Joyner * @q_handle: software queue handle 466271d10453SEric Joyner * @rl_type: min, max, or shared 466371d10453SEric Joyner * @bw: bandwidth in Kbps 466471d10453SEric Joyner * 466571d10453SEric Joyner * This function configures BW limit of queue scheduling node. 466671d10453SEric Joyner */ 4667*f2635e84SEric Joyner int 466871d10453SEric Joyner ice_cfg_q_bw_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc, 466971d10453SEric Joyner u16 q_handle, enum ice_rl_type rl_type, u32 bw) 467071d10453SEric Joyner { 467171d10453SEric Joyner return ice_sched_set_q_bw_lmt(pi, vsi_handle, tc, q_handle, rl_type, 467271d10453SEric Joyner bw); 467371d10453SEric Joyner } 467471d10453SEric Joyner 467571d10453SEric Joyner /** 467671d10453SEric Joyner * ice_cfg_q_bw_dflt_lmt - configure queue BW default limit 467771d10453SEric Joyner * @pi: port information structure 467871d10453SEric Joyner * @vsi_handle: sw VSI handle 467971d10453SEric Joyner * @tc: traffic class 468071d10453SEric Joyner * @q_handle: software queue handle 468171d10453SEric Joyner * @rl_type: min, max, or shared 468271d10453SEric Joyner * 468371d10453SEric Joyner * This function configures BW default limit of queue scheduling node. 468471d10453SEric Joyner */ 4685*f2635e84SEric Joyner int 468671d10453SEric Joyner ice_cfg_q_bw_dflt_lmt(struct ice_port_info *pi, u16 vsi_handle, u8 tc, 468771d10453SEric Joyner u16 q_handle, enum ice_rl_type rl_type) 468871d10453SEric Joyner { 468971d10453SEric Joyner return ice_sched_set_q_bw_lmt(pi, vsi_handle, tc, q_handle, rl_type, 469071d10453SEric Joyner ICE_SCHED_DFLT_BW); 469171d10453SEric Joyner } 469271d10453SEric Joyner 469371d10453SEric Joyner /** 469471d10453SEric Joyner * ice_sched_save_tc_node_bw - save TC node BW limit 469571d10453SEric Joyner * @pi: port information structure 469671d10453SEric Joyner * @tc: TC number 469771d10453SEric Joyner * @rl_type: min or max 469871d10453SEric Joyner * @bw: bandwidth in Kbps 469971d10453SEric Joyner * 470071d10453SEric Joyner * This function saves the modified values of bandwidth settings for later 470171d10453SEric Joyner * replay purpose (restore) after reset. 470271d10453SEric Joyner */ 4703*f2635e84SEric Joyner static int 470471d10453SEric Joyner ice_sched_save_tc_node_bw(struct ice_port_info *pi, u8 tc, 470571d10453SEric Joyner enum ice_rl_type rl_type, u32 bw) 470671d10453SEric Joyner { 470771d10453SEric Joyner if (tc >= ICE_MAX_TRAFFIC_CLASS) 470871d10453SEric Joyner return ICE_ERR_PARAM; 470971d10453SEric Joyner switch (rl_type) { 471071d10453SEric Joyner case ICE_MIN_BW: 471171d10453SEric Joyner ice_set_clear_cir_bw(&pi->tc_node_bw_t_info[tc], bw); 471271d10453SEric Joyner break; 471371d10453SEric Joyner case ICE_MAX_BW: 471471d10453SEric Joyner ice_set_clear_eir_bw(&pi->tc_node_bw_t_info[tc], bw); 471571d10453SEric Joyner break; 471671d10453SEric Joyner case ICE_SHARED_BW: 471771d10453SEric Joyner ice_set_clear_shared_bw(&pi->tc_node_bw_t_info[tc], bw); 471871d10453SEric Joyner break; 471971d10453SEric Joyner default: 472071d10453SEric Joyner return ICE_ERR_PARAM; 472171d10453SEric Joyner } 4722*f2635e84SEric Joyner return 0; 472371d10453SEric Joyner } 472471d10453SEric Joyner 4725*f2635e84SEric Joyner #define ICE_SCHED_GENERIC_STRICT_MODE BIT(4) 4726*f2635e84SEric Joyner #define ICE_SCHED_GENERIC_PRIO_S 1 4727*f2635e84SEric Joyner 472871d10453SEric Joyner /** 472971d10453SEric Joyner * ice_sched_set_tc_node_bw_lmt - sets TC node BW limit 473071d10453SEric Joyner * @pi: port information structure 473171d10453SEric Joyner * @tc: TC number 473271d10453SEric Joyner * @rl_type: min or max 473371d10453SEric Joyner * @bw: bandwidth in Kbps 473471d10453SEric Joyner * 473571d10453SEric Joyner * This function configures bandwidth limit of TC node. 473671d10453SEric Joyner */ 4737*f2635e84SEric Joyner static int 473871d10453SEric Joyner ice_sched_set_tc_node_bw_lmt(struct ice_port_info *pi, u8 tc, 473971d10453SEric Joyner enum ice_rl_type rl_type, u32 bw) 474071d10453SEric Joyner { 4741*f2635e84SEric Joyner struct ice_aqc_txsched_elem_data buf; 4742*f2635e84SEric Joyner struct ice_aqc_txsched_elem *data; 474371d10453SEric Joyner struct ice_sched_node *tc_node; 4744*f2635e84SEric Joyner int status = ICE_ERR_PARAM; 474571d10453SEric Joyner 474671d10453SEric Joyner if (tc >= ICE_MAX_TRAFFIC_CLASS) 474771d10453SEric Joyner return status; 474871d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 474971d10453SEric Joyner tc_node = ice_sched_get_tc_node(pi, tc); 475071d10453SEric Joyner if (!tc_node) 475171d10453SEric Joyner goto exit_set_tc_node_bw; 4752*f2635e84SEric Joyner 4753*f2635e84SEric Joyner /* update node's generic field */ 4754*f2635e84SEric Joyner buf = tc_node->info; 4755*f2635e84SEric Joyner data = &buf.data; 4756*f2635e84SEric Joyner data->valid_sections = ICE_AQC_ELEM_VALID_GENERIC; 4757*f2635e84SEric Joyner data->generic = (tc << ICE_SCHED_GENERIC_PRIO_S) | 4758*f2635e84SEric Joyner ICE_SCHED_GENERIC_STRICT_MODE; 4759*f2635e84SEric Joyner status = ice_sched_update_elem(pi->hw, tc_node, &buf); 4760*f2635e84SEric Joyner if (status) 4761*f2635e84SEric Joyner goto exit_set_tc_node_bw; 4762*f2635e84SEric Joyner 476371d10453SEric Joyner if (bw == ICE_SCHED_DFLT_BW) 476471d10453SEric Joyner status = ice_sched_set_node_bw_dflt_lmt(pi, tc_node, rl_type); 476571d10453SEric Joyner else 476671d10453SEric Joyner status = ice_sched_set_node_bw_lmt(pi, tc_node, rl_type, bw); 476771d10453SEric Joyner if (!status) 476871d10453SEric Joyner status = ice_sched_save_tc_node_bw(pi, tc, rl_type, bw); 476971d10453SEric Joyner 477071d10453SEric Joyner exit_set_tc_node_bw: 477171d10453SEric Joyner ice_release_lock(&pi->sched_lock); 477271d10453SEric Joyner return status; 477371d10453SEric Joyner } 477471d10453SEric Joyner 477571d10453SEric Joyner /** 477671d10453SEric Joyner * ice_cfg_tc_node_bw_lmt - configure TC node BW limit 477771d10453SEric Joyner * @pi: port information structure 477871d10453SEric Joyner * @tc: TC number 477971d10453SEric Joyner * @rl_type: min or max 478071d10453SEric Joyner * @bw: bandwidth in Kbps 478171d10453SEric Joyner * 478271d10453SEric Joyner * This function configures BW limit of TC node. 478371d10453SEric Joyner * Note: The minimum guaranteed reservation is done via DCBX. 478471d10453SEric Joyner */ 4785*f2635e84SEric Joyner int 478671d10453SEric Joyner ice_cfg_tc_node_bw_lmt(struct ice_port_info *pi, u8 tc, 478771d10453SEric Joyner enum ice_rl_type rl_type, u32 bw) 478871d10453SEric Joyner { 478971d10453SEric Joyner return ice_sched_set_tc_node_bw_lmt(pi, tc, rl_type, bw); 479071d10453SEric Joyner } 479171d10453SEric Joyner 479271d10453SEric Joyner /** 479371d10453SEric Joyner * ice_cfg_tc_node_bw_dflt_lmt - configure TC node BW default limit 479471d10453SEric Joyner * @pi: port information structure 479571d10453SEric Joyner * @tc: TC number 479671d10453SEric Joyner * @rl_type: min or max 479771d10453SEric Joyner * 479871d10453SEric Joyner * This function configures BW default limit of TC node. 479971d10453SEric Joyner */ 4800*f2635e84SEric Joyner int 480171d10453SEric Joyner ice_cfg_tc_node_bw_dflt_lmt(struct ice_port_info *pi, u8 tc, 480271d10453SEric Joyner enum ice_rl_type rl_type) 480371d10453SEric Joyner { 480471d10453SEric Joyner return ice_sched_set_tc_node_bw_lmt(pi, tc, rl_type, ICE_SCHED_DFLT_BW); 480571d10453SEric Joyner } 480671d10453SEric Joyner 480771d10453SEric Joyner /** 480871d10453SEric Joyner * ice_sched_save_tc_node_bw_alloc - save TC node's BW alloc information 480971d10453SEric Joyner * @pi: port information structure 481071d10453SEric Joyner * @tc: traffic class 481171d10453SEric Joyner * @rl_type: rate limit type min or max 481271d10453SEric Joyner * @bw_alloc: Bandwidth allocation information 481371d10453SEric Joyner * 481471d10453SEric Joyner * Save BW alloc information of VSI type node for post replay use. 481571d10453SEric Joyner */ 4816*f2635e84SEric Joyner static int 481771d10453SEric Joyner ice_sched_save_tc_node_bw_alloc(struct ice_port_info *pi, u8 tc, 481871d10453SEric Joyner enum ice_rl_type rl_type, u16 bw_alloc) 481971d10453SEric Joyner { 482071d10453SEric Joyner if (tc >= ICE_MAX_TRAFFIC_CLASS) 482171d10453SEric Joyner return ICE_ERR_PARAM; 482271d10453SEric Joyner switch (rl_type) { 482371d10453SEric Joyner case ICE_MIN_BW: 482471d10453SEric Joyner ice_set_clear_cir_bw_alloc(&pi->tc_node_bw_t_info[tc], 482571d10453SEric Joyner bw_alloc); 482671d10453SEric Joyner break; 482771d10453SEric Joyner case ICE_MAX_BW: 482871d10453SEric Joyner ice_set_clear_eir_bw_alloc(&pi->tc_node_bw_t_info[tc], 482971d10453SEric Joyner bw_alloc); 483071d10453SEric Joyner break; 483171d10453SEric Joyner default: 483271d10453SEric Joyner return ICE_ERR_PARAM; 483371d10453SEric Joyner } 4834*f2635e84SEric Joyner return 0; 483571d10453SEric Joyner } 483671d10453SEric Joyner 483771d10453SEric Joyner /** 483871d10453SEric Joyner * ice_sched_set_tc_node_bw_alloc - set TC node BW alloc 483971d10453SEric Joyner * @pi: port information structure 484071d10453SEric Joyner * @tc: TC number 484171d10453SEric Joyner * @rl_type: min or max 484271d10453SEric Joyner * @bw_alloc: bandwidth alloc 484371d10453SEric Joyner * 484471d10453SEric Joyner * This function configures bandwidth alloc of TC node, also saves the 484571d10453SEric Joyner * changed settings for replay purpose, and return success if it succeeds 484671d10453SEric Joyner * in modifying bandwidth alloc setting. 484771d10453SEric Joyner */ 4848*f2635e84SEric Joyner static int 484971d10453SEric Joyner ice_sched_set_tc_node_bw_alloc(struct ice_port_info *pi, u8 tc, 485071d10453SEric Joyner enum ice_rl_type rl_type, u8 bw_alloc) 485171d10453SEric Joyner { 485271d10453SEric Joyner struct ice_sched_node *tc_node; 4853*f2635e84SEric Joyner int status = ICE_ERR_PARAM; 485471d10453SEric Joyner 485571d10453SEric Joyner if (tc >= ICE_MAX_TRAFFIC_CLASS) 485671d10453SEric Joyner return status; 485771d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 485871d10453SEric Joyner tc_node = ice_sched_get_tc_node(pi, tc); 485971d10453SEric Joyner if (!tc_node) 486071d10453SEric Joyner goto exit_set_tc_node_bw_alloc; 486171d10453SEric Joyner status = ice_sched_cfg_node_bw_alloc(pi->hw, tc_node, rl_type, 486271d10453SEric Joyner bw_alloc); 486371d10453SEric Joyner if (status) 486471d10453SEric Joyner goto exit_set_tc_node_bw_alloc; 486571d10453SEric Joyner status = ice_sched_save_tc_node_bw_alloc(pi, tc, rl_type, bw_alloc); 486671d10453SEric Joyner 486771d10453SEric Joyner exit_set_tc_node_bw_alloc: 486871d10453SEric Joyner ice_release_lock(&pi->sched_lock); 486971d10453SEric Joyner return status; 487071d10453SEric Joyner } 487171d10453SEric Joyner 487271d10453SEric Joyner /** 487371d10453SEric Joyner * ice_cfg_tc_node_bw_alloc - configure TC node BW alloc 487471d10453SEric Joyner * @pi: port information structure 487571d10453SEric Joyner * @tc: TC number 487671d10453SEric Joyner * @rl_type: min or max 487771d10453SEric Joyner * @bw_alloc: bandwidth alloc 487871d10453SEric Joyner * 487971d10453SEric Joyner * This function configures BW limit of TC node. 488071d10453SEric Joyner * Note: The minimum guaranteed reservation is done via DCBX. 488171d10453SEric Joyner */ 4882*f2635e84SEric Joyner int 488371d10453SEric Joyner ice_cfg_tc_node_bw_alloc(struct ice_port_info *pi, u8 tc, 488471d10453SEric Joyner enum ice_rl_type rl_type, u8 bw_alloc) 488571d10453SEric Joyner { 488671d10453SEric Joyner return ice_sched_set_tc_node_bw_alloc(pi, tc, rl_type, bw_alloc); 488771d10453SEric Joyner } 488871d10453SEric Joyner 488971d10453SEric Joyner /** 489071d10453SEric Joyner * ice_sched_set_agg_bw_dflt_lmt - set aggregator node's BW limit to default 489171d10453SEric Joyner * @pi: port information structure 489271d10453SEric Joyner * @vsi_handle: software VSI handle 489371d10453SEric Joyner * 489471d10453SEric Joyner * This function retrieves the aggregator ID based on VSI ID and TC, 489571d10453SEric Joyner * and sets node's BW limit to default. This function needs to be 489671d10453SEric Joyner * called with the scheduler lock held. 489771d10453SEric Joyner */ 4898*f2635e84SEric Joyner int 489971d10453SEric Joyner ice_sched_set_agg_bw_dflt_lmt(struct ice_port_info *pi, u16 vsi_handle) 490071d10453SEric Joyner { 490171d10453SEric Joyner struct ice_vsi_ctx *vsi_ctx; 4902*f2635e84SEric Joyner int status = 0; 490371d10453SEric Joyner u8 tc; 490471d10453SEric Joyner 490571d10453SEric Joyner if (!ice_is_vsi_valid(pi->hw, vsi_handle)) 490671d10453SEric Joyner return ICE_ERR_PARAM; 490771d10453SEric Joyner vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle); 490871d10453SEric Joyner if (!vsi_ctx) 490971d10453SEric Joyner return ICE_ERR_PARAM; 491071d10453SEric Joyner 491171d10453SEric Joyner ice_for_each_traffic_class(tc) { 491271d10453SEric Joyner struct ice_sched_node *node; 491371d10453SEric Joyner 491471d10453SEric Joyner node = vsi_ctx->sched.ag_node[tc]; 491571d10453SEric Joyner if (!node) 491671d10453SEric Joyner continue; 491771d10453SEric Joyner 491871d10453SEric Joyner /* Set min profile to default */ 491971d10453SEric Joyner status = ice_sched_set_node_bw_dflt_lmt(pi, node, ICE_MIN_BW); 492071d10453SEric Joyner if (status) 492171d10453SEric Joyner break; 492271d10453SEric Joyner 492371d10453SEric Joyner /* Set max profile to default */ 492471d10453SEric Joyner status = ice_sched_set_node_bw_dflt_lmt(pi, node, ICE_MAX_BW); 492571d10453SEric Joyner if (status) 492671d10453SEric Joyner break; 492771d10453SEric Joyner 492871d10453SEric Joyner /* Remove shared profile, if there is one */ 492971d10453SEric Joyner status = ice_sched_set_node_bw_dflt_lmt(pi, node, 493071d10453SEric Joyner ICE_SHARED_BW); 493171d10453SEric Joyner if (status) 493271d10453SEric Joyner break; 493371d10453SEric Joyner } 493471d10453SEric Joyner 493571d10453SEric Joyner return status; 493671d10453SEric Joyner } 493771d10453SEric Joyner 493871d10453SEric Joyner /** 493971d10453SEric Joyner * ice_sched_get_node_by_id_type - get node from ID type 494071d10453SEric Joyner * @pi: port information structure 494171d10453SEric Joyner * @id: identifier 494271d10453SEric Joyner * @agg_type: type of aggregator 494371d10453SEric Joyner * @tc: traffic class 494471d10453SEric Joyner * 494571d10453SEric Joyner * This function returns node identified by ID of type aggregator, and 494671d10453SEric Joyner * based on traffic class (TC). This function needs to be called with 494771d10453SEric Joyner * the scheduler lock held. 494871d10453SEric Joyner */ 494971d10453SEric Joyner static struct ice_sched_node * 495071d10453SEric Joyner ice_sched_get_node_by_id_type(struct ice_port_info *pi, u32 id, 495171d10453SEric Joyner enum ice_agg_type agg_type, u8 tc) 495271d10453SEric Joyner { 495371d10453SEric Joyner struct ice_sched_node *node = NULL; 495471d10453SEric Joyner 495571d10453SEric Joyner switch (agg_type) { 495671d10453SEric Joyner case ICE_AGG_TYPE_VSI: { 495771d10453SEric Joyner struct ice_vsi_ctx *vsi_ctx; 495871d10453SEric Joyner u16 vsi_handle = (u16)id; 495971d10453SEric Joyner 496071d10453SEric Joyner if (!ice_is_vsi_valid(pi->hw, vsi_handle)) 496171d10453SEric Joyner break; 496271d10453SEric Joyner /* Get sched_vsi_info */ 496371d10453SEric Joyner vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle); 496471d10453SEric Joyner if (!vsi_ctx) 496571d10453SEric Joyner break; 496671d10453SEric Joyner node = vsi_ctx->sched.vsi_node[tc]; 496771d10453SEric Joyner break; 496871d10453SEric Joyner } 496971d10453SEric Joyner 497071d10453SEric Joyner case ICE_AGG_TYPE_AGG: { 497171d10453SEric Joyner struct ice_sched_node *tc_node; 497271d10453SEric Joyner 497371d10453SEric Joyner tc_node = ice_sched_get_tc_node(pi, tc); 497471d10453SEric Joyner if (tc_node) 497571d10453SEric Joyner node = ice_sched_get_agg_node(pi, tc_node, id); 497671d10453SEric Joyner break; 497771d10453SEric Joyner } 497871d10453SEric Joyner 497971d10453SEric Joyner case ICE_AGG_TYPE_Q: 498071d10453SEric Joyner /* The current implementation allows single queue to modify */ 49818923de59SPiotr Kubaj node = ice_sched_find_node_by_teid(pi->root, id); 498271d10453SEric Joyner break; 498371d10453SEric Joyner 49848923de59SPiotr Kubaj case ICE_AGG_TYPE_QG: { 49858923de59SPiotr Kubaj struct ice_sched_node *child_node; 49868923de59SPiotr Kubaj 498771d10453SEric Joyner /* The current implementation allows single qg to modify */ 49888923de59SPiotr Kubaj child_node = ice_sched_find_node_by_teid(pi->root, id); 498971d10453SEric Joyner if (!child_node) 499071d10453SEric Joyner break; 499171d10453SEric Joyner node = child_node->parent; 499271d10453SEric Joyner break; 49938923de59SPiotr Kubaj } 499471d10453SEric Joyner 499571d10453SEric Joyner default: 499671d10453SEric Joyner break; 499771d10453SEric Joyner } 499871d10453SEric Joyner 499971d10453SEric Joyner return node; 500071d10453SEric Joyner } 500171d10453SEric Joyner 500271d10453SEric Joyner /** 500371d10453SEric Joyner * ice_sched_set_node_bw_lmt_per_tc - set node BW limit per TC 500471d10453SEric Joyner * @pi: port information structure 500571d10453SEric Joyner * @id: ID (software VSI handle or AGG ID) 500671d10453SEric Joyner * @agg_type: aggregator type (VSI or AGG type node) 500771d10453SEric Joyner * @tc: traffic class 500871d10453SEric Joyner * @rl_type: min or max 500971d10453SEric Joyner * @bw: bandwidth in Kbps 501071d10453SEric Joyner * 501171d10453SEric Joyner * This function sets BW limit of VSI or Aggregator scheduling node 501271d10453SEric Joyner * based on TC information from passed in argument BW. 501371d10453SEric Joyner */ 5014*f2635e84SEric Joyner int 501571d10453SEric Joyner ice_sched_set_node_bw_lmt_per_tc(struct ice_port_info *pi, u32 id, 501671d10453SEric Joyner enum ice_agg_type agg_type, u8 tc, 501771d10453SEric Joyner enum ice_rl_type rl_type, u32 bw) 501871d10453SEric Joyner { 501971d10453SEric Joyner struct ice_sched_node *node; 5020*f2635e84SEric Joyner int status = ICE_ERR_PARAM; 502171d10453SEric Joyner 502271d10453SEric Joyner if (!pi) 502371d10453SEric Joyner return status; 502471d10453SEric Joyner 502571d10453SEric Joyner if (rl_type == ICE_UNKNOWN_BW) 502671d10453SEric Joyner return status; 502771d10453SEric Joyner 502871d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 502971d10453SEric Joyner node = ice_sched_get_node_by_id_type(pi, id, agg_type, tc); 503071d10453SEric Joyner if (!node) { 503171d10453SEric Joyner ice_debug(pi->hw, ICE_DBG_SCHED, "Wrong id, agg type, or tc\n"); 503271d10453SEric Joyner goto exit_set_node_bw_lmt_per_tc; 503371d10453SEric Joyner } 503471d10453SEric Joyner if (bw == ICE_SCHED_DFLT_BW) 503571d10453SEric Joyner status = ice_sched_set_node_bw_dflt_lmt(pi, node, rl_type); 503671d10453SEric Joyner else 503771d10453SEric Joyner status = ice_sched_set_node_bw_lmt(pi, node, rl_type, bw); 503871d10453SEric Joyner 503971d10453SEric Joyner exit_set_node_bw_lmt_per_tc: 504071d10453SEric Joyner ice_release_lock(&pi->sched_lock); 504171d10453SEric Joyner return status; 504271d10453SEric Joyner } 504371d10453SEric Joyner 504471d10453SEric Joyner /** 504571d10453SEric Joyner * ice_sched_validate_vsi_srl_node - validate VSI SRL node 504671d10453SEric Joyner * @pi: port information structure 504771d10453SEric Joyner * @vsi_handle: software VSI handle 504871d10453SEric Joyner * 504971d10453SEric Joyner * This function validates SRL node of the VSI node if available SRL layer is 505071d10453SEric Joyner * different than the VSI node layer on all TC(s).This function needs to be 505171d10453SEric Joyner * called with scheduler lock held. 505271d10453SEric Joyner */ 5053*f2635e84SEric Joyner static int 505471d10453SEric Joyner ice_sched_validate_vsi_srl_node(struct ice_port_info *pi, u16 vsi_handle) 505571d10453SEric Joyner { 505671d10453SEric Joyner u8 sel_layer = ICE_SCHED_INVAL_LAYER_NUM; 505771d10453SEric Joyner u8 tc; 505871d10453SEric Joyner 505971d10453SEric Joyner if (!ice_is_vsi_valid(pi->hw, vsi_handle)) 506071d10453SEric Joyner return ICE_ERR_PARAM; 506171d10453SEric Joyner 506271d10453SEric Joyner /* Return success if no nodes are present across TC */ 506371d10453SEric Joyner ice_for_each_traffic_class(tc) { 506471d10453SEric Joyner struct ice_sched_node *tc_node, *vsi_node; 506571d10453SEric Joyner enum ice_rl_type rl_type = ICE_SHARED_BW; 5066*f2635e84SEric Joyner int status; 506771d10453SEric Joyner 506871d10453SEric Joyner tc_node = ice_sched_get_tc_node(pi, tc); 506971d10453SEric Joyner if (!tc_node) 507071d10453SEric Joyner continue; 507171d10453SEric Joyner 507271d10453SEric Joyner vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle); 507371d10453SEric Joyner if (!vsi_node) 507471d10453SEric Joyner continue; 507571d10453SEric Joyner 507671d10453SEric Joyner /* SRL bandwidth layer selection */ 507771d10453SEric Joyner if (sel_layer == ICE_SCHED_INVAL_LAYER_NUM) { 507871d10453SEric Joyner u8 node_layer = vsi_node->tx_sched_layer; 507971d10453SEric Joyner u8 layer_num; 508071d10453SEric Joyner 508171d10453SEric Joyner layer_num = ice_sched_get_rl_prof_layer(pi, rl_type, 508271d10453SEric Joyner node_layer); 508371d10453SEric Joyner if (layer_num >= pi->hw->num_tx_sched_layers) 508471d10453SEric Joyner return ICE_ERR_PARAM; 508571d10453SEric Joyner sel_layer = layer_num; 508671d10453SEric Joyner } 508771d10453SEric Joyner 508871d10453SEric Joyner status = ice_sched_validate_srl_node(vsi_node, sel_layer); 508971d10453SEric Joyner if (status) 509071d10453SEric Joyner return status; 509171d10453SEric Joyner } 5092*f2635e84SEric Joyner return 0; 509371d10453SEric Joyner } 509471d10453SEric Joyner 509571d10453SEric Joyner /** 5096d08b8680SEric Joyner * ice_sched_set_save_vsi_srl_node_bw - set VSI shared limit values 5097d08b8680SEric Joyner * @pi: port information structure 5098d08b8680SEric Joyner * @vsi_handle: software VSI handle 5099d08b8680SEric Joyner * @tc: traffic class 5100d08b8680SEric Joyner * @srl_node: sched node to configure 5101d08b8680SEric Joyner * @rl_type: rate limit type minimum, maximum, or shared 5102d08b8680SEric Joyner * @bw: minimum, maximum, or shared bandwidth in Kbps 5103d08b8680SEric Joyner * 5104d08b8680SEric Joyner * Configure shared rate limiter(SRL) of VSI type nodes across given traffic 5105d08b8680SEric Joyner * class, and saves those value for later use for replaying purposes. The 5106d08b8680SEric Joyner * caller holds the scheduler lock. 5107d08b8680SEric Joyner */ 5108*f2635e84SEric Joyner static int 5109d08b8680SEric Joyner ice_sched_set_save_vsi_srl_node_bw(struct ice_port_info *pi, u16 vsi_handle, 5110d08b8680SEric Joyner u8 tc, struct ice_sched_node *srl_node, 5111d08b8680SEric Joyner enum ice_rl_type rl_type, u32 bw) 5112d08b8680SEric Joyner { 5113*f2635e84SEric Joyner int status; 5114d08b8680SEric Joyner 5115d08b8680SEric Joyner if (bw == ICE_SCHED_DFLT_BW) { 5116d08b8680SEric Joyner status = ice_sched_set_node_bw_dflt_lmt(pi, srl_node, rl_type); 5117d08b8680SEric Joyner } else { 5118d08b8680SEric Joyner status = ice_sched_set_node_bw_lmt(pi, srl_node, rl_type, bw); 5119d08b8680SEric Joyner if (status) 5120d08b8680SEric Joyner return status; 5121d08b8680SEric Joyner status = ice_sched_save_vsi_bw(pi, vsi_handle, tc, rl_type, bw); 5122d08b8680SEric Joyner } 5123d08b8680SEric Joyner return status; 5124d08b8680SEric Joyner } 5125d08b8680SEric Joyner 5126d08b8680SEric Joyner /** 5127d08b8680SEric Joyner * ice_sched_set_vsi_node_srl_per_tc - set VSI node BW shared limit for tc 5128d08b8680SEric Joyner * @pi: port information structure 5129d08b8680SEric Joyner * @vsi_handle: software VSI handle 5130d08b8680SEric Joyner * @tc: traffic class 5131d08b8680SEric Joyner * @min_bw: minimum bandwidth in Kbps 5132d08b8680SEric Joyner * @max_bw: maximum bandwidth in Kbps 5133d08b8680SEric Joyner * @shared_bw: shared bandwidth in Kbps 5134d08b8680SEric Joyner * 5135d08b8680SEric Joyner * Configure shared rate limiter(SRL) of VSI type nodes across requested 5136d08b8680SEric Joyner * traffic class for VSI matching handle. When BW value of ICE_SCHED_DFLT_BW 5137d08b8680SEric Joyner * is passed, it removes the corresponding bw from the node. The caller 5138d08b8680SEric Joyner * holds scheduler lock. 5139d08b8680SEric Joyner */ 5140*f2635e84SEric Joyner static int 5141d08b8680SEric Joyner ice_sched_set_vsi_node_srl_per_tc(struct ice_port_info *pi, u16 vsi_handle, 5142d08b8680SEric Joyner u8 tc, u32 min_bw, u32 max_bw, u32 shared_bw) 5143d08b8680SEric Joyner { 5144d08b8680SEric Joyner struct ice_sched_node *tc_node, *vsi_node, *cfg_node; 5145d08b8680SEric Joyner u8 layer_num; 5146*f2635e84SEric Joyner int status; 5147d08b8680SEric Joyner 5148d08b8680SEric Joyner tc_node = ice_sched_get_tc_node(pi, tc); 5149d08b8680SEric Joyner if (!tc_node) 5150d08b8680SEric Joyner return ICE_ERR_CFG; 5151d08b8680SEric Joyner 5152d08b8680SEric Joyner vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle); 5153d08b8680SEric Joyner if (!vsi_node) 5154d08b8680SEric Joyner return ICE_ERR_CFG; 5155d08b8680SEric Joyner 5156d08b8680SEric Joyner layer_num = ice_sched_get_rl_prof_layer(pi, ICE_SHARED_BW, 5157d08b8680SEric Joyner vsi_node->tx_sched_layer); 5158d08b8680SEric Joyner if (layer_num >= pi->hw->num_tx_sched_layers) 5159d08b8680SEric Joyner return ICE_ERR_PARAM; 5160d08b8680SEric Joyner 5161d08b8680SEric Joyner /* SRL node may be different */ 5162d08b8680SEric Joyner cfg_node = ice_sched_get_srl_node(vsi_node, layer_num); 5163d08b8680SEric Joyner if (!cfg_node) 5164d08b8680SEric Joyner return ICE_ERR_CFG; 5165d08b8680SEric Joyner 5166d08b8680SEric Joyner status = ice_sched_set_save_vsi_srl_node_bw(pi, vsi_handle, tc, 5167d08b8680SEric Joyner cfg_node, ICE_MIN_BW, 5168d08b8680SEric Joyner min_bw); 5169d08b8680SEric Joyner if (status) 5170d08b8680SEric Joyner return status; 5171d08b8680SEric Joyner 5172d08b8680SEric Joyner status = ice_sched_set_save_vsi_srl_node_bw(pi, vsi_handle, tc, 5173d08b8680SEric Joyner cfg_node, ICE_MAX_BW, 5174d08b8680SEric Joyner max_bw); 5175d08b8680SEric Joyner if (status) 5176d08b8680SEric Joyner return status; 5177d08b8680SEric Joyner 5178d08b8680SEric Joyner return ice_sched_set_save_vsi_srl_node_bw(pi, vsi_handle, tc, cfg_node, 5179d08b8680SEric Joyner ICE_SHARED_BW, shared_bw); 5180d08b8680SEric Joyner } 5181d08b8680SEric Joyner 5182d08b8680SEric Joyner /** 518371d10453SEric Joyner * ice_sched_set_vsi_bw_shared_lmt - set VSI BW shared limit 518471d10453SEric Joyner * @pi: port information structure 518571d10453SEric Joyner * @vsi_handle: software VSI handle 5186d08b8680SEric Joyner * @min_bw: minimum bandwidth in Kbps 5187d08b8680SEric Joyner * @max_bw: maximum bandwidth in Kbps 5188d08b8680SEric Joyner * @shared_bw: shared bandwidth in Kbps 518971d10453SEric Joyner * 5190d08b8680SEric Joyner * Configure shared rate limiter(SRL) of all VSI type nodes across all traffic 5191d08b8680SEric Joyner * classes for VSI matching handle. When BW value of ICE_SCHED_DFLT_BW is 5192d08b8680SEric Joyner * passed, it removes those value(s) from the node. 519371d10453SEric Joyner */ 5194*f2635e84SEric Joyner int 519571d10453SEric Joyner ice_sched_set_vsi_bw_shared_lmt(struct ice_port_info *pi, u16 vsi_handle, 5196d08b8680SEric Joyner u32 min_bw, u32 max_bw, u32 shared_bw) 519771d10453SEric Joyner { 5198*f2635e84SEric Joyner int status = 0; 519971d10453SEric Joyner u8 tc; 520071d10453SEric Joyner 520171d10453SEric Joyner if (!pi) 520271d10453SEric Joyner return ICE_ERR_PARAM; 520371d10453SEric Joyner 520471d10453SEric Joyner if (!ice_is_vsi_valid(pi->hw, vsi_handle)) 520571d10453SEric Joyner return ICE_ERR_PARAM; 520671d10453SEric Joyner 520771d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 520871d10453SEric Joyner status = ice_sched_validate_vsi_srl_node(pi, vsi_handle); 520971d10453SEric Joyner if (status) 521071d10453SEric Joyner goto exit_set_vsi_bw_shared_lmt; 521171d10453SEric Joyner /* Return success if no nodes are present across TC */ 521271d10453SEric Joyner ice_for_each_traffic_class(tc) { 521371d10453SEric Joyner struct ice_sched_node *tc_node, *vsi_node; 521471d10453SEric Joyner 521571d10453SEric Joyner tc_node = ice_sched_get_tc_node(pi, tc); 521671d10453SEric Joyner if (!tc_node) 521771d10453SEric Joyner continue; 521871d10453SEric Joyner 521971d10453SEric Joyner vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle); 522071d10453SEric Joyner if (!vsi_node) 522171d10453SEric Joyner continue; 522271d10453SEric Joyner 5223d08b8680SEric Joyner status = ice_sched_set_vsi_node_srl_per_tc(pi, vsi_handle, tc, 5224d08b8680SEric Joyner min_bw, max_bw, 5225d08b8680SEric Joyner shared_bw); 522671d10453SEric Joyner if (status) 522771d10453SEric Joyner break; 522871d10453SEric Joyner } 522971d10453SEric Joyner 523071d10453SEric Joyner exit_set_vsi_bw_shared_lmt: 523171d10453SEric Joyner ice_release_lock(&pi->sched_lock); 523271d10453SEric Joyner return status; 523371d10453SEric Joyner } 523471d10453SEric Joyner 523571d10453SEric Joyner /** 523671d10453SEric Joyner * ice_sched_validate_agg_srl_node - validate AGG SRL node 523771d10453SEric Joyner * @pi: port information structure 523871d10453SEric Joyner * @agg_id: aggregator ID 523971d10453SEric Joyner * 524071d10453SEric Joyner * This function validates SRL node of the AGG node if available SRL layer is 524171d10453SEric Joyner * different than the AGG node layer on all TC(s).This function needs to be 524271d10453SEric Joyner * called with scheduler lock held. 524371d10453SEric Joyner */ 5244*f2635e84SEric Joyner static int 524571d10453SEric Joyner ice_sched_validate_agg_srl_node(struct ice_port_info *pi, u32 agg_id) 524671d10453SEric Joyner { 524771d10453SEric Joyner u8 sel_layer = ICE_SCHED_INVAL_LAYER_NUM; 524871d10453SEric Joyner struct ice_sched_agg_info *agg_info; 524971d10453SEric Joyner bool agg_id_present = false; 5250*f2635e84SEric Joyner int status = 0; 525171d10453SEric Joyner u8 tc; 525271d10453SEric Joyner 525371d10453SEric Joyner LIST_FOR_EACH_ENTRY(agg_info, &pi->hw->agg_list, ice_sched_agg_info, 525471d10453SEric Joyner list_entry) 525571d10453SEric Joyner if (agg_info->agg_id == agg_id) { 525671d10453SEric Joyner agg_id_present = true; 525771d10453SEric Joyner break; 525871d10453SEric Joyner } 525971d10453SEric Joyner if (!agg_id_present) 526071d10453SEric Joyner return ICE_ERR_PARAM; 526171d10453SEric Joyner /* Return success if no nodes are present across TC */ 526271d10453SEric Joyner ice_for_each_traffic_class(tc) { 526371d10453SEric Joyner struct ice_sched_node *tc_node, *agg_node; 526471d10453SEric Joyner enum ice_rl_type rl_type = ICE_SHARED_BW; 526571d10453SEric Joyner 526671d10453SEric Joyner tc_node = ice_sched_get_tc_node(pi, tc); 526771d10453SEric Joyner if (!tc_node) 526871d10453SEric Joyner continue; 526971d10453SEric Joyner 527071d10453SEric Joyner agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id); 527171d10453SEric Joyner if (!agg_node) 527271d10453SEric Joyner continue; 527371d10453SEric Joyner /* SRL bandwidth layer selection */ 527471d10453SEric Joyner if (sel_layer == ICE_SCHED_INVAL_LAYER_NUM) { 527571d10453SEric Joyner u8 node_layer = agg_node->tx_sched_layer; 527671d10453SEric Joyner u8 layer_num; 527771d10453SEric Joyner 527871d10453SEric Joyner layer_num = ice_sched_get_rl_prof_layer(pi, rl_type, 527971d10453SEric Joyner node_layer); 528071d10453SEric Joyner if (layer_num >= pi->hw->num_tx_sched_layers) 528171d10453SEric Joyner return ICE_ERR_PARAM; 528271d10453SEric Joyner sel_layer = layer_num; 528371d10453SEric Joyner } 528471d10453SEric Joyner 528571d10453SEric Joyner status = ice_sched_validate_srl_node(agg_node, sel_layer); 528671d10453SEric Joyner if (status) 528771d10453SEric Joyner break; 528871d10453SEric Joyner } 528971d10453SEric Joyner return status; 529071d10453SEric Joyner } 529171d10453SEric Joyner 529271d10453SEric Joyner /** 5293d08b8680SEric Joyner * ice_sched_validate_agg_id - Validate aggregator id 529471d10453SEric Joyner * @pi: port information structure 529571d10453SEric Joyner * @agg_id: aggregator ID 529671d10453SEric Joyner * 5297d08b8680SEric Joyner * This function validates aggregator id. Caller holds the scheduler lock. 529871d10453SEric Joyner */ 5299*f2635e84SEric Joyner static int 5300d08b8680SEric Joyner ice_sched_validate_agg_id(struct ice_port_info *pi, u32 agg_id) 530171d10453SEric Joyner { 530271d10453SEric Joyner struct ice_sched_agg_info *agg_info; 530371d10453SEric Joyner struct ice_sched_agg_info *tmp; 530471d10453SEric Joyner bool agg_id_present = false; 5305*f2635e84SEric Joyner int status; 530671d10453SEric Joyner 530771d10453SEric Joyner status = ice_sched_validate_agg_srl_node(pi, agg_id); 530871d10453SEric Joyner if (status) 5309d08b8680SEric Joyner return status; 531071d10453SEric Joyner 531171d10453SEric Joyner LIST_FOR_EACH_ENTRY_SAFE(agg_info, tmp, &pi->hw->agg_list, 531271d10453SEric Joyner ice_sched_agg_info, list_entry) 531371d10453SEric Joyner if (agg_info->agg_id == agg_id) { 531471d10453SEric Joyner agg_id_present = true; 531571d10453SEric Joyner break; 531671d10453SEric Joyner } 531771d10453SEric Joyner 5318d08b8680SEric Joyner if (!agg_id_present) 5319d08b8680SEric Joyner return ICE_ERR_PARAM; 5320d08b8680SEric Joyner 5321*f2635e84SEric Joyner return 0; 532271d10453SEric Joyner } 532371d10453SEric Joyner 5324d08b8680SEric Joyner /** 5325d08b8680SEric Joyner * ice_sched_set_save_agg_srl_node_bw - set aggregator shared limit values 5326d08b8680SEric Joyner * @pi: port information structure 5327d08b8680SEric Joyner * @agg_id: aggregator ID 5328d08b8680SEric Joyner * @tc: traffic class 5329d08b8680SEric Joyner * @srl_node: sched node to configure 5330d08b8680SEric Joyner * @rl_type: rate limit type minimum, maximum, or shared 5331d08b8680SEric Joyner * @bw: minimum, maximum, or shared bandwidth in Kbps 5332d08b8680SEric Joyner * 5333d08b8680SEric Joyner * Configure shared rate limiter(SRL) of aggregator type nodes across 5334d08b8680SEric Joyner * requested traffic class, and saves those value for later use for 5335d08b8680SEric Joyner * replaying purposes. The caller holds the scheduler lock. 5336d08b8680SEric Joyner */ 5337*f2635e84SEric Joyner static int 5338d08b8680SEric Joyner ice_sched_set_save_agg_srl_node_bw(struct ice_port_info *pi, u32 agg_id, u8 tc, 5339d08b8680SEric Joyner struct ice_sched_node *srl_node, 5340d08b8680SEric Joyner enum ice_rl_type rl_type, u32 bw) 5341d08b8680SEric Joyner { 5342*f2635e84SEric Joyner int status; 5343d08b8680SEric Joyner 5344d08b8680SEric Joyner if (bw == ICE_SCHED_DFLT_BW) { 5345d08b8680SEric Joyner status = ice_sched_set_node_bw_dflt_lmt(pi, srl_node, rl_type); 5346d08b8680SEric Joyner } else { 5347d08b8680SEric Joyner status = ice_sched_set_node_bw_lmt(pi, srl_node, rl_type, bw); 5348d08b8680SEric Joyner if (status) 5349d08b8680SEric Joyner return status; 5350d08b8680SEric Joyner status = ice_sched_save_agg_bw(pi, agg_id, tc, rl_type, bw); 5351d08b8680SEric Joyner } 5352d08b8680SEric Joyner return status; 5353d08b8680SEric Joyner } 5354d08b8680SEric Joyner 5355d08b8680SEric Joyner /** 5356d08b8680SEric Joyner * ice_sched_set_agg_node_srl_per_tc - set aggregator SRL per tc 5357d08b8680SEric Joyner * @pi: port information structure 5358d08b8680SEric Joyner * @agg_id: aggregator ID 5359d08b8680SEric Joyner * @tc: traffic class 5360d08b8680SEric Joyner * @min_bw: minimum bandwidth in Kbps 5361d08b8680SEric Joyner * @max_bw: maximum bandwidth in Kbps 5362d08b8680SEric Joyner * @shared_bw: shared bandwidth in Kbps 5363d08b8680SEric Joyner * 5364d08b8680SEric Joyner * This function configures the shared rate limiter(SRL) of aggregator type 5365d08b8680SEric Joyner * node for a given traffic class for aggregator matching agg_id. When BW 5366d08b8680SEric Joyner * value of ICE_SCHED_DFLT_BW is passed, it removes SRL from the node. Caller 5367d08b8680SEric Joyner * holds the scheduler lock. 5368d08b8680SEric Joyner */ 5369*f2635e84SEric Joyner static int 5370d08b8680SEric Joyner ice_sched_set_agg_node_srl_per_tc(struct ice_port_info *pi, u32 agg_id, 5371d08b8680SEric Joyner u8 tc, u32 min_bw, u32 max_bw, u32 shared_bw) 5372d08b8680SEric Joyner { 5373d08b8680SEric Joyner struct ice_sched_node *tc_node, *agg_node, *cfg_node; 5374d08b8680SEric Joyner enum ice_rl_type rl_type = ICE_SHARED_BW; 5375*f2635e84SEric Joyner int status = ICE_ERR_CFG; 5376d08b8680SEric Joyner u8 layer_num; 5377d08b8680SEric Joyner 5378d08b8680SEric Joyner tc_node = ice_sched_get_tc_node(pi, tc); 5379d08b8680SEric Joyner if (!tc_node) 5380d08b8680SEric Joyner return ICE_ERR_CFG; 5381d08b8680SEric Joyner 5382d08b8680SEric Joyner agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id); 5383d08b8680SEric Joyner if (!agg_node) 5384d08b8680SEric Joyner return ICE_ERR_CFG; 5385d08b8680SEric Joyner 5386d08b8680SEric Joyner layer_num = ice_sched_get_rl_prof_layer(pi, rl_type, 5387d08b8680SEric Joyner agg_node->tx_sched_layer); 5388d08b8680SEric Joyner if (layer_num >= pi->hw->num_tx_sched_layers) 5389d08b8680SEric Joyner return ICE_ERR_PARAM; 5390d08b8680SEric Joyner 5391d08b8680SEric Joyner /* SRL node may be different */ 5392d08b8680SEric Joyner cfg_node = ice_sched_get_srl_node(agg_node, layer_num); 5393d08b8680SEric Joyner if (!cfg_node) 5394d08b8680SEric Joyner return ICE_ERR_CFG; 5395d08b8680SEric Joyner 5396d08b8680SEric Joyner status = ice_sched_set_save_agg_srl_node_bw(pi, agg_id, tc, cfg_node, 5397d08b8680SEric Joyner ICE_MIN_BW, min_bw); 5398d08b8680SEric Joyner if (status) 5399d08b8680SEric Joyner return status; 5400d08b8680SEric Joyner 5401d08b8680SEric Joyner status = ice_sched_set_save_agg_srl_node_bw(pi, agg_id, tc, cfg_node, 5402d08b8680SEric Joyner ICE_MAX_BW, max_bw); 5403d08b8680SEric Joyner if (status) 5404d08b8680SEric Joyner return status; 5405d08b8680SEric Joyner 5406d08b8680SEric Joyner status = ice_sched_set_save_agg_srl_node_bw(pi, agg_id, tc, cfg_node, 5407d08b8680SEric Joyner ICE_SHARED_BW, shared_bw); 5408d08b8680SEric Joyner return status; 5409d08b8680SEric Joyner } 5410d08b8680SEric Joyner 5411d08b8680SEric Joyner /** 5412d08b8680SEric Joyner * ice_sched_set_agg_bw_shared_lmt - set aggregator BW shared limit 5413d08b8680SEric Joyner * @pi: port information structure 5414d08b8680SEric Joyner * @agg_id: aggregator ID 5415d08b8680SEric Joyner * @min_bw: minimum bandwidth in Kbps 5416d08b8680SEric Joyner * @max_bw: maximum bandwidth in Kbps 5417d08b8680SEric Joyner * @shared_bw: shared bandwidth in Kbps 5418d08b8680SEric Joyner * 5419d08b8680SEric Joyner * This function configures the shared rate limiter(SRL) of all aggregator type 5420d08b8680SEric Joyner * nodes across all traffic classes for aggregator matching agg_id. When 5421d08b8680SEric Joyner * BW value of ICE_SCHED_DFLT_BW is passed, it removes SRL from the 5422d08b8680SEric Joyner * node(s). 5423d08b8680SEric Joyner */ 5424*f2635e84SEric Joyner int 5425d08b8680SEric Joyner ice_sched_set_agg_bw_shared_lmt(struct ice_port_info *pi, u32 agg_id, 5426d08b8680SEric Joyner u32 min_bw, u32 max_bw, u32 shared_bw) 5427d08b8680SEric Joyner { 5428*f2635e84SEric Joyner int status; 5429d08b8680SEric Joyner u8 tc; 5430d08b8680SEric Joyner 5431d08b8680SEric Joyner if (!pi) 5432d08b8680SEric Joyner return ICE_ERR_PARAM; 5433d08b8680SEric Joyner 5434d08b8680SEric Joyner ice_acquire_lock(&pi->sched_lock); 5435d08b8680SEric Joyner status = ice_sched_validate_agg_id(pi, agg_id); 5436d08b8680SEric Joyner if (status) 5437d08b8680SEric Joyner goto exit_agg_bw_shared_lmt; 5438d08b8680SEric Joyner 543971d10453SEric Joyner /* Return success if no nodes are present across TC */ 544071d10453SEric Joyner ice_for_each_traffic_class(tc) { 544171d10453SEric Joyner struct ice_sched_node *tc_node, *agg_node; 544271d10453SEric Joyner 544371d10453SEric Joyner tc_node = ice_sched_get_tc_node(pi, tc); 544471d10453SEric Joyner if (!tc_node) 544571d10453SEric Joyner continue; 544671d10453SEric Joyner 544771d10453SEric Joyner agg_node = ice_sched_get_agg_node(pi, tc_node, agg_id); 544871d10453SEric Joyner if (!agg_node) 544971d10453SEric Joyner continue; 545071d10453SEric Joyner 5451d08b8680SEric Joyner status = ice_sched_set_agg_node_srl_per_tc(pi, agg_id, tc, 5452d08b8680SEric Joyner min_bw, max_bw, 5453d08b8680SEric Joyner shared_bw); 545471d10453SEric Joyner if (status) 545571d10453SEric Joyner break; 545671d10453SEric Joyner } 545771d10453SEric Joyner 545871d10453SEric Joyner exit_agg_bw_shared_lmt: 545971d10453SEric Joyner ice_release_lock(&pi->sched_lock); 546071d10453SEric Joyner return status; 546171d10453SEric Joyner } 546271d10453SEric Joyner 546371d10453SEric Joyner /** 5464d08b8680SEric Joyner * ice_sched_set_agg_bw_shared_lmt_per_tc - set aggregator BW shared lmt per tc 5465d08b8680SEric Joyner * @pi: port information structure 5466d08b8680SEric Joyner * @agg_id: aggregator ID 5467d08b8680SEric Joyner * @tc: traffic class 5468d08b8680SEric Joyner * @min_bw: minimum bandwidth in Kbps 5469d08b8680SEric Joyner * @max_bw: maximum bandwidth in Kbps 5470d08b8680SEric Joyner * @shared_bw: shared bandwidth in Kbps 5471d08b8680SEric Joyner * 5472d08b8680SEric Joyner * This function configures the shared rate limiter(SRL) of aggregator type 5473d08b8680SEric Joyner * node for a given traffic class for aggregator matching agg_id. When BW 5474d08b8680SEric Joyner * value of ICE_SCHED_DFLT_BW is passed, it removes SRL from the node. 5475d08b8680SEric Joyner */ 5476*f2635e84SEric Joyner int 5477d08b8680SEric Joyner ice_sched_set_agg_bw_shared_lmt_per_tc(struct ice_port_info *pi, u32 agg_id, 5478d08b8680SEric Joyner u8 tc, u32 min_bw, u32 max_bw, 5479d08b8680SEric Joyner u32 shared_bw) 5480d08b8680SEric Joyner { 5481*f2635e84SEric Joyner int status; 5482d08b8680SEric Joyner 5483d08b8680SEric Joyner if (!pi) 5484d08b8680SEric Joyner return ICE_ERR_PARAM; 5485d08b8680SEric Joyner ice_acquire_lock(&pi->sched_lock); 5486d08b8680SEric Joyner status = ice_sched_validate_agg_id(pi, agg_id); 5487d08b8680SEric Joyner if (status) 5488d08b8680SEric Joyner goto exit_agg_bw_shared_lmt_per_tc; 5489d08b8680SEric Joyner 5490d08b8680SEric Joyner status = ice_sched_set_agg_node_srl_per_tc(pi, agg_id, tc, min_bw, 5491d08b8680SEric Joyner max_bw, shared_bw); 5492d08b8680SEric Joyner 5493d08b8680SEric Joyner exit_agg_bw_shared_lmt_per_tc: 5494d08b8680SEric Joyner ice_release_lock(&pi->sched_lock); 5495d08b8680SEric Joyner return status; 5496d08b8680SEric Joyner } 5497d08b8680SEric Joyner 5498d08b8680SEric Joyner /** 549971d10453SEric Joyner * ice_sched_cfg_sibl_node_prio - configure node sibling priority 550071d10453SEric Joyner * @pi: port information structure 550171d10453SEric Joyner * @node: sched node to configure 550271d10453SEric Joyner * @priority: sibling priority 550371d10453SEric Joyner * 550471d10453SEric Joyner * This function configures node element's sibling priority only. This 550571d10453SEric Joyner * function needs to be called with scheduler lock held. 550671d10453SEric Joyner */ 5507*f2635e84SEric Joyner int 550871d10453SEric Joyner ice_sched_cfg_sibl_node_prio(struct ice_port_info *pi, 550971d10453SEric Joyner struct ice_sched_node *node, u8 priority) 551071d10453SEric Joyner { 551171d10453SEric Joyner struct ice_aqc_txsched_elem_data buf; 551271d10453SEric Joyner struct ice_aqc_txsched_elem *data; 551371d10453SEric Joyner struct ice_hw *hw = pi->hw; 5514*f2635e84SEric Joyner int status; 551571d10453SEric Joyner 551671d10453SEric Joyner if (!hw) 551771d10453SEric Joyner return ICE_ERR_PARAM; 551871d10453SEric Joyner buf = node->info; 551971d10453SEric Joyner data = &buf.data; 552071d10453SEric Joyner data->valid_sections |= ICE_AQC_ELEM_VALID_GENERIC; 552171d10453SEric Joyner priority = (priority << ICE_AQC_ELEM_GENERIC_PRIO_S) & 552271d10453SEric Joyner ICE_AQC_ELEM_GENERIC_PRIO_M; 552371d10453SEric Joyner data->generic &= ~ICE_AQC_ELEM_GENERIC_PRIO_M; 552471d10453SEric Joyner data->generic |= priority; 552571d10453SEric Joyner 552671d10453SEric Joyner /* Configure element */ 552771d10453SEric Joyner status = ice_sched_update_elem(hw, node, &buf); 552871d10453SEric Joyner return status; 552971d10453SEric Joyner } 553071d10453SEric Joyner 553171d10453SEric Joyner /** 553271d10453SEric Joyner * ice_cfg_rl_burst_size - Set burst size value 553371d10453SEric Joyner * @hw: pointer to the HW struct 553471d10453SEric Joyner * @bytes: burst size in bytes 553571d10453SEric Joyner * 553671d10453SEric Joyner * This function configures/set the burst size to requested new value. The new 553771d10453SEric Joyner * burst size value is used for future rate limit calls. It doesn't change the 553871d10453SEric Joyner * existing or previously created RL profiles. 553971d10453SEric Joyner */ 5540*f2635e84SEric Joyner int ice_cfg_rl_burst_size(struct ice_hw *hw, u32 bytes) 554171d10453SEric Joyner { 554271d10453SEric Joyner u16 burst_size_to_prog; 554371d10453SEric Joyner 554471d10453SEric Joyner if (bytes < ICE_MIN_BURST_SIZE_ALLOWED || 554571d10453SEric Joyner bytes > ICE_MAX_BURST_SIZE_ALLOWED) 554671d10453SEric Joyner return ICE_ERR_PARAM; 554771d10453SEric Joyner if (ice_round_to_num(bytes, 64) <= 554871d10453SEric Joyner ICE_MAX_BURST_SIZE_64_BYTE_GRANULARITY) { 554971d10453SEric Joyner /* 64 byte granularity case */ 555071d10453SEric Joyner /* Disable MSB granularity bit */ 555171d10453SEric Joyner burst_size_to_prog = ICE_64_BYTE_GRANULARITY; 555271d10453SEric Joyner /* round number to nearest 64 byte granularity */ 555371d10453SEric Joyner bytes = ice_round_to_num(bytes, 64); 555471d10453SEric Joyner /* The value is in 64 byte chunks */ 555571d10453SEric Joyner burst_size_to_prog |= (u16)(bytes / 64); 555671d10453SEric Joyner } else { 555771d10453SEric Joyner /* k bytes granularity case */ 555871d10453SEric Joyner /* Enable MSB granularity bit */ 555971d10453SEric Joyner burst_size_to_prog = ICE_KBYTE_GRANULARITY; 556071d10453SEric Joyner /* round number to nearest 1024 granularity */ 556171d10453SEric Joyner bytes = ice_round_to_num(bytes, 1024); 556271d10453SEric Joyner /* check rounding doesn't go beyond allowed */ 556371d10453SEric Joyner if (bytes > ICE_MAX_BURST_SIZE_KBYTE_GRANULARITY) 556471d10453SEric Joyner bytes = ICE_MAX_BURST_SIZE_KBYTE_GRANULARITY; 556571d10453SEric Joyner /* The value is in k bytes */ 556671d10453SEric Joyner burst_size_to_prog |= (u16)(bytes / 1024); 556771d10453SEric Joyner } 556871d10453SEric Joyner hw->max_burst_size = burst_size_to_prog; 5569*f2635e84SEric Joyner return 0; 557071d10453SEric Joyner } 557171d10453SEric Joyner 55727d7af7f8SEric Joyner /** 557371d10453SEric Joyner * ice_sched_replay_node_prio - re-configure node priority 557471d10453SEric Joyner * @hw: pointer to the HW struct 557571d10453SEric Joyner * @node: sched node to configure 557671d10453SEric Joyner * @priority: priority value 557771d10453SEric Joyner * 557871d10453SEric Joyner * This function configures node element's priority value. It 557971d10453SEric Joyner * needs to be called with scheduler lock held. 558071d10453SEric Joyner */ 5581*f2635e84SEric Joyner static int 558271d10453SEric Joyner ice_sched_replay_node_prio(struct ice_hw *hw, struct ice_sched_node *node, 558371d10453SEric Joyner u8 priority) 558471d10453SEric Joyner { 558571d10453SEric Joyner struct ice_aqc_txsched_elem_data buf; 558671d10453SEric Joyner struct ice_aqc_txsched_elem *data; 5587*f2635e84SEric Joyner int status; 558871d10453SEric Joyner 558971d10453SEric Joyner buf = node->info; 559071d10453SEric Joyner data = &buf.data; 559171d10453SEric Joyner data->valid_sections |= ICE_AQC_ELEM_VALID_GENERIC; 559271d10453SEric Joyner data->generic = priority; 559371d10453SEric Joyner 559471d10453SEric Joyner /* Configure element */ 559571d10453SEric Joyner status = ice_sched_update_elem(hw, node, &buf); 559671d10453SEric Joyner return status; 559771d10453SEric Joyner } 559871d10453SEric Joyner 559971d10453SEric Joyner /** 560071d10453SEric Joyner * ice_sched_replay_node_bw - replay node(s) BW 560171d10453SEric Joyner * @hw: pointer to the HW struct 560271d10453SEric Joyner * @node: sched node to configure 560371d10453SEric Joyner * @bw_t_info: BW type information 560471d10453SEric Joyner * 560571d10453SEric Joyner * This function restores node's BW from bw_t_info. The caller needs 560671d10453SEric Joyner * to hold the scheduler lock. 560771d10453SEric Joyner */ 5608*f2635e84SEric Joyner static int 560971d10453SEric Joyner ice_sched_replay_node_bw(struct ice_hw *hw, struct ice_sched_node *node, 561071d10453SEric Joyner struct ice_bw_type_info *bw_t_info) 561171d10453SEric Joyner { 561271d10453SEric Joyner struct ice_port_info *pi = hw->port_info; 5613*f2635e84SEric Joyner int status = ICE_ERR_PARAM; 561471d10453SEric Joyner u16 bw_alloc; 561571d10453SEric Joyner 561671d10453SEric Joyner if (!node) 561771d10453SEric Joyner return status; 561871d10453SEric Joyner if (!ice_is_any_bit_set(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_CNT)) 5619*f2635e84SEric Joyner return 0; 562071d10453SEric Joyner if (ice_is_bit_set(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_PRIO)) { 562171d10453SEric Joyner status = ice_sched_replay_node_prio(hw, node, 562271d10453SEric Joyner bw_t_info->generic); 562371d10453SEric Joyner if (status) 562471d10453SEric Joyner return status; 562571d10453SEric Joyner } 562671d10453SEric Joyner if (ice_is_bit_set(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_CIR)) { 562771d10453SEric Joyner status = ice_sched_set_node_bw_lmt(pi, node, ICE_MIN_BW, 562871d10453SEric Joyner bw_t_info->cir_bw.bw); 562971d10453SEric Joyner if (status) 563071d10453SEric Joyner return status; 563171d10453SEric Joyner } 563271d10453SEric Joyner if (ice_is_bit_set(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_CIR_WT)) { 563371d10453SEric Joyner bw_alloc = bw_t_info->cir_bw.bw_alloc; 563471d10453SEric Joyner status = ice_sched_cfg_node_bw_alloc(hw, node, ICE_MIN_BW, 563571d10453SEric Joyner bw_alloc); 563671d10453SEric Joyner if (status) 563771d10453SEric Joyner return status; 563871d10453SEric Joyner } 563971d10453SEric Joyner if (ice_is_bit_set(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_EIR)) { 564071d10453SEric Joyner status = ice_sched_set_node_bw_lmt(pi, node, ICE_MAX_BW, 564171d10453SEric Joyner bw_t_info->eir_bw.bw); 564271d10453SEric Joyner if (status) 564371d10453SEric Joyner return status; 564471d10453SEric Joyner } 564571d10453SEric Joyner if (ice_is_bit_set(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_EIR_WT)) { 564671d10453SEric Joyner bw_alloc = bw_t_info->eir_bw.bw_alloc; 564771d10453SEric Joyner status = ice_sched_cfg_node_bw_alloc(hw, node, ICE_MAX_BW, 564871d10453SEric Joyner bw_alloc); 564971d10453SEric Joyner if (status) 565071d10453SEric Joyner return status; 565171d10453SEric Joyner } 565271d10453SEric Joyner if (ice_is_bit_set(bw_t_info->bw_t_bitmap, ICE_BW_TYPE_SHARED)) 565371d10453SEric Joyner status = ice_sched_set_node_bw_lmt(pi, node, ICE_SHARED_BW, 565471d10453SEric Joyner bw_t_info->shared_bw); 565571d10453SEric Joyner return status; 565671d10453SEric Joyner } 565771d10453SEric Joyner 565871d10453SEric Joyner /** 565971d10453SEric Joyner * ice_sched_replay_agg_bw - replay aggregator node(s) BW 566071d10453SEric Joyner * @hw: pointer to the HW struct 566171d10453SEric Joyner * @agg_info: aggregator data structure 566271d10453SEric Joyner * 566371d10453SEric Joyner * This function re-creates aggregator type nodes. The caller needs to hold 566471d10453SEric Joyner * the scheduler lock. 566571d10453SEric Joyner */ 5666*f2635e84SEric Joyner static int 566771d10453SEric Joyner ice_sched_replay_agg_bw(struct ice_hw *hw, struct ice_sched_agg_info *agg_info) 566871d10453SEric Joyner { 566971d10453SEric Joyner struct ice_sched_node *tc_node, *agg_node; 5670*f2635e84SEric Joyner int status = 0; 567171d10453SEric Joyner u8 tc; 567271d10453SEric Joyner 567371d10453SEric Joyner if (!agg_info) 567471d10453SEric Joyner return ICE_ERR_PARAM; 567571d10453SEric Joyner ice_for_each_traffic_class(tc) { 567671d10453SEric Joyner if (!ice_is_any_bit_set(agg_info->bw_t_info[tc].bw_t_bitmap, 567771d10453SEric Joyner ICE_BW_TYPE_CNT)) 567871d10453SEric Joyner continue; 567971d10453SEric Joyner tc_node = ice_sched_get_tc_node(hw->port_info, tc); 568071d10453SEric Joyner if (!tc_node) { 568171d10453SEric Joyner status = ICE_ERR_PARAM; 568271d10453SEric Joyner break; 568371d10453SEric Joyner } 568471d10453SEric Joyner agg_node = ice_sched_get_agg_node(hw->port_info, tc_node, 568571d10453SEric Joyner agg_info->agg_id); 568671d10453SEric Joyner if (!agg_node) { 568771d10453SEric Joyner status = ICE_ERR_PARAM; 568871d10453SEric Joyner break; 568971d10453SEric Joyner } 569071d10453SEric Joyner status = ice_sched_replay_node_bw(hw, agg_node, 569171d10453SEric Joyner &agg_info->bw_t_info[tc]); 569271d10453SEric Joyner if (status) 569371d10453SEric Joyner break; 569471d10453SEric Joyner } 569571d10453SEric Joyner return status; 569671d10453SEric Joyner } 569771d10453SEric Joyner 569871d10453SEric Joyner /** 569971d10453SEric Joyner * ice_sched_get_ena_tc_bitmap - get enabled TC bitmap 570071d10453SEric Joyner * @pi: port info struct 570171d10453SEric Joyner * @tc_bitmap: 8 bits TC bitmap to check 570271d10453SEric Joyner * @ena_tc_bitmap: 8 bits enabled TC bitmap to return 570371d10453SEric Joyner * 570471d10453SEric Joyner * This function returns enabled TC bitmap in variable ena_tc_bitmap. Some TCs 570571d10453SEric Joyner * may be missing, it returns enabled TCs. This function needs to be called with 570671d10453SEric Joyner * scheduler lock held. 570771d10453SEric Joyner */ 570871d10453SEric Joyner static void 570971d10453SEric Joyner ice_sched_get_ena_tc_bitmap(struct ice_port_info *pi, ice_bitmap_t *tc_bitmap, 571071d10453SEric Joyner ice_bitmap_t *ena_tc_bitmap) 571171d10453SEric Joyner { 571271d10453SEric Joyner u8 tc; 571371d10453SEric Joyner 571471d10453SEric Joyner /* Some TC(s) may be missing after reset, adjust for replay */ 571571d10453SEric Joyner ice_for_each_traffic_class(tc) 571671d10453SEric Joyner if (ice_is_tc_ena(*tc_bitmap, tc) && 571771d10453SEric Joyner (ice_sched_get_tc_node(pi, tc))) 571871d10453SEric Joyner ice_set_bit(tc, ena_tc_bitmap); 571971d10453SEric Joyner } 572071d10453SEric Joyner 572171d10453SEric Joyner /** 572271d10453SEric Joyner * ice_sched_replay_agg - recreate aggregator node(s) 572371d10453SEric Joyner * @hw: pointer to the HW struct 572471d10453SEric Joyner * 572571d10453SEric Joyner * This function recreate aggregator type nodes which are not replayed earlier. 572671d10453SEric Joyner * It also replay aggregator BW information. These aggregator nodes are not 572771d10453SEric Joyner * associated with VSI type node yet. 572871d10453SEric Joyner */ 572971d10453SEric Joyner void ice_sched_replay_agg(struct ice_hw *hw) 573071d10453SEric Joyner { 573171d10453SEric Joyner struct ice_port_info *pi = hw->port_info; 573271d10453SEric Joyner struct ice_sched_agg_info *agg_info; 573371d10453SEric Joyner 573471d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 573571d10453SEric Joyner LIST_FOR_EACH_ENTRY(agg_info, &hw->agg_list, ice_sched_agg_info, 57367d7af7f8SEric Joyner list_entry) 573771d10453SEric Joyner /* replay aggregator (re-create aggregator node) */ 573871d10453SEric Joyner if (!ice_cmp_bitmap(agg_info->tc_bitmap, 573971d10453SEric Joyner agg_info->replay_tc_bitmap, 574071d10453SEric Joyner ICE_MAX_TRAFFIC_CLASS)) { 574171d10453SEric Joyner ice_declare_bitmap(replay_bitmap, 574271d10453SEric Joyner ICE_MAX_TRAFFIC_CLASS); 5743*f2635e84SEric Joyner int status; 574471d10453SEric Joyner 574571d10453SEric Joyner ice_zero_bitmap(replay_bitmap, ICE_MAX_TRAFFIC_CLASS); 574671d10453SEric Joyner ice_sched_get_ena_tc_bitmap(pi, 574771d10453SEric Joyner agg_info->replay_tc_bitmap, 574871d10453SEric Joyner replay_bitmap); 574971d10453SEric Joyner status = ice_sched_cfg_agg(hw->port_info, 575071d10453SEric Joyner agg_info->agg_id, 575171d10453SEric Joyner ICE_AGG_TYPE_AGG, 575271d10453SEric Joyner replay_bitmap); 575371d10453SEric Joyner if (status) { 575471d10453SEric Joyner ice_info(hw, "Replay agg id[%d] failed\n", 575571d10453SEric Joyner agg_info->agg_id); 575671d10453SEric Joyner /* Move on to next one */ 575771d10453SEric Joyner continue; 575871d10453SEric Joyner } 575971d10453SEric Joyner /* Replay aggregator node BW (restore aggregator BW) */ 576071d10453SEric Joyner status = ice_sched_replay_agg_bw(hw, agg_info); 576171d10453SEric Joyner if (status) 576271d10453SEric Joyner ice_info(hw, "Replay agg bw [id=%d] failed\n", 576371d10453SEric Joyner agg_info->agg_id); 576471d10453SEric Joyner } 576571d10453SEric Joyner ice_release_lock(&pi->sched_lock); 576671d10453SEric Joyner } 576771d10453SEric Joyner 576871d10453SEric Joyner /** 576971d10453SEric Joyner * ice_sched_replay_agg_vsi_preinit - Agg/VSI replay pre initialization 577071d10453SEric Joyner * @hw: pointer to the HW struct 577171d10453SEric Joyner * 577271d10453SEric Joyner * This function initialize aggregator(s) TC bitmap to zero. A required 577371d10453SEric Joyner * preinit step for replaying aggregators. 577471d10453SEric Joyner */ 577571d10453SEric Joyner void ice_sched_replay_agg_vsi_preinit(struct ice_hw *hw) 577671d10453SEric Joyner { 577771d10453SEric Joyner struct ice_port_info *pi = hw->port_info; 577871d10453SEric Joyner struct ice_sched_agg_info *agg_info; 577971d10453SEric Joyner 578071d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 578171d10453SEric Joyner LIST_FOR_EACH_ENTRY(agg_info, &hw->agg_list, ice_sched_agg_info, 578271d10453SEric Joyner list_entry) { 578371d10453SEric Joyner struct ice_sched_agg_vsi_info *agg_vsi_info; 578471d10453SEric Joyner 578571d10453SEric Joyner agg_info->tc_bitmap[0] = 0; 578671d10453SEric Joyner LIST_FOR_EACH_ENTRY(agg_vsi_info, &agg_info->agg_vsi_list, 578771d10453SEric Joyner ice_sched_agg_vsi_info, list_entry) 578871d10453SEric Joyner agg_vsi_info->tc_bitmap[0] = 0; 578971d10453SEric Joyner } 579071d10453SEric Joyner ice_release_lock(&pi->sched_lock); 579171d10453SEric Joyner } 579271d10453SEric Joyner 579371d10453SEric Joyner /** 57947d7af7f8SEric Joyner * ice_sched_replay_root_node_bw - replay root node BW 57957d7af7f8SEric Joyner * @pi: port information structure 57967d7af7f8SEric Joyner * 57977d7af7f8SEric Joyner * Replay root node BW settings. 57987d7af7f8SEric Joyner */ 5799*f2635e84SEric Joyner int ice_sched_replay_root_node_bw(struct ice_port_info *pi) 58007d7af7f8SEric Joyner { 5801*f2635e84SEric Joyner int status = 0; 58027d7af7f8SEric Joyner 58037d7af7f8SEric Joyner if (!pi->hw) 58047d7af7f8SEric Joyner return ICE_ERR_PARAM; 58057d7af7f8SEric Joyner ice_acquire_lock(&pi->sched_lock); 58067d7af7f8SEric Joyner 58077d7af7f8SEric Joyner status = ice_sched_replay_node_bw(pi->hw, pi->root, 58087d7af7f8SEric Joyner &pi->root_node_bw_t_info); 58097d7af7f8SEric Joyner ice_release_lock(&pi->sched_lock); 58107d7af7f8SEric Joyner return status; 58117d7af7f8SEric Joyner } 58127d7af7f8SEric Joyner 58137d7af7f8SEric Joyner /** 581471d10453SEric Joyner * ice_sched_replay_tc_node_bw - replay TC node(s) BW 581571d10453SEric Joyner * @pi: port information structure 581671d10453SEric Joyner * 581771d10453SEric Joyner * This function replay TC nodes. 581871d10453SEric Joyner */ 5819*f2635e84SEric Joyner int ice_sched_replay_tc_node_bw(struct ice_port_info *pi) 582071d10453SEric Joyner { 5821*f2635e84SEric Joyner int status = 0; 582271d10453SEric Joyner u8 tc; 582371d10453SEric Joyner 582471d10453SEric Joyner if (!pi->hw) 582571d10453SEric Joyner return ICE_ERR_PARAM; 582671d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 582771d10453SEric Joyner ice_for_each_traffic_class(tc) { 582871d10453SEric Joyner struct ice_sched_node *tc_node; 582971d10453SEric Joyner 583071d10453SEric Joyner tc_node = ice_sched_get_tc_node(pi, tc); 583171d10453SEric Joyner if (!tc_node) 583271d10453SEric Joyner continue; /* TC not present */ 583371d10453SEric Joyner status = ice_sched_replay_node_bw(pi->hw, tc_node, 583471d10453SEric Joyner &pi->tc_node_bw_t_info[tc]); 583571d10453SEric Joyner if (status) 583671d10453SEric Joyner break; 583771d10453SEric Joyner } 583871d10453SEric Joyner ice_release_lock(&pi->sched_lock); 583971d10453SEric Joyner return status; 584071d10453SEric Joyner } 584171d10453SEric Joyner 584271d10453SEric Joyner /** 584371d10453SEric Joyner * ice_sched_replay_vsi_bw - replay VSI type node(s) BW 584471d10453SEric Joyner * @hw: pointer to the HW struct 584571d10453SEric Joyner * @vsi_handle: software VSI handle 584671d10453SEric Joyner * @tc_bitmap: 8 bits TC bitmap 584771d10453SEric Joyner * 584871d10453SEric Joyner * This function replays VSI type nodes bandwidth. This function needs to be 584971d10453SEric Joyner * called with scheduler lock held. 585071d10453SEric Joyner */ 5851*f2635e84SEric Joyner static int 585271d10453SEric Joyner ice_sched_replay_vsi_bw(struct ice_hw *hw, u16 vsi_handle, 585371d10453SEric Joyner ice_bitmap_t *tc_bitmap) 585471d10453SEric Joyner { 585571d10453SEric Joyner struct ice_sched_node *vsi_node, *tc_node; 585671d10453SEric Joyner struct ice_port_info *pi = hw->port_info; 585771d10453SEric Joyner struct ice_bw_type_info *bw_t_info; 585871d10453SEric Joyner struct ice_vsi_ctx *vsi_ctx; 5859*f2635e84SEric Joyner int status = 0; 586071d10453SEric Joyner u8 tc; 586171d10453SEric Joyner 586271d10453SEric Joyner vsi_ctx = ice_get_vsi_ctx(pi->hw, vsi_handle); 586371d10453SEric Joyner if (!vsi_ctx) 586471d10453SEric Joyner return ICE_ERR_PARAM; 586571d10453SEric Joyner ice_for_each_traffic_class(tc) { 586671d10453SEric Joyner if (!ice_is_tc_ena(*tc_bitmap, tc)) 586771d10453SEric Joyner continue; 586871d10453SEric Joyner tc_node = ice_sched_get_tc_node(pi, tc); 586971d10453SEric Joyner if (!tc_node) 587071d10453SEric Joyner continue; 587171d10453SEric Joyner vsi_node = ice_sched_get_vsi_node(pi, tc_node, vsi_handle); 587271d10453SEric Joyner if (!vsi_node) 587371d10453SEric Joyner continue; 587471d10453SEric Joyner bw_t_info = &vsi_ctx->sched.bw_t_info[tc]; 587571d10453SEric Joyner status = ice_sched_replay_node_bw(hw, vsi_node, bw_t_info); 587671d10453SEric Joyner if (status) 587771d10453SEric Joyner break; 587871d10453SEric Joyner } 587971d10453SEric Joyner return status; 588071d10453SEric Joyner } 588171d10453SEric Joyner 588271d10453SEric Joyner /** 588371d10453SEric Joyner * ice_sched_replay_vsi_agg - replay aggregator & VSI to aggregator node(s) 588471d10453SEric Joyner * @hw: pointer to the HW struct 588571d10453SEric Joyner * @vsi_handle: software VSI handle 588671d10453SEric Joyner * 588771d10453SEric Joyner * This function replays aggregator node, VSI to aggregator type nodes, and 588871d10453SEric Joyner * their node bandwidth information. This function needs to be called with 588971d10453SEric Joyner * scheduler lock held. 589071d10453SEric Joyner */ 5891*f2635e84SEric Joyner static int 589271d10453SEric Joyner ice_sched_replay_vsi_agg(struct ice_hw *hw, u16 vsi_handle) 589371d10453SEric Joyner { 589471d10453SEric Joyner ice_declare_bitmap(replay_bitmap, ICE_MAX_TRAFFIC_CLASS); 589571d10453SEric Joyner struct ice_sched_agg_vsi_info *agg_vsi_info; 589671d10453SEric Joyner struct ice_port_info *pi = hw->port_info; 589771d10453SEric Joyner struct ice_sched_agg_info *agg_info; 5898*f2635e84SEric Joyner int status; 589971d10453SEric Joyner 590071d10453SEric Joyner ice_zero_bitmap(replay_bitmap, ICE_MAX_TRAFFIC_CLASS); 590171d10453SEric Joyner if (!ice_is_vsi_valid(hw, vsi_handle)) 590271d10453SEric Joyner return ICE_ERR_PARAM; 590371d10453SEric Joyner agg_info = ice_get_vsi_agg_info(hw, vsi_handle); 590471d10453SEric Joyner if (!agg_info) 5905*f2635e84SEric Joyner return 0; /* Not present in list - default Agg case */ 590671d10453SEric Joyner agg_vsi_info = ice_get_agg_vsi_info(agg_info, vsi_handle); 590771d10453SEric Joyner if (!agg_vsi_info) 5908*f2635e84SEric Joyner return 0; /* Not present in list - default Agg case */ 590971d10453SEric Joyner ice_sched_get_ena_tc_bitmap(pi, agg_info->replay_tc_bitmap, 591071d10453SEric Joyner replay_bitmap); 591171d10453SEric Joyner /* Replay aggregator node associated to vsi_handle */ 591271d10453SEric Joyner status = ice_sched_cfg_agg(hw->port_info, agg_info->agg_id, 591371d10453SEric Joyner ICE_AGG_TYPE_AGG, replay_bitmap); 591471d10453SEric Joyner if (status) 591571d10453SEric Joyner return status; 591671d10453SEric Joyner /* Replay aggregator node BW (restore aggregator BW) */ 591771d10453SEric Joyner status = ice_sched_replay_agg_bw(hw, agg_info); 591871d10453SEric Joyner if (status) 591971d10453SEric Joyner return status; 592071d10453SEric Joyner 592171d10453SEric Joyner ice_zero_bitmap(replay_bitmap, ICE_MAX_TRAFFIC_CLASS); 592271d10453SEric Joyner ice_sched_get_ena_tc_bitmap(pi, agg_vsi_info->replay_tc_bitmap, 592371d10453SEric Joyner replay_bitmap); 592471d10453SEric Joyner /* Move this VSI (vsi_handle) to above aggregator */ 592571d10453SEric Joyner status = ice_sched_assoc_vsi_to_agg(pi, agg_info->agg_id, vsi_handle, 592671d10453SEric Joyner replay_bitmap); 592771d10453SEric Joyner if (status) 592871d10453SEric Joyner return status; 592971d10453SEric Joyner /* Replay VSI BW (restore VSI BW) */ 593071d10453SEric Joyner return ice_sched_replay_vsi_bw(hw, vsi_handle, 593171d10453SEric Joyner agg_vsi_info->tc_bitmap); 593271d10453SEric Joyner } 593371d10453SEric Joyner 593471d10453SEric Joyner /** 593571d10453SEric Joyner * ice_replay_vsi_agg - replay VSI to aggregator node 593671d10453SEric Joyner * @hw: pointer to the HW struct 593771d10453SEric Joyner * @vsi_handle: software VSI handle 593871d10453SEric Joyner * 593971d10453SEric Joyner * This function replays association of VSI to aggregator type nodes, and 594071d10453SEric Joyner * node bandwidth information. 594171d10453SEric Joyner */ 5942*f2635e84SEric Joyner int ice_replay_vsi_agg(struct ice_hw *hw, u16 vsi_handle) 594371d10453SEric Joyner { 594471d10453SEric Joyner struct ice_port_info *pi = hw->port_info; 5945*f2635e84SEric Joyner int status; 594671d10453SEric Joyner 594771d10453SEric Joyner ice_acquire_lock(&pi->sched_lock); 594871d10453SEric Joyner status = ice_sched_replay_vsi_agg(hw, vsi_handle); 594971d10453SEric Joyner ice_release_lock(&pi->sched_lock); 595071d10453SEric Joyner return status; 595171d10453SEric Joyner } 595271d10453SEric Joyner 595371d10453SEric Joyner /** 595471d10453SEric Joyner * ice_sched_replay_q_bw - replay queue type node BW 595571d10453SEric Joyner * @pi: port information structure 595671d10453SEric Joyner * @q_ctx: queue context structure 595771d10453SEric Joyner * 595871d10453SEric Joyner * This function replays queue type node bandwidth. This function needs to be 595971d10453SEric Joyner * called with scheduler lock held. 596071d10453SEric Joyner */ 5961*f2635e84SEric Joyner int 596271d10453SEric Joyner ice_sched_replay_q_bw(struct ice_port_info *pi, struct ice_q_ctx *q_ctx) 596371d10453SEric Joyner { 596471d10453SEric Joyner struct ice_sched_node *q_node; 596571d10453SEric Joyner 596671d10453SEric Joyner /* Following also checks the presence of node in tree */ 596771d10453SEric Joyner q_node = ice_sched_find_node_by_teid(pi->root, q_ctx->q_teid); 596871d10453SEric Joyner if (!q_node) 596971d10453SEric Joyner return ICE_ERR_PARAM; 597071d10453SEric Joyner return ice_sched_replay_node_bw(pi->hw, q_node, &q_ctx->bw_t_info); 597171d10453SEric Joyner } 5972